ublox 0.10.0

A crate to communicate with u-blox GPS devices using the UBX protocol
Documentation
#[allow(unused_imports, reason = "It is only unused in some feature sets")]
use crate::FieldIter;
use bitflags::bitflags;
#[cfg(feature = "serde")]
use {super::SerializeUbxPacketFields, crate::serde::ser::SerializeMap};

use crate::{error::ParserError, UbxPacketMeta};
use ublox_derive::{ubx_extend_bitflags, ubx_packet_recv};

#[ubx_packet_recv]
#[ubx(class = 0x02, id = 0x15, max_payload_len = 8176)] // 16 + 255 * 32
struct RxmRawx {
    /// Measurement time of week in receiver local time approximately aligned to the GPS time system.
    rcv_tow: f64,

    /// GPS week number. U-Blox receivers always express this counter in GPST.
    week: u16,

    /// GPS leap seconds (GPS-UTC)
    leap_s: i8,

    /// Number of measurements to follow
    num_meas: u8,

    /// Receiver tracking status bitfield
    #[ubx(map_type = RecStatFlags)]
    rec_stat: u8,

    /// Message version
    version: u8,

    /// Reserved
    reserved1: [u8; 2],

    /// Extended software information strings
    #[ubx(
        map_type = RxmRawxInfoIter,
        from = RxmRawxInfoIter::new,
        may_fail,
        is_valid = RxmRawxInfoIter::is_valid,
    )]
    measurements: [u8; 0],
}

#[ubx_extend_bitflags]
#[ubx(from, into_raw, rest_reserved)]
bitflags! {
    #[derive(Default, Debug)]
    pub struct RecStatFlags: u8 {
        /// Leap seconds have been determined
        const LEAP_SEC = 0x1;

        /// Clock reset applied.
        const CLK_RESET = 0x2;
    }
}

#[derive(Debug, Clone)]
pub struct RxmRawxInfoIter<'a>(core::slice::ChunksExact<'a, u8>);

impl<'a> RxmRawxInfoIter<'a> {
    fn new(data: &'a [u8]) -> Self {
        Self(data.chunks_exact(32))
    }

    fn is_valid(bytes: &[u8]) -> bool {
        bytes.len().is_multiple_of(32)
    }
}

impl<'a> core::iter::Iterator for RxmRawxInfoIter<'a> {
    type Item = RxmRawxInfoRef<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(RxmRawxInfoRef)
    }
}

#[ubx_packet_recv]
#[ubx(class = 0x02, id = 0x15, fixed_payload_len = 32)]
#[derive(Debug)]
pub struct RxmRawxInfo {
    /// Pseudo range measurement
    pr_mes: f64,

    /// Carrier phase measurement
    cp_mes: f64,

    /// Doppler shift
    do_mes: f32,

    /// GNSS-ID of signal source
    gnss_id: u8,

    /// PRN ID of signal source
    sv_id: u8,

    /// Reserved
    reserved2: u8,

    /// Frequency ID in case of Glonass signal source
    freq_id: u8,

    /// Lock time
    lock_time: u16,

    /// Measurement C/NO
    cno: u8,

    /// Pseudo range standard deviation
    #[ubx(map_type = StdevFlags)]
    pr_stdev: u8,

    /// Carrier phase standard deviation
    #[ubx(map_type = StdevFlags)]
    cp_stdev: u8,

    /// Doppler shift standard deviation
    #[ubx(map_type = StdevFlags)]
    do_stdev: u8,

    /// Tracking status
    #[ubx(map_type = TrkStatFlags)]
    trk_stat: u8,

    /// Reserved
    reserved3: u8,
}

#[ubx_extend_bitflags]
#[ubx(from, rest_reserved)]
bitflags! {
    #[derive(Debug)]
    pub struct StdevFlags: u8 {
        const STD_1 = 0x01;
        const STD_2 = 0x02;
        const STD_3 = 0x04;
        const STD_4 = 0x08;
    }
}

#[ubx_extend_bitflags]
#[ubx(from, rest_reserved)]
bitflags! {
    #[derive(Debug)]
    pub struct TrkStatFlags: u8 {
        const PR_VALID = 0x01;
        const CP_VALID = 0x02;
        const HALF_CYCLE = 0x04;
        const SUB_HALF_CYCLE = 0x08;
    }
}