use crate::binrw_util;
use crate::{NestedBlock, NestedHeader, SubBlock};
use alloc::vec::Vec;
use binrw::binrw;
use bitflags::bitflags;
use core::ops::RangeInclusive;
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MeasEpochCommonFlags: u8 {
const MULTIPATH_MITIGATION = 1 << 0;
const SMOOTHING = 1 << 1;
const CLOCK_STEERING = 1 << 3;
const HIGH_DYNAMICS = 1 << 5;
const E6B_USED = 1 << 6;
const SCRAMBLED = 1 << 7;
}
}
const SIG_NR_ESCAPE: u8 = 31;
const SIG_NR_EXTENSION_OFFSET: u8 = 32;
const GLONASS_SIG_NRS: RangeInclusive<u8> = 8..=11;
const GLONASS_FREQ_NR_OFFSET: i8 = 8;
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MeasEpochObsInfo: u8 {
const SMOOTHED = 1 << 0;
const HALF_CYCLE_AMBIGUITY = 1 << 2;
const SIG_IDX_HI_MASK = 0b11111 << Self::SIG_IDX_HI_SHIFT;
}
}
impl MeasEpochObsInfo {
const SIG_IDX_HI_SHIFT: u32 = 3;
pub fn sig_idx_hi(&self) -> u8 {
self.intersection(Self::SIG_IDX_HI_MASK).bits() >> Self::SIG_IDX_HI_SHIFT
}
}
#[binrw]
#[derive(Clone, Debug)]
pub struct MeasEpoch {
#[br(map = binrw_util::map_u4)]
#[bw(map = binrw_util::unmap_u4)]
pub tow: Option<u32>,
#[br(map = binrw_util::map_u2)]
#[bw(map = binrw_util::unmap_u2)]
pub wnc: Option<u16>,
pub n1: u8,
pub sb1_length: u8,
pub sb2_length: u8,
#[br(map = |x: u8| MeasEpochCommonFlags::from_bits_retain(x))]
#[bw(map = |x: &MeasEpochCommonFlags| x.bits())]
pub common_flags: MeasEpochCommonFlags,
pub cum_clk_jumps: u8,
pub rev1: u8,
#[br(args { count: usize::from(n1), inner: (usize::from(sb1_length), usize::from(sb2_length)) },
map = |v: Vec<NestedBlock<MeasEpochChannelType1Header, MeasEpochChannelType2>>| v.into_iter().map(MeasEpochChannelType1::from).collect())]
#[bw(args_raw = (usize::from(*sb1_length), usize::from(*sb2_length)),
map = |v: &Vec<MeasEpochChannelType1>| v.iter().cloned().map(NestedBlock::from).collect::<Vec<NestedBlock<MeasEpochChannelType1Header, MeasEpochChannelType2>>>())]
pub channel_type1: Vec<MeasEpochChannelType1>,
}
#[binrw]
#[derive(Clone, Debug)]
struct MeasEpochChannelType1Header {
pub rx_channel: u8,
pub type_field: u8,
pub svid: u8,
pub misc: u8,
pub code_lsb: u32,
#[br(map = |x: i32| if x == -2147483648 { None } else { Some(x) })]
#[bw(map = |x: &Option<i32>| x.unwrap_or(-2147483648))]
pub doppler: Option<i32>,
pub carrier_lsb: u16,
pub carrier_msb: i8,
#[br(map = binrw_util::map_u1)]
#[bw(map = binrw_util::unmap_u1)]
pub cn0: Option<u8>,
#[br(map = binrw_util::map_u2)]
#[bw(map = binrw_util::unmap_u2)]
pub lock_time: Option<u16>,
#[br(map = MeasEpochObsInfo::from_bits_retain)]
#[bw(map = |x: &MeasEpochObsInfo| x.bits())]
pub obs_info: MeasEpochObsInfo,
pub n2: u8,
}
impl NestedHeader for MeasEpochChannelType1Header {
fn nested_count(&self) -> usize {
usize::from(self.n2)
}
}
#[derive(Clone, Debug)]
pub struct MeasEpochChannelType1 {
pub rx_channel: u8,
pub type_field: u8,
pub svid: u8,
pub misc: u8,
pub code_lsb: u32,
pub doppler: Option<i32>,
pub carrier_lsb: u16,
pub carrier_msb: i8,
pub cn0: Option<u8>,
pub lock_time: Option<u16>,
pub obs_info: MeasEpochObsInfo,
pub n2: u8,
pub channel_type2: Vec<MeasEpochChannelType2>,
}
impl From<NestedBlock<MeasEpochChannelType1Header, MeasEpochChannelType2>> for MeasEpochChannelType1 {
fn from(nb: NestedBlock<MeasEpochChannelType1Header, MeasEpochChannelType2>) -> Self {
MeasEpochChannelType1 {
rx_channel: nb.header.rx_channel,
type_field: nb.header.type_field,
svid: nb.header.svid,
misc: nb.header.misc,
code_lsb: nb.header.code_lsb,
doppler: nb.header.doppler,
carrier_lsb: nb.header.carrier_lsb,
carrier_msb: nb.header.carrier_msb,
cn0: nb.header.cn0,
lock_time: nb.header.lock_time,
obs_info: nb.header.obs_info,
n2: nb.header.n2,
channel_type2: nb.items.into_iter().map(SubBlock::into_inner).collect(),
}
}
}
impl From<MeasEpochChannelType1> for NestedBlock<MeasEpochChannelType1Header, MeasEpochChannelType2> {
fn from(ct1: MeasEpochChannelType1) -> Self {
NestedBlock {
header: MeasEpochChannelType1Header {
rx_channel: ct1.rx_channel,
type_field: ct1.type_field,
svid: ct1.svid,
misc: ct1.misc,
code_lsb: ct1.code_lsb,
doppler: ct1.doppler,
carrier_lsb: ct1.carrier_lsb,
carrier_msb: ct1.carrier_msb,
cn0: ct1.cn0,
lock_time: ct1.lock_time,
obs_info: ct1.obs_info,
n2: ct1.n2,
},
items: ct1.channel_type2.into_iter().map(SubBlock::from).collect(),
}
}
}
impl MeasEpochChannelType1 {
pub fn antenna_id(&self) -> u8 {
self.type_field >> 5
}
pub fn signal_number(&self) -> u8 {
let sig_idx_lo = self.type_field & 0x1F;
if sig_idx_lo == SIG_NR_ESCAPE {
SIG_NR_EXTENSION_OFFSET + self.obs_info.sig_idx_hi()
} else {
sig_idx_lo
}
}
pub fn glonass_freq_nr(&self) -> Option<i8> {
let sig_idx_lo = self.type_field & 0x1F;
if GLONASS_SIG_NRS.contains(&sig_idx_lo) {
Some(self.obs_info.sig_idx_hi() as i8 - GLONASS_FREQ_NR_OFFSET)
} else {
None
}
}
}
#[binrw]
#[derive(Clone, Debug)]
pub struct MeasEpochChannelType2 {
pub type_field: u8,
#[br(map = binrw_util::map_u1)]
#[bw(map = binrw_util::unmap_u1)]
pub lock_time: Option<u8>,
#[br(map = binrw_util::map_u1)]
#[bw(map = binrw_util::unmap_u1)]
pub cn0: Option<u8>,
pub offsets_msb: u8,
pub carrier_msb: i8,
#[br(map = MeasEpochObsInfo::from_bits_retain)]
#[bw(map = |x: &MeasEpochObsInfo| x.bits())]
pub obs_info: MeasEpochObsInfo,
pub code_offset_lsb: u16,
pub carrier_lsb: u16,
pub doppler_offset_lsb: u16,
}
impl MeasEpochChannelType2 {
pub fn antenna_id(&self) -> u8 {
self.type_field >> 5
}
pub fn signal_number(&self) -> u8 {
let sig_idx_lo = self.type_field & 0x1F;
if sig_idx_lo == SIG_NR_ESCAPE {
SIG_NR_EXTENSION_OFFSET + self.obs_info.sig_idx_hi()
} else {
sig_idx_lo
}
}
}