canboat_rs/
lib.rs

1#![cfg_attr(not(test), no_std)]
2
3//! # canboat-rs
4//! ## Parsing nmea data
5//!
6//! ```
7//! use chrono::Datelike;
8//! use canboat_rs::pgns::pgn::Pgn;
9//! use canboat_rs::NmeaParser;
10//! // Check the `can-analyzer` project to figure out how to grab
11//! // a can id and data.
12//!
13//! pub fn main() {
14//!     let id = 233836644;
15//!     let data: &[u8] = &[255, 255, 79, 78, 144, 3, 32, 46];
16//!     let mut parser = NmeaParser::new();
17//!     let parsed_message = parser.parse(id, data);
18//!     match parsed_message.unwrap() {
19//!         Pgn::SystemTime(time) => {
20//!             println!("{:?}", time);
21//!         }
22//!         _ => {},
23//!     };
24//! }
25//! ```
26
27pub mod fast_packet;
28pub mod nmea_id;
29pub mod pgn_types;
30pub mod pgns;
31use fast_packet::{AddFrame, FastPacket};
32use heapless::Entry;
33use heapless::{FnvIndexMap, Vec};
34use nmea_id::NmeaId;
35use pgns::get_pgn_type::get_pgn_type;
36use pgns::pgn::Pgn;
37pub mod date;
38pub mod nmea_option;
39pub mod parse;
40
41#[derive(Debug)]
42pub struct NmeaParser {
43    pub fast_packet_map: FnvIndexMap<u32, FastPacket, 16>,
44}
45
46impl NmeaParser {
47    pub fn new() -> NmeaParser {
48        let fast_packet_map = FnvIndexMap::<u32, FastPacket, 16>::new();
49        NmeaParser { fast_packet_map }
50    }
51
52    pub fn parse(&mut self, id: u32, data: &[u8]) -> Option<Pgn> {
53        let pgn = NmeaId(id);
54        let pgn_type = get_pgn_type(pgn.get_pgn());
55        match pgn_type {
56            pgn_types::PgnType::Fast => {
57                if let Some(data) = self.parse_fast_packet(id, data) {
58                    parse::get_nmea_message(pgn.get_pgn(), data.as_slice())
59                } else {
60                    None
61                }
62            }
63            pgn_types::PgnType::Single => parse::get_nmea_message(pgn.get_pgn(), data),
64            _ => None,
65        }
66    }
67
68    pub fn parse_fast_packet(&mut self, id: u32, data: &[u8]) -> Option<Vec<u8, 128>> {
69        let nmea_message = NmeaId(id);
70        let pgn = nmea_message.get_pgn();
71        let fp = FastPacket::new(data);
72
73        if let Some(fp) = fp {
74            match self.fast_packet_map.entry(pgn) {
75                Entry::Vacant(packet) => {
76                    packet.insert(fp).unwrap();
77                    None
78                }
79                Entry::Occupied(mut packet) => {
80                    let current_packet = packet.get_mut();
81                    match current_packet.add_frame(data) {
82                        // TODO: If first frame and occupied, replace
83                        AddFrame::Error => {
84                            packet.remove();
85                            let _ = self.fast_packet_map.insert(pgn, fp);
86                            None
87                        }
88                        _ => None,
89                    }
90                }
91            }
92        } else {
93            match self.fast_packet_map.entry(pgn) {
94                Entry::Vacant(_) => None,
95                Entry::Occupied(mut packet) => {
96                    let fp = packet.get_mut();
97                    match fp.add_frame(data) {
98                        // TODO: If firsrt frame and occupied, replace
99                        AddFrame::Error => {
100                            packet.remove();
101                            None
102                        }
103                        AddFrame::Complete => {
104                            let (_, complete_packet) = packet.remove_entry();
105                            Some(complete_packet.data)
106                        }
107                        _ => None,
108                    }
109                }
110            }
111        }
112    }
113}
114
115#[cfg(test)]
116mod tests {
117
118    use chrono::Datelike;
119
120    use super::*;
121
122    #[test]
123    fn matches_pgn_correctly() {
124        let id = 233836644;
125        let data: &[u8] = &[255, 255, 79, 78, 144, 3, 32, 46];
126        let mut parser = NmeaParser::new();
127        let data = parser.parse(id, data);
128        let date = match data.unwrap() {
129            Pgn::SystemTime(time) => {
130                println!("{:?}", time);
131                Some(time)
132            }
133            _ => None,
134        };
135
136        assert_eq!(date.unwrap().date().datetime.year(), 2018);
137    }
138}