use crate::error::{Error, Result};
use crate::id::GnssSystem;
use super::bits::{BitReader, BitWriter, OutOfInput};
use super::DecodeResult;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MsmKind {
Msm4,
Msm7,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct MsmHeader {
pub reference_station_id: u16,
pub epoch_time: u32,
pub multiple_message: bool,
pub iods: u8,
pub reserved: u8,
pub clock_steering: u8,
pub external_clock: u8,
pub divergence_free_smoothing: bool,
pub smoothing_interval: u8,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct MsmSatellite {
pub id: u8,
pub rough_range_ms: u8,
pub rough_range_mod1: u16,
pub extended_info: Option<u8>,
pub rough_phase_range_rate_m_s: Option<i16>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct MsmSignal {
pub satellite_id: u8,
pub signal_id: u8,
pub fine_pseudorange: i32,
pub fine_phase_range: i32,
pub lock_time_indicator: u16,
pub half_cycle_ambiguity: bool,
pub cnr: u16,
pub fine_phase_range_rate: Option<i16>,
}
impl MsmSignal {
pub fn minimum_lock_time_ms(&self, kind: MsmKind) -> Option<u32> {
super::lli::minimum_lock_time_ms(kind, self.lock_time_indicator)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MsmMessage {
pub message_number: u16,
pub system: GnssSystem,
pub kind: MsmKind,
pub header: MsmHeader,
pub satellites: Vec<MsmSatellite>,
pub signals: Vec<MsmSignal>,
}
pub(crate) fn msm_kind(message_number: u16) -> Option<(GnssSystem, MsmKind)> {
if !(1071..=1137).contains(&message_number) {
return None;
}
let group = (message_number - 1071) / 10;
let system = match group {
0 => GnssSystem::Gps,
1 => GnssSystem::Glonass,
2 => GnssSystem::Galileo,
3 => GnssSystem::Sbas,
4 => GnssSystem::Qzss,
5 => GnssSystem::BeiDou,
6 => GnssSystem::Navic,
_ => return None,
};
let kind = match message_number % 10 {
4 => MsmKind::Msm4,
7 => MsmKind::Msm7,
_ => return None,
};
Some((system, kind))
}
pub(crate) fn is_supported_msm(message_number: u16) -> bool {
msm_kind(message_number).is_some()
}
impl MsmMessage {
pub fn decode(body: &[u8]) -> Result<Self> {
Self::decode_inner(body).map_err(Into::into)
}
pub(crate) fn decode_inner(body: &[u8]) -> DecodeResult<Self> {
let mut r = BitReader::new(body);
let message_number = r.u(12)? as u16;
let (system, kind) = msm_kind(message_number).ok_or_else(|| {
Error::Parse(format!(
"message {message_number} is not a supported MSM4/MSM7 type"
))
})?;
let header = MsmHeader {
reference_station_id: r.u(12)? as u16,
epoch_time: r.u(30)? as u32,
multiple_message: r.flag()?,
iods: r.u(3)? as u8,
reserved: r.u(7)? as u8,
clock_steering: r.u(2)? as u8,
external_clock: r.u(2)? as u8,
divergence_free_smoothing: r.flag()?,
smoothing_interval: r.u(3)? as u8,
};
let satellite_mask = r.u(64)?;
let signal_mask = r.u(32)? as u32;
let sat_ids = set_bits(satellite_mask, 64);
let sig_ids = set_bits_u32(signal_mask);
let nsat = sat_ids.len();
let nsig = sig_ids.len();
let mut cell_present = Vec::with_capacity(nsat * nsig);
for _ in 0..nsat * nsig {
cell_present.push(r.flag()?);
}
let mut rough_range_ms = Vec::with_capacity(nsat);
for _ in 0..nsat {
rough_range_ms.push(r.u(8)? as u8);
}
let extended_info = if kind == MsmKind::Msm7 {
let mut v = Vec::with_capacity(nsat);
for _ in 0..nsat {
v.push(Some(r.u(4)? as u8));
}
v
} else {
vec![None; nsat]
};
let mut rough_range_mod1 = Vec::with_capacity(nsat);
for _ in 0..nsat {
rough_range_mod1.push(r.u(10)? as u16);
}
let rough_prr = if kind == MsmKind::Msm7 {
let mut v = Vec::with_capacity(nsat);
for _ in 0..nsat {
v.push(Some(r.i(14)? as i16));
}
v
} else {
vec![None; nsat]
};
let satellites: Vec<MsmSatellite> = (0..nsat)
.map(|s| MsmSatellite {
id: sat_ids[s],
rough_range_ms: rough_range_ms[s],
rough_range_mod1: rough_range_mod1[s],
extended_info: extended_info[s],
rough_phase_range_rate_m_s: rough_prr[s],
})
.collect();
let cells = active_cells(&sat_ids, &sig_ids, &cell_present);
let ncell = cells.len();
let signals = match kind {
MsmKind::Msm4 => {
let fine_pr = read_vec(&mut r, ncell, |rr| rr.i(15).map(|v| v as i32))?;
let fine_ph = read_vec(&mut r, ncell, |rr| rr.i(22).map(|v| v as i32))?;
let lock = read_vec(&mut r, ncell, |rr| rr.u(4).map(|v| v as u16))?;
let half = read_vec(&mut r, ncell, |rr| rr.flag())?;
let cnr = read_vec(&mut r, ncell, |rr| rr.u(6).map(|v| v as u16))?;
cells
.iter()
.enumerate()
.map(|(c, &(sat, sig))| MsmSignal {
satellite_id: sat,
signal_id: sig,
fine_pseudorange: fine_pr[c],
fine_phase_range: fine_ph[c],
lock_time_indicator: lock[c],
half_cycle_ambiguity: half[c],
cnr: cnr[c],
fine_phase_range_rate: None,
})
.collect()
}
MsmKind::Msm7 => {
let fine_pr = read_vec(&mut r, ncell, |rr| rr.i(20).map(|v| v as i32))?;
let fine_ph = read_vec(&mut r, ncell, |rr| rr.i(24).map(|v| v as i32))?;
let lock = read_vec(&mut r, ncell, |rr| rr.u(10).map(|v| v as u16))?;
let half = read_vec(&mut r, ncell, |rr| rr.flag())?;
let cnr = read_vec(&mut r, ncell, |rr| rr.u(10).map(|v| v as u16))?;
let fine_prr = read_vec(&mut r, ncell, |rr| rr.i(15).map(|v| v as i16))?;
cells
.iter()
.enumerate()
.map(|(c, &(sat, sig))| MsmSignal {
satellite_id: sat,
signal_id: sig,
fine_pseudorange: fine_pr[c],
fine_phase_range: fine_ph[c],
lock_time_indicator: lock[c],
half_cycle_ambiguity: half[c],
cnr: cnr[c],
fine_phase_range_rate: Some(fine_prr[c]),
})
.collect()
}
};
Ok(Self {
message_number,
system,
kind,
header,
satellites,
signals,
})
}
pub fn encode(&self) -> Vec<u8> {
let mut w = BitWriter::new();
w.push_u(u64::from(self.message_number), 12);
w.push_u(u64::from(self.header.reference_station_id), 12);
w.push_u(u64::from(self.header.epoch_time), 30);
w.push_flag(self.header.multiple_message);
w.push_u(u64::from(self.header.iods), 3);
w.push_u(u64::from(self.header.reserved), 7);
w.push_u(u64::from(self.header.clock_steering), 2);
w.push_u(u64::from(self.header.external_clock), 2);
w.push_flag(self.header.divergence_free_smoothing);
w.push_u(u64::from(self.header.smoothing_interval), 3);
let mut sat_ids: Vec<u8> = self.satellites.iter().map(|s| s.id).collect();
sat_ids.sort_unstable();
let mut satellite_mask: u64 = 0;
for &id in &sat_ids {
satellite_mask |= 1u64 << (64 - u32::from(id));
}
let mut sig_ids: Vec<u8> = self.signals.iter().map(|s| s.signal_id).collect();
sig_ids.sort_unstable();
sig_ids.dedup();
let mut signal_mask: u32 = 0;
for &id in &sig_ids {
signal_mask |= 1u32 << (32 - u32::from(id));
}
w.push_u(satellite_mask, 64);
w.push_u(u64::from(signal_mask), 32);
let mut ordered_cells: Vec<(u8, u8)> = Vec::new();
for &sat in &sat_ids {
for &sig in &sig_ids {
let present = self
.signals
.iter()
.any(|s| s.satellite_id == sat && s.signal_id == sig);
w.push_flag(present);
if present {
ordered_cells.push((sat, sig));
}
}
}
let sat_by_id = |id: u8| self.satellites.iter().find(|s| s.id == id);
for &id in &sat_ids {
let sat = sat_by_id(id);
w.push_u(u64::from(sat.map_or(0, |s| s.rough_range_ms)), 8);
}
if self.kind == MsmKind::Msm7 {
for &id in &sat_ids {
let ext = sat_by_id(id).and_then(|s| s.extended_info).unwrap_or(0);
w.push_u(u64::from(ext), 4);
}
}
for &id in &sat_ids {
let sat = sat_by_id(id);
w.push_u(u64::from(sat.map_or(0, |s| s.rough_range_mod1)), 10);
}
if self.kind == MsmKind::Msm7 {
for &id in &sat_ids {
let prr = sat_by_id(id)
.and_then(|s| s.rough_phase_range_rate_m_s)
.unwrap_or(0);
w.push_i(i64::from(prr), 14);
}
}
let cell_signal = |sat: u8, sig: u8| {
self.signals
.iter()
.find(|s| s.satellite_id == sat && s.signal_id == sig)
.expect("ordered cell must reference an existing signal")
};
let ordered: Vec<&MsmSignal> = ordered_cells
.iter()
.map(|&(sat, sig)| cell_signal(sat, sig))
.collect();
match self.kind {
MsmKind::Msm4 => {
for s in &ordered {
w.push_i(i64::from(s.fine_pseudorange), 15);
}
for s in &ordered {
w.push_i(i64::from(s.fine_phase_range), 22);
}
for s in &ordered {
w.push_u(u64::from(s.lock_time_indicator), 4);
}
for s in &ordered {
w.push_flag(s.half_cycle_ambiguity);
}
for s in &ordered {
w.push_u(u64::from(s.cnr), 6);
}
}
MsmKind::Msm7 => {
for s in &ordered {
w.push_i(i64::from(s.fine_pseudorange), 20);
}
for s in &ordered {
w.push_i(i64::from(s.fine_phase_range), 24);
}
for s in &ordered {
w.push_u(u64::from(s.lock_time_indicator), 10);
}
for s in &ordered {
w.push_flag(s.half_cycle_ambiguity);
}
for s in &ordered {
w.push_u(u64::from(s.cnr), 10);
}
for s in &ordered {
w.push_i(i64::from(s.fine_phase_range_rate.unwrap_or(0)), 15);
}
}
}
w.into_bytes()
}
}
fn read_vec<T>(
r: &mut BitReader<'_>,
n: usize,
mut f: impl FnMut(&mut BitReader<'_>) -> std::result::Result<T, OutOfInput>,
) -> std::result::Result<Vec<T>, OutOfInput> {
let mut v = Vec::with_capacity(n);
for _ in 0..n {
v.push(f(r)?);
}
Ok(v)
}
fn set_bits(mask: u64, n: u32) -> Vec<u8> {
let mut ids = Vec::new();
for i in 0..n {
if (mask >> (n - 1 - i)) & 1 == 1 {
ids.push((i + 1) as u8);
}
}
ids
}
fn set_bits_u32(mask: u32) -> Vec<u8> {
let mut ids = Vec::new();
for i in 0..32u32 {
if (mask >> (31 - i)) & 1 == 1 {
ids.push((i + 1) as u8);
}
}
ids
}
fn active_cells(sat_ids: &[u8], sig_ids: &[u8], cell_present: &[bool]) -> Vec<(u8, u8)> {
let nsig = sig_ids.len();
let mut cells = Vec::new();
for (si, &sat) in sat_ids.iter().enumerate() {
for (gi, &sig) in sig_ids.iter().enumerate() {
if cell_present[si * nsig + gi] {
cells.push((sat, sig));
}
}
}
cells
}