Repository: ublox-rs/ublox
Pull request #106: Add CfgValGet message for requesting key values.
Author: login: andrei-ng
Created: 2025-04-18T07:33:00Z | Merged: 2025-04-23T08:31:58Z


Porting and splitting the additions from PR #56 into this and separate PRs as our master has diverged substantially with the introduction of the feature flags. Credit for the work goes to @stevenlovegrove, @Hackerman342  


Diff:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c5a2a5b0..0bf76f28 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,9 @@ All notable changes to this project will be documented in this file.
 - Fixed typo: `HnrPvtRef::heading_accurracy` to `HnrPvtRef::heading_accuracy` ([#118](https://github.com/ublox-rs/ublox/pull/118))
 - Fixed typo: `CfgTmode2Builder.survery_in_accur_limit` to `CfgTmode2Builder.survey_in_accur_limit` ([#118](https://github.com/ublox-rs/ublox/pull/118))
 
+- Almost all `CfgVal` enum variants have been renamed to have a consistent CamelCase representation ([#106](https://github.com/ublox-rs/ublox/pull/106))
+- Added new Packet variant `CfgValGetRecv` for UBX Proto 27 and UBX Proto 31 ([#106](https://github.com/ublox-rs/ublox/pull/106))
+
 ### CI
 
 - Add typo checking workflow ([#122](https://github.com/ublox-rs/ublox/pull/122))
diff --git a/README.md b/README.md
index c2b09f0f..73e0fc16 100644
--- a/README.md
+++ b/README.md
@@ -53,12 +53,12 @@ let packet: [u8; 28] = CfgPrtUartBuilder {
 For variable-size packets like `CfgValSet`, you can construct it into a new `Vec<u8>`:
 
 ```rust
-use ublox::{cfg_val::CfgVal::*, CfgLayer, CfgValSetBuilder};
+use ublox::{cfg_val::CfgVal::*, CfgLayerSet, CfgValSetBuilder};
 let mut buffer = Vec::new();
 
 CfgValSetBuilder {
     version: 1,
-    layers: CfgLayer::RAM,
+    layers: CfgLayerSet::RAM,
     reserved1: 0,
     cfg_data: &[UsbOutProtNmea(true), UsbOutProtRtcm3x(true), UsbOutProtUbx(true)],
 }
@@ -68,12 +68,12 @@ CfgValSetBuilder {
 Or by extending to an existing one:
 
 ```rust
-use ublox::{cfg_val::CfgVal::*, CfgLayer, CfgValSetBuilder};
+use ublox::{cfg_val::CfgVal::*, CfgLayerSet, CfgValSetBuilder};
 
 let mut packet_vec = Vec::new();
 CfgValSetBuilder {
     version: 1,
-    layers: CfgLayer::RAM,
+    layers: CfgLayerSet::RAM,
     reserved1: 0,
     cfg_data: &[UsbOutProtNmea(true), UsbOutProtRtcm3x(true), UsbOutProtUbx(true)],
 }
diff --git a/ublox/src/ubx_packets/cfg_val.rs b/ublox/src/ubx_packets/cfg_val.rs
index 500f83a1..d984359c 100644
--- a/ublox/src/ubx_packets/cfg_val.rs
+++ b/ublox/src/ubx_packets/cfg_val.rs
@@ -1,7 +1,6 @@
-use super::{AlignmentToReferenceTime, CfgInfMask, DataBits, Parity, StopBits};
-
-pub struct KeyId(u32);
+use super::{AlignmentToReferenceTime, CfgInfMask, CfgTModeModes, DataBits, Parity, StopBits};
 
+/// Supported storage size identiﬁers for the Configuration Value
 pub enum StorageSize {
     OneBit,
     OneByte,
@@ -21,9 +20,13 @@ impl StorageSize {
     }
 }
 
+/// Configuration Key ID for the uBlox Conﬁguration Interface
+pub struct KeyId(u32);
+
 impl KeyId {
     pub(crate) const SIZE: usize = 4;
 
+    /// Retrieve the storage size of the Configuration Value
     pub const fn value_size(&self) -> StorageSize {
         match (self.0 >> 28) & 0b111 {
             1 => StorageSize::OneBit,
@@ -35,13 +38,25 @@ impl KeyId {
         }
     }
 
+    /// Group ID portion of the Key ID
     pub const fn group_id(&self) -> u8 {
         (self.0 >> 16) as u8
     }
 
+    /// Item ID portion of the Key ID
     pub const fn item_id(&self) -> u8 {
         self.0 as u8
     }
+
+    /// Extend a buffer with the contents of [KeyId].
+    pub fn extend_to<T>(&self, buf: &mut T) -> usize
+    where
+        T: core::iter::Extend<u8>,
+    {
+        let bytes = self.0.to_le_bytes();
+        buf.extend(bytes);
+        Self::SIZE
+    }
 }
 
 macro_rules! from_cfg_v_bytes {
@@ -55,6 +70,9 @@ macro_rules! from_cfg_v_bytes {
     ($buf:expr, u8) => {
         $buf[0]
     };
+    ($buf:expr, i8) => {
+        $buf[0] as i8
+    };
     ($buf:expr, u16) => {
         u16::from_le_bytes([$buf[0], $buf[1]])
     };
@@ -64,6 +82,9 @@ macro_rules! from_cfg_v_bytes {
     ($buf:expr, u32) => {
         u32::from_le_bytes([$buf[0], $buf[1], $buf[2], $buf[3]])
     };
+    ($buf:expr, i32) => {
+        i32::from_le_bytes([$buf[0], $buf[1], $buf[2], $buf[3]])
+    };
     ($buf:expr, u64) => {
         u64::from_le_bytes([
             $buf[0], $buf[1], $buf[2], $buf[3], $buf[4], $buf[5], $buf[6], $buf[7],
@@ -76,7 +97,7 @@ macro_rules! from_cfg_v_bytes {
         match $buf[0] {
             0 => DataBits::Eight,
             1 => DataBits::Seven,
-            _ => unreachable!(),
+            _ => unreachable!("DataBits value not supported by protocol specification"),
         }
     };
     ($buf:expr, Parity) => {
@@ -84,7 +105,7 @@ macro_rules! from_cfg_v_bytes {
             0 => Parity::None,
             1 => Parity::Odd,
             2 => Parity::Even,
-            _ => unreachable!(),
+            _ => unreachable!("Parity value not supported by protocol specification"),
         }
     };
     ($buf:expr, StopBits) => {
@@ -93,7 +114,7 @@ macro_rules! from_cfg_v_bytes {
             1 => StopBits::One,
             2 => StopBits::OneHalf,
             3 => StopBits::Two,
-            _ => unreachable!(),
+            _ => unreachable!("StopBits value not supported by protocol specification"),
         }
     };
     ($buf:expr, AlignmentToReferenceTime) => {
@@ -103,21 +124,38 @@ macro_rules! from_cfg_v_bytes {
             2 => AlignmentToReferenceTime::Glo,
             3 => AlignmentToReferenceTime::Bds,
             4 => AlignmentToReferenceTime::Gal,
-            _ => unreachable!(),
+            _ => unreachable!("CFG-RATE-TIMEREF value not supported by protocol specification"),
         }
     };
     ($buf:expr, TpPulse) => {
         match $buf[0] {
             0 => TpPulse::Period,
             1 => TpPulse::Freq,
-            _ => unreachable!(),
+            _ => unreachable!("CFG-TP-PULSE_DEF value not supported by protocol specification"),
         }
     };
     ($buf:expr, TpPulseLength) => {
         match $buf[0] {
             0 => TpPulseLength::Ratio,
             1 => TpPulseLength::Length,
-            _ => unreachable!(),
+            _ => unreachable!(
+                "CFG-TP-PULSE_LENGTH_DEF value not supported by protocol specification"
+            ),
+        }
+    };
+    ($buf:expr, CfgTModeModes) => {
+        match $buf[0] {
+            0 => CfgTModeModes::Disabled,
+            1 => CfgTModeModes::SurveyIn,
+            2 => CfgTModeModes::Fixed,
+            _ => unreachable!("CFG-TMODE-MODE value not supported by protocol specification"),
+        }
+    };
+    ($buf:expr, TModePosType) => {
+        match $buf[0] {
+            0 => TModePosType::ECEF,
+            1 => TModePosType::LLH,
+            _ => unreachable!("CFG-TMODE-POS_TYPE value not supported by protocol specification"),
         }
     };
 }
@@ -139,6 +177,9 @@ macro_rules! into_cfg_kv_bytes {
     ($this:expr, u8) => {{
       into_cfg_kv_bytes!(@inner [$this.0])
     }};
+    ($this:expr, i8) => {{
+      into_cfg_kv_bytes!(@inner [$this.0 as u8])
+    }};
     ($this:expr, u16) => {{
       let bytes = $this.0.to_le_bytes();
       into_cfg_kv_bytes!(@inner [bytes[0], bytes[1]])
@@ -151,6 +192,10 @@ macro_rules! into_cfg_kv_bytes {
       let bytes = $this.0.to_le_bytes();
       into_cfg_kv_bytes!(@inner [bytes[0], bytes[1], bytes[2], bytes[3]])
     }};
+    ($this:expr, i32) => {{
+      let bytes = $this.0.to_le_bytes();
+      into_cfg_kv_bytes!(@inner [bytes[0], bytes[1], bytes[2], bytes[3]])
+    }};
     ($this:expr, u64) => {{
       let bytes = $this.0.to_le_bytes();
       into_cfg_kv_bytes!(@inner [bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]])
@@ -202,6 +247,16 @@ macro_rules! into_cfg_kv_bytes {
           $this.0 as u8
       ])
     };
+    ($this:expr, CfgTModeModes) => {
+      into_cfg_kv_bytes!(@inner [
+          $this.0 as u8
+      ])
+    };
+    ($this:expr, TModePosType) => {
+      into_cfg_kv_bytes!(@inner [
+          $this.0 as u8
+      ])
+    };
 }
 
 macro_rules! cfg_val {
@@ -211,7 +266,18 @@ macro_rules! cfg_val {
       $cfg_item:ident, $cfg_key_id:expr, $cfg_value_type:ident,
     )*
   ) => {
-    #[derive(Debug, Clone)]
+    #[derive(Debug, Clone, Copy)]
+    #[non_exhaustive]
+    pub enum CfgKey {
+      WildcardAll = 0x7fffffff,
+      $(
+        $(#[$class_comment])*
+        $cfg_item = $cfg_key_id,
+      )*
+    }
+
+    #[derive(Debug, Clone, Copy)]
+    #[cfg_attr(feature = "serde", derive(serde::Serialize))]
     #[non_exhaustive]
     pub enum CfgVal {
       $(
@@ -236,15 +302,19 @@ macro_rules! cfg_val {
       }
 
       #[track_caller]
-      pub fn parse(buf: &[u8]) -> Self {
+      pub fn parse(buf: &[u8]) -> Option<Self> {
         let key_id = u32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]);
         match key_id {
           $(
             $cfg_key_id => {
-              Self::$cfg_item(from_cfg_v_bytes!(&buf[4..], $cfg_value_type))
+              Some(Self::$cfg_item(from_cfg_v_bytes!(&buf[4..], $cfg_value_type)))
             },
           )*
-          _ => unimplemented!("unknown key ID: 0x{:8X}", key_id),
+          _ => {
+            // TODO: add a mechanism to log such messages that supports also no_std
+            // eprintln!("unknown key ID: 0x{:8X}", key_id);
+            None
+           },
         }
       }
 
@@ -292,6 +362,18 @@ macro_rules! cfg_val {
   }
 }
 
+impl CfgKey {
+    pub fn extend_to<T>(&self, buf: &mut T) -> usize
+    where
+        T: core::iter::Extend<u8>,
+    {
+        let bytes = (*self as u32).to_le_bytes();
+        let bytes_len = bytes.len();
+        buf.extend(bytes);
+        bytes_len
+    }
+}
+
 cfg_val! {
   // CFG-UART1
   Uart1Baudrate,        0x40520001, u32,
@@ -348,9 +430,9 @@ cfg_val! {
   UsbSerialNoStr3,      0x50650018, u64,
 
   // CFG-USBINPROT-*
-  UsbinprotUbx,         0x10770001, bool,
-  UsbinprotNmea,        0x10770002, bool,
-  UsbinprotRtcm3X,      0x10770004, bool,
+  UsbInProtUbx,         0x10770001, bool,
+  UsbInProtNmea,        0x10770002, bool,
+  UsbInProtRtcm3x,      0x10770004, bool,
 
   // CFG-USBOUTPROT-*
   UsbOutProtUbx,        0x10780001, bool,
@@ -358,16 +440,16 @@ cfg_val! {
   UsbOutProtRtcm3x,     0x10780004, bool,
 
   // CFG-INFMSG
-  InfmsgUbxI2c,          0x20920001, CfgInfMask,
-  InfmsgUbxUart1,        0x20920002, CfgInfMask,
-  InfmsgUbxUart2,        0x20920003, CfgInfMask,
-  InfmsgUbxUsb,          0x20920004, CfgInfMask,
-  InfmsgUbxSpi,          0x20920005, CfgInfMask,
-  InfmsgNmeaI2c,         0x20920006, CfgInfMask,
-  InfmsgNmeaUart1,       0x20920007, CfgInfMask,
-  InfmsgNmeaUart2,       0x20920008, CfgInfMask,
-  InfmsgNmeaUsb,         0x20920009, CfgInfMask,
-  InfmsgNmeaSpi,         0x2092000a, CfgInfMask,
+  InfMsgUbxI2c,          0x20920001, CfgInfMask,
+  InfMsgUbxUart1,        0x20920002, CfgInfMask,
+  InfMsgUbxUart2,        0x20920003, CfgInfMask,
+  InfMsgUbxUsb,          0x20920004, CfgInfMask,
+  InfMsgUbxSpi,          0x20920005, CfgInfMask,
+  InfMsgNmeaI2c,         0x20920006, CfgInfMask,
+  InfMsgNmeaUart1,       0x20920007, CfgInfMask,
+  InfMsgNmeaUart2,       0x20920008, CfgInfMask,
+  InfMsgNmeaUsb,         0x20920009, CfgInfMask,
+  InfMsgNmeaSpi,         0x2092000a, CfgInfMask,
 
   // CFG-RATE-*
   /// Nominal time between GNSS measurements
@@ -380,695 +462,716 @@ cfg_val! {
 
   // CFG-MSGOUT-*
   /// Output rate of the NMEA-GX-DTM message on port I2C
-  MsgoutNmeaIdDtmI2c, 0x209100a6, u8,
+  MsgOutNmeaIdDtmI2c, 0x209100a6, u8,
   /// Output rate of the NMEA-GX-DTM message on port SPI
-  MsgoutNmeaIdDtmSpi, 0x209100aa, u8,
+  MsgOutNmeaIdDtmSpi, 0x209100aa, u8,
   /// Output rate of the NMEA-GX-DTM message on port UART1
-  MsgoutNmeaIdDtmUart1, 0x209100a7, u8,
+  MsgOutNmeaIdDtmuart1, 0x209100a7, u8,
   /// Output rate of the NMEA-GX-DTM message on port UART2
-  MsgoutNmeaIdDtmUart2, 0x209100a8, u8,
+  MsgOutNmeaIdDtmuart2, 0x209100a8, u8,
   /// Output rate of the NMEA-GX-DTM message on port USB
-  MsgoutNmeaIdDtmUsb, 0x209100a9, u8,
+  MsgOutNmeaIdDtmUsb, 0x209100a9, u8,
   /// Output rate of the NMEA-GX-GBS message on port I2C
-  MsgoutNmeaIdGbsI2c, 0x209100dd, u8,
+  MsgOutNmeaIdGbsI2c, 0x209100dd, u8,
   /// Output rate of the NMEA-GX-GBS message on port SPI
-  MsgoutNmeaIdGbsSpi, 0x209100e1, u8,
+  MsgOutNmeaIdGbsSpi, 0x209100e1, u8,
   /// Output rate of the NMEA-GX-GBS message on port UART1
-  MsgoutNmeaIdGbsUart1, 0x209100de, u8,
+  MsgOutNmeaIdGbsUart1, 0x209100de, u8,
   /// Output rate of the NMEA-GX-GBS message on port UART2
-  MsgoutNmeaIdGbsUart2, 0x209100df, u8,
+  MsgOutNmeaIdGbsUart2, 0x209100df, u8,
   /// Output rate of the NMEA-GX-GBS message on port USB
-  MsgoutNmeaIdGbsUsb, 0x209100e0, u8,
+  MsgOutNmeaIdGbsUsb, 0x209100e0, u8,
   /// Output rate of the NMEA-GX-GGA message on port I2C
-  MsgoutNmeaIdGgaI2c, 0x209100ba, u8,
+  MsgOutNmeaIdGgaI2c, 0x209100ba, u8,
   /// Output rate of the NMEA-GX-GGA message on port SPI
-  MsgoutNmeaIdGgaSpi, 0x209100be, u8,
+  MsgOutNmeaIdGgaSpi, 0x209100be, u8,
   /// Output rate of the NMEA-GX-GGA message on port UART1
-  MsgoutNmeaIdGgaUart1, 0x209100bb, u8,
+  MsgOutNmeaIdGgaUart1, 0x209100bb, u8,
   /// Output rate of the NMEA-GX-GGA message on port UART2
-  MsgoutNmeaIdGgaUart2, 0x209100bc, u8,
+  MsgOutNmeaIdGgaUart2, 0x209100bc, u8,
   /// Output rate of the NMEA-GX-GGA message on port USB
-  MsgoutNmeaIdGgaUsb, 0x209100bd, u8,
+  MsgOutNmeaIdGgaUsb, 0x209100bd, u8,
   /// Output rate of the NMEA-GX-GLL message on port I2C
-  MsgoutNmeaIdGllI2c, 0x209100c9, u8,
+  MsgOutNmeaIdGllI2c, 0x209100c9, u8,
   /// Output rate of the NMEA-GX-GLL message on port SPI
-  MsgoutNmeaIdGllSpi, 0x209100cd, u8,
+  MsgOutNmeaIdGllSpi, 0x209100cd, u8,
   /// Output rate of the NMEA-GX-GLL message on port UART1
-  MsgoutNmeaIdGllUart1, 0x209100ca, u8,
+  MsgOutNmeaIdGllUart1, 0x209100ca, u8,
   /// Output rate of the NMEA-GX-GLL message on port UART2
-  MsgoutNmeaIdGllUart2, 0x209100cb, u8,
+  MsgOutNmeaIdGllUart2, 0x209100cb, u8,
   /// Output rate of the NMEA-GX-GLL message on port USB
-  MsgoutNmeaIdGllUsb, 0x209100cc, u8,
+  MsgOutNmeaIdGllUsb, 0x209100cc, u8,
   /// Output rate of the NMEA-GX-GNS message on port I2C
-  MsgoutNmeaIdGnsI2c, 0x209100b5, u8,
+  MsgOutNmeaIdGnsI2c, 0x209100b5, u8,
   /// Output rate of the NMEA-GX-GNS message on port SPI
-  MsgoutNmeaIdGnsSpi, 0x209100b9, u8,
+  MsgOutNmeaIdGnsSpi, 0x209100b9, u8,
   /// Output rate of the NMEA-GX-GNS message on port UART1
-  MsgoutNmeaIdGnsUart1, 0x209100b6, u8,
+  MsgOutNmeaIdGnsUart1, 0x209100b6, u8,
   /// Output rate of the NMEA-GX-GNS message on port UART2
-  MsgoutNmeaIdGnsUart2, 0x209100b7, u8,
+  MsgOutNmeaIdGnsUart2, 0x209100b7, u8,
   /// Output rate of the NMEA-GX-GNS message on port USB
-  MsgoutNmeaIdGnsUsb, 0x209100b8, u8,
+  MsgOutNmeaIdGnsUsb, 0x209100b8, u8,
   /// Output rate of the NMEA-GX-GRS message on port I2C
-  MsgoutNmeaIdGrsI2c, 0x209100ce, u8,
+  MsgOutNmeaIdGrsI2c, 0x209100ce, u8,
   /// Output rate of the NMEA-GX-GRS message on port SPI
-  MsgoutNmeaIdGrsSpi, 0x209100d2, u8,
+  MsgOutNmeaIdGrsSpi, 0x209100d2, u8,
   /// Output rate of the NMEA-GX-GRS message on port UART1
-  MsgoutNmeaIdGrsUart1, 0x209100cf, u8,
+  MsgOutNmeaIdGrsUart1, 0x209100cf, u8,
   /// Output rate of the NMEA-GX-GRS message on port UART2
-  MsgoutNmeaIdGrsUart2, 0x209100d0, u8,
+  MsgOutNmeaIdGrsUart2, 0x209100d0, u8,
   /// Output rate of the NMEA-GX-GRS message on port USB
-  MsgoutNmeaIdGrsUsb, 0x209100d1, u8,
+  MsgOutNmeaIdGrsUsb, 0x209100d1, u8,
   /// Output rate of the NMEA-GX-GSA message on port I2C
-  MsgoutNmeaIdGsaI2c, 0x209100bf, u8,
+  MsgOutNmeaIdGsaI2c, 0x209100bf, u8,
   /// Output rate of the NMEA-GX-GSA message on port SPI
-  MsgoutNmeaIdGsaSpi, 0x209100c3, u8,
+  MsgOutNmeaIdGsaSpi, 0x209100c3, u8,
   /// Output rate of the NMEA-GX-GSA message on port UART1
-  MsgoutNmeaIdGsaUart1, 0x209100c0, u8,
+  MsgOutNmeaIdGsaUart1, 0x209100c0, u8,
   /// Output rate of the NMEA-GX-GSA message on port UART2
-  MsgoutNmeaIdGsaUart2, 0x209100c1, u8,
+  MsgOutNmeaIdGsaUart2, 0x209100c1, u8,
   /// Output rate of the NMEA-GX-GSA message on port USB
-  MsgoutNmeaIdGsaUsb, 0x209100c2, u8,
+  MsgOutNmeaIdGsaUsb, 0x209100c2, u8,
   /// Output rate of the NMEA-GX-GST message on port I2C
-  MsgoutNmeaIdGstI2c, 0x209100d3, u8,
+  MsgOutNmeaIdGstI2c, 0x209100d3, u8,
   /// Output rate of the NMEA-GX-GST message on port SPI
-  MsgoutNmeaIdGstSpi, 0x209100d7, u8,
+  MsgOutNmeaIdGstSpi, 0x209100d7, u8,
   /// Output rate of the NMEA-GX-GST message on port UART1
-  MsgoutNmeaIdGstUart1, 0x209100d4, u8,
+  MsgOutNmeaIdGstUart1, 0x209100d4, u8,
   /// Output rate of the NMEA-GX-GST message on port UART2
-  MsgoutNmeaIdGstUart2, 0x209100d5, u8,
+  MsgOutNmeaIdGstUart2, 0x209100d5, u8,
   /// Output rate of the NMEA-GX-GST message on port USB
-  MsgoutNmeaIdGstUsb, 0x209100d6, u8,
+  MsgOutNmeaIdGstUsb, 0x209100d6, u8,
   /// Output rate of the NMEA-GX-GSV message on port I2C
-  MsgoutNmeaIdGsvI2c, 0x209100c4, u8,
+  MsgOutNmeaIdGsvI2c, 0x209100c4, u8,
   /// Output rate of the NMEA-GX-GSV message on port SPI
-  MsgoutNmeaIdGsvSpi, 0x209100c8, u8,
+  MsgOutNmeaIdGsvSpi, 0x209100c8, u8,
   /// Output rate of the NMEA-GX-GSV message on port UART1
-  MsgoutNmeaIdGsvUart1, 0x209100c5, u8,
+  MsgOutNmeaIdGsvUart1, 0x209100c5, u8,
   /// Output rate of the NMEA-GX-GSV message on port UART2
-  MsgoutNmeaIdGsvUart2, 0x209100c6, u8,
+  MsgOutNmeaIdGsvUart2, 0x209100c6, u8,
   /// Output rate of the NMEA-GX-GSV message on port USB
-  MsgoutNmeaIdGsvUsb, 0x209100c7, u8,
+  MsgOutNmeaIdGsvUsb, 0x209100c7, u8,
   /// Output rate of the NMEA-GX-RMC message on port I2C
-  MsgoutNmeaIdRmcI2c, 0x209100ab, u8,
+  MsgOutNmeaIdRmcI2c, 0x209100ab, u8,
   /// Output rate of the NMEA-GX-RMC message on port SPI
-  MsgoutNmeaIdRmcSpi, 0x209100af, u8,
+  MsgOutNmeaIdRmcSpi, 0x209100af, u8,
   /// Output rate of the NMEA-GX-RMC message on port UART1
-  MsgoutNmeaIdRmcUart1, 0x209100ac, u8,
+  MsgOutNmeaIdRmcUart1, 0x209100ac, u8,
   /// Output rate of the NMEA-GX-RMC message on port UART2
-  MsgoutNmeaIdRmcUart2, 0x209100ad, u8,
+  MsgOutNmeaIdRmcUart2, 0x209100ad, u8,
   /// Output rate of the NMEA-GX-RMC message on port USB
-  MsgoutNmeaIdRmcUsb, 0x209100ae, u8,
+  MsgOutNmeaIdRmcUsb, 0x209100ae, u8,
   /// Output rate of the NMEA-GX-VLW message on port I2C
-  MsgoutNmeaIdVlwI2c, 0x209100e7, u8,
+  MsgOutNmeaIdVlwI2c, 0x209100e7, u8,
   /// Output rate of the NMEA-GX-VLW message on port SPI
-  MsgoutNmeaIdVlwSpi, 0x209100eb, u8,
+  MsgOutNmeaIdVlwSpi, 0x209100eb, u8,
   /// Output rate of the NMEA-GX-VLW message on port UART1
-  MsgoutNmeaIdVlwUart1, 0x209100e8, u8,
+  MsgOutNmeaIdVlwUart1, 0x209100e8, u8,
   /// Output rate of the NMEA-GX-VLW message on port UART2
-  MsgoutNmeaIdVlwUart2, 0x209100e9, u8,
+  MsgOutNmeaIdVlwUart2, 0x209100e9, u8,
   /// Output rate of the NMEA-GX-VLW message on port USB
-  MsgoutNmeaIdVlwUsb, 0x209100ea, u8,
+  MsgOutNmeaIdVlwUsb, 0x209100ea, u8,
   /// Output rate of the NMEA-GX-VTG message on port I2C
-  MsgoutNmeaIdVtgI2c, 0x209100b0, u8,
+  MsgOutNmeaIdVtgI2c, 0x209100b0, u8,
   /// Output rate of the NMEA-GX-VTG message on port SPI
-  MsgoutNmeaIdVtgSpi, 0x209100b4, u8,
+  MsgOutNmeaIdVtgSpi, 0x209100b4, u8,
   /// Output rate of the NMEA-GX-VTG message on port UART1
-  MsgoutNmeaIdVtgUart1, 0x209100b1, u8,
+  MsgOutNmeaIdVtgUart1, 0x209100b1, u8,
   /// Output rate of the NMEA-GX-VTG message on port UART2
-  MsgoutNmeaIdVtgUart2, 0x209100b2, u8,
+  MsgOutNmeaIdVtgUart2, 0x209100b2, u8,
   /// Output rate of the NMEA-GX-VTG message on port USB
-  MsgoutNmeaIdVtgUsb, 0x209100b3, u8,
+  MsgOutNmeaIdVtgUsb, 0x209100b3, u8,
   /// Output rate of the NMEA-GX-ZDA message on port I2C
-  MsgoutNmeaIdZdaI2c, 0x209100d8, u8,
+  MsgOutNmeaIdZdaI2c, 0x209100d8, u8,
   /// Output rate of the NMEA-GX-ZDA message on port SPI
-  MsgoutNmeaIdZdaSpi, 0x209100dc, u8,
+  MsgOutNmeaIdZdaSpi, 0x209100dc, u8,
   /// Output rate of the NMEA-GX-ZDA message on port UART1
-  MsgoutNmeaIdZdaUart1, 0x209100d9, u8,
+  MsgOutNmeaIdZdaUart1, 0x209100d9, u8,
   /// Output rate of the NMEA-GX-ZDA message on port UART2
-  MsgoutNmeaIdZdaUart2, 0x209100da, u8,
+  MsgOutNmeaIdZdaUart2, 0x209100da, u8,
   /// Output rate of the NMEA-GX-ZDA message on port USB
-  MsgoutNmeaIdZdaUsb, 0x209100db, u8,
+  MsgOutNmeaIdZdaUsb, 0x209100db, u8,
   /// Output rate of the NMEA-GX-PUBX00 message on port I2C
-  MsgoutPubxIdPolypI2c, 0x209100ec, u8,
+  MsgOutPubxIdPolypI2c, 0x209100ec, u8,
   /// Output rate of the NMEA-GX-PUBX00 message on port SPI
-  MsgoutPubxIdPolypSpi, 0x209100f0, u8,
+  MsgOutPubxIdPolypSpi, 0x209100f0, u8,
   /// Output rate of the NMEA-GX-PUBX00 message on port UART1
-  MsgoutPubxIdPolypUart1, 0x209100ed, u8,
+  MsgOutPubxIdPolypUart1, 0x209100ed, u8,
   /// Output rate of the NMEA-GX-PUBX00 message on port UART2
-  MsgoutPubxIdPolypUart2, 0x209100ee, u8,
+  MsgOutPubxIdPolypUart2, 0x209100ee, u8,
   /// Output rate of the NMEA-GX-PUBX00 message on port USB
-  MsgoutPubxIdPolypUsb, 0x209100ef, u8,
+  MsgOutPubxIdPolypUsb, 0x209100ef, u8,
   /// Output rate of the NMEA-GX-PUBX03 message on port I2C
-  MsgoutPubxIdPolysI2c, 0x209100f1, u8,
+  MsgOutPubxIdPolysI2c, 0x209100f1, u8,
   /// Output rate of the NMEA-GX-PUBX03 message on port SPI
-  MsgoutPubxIdPolysSpi, 0x209100f5, u8,
+  MsgOutPubxIdPolysSpi, 0x209100f5, u8,
   /// Output rate of the NMEA-GX-PUBX03 message on port UART1
-  MsgoutPubxIdPolysUart1, 0x209100f2, u8,
+  MsgOutPubxIdPolysUart1, 0x209100f2, u8,
   /// Output rate of the NMEA-GX-PUBX03 message on port UART2
-  MsgoutPubxIdPolysUart2, 0x209100f3, u8,
+  MsgOutPubxIdPolysUart2, 0x209100f3, u8,
   /// Output rate of the NMEA-GX-PUBX03 message on port USB
-  MsgoutPubxIdPolysUsb, 0x209100f4, u8,
+  MsgOutPubxIdPolysUsb, 0x209100f4, u8,
   /// Output rate of the NMEA-GX-PUBX04 message on port I2C
-  MsgoutPubxIdPolytI2c, 0x209100f6, u8,
+  MsgOutPubxIdPolytI2c, 0x209100f6, u8,
   /// Output rate of the NMEA-GX-PUBX04 message on port SPI
-  MsgoutPubxIdPolytSpi, 0x209100fa, u8,
+  MsgOutPubxIdPolytSpi, 0x209100fa, u8,
   /// Output rate of the NMEA-GX-PUBX04 message on port UART1
-  MsgoutPubxIdPolytUart1, 0x209100f7, u8,
+  MsgOutPubxIdPolytUart1, 0x209100f7, u8,
   /// Output rate of the NMEA-GX-PUBX04 message on port UART2
-  MsgoutPubxIdPolytUart2, 0x209100f8, u8,
+  MsgOutPubxIdPolytUart2, 0x209100f8, u8,
   /// Output rate of the NMEA-GX-PUBX04 message on port USB
-  MsgoutPubxIdPolytUsb, 0x209100f9, u8,
+  MsgOutPubxIdPolytUsb, 0x209100f9, u8,
   /// Output rate of the RTCM-3XTYPE1005 message on port I2C
-  MsgoutRtcm3xType1005I2c, 0x209102bd, u8,
+  MsgOutRtcm3Xtype1005I2c, 0x209102bd, u8,
   /// Output rate of the RTCM-3XTYPE1005 message on port SPI
-  MsgoutRtcm3xType1005Spi, 0x209102c1, u8,
+  MsgOutRtcm3Xtype1005Spi, 0x209102c1, u8,
   /// Output rate of the RTCM-3XTYPE1005 message on port UART1
-  MsgoutRtcm3xType1005Uart1, 0x209102be, u8,
+  MsgOutRtcm3Xtype1005Uart1, 0x209102be, u8,
   /// Output rate of the RTCM-3XTYPE1005 message on port UART2
-  MsgoutRtcm3xType1005Uart2, 0x209102bf, u8,
+  MsgOutRtcm3Xtype1005Uart2, 0x209102bf, u8,
   /// Output rate of the RTCM-3XTYPE1005 message on port USB
-  MsgoutRtcm3xType1005Usb, 0x209102c0, u8,
+  MsgOutRtcm3Xtype1005Usb, 0x209102c0, u8,
   /// Output rate of the RTCM-3XTYPE1074 message on port I2C
-  MsgoutRtcm3xType1074I2c, 0x2091035e, u8,
+  MsgOutRtcm3Xtype1074I2c, 0x2091035e, u8,
   /// Output rate of the RTCM-3XTYPE1074 message on port SPI
-  MsgoutRtcm3xType1074Spi, 0x20910362, u8,
+  MsgOutRtcm3Xtype1074Spi, 0x20910362, u8,
   /// Output rate of the RTCM-3XTYPE1074 message on port UART1
-  MsgoutRtcm3xType1074Uart1, 0x2091035f, u8,
+  MsgOutRtcm3Xtype1074Uart1, 0x2091035f, u8,
   /// Output rate of the RTCM-3XTYPE1074 message on port UART2
-  MsgoutRtcm3xType1074Uart2, 0x20910360, u8,
+  MsgOutRtcm3Xtype1074Uart2, 0x20910360, u8,
   /// Output rate of the RTCM-3XTYPE1074 message on port USB
-  MsgoutRtcm3xType1074Usb, 0x20910361, u8,
+  MsgOutRtcm3Xtype1074Usb, 0x20910361, u8,
   /// Output rate of the RTCM-3XTYPE1077 message on port I2C
-  MsgoutRtcm3xType1077I2c, 0x209102cc, u8,
+  MsgOutRtcm3Xtype1077I2c, 0x209102cc, u8,
   /// Output rate of the RTCM-3XTYPE1077 message on port SPI
-  MsgoutRtcm3xType1077Spi, 0x209102d0, u8,
+  MsgOutRtcm3Xtype1077Spi, 0x209102d0, u8,
   /// Output rate of the RTCM-3XTYPE1077 message on port UART1
-  MsgoutRtcm3xType1077Uart1, 0x209102cd, u8,
+  MsgOutRtcm3Xtype1077Uart1, 0x209102cd, u8,
   /// Output rate of the RTCM-3XTYPE1077 message on port UART2
-  MsgoutRtcm3xType1077Uart2, 0x209102ce, u8,
+  MsgOutRtcm3Xtype1077Uart2, 0x209102ce, u8,
   /// Output rate of the RTCM-3XTYPE1077 message on port USB
-  MsgoutRtcm3xType1077Usb, 0x209102cf, u8,
+  MsgOutRtcm3Xtype1077Usb, 0x209102cf, u8,
   /// Output rate of the RTCM-3XTYPE1084 message on port I2C
-  MsgoutRtcm3xType1084I2c, 0x20910363, u8,
+  MsgOutRtcm3Xtype1084I2c, 0x20910363, u8,
   /// Output rate of the RTCM-3XTYPE1084 message on port SPI
-  MsgoutRtcm3xType1084Spi, 0x20910367, u8,
+  MsgOutRtcm3Xtype1084Spi, 0x20910367, u8,
   /// Output rate of the RTCM-3XTYPE1084 message on port UART1
-  MsgoutRtcm3xType1084Uart1, 0x20910364, u8,
+  MsgOutRtcm3Xtype1084Uart1, 0x20910364, u8,
   /// Output rate of the RTCM-3XTYPE1084 message on port UART2
-  MsgoutRtcm3xType1084Uart2, 0x20910365, u8,
+  MsgOutRtcm3Xtype1084Uart2, 0x20910365, u8,
   /// Output rate of the RTCM-3XTYPE1084 message on port USB
-  MsgoutRtcm3xType1084Usb, 0x20910366, u8,
+  MsgOutRtcm3Xtype1084Usb, 0x20910366, u8,
   /// Output rate of the RTCM-3XTYPE1087 message on port I2C
-  MsgoutRtcm3xType1087I2c, 0x209102d1, u8,
+  MsgOutRtcm3Xtype1087I2c, 0x209102d1, u8,
   /// Output rate of the RTCM-3XTYPE1087 message on port SPI
-  MsgoutRtcm3xType1087Spi, 0x209102d5, u8,
+  MsgOutRtcm3Xtype1087Spi, 0x209102d5, u8,
   /// Output rate of the RTCM-3XTYPE1087 message on port UART1
-  MsgoutRtcm3xType1087Uart1, 0x209102d2, u8,
+  MsgOutRtcm3Xtype1087Uart1, 0x209102d2, u8,
   /// Output rate of the RTCM-3XTYPE1087 message on port UART2
-  MsgoutRtcm3xType1087Uart2, 0x209102d3, u8,
+  MsgOutRtcm3Xtype1087Uart2, 0x209102d3, u8,
   /// Output rate of the RTCM-3XTYPE1087 message on port USB
-  MsgoutRtcm3xType1087Usb, 0x209102d4, u8,
+  MsgOutRtcm3Xtype1087Usb, 0x209102d4, u8,
   /// Output rate of the RTCM-3XTYPE1094 message on port I2C
-  MsgoutRtcm3xType1094I2c, 0x20910368, u8,
+  MsgOutRtcm3Xtype1094I2c, 0x20910368, u8,
   /// Output rate of the RTCM-3XTYPE1094 message on port SPI
-  MsgoutRtcm3xType1094Spi, 0x2091036c, u8,
+  MsgOutRtcm3Xtype1094Spi, 0x2091036c, u8,
   /// Output rate of the RTCM-3XTYPE1094 message on port UART1
-  MsgoutRtcm3xType1094Uart1, 0x20910369, u8,
+  MsgOutRtcm3Xtype1094Uart1, 0x20910369, u8,
   /// Output rate of the RTCM-3XTYPE1094 message on port UART2
-  MsgoutRtcm3xType1094Uart2, 0x2091036a, u8,
+  MsgOutRtcm3Xtype1094Uart2, 0x2091036a, u8,
   /// Output rate of the RTCM-3XTYPE1094 message on port USB
-  MsgoutRtcm3xType1094Usb, 0x2091036b, u8,
+  MsgOutRtcm3Xtype1094Usb, 0x2091036b, u8,
   /// Output rate of the RTCM-3XTYPE1097 message on port I2C
-  MsgoutRtcm3xType1097I2c, 0x20910318, u8,
+  MsgOutRtcm3Xtype1097I2c, 0x20910318, u8,
   /// Output rate of the RTCM-3XTYPE1097 message on port SPI
-  MsgoutRtcm3xType1097Spi, 0x2091031c, u8,
+  MsgOutRtcm3Xtype1097Spi, 0x2091031c, u8,
   /// Output rate of the RTCM-3XTYPE1097 message on port UART1
-  MsgoutRtcm3xType1097Uart1, 0x20910319, u8,
+  MsgOutRtcm3Xtype1097Uart1, 0x20910319, u8,
   /// Output rate of the RTCM-3XTYPE1097 message on port UART2
-  MsgoutRtcm3xType1097Uart2, 0x2091031a, u8,
+  MsgOutRtcm3Xtype1097Uart2, 0x2091031a, u8,
   /// Output rate of the RTCM-3XTYPE1097 message on port USB
-  MsgoutRtcm3xType1097Usb, 0x2091031b, u8,
+  MsgOutRtcm3Xtype1097Usb, 0x2091031b, u8,
   /// Output rate of the RTCM-3XTYPE1124 message on port I2C
-  MsgoutRtcm3xType1124I2c, 0x2091036d, u8,
+  MsgOutRtcm3Xtype1124I2c, 0x2091036d, u8,
   /// Output rate of the RTCM-3XTYPE1124 message on port SPI
-  MsgoutRtcm3xType1124Spi, 0x20910371, u8,
+  MsgOutRtcm3Xtype1124Spi, 0x20910371, u8,
   /// Output rate of the RTCM-3XTYPE1124 message on port UART1
-  MsgoutRtcm3xType1124Uart1, 0x2091036e, u8,
+  MsgOutRtcm3Xtype1124Uart1, 0x2091036e, u8,
   /// Output rate of the RTCM-3XTYPE1124 message on port UART2
-  MsgoutRtcm3xType1124Uart2, 0x2091036f, u8,
+  MsgOutRtcm3Xtype1124Uart2, 0x2091036f, u8,
   /// Output rate of the RTCM-3XTYPE1124 message on port USB
-  MsgoutRtcm3xType1124Usb, 0x20910370, u8,
+  MsgOutRtcm3Xtype1124Usb, 0x20910370, u8,
   /// Output rate of the RTCM-3XTYPE1127 message on port I2C
-  MsgoutRtcm3xType1127I2c, 0x209102d6, u8,
+  MsgOutRtcm3Xtype1127I2c, 0x209102d6, u8,
   /// Output rate of the RTCM-3XTYPE1127 message on port SPI
-  MsgoutRtcm3xType1127Spi, 0x209102da, u8,
+  MsgOutRtcm3Xtype1127Spi, 0x209102da, u8,
   /// Output rate of the RTCM-3XTYPE1127 message on port UART1
-  MsgoutRtcm3xType1127Uart1, 0x209102d7, u8,
+  MsgOutRtcm3Xtype1127Uart1, 0x209102d7, u8,
   /// Output rate of the RTCM-3XTYPE1127 message on port UART2
-  MsgoutRtcm3xType1127Uart2, 0x209102d8, u8,
+  MsgOutRtcm3Xtype1127Uart2, 0x209102d8, u8,
   /// Output rate of the RTCM-3XTYPE1127 message on port USB
-  MsgoutRtcm3xType1127Usb, 0x209102d9, u8,
+  MsgOutRtcm3Xtype1127Usb, 0x209102d9, u8,
   /// Output rate of the RTCM-3XTYPE1230 message on port I2C
-  MsgoutRtcm3xType1230I2c, 0x20910303, u8,
+  MsgOutRtcm3Xtype1230I2c, 0x20910303, u8,
   /// Output rate of the RTCM-3XTYPE1230 message on port SPI
-  MsgoutRtcm3xType1230Spi, 0x20910307, u8,
+  MsgOutRtcm3Xtype1230Spi, 0x20910307, u8,
   /// Output rate of the RTCM-3XTYPE1230 message on port UART1
-  MsgoutRtcm3xType1230Uart1, 0x20910304, u8,
+  MsgOutRtcm3Xtype1230Uart1, 0x20910304, u8,
   /// Output rate of the RTCM-3XTYPE1230 message on port UART2
-  MsgoutRtcm3xType1230Uart2, 0x20910305, u8,
+  MsgOutRtcm3Xtype1230Uart2, 0x20910305, u8,
   /// Output rate of the RTCM-3XTYPE1230 message on port USB
-  MsgoutRtcm3xType1230Usb, 0x20910306, u8,
+  MsgOutRtcm3Xtype1230Usb, 0x20910306, u8,
+  /// Output rate of the RTCM-3XTYPE4072_0 message on port I2C
+  MsgOutRtcm3Xtype40720I2c, 0x209102fe, u8,
+  /// Output rate of the RTCM-3XTYPE4072_0 message on port SPI
+  MsgOutRtcm3Xtype40720Spi, 0x20910302, u8,
+  /// Output rate of the RTCM-3XTYPE4072_0 message on port UART1
+  MsgOutRtcm3Xtype40720Uart1, 0x209102ff, u8,
+  /// Output rate of the RTCM-3XTYPE4072_0 message on port UART2
+  MsgOutRtcm3Xtype40720Uart2, 0x20910300, u8,
+  /// Output rate of the RTCM-3XTYPE4072_0 message on port USB
+  MsgOutRtcm3Xtype40720Usb, 0x20910301, u8,
+  /// Output rate of the RTCM-3XTYPE4072_1 message on port I2C
+  MsgOutRtcm3Xtype40721I2c, 0x20910381, u8,
+  /// Output rate of the RTCM-3XTYPE4072_1 message on port SPI
+  MsgOutRtcm3Xtype40721Spi, 0x20910385, u8,
+  /// Output rate of the RTCM-3XTYPE4072_1 message on port UART1
+  MsgOutRtcm3Xtype40721Uart1, 0x20910382, u8,
+  /// Output rate of the RTCM-3XTYPE4072_1 message on port UART2
+  MsgOutRtcm3Xtype40721Uart2, 0x20910383, u8,
+  /// Output rate of the RTCM-3XTYPE4072_1 message on port USB
+  MsgOutRtcm3Xtype40721Usb, 0x20910384, u8,
+
   /// Output rate of the UBX-LOG-INFO message on port I2C
-  MsgoutUbxLogInfoI2c, 0x20910259, u8,
+  MsgOutUbxLogInfoI2c, 0x20910259, u8,
   /// Output rate of the UBX-LOG-INFO message on port SPI
-  MsgoutUbxLogInfoSpi, 0x2091025d, u8,
+  MsgOutUbxLogInfoSpi, 0x2091025d, u8,
   /// Output rate of the UBX-LOG-INFO message on port UART1
-  MsgoutUbxLogInfoUart1, 0x2091025a, u8,
+  MsgOutUbxLogInfoUart1, 0x2091025a, u8,
   /// Output rate of the UBX-LOG-INFO message on port UART2
-  MsgoutUbxLogInfoUart2, 0x2091025b, u8,
+  MsgOutUbxLogInfoUart2, 0x2091025b, u8,
   /// Output rate of the UBX-LOG-INFO message on port USB
-  MsgoutUbxLogInfoUsb, 0x2091025c, u8,
+  MsgOutUbxLogInfoUsb, 0x2091025c, u8,
   /// Output rate of the UBX-MONCOMMS message on port I2C
-  MsgoutUbxMonCommsI2c, 0x2091034f, u8,
+  MsgOutUbxMoncommsI2c, 0x2091034f, u8,
   /// Output rate of the UBX-MONCOMMS message on port SPI
-  MsgoutUbxMonCommsSpi, 0x20910353, u8,
+  MsgOutUbxMoncommsSpi, 0x20910353, u8,
   /// Output rate of the UBX-MONCOMMS message on port UART1
-  MsgoutUbxMonCommsUart1, 0x20910350, u8,
+  MsgOutUbxMoncommsUart1, 0x20910350, u8,
   /// Output rate of the UBX-MONCOMMS message on port UART2
-  MsgoutUbxMonCommsUart2, 0x20910351, u8,
+  MsgOutUbxMoncommsUart2, 0x20910351, u8,
   /// Output rate of the UBX-MONCOMMS message on port USB
-  MsgoutUbxMonCommsUsb, 0x20910352, u8,
+  MsgOutUbxMoncommsUsb, 0x20910352, u8,
   /// Output rate of the UBX-MON-HW2 message on port I2C
-  MsgoutUbxMonHw2I2c, 0x209101b9, u8,
+  MsgOutUbxMonHw2I2c, 0x209101b9, u8,
   /// Output rate of the UBX-MON-HW2 message on port SPI
-  MsgoutUbxMonHw2Spi, 0x209101bd, u8,
+  MsgOutUbxMonHw2Spi, 0x209101bd, u8,
   /// Output rate of the UBX-MON-HW2 message on port UART1
-  MsgoutUbxMonHw2Uart1, 0x209101ba, u8,
+  MsgOutUbxMonHw2Uart1, 0x209101ba, u8,
   /// Output rate of the UBX-MON-HW2 message on port UART2
-  MsgoutUbxMonHw2Uart2, 0x209101bb, u8,
+  MsgOutUbxMonHw2Uart2, 0x209101bb, u8,
   /// Output rate of the UBX-MON-HW2 message on port USB
-  MsgoutUbxMonHw2Usb, 0x209101bc, u8,
+  MsgOutUbxMonHw2Usb, 0x209101bc, u8,
   /// Output rate of the UBX-MON-HW3 message on port I2C
-  MsgoutUbxMonHw3I2c, 0x20910354, u8,
+  MsgOutUbxMonHw3I2c, 0x20910354, u8,
   /// Output rate of the UBX-MON-HW3 message on port SPI
-  MsgoutUbxMonHw3Spi, 0x20910358, u8,
+  MsgOutUbxMonHw3Spi, 0x20910358, u8,
   /// Output rate of the UBX-MON-HW3 message on port UART1
-  MsgoutUbxMonHw3Uart1, 0x20910355, u8,
+  MsgOutUbxMonHw3Uart1, 0x20910355, u8,
   /// Output rate of the UBX-MON-HW3 message on port UART2
-  MsgoutUbxMonHw3Uart2, 0x20910356, u8,
+  MsgOutUbxMonHw3Uart2, 0x20910356, u8,
   /// Output rate of the UBX-MON-HW3 message on port USB
-  MsgoutUbxMonHw3Usb, 0x20910357, u8,
+  MsgOutUbxMonHw3Usb, 0x20910357, u8,
   /// Output rate of the UBX-MON-HW message on port I2C
-  MsgoutUbxMonHwI2c, 0x209101b4, u8,
+  MsgOutUbxMonHwI2c, 0x209101b4, u8,
   /// Output rate of the UBX-MON-HW message on port SPI
-  MsgoutUbxMonHwSpi, 0x209101b8, u8,
+  MsgOutUbxMonHwSpi, 0x209101b8, u8,
   /// Output rate of the UBX-MON-HW message on port UART1
-  MsgoutUbxMonHwUart1, 0x209101b5, u8,
+  MsgOutUbxMonHwUart1, 0x209101b5, u8,
   /// Output rate of the UBX-MON-HW message on port UART2
-  MsgoutUbxMonHwUart2, 0x209101b6, u8,
+  MsgOutUbxMonHwUart2, 0x209101b6, u8,
   /// Output rate of the UBX-MON-HW message on port USB
-  MsgoutUbxMonHwUsb, 0x209101b7, u8,
+  MsgOutUbxMonHwUsb, 0x209101b7, u8,
   /// Output rate of the UBX-MON-IO message on port I2C
-  MsgoutUbxMonIoI2c, 0x209101a5, u8,
+  MsgOutUbxMonIoI2c, 0x209101a5, u8,
   /// Output rate of the UBX-MON-IO message on port SPI
-  MsgoutUbxMonIoSpi, 0x209101a9, u8,
+  MsgOutUbxMonIoSpi, 0x209101a9, u8,
   /// Output rate of the UBX-MON-IO message on port UART1
-  MsgoutUbxMonIoUart1, 0x209101a6, u8,
+  MsgOutUbxMonIoUart1, 0x209101a6, u8,
   /// Output rate of the UBX-MON-IO message on port UART2
-  MsgoutUbxMonIoUart2, 0x209101a7, u8,
+  MsgOutUbxMonIoUart2, 0x209101a7, u8,
   /// Output rate of the UBX-MON-IO message on port USB
-  MsgoutUbxMonIoUsb, 0x209101a8, u8,
+  MsgOutUbxMonIoUsb, 0x209101a8, u8,
   /// Output rate of the UBX-MON-MSGPP message on port I2C
-  MsgoutUbxMonMsgPpI2c, 0x20910196, u8,
+  MsgOutUbxMonMsgppI2c, 0x20910196, u8,
   /// Output rate of the UBX-MON-MSGPP message on port SPI
-  MsgoutUbxMonMsgPpSpi, 0x2091019a, u8,
+  MsgOutUbxMonMsgppSpi, 0x2091019a, u8,
   /// Output rate of the UBX-MON-MSGPP message on port UART1
-  MsgoutUbxMonMsgPpUart1, 0x20910197, u8,
+  MsgOutUbxMonMsgppUart1, 0x20910197, u8,
   /// Output rate of the UBX-MON-MSGPP message on port UART2
-  MsgoutUbxMonMsgPpUart2, 0x20910198, u8,
+  MsgOutUbxMonMsgppUart2, 0x20910198, u8,
   /// Output rate of the UBX-MON-MSGPP message on port USB
-  MsgoutUbxMonMsgPpUsb, 0x20910199, u8,
+  MsgOutUbxMonMsgppUsb, 0x20910199, u8,
   /// Output rate of the UBX-MON-RF message on port I2C
-  MsgoutUbxMonRfI2c, 0x20910359, u8,
+  MsgOutUbxMonRfI2c, 0x20910359, u8,
   /// Output rate of the UBX-MON-RF message on port SPI
-  MsgoutUbxMonRfSpi, 0x2091035d, u8,
+  MsgOutUbxMonRfSpi, 0x2091035d, u8,
   /// Output rate of the UBX-MON-RF message on port UART1
-  MsgoutUbxMonRfUart1, 0x2091035a, u8,
+  MsgOutUbxMonRfUart1, 0x2091035a, u8,
   /// Output rate of the UBX-MON-RF message on port UART2
-  MsgoutUbxMonRfUart2, 0x2091035b, u8,
+  MsgOutUbxMonRfUart2, 0x2091035b, u8,
   /// Output rate of the UBX-MON-RF message on port USB
-  MsgoutUbxMonRfUsb, 0x2091035c, u8,
+  MsgOutUbxMonRfUsb, 0x2091035c, u8,
   /// Output rate of the UBX-MON-RXBUF message on port I2C
-  MsgoutUbxMonRxbufI2c, 0x209101a0, u8,
+  MsgOutUbxMonRxbufI2c, 0x209101a0, u8,
   /// Output rate of the UBX-MON-RXBUF message on port SPI
-  MsgoutUbxMonRxbufSpi, 0x209101a4, u8,
+  MsgOutUbxMonRxbufSpi, 0x209101a4, u8,
   /// Output rate of the UBX-MON-RXBUF message on port UART1
-  MsgoutUbxMonRxbufUart1, 0x209101a1, u8,
+  MsgOutUbxMonRxbufUart1, 0x209101a1, u8,
   /// Output rate of the UBX-MON-RXBUF message on port UART2
-  MsgoutUbxMonRxbufUart2, 0x209101a2, u8,
+  MsgOutUbxMonRxbufUart2, 0x209101a2, u8,
   /// Output rate of the UBX-MON-RXBUF message on port USB
-  MsgoutUbxMonRxbufUsb, 0x209101a3, u8,
+  MsgOutUbxMonRxbufUsb, 0x209101a3, u8,
   /// Output rate of the UBX-MON-RXR message on port I2C
-  MsgoutUbxMonRxrI2c, 0x20910187, u8,
+  MsgOutUbxMonRxrI2c, 0x20910187, u8,
   /// Output rate of the UBX-MON-RXR message on port SPI
-  MsgoutUbxMonRxrSpi, 0x2091018b, u8,
+  MsgOutUbxMonRxrSpi, 0x2091018b, u8,
   /// Output rate of the UBX-MON-RXR message on port UART1
-  MsgoutUbxMonRxrUart1, 0x20910188, u8,
+  MsgOutUbxMonRxrUart1, 0x20910188, u8,
   /// Output rate of the UBX-MON-RXR message on port UART2
-  MsgoutUbxMonRxrUart2, 0x20910189, u8,
+  MsgOutUbxMonRxrUart2, 0x20910189, u8,
   /// Output rate of the UBX-MON-RXR message on port USB
-  MsgoutUbxMonRxrUsb, 0x2091018a, u8,
+  MsgOutUbxMonRxrUsb, 0x2091018a, u8,
   /// Output rate of the UBX-MON-TXBUF message on port I2C
-  MsgoutUbxMonTxbufI2c, 0x2091019b, u8,
+  MsgOutUbxMonTxbufI2c, 0x2091019b, u8,
   /// Output rate of the UBX-MON-TXBUF message on port SPI
-  MsgoutUbxMonTxbufSpi, 0x2091019f, u8,
+  MsgOutUbxMonTxbufSpi, 0x2091019f, u8,
   /// Output rate of the UBX-MON-TXBUF message on port UART1
-  MsgoutUbxMonTxbufUart1, 0x2091019c, u8,
+  MsgOutUbxMonTxbufUart1, 0x2091019c, u8,
   /// Output rate of the UBX-MON-TXBUF message on port UART2
-  MsgoutUbxMonTxbufUart2, 0x2091019d, u8,
+  MsgOutUbxMonTxbufUart2, 0x2091019d, u8,
   /// Output rate of the UBX-MON-TXBUF message on port USB
-  MsgoutUbxMonTxbufUsb, 0x2091019e, u8,
+  MsgOutUbxMonTxbufUsb, 0x2091019e, u8,
   /// Output rate of the UBX-NAV-CLOCK message on port I2C
-  MsgoutUbxNavClockI2c, 0x20910065, u8,
+  MsgOutUbxNavClockI2c, 0x20910065, u8,
   /// Output rate of the UBX-NAV-CLOCK message on port SPI
-  MsgoutUbxNavClockSpi, 0x20910069, u8,
+  MsgOutUbxNavClockSpi, 0x20910069, u8,
   /// Output rate of the UBX-NAV-CLOCK message on port UART1
-  MsgoutUbxNavClockUart1, 0x20910066, u8,
+  MsgOutUbxNavClockUart1, 0x20910066, u8,
   /// Output rate of the UBX-NAV-CLOCK message on port UART2
-  MsgoutUbxNavClockUart2, 0x20910067, u8,
+  MsgOutUbxNavClockUart2, 0x20910067, u8,
   /// Output rate of the UBX-NAV-CLOCK message on port USB
-  MsgoutUbxNavClockUsb, 0x20910068, u8,
+  MsgOutUbxNavClockUsb, 0x20910068, u8,
   /// Output rate of the UBX-NAV-DOP message on port I2C
-  MsgoutUbxNavDopI2c, 0x20910038, u8,
+  MsgOutUbxNavDopI2c, 0x20910038, u8,
   /// Output rate of the UBX-NAV-DOP message on port SPI
-  MsgoutUbxNavDopSpi, 0x2091003c, u8,
+  MsgOutUbxNavDopSpi, 0x2091003c, u8,
   /// Output rate of the UBX-NAV-DOP message on port UART1
-  MsgoutUbxNavDopUart1, 0x20910039, u8,
+  MsgOutUbxNavDopUart1, 0x20910039, u8,
   /// Output rate of the UBX-NAV-DOP message on port UART2
-  MsgoutUbxNavDopUart2, 0x2091003a, u8,
+  MsgOutUbxNavDopUart2, 0x2091003a, u8,
   /// Output rate of the UBX-NAV-DOP message on port USB
-  MsgoutUbxNavDopUsb, 0x2091003b, u8,
+  MsgOutUbxNavDopUsb, 0x2091003b, u8,
   /// Output rate of the UBX-NAV-EOE message on port I2C
-  MsgoutUbxNavEoeI2c, 0x2091015f, u8,
+  MsgOutUbxNavEoeI2c, 0x2091015f, u8,
   /// Output rate of the UBX-NAV-EOE message on port SPI
-  MsgoutUbxNavEoeSpi, 0x20910163, u8,
+  MsgOutUbxNavEoeSpi, 0x20910163, u8,
   /// Output rate of the UBX-NAV-EOE message on port UART1
-  MsgoutUbxNavEoeUart1, 0x20910160, u8,
+  MsgOutUbxNavEoeUart1, 0x20910160, u8,
   /// Output rate of the UBX-NAV-EOE message on port UART2
-  MsgoutUbxNavEoeUart2, 0x20910161, u8,
+  MsgOutUbxNavEoeUart2, 0x20910161, u8,
   /// Output rate of the UBX-NAV-EOE message on port USB
-  MsgoutUbxNavEoeUsb, 0x20910162, u8,
+  MsgOutUbxNavEoeUsb, 0x20910162, u8,
   /// Output rate of the UBX-NAVGEOFENCE message on port I2C
-  MsgoutUbxNavGeofenceI2c, 0x209100a1, u8,
+  MsgOutUbxNavGeofenceI2c, 0x209100a1, u8,
   /// Output rate of the UBX-NAVGEOFENCE message on port SPI
-  MsgoutUbxNavGeofenceSpi, 0x209100a5, u8,
+  MsgOutUbxNavGeofenceSpi, 0x209100a5, u8,
   /// Output rate of the UBX-NAVGEOFENCE message on port UART1
-  MsgoutUbxNavGeofenceUart1, 0x209100a2, u8,
+  MsgOutUbxNavGeofenceUart1, 0x209100a2, u8,
   /// Output rate of the UBX-NAVGEOFENCE message on port UART2
-  MsgoutUbxNavGeofenceUart2, 0x209100a3, u8,
+  MsgOutUbxNavGeofenceUart2, 0x209100a3, u8,
   /// Output rate of the UBX-NAVGEOFENCE message on port USB
-  MsgoutUbxNavGeofenceUsb, 0x209100a4, u8,
+  MsgOutUbxNavGeofenceUsb, 0x209100a4, u8,
   /// Output rate of the UBX-NAVHPPOSECEF message on port I2C
-  MsgoutUbxNavHpPosEcefI2c, 0x2091002e, u8,
+  MsgOutUbxNavHpPosEcefI2c, 0x2091002e, u8,
   /// Output rate of the UBX-NAVHPPOSECEF message on port SPI
-  MsgoutUbxNavHpPosEcefSpi, 0x20910032, u8,
+  MsgOutUbxNavHpPosEcefSpi, 0x20910032, u8,
   /// Output rate of the UBX-NAVHPPOSECEF message on port UART1
-  MsgoutUbxNavHpPosEcefUart1, 0x2091002f, u8,
+  MsgOutUbxNavHpPosEcefUart1, 0x2091002f, u8,
   /// Output rate of the UBX-NAVHPPOSECEF message on port UART2
-  MsgoutUbxNavHpPosEcefUart2, 0x20910030, u8,
+  MsgOutUbxNavHpPosEcefUart2, 0x20910030, u8,
   /// Output rate of the UBX-NAVHPPOSECEF message on port USB
-  MsgoutUbxNavHpPosEcefUsb, 0x20910031, u8,
+  MsgOutUbxNavHpPosEcefUsb, 0x20910031, u8,
   /// Output rate of the UBX-NAVHPPOSLLH message on port I2C
-  MsgoutUbxNavHpPosllhI2c, 0x20910033, u8,
+  MsgOutUbxNavHpPosLlhI2c, 0x20910033, u8,
   /// Output rate of the UBX-NAVHPPOSLLH message on port SPI
-  MsgoutUbxNavHpPosllhSpi, 0x20910037, u8,
+  MsgOutUbxNavHpPosLlhSpi, 0x20910037, u8,
   /// Output rate of the UBX-NAVHPPOSLLH message on port UART1
-  MsgoutUbxNavHpPosllhUart1, 0x20910034, u8,
+  MsgOutUbxNavHpPosLlhUart1, 0x20910034, u8,
   /// Output rate of the UBX-NAVHPPOSLLH message on port UART2
-  MsgoutUbxNavHpPosllhUart2, 0x20910035, u8,
+  MsgOutUbxNavHpPosLlhUart2, 0x20910035, u8,
   /// Output rate of the UBX-NAVHPPOSLLH message on port USB
-  MsgoutUbxNavHpPosllhUsb, 0x20910036, u8,
+  MsgOutUbxNavHpPosLlhUsb, 0x20910036, u8,
   /// Output rate of the UBX-NAV-ODO message on port I2C
-  MsgoutUbxNavOdoI2c, 0x2091007e, u8,
+  MsgOutUbxNavOdoI2C, 0x2091007e, u8,
   /// Output rate of the UBX-NAV-ODO message on port SPI
-  MsgoutUbxNavOdoSpi, 0x20910082, u8,
+  MsgOutUbxNavOdoSpi, 0x20910082, u8,
   /// Output rate of the UBX-NAV-ODO message on port UART1
-  MsgoutUbxNavOdoUart1, 0x2091007f, u8,
+  MsgOutUbxNavOdoUart1, 0x2091007f, u8,
   /// Output rate of the UBX-NAV-ODO message on port UART2
-  MsgoutUbxNavOdoUart2, 0x20910080, u8,
+  MsgOutUbxNavOdoUart2, 0x20910080, u8,
   /// Output rate of the UBX-NAV-ODO message on port USB
-  MsgoutUbxNavOdoUsb, 0x20910081, u8,
+  MsgOutUbxNavOdoUsb, 0x20910081, u8,
   /// Output rate of the UBX-NAV-ORB message on port I2C
-  MsgoutUbxNavOrbI2c, 0x20910010, u8,
+  MsgOutUbxNavOrbI2c, 0x20910010, u8,
   /// Output rate of the UBX-NAV-ORB message on port SPI
-  MsgoutUbxNavOrbSpi, 0x20910014, u8,
+  MsgOutUbxNavOrbSpi, 0x20910014, u8,
   /// Output rate of the UBX-NAV-ORB message on port UART1
-  MsgoutUbxNavOrbUart1, 0x20910011, u8,
+  MsgOutUbxNavOrbUart1, 0x20910011, u8,
   /// Output rate of the UBX-NAV-ORB message on port UART2
-  MsgoutUbxNavOrbUart2, 0x20910012, u8,
+  MsgOutUbxNavOrbUart2, 0x20910012, u8,
   /// Output rate of the UBX-NAV-ORB message on port USB
-  MsgoutUbxNavOrbUsb, 0x20910013, u8,
+  MsgOutUbxNavOrbUsb, 0x20910013, u8,
   /// Output rate of the UBX-NAV-POSECEF message on port I2C
-  MsgoutUbxNavPosEcefI2c, 0x20910024, u8,
+  MsgOutUbxNavPosEcefI2c, 0x20910024, u8,
   /// Output rate of the UBX-NAV-POSECEF message on port SPI
-  MsgoutUbxNavPosEcefSpi, 0x20910028, u8,
+  MsgOutUbxNavPosEcefSpi, 0x20910028, u8,
   /// Output rate of the UBX-NAV-POSECEF message on port UART1
-  MsgoutUbxNavPosEcefUart1, 0x20910025, u8,
+  MsgOutUbxNavPosEcefUart1, 0x20910025, u8,
   /// Output rate of the UBX-NAV-POSECEF message on port UART2
-  MsgoutUbxNavPosEcefUart2, 0x20910026, u8,
+  MsgOutUbxNavPosEcefUart2, 0x20910026, u8,
   /// Output rate of the UBX-NAV-POSECEF message on port USB
-  MsgoutUbxNavPosEcefUsb, 0x20910027, u8,
+  MsgOutUbxNavPosEcefUsb, 0x20910027, u8,
   /// Output rate of the UBX-NAV-POSLLH message on port I2C
-  MsgoutUbxNavPosLlhI2c, 0x20910029, u8,
+  MsgOutUbxNavPosLlhI2c, 0x20910029, u8,
   /// Output rate of the UBX-NAV-POSLLH message on port SPI
-  MsgoutUbxNavPosLlhSpi, 0x2091002d, u8,
+  MsgOutUbxNavPosLlhSpi, 0x2091002d, u8,
   /// Output rate of the UBX-NAV-POSLLH message on port UART1
-  MsgoutUbxNavPosLlhUart1, 0x2091002a, u8,
+  MsgOutUbxNavPosLlhUart1, 0x2091002a, u8,
   /// Output rate of the UBX-NAV-POSLLH message on port UART2
-  MsgoutUbxNavPosLlhUart2, 0x2091002b, u8,
+  MsgOutUbxNavPosLlhUart2, 0x2091002b, u8,
   /// Output rate of the UBX-NAV-POSLLH message on port USB
-  MsgoutUbxNavPosLlhUsb, 0x2091002c, u8,
+  MsgOutUbxNavPosLlhUsb, 0x2091002c, u8,
   /// Output rate of the UBX-NAV-PVT message on port I2C
-  MsgoutUbxNavPvtI2c, 0x20910006, u8,
+  MsgOutUbxNavPvtI2c, 0x20910006, u8,
   /// Output rate of the UBX-NAV-PVT message on port SPI
-  MsgoutUbxNavPvtSpi, 0x2091000a, u8,
+  MsgOutUbxNavPvtSpi, 0x2091000a, u8,
   /// Output rate of the UBX-NAV-PVT message on port UART1
-  MsgoutUbxNavPvtUart1, 0x20910007, u8,
+  MsgOutUbxNavPvtUart1, 0x20910007, u8,
   /// Output rate of the UBX-NAV-PVT message on port UART2
-  MsgoutUbxNavPvtUart2, 0x20910008, u8,
+  MsgOutUbxNavPvtUart2, 0x20910008, u8,
   /// Output rate of the UBX-NAV-PVT message on port USB
-  MsgoutUbxNavPvtUsb, 0x20910009, u8,
+  MsgOutUbxNavPvtUsb, 0x20910009, u8,
   /// Output rate of the UBX-NAVRELPOSNED message on port I2C
-  MsgoutUbxNavRelposnedI2c, 0x2091008d, u8,
+  MsgOutUbxNavRelposNedI2c, 0x2091008d, u8,
   /// Output rate of the UBX-NAVRELPOSNED message on port SPI
-  MsgoutUbxNavRelposnedSpi, 0x20910091, u8,
+  MsgOutUbxNavRelposNedSpi, 0x20910091, u8,
   /// Output rate of the UBX-NAVRELPOSNED message on port UART1
-  MsgoutUbxNavRelposnedUart1, 0x2091008e, u8,
+  MsgOutUbxNavRelposNedUart1, 0x2091008e, u8,
   /// Output rate of the UBX-NAVRELPOSNED message on port UART2
-  MsgoutUbxNavRelposnedUart2, 0x2091008f, u8,
+  MsgOutUbxNavRelposNedUart2, 0x2091008f, u8,
   /// Output rate of the UBX-NAVRELPOSNED message on port USB
-  MsgoutUbxNavRelposnedUsb, 0x20910090, u8,
+  MsgOutUbxNavRelposNedUsb, 0x20910090, u8,
   /// Output rate of the UBX-NAV-SAT message on port I2C
-  MsgoutUbxNavSatI2c, 0x20910015, u8,
+  MsgOutUbxNavSatI2c, 0x20910015, u8,
   /// Output rate of the UBX-NAV-SAT message on port SPI
-  MsgoutUbxNavSatSpi, 0x20910019, u8,
+  MsgOutUbxNavSatSpi, 0x20910019, u8,
   /// Output rate of the UBX-NAV-SAT message on port UART1
-  MsgoutUbxNavSatUart1, 0x20910016, u8,
+  MsgOutUbxNavSatUart1, 0x20910016, u8,
   /// Output rate of the UBX-NAV-SAT message on port UART2
-  MsgoutUbxNavSatUart2, 0x20910017, u8,
+  MsgOutUbxNavSatUart2, 0x20910017, u8,
   /// Output rate of the UBX-NAV-SAT message on port USB
-  MsgoutUbxNavSatUsb, 0x20910018, u8,
+  MsgOutUbxNavSatUsb, 0x20910018, u8,
   /// Output rate of the UBX-NAV-SIG message on port I2C
-  MsgoutUbxNavSigI2c, 0x20910345, u8,
+  MsgOutUbxNavSigI2c, 0x20910345, u8,
   /// Output rate of the UBX-NAV-SIG message on port SPI
-  MsgoutUbxNavSigSpi, 0x20910349, u8,
+  MsgOutUbxNavSigSpi, 0x20910349, u8,
   /// Output rate of the UBX-NAV-SIG message on port UART1
-  MsgoutUbxNavSigUart1, 0x20910346, u8,
+  MsgOutUbxNavSigUart1, 0x20910346, u8,
   /// Output rate of the UBX-NAV-SIG message on port UART2
-  MsgoutUbxNavSigUart2, 0x20910347, u8,
+  MsgOutUbxNavSigUart2, 0x20910347, u8,
   /// Output rate of the UBX-NAV-SIG message on port USB
-  MsgoutUbxNavSigUsb, 0x20910348, u8,
+  MsgOutUbxNavSigUsb, 0x20910348, u8,
   /// Output rate of the UBX-NAV-STATUS message on port I2C
-  MsgoutUbxNavStatusI2c, 0x2091001a, u8,
+  MsgOutUbxNavStatusI2c, 0x2091001a, u8,
   /// Output rate of the UBX-NAV-STATUS message on port SPI
-  MsgoutUbxNavStatusSpi, 0x2091001e, u8,
+  MsgOutUbxNavStatusSpi, 0x2091001e, u8,
   /// Output rate of the UBX-NAV-STATUS message on port UART1
-  MsgoutUbxNavStatusUart1, 0x2091001b, u8,
+  MsgOutUbxNavStatusUart1, 0x2091001b, u8,
   /// Output rate of the UBX-NAV-STATUS message on port UART2
-  MsgoutUbxNavStatusUart2, 0x2091001c, u8,
+  MsgOutUbxNavStatusUart2, 0x2091001c, u8,
   /// Output rate of the UBX-NAV-STATUS message on port USB
-  MsgoutUbxNavStatusUsb, 0x2091001d, u8,
+  MsgOutUbxNavStatusUsb, 0x2091001d, u8,
   /// Output rate of the UBX-NAV-SVIN message on port I2C
-  MsgoutUbxNavSvinI2c, 0x20910088, u8,
+  MsgOutUbxNavSvinI2c, 0x20910088, u8,
   /// Output rate of the UBX-NAV-SVIN message on port SPI
-  MsgoutUbxNavSvinSpi, 0x2091008c, u8,
+  MsgOutUbxNavSvinSpi, 0x2091008c, u8,
   /// Output rate of the UBX-NAV-SVIN message on port UART1
-  MsgoutUbxNavSvinUart1, 0x20910089, u8,
+  MsgOutUbxNavSvinUart1, 0x20910089, u8,
   /// Output rate of the UBX-NAV-SVIN message on port UART2
-  MsgoutUbxNavSvinUart2, 0x2091008a, u8,
+  MsgOutUbxNavSvinUart2, 0x2091008a, u8,
   /// Output rate of the UBX-NAV-SVIN message on port USB
-  MsgoutUbxNavSvinUsb, 0x2091008b, u8,
+  MsgOutUbxNavSvinUsb, 0x2091008b, u8,
   /// Output rate of the UBX-NAV-TIMEBDS message on port I2C
-  MsgoutUbxNavTimeBdsI2c, 0x20910051, u8,
+  MsgOutUbxNavTimeBdsI2c, 0x20910051, u8,
   /// Output rate of the UBX-NAV-TIMEBDS message on port SPI
-  MsgoutUbxNavTimeBdsSpi, 0x20910055, u8,
+  MsgOutUbxNavTimeBdsSpi, 0x20910055, u8,
   /// Output rate of the UBX-NAV-TIMEBDS message on port UART1
-  MsgoutUbxNavTimeBdsUart1, 0x20910052, u8,
+  MsgOutUbxNavTimeBdsUart1, 0x20910052, u8,
   /// Output rate of the UBX-NAV-TIMEBDS message on port UART2
-  MsgoutUbxNavTimeBdsUart2, 0x20910053, u8,
+  MsgOutUbxNavTimeBdsUart2, 0x20910053, u8,
   /// Output rate of the UBX-NAV-TIMEBDS message on port USB
-  MsgoutUbxNavTimeBdsUsb, 0x20910054, u8,
+  MsgOutUbxNavTimeBdsUsb, 0x20910054, u8,
   /// Output rate of the UBX-NAVTIMEGAL message on port I2C
-  MsgoutUbxNavTimeGalI2c, 0x20910056, u8,
+  MsgOutUbxNavTimeGalI2c, 0x20910056, u8,
   /// Output rate of the UBX-NAVTIMEGAL message on port SPI
-  MsgoutUbxNavTimeGalSpi, 0x2091005a, u8,
+  MsgOutUbxNavTimeGalSpi, 0x2091005a, u8,
   /// Output rate of the UBX-NAVTIMEGAL message on port UART1
-  MsgoutUbxNavTimeGalUart1, 0x20910057, u8,
+  MsgOutUbxNavTimeGalUart1, 0x20910057, u8,
   /// Output rate of the UBX-NAVTIMEGAL message on port UART2
-  MsgoutUbxNavTimeGalUart2, 0x20910058, u8,
+  MsgOutUbxNavTimeGalUart2, 0x20910058, u8,
   /// Output rate of the UBX-NAVTIMEGAL message on port USB
-  MsgoutUbxNavTimeGalUsb, 0x20910059, u8,
+  MsgOutUbxNavTimeGalUsb, 0x20910059, u8,
   /// Output rate of the UBX-NAVTIMEGLO message on port I2C
-  MsgoutUbxNavTimeGloI2c, 0x2091004c, u8,
+  MsgOutUbxNavTimeGloI2c, 0x2091004c, u8,
   /// Output rate of the UBX-NAVTIMEGLO message on port SPI
-  MsgoutUbxNavTimeGloSpi, 0x20910050, u8,
+  MsgOutUbxNavTimeGloSpi, 0x20910050, u8,
   /// Output rate of the UBX-NAVTIMEGLO message on port UART1
-  MsgoutUbxNavTimeGloUart1, 0x2091004d, u8,
+  MsgOutUbxNavTimeGloUart1, 0x2091004d, u8,
   /// Output rate of the UBX-NAVTIMEGLO message on port UART2
-  MsgoutUbxNavTimeGloUart2, 0x2091004e, u8,
+  MsgOutUbxNavTimeGloUart2, 0x2091004e, u8,
   /// Output rate of the UBX-NAVTIMEGLO message on port USB
-  MsgoutUbxNavTimeGloUsb, 0x2091004f, u8,
+  MsgOutUbxNavTimeGloUsb, 0x2091004f, u8,
   /// Output rate of the UBX-NAV-TIMEGPS message on port I2C
-  MsgoutUbxNavTimeGpsI2c, 0x20910047, u8,
+  MsgOutUbxNavTimeGpsI2c, 0x20910047, u8,
   /// Output rate of the UBX-NAV-TIMEGPS message on port SPI
-  MsgoutUbxNavTimeGpsSpi, 0x2091004b, u8,
+  MsgOutUbxNavTimeGpsSpi, 0x2091004b, u8,
   /// Output rate of the UBX-NAV-TIMEGPS message on port UART1
-  MsgoutUbxNavTimeGpsUart1, 0x20910048, u8,
+  MsgOutUbxNavTimeGpsUart1, 0x20910048, u8,
   /// Output rate of the UBX-NAV-TIMEGPS message on port UART2
-  MsgoutUbxNavTimeGpsUart2, 0x20910049, u8,
+  MsgOutUbxNavTimeGpsUart2, 0x20910049, u8,
   /// Output rate of the UBX-NAV-TIMEGPS message on port USB
-  MsgoutUbxNavTimeGpsUsb, 0x2091004a, u8,
+  MsgOutUbxNavTimeGpsUsb, 0x2091004a, u8,
   /// Output rate of the UBX-NAV-TIMELS message on port I2C
-  MsgoutUbxNavTimeLsI2c, 0x20910060, u8,
+  MsgOutUbxNavTimeLsI2c, 0x20910060, u8,
   /// Output rate of the UBX-NAV-TIMELS message on port SPI
-  MsgoutUbxNavTimeLsSpi, 0x20910064, u8,
+  MsgOutUbxNavTimeLsSpi, 0x20910064, u8,
   /// Output rate of the UBX-NAV-TIMELS message on port UART1
-  MsgoutUbxNavTimeLsUart1, 0x20910061, u8,
+  MsgOutUbxNavTimeLsUart1, 0x20910061, u8,
   /// Output rate of the UBX-NAV-TIMELS message on port UART2
-  MsgoutUbxNavTimeLsUart2, 0x20910062, u8,
+  MsgOutUbxNavTimeLsUart2, 0x20910062, u8,
   /// Output rate of the UBX-NAV-TIMELS message on port USB
-  MsgoutUbxNavTimeLsUsb, 0x20910063, u8,
+  MsgOutUbxNavTimeLsUsb, 0x20910063, u8,
   /// Output rate of the UBX-NAVTIMEUTC message on port I2C
-  MsgoutUbxNavTimeUtcI2c, 0x2091005b, u8,
+  MsgOutUbxNavTimeUtcI2c, 0x2091005b, u8,
   /// Output rate of the UBX-NAVTIMEUTC message on port SPI
-  MsgoutUbxNavTimeUtcSpi, 0x2091005f, u8,
+  MsgOutUbxNavTimeUtcSpi, 0x2091005f, u8,
   /// Output rate of the UBX-NAVTIMEUTC message on port UART1
-  MsgoutUbxNavTimeUtcUart1, 0x2091005c, u8,
+  MsgOutUbxNavTimeUtcUart1, 0x2091005c, u8,
   /// Output rate of the UBX-NAVTIMEUTC message on port UART2
-  MsgoutUbxNavTimeUtcUart2, 0x2091005d, u8,
+  MsgOutUbxNavTimeUtcUart2, 0x2091005d, u8,
   /// Output rate of the UBX-NAVTIMEUTC message on port USB
-  MsgoutUbxNavTimeUtcUsb, 0x2091005e, u8,
+  MsgOutUbxNavTimeUtcUsb, 0x2091005e, u8,
   /// Output rate of the UBX-NAV-VELECEF message on port I2C
-  MsgoutUbxNavVelEcefI2c, 0x2091003d, u8,
+  MsgOutUbxNavVelEcefI2c, 0x2091003d, u8,
   /// Output rate of the UBX-NAV-VELECEF message on port SPI
-  MsgoutUbxNavVelEcefSpi, 0x20910041, u8,
+  MsgOutUbxNavVelEcefSpi, 0x20910041, u8,
   /// Output rate of the UBX-NAV-VELECEF message on port UART1
-  MsgoutUbxNavVelEcefUart1, 0x2091003e, u8,
+  MsgOutUbxNavVelEcefUart1, 0x2091003e, u8,
   /// Output rate of the UBX-NAV-VELECEF message on port UART2
-  MsgoutUbxNavVelEcefUart2, 0x2091003f, u8,
+  MsgOutUbxNavVelEcefUart2, 0x2091003f, u8,
   /// Output rate of the UBX-NAV-VELECEF message on port USB
-  MsgoutUbxNavVelEcefUsb, 0x20910040, u8,
+  MsgOutUbxNavVelEcefUsb, 0x20910040, u8,
   /// Output rate of the UBX-NAV-VELNED message on port I2C
-  MsgoutUbxNavVelNedI2c, 0x20910042, u8,
+  MsgOutUbxNavVelNedI2c, 0x20910042, u8,
   /// Output rate of the UBX-NAV-VELNED message on port SPI
-  MsgoutUbxNavVelNedSpi, 0x20910046, u8,
+  MsgOutUbxNavVelNedSpi, 0x20910046, u8,
   /// Output rate of the UBX-NAV-VELNED message on port UART1
-  MsgoutUbxNavVelNedUart1, 0x20910043, u8,
+  MsgOutUbxNavVelNedUart1, 0x20910043, u8,
   /// Output rate of the UBX-NAV-VELNED message on port UART2
-  MsgoutUbxNavVelNedUart2, 0x20910044, u8,
+  MsgOutUbxNavVelNedUart2, 0x20910044, u8,
   /// Output rate of the UBX-NAV-VELNED message on port USB
-  MsgoutUbxNavVelNedUsb, 0x20910045, u8,
+  MsgOutUbxNavVelNedUsb, 0x20910045, u8,
   /// Output rate of the UBX-RXM-MEASX message on port I2C
-  MsgoutUbxRxmMeasxI2c, 0x20910204, u8,
+  MsgOutUbxRxmMeasxI2c, 0x20910204, u8,
   /// Output rate of the UBX-RXM-MEASX message on port SPI
-  MsgoutUbxRxmMeasxSpi, 0x20910208, u8,
+  MsgOutUbxRxmMeasxSpi, 0x20910208, u8,
   /// Output rate of the UBX-RXM-MEASX message on port UART1
-  MsgoutUbxRxmMeasxUart1, 0x20910205, u8,
+  MsgOutUbxRxmMeasxUart1, 0x20910205, u8,
   /// Output rate of the UBX-RXM-MEASX message on port UART2
-  MsgoutUbxRxmMeasxUart2, 0x20910206, u8,
+  MsgOutUbxRxmMeasxUart2, 0x20910206, u8,
   /// Output rate of the UBX-RXM-MEASX message on port USB
-  MsgoutUbxRxmMeasxUsb, 0x20910207, u8,
+  MsgOutUbxRxmMeasxUsb, 0x20910207, u8,
   /// Output rate of the UBX-RXM-RAWX message on port I2C
-  MsgoutUbxRxmRawxI2c, 0x209102a4, u8,
+  MsgOutUbxRxmRawxI2c, 0x209102a4, u8,
   /// Output rate of the UBX-RXM-RAWX message on port SPI
-  MsgoutUbxRxmRawxSpi, 0x209102a8, u8,
+  MsgOutUbxRxmRawxSpi, 0x209102a8, u8,
   /// Output rate of the UBX-RXM-RAWX message on port UART1
-  MsgoutUbxRxmRawxUart1, 0x209102a5, u8,
+  MsgOutUbxRxmRawxUart1, 0x209102a5, u8,
   /// Output rate of the UBX-RXM-RAWX message on port UART2
-  MsgoutUbxRxmRawxUart2, 0x209102a6, u8,
+  MsgOutUbxRxmRawxUart2, 0x209102a6, u8,
   /// Output rate of the UBX-RXM-RAWX message on port USB
-  MsgoutUbxRxmRawxUsb, 0x209102a7, u8,
+  MsgOutUbxRxmRawxUsb, 0x209102a7, u8,
   /// Output rate of the UBX-RXM-RLM message on port I2C
-  MsgoutUbxRxmRlmI2c, 0x2091025e, u8,
+  MsgOutUbxRxmRlmI2c, 0x2091025e, u8,
   /// Output rate of the UBX-RXM-RLM message on port SPI
-  MsgoutUbxRxmRlmSpi, 0x20910262, u8,
+  MsgOutUbxRxmRlmSpi, 0x20910262, u8,
   /// Output rate of the UBX-RXM-RLM message on port UART1
-  MsgoutUbxRxmRlmUart1, 0x2091025f, u8,
+  MsgOutUbxRxmRlmUart1, 0x2091025f, u8,
   /// Output rate of the UBX-RXM-RLM message on port UART2
-  MsgoutUbxRxmRlmUart2, 0x20910260, u8,
+  MsgOutUbxRxmRlmUart2, 0x20910260, u8,
   /// Output rate of the UBX-RXM-RLM message on port USB
-  MsgoutUbxRxmRlmUsb, 0x20910261, u8,
+  MsgOutUbxRxmRlmUsb, 0x20910261, u8,
   /// Output rate of the UBX-RXM-RTCM message on port I2C
-  MsgoutUbxRxmRtcmI2c, 0x20910268, u8,
+  MsgOutUbxRxmRtcmI2c, 0x20910268, u8,
   /// Output rate of the UBX-RXM-RTCM message on port SPI
-  MsgoutUbxRxmRtcmSpi, 0x2091026c, u8,
+  MsgOutUbxRxmRtcmSpi, 0x2091026c, u8,
   /// Output rate of the UBX-RXM-RTCM message on port UART1
-  MsgoutUbxRxmRtcmUart1, 0x20910269, u8,
+  MsgOutUbxRxmRtcmUart1, 0x20910269, u8,
   /// Output rate of the UBX-RXM-RTCM message on port UART2
-  MsgoutUbxRxmRtcmUart2, 0x2091026a, u8,
+  MsgOutUbxRxmRtcmUart2, 0x2091026a, u8,
   /// Output rate of the UBX-RXM-RTCM message on port USB
-  MsgoutUbxRxmRtcmUsb, 0x2091026b, u8,
+  MsgOutUbxRxmRtcmUsb, 0x2091026b, u8,
   /// Output rate of the UBX-RXM-SFRBX message on port I2C
-  MsgoutUbxRxmSfrbxI2c, 0x20910231, u8,
+  MsgOutUbxRxmSfrbxI2c, 0x20910231, u8,
   /// Output rate of the UBX-RXM-SFRBX message on port SPI
-  MsgoutUbxRxmSfrbxSpi, 0x20910235, u8,
+  MsgOutUbxRxmSfrbxSpi, 0x20910235, u8,
   /// Output rate of the UBX-RXM-SFRBX message on port UART1
-  MsgoutUbxRxmSfrbxUart1, 0x20910232, u8,
+  MsgOutUbxRxmSfrbxUart1, 0x20910232, u8,
   /// Output rate of the UBX-RXM-SFRBX message on port UART2
-  MsgoutUbxRxmSfrbxUart2, 0x20910233, u8,
+  MsgOutUbxRxmSfrbxUart2, 0x20910233, u8,
   /// Output rate of the UBX-RXM-SFRBX message on port USB
-  MsgoutUbxRxmSfrbxUsb, 0x20910234, u8,
+  MsgOutUbxRxmSfrbxUsb, 0x20910234, u8,
   /// Output rate of the UBX-TIM-TM2 message on port I2C
-  MsgoutUbxTimTm2I2c, 0x20910178, u8,
+  MsgOutUbxTimTm2I2c, 0x20910178, u8,
   /// Output rate of the UBX-TIM-TM2 message on port SPI
-  MsgoutUbxTimTm2Spi, 0x2091017c, u8,
+  MsgOutUbxTimTm2Spi, 0x2091017c, u8,
   /// Output rate of the UBX-TIM-TM2 message on port UART1
-  MsgoutUbxTimTm2Uart1, 0x20910179, u8,
+  MsgOutUbxTimTm2Uart1, 0x20910179, u8,
   /// Output rate of the UBX-TIM-TM2 message on port UART2
-  MsgoutUbxTimTm2Uart2, 0x2091017a, u8,
+  MsgOutUbxTimTm2Uart2, 0x2091017a, u8,
   /// Output rate of the UBX-TIM-TM2 message on port USB
-  MsgoutUbxTimTm2Usb, 0x2091017b, u8,
+  MsgOutUbxTimTm2Usb, 0x2091017b, u8,
   /// Output rate of the UBX-TIM-TP message on port I2C
-  MsgoutUbxTimTpI2c, 0x2091017d, u8,
+  MsgOutUbxTimTpI2c, 0x2091017d, u8,
   /// Output rate of the UBX-TIM-TP message on port SPI
-  MsgoutUbxTimTpSpi, 0x20910181, u8,
+  MsgOutUbxTimTpSpi, 0x20910181, u8,
   /// Output rate of the UBX-TIM-TP message on port UART1
-  MsgoutUbxTimTpUart1, 0x2091017e, u8,
+  MsgOutUbxTimTpUart1, 0x2091017e, u8,
   /// Output rate of the UBX-TIM-TP message on port UART2
-  MsgoutUbxTimTpUart2, 0x2091017f, u8,
+  MsgOutUbxTimTpUart2, 0x2091017f, u8,
   /// Output rate of the UBX-TIM-TP message on port USB
-  MsgoutUbxTimTpUsb, 0x20910180, u8,
+  MsgOutUbxTimTpUsb, 0x20910180, u8,
   /// Output rate of the UBX-TIM-VRFY message on port I2C
-  MsgoutUbxTimVrfyI2c, 0x20910092, u8,
+  MsgOutUbxTimVrfyI2c, 0x20910092, u8,
   /// Output rate of the UBX-TIM-VRFY message on port SPI
-  MsgoutUbxTimVrfySpi, 0x20910096, u8,
+  MsgOutUbxTimVrfySpi, 0x20910096, u8,
   /// Output rate of the UBX-TIM-VRFY message on port UART1
-  MsgoutUbxTimVrfyUart1, 0x20910093, u8,
+  MsgOutUbxTimVrfyUart1, 0x20910093, u8,
   /// Output rate of the UBX-TIM-VRFY message on port UART2
-  MsgoutUbxTimVrfyUart2, 0x20910094, u8,
+  MsgOutUbxTimVrfyUart2, 0x20910094, u8,
   /// Output rate of the UBX-TIM-VRFY message on port USB
-  MsgoutUbxTimVrfyUsb, 0x20910095, u8,
+  MsgOutUbxTimVrfyUsb, 0x20910095, u8,
 
   // CFG-SIGNAL-*
   SignalGpsEna,          0x1031001f, bool,
@@ -1107,9 +1210,60 @@ cfg_val! {
   TpAlignToTowTp1,       0x1005000a, bool,
   TpPolTp1,              0x1005000b, bool,
   TpTimegridTp1,         0x2005000c, AlignmentToReferenceTime,
+
+  /// CFG-TMode* (Time-only mode settings - position fixed)
+  /// Receiver mode
+  TModeModeDef, 0x20030001,  CfgTModeModes,
+  /// Determines whether the Antenna Reference Point (ARP) position is given in ECEF or LAT/LON/HEIGHT?
+  TModePosTypeDef, 0x20030002,  TModePosType,
+  /// ECEF X coordinate of the ARP position in [cm].
+  /// This will only be used if CfgTModeModes=Fixed and TModePOS_TYPE=ECEF.
+  TModeEcefX, 0x40030003,  i32,
+  /// ECEF Y coordinate of the ARP position in [cm].
+  /// This will only be used if CfgTModeModes=Fixed and TModePOS_TYPE=ECEF.
+  TModeEcefY, 0x40030004,  i32,
+  /// ECEF Z coordinate of the ARP position in [cm] .
+  /// This will only be used if CfgTModeModes=Fixed and TModePOS_TYPE=ECEF.
+  TModeEcefZ, 0x40030005,  i32,
+  /// High-precision ECEF X coordinate of the ARP position, [-99 to +99] in [mm].
+  /// This will only be used if CfgTModeModes=Fixed and TModePOS_TYPE=ECEF.
+  TModeEcefXHp, 0x20030006,  i8,
+  /// High-precision ECEF Y coordinate of the ARP position [-99 to +99] in [mm].
+  /// This will only be used if CfgTModeModes=Fixed and TModePOS_TYPE=ECEF.
+  TModeEcefYHp, 0x20030007,  i8,
+  /// High-precision ECEF Z coordinate of the ARP position [-99 to +99] in [mm].
+  /// This will only be used if CfgTModeModes=Fixed and TModePOS_TYPE=ECEF.
+  TModeEcefZHp, 0x20030008,  i8,
+  /// Latitude of the ARP position in [deg].
+  /// This will only be used if CfgTModeModes=Fixed and TModePOS_TYPE=LLH.
+  TModeLat, 0x40030009,  i32,
+  /// Longitude of the ARP position in [deg].
+  /// This will only be used if CfgTModeModes=Fixed and TModePOS_TYPE=LLH.
+  TModeLon, 0x4003000a,  i32,
+  /// Height of the ARP position in [cm].
+  /// This will only be used if CfgTModeModes=Fixed and TModePOS_TYPE=LLH.
+  TModeHeight, 0x4003000b,  i32,
+  /// High-precision latitude of the ARP position [-99 to +99] in [deg].
+  /// This will only be used if CfgTModeModes=Fixed and TModePOS_TYPE=LLH.
+  TModeLatHp, 0x2003000c,  i8,
+  /// High-precision longitude of the ARP position [-99 to +99] in [deg].
+  /// This will only be used if CfgTModeModes=Fixed and TModePOS_TYPE=LLH.
+  TModeLonHp, 0x2003000d,  i8,
+  /// High-precision height of the ARP position [-99 to +99] in [mm].
+  /// This will only be used if CfgTModeModes=Fixed and TModePOS_TYPE=LLH.
+  TModeHeightHp, 0x2003000e,  i8,
+  /// Fixed position 3D accuracy in [mm]
+  TModeFixedPosAcc, 0x4003000f,  u32,
+  /// Survey-in minimum duration in [sec].
+  /// This will only be used if CfgTModeModes=SurveyIn.
+  TModeSvInMinDur, 0x40030010,  u32,
+  /// Survey-in position accuracy limit in [mm]
+  /// This will only be used if CfgTModeModes=SurveyIn.
+  TModeSvInAccLimit, 0x40030011,  u32,
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub enum TpPulse {
     /// Time pulse period
     Period = 0,
@@ -1118,9 +1272,19 @@ pub enum TpPulse {
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub enum TpPulseLength {
     /// Time pulse ratio
     Ratio = 0,
     /// Time pulse length
     Length = 1,
 }
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum TModePosType {
+    /// ECEF position
+    ECEF = 0,
+    /// Lat/Lon/Height position
+    LLH = 1,
+}
diff --git a/ublox/src/ubx_packets/packets.rs b/ublox/src/ubx_packets/packets.rs
index 64688ba7..a3430999 100644
--- a/ublox/src/ubx_packets/packets.rs
+++ b/ublox/src/ubx_packets/packets.rs
@@ -1,4 +1,4 @@
-use crate::cfg_val::CfgVal;
+use crate::cfg_val::{CfgKey, CfgVal};
 use core::convert::TryInto;
 use core::fmt;
 
@@ -829,7 +829,7 @@ impl FixStatusInfo {
             1 => MapMatchingStatus::Valid,
             2 => MapMatchingStatus::Used,
             3 => MapMatchingStatus::Dr,
-            _ => unreachable!(),
+            _ => unreachable!("MapMatching Status value not supported by protocol specification"),
         }
     }
     pub const fn from(x: u8) -> Self {
@@ -2008,8 +2008,8 @@ pub enum CfgTp5TimePulseMode {
     flags = "default_for_builder"
 )]
 struct CfgTmode2 {
-    /// Time transfer modes, see [CfgTmode2TimeXferModes] for details
-    #[ubx(map_type = CfgTmode2TimeXferModes, may_fail)]
+    /// Time transfer modes, see [CfgTModeModes] for details
+    #[ubx(map_type = CfgTModeModes, may_fail)]
     time_transfer_mode: u8,
     reserved1: u8,
     #[ubx(map_type = CfgTmode2Flags)]
@@ -2042,13 +2042,14 @@ struct CfgTmode2 {
 #[ubx(from_unchecked, into_raw, rest_error)]
 #[repr(u8)]
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum CfgTmode2TimeXferModes {
+#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
+pub enum CfgTModeModes {
     #[default]
     Disabled = 0,
     SurveyIn = 1,
-    /// True position information required
-    /// when using `fixed mode`
-    FixedMode = 2,
+    /// True Antenna Reference Point (ARP) position information required
+    /// when using `Fixed`
+    Fixed = 2,
 }
 
 #[ubx_extend_bitflags]
@@ -2216,7 +2217,7 @@ bitflags! {
     pub struct CfgTmode3RcvrMode: u8 {
         const DISABLED = 0x01;
         const SURVEY_IN = 0x02;
-        /// True ARP position is required in `FixedMode`
+        /// True Antenna Reference Point (ARP) position information required
         const FIXED_MODE = 0x04;
     }
 }
@@ -2352,30 +2353,89 @@ struct CfgValSet<'a> {
     /// Message version
     version: u8,
     /// The layers from which the configuration items should be retrieved
-    #[ubx(map_type = CfgLayer)]
+    #[ubx(map_type = CfgLayerSet)]
     layers: u8,
     reserved1: u16,
     cfg_data: &'a [CfgVal],
 }
 
+/// The CfgValGet message is limited to requesting a maximum of 64 key-value pairs.
+pub const MAX_CFG_KEYS: u16 = 64;
+
+#[ubx_packet_send]
+#[ubx(
+  class = 0x06,
+  id = 0x8b,
+  max_payload_len = 260, // 4 + sizeof(u32) * MAX_CFG_KEYS
+)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+/// This message is limited to containing a maximum of 64 key IDs.
+/// This message returns a UBX-ACK-NAK
+///  - if any key is unknown to the receiver FW
+///  - if the layer field speciﬁes an invalid layer to get the value from
+///  - if the keys array speciﬁes more than 64 key IDs.
+struct CfgValGetSend<'a> {
+    /// Message version
+    version: u8,
+    /// The layers from which the configuration items should be retrieved
+    #[ubx(map_type = CfgLayerGet)]
+    layers: u8,
+    position: u16,
+    cfg_keys: &'a [CfgKey],
+}
+
+#[ubx_packet_recv]
+#[ubx(
+  class = 0x06,
+  id = 0x8b,
+  max_payload_len = 772, // 4 + (sizeof(u32) + sizeof(largest val)) * MAX_CFG_KEYS
+)]
+struct CfgValGetRecv {
+    /// Message version
+    version: u8,
+    #[ubx(map_type = CfgLayerGet)]
+    layers: u8,
+    position: u16,
+    #[ubx(
+        map_type = CfgValIter,
+        from = CfgValIter::new,
+        may_fail,
+        is_valid = CfgValIter::is_valid,
+    )]
+    cfg_data: [u8; 0],
+}
+
+/// The [CfgLayerGet] enum is used to specify the configuration layer to read from.
+/// The configuration system in the ublox device is stacked, so a property
+/// may be empty for a particular layer and you will receive a NAK.
+#[ubx_extend]
+#[ubx(from, into_raw, rest_reserved)]
+#[repr(u8)]
+#[derive(Debug, Copy, Clone)]
+pub enum CfgLayerGet {
+    /// Read from RAM
+    Ram = 0,
+    /// Read from BBR (battery backed RAM)
+    Bbr = 1,
+    /// Read from Flash, if available
+    Flash = 2,
+    /// Read the current configuration from the active source
+    Default = 7,
+}
+
 #[derive(Debug, Clone)]
 pub struct CfgValIter<'a> {
-    pub(crate) data: &'a [u8],
-    pub(crate) offset: usize,
+    data: &'a [u8],
 }
 
 impl<'a> CfgValIter<'a> {
-    pub fn new(data: &'a mut [u8], values: &[CfgVal]) -> Self {
-        let mut offset = 0;
-
-        for value in values {
-            offset += value.write_to(&mut data[offset..]);
-        }
+    fn new(data: &'a [u8]) -> Self {
+        Self { data }
+    }
 
-        Self {
-            data: &data[..offset],
-            offset: 0,
-        }
+    fn is_valid(bytes: &[u8]) -> bool {
+        // we need at least 5 bytes for a key id (4) + val (1)
+        bytes.len() >= 5
     }
 }
 
@@ -2383,30 +2443,33 @@ impl core::iter::Iterator for CfgValIter<'_> {
     type Item = CfgVal;
 
     fn next(&mut self) -> Option<Self::Item> {
-        if self.offset < self.data.len() {
-            let cfg_val = CfgVal::parse(&self.data[self.offset..]);
-
-            self.offset += cfg_val.len();
-
-            Some(cfg_val)
-        } else {
-            None
+        if Self::is_valid(self.data) {
+            if let Some(cfg_val) = CfgVal::parse(self.data) {
+                self.data = &self.data[cfg_val.len()..];
+                return Some(cfg_val);
+            }
+            // TODO: Is there some logging mechanism?
+            // eprintln!("Failure parsing key in (key,value) list, {:?}", self.data);
         }
+        None
     }
 }
 
+/// The `CfgLayerSet` defines the configuration layer used to set configuration values to.
+/// The definition of the Layers for updating the configuration values is different than
+/// the definition of the Layers for reading values, see [CfgLayerGet]
 #[ubx_extend_bitflags]
 #[ubx(from, into_raw, rest_reserved)]
 bitflags! {
     /// A mask describing where configuration is applied.
-    pub struct CfgLayer: u8 {
+    pub struct CfgLayerSet: u8 {
         const RAM = 0b001;
         const BBR = 0b010;
         const FLASH = 0b100;
     }
 }
 
-impl Default for CfgLayer {
+impl Default for CfgLayerSet {
     fn default() -> Self {
         Self::RAM | Self::BBR | Self::FLASH
     }
@@ -2536,11 +2599,11 @@ impl DataBits {
 impl From<u32> for DataBits {
     fn from(mode: u32) -> Self {
         match (mode >> Self::POSITION) & Self::MASK {
-            0b00 => unimplemented!("five data bits"),
-            0b01 => unimplemented!("six data bits"),
+            0b00 => unimplemented!("five data bits not supported by u-blox protocol specification"),
+            0b01 => unimplemented!("six data bits not supported by u-blox protocol specification"),
             0b10 => Self::Seven,
             0b11 => Self::Eight,
-            _ => unreachable!(),
+            _ => unreachable!("DataBits value not supported by protocol specification"),
         }
     }
 }
@@ -2573,7 +2636,7 @@ impl From<u32> for Parity {
             0b001 => Self::Odd,
             0b100 | 0b101 => Self::None,
             0b010 | 0b011 | 0b110 | 0b111 => unimplemented!("reserved"),
-            _ => unreachable!(),
+            _ => unreachable!("Parity value not supported by protocol specification"),
         }
     }
 }
@@ -2608,7 +2671,7 @@ impl From<u32> for StopBits {
             0b01 => Self::OneHalf,
             0b10 => Self::Two,
             0b11 => Self::Half,
-            _ => unreachable!(),
+            _ => unreachable!("StopBits value not supported by protocol specification"),
         }
     }
 }
@@ -2753,6 +2816,7 @@ struct CfgRate {
 /// Alignment to reference time
 #[repr(u16)]
 #[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub enum AlignmentToReferenceTime {
     Utc = 0,
     Gps = 1,
@@ -3591,7 +3655,7 @@ impl TimTm2Flags {
             0 => TimTm2TimeBase::Receiver,
             1 => TimTm2TimeBase::Gnss,
             2 => TimTm2TimeBase::Utc,
-            _ => unreachable!(),
+            _ => unreachable!("TimeBase value not supported by protocol specification"),
         }
     }
 
@@ -4033,7 +4097,7 @@ impl<'a> EsfMeasDataIter<'a> {
         Self(bytes.chunks_exact(Self::BLOCK_SIZE))
     }
 
-    fn is_valid(bytes: &'a [u8]) -> bool {
+    fn is_valid(bytes: &[u8]) -> bool {
         bytes.len() % Self::BLOCK_SIZE == 0
     }
 }
@@ -4518,7 +4582,7 @@ impl<'a> EsfSensorStatusIter<'a> {
         Self(bytes.chunks_exact(Self::BLOCK_SIZE))
     }
 
-    fn is_valid(bytes: &'a [u8]) -> bool {
+    fn is_valid(bytes: &[u8]) -> bool {
         bytes.len() % Self::BLOCK_SIZE == 0
     }
 }
@@ -4909,7 +4973,7 @@ impl<'a> DwrdIter<'a> {
         DwrdIter(bytes.chunks_exact(4))
     }
 
-    fn is_valid(bytes: &'a [u8]) -> bool {
+    fn is_valid(bytes: &[u8]) -> bool {
         bytes.len() % 4 == 0
     }
 }
@@ -4930,7 +4994,7 @@ struct NavVelECEF {
     itow: u32,
     ecef_vx: i32,
     ecef_vy: i32,
-    ecef_vz: u32,
+    ecef_vz: i32,
     s_acc: u32,
 }
 
@@ -5047,7 +5111,7 @@ impl<'a> RxmRawxInfoIter<'a> {
         Self(data.chunks_exact(32))
     }
 
-    fn is_valid(bytes: &'a [u8]) -> bool {
+    fn is_valid(bytes: &[u8]) -> bool {
         bytes.len() % 32 == 0
     }
 }
diff --git a/ublox/src/ubx_packets/packets/packetref.rs b/ublox/src/ubx_packets/packets/packetref.rs
index 4f97dd33..b38e39cc 100644
--- a/ublox/src/ubx_packets/packets/packetref.rs
+++ b/ublox/src/ubx_packets/packets/packetref.rs
@@ -89,6 +89,7 @@ define_recv_packets!(
         CfgTp5,
         CfgEsfAlg,
         CfgEsfWt,
+        CfgValGetRecv,
         EsfAlg,
         EsfIns,
         EsfMeas,
@@ -153,6 +154,7 @@ define_recv_packets!(
         CfgTp5,
         CfgEsfAlg,
         CfgEsfWt,
+        CfgValGetRecv,
         EsfAlg,
         EsfIns,
         EsfMeas,


Reviews:
user: login: CramBL
body: Have a bunch of comments, some are a little more general, it's minor things overall (I hope).
state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-04-18T13:37:30Z
user: login: andrei-ng
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-22T11:06:05Z
user: login: andrei-ng
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-22T11:13:45Z
user: login: andrei-ng
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-22T11:16:48Z
user: login: andrei-ng
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-22T11:22:01Z
user: login: andrei-ng
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-22T11:35:16Z
user: login: andrei-ng
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-22T11:42:21Z
user: login: andrei-ng
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-22T11:59:08Z
user: login: andrei-ng
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-22T12:05:08Z
user: login: andrei-ng
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-22T13:41:09Z
user: login: CramBL
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-22T13:51:45Z
user: login: CramBL
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-22T13:53:11Z
user: login: CramBL
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-22T13:53:54Z
user: login: andrei-ng
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-22T14:08:57Z
user: login: CramBL
body: Looks great!
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-22T18:23:01Z
user: login: gwbres
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-23T06:22:47Z
user: login: andrei-ng
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-23T07:02:49Z
user: login: andrei-ng
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-23T07:14:36Z

Review comments:
diff_hunk: @@ -1124,3 +1244,19 @@ pub enum TpPulseLength {
     /// Time pulse length
     Length = 1,
 }
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum TModeMode {
+    Disabled = 0,
+    SurveyIn = 1,
+    // true ARP position information required
path: ublox/src/ubx_packets/cfg_val.rs
user: login: gwbres
body: ```suggestion
    /// True ARP position information required
```
created_at: 2025-04-18T08:33:52Z
author_association: COLLABORATOR
diff_hunk: @@ -5069,6 +5085,24 @@ struct SecUniqId {
     unique_id: [u8; 5],
 }
 
+/// The `CfgReadLayer` enum is used to specify the configuration layer to read from.
+/// The configuration system in the ublox device is stacked, so a property
+/// may be empty for a particular layer and you will receive a NAK.
+#[ubx_extend]
+#[ubx(from_unchecked, into_raw, rest_error)]
+#[repr(u8)]
+#[derive(Debug, Copy, Clone)]
+pub enum CfgReadLayer {
path: ublox/src/ubx_packets/packets.rs
user: login: gwbres
body: This should probably either replace the `CfgLayer` we already have, or reuse it, is it not possible ?
created_at: 2025-04-18T08:37:03Z
author_association: COLLABORATOR
diff_hunk: @@ -42,6 +42,16 @@ impl KeyId {
     pub const fn item_id(&self) -> u8 {
         self.0 as u8
     }
+
+    pub fn extend_to<T>(&self, buf: &mut T) -> usize
+    where
+        T: core::iter::Extend<u8>,
+    {
+        let bytes = self.0.to_le_bytes();
+        assert_eq!(bytes.len(), Self::SIZE);
path: ublox/src/ubx_packets/cfg_val.rs
user: login: CramBL
body: Is it necessary to have a runtime assert here?

```suggestion
        debug_assert_eq!(bytes.len(), Self::SIZE);
```
created_at: 2025-04-18T12:55:45Z
author_association: COLLABORATOR
diff_hunk: @@ -120,6 +136,21 @@ macro_rules! from_cfg_v_bytes {
             _ => unreachable!(),
         }
     };
+    ($buf:expr, TModeMode) => {
+        match $buf[0] {
+            0 => TModeMode::Disabled,
+            1 => TModeMode::SurveyIn,
+            2 => TModeMode::FixedMode,
+            _ => unreachable!(),
path: ublox/src/ubx_packets/cfg_val.rs
user: login: CramBL
body: Can we document it?

e.g.
```suggestion
            _ => unreachable!("Unreachable unless <some esoteric unsoundness error>"),
```
created_at: 2025-04-18T12:58:00Z
author_association: COLLABORATOR
diff_hunk: @@ -120,6 +136,21 @@ macro_rules! from_cfg_v_bytes {
             _ => unreachable!(),
         }
     };
+    ($buf:expr, TModeMode) => {
+        match $buf[0] {
+            0 => TModeMode::Disabled,
+            1 => TModeMode::SurveyIn,
+            2 => TModeMode::FixedMode,
+            _ => unreachable!(),
+        }
+    };
+    ($buf:expr, TModePosType) => {
+        match $buf[0] {
+            0 => TModePosType::ECEF,
+            1 => TModePosType::LLH,
+            _ => unreachable!(),
path: ublox/src/ubx_packets/cfg_val.rs
user: login: CramBL
body: Likewise would be nice to document
created_at: 2025-04-18T12:58:13Z
author_association: COLLABORATOR
diff_hunk: @@ -42,6 +42,16 @@ impl KeyId {
     pub const fn item_id(&self) -> u8 {
         self.0 as u8
     }
+
+    pub fn extend_to<T>(&self, buf: &mut T) -> usize
path: ublox/src/ubx_packets/cfg_val.rs
user: login: CramBL
body: Is now a good time to start more rigorously documenting the API? 😄 

```suggestion
    /// Extend a buffer with the contents of [KeyId].
    pub fn extend_to<T>(&self, buf: &mut T) -> usize
```
created_at: 2025-04-18T13:12:28Z
author_association: COLLABORATOR
diff_hunk: @@ -236,15 +295,19 @@ macro_rules! cfg_val {
       }
 
       #[track_caller]
-      pub fn parse(buf: &[u8]) -> Self {
+      pub fn parse(buf: &[u8]) -> Option<Self> {
         let key_id = u32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]);
         match key_id {
           $(
             $cfg_key_id => {
-              Self::$cfg_item(from_cfg_v_bytes!(&buf[4..], $cfg_value_type))
+              Some(Self::$cfg_item(from_cfg_v_bytes!(&buf[4..], $cfg_value_type)))
             },
           )*
-          _ => unimplemented!("unknown key ID: 0x{:8X}", key_id),
+          _ => {
+            // TODO: add a mechanism to log such messages that supports also no_std
+            // eprintln!("unknown key ID: 0x{:8X}", key_id);
+            None
+           },
path: ublox/src/ubx_packets/cfg_val.rs
user: login: CramBL
body: This suggest that the function should actually return `Result` instead of `Option`. If you have an unknown key ID isn't that just an error?
created_at: 2025-04-18T13:16:47Z
author_association: COLLABORATOR
diff_hunk: @@ -1118,9 +1265,28 @@ pub enum TpPulse {
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub enum TpPulseLength {
     /// Time pulse ratio
     Ratio = 0,
     /// Time pulse length
     Length = 1,
 }
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum TModeMode {
+    Disabled = 0,
+    SurveyIn = 1,
+    // true ARP position information required
path: ublox/src/ubx_packets/cfg_val.rs
user: login: CramBL
body: ```suggestion
    /// true ARP position information required
```
created_at: 2025-04-18T13:20:31Z
author_association: COLLABORATOR
diff_hunk: @@ -2358,6 +2358,97 @@ struct CfgValSet<'a> {
     cfg_data: &'a [CfgVal],
 }
 
+pub const MAX_CFG_KEYS: u16 = 64;
+
+#[ubx_packet_send]
+#[ubx(
+  class = 0x06,
+  id = 0x8b,
+  max_payload_len = 260, // 4 + sizeof(u32) * MAX_CFG_KEYS
+)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+struct CfgValGet<'a> {
+    /// Message version
+    version: u8,
+    /// The layers from which the configuration items should be retrieved
+    #[ubx(map_type = CfgReadLayer)]
+    layers: u8,
+    position: u16,
+    cfg_keys: &'a [CfgKey],
path: ublox/src/ubx_packets/packets.rs
user: login: CramBL
body: Just to get some kind of association between the lifetime name and the value that determines the lifetime

```suggestion
struct CfgValGet<'k> {
    /// Message version
    version: u8,
    /// The layers from which the configuration items should be retrieved
    #[ubx(map_type = CfgReadLayer)]
    layers: u8,
    position: u16,
    cfg_keys: &'k [CfgKey],
```
created_at: 2025-04-18T13:23:07Z
author_association: COLLABORATOR
diff_hunk: @@ -2358,6 +2358,97 @@ struct CfgValSet<'a> {
     cfg_data: &'a [CfgVal],
 }
 
+pub const MAX_CFG_KEYS: u16 = 64;
+
+#[ubx_packet_send]
+#[ubx(
+  class = 0x06,
+  id = 0x8b,
+  max_payload_len = 260, // 4 + sizeof(u32) * MAX_CFG_KEYS
+)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+struct CfgValGet<'a> {
+    /// Message version
+    version: u8,
+    /// The layers from which the configuration items should be retrieved
+    #[ubx(map_type = CfgReadLayer)]
+    layers: u8,
+    position: u16,
+    cfg_keys: &'a [CfgKey],
+}
+
+#[ubx_packet_recv]
+#[ubx(
+  class = 0x06,
+  id = 0x8b,
+  max_payload_len = 772, // 4 + (sizeof(u32) + sizeof(largest val)) * MAX_CFG_KEYS
+)]
+struct CfgValGetResponse {
+    /// Message version
+    version: u8,
+    #[ubx(map_type = CfgReadLayer)]
+    layers: u8,
+    position: u16,
+    #[ubx(
+        map_type = CfgValReadIter,
+        from = CfgValReadIter::new,
+        may_fail,
+        is_valid = CfgValReadIter::is_valid,
+    )]
+    cfg_data: [u8; 0],
+}
+
+/// The `CfgReadLayer` enum is used to specify the configuration layer to read from.
+/// The configuration system in the ublox device is stacked, so a property
+/// may be empty for a particular layer and you will receive a NAK.
+#[ubx_extend]
+#[ubx(from, into_raw, rest_reserved)]
+#[repr(u8)]
+#[derive(Debug, Copy, Clone)]
+pub enum CfgReadLayer {
+    /// Read from RAM
+    Ram = 0,
+    /// Read from Bbr (battery backed RAM)
+    Bbr = 1,
+    /// Read from Flash, if available
+    Flash = 2,
+    /// Read the current configuration from the active source
+    Default = 7,
+}
+
+#[derive(Debug, Clone)]
+pub struct CfgValReadIter<'a> {
+    data: &'a [u8],
+}
+
+impl<'a> CfgValReadIter<'a> {
+    fn new(data: &'a [u8]) -> Self {
+        // todo!("stolen from RxmRawxInfoIter. Reimplement.");
+        Self { data }
+    }
+
+    fn is_valid(bytes: &'a [u8]) -> bool {
path: ublox/src/ubx_packets/packets.rs
user: login: CramBL
body: This lifetime should not be needed

```suggestion
    fn is_valid(bytes: &[u8]) -> bool {
```
created_at: 2025-04-18T13:25:49Z
author_association: COLLABORATOR
diff_hunk: @@ -2358,6 +2358,97 @@ struct CfgValSet<'a> {
     cfg_data: &'a [CfgVal],
 }
 
+pub const MAX_CFG_KEYS: u16 = 64;
+
+#[ubx_packet_send]
+#[ubx(
+  class = 0x06,
+  id = 0x8b,
+  max_payload_len = 260, // 4 + sizeof(u32) * MAX_CFG_KEYS
+)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+struct CfgValGet<'a> {
+    /// Message version
+    version: u8,
+    /// The layers from which the configuration items should be retrieved
+    #[ubx(map_type = CfgReadLayer)]
+    layers: u8,
+    position: u16,
+    cfg_keys: &'a [CfgKey],
+}
+
+#[ubx_packet_recv]
+#[ubx(
+  class = 0x06,
+  id = 0x8b,
+  max_payload_len = 772, // 4 + (sizeof(u32) + sizeof(largest val)) * MAX_CFG_KEYS
+)]
+struct CfgValGetResponse {
+    /// Message version
+    version: u8,
+    #[ubx(map_type = CfgReadLayer)]
+    layers: u8,
+    position: u16,
+    #[ubx(
+        map_type = CfgValReadIter,
+        from = CfgValReadIter::new,
+        may_fail,
+        is_valid = CfgValReadIter::is_valid,
+    )]
+    cfg_data: [u8; 0],
+}
+
+/// The `CfgReadLayer` enum is used to specify the configuration layer to read from.
+/// The configuration system in the ublox device is stacked, so a property
+/// may be empty for a particular layer and you will receive a NAK.
+#[ubx_extend]
+#[ubx(from, into_raw, rest_reserved)]
+#[repr(u8)]
+#[derive(Debug, Copy, Clone)]
+pub enum CfgReadLayer {
+    /// Read from RAM
+    Ram = 0,
+    /// Read from Bbr (battery backed RAM)
+    Bbr = 1,
+    /// Read from Flash, if available
+    Flash = 2,
+    /// Read the current configuration from the active source
+    Default = 7,
+}
+
+#[derive(Debug, Clone)]
+pub struct CfgValReadIter<'a> {
+    data: &'a [u8],
+}
+
+impl<'a> CfgValReadIter<'a> {
+    fn new(data: &'a [u8]) -> Self {
+        // todo!("stolen from RxmRawxInfoIter. Reimplement.");
+        Self { data }
+    }
+
+    fn is_valid(bytes: &'a [u8]) -> bool {
+        // we need at least 5 bytes for a key id (4) + val (1)
+        bytes.len() >= 5
+    }
+}
+
+impl<'a> core::iter::Iterator for CfgValReadIter<'a> {
+    type Item = CfgVal;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if Self::is_valid(self.data) {
+            if let Some(cfg_val) = CfgVal::parse(self.data) {
+                self.data = &self.data[cfg_val.len()..];
+                return Some(cfg_val);
+            }
+            // TODO: Is there some logging mechanism?
+            // eprintln!("Failure parsing key in (key,value) list, {:?}", self.data);
path: ublox/src/ubx_packets/packets.rs
user: login: CramBL
body: We could use https://defmt.ferrous-systems.com.

Then we could wrap them in a macro and support the normal std logging facade as well.
created_at: 2025-04-18T13:29:03Z
author_association: COLLABORATOR
diff_hunk: @@ -2379,19 +2470,17 @@ impl<'a> CfgValIter<'a> {
     }
 }
 
-impl core::iter::Iterator for CfgValIter<'_> {
path: ublox/src/ubx_packets/packets.rs
user: login: CramBL
body: Pretty sure this lifetime can be elided
created_at: 2025-04-18T13:31:07Z
author_association: COLLABORATOR
diff_hunk: @@ -42,6 +42,16 @@ impl KeyId {
     pub const fn item_id(&self) -> u8 {
         self.0 as u8
     }
+
+    pub fn extend_to<T>(&self, buf: &mut T) -> usize
path: ublox/src/ubx_packets/cfg_val.rs
user: login: CramBL
body: To be honest I don't really understand this implementation, why do we require the buffer to have the same length as what we extend it with?
created_at: 2025-04-18T13:36:18Z
author_association: COLLABORATOR
diff_hunk: @@ -120,6 +136,21 @@ macro_rules! from_cfg_v_bytes {
             _ => unreachable!(),
         }
     };
+    ($buf:expr, TModeMode) => {
+        match $buf[0] {
+            0 => TModeMode::Disabled,
+            1 => TModeMode::SurveyIn,
+            2 => TModeMode::FixedMode,
+            _ => unreachable!(),
path: ublox/src/ubx_packets/cfg_val.rs
user: login: andrei-ng
body: Good point, thanks!
I added specific messages to almost all `unreachable` code blocks. Please review that specific part again @CramBL .
created_at: 2025-04-22T11:06:05Z
author_association: COLLABORATOR
diff_hunk: @@ -2358,6 +2358,97 @@ struct CfgValSet<'a> {
     cfg_data: &'a [CfgVal],
 }
 
+pub const MAX_CFG_KEYS: u16 = 64;
+
+#[ubx_packet_send]
+#[ubx(
+  class = 0x06,
+  id = 0x8b,
+  max_payload_len = 260, // 4 + sizeof(u32) * MAX_CFG_KEYS
+)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+struct CfgValGet<'a> {
+    /// Message version
+    version: u8,
+    /// The layers from which the configuration items should be retrieved
+    #[ubx(map_type = CfgReadLayer)]
+    layers: u8,
+    position: u16,
+    cfg_keys: &'a [CfgKey],
path: ublox/src/ubx_packets/packets.rs
user: login: andrei-ng
body: Not sure it matters that much here as we have a single lifetime specifier. But I will do it. 
created_at: 2025-04-22T11:13:45Z
author_association: COLLABORATOR
diff_hunk: @@ -42,6 +42,16 @@ impl KeyId {
     pub const fn item_id(&self) -> u8 {
         self.0 as u8
     }
+
+    pub fn extend_to<T>(&self, buf: &mut T) -> usize
+    where
+        T: core::iter::Extend<u8>,
+    {
+        let bytes = self.0.to_le_bytes();
+        assert_eq!(bytes.len(), Self::SIZE);
path: ublox/src/ubx_packets/cfg_val.rs
user: login: andrei-ng
body: True. It should not be there. Probably it was a leftover from the debugging phase of the original development.
created_at: 2025-04-22T11:16:48Z
author_association: COLLABORATOR
diff_hunk: @@ -42,6 +42,16 @@ impl KeyId {
     pub const fn item_id(&self) -> u8 {
         self.0 as u8
     }
+
+    pub fn extend_to<T>(&self, buf: &mut T) -> usize
path: ublox/src/ubx_packets/cfg_val.rs
user: login: andrei-ng
body: true
created_at: 2025-04-22T11:22:01Z
author_association: COLLABORATOR
diff_hunk: @@ -2358,6 +2358,97 @@ struct CfgValSet<'a> {
     cfg_data: &'a [CfgVal],
 }
 
+pub const MAX_CFG_KEYS: u16 = 64;
+
+#[ubx_packet_send]
+#[ubx(
+  class = 0x06,
+  id = 0x8b,
+  max_payload_len = 260, // 4 + sizeof(u32) * MAX_CFG_KEYS
+)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+struct CfgValGet<'a> {
+    /// Message version
+    version: u8,
+    /// The layers from which the configuration items should be retrieved
+    #[ubx(map_type = CfgReadLayer)]
+    layers: u8,
+    position: u16,
+    cfg_keys: &'a [CfgKey],
path: ublox/src/ubx_packets/packets.rs
user: login: andrei-ng
body: Interestingly, trying to fix your suggestion made me catch this ... The lifetime needs to always be `'a` as it is hardcoded in the macro here https://github.com/ublox-rs/ublox/blob/0f9889bf9fc30ef71e13cff6610c20e2bf8beb6d/ublox_derive/src/output.rs#L449

Interestingly, the lifetime specifier for the struct definition does not seem to be needed.

@CramBL, any ideas here? Should we change/improve the macro or tackle it as part of another issue/PR next?
created_at: 2025-04-22T11:35:15Z
author_association: COLLABORATOR
diff_hunk: @@ -2358,6 +2358,97 @@ struct CfgValSet<'a> {
     cfg_data: &'a [CfgVal],
 }
 
+pub const MAX_CFG_KEYS: u16 = 64;
+
+#[ubx_packet_send]
+#[ubx(
+  class = 0x06,
+  id = 0x8b,
+  max_payload_len = 260, // 4 + sizeof(u32) * MAX_CFG_KEYS
+)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+struct CfgValGet<'a> {
+    /// Message version
+    version: u8,
+    /// The layers from which the configuration items should be retrieved
+    #[ubx(map_type = CfgReadLayer)]
+    layers: u8,
+    position: u16,
+    cfg_keys: &'a [CfgKey],
+}
+
+#[ubx_packet_recv]
+#[ubx(
+  class = 0x06,
+  id = 0x8b,
+  max_payload_len = 772, // 4 + (sizeof(u32) + sizeof(largest val)) * MAX_CFG_KEYS
+)]
+struct CfgValGetResponse {
+    /// Message version
+    version: u8,
+    #[ubx(map_type = CfgReadLayer)]
+    layers: u8,
+    position: u16,
+    #[ubx(
+        map_type = CfgValReadIter,
+        from = CfgValReadIter::new,
+        may_fail,
+        is_valid = CfgValReadIter::is_valid,
+    )]
+    cfg_data: [u8; 0],
+}
+
+/// The `CfgReadLayer` enum is used to specify the configuration layer to read from.
+/// The configuration system in the ublox device is stacked, so a property
+/// may be empty for a particular layer and you will receive a NAK.
+#[ubx_extend]
+#[ubx(from, into_raw, rest_reserved)]
+#[repr(u8)]
+#[derive(Debug, Copy, Clone)]
+pub enum CfgReadLayer {
+    /// Read from RAM
+    Ram = 0,
+    /// Read from Bbr (battery backed RAM)
+    Bbr = 1,
+    /// Read from Flash, if available
+    Flash = 2,
+    /// Read the current configuration from the active source
+    Default = 7,
+}
+
+#[derive(Debug, Clone)]
+pub struct CfgValReadIter<'a> {
+    data: &'a [u8],
+}
+
+impl<'a> CfgValReadIter<'a> {
+    fn new(data: &'a [u8]) -> Self {
+        // todo!("stolen from RxmRawxInfoIter. Reimplement.");
+        Self { data }
+    }
+
+    fn is_valid(bytes: &'a [u8]) -> bool {
+        // we need at least 5 bytes for a key id (4) + val (1)
+        bytes.len() >= 5
+    }
+}
+
+impl<'a> core::iter::Iterator for CfgValReadIter<'a> {
+    type Item = CfgVal;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if Self::is_valid(self.data) {
+            if let Some(cfg_val) = CfgVal::parse(self.data) {
+                self.data = &self.data[cfg_val.len()..];
+                return Some(cfg_val);
+            }
+            // TODO: Is there some logging mechanism?
+            // eprintln!("Failure parsing key in (key,value) list, {:?}", self.data);
path: ublox/src/ubx_packets/packets.rs
user: login: andrei-ng
body: I will make an issue out of this. We should add something along those lines, but not as part of this PR as at least `defmt` will require a bit of work and testing.
created_at: 2025-04-22T11:42:21Z
author_association: COLLABORATOR
diff_hunk: @@ -42,6 +42,16 @@ impl KeyId {
     pub const fn item_id(&self) -> u8 {
         self.0 as u8
     }
+
+    pub fn extend_to<T>(&self, buf: &mut T) -> usize
path: ublox/src/ubx_packets/cfg_val.rs
user: login: andrei-ng
body: Looking at the code, this seems to be a mistake. Maybe the intention was to limit the number of keys the user can request. The F9R documentation specifies that `This message is limited to containing a maximum of 64 key IDs.` If I were to guess, maybe the intention was to limit the buffer to `MAX_CFG_KEYS = 64`. That is something @stevenlovegrove could confirm/deny. 
created_at: 2025-04-22T11:59:07Z
author_association: COLLABORATOR
diff_hunk: @@ -42,6 +42,16 @@ impl KeyId {
     pub const fn item_id(&self) -> u8 {
         self.0 as u8
     }
+
+    pub fn extend_to<T>(&self, buf: &mut T) -> usize
path: ublox/src/ubx_packets/cfg_val.rs
user: login: andrei-ng
body: Anyway, in the meantime I've decided to remove the `assert` alltogether.
created_at: 2025-04-22T12:05:07Z
author_association: COLLABORATOR
diff_hunk: @@ -236,15 +295,19 @@ macro_rules! cfg_val {
       }
 
       #[track_caller]
-      pub fn parse(buf: &[u8]) -> Self {
+      pub fn parse(buf: &[u8]) -> Option<Self> {
         let key_id = u32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]);
         match key_id {
           $(
             $cfg_key_id => {
-              Self::$cfg_item(from_cfg_v_bytes!(&buf[4..], $cfg_value_type))
+              Some(Self::$cfg_item(from_cfg_v_bytes!(&buf[4..], $cfg_value_type)))
             },
           )*
-          _ => unimplemented!("unknown key ID: 0x{:8X}", key_id),
+          _ => {
+            // TODO: add a mechanism to log such messages that supports also no_std
+            // eprintln!("unknown key ID: 0x{:8X}", key_id);
+            None
+           },
path: ublox/src/ubx_packets/cfg_val.rs
user: login: andrei-ng
body: I think you are right. The `parse` function seems to be called only in the `CfgValIter` `next` method so at that level, Result can be handled the same as the Option. 
created_at: 2025-04-22T13:41:09Z
author_association: COLLABORATOR
diff_hunk: @@ -236,15 +295,19 @@ macro_rules! cfg_val {
       }
 
       #[track_caller]
-      pub fn parse(buf: &[u8]) -> Self {
+      pub fn parse(buf: &[u8]) -> Option<Self> {
         let key_id = u32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]);
         match key_id {
           $(
             $cfg_key_id => {
-              Self::$cfg_item(from_cfg_v_bytes!(&buf[4..], $cfg_value_type))
+              Some(Self::$cfg_item(from_cfg_v_bytes!(&buf[4..], $cfg_value_type)))
             },
           )*
-          _ => unimplemented!("unknown key ID: 0x{:8X}", key_id),
+          _ => {
+            // TODO: add a mechanism to log such messages that supports also no_std
+            // eprintln!("unknown key ID: 0x{:8X}", key_id);
+            None
+           },
path: ublox/src/ubx_packets/cfg_val.rs
user: login: CramBL
body: good point but a little confusing...
created_at: 2025-04-22T13:51:45Z
author_association: COLLABORATOR
diff_hunk: @@ -2358,6 +2358,97 @@ struct CfgValSet<'a> {
     cfg_data: &'a [CfgVal],
 }
 
+pub const MAX_CFG_KEYS: u16 = 64;
+
+#[ubx_packet_send]
+#[ubx(
+  class = 0x06,
+  id = 0x8b,
+  max_payload_len = 260, // 4 + sizeof(u32) * MAX_CFG_KEYS
+)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+struct CfgValGet<'a> {
+    /// Message version
+    version: u8,
+    /// The layers from which the configuration items should be retrieved
+    #[ubx(map_type = CfgReadLayer)]
+    layers: u8,
+    position: u16,
+    cfg_keys: &'a [CfgKey],
path: ublox/src/ubx_packets/packets.rs
user: login: CramBL
body: haha yea that's pretty ugly, it has to be part of the macro refactor at a later time imo
created_at: 2025-04-22T13:53:11Z
author_association: COLLABORATOR
diff_hunk: @@ -2358,6 +2358,97 @@ struct CfgValSet<'a> {
     cfg_data: &'a [CfgVal],
 }
 
+pub const MAX_CFG_KEYS: u16 = 64;
+
+#[ubx_packet_send]
+#[ubx(
+  class = 0x06,
+  id = 0x8b,
+  max_payload_len = 260, // 4 + sizeof(u32) * MAX_CFG_KEYS
+)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+struct CfgValGet<'a> {
+    /// Message version
+    version: u8,
+    /// The layers from which the configuration items should be retrieved
+    #[ubx(map_type = CfgReadLayer)]
+    layers: u8,
+    position: u16,
+    cfg_keys: &'a [CfgKey],
+}
+
+#[ubx_packet_recv]
+#[ubx(
+  class = 0x06,
+  id = 0x8b,
+  max_payload_len = 772, // 4 + (sizeof(u32) + sizeof(largest val)) * MAX_CFG_KEYS
+)]
+struct CfgValGetResponse {
+    /// Message version
+    version: u8,
+    #[ubx(map_type = CfgReadLayer)]
+    layers: u8,
+    position: u16,
+    #[ubx(
+        map_type = CfgValReadIter,
+        from = CfgValReadIter::new,
+        may_fail,
+        is_valid = CfgValReadIter::is_valid,
+    )]
+    cfg_data: [u8; 0],
+}
+
+/// The `CfgReadLayer` enum is used to specify the configuration layer to read from.
+/// The configuration system in the ublox device is stacked, so a property
+/// may be empty for a particular layer and you will receive a NAK.
+#[ubx_extend]
+#[ubx(from, into_raw, rest_reserved)]
+#[repr(u8)]
+#[derive(Debug, Copy, Clone)]
+pub enum CfgReadLayer {
+    /// Read from RAM
+    Ram = 0,
+    /// Read from Bbr (battery backed RAM)
+    Bbr = 1,
+    /// Read from Flash, if available
+    Flash = 2,
+    /// Read the current configuration from the active source
+    Default = 7,
+}
+
+#[derive(Debug, Clone)]
+pub struct CfgValReadIter<'a> {
+    data: &'a [u8],
+}
+
+impl<'a> CfgValReadIter<'a> {
+    fn new(data: &'a [u8]) -> Self {
+        // todo!("stolen from RxmRawxInfoIter. Reimplement.");
+        Self { data }
+    }
+
+    fn is_valid(bytes: &'a [u8]) -> bool {
+        // we need at least 5 bytes for a key id (4) + val (1)
+        bytes.len() >= 5
+    }
+}
+
+impl<'a> core::iter::Iterator for CfgValReadIter<'a> {
+    type Item = CfgVal;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if Self::is_valid(self.data) {
+            if let Some(cfg_val) = CfgVal::parse(self.data) {
+                self.data = &self.data[cfg_val.len()..];
+                return Some(cfg_val);
+            }
+            // TODO: Is there some logging mechanism?
+            // eprintln!("Failure parsing key in (key,value) list, {:?}", self.data);
path: ublox/src/ubx_packets/packets.rs
user: login: CramBL
body: for sure, it is a project in itself
created_at: 2025-04-22T13:53:54Z
author_association: COLLABORATOR
diff_hunk: @@ -2358,6 +2358,97 @@ struct CfgValSet<'a> {
     cfg_data: &'a [CfgVal],
 }
 
+pub const MAX_CFG_KEYS: u16 = 64;
+
+#[ubx_packet_send]
+#[ubx(
+  class = 0x06,
+  id = 0x8b,
+  max_payload_len = 260, // 4 + sizeof(u32) * MAX_CFG_KEYS
+)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+struct CfgValGet<'a> {
+    /// Message version
+    version: u8,
+    /// The layers from which the configuration items should be retrieved
+    #[ubx(map_type = CfgReadLayer)]
+    layers: u8,
+    position: u16,
+    cfg_keys: &'a [CfgKey],
path: ublox/src/ubx_packets/packets.rs
user: login: andrei-ng
body: I'll turn this into an issue and resolve the comment.
created_at: 2025-04-22T14:08:57Z
author_association: COLLABORATOR
diff_hunk: @@ -1124,3 +1244,19 @@ pub enum TpPulseLength {
     /// Time pulse length
     Length = 1,
 }
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum TModeMode {
+    Disabled = 0,
+    SurveyIn = 1,
+    // true ARP position information required
path: ublox/src/ubx_packets/cfg_val.rs
user: login: andrei-ng
body: Done!
created_at: 2025-04-23T07:02:49Z
author_association: COLLABORATOR
diff_hunk: @@ -5069,6 +5085,24 @@ struct SecUniqId {
     unique_id: [u8; 5],
 }
 
+/// The `CfgReadLayer` enum is used to specify the configuration layer to read from.
+/// The configuration system in the ublox device is stacked, so a property
+/// may be empty for a particular layer and you will receive a NAK.
+#[ubx_extend]
+#[ubx(from_unchecked, into_raw, rest_error)]
+#[repr(u8)]
+#[derive(Debug, Copy, Clone)]
+pub enum CfgReadLayer {
path: ublox/src/ubx_packets/packets.rs
user: login: andrei-ng
body: @gwbres  Unfortunately it is not possible. uBlox must have messed it up here. The definition of the Layer is different between CFG-VALSET and CFG-VALGET, so unfortunately we cannot reuse it. I just renamed the two to give them a more representative name `CfgLayerSet` and `CfgLayerGet`. Other suggestions are welcome :) 
created_at: 2025-04-23T07:14:36Z
author_association: COLLABORATOR

PR comments:
user: login: andrei-ng
created_at: 2025-04-18T10:41:46Z
body: @CramBL, @gwbres , I will be splitting the original PR #56 into 3:
 - 1st one: (this current PR) related to adding support for UBX-CFG-VALGET
 - ~2nd one: related to the additon of extra messages (TODO  ... )~ (after checking, the new packages have made it to master in the meantime, this PR is not needed)
 - 3rd one: based basically only on this commit: [Add support for extracting RTCM packets from stream unparsed ... ](https://github.com/ublox-rs/ublox/pull/56/commits/835f44e821b8a4c73d155e365ce52cd363482ca0)  (TODO  ... )

Please review and let me know if you spot anything I might have missed. 

EDIT: @stevenlovegrove, @Hackerman342 please feel free to review as well.

author_association: COLLABORATOR
user: login: CramBL
created_at: 2025-04-18T11:36:33Z
body: You are still working on making the semver checks pass right? Just checking because I prefer waiting for CI to pass before starting review
author_association: COLLABORATOR
user: login: andrei-ng
created_at: 2025-04-18T11:39:02Z
body: > You are still working on making the semver checks pass right? Just checking because I prefer waiting for CI to pass before starting review

Semver won't pass as this PR introudces 
 - new packet in Recv enum
 - renames enum variants in CfgVal

So this will require a new major bump eventually :( 
author_association: COLLABORATOR
user: login: CramBL
created_at: 2025-04-18T12:16:32Z
body: > > You are still working on making the semver checks pass right? Just checking because I prefer waiting for CI to pass before starting review
> 
> Semver won't pass as this PR introudces
> 
>     * new packet in Recv enum
> 
>     * renames enum variants in CfgVal
> 
> 
> So this will require a new major bump eventually :(

Oh okay. I'll take a look then, maybe we should consider 1.0.0 in the not too distant future.
author_association: COLLABORATOR
user: login: gwbres
created_at: 2025-04-18T13:58:13Z
body: Hello, I'll have some time to review your work and test it tomorrow, I will keep you updated
author_association: COLLABORATOR
user: login: andrei-ng
created_at: 2025-04-22T13:03:48Z
body: @CramBL , @gwbres, originally when I created the PR, I simply cherry-picked the old PR's commits and fixed any compiler issues along the way, As @CramBL proposed improvements, I looked closer at the implementation and I realised that this implemenation brought back an older issues I had with the macros implementation in the crate. 

The messages added by this PR `CfgValGet` and `CfgValGetResponse` are in implemented using the `#[ubx_packet_send]` macro and `#[ubx_packet_recv]` respectively. But these are in principle the same message (same class and same message ID), and our crate has in theory support for `#[ubx_packet_recv_send]` messages. However, this macro never worked with messages that have variable payloads. I faced the same issue way back when I was trying to implement the `UbxEsfMeas` message which can also be sent or received. 

So my question to both of you is how to address this going forward. For this kind of messages, do we stick with two different derived implementations: one using  `#[ubx_packet_send]` macro and one with `#[ubx_packet_recv]` or should we spend some time and try to find a way to make  `#[ubx_packet_recv_send]` work in this kind of cases. (for that I would need @CramBL macro know-how though ... ) . And how do we go forward with this PR?


author_association: COLLABORATOR
user: login: CramBL
created_at: 2025-04-22T14:02:21Z
body: > @CramBL , @gwbres, originally when I created the PR, I simply cherry-picked the old PR's commits and fixed any compiler issues along the way, As @CramBL proposed improvements, I looked closer at the implementation and I realised that this implemenation brought back an older issues I had with the macros implementation in the crate.
> 
> The messages added by this PR `CfgValGet` and `CfgValGetResponse` are in implemented using the `#[ubx_packet_send]` macro and `#[ubx_packet_recv]` respectively. But these are in principle the same message (same class and same message ID), and our crate has in theory support for `#[ubx_packet_recv_send]` messages. However, this macro never worked with messages that have variable payloads. I faced the same issue way back when I was trying to implement the `UbxEsfMeas` message which can also be sent or received.
> 
> So my question to both of you is how to address this going forward. For this kind of messages, do we stick with two different derived implementations: one using `#[ubx_packet_send]` macro and one with `#[ubx_packet_recv]` or should we spend some time and try to find a way to make `#[ubx_packet_recv_send]` work in this kind of cases. (for that I would need @CramBL macro know-how though ... ) . And how do we go forward with this PR?

I guess we **should** try to make `#[ubx_packet_recv_send]` work.

Should we start by getting all of this stuff merged in good condition and then make `#[ubx_packet_recv_send]` work afterwards? We need to do it before the next release though, so we don't immediately have to do another breaking change.
author_association: COLLABORATOR
user: login: andrei-ng
created_at: 2025-04-22T14:18:00Z
body: > Should we start by getting all of this stuff merged in good condition and then make `#[ubx_packet_recv_send]` work afterwards? We need to do it before the next release though, so we don't immediately have to do another breaking change.

Yes, my thinking would be the same, 
 - we **should** first try to make it work, if we fail, then we know we've tried and we don't have a clear way forward.
 - I also think we should merge this the rest of the work from the old PR in and only then rework  `#[ubx_packet_recv_send]` prior to any major release. 
 - the fact that  `#[ubx_packet_recv_send]` is not working with variable payload is bloking me in implementing `EsfMeas` and as far as I remember blocking at least a few others, like @aholtzma-am for CfgGnss (and @gwbres ) [as discussed  [here](https://github.com/ublox-rs/ublox/pull/73#issuecomment-2729664598), so it is an issue that comes up again and again :grin: 
author_association: COLLABORATOR
user: login: andrei-ng
created_at: 2025-04-22T14:27:57Z
body: Once @gwbres reviews it, I will merge it in and continue with the remaining of #56 
author_association: COLLABORATOR