ublox/
ubx_packets.rs

1pub mod cfg_val;
2pub mod packets;
3mod types;
4
5use crate::error::MemWriterError;
6pub use packets::*;
7pub use types::*;
8
9/// Information about concrete UBX protocol's packet
10pub trait UbxPacketMeta {
11    const CLASS: u8;
12    const ID: u8;
13    const FIXED_PAYLOAD_LEN: Option<u16>;
14    const MAX_PAYLOAD_LEN: u16;
15}
16
17pub(crate) const SYNC_CHAR_1: u8 = 0xb5;
18pub(crate) const SYNC_CHAR_2: u8 = 0x62;
19pub(crate) const RTCM_SYNC_CHAR: u8 = 0xd3;
20
21/// The checksum is calculated over the packet, starting and including
22/// the CLASS field, up until, but excluding, the checksum field.
23/// So slice should starts with class id.
24/// Return ck_a and ck_b
25pub(crate) fn ubx_checksum(data: &[u8]) -> (u8, u8) {
26    let mut ck_a = 0_u8;
27    let mut ck_b = 0_u8;
28    for byte in data {
29        ck_a = ck_a.overflowing_add(*byte).0;
30        ck_b = ck_b.overflowing_add(ck_a).0;
31    }
32    (ck_a, ck_b)
33}
34
35/// For ubx checksum on the fly
36#[derive(Default)]
37struct UbxChecksumCalc {
38    ck_a: u8,
39    ck_b: u8,
40}
41
42impl UbxChecksumCalc {
43    fn update(&mut self, chunk: &[u8]) {
44        for byte in chunk {
45            self.ck_a = self.ck_a.overflowing_add(*byte).0;
46            self.ck_b = self.ck_b.overflowing_add(self.ck_a).0;
47        }
48    }
49    fn result(self) -> (u8, u8) {
50        (self.ck_a, self.ck_b)
51    }
52}
53
54/// Abstraction for buffer creation/reallocation
55/// to storing packet
56pub trait MemWriter {
57    type Error;
58    /// make sure that we have at least `len` bytes for writing
59    fn reserve_allocate(&mut self, len: usize) -> Result<(), MemWriterError<Self::Error>>;
60    fn write(&mut self, buf: &[u8]) -> Result<(), MemWriterError<Self::Error>>;
61}
62
63#[cfg(feature = "std")]
64impl MemWriter for Vec<u8> {
65    type Error = std::io::Error;
66
67    fn reserve_allocate(&mut self, len: usize) -> Result<(), MemWriterError<Self::Error>> {
68        self.reserve(len);
69        Ok(())
70    }
71    fn write(&mut self, buf: &[u8]) -> Result<(), MemWriterError<Self::Error>> {
72        let ret = <dyn std::io::Write>::write(self, buf).map_err(MemWriterError::Custom)?;
73        if ret == buf.len() {
74            Ok(())
75        } else {
76            Err(MemWriterError::NotEnoughMem)
77        }
78    }
79}
80
81pub trait UbxPacketCreator {
82    /// Create packet and store bytes sequence to somewhere using `out`
83    fn create_packet<T: MemWriter>(self, out: &mut T) -> Result<(), MemWriterError<T::Error>>;
84}
85
86/// Packet not supported yet by this crate
87#[derive(Debug, Clone, Copy)]
88#[cfg_attr(feature = "serde", derive(serde::Serialize))]
89pub struct UbxUnknownPacketRef<'a> {
90    pub payload: &'a [u8],
91    pub class: u8,
92    pub msg_id: u8,
93}
94
95#[derive(Debug, Clone)]
96pub struct UbxUnknownPacketOwned<const MAX_PAYLOAD_LEN: usize> {
97    pub payload: [u8; MAX_PAYLOAD_LEN],
98    pub payload_len: usize,
99    pub class: u8,
100    pub msg_id: u8,
101}
102
103/// Request specific packet
104pub struct UbxPacketRequest {
105    req_class: u8,
106    req_id: u8,
107}
108
109impl UbxPacketRequest {
110    pub const PACKET_LEN: usize = 8;
111
112    #[inline]
113    pub fn request_for<T: UbxPacketMeta>() -> Self {
114        Self {
115            req_class: T::CLASS,
116            req_id: T::ID,
117        }
118    }
119    #[inline]
120    pub fn request_for_unknown(req_class: u8, req_id: u8) -> Self {
121        Self { req_class, req_id }
122    }
123
124    #[inline]
125    pub fn into_packet_bytes(self) -> [u8; Self::PACKET_LEN] {
126        let mut ret = [
127            SYNC_CHAR_1,
128            SYNC_CHAR_2,
129            self.req_class,
130            self.req_id,
131            0,
132            0,
133            0,
134            0,
135        ];
136        let (ck_a, ck_b) = ubx_checksum(&ret[2..6]);
137        ret[6] = ck_a;
138        ret[7] = ck_b;
139        ret
140    }
141}