#[allow(unused_imports, reason = "It is only unused in some feature sets")]
use crate::FieldIter;
#[cfg(feature = "serde")]
use {super::SerializeUbxPacketFields, crate::serde::ser::SerializeMap};
use crate::{error::ParserError, UbxPacketMeta};
use ublox_derive::ubx_packet_recv;
#[ubx_packet_recv]
#[ubx(class = 0x0a, id = 0x04, max_payload_len = 1240)]
pub struct MonVer {
#[ubx(map_type = &str, may_fail, from = convert_to_str_unchecked,
is_valid = is_cstr_valid, get_as_ref)]
software_version: [u8; 30],
#[ubx(map_type = &str, may_fail, from = convert_to_str_unchecked,
is_valid = is_cstr_valid, get_as_ref)]
hardware_version: [u8; 10],
#[ubx(map_type = MonVerExtensionIter, may_fail,
from = MonVerExtensionIter::new,
is_valid = MonVerExtensionIter::is_valid)]
extension: [u8; 0],
}
pub(crate) fn convert_to_str_unchecked(bytes: &[u8]) -> &str {
let null_pos = bytes
.iter()
.position(|x| *x == 0)
.expect("is_cstr_valid bug?");
core::str::from_utf8(&bytes[0..null_pos])
.expect("is_cstr_valid should have prevented this code from running")
}
pub(crate) fn is_cstr_valid(bytes: &[u8]) -> bool {
let null_pos = match bytes.iter().position(|x| *x == 0) {
Some(pos) => pos,
None => {
return false;
},
};
core::str::from_utf8(&bytes[0..null_pos]).is_ok()
}
#[derive(Debug, Clone)]
pub struct MonVerExtensionIter<'a> {
data: &'a [u8],
offset: usize,
}
impl<'a> MonVerExtensionIter<'a> {
fn new(data: &'a [u8]) -> Self {
Self { data, offset: 0 }
}
fn is_valid(payload: &[u8]) -> bool {
payload.len().is_multiple_of(30) && payload.chunks(30).all(is_cstr_valid)
}
}
impl<'a> core::iter::Iterator for MonVerExtensionIter<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<Self::Item> {
while self.offset < self.data.len() {
let data = &self.data[self.offset..self.offset + 30];
self.offset += 30;
if is_cstr_valid(data) {
let str_result = convert_to_str_unchecked(data);
if !str_result.is_empty() {
return Some(str_result);
}
} else {
return None;
}
}
None
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn mon_ver_rom_interpret() {
let payload: [u8; 160] = [
82, 79, 77, 32, 67, 79, 82, 69, 32, 51, 46, 48, 49, 32, 40, 49, 48, 55, 56, 56, 56, 41,
0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 56, 48, 48, 48, 48, 0, 0, 70, 87, 86, 69, 82, 61,
83, 80, 71, 32, 51, 46, 48, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 82,
79, 84, 86, 69, 82, 61, 49, 56, 46, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 71, 80, 83, 59, 71, 76, 79, 59, 71, 65, 76, 59, 66, 68, 83, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 66, 65, 83, 59, 73, 77, 69, 83, 59, 81, 90, 83, 83, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
assert_eq!(Ok(()), <MonVerRef>::validate(&payload));
let ver = MonVerRef(&payload);
assert_eq!("ROM CORE 3.01 (107888)", ver.software_version());
assert_eq!("00080000", ver.hardware_version());
let mut it = ver.extension();
assert_eq!("FWVER=SPG 3.01", it.next().unwrap());
assert_eq!("PROTVER=18.00", it.next().unwrap());
assert_eq!("GPS;GLO;GAL;BDS", it.next().unwrap());
assert_eq!("SBAS;IMES;QZSS", it.next().unwrap());
assert_eq!(None, it.next());
}
#[test]
fn mon_ver_flash_m8l_interpret() {
let payload: [u8; 250] = [
69, 88, 84, 32, 67, 79, 82, 69, 32, 51, 46, 48, 49, 32, 40, 100, 49, 56, 57, 102, 102,
41, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 56, 48, 48, 48, 48, 0, 0, 82, 79, 77, 32, 66,
65, 83, 69, 32, 51, 46, 48, 49, 32, 40, 49, 48, 55, 56, 56, 56, 41, 0, 0, 0, 0, 0, 0,
0, 0, 70, 87, 86, 69, 82, 61, 65, 68, 82, 32, 52, 46, 49, 49, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 80, 82, 79, 84, 86, 69, 82, 61, 49, 57, 46, 49, 48, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 79, 68, 61, 78, 69, 79, 45, 77, 56, 76, 45,
48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 73, 83, 61, 48, 120, 69, 70,
52, 48, 49, 53, 32, 40, 49, 48, 48, 49, 49, 49, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 80,
83, 59, 71, 76, 79, 59, 71, 65, 76, 59, 66, 68, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 83, 66, 65, 83, 59, 73, 77, 69, 83, 59, 81, 90, 83, 83, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,
];
assert_eq!(Ok(()), <MonVerRef>::validate(&payload));
let ver = MonVerRef(&payload);
assert_eq!("EXT CORE 3.01 (d189ff)", ver.software_version());
assert_eq!("00080000", ver.hardware_version());
let mut it = ver.extension();
assert_eq!("ROM BASE 3.01 (107888)", it.next().unwrap());
assert_eq!("FWVER=ADR 4.11", it.next().unwrap());
assert_eq!("PROTVER=19.10", it.next().unwrap());
assert_eq!("MOD=NEO-M8L-0", it.next().unwrap());
assert_eq!("FIS=0xEF4015 (100111)", it.next().unwrap());
assert_eq!("GPS;GLO;GAL;BDS", it.next().unwrap());
assert_eq!("SBAS;IMES;QZSS", it.next().unwrap());
assert_eq!(None, it.next());
}
#[test]
#[cfg(feature = "std")]
fn mon_ver_to_owned() {
let payload: [u8; 160] = [
82, 79, 77, 32, 67, 79, 82, 69, 32, 51, 46, 48, 49, 32, 40, 49, 48, 55, 56, 56, 56, 41,
0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 56, 48, 48, 48, 48, 0, 0, 70, 87, 86, 69, 82, 61,
83, 80, 71, 32, 51, 46, 48, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 82,
79, 84, 86, 69, 82, 61, 49, 56, 46, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 71, 80, 83, 59, 71, 76, 79, 59, 71, 65, 76, 59, 66, 68, 83, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 66, 65, 83, 59, 73, 77, 69, 83, 59, 81, 90, 83, 83, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
assert_eq!(Ok(()), <MonVerRef>::validate(&payload));
let ver = MonVerRef(&payload);
let sw = ver.software_version();
let sw_raw = ver.software_version_raw();
let hw = ver.hardware_version();
let hw_raw = ver.hardware_version_raw();
let ext = ver
.extension()
.map(|s| s.to_owned())
.collect::<Vec<String>>();
let owned = ver.to_owned();
let owned_sw = owned.software_version();
let owned_sw_raw = owned.software_version_raw();
let owned_hw = owned.hardware_version();
let owned_hw_raw = owned.hardware_version_raw();
let owned_ext = owned
.extension()
.map(|s| s.to_owned())
.collect::<Vec<String>>();
assert_eq!(sw, owned_sw);
assert_eq!(sw_raw, owned_sw_raw);
assert_eq!(hw, owned_hw);
assert_eq!(hw_raw, owned_hw_raw);
assert_eq!(ext, owned_ext);
}
}