1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
#![cfg_attr(not(test), no_std)] extern crate micromath; #[cfg(test)] #[macro_use] extern crate pretty_assertions; pub mod message; pub mod messages; pub mod types; pub use message::{Message, SentenceFormatter}; const MAX_MESSAGE_SIZE: usize = 79; pub struct Parser { buffer: [u8; MAX_MESSAGE_SIZE], index: usize, enabled: u32, } impl Parser { pub fn new() -> Self { Self { buffer: [0u8; MAX_MESSAGE_SIZE], index: 0, enabled: u32::MAX } } pub fn with_enables(enableds: impl AsRef<[SentenceFormatter]>) -> Self { let mut enabled: u32 = 0; for &message in enableds.as_ref().iter() { enabled |= 1 << (message as usize); } Self { buffer: [0u8; MAX_MESSAGE_SIZE], index: 0, enabled } } fn parse_line(&mut self, line: &[u8]) -> Option<Message> { let mut line = line; if !line.starts_with(b"$") || !line.ends_with(b"\r") { if line.len() > self.buffer.len() - self.index { self.index = 0; return None; } self.buffer[self.index..self.index + line.len()].copy_from_slice(line); self.index += line.len(); line = &self.buffer[..self.index]; } if !line.ends_with(b"\r") { return None; } self.index = 0; if line.len() < 7 { return None; } let option = SentenceFormatter::try_from(&line[3..6]); if !option.map(|f| (1 << f as usize) & self.enabled > 0).unwrap_or(false) { return None; } Message::try_from(&line[1..line.len() - 1]) } pub fn parse_bytes<'a>(&'a mut self, bytes: &'a [u8]) -> impl Iterator<Item = Message> + 'a { bytes .split(|&b| b == b'\n') .map(move |line| self.parse_line(line)) .filter(|o| o.is_some()) .map(|o| o.unwrap()) } } mod test { #[test] fn test_parser() { use super::Parser; use crate::message::Message; let bytes = b"blablabla$GPGLL,4717.11364,N,00833.91565,E,092321.00,A,A*60\r\n\ $GPGGA,092725.00,4717.11399,N,00833.91590,E,1,08,1.01,499.6,M,48.0,M,,*5B\r\n\ $GNGNS,103600.01,5114.51176,N,00012.29380,W,ANNN,07,1.18,111.5,45.6,,,V*00\r\n\ $GPRMC,083559.00,A,4717.11437,N,00833.91522,E,0.004,77.52,091202,,,A,V*2D\r\n\ $GPGLL,4717.11364,N,00833.91565,E,092321.00,A,A*60\r\n"; let mut parser = Parser::new(); { let mut messages = parser.parse_bytes(bytes); match messages.next().unwrap() { Message::GGA(gga) => assert_eq!("499.6#1", format!("{:?}", gga.altitude)), _ => panic!(), } match messages.next().unwrap() { Message::GNS(gns) => assert_eq!("111.5#1", format!("{:?}", gns.altitude)), _ => panic!(), } match messages.next().unwrap() { Message::RMC(rmc) => assert_eq!("0.4#3", format!("{:?}", rmc.speed)), _ => panic!(), } assert!(messages.next().is_none()); } { assert!(parser.parse_bytes(&bytes[0..64]).next().is_none()); } { assert!(parser.parse_bytes(&bytes[64..128]).next().is_none()); } { let mut results = parser.parse_bytes(&bytes[128..192]); assert!(results.next().is_some()); assert!(results.next().is_none()); } { let mut results = parser.parse_bytes(&bytes[192..256]); assert!(results.next().is_some()); assert!(results.next().is_none()); } { let mut results = parser.parse_bytes(&bytes[256..320]); assert!(results.next().is_some()); assert!(results.next().is_none()); } } }