1use crate::error::{Error, Result};
38use crate::id::GnssSystem;
39
40use super::bits::{BitReader, BitWriter};
41
42#[derive(Clone, Copy, Debug, PartialEq, Eq)]
44pub enum MsmKind {
45 Msm4,
47 Msm7,
50}
51
52#[derive(Clone, Copy, Debug, PartialEq, Eq)]
54pub struct MsmHeader {
55 pub reference_station_id: u16,
57 pub epoch_time: u32,
61 pub multiple_message: bool,
63 pub iods: u8,
65 pub reserved: u8,
67 pub clock_steering: u8,
69 pub external_clock: u8,
71 pub divergence_free_smoothing: bool,
73 pub smoothing_interval: u8,
75}
76
77#[derive(Clone, Copy, Debug, PartialEq, Eq)]
79pub struct MsmSatellite {
80 pub id: u8,
83 pub rough_range_ms: u8,
86 pub rough_range_mod1: u16,
88 pub extended_info: Option<u8>,
91 pub rough_phase_range_rate_m_s: Option<i16>,
93}
94
95#[derive(Clone, Copy, Debug, PartialEq, Eq)]
97pub struct MsmSignal {
98 pub satellite_id: u8,
100 pub signal_id: u8,
102 pub fine_pseudorange: i32,
105 pub fine_phase_range: i32,
108 pub lock_time_indicator: u16,
111 pub half_cycle_ambiguity: bool,
113 pub cnr: u16,
116 pub fine_phase_range_rate: Option<i16>,
118}
119
120#[derive(Clone, Debug, PartialEq, Eq)]
122pub struct MsmMessage {
123 pub message_number: u16,
125 pub system: GnssSystem,
127 pub kind: MsmKind,
129 pub header: MsmHeader,
131 pub satellites: Vec<MsmSatellite>,
133 pub signals: Vec<MsmSignal>,
135}
136
137pub(crate) fn msm_kind(message_number: u16) -> Option<(GnssSystem, MsmKind)> {
142 if !(1071..=1137).contains(&message_number) {
143 return None;
144 }
145 let group = (message_number - 1071) / 10;
146 let system = match group {
147 0 => GnssSystem::Gps,
148 1 => GnssSystem::Glonass,
149 2 => GnssSystem::Galileo,
150 3 => GnssSystem::Sbas,
151 4 => GnssSystem::Qzss,
152 5 => GnssSystem::BeiDou,
153 6 => GnssSystem::Navic,
154 _ => return None,
155 };
156 let kind = match message_number % 10 {
157 4 => MsmKind::Msm4,
158 7 => MsmKind::Msm7,
159 _ => return None,
160 };
161 Some((system, kind))
162}
163
164pub(crate) fn is_supported_msm(message_number: u16) -> bool {
166 msm_kind(message_number).is_some()
167}
168
169impl MsmMessage {
170 pub fn decode(body: &[u8]) -> Result<Self> {
172 let mut r = BitReader::new(body);
173 let message_number = r.u(12)? as u16;
174 let (system, kind) = msm_kind(message_number).ok_or_else(|| {
175 Error::Parse(format!(
176 "message {message_number} is not a supported MSM4/MSM7 type"
177 ))
178 })?;
179
180 let header = MsmHeader {
181 reference_station_id: r.u(12)? as u16,
182 epoch_time: r.u(30)? as u32,
183 multiple_message: r.flag()?,
184 iods: r.u(3)? as u8,
185 reserved: r.u(7)? as u8,
186 clock_steering: r.u(2)? as u8,
187 external_clock: r.u(2)? as u8,
188 divergence_free_smoothing: r.flag()?,
189 smoothing_interval: r.u(3)? as u8,
190 };
191
192 let satellite_mask = r.u(64)?;
193 let signal_mask = r.u(32)? as u32;
194 let sat_ids = set_bits(satellite_mask, 64);
195 let sig_ids = set_bits_u32(signal_mask);
196
197 let nsat = sat_ids.len();
198 let nsig = sig_ids.len();
199
200 let mut cell_present = Vec::with_capacity(nsat * nsig);
202 for _ in 0..nsat * nsig {
203 cell_present.push(r.flag()?);
204 }
205
206 let mut rough_range_ms = Vec::with_capacity(nsat);
208 for _ in 0..nsat {
209 rough_range_ms.push(r.u(8)? as u8);
210 }
211 let extended_info = if kind == MsmKind::Msm7 {
212 let mut v = Vec::with_capacity(nsat);
213 for _ in 0..nsat {
214 v.push(Some(r.u(4)? as u8));
215 }
216 v
217 } else {
218 vec![None; nsat]
219 };
220 let mut rough_range_mod1 = Vec::with_capacity(nsat);
221 for _ in 0..nsat {
222 rough_range_mod1.push(r.u(10)? as u16);
223 }
224 let rough_prr = if kind == MsmKind::Msm7 {
225 let mut v = Vec::with_capacity(nsat);
226 for _ in 0..nsat {
227 v.push(Some(r.i(14)? as i16));
228 }
229 v
230 } else {
231 vec![None; nsat]
232 };
233
234 let satellites: Vec<MsmSatellite> = (0..nsat)
235 .map(|s| MsmSatellite {
236 id: sat_ids[s],
237 rough_range_ms: rough_range_ms[s],
238 rough_range_mod1: rough_range_mod1[s],
239 extended_info: extended_info[s],
240 rough_phase_range_rate_m_s: rough_prr[s],
241 })
242 .collect();
243
244 let cells = active_cells(&sat_ids, &sig_ids, &cell_present);
246 let ncell = cells.len();
247
248 let signals = match kind {
250 MsmKind::Msm4 => {
251 let fine_pr = read_vec(&mut r, ncell, |rr| rr.i(15).map(|v| v as i32))?;
252 let fine_ph = read_vec(&mut r, ncell, |rr| rr.i(22).map(|v| v as i32))?;
253 let lock = read_vec(&mut r, ncell, |rr| rr.u(4).map(|v| v as u16))?;
254 let half = read_vec(&mut r, ncell, |rr| rr.flag())?;
255 let cnr = read_vec(&mut r, ncell, |rr| rr.u(6).map(|v| v as u16))?;
256 cells
257 .iter()
258 .enumerate()
259 .map(|(c, &(sat, sig))| MsmSignal {
260 satellite_id: sat,
261 signal_id: sig,
262 fine_pseudorange: fine_pr[c],
263 fine_phase_range: fine_ph[c],
264 lock_time_indicator: lock[c],
265 half_cycle_ambiguity: half[c],
266 cnr: cnr[c],
267 fine_phase_range_rate: None,
268 })
269 .collect()
270 }
271 MsmKind::Msm7 => {
272 let fine_pr = read_vec(&mut r, ncell, |rr| rr.i(20).map(|v| v as i32))?;
273 let fine_ph = read_vec(&mut r, ncell, |rr| rr.i(24).map(|v| v as i32))?;
274 let lock = read_vec(&mut r, ncell, |rr| rr.u(10).map(|v| v as u16))?;
275 let half = read_vec(&mut r, ncell, |rr| rr.flag())?;
276 let cnr = read_vec(&mut r, ncell, |rr| rr.u(10).map(|v| v as u16))?;
277 let fine_prr = read_vec(&mut r, ncell, |rr| rr.i(15).map(|v| v as i16))?;
278 cells
279 .iter()
280 .enumerate()
281 .map(|(c, &(sat, sig))| MsmSignal {
282 satellite_id: sat,
283 signal_id: sig,
284 fine_pseudorange: fine_pr[c],
285 fine_phase_range: fine_ph[c],
286 lock_time_indicator: lock[c],
287 half_cycle_ambiguity: half[c],
288 cnr: cnr[c],
289 fine_phase_range_rate: Some(fine_prr[c]),
290 })
291 .collect()
292 }
293 };
294
295 Ok(Self {
296 message_number,
297 system,
298 kind,
299 header,
300 satellites,
301 signals,
302 })
303 }
304
305 pub fn encode(&self) -> Vec<u8> {
307 let mut w = BitWriter::new();
308 w.push_u(u64::from(self.message_number), 12);
309 w.push_u(u64::from(self.header.reference_station_id), 12);
310 w.push_u(u64::from(self.header.epoch_time), 30);
311 w.push_flag(self.header.multiple_message);
312 w.push_u(u64::from(self.header.iods), 3);
313 w.push_u(u64::from(self.header.reserved), 7);
314 w.push_u(u64::from(self.header.clock_steering), 2);
315 w.push_u(u64::from(self.header.external_clock), 2);
316 w.push_flag(self.header.divergence_free_smoothing);
317 w.push_u(u64::from(self.header.smoothing_interval), 3);
318
319 let mut sat_ids: Vec<u8> = self.satellites.iter().map(|s| s.id).collect();
321 sat_ids.sort_unstable();
322 let mut satellite_mask: u64 = 0;
323 for &id in &sat_ids {
324 satellite_mask |= 1u64 << (64 - u32::from(id));
325 }
326
327 let mut sig_ids: Vec<u8> = self.signals.iter().map(|s| s.signal_id).collect();
329 sig_ids.sort_unstable();
330 sig_ids.dedup();
331 let mut signal_mask: u32 = 0;
332 for &id in &sig_ids {
333 signal_mask |= 1u32 << (32 - u32::from(id));
334 }
335
336 w.push_u(satellite_mask, 64);
337 w.push_u(u64::from(signal_mask), 32);
338
339 let mut ordered_cells: Vec<(u8, u8)> = Vec::new();
341 for &sat in &sat_ids {
342 for &sig in &sig_ids {
343 let present = self
344 .signals
345 .iter()
346 .any(|s| s.satellite_id == sat && s.signal_id == sig);
347 w.push_flag(present);
348 if present {
349 ordered_cells.push((sat, sig));
350 }
351 }
352 }
353
354 let sat_by_id = |id: u8| self.satellites.iter().find(|s| s.id == id);
356 for &id in &sat_ids {
357 let sat = sat_by_id(id);
358 w.push_u(u64::from(sat.map_or(0, |s| s.rough_range_ms)), 8);
359 }
360 if self.kind == MsmKind::Msm7 {
361 for &id in &sat_ids {
362 let ext = sat_by_id(id).and_then(|s| s.extended_info).unwrap_or(0);
363 w.push_u(u64::from(ext), 4);
364 }
365 }
366 for &id in &sat_ids {
367 let sat = sat_by_id(id);
368 w.push_u(u64::from(sat.map_or(0, |s| s.rough_range_mod1)), 10);
369 }
370 if self.kind == MsmKind::Msm7 {
371 for &id in &sat_ids {
372 let prr = sat_by_id(id)
373 .and_then(|s| s.rough_phase_range_rate_m_s)
374 .unwrap_or(0);
375 w.push_i(i64::from(prr), 14);
376 }
377 }
378
379 let cell_signal = |sat: u8, sig: u8| {
381 self.signals
382 .iter()
383 .find(|s| s.satellite_id == sat && s.signal_id == sig)
384 .expect("ordered cell must reference an existing signal")
385 };
386 let ordered: Vec<&MsmSignal> = ordered_cells
387 .iter()
388 .map(|&(sat, sig)| cell_signal(sat, sig))
389 .collect();
390
391 match self.kind {
392 MsmKind::Msm4 => {
393 for s in &ordered {
394 w.push_i(i64::from(s.fine_pseudorange), 15);
395 }
396 for s in &ordered {
397 w.push_i(i64::from(s.fine_phase_range), 22);
398 }
399 for s in &ordered {
400 w.push_u(u64::from(s.lock_time_indicator), 4);
401 }
402 for s in &ordered {
403 w.push_flag(s.half_cycle_ambiguity);
404 }
405 for s in &ordered {
406 w.push_u(u64::from(s.cnr), 6);
407 }
408 }
409 MsmKind::Msm7 => {
410 for s in &ordered {
411 w.push_i(i64::from(s.fine_pseudorange), 20);
412 }
413 for s in &ordered {
414 w.push_i(i64::from(s.fine_phase_range), 24);
415 }
416 for s in &ordered {
417 w.push_u(u64::from(s.lock_time_indicator), 10);
418 }
419 for s in &ordered {
420 w.push_flag(s.half_cycle_ambiguity);
421 }
422 for s in &ordered {
423 w.push_u(u64::from(s.cnr), 10);
424 }
425 for s in &ordered {
426 w.push_i(i64::from(s.fine_phase_range_rate.unwrap_or(0)), 15);
427 }
428 }
429 }
430
431 w.into_bytes()
432 }
433}
434
435fn read_vec<T>(
437 r: &mut BitReader<'_>,
438 n: usize,
439 mut f: impl FnMut(&mut BitReader<'_>) -> Result<T>,
440) -> Result<Vec<T>> {
441 let mut v = Vec::with_capacity(n);
442 for _ in 0..n {
443 v.push(f(r)?);
444 }
445 Ok(v)
446}
447
448fn set_bits(mask: u64, n: u32) -> Vec<u8> {
451 let mut ids = Vec::new();
452 for i in 0..n {
453 if (mask >> (n - 1 - i)) & 1 == 1 {
454 ids.push((i + 1) as u8);
455 }
456 }
457 ids
458}
459
460fn set_bits_u32(mask: u32) -> Vec<u8> {
462 let mut ids = Vec::new();
463 for i in 0..32u32 {
464 if (mask >> (31 - i)) & 1 == 1 {
465 ids.push((i + 1) as u8);
466 }
467 }
468 ids
469}
470
471fn active_cells(sat_ids: &[u8], sig_ids: &[u8], cell_present: &[bool]) -> Vec<(u8, u8)> {
473 let nsig = sig_ids.len();
474 let mut cells = Vec::new();
475 for (si, &sat) in sat_ids.iter().enumerate() {
476 for (gi, &sig) in sig_ids.iter().enumerate() {
477 if cell_present[si * nsig + gi] {
478 cells.push((sat, sig));
479 }
480 }
481 }
482 cells
483}