1mod attitude;
6pub mod catalog;
7mod dnu;
8mod differential;
9mod extended;
10mod external;
11mod ins;
12mod meas3;
13mod meas3_decoder;
14mod measurement;
15mod navigation;
16mod position;
17mod sbas;
18mod status;
19mod time;
20
21pub use attitude::*;
22pub use differential::*;
23pub use extended::*;
24pub use external::*;
25pub use ins::*;
26pub use meas3::*;
27pub use meas3_decoder::*;
28pub use measurement::*;
29pub use navigation::*;
30pub use position::*;
31pub use sbas::*;
32pub use status::*;
33pub use time::*;
34
35pub use catalog::fallback_name;
36
37use crate::error::{SbfError, SbfResult};
38use crate::header::SbfHeader;
39
40pub mod block_ids {
46 pub const MEAS_EPOCH: u16 = 4027;
48 pub const MEAS_EXTRA: u16 = 4000;
49 pub const END_OF_MEAS: u16 = 5922;
50 pub const IQ_CORR: u16 = 4046;
51 pub const MEAS3_RANGES: u16 = 4109;
52 pub const MEAS3_CN0_HI_RES: u16 = 4110;
53 pub const MEAS3_DOPPLER: u16 = 4111;
54 pub const MEAS3_PP: u16 = 4112;
55 pub const MEAS3_MP: u16 = 4113;
56
57 pub const PVT_CARTESIAN: u16 = 4006;
59 pub const PVT_GEODETIC: u16 = 4007;
60 pub const DOP: u16 = 4001;
61 pub const DOP_LEGACY: u16 = 5909;
62 pub const POS_CART: u16 = 4044;
63 pub const PVT_SAT_CARTESIAN: u16 = 4008;
64 pub const PVT_RESIDUALS_V2: u16 = 4009;
65 pub const RAIM_STATISTICS_V2: u16 = 4011;
66 pub const BASE_VECTOR_CART: u16 = 4043;
67 pub const BASE_VECTOR_GEOD: u16 = 4028;
68 pub const POS_COV_CARTESIAN: u16 = 5905;
69 pub const POS_COV_GEODETIC: u16 = 5906;
70 pub const VEL_COV_CARTESIAN: u16 = 5907;
71 pub const VEL_COV_GEODETIC: u16 = 5908;
72 pub const GEO_CORRECTIONS: u16 = 5935;
73 pub const BASE_STATION: u16 = 5949;
74 pub const DIFF_CORR_IN: u16 = 5919;
75 pub const END_OF_PVT: u16 = 5921;
76 pub const PVT_SUPPORT: u16 = 4076;
77 pub const PVT_SUPPORT_A: u16 = 4079;
78 pub const FUGRO_DDS: u16 = 4211;
79 pub const POS_LOCAL: u16 = 4052;
80 pub const POS_PROJECTED: u16 = 4094;
81
82 pub const INT_PV_CART: u16 = 4060;
84 pub const INT_PV_GEOD: u16 = 4061;
85 pub const INT_PVA_AGEOD: u16 = 4045;
86 pub const INT_POS_COV_CART: u16 = 4062;
87 pub const INT_VEL_COV_CART: u16 = 4063;
88 pub const INT_POS_COV_GEOD: u16 = 4064;
89 pub const INT_VEL_COV_GEOD: u16 = 4065;
90 pub const INT_ATT_EULER: u16 = 4070;
91 pub const INT_ATT_COV_EULER: u16 = 4072;
92
93 pub const ATT_EULER: u16 = 5938;
97 pub const ATT_COV_EULER: u16 = 5939;
98 pub const AUX_ANT_POSITIONS: u16 = 5942;
99 pub const END_OF_ATT: u16 = 5943;
100
101 pub const GPS_NAV: u16 = 5891;
103 pub const GPS_ALM: u16 = 5892;
104 pub const GPS_ION: u16 = 5893;
105 pub const GPS_UTC: u16 = 5894;
106 pub const GPS_CNAV: u16 = 4042;
107 pub const GPS_RAW_CA: u16 = 4017;
108 pub const GPS_RAW_L2C: u16 = 4018;
109 pub const GPS_RAW_L5: u16 = 4019;
110 pub const GEO_RAW_L1: u16 = 4020;
111 pub const GAL_RAW_FNAV: u16 = 4022;
112 pub const GAL_RAW_INAV: u16 = 4023;
113 pub const GAL_RAW_CNAV: u16 = 4024;
114 pub const GLO_RAW_CA: u16 = 4026;
115 pub const CMP_RAW: u16 = 4047;
116 pub const QZS_RAW_L1CA: u16 = 4066;
117 pub const QZS_RAW_L2C: u16 = 4067;
118 pub const QZS_RAW_L5: u16 = 4068;
119 pub const GLO_NAV: u16 = 4004;
120 pub const GLO_ALM: u16 = 4005;
121 pub const GLO_TIME: u16 = 4036;
122 pub const GAL_NAV: u16 = 4002;
123 pub const GAL_ALM: u16 = 4003;
124 pub const GAL_ION: u16 = 4030;
125 pub const GAL_UTC: u16 = 4031;
126 pub const GAL_GST_GPS: u16 = 4032;
127 pub const GAL_SAR_RLM: u16 = 4034;
128 pub const BDS_ION: u16 = 4120;
129 pub const BDS_NAV: u16 = 4081;
130 pub const BDS_ALM: u16 = 4119;
131 pub const BDS_UTC: u16 = 4121;
132 pub const BDS_CNAV1: u16 = 4251;
133 pub const BDS_CNAV2: u16 = 4252;
134 pub const BDS_CNAV3: u16 = 4253;
135 pub const QZS_NAV: u16 = 4095;
136 pub const QZS_ALM: u16 = 4116;
137 pub const GEO_RAW_L5: u16 = 4021;
138 pub const BDS_RAW_B1C: u16 = 4218;
139 pub const BDS_RAW_B2A: u16 = 4219;
140 pub const NAVIC_RAW: u16 = 4093;
141 pub const GEO_IONO_DELAY: u16 = 5933;
142 pub const GEO_MT00: u16 = 5925;
143 pub const GEO_PRN_MASK: u16 = 5926;
144 pub const GEO_FAST_CORR: u16 = 5927;
145 pub const GEO_FAST_CORR_DEGR: u16 = 5929;
146 pub const GEO_DEGR_FACTORS: u16 = 5930;
147 pub const GEO_SERVICE_LEVEL: u16 = 5917;
148 pub const GEO_NAV: u16 = 5896;
149 pub const GEO_INTEGRITY: u16 = 5928;
150 pub const GEO_ALM: u16 = 5897;
151 pub const GEO_NETWORK_TIME: u16 = 5918;
152 pub const GEO_IGP_MASK: u16 = 5931;
153 pub const GEO_LONG_TERM_CORR: u16 = 5932;
154 pub const GEO_CLOCK_EPH_COV_MATRIX: u16 = 5934;
155
156 pub const RECEIVER_STATUS: u16 = 4014;
160 pub const TRACKING_STATUS: u16 = 5912;
161 pub const CHANNEL_STATUS: u16 = 4013;
162 pub const SAT_VISIBILITY: u16 = 4012;
163 pub const QUALITY_IND: u16 = 4082;
164 pub const INPUT_LINK: u16 = 4090;
165 pub const OUTPUT_LINK: u16 = 4091;
166 pub const IP_STATUS: u16 = 4058;
167 pub const LBAND_TRACKER_STATUS: u16 = 4201;
168 pub const LBAND_BEAMS: u16 = 4204;
169 pub const EXT_SENSOR_MEAS: u16 = 4050;
170 pub const EXT_SENSOR_STATUS: u16 = 4056;
171 pub const EXT_SENSOR_SETUP: u16 = 4057;
172 pub const COMMANDS: u16 = 4015;
173 pub const COMMENT: u16 = 5936;
174 pub const RECEIVER_SETUP: u16 = 5902;
175 pub const BB_SAMPLES: u16 = 4040;
176 pub const ASCII_IN: u16 = 4075;
177 pub const RX_MESSAGE: u16 = 4103;
178 pub const ENCAPSULATED_OUTPUT: u16 = 4097;
179 pub const GIS_ACTION: u16 = 4106;
180 pub const GIS_STATUS: u16 = 4107;
181 pub const DYN_DNS_STATUS: u16 = 4105;
182 pub const DISK_STATUS: u16 = 4059;
183 pub const NTRIP_CLIENT_STATUS: u16 = 4053;
184 pub const NTRIP_SERVER_STATUS: u16 = 4122;
185 pub const RF_STATUS: u16 = 4092;
186 pub const P2PP_STATUS: u16 = 4238;
187 pub const COSMOS_STATUS: u16 = 4243;
188 pub const RTCM_DATUM: u16 = 4049;
189
190 pub const RECEIVER_TIME: u16 = 5914;
192 pub const PPS_OFFSET: u16 = 5911;
193 pub const EXT_EVENT: u16 = 5924;
194 pub const EXT_EVENT_PVT_CARTESIAN: u16 = 4037;
195 pub const EXT_EVENT_PVT_GEODETIC: u16 = 4038;
196 pub const EXT_EVENT_BASE_VECT_GEOD: u16 = 4217;
197 pub const EXT_EVENT_ATT_EULER: u16 = 4237;
198}
199
200pub fn block_name(id: u16) -> &'static str {
206 match id {
207 block_ids::MEAS_EPOCH => "MeasEpoch",
208 block_ids::MEAS_EXTRA => "MeasExtra",
209 block_ids::IQ_CORR => "IQCorr",
210 block_ids::END_OF_MEAS => "EndOfMeas",
211 block_ids::MEAS3_RANGES => "Meas3Ranges",
212 block_ids::MEAS3_CN0_HI_RES => "Meas3CN0HiRes",
213 block_ids::MEAS3_DOPPLER => "Meas3Doppler",
214 block_ids::MEAS3_PP => "Meas3PP",
215 block_ids::MEAS3_MP => "Meas3MP",
216 block_ids::PVT_CARTESIAN => "PVTCartesian",
217 block_ids::PVT_GEODETIC => "PVTGeodetic",
218 block_ids::DOP => "DOP",
219 block_ids::DOP_LEGACY => "DOP",
220 block_ids::POS_CART => "PosCart",
221 block_ids::PVT_SAT_CARTESIAN => "PVTSatCartesian",
222 block_ids::PVT_RESIDUALS_V2 => "PVTResiduals_v2",
223 block_ids::RAIM_STATISTICS_V2 => "RAIMStatistics_v2",
224 block_ids::BASE_VECTOR_CART => "BaseVectorCart",
225 block_ids::BASE_VECTOR_GEOD => "BaseVectorGeod",
226 block_ids::POS_COV_CARTESIAN => "PosCovCartesian",
227 block_ids::POS_COV_GEODETIC => "PosCovGeodetic",
228 block_ids::VEL_COV_CARTESIAN => "VelCovCartesian",
229 block_ids::VEL_COV_GEODETIC => "VelCovGeodetic",
230 block_ids::GEO_CORRECTIONS => "GEOCorrections",
231 block_ids::BASE_STATION => "BaseStation",
232 block_ids::DIFF_CORR_IN => "DiffCorrIn",
233 block_ids::END_OF_PVT => "EndOfPVT",
234 block_ids::PVT_SUPPORT => "PVTSupport",
235 block_ids::PVT_SUPPORT_A => "PVTSupportA",
236 block_ids::FUGRO_DDS => "FugroDDS",
237 block_ids::INT_PV_CART => "IntPVCart",
238 block_ids::INT_PV_GEOD => "IntPVGeod",
239 block_ids::INT_PVA_AGEOD => "IntPVAAGeod",
240 block_ids::INT_ATT_EULER => "IntAttEuler",
241 block_ids::INT_POS_COV_CART => "IntPosCovCart",
242 block_ids::INT_VEL_COV_CART => "IntVelCovCart",
243 block_ids::INT_POS_COV_GEOD => "IntPosCovGeod",
244 block_ids::INT_VEL_COV_GEOD => "IntVelCovGeod",
245 block_ids::INT_ATT_COV_EULER => "IntAttCovEuler",
246 block_ids::IP_STATUS => "IPStatus",
247 block_ids::EXT_SENSOR_MEAS => "ExtSensorMeas",
248 block_ids::EXT_SENSOR_STATUS => "ExtSensorStatus",
249 block_ids::EXT_SENSOR_SETUP => "ExtSensorSetup",
250 block_ids::ATT_EULER => "AttEuler",
251 block_ids::ATT_COV_EULER => "AttCovEuler",
252 block_ids::AUX_ANT_POSITIONS => "AuxAntPositions",
253 block_ids::END_OF_ATT => "EndOfAtt",
254 block_ids::GPS_NAV => "GPSNav",
255 block_ids::GPS_ALM => "GPSAlm",
256 block_ids::GPS_ION => "GPSIon",
257 block_ids::GPS_UTC => "GPSUtc",
258 block_ids::GPS_CNAV => "GPSCNav",
259 block_ids::GLO_NAV => "GLONav",
260 block_ids::GLO_ALM => "GLOAlm",
261 block_ids::GLO_TIME => "GLOTime",
262 block_ids::GAL_NAV => "GALNav",
263 block_ids::GAL_ALM => "GALAlm",
264 block_ids::GAL_ION => "GALIon",
265 block_ids::GAL_UTC => "GALUtc",
266 block_ids::GAL_GST_GPS => "GALGstGps",
267 block_ids::GAL_SAR_RLM => "GALSARRLM",
268 block_ids::BDS_ION => "BDSIon",
269 block_ids::BDS_CNAV1 => "BDSCNav1",
270 block_ids::GEO_IONO_DELAY => "GEOIonoDelay",
271 block_ids::GEO_MT00 => "GEOMT00",
272 block_ids::GEO_PRN_MASK => "GEOPRNMask",
273 block_ids::GEO_FAST_CORR => "GEOFastCorr",
274 block_ids::GEO_FAST_CORR_DEGR => "GEOFastCorrDegr",
275 block_ids::GEO_DEGR_FACTORS => "GEODegrFactors",
276 block_ids::GEO_SERVICE_LEVEL => "GEOServiceLevel",
277 block_ids::GEO_NAV => "GEONav",
278 block_ids::GEO_INTEGRITY => "GEOIntegrity",
279 block_ids::GEO_ALM => "GEOAlm",
280 block_ids::GEO_NETWORK_TIME => "GEONetworkTime",
281 block_ids::GEO_IGP_MASK => "GEOIGPMask",
282 block_ids::GEO_LONG_TERM_CORR => "GEOLongTermCorr",
283 block_ids::GEO_CLOCK_EPH_COV_MATRIX => "GEOClockEphCovMatrix",
284 block_ids::GPS_RAW_CA => "GPSRawCA",
285 block_ids::GPS_RAW_L2C => "GPSRawL2C",
286 block_ids::GPS_RAW_L5 => "GPSRawL5",
287 block_ids::GAL_RAW_FNAV => "GALRawFNAV",
288 block_ids::GAL_RAW_INAV => "GALRawINAV",
289 block_ids::GAL_RAW_CNAV => "GALRawCNAV",
290 block_ids::GEO_RAW_L1 => "GEORawL1",
291 block_ids::GLO_RAW_CA => "GLORawCA",
292 block_ids::CMP_RAW => "CMPRaw",
293 block_ids::QZS_RAW_L1CA => "QZSRawL1CA",
294 block_ids::QZS_RAW_L2C => "QZSRawL2C",
295 block_ids::QZS_RAW_L5 => "QZSRawL5",
296 block_ids::RECEIVER_STATUS => "ReceiverStatus",
297 block_ids::TRACKING_STATUS => "TrackingStatus",
298 block_ids::CHANNEL_STATUS => "ChannelStatus",
299 block_ids::SAT_VISIBILITY => "SatVisibility",
300 block_ids::QUALITY_IND => "QualityInd",
301 block_ids::INPUT_LINK => "InputLink",
302 block_ids::OUTPUT_LINK => "OutputLink",
303 block_ids::LBAND_TRACKER_STATUS => "LBandTrackerStatus",
304 block_ids::COMMANDS => "Commands",
305 block_ids::COMMENT => "Comment",
306 block_ids::RECEIVER_SETUP => "ReceiverSetup",
307 block_ids::BB_SAMPLES => "BBSamples",
308 block_ids::ASCII_IN => "ASCIIIn",
309 block_ids::NTRIP_CLIENT_STATUS => "NTRIPClientStatus",
310 block_ids::NTRIP_SERVER_STATUS => "NTRIPServerStatus",
311 block_ids::RF_STATUS => "RFStatus",
312 block_ids::RECEIVER_TIME => "ReceiverTime",
313 block_ids::PPS_OFFSET => "xPPSOffset",
314 block_ids::EXT_EVENT => "ExtEvent",
315 block_ids::EXT_EVENT_PVT_CARTESIAN => "ExtEventPVTCartesian",
316 block_ids::EXT_EVENT_PVT_GEODETIC => "ExtEventPVTGeodetic",
317 block_ids::EXT_EVENT_BASE_VECT_GEOD => "ExtEventBaseVectGeod",
318 block_ids::EXT_EVENT_ATT_EULER => "ExtEventAttEuler",
319 block_ids::POS_LOCAL => "PosLocal",
320 block_ids::POS_PROJECTED => "PosProjected",
321 block_ids::BDS_NAV => "BDSNav",
322 block_ids::BDS_ALM => "BDSAlm",
323 block_ids::BDS_UTC => "BDSUtc",
324 block_ids::BDS_CNAV2 => "BDSCNav2",
325 block_ids::BDS_CNAV3 => "BDSCNav3",
326 block_ids::QZS_NAV => "QZSNav",
327 block_ids::QZS_ALM => "QZSAlm",
328 block_ids::GEO_RAW_L5 => "GEORawL5",
329 block_ids::BDS_RAW_B1C => "BDSRawB1C",
330 block_ids::BDS_RAW_B2A => "BDSRawB2a",
331 block_ids::NAVIC_RAW => "NAVICRaw",
332 block_ids::RTCM_DATUM => "RTCMDatum",
333 block_ids::LBAND_BEAMS => "LBandBeams",
334 block_ids::DYN_DNS_STATUS => "DynDNSStatus",
335 block_ids::DISK_STATUS => "DiskStatus",
336 block_ids::P2PP_STATUS => "P2PPStatus",
337 block_ids::COSMOS_STATUS => "CosmosStatus",
338 block_ids::RX_MESSAGE => "RxMessage",
339 block_ids::ENCAPSULATED_OUTPUT => "EncapsulatedOutput",
340 block_ids::GIS_ACTION => "GISAction",
341 block_ids::GIS_STATUS => "GISStatus",
342 _ => catalog::fallback_name(id),
343 }
344}
345
346pub fn is_known_opaque_id(id: u16) -> bool {
348 matches!(id, block_ids::FUGRO_DDS)
349}
350
351pub trait SbfBlockParse: Sized {
357 const BLOCK_ID: u16;
359
360 fn parse(header: &SbfHeader, data: &[u8]) -> SbfResult<Self>;
369}
370
371#[derive(Debug, Clone)]
377pub enum SbfBlock {
378 MeasEpoch(MeasEpochBlock),
380 MeasExtra(MeasExtraBlock),
381 EndOfMeas(EndOfMeasBlock),
382 Meas3Ranges(Meas3RangesBlock),
383 Meas3Cn0HiRes(Meas3Cn0HiResBlock),
384 Meas3Doppler(Meas3DopplerBlock),
385 Meas3Pp(Meas3PpBlock),
386 Meas3Mp(Meas3MpBlock),
387
388 PvtGeodetic(PvtGeodeticBlock),
390 PvtCartesian(PvtCartesianBlock),
391 Dop(DopBlock),
392 PosCart(PosCartBlock),
393 PvtSatCartesian(PvtSatCartesianBlock),
394 PvtResidualsV2(PvtResidualsV2Block),
395 RaimStatisticsV2(RaimStatisticsV2Block),
396 BaseVectorCart(BaseVectorCartBlock),
397 BaseVectorGeod(BaseVectorGeodBlock),
398 PosCovCartesian(PosCovCartesianBlock),
399 PosCovGeodetic(PosCovGeodeticBlock),
400 VelCovCartesian(VelCovCartesianBlock),
401 VelCovGeodetic(VelCovGeodeticBlock),
402 GeoCorrections(GeoCorrectionsBlock),
403 BaseStation(BaseStationBlock),
404 DiffCorrIn(DiffCorrInBlock),
405 PvtSupport(PvtSupportBlock),
406 PvtSupportA(PvtSupportABlock),
407 PosLocal(PosLocalBlock),
408 PosProjected(PosProjectedBlock),
409
410 AttEuler(AttEulerBlock),
412 AttCovEuler(AttCovEulerBlock),
413 AuxAntPositions(AuxAntPositionsBlock),
414 EndOfAtt(EndOfAttBlock),
415
416 GpsNav(GpsNavBlock),
418 GpsAlm(GpsAlmBlock),
419 GpsIon(GpsIonBlock),
420 GpsUtc(GpsUtcBlock),
421 GpsCNav(GpsCNavBlock),
422 GalNav(GalNavBlock),
423 GalAlm(GalAlmBlock),
424 GalIon(GalIonBlock),
425 GalUtc(GalUtcBlock),
426 GalGstGps(GalGstGpsBlock),
427 GalSarRlm(GalSarRlmBlock),
428 GloNav(GloNavBlock),
429 GloAlm(GloAlmBlock),
430 GloTime(GloTimeBlock),
431 BdsIon(BdsIonBlock),
432 BdsNav(BdsNavBlock),
433 BdsAlm(BdsAlmBlock),
434 BdsUtc(BdsUtcBlock),
435 BdsCNav1(BdsCNav1Block),
436 BdsCNav2(BdsCNav2Block),
437 BdsCNav3(BdsCNav3Block),
438 QzsNav(QzsNavBlock),
439 QzsAlm(QzsAlmBlock),
440 GeoIonoDelay(GeoIonoDelayBlock),
441 GpsRawCa(GpsRawCaBlock),
442 GpsRawL2C(GpsRawL2CBlock),
443 GpsRawL5(GpsRawL5Block),
444 GalRawFnav(GalRawFnavBlock),
445 GalRawInav(GalRawInavBlock),
446 GalRawCnav(GalRawCnavBlock),
447 GeoRawL1(GeoRawL1Block),
448 GeoRawL5(GeoRawL5Block),
449 GloRawCa(GloRawCaBlock),
450 CmpRaw(CmpRawBlock),
451 BdsRawB1c(BdsRawB1cBlock),
452 BdsRawB2a(BdsRawB2aBlock),
453 IrnssRaw(IrnssRawBlock),
454 QzsRawL1Ca(QzsRawL1CaBlock),
455 QzsRawL2C(QzsRawL2CBlock),
456 QzsRawL5(QzsRawL5Block),
457 GeoMt00(GeoMt00Block),
458 GeoPrnMask(GeoPrnMaskBlock),
459 GeoFastCorr(GeoFastCorrBlock),
460 GeoFastCorrDegr(GeoFastCorrDegrBlock),
461 GeoDegrFactors(GeoDegrFactorsBlock),
462 GeoServiceLevel(GeoServiceLevelBlock),
463 GeoNav(GeoNavBlock),
464 GeoIntegrity(GeoIntegrityBlock),
465 GeoAlm(GeoAlmBlock),
466 GeoNetworkTime(GeoNetworkTimeBlock),
467 GeoIgpMask(GeoIgpMaskBlock),
468 GeoLongTermCorr(GeoLongTermCorrBlock),
469 GeoClockEphCovMatrix(GeoClockEphCovMatrixBlock),
470
471 ReceiverStatus(ReceiverStatusBlock),
473 TrackingStatus(ChannelStatusBlock),
474 ChannelStatus(ChannelStatusBlock),
475 SatVisibility(SatVisibilityBlock),
476 QualityInd(QualityIndBlock),
477 InputLink(InputLinkBlock),
478 OutputLink(OutputLinkBlock),
479 LBandTrackerStatus(LBandTrackerStatusBlock),
480 Commands(CommandsBlock),
481 Comment(CommentBlock),
482 ReceiverSetup(ReceiverSetupBlock),
483 BBSamples(BBSamplesBlock),
484 ASCIIIn(ASCIIInBlock),
485 NtripClientStatus(NtripClientStatusBlock),
486 NtripServerStatus(NtripServerStatusBlock),
487 RfStatus(RfStatusBlock),
488 RtcmDatum(RtcmDatumBlock),
489 LBandBeams(LBandBeamsBlock),
490 DynDnsStatus(DynDnsStatusBlock),
491 DiskStatus(DiskStatusBlock),
492 P2ppStatus(P2ppStatusBlock),
493 CosmosStatus(CosmosStatusBlock),
494 RxMessage(RxMessageBlock),
495 EncapsulatedOutput(EncapsulatedOutputBlock),
496 GisAction(GisActionBlock),
497 GisStatus(GisStatusBlock),
498
499 ReceiverTime(ReceiverTimeBlock),
501 PpsOffset(PpsOffsetBlock),
502 ExtEvent(ExtEventBlock),
503 ExtEventPvtCartesian(ExtEventPvtCartesianBlock),
504 ExtEventPvtGeodetic(ExtEventPvtGeodeticBlock),
505 ExtEventBaseVectGeod(ExtEventBaseVectGeodBlock),
506 ExtEventAttEuler(ExtEventAttEulerBlock),
507 EndOfPvt(EndOfPvtBlock),
508 IntPvCart(IntPvCartBlock),
509 IntPvGeod(IntPvGeodBlock),
510 IntPvaaGeod(IntPvaaGeodBlock),
511 IntAttEuler(IntAttEulerBlock),
512 IntPosCovCart(IntPosCovCartBlock),
513 IntVelCovCart(IntVelCovCartBlock),
514 IntPosCovGeod(IntPosCovGeodBlock),
515 IntVelCovGeod(IntVelCovGeodBlock),
516 IntAttCovEuler(IntAttCovEulerBlock),
517 IpStatus(IpStatusBlock),
518 IqCorr(IqCorrBlock),
519 ExtSensorMeas(ExtSensorMeasBlock),
520 ExtSensorStatus(ExtSensorStatusBlock),
521 ExtSensorSetup(ExtSensorSetupBlock),
522
523 KnownOpaque {
525 id: u16,
526 rev: u8,
527 data: Vec<u8>,
529 },
530
531 Unknown {
533 id: u16,
534 rev: u8,
535 data: Vec<u8>,
537 },
538}
539
540impl SbfBlock {
541 pub fn parse(data: &[u8]) -> SbfResult<(Self, usize)> {
549 if data.len() < 2 || data[0] != 0x24 || data[1] != 0x40 {
551 return Err(SbfError::InvalidSync);
552 }
553
554 let header = SbfHeader::parse(&data[2..])?;
556 let total_len = header.length as usize;
557
558 if data.len() < total_len {
560 return Err(SbfError::IncompleteBlock {
561 needed: total_len,
562 have: data.len(),
563 });
564 }
565
566 let block_data = &data[2..];
568
569 let block = match header.block_id {
571 block_ids::MEAS_EPOCH => {
572 SbfBlock::MeasEpoch(MeasEpochBlock::parse(&header, block_data)?)
573 }
574 block_ids::MEAS_EXTRA => {
575 SbfBlock::MeasExtra(MeasExtraBlock::parse(&header, block_data)?)
576 }
577 block_ids::END_OF_MEAS => {
578 SbfBlock::EndOfMeas(EndOfMeasBlock::parse(&header, block_data)?)
579 }
580 block_ids::MEAS3_RANGES => {
581 SbfBlock::Meas3Ranges(Meas3RangesBlock::parse(&header, block_data)?)
582 }
583 block_ids::MEAS3_CN0_HI_RES => {
584 SbfBlock::Meas3Cn0HiRes(Meas3Cn0HiResBlock::parse(&header, block_data)?)
585 }
586 block_ids::MEAS3_DOPPLER => {
587 SbfBlock::Meas3Doppler(Meas3DopplerBlock::parse(&header, block_data)?)
588 }
589 block_ids::MEAS3_PP => SbfBlock::Meas3Pp(Meas3PpBlock::parse(&header, block_data)?),
590 block_ids::MEAS3_MP => SbfBlock::Meas3Mp(Meas3MpBlock::parse(&header, block_data)?),
591 block_ids::PVT_GEODETIC => {
592 SbfBlock::PvtGeodetic(PvtGeodeticBlock::parse(&header, block_data)?)
593 }
594 block_ids::PVT_CARTESIAN => {
595 SbfBlock::PvtCartesian(PvtCartesianBlock::parse(&header, block_data)?)
596 }
597 block_ids::DOP | block_ids::DOP_LEGACY => {
598 SbfBlock::Dop(DopBlock::parse(&header, block_data)?)
599 }
600 block_ids::POS_CART => SbfBlock::PosCart(PosCartBlock::parse(&header, block_data)?),
601 block_ids::PVT_SAT_CARTESIAN => {
602 SbfBlock::PvtSatCartesian(PvtSatCartesianBlock::parse(&header, block_data)?)
603 }
604 block_ids::PVT_RESIDUALS_V2 => {
605 SbfBlock::PvtResidualsV2(PvtResidualsV2Block::parse(&header, block_data)?)
606 }
607 block_ids::RAIM_STATISTICS_V2 => {
608 SbfBlock::RaimStatisticsV2(RaimStatisticsV2Block::parse(&header, block_data)?)
609 }
610 block_ids::BASE_VECTOR_CART => {
611 SbfBlock::BaseVectorCart(BaseVectorCartBlock::parse(&header, block_data)?)
612 }
613 block_ids::BASE_VECTOR_GEOD => {
614 SbfBlock::BaseVectorGeod(BaseVectorGeodBlock::parse(&header, block_data)?)
615 }
616 block_ids::POS_COV_CARTESIAN => {
617 SbfBlock::PosCovCartesian(PosCovCartesianBlock::parse(&header, block_data)?)
618 }
619 block_ids::POS_COV_GEODETIC => {
620 SbfBlock::PosCovGeodetic(PosCovGeodeticBlock::parse(&header, block_data)?)
621 }
622 block_ids::VEL_COV_CARTESIAN => {
623 SbfBlock::VelCovCartesian(VelCovCartesianBlock::parse(&header, block_data)?)
624 }
625 block_ids::VEL_COV_GEODETIC => {
626 SbfBlock::VelCovGeodetic(VelCovGeodeticBlock::parse(&header, block_data)?)
627 }
628 block_ids::GEO_CORRECTIONS => {
629 SbfBlock::GeoCorrections(GeoCorrectionsBlock::parse(&header, block_data)?)
630 }
631 block_ids::BASE_STATION => {
632 SbfBlock::BaseStation(BaseStationBlock::parse(&header, block_data)?)
633 }
634 block_ids::DIFF_CORR_IN => {
635 SbfBlock::DiffCorrIn(DiffCorrInBlock::parse(&header, block_data)?)
636 }
637 block_ids::PVT_SUPPORT => {
638 SbfBlock::PvtSupport(PvtSupportBlock::parse(&header, block_data)?)
639 }
640 block_ids::PVT_SUPPORT_A => {
641 SbfBlock::PvtSupportA(PvtSupportABlock::parse(&header, block_data)?)
642 }
643 block_ids::POS_LOCAL => SbfBlock::PosLocal(PosLocalBlock::parse(&header, block_data)?),
644 block_ids::POS_PROJECTED => {
645 SbfBlock::PosProjected(PosProjectedBlock::parse(&header, block_data)?)
646 }
647 block_ids::INT_PVA_AGEOD => {
648 SbfBlock::IntPvaaGeod(IntPvaaGeodBlock::parse(&header, block_data)?)
649 }
650 block_ids::ATT_EULER => SbfBlock::AttEuler(AttEulerBlock::parse(&header, block_data)?),
651 block_ids::ATT_COV_EULER => {
652 SbfBlock::AttCovEuler(AttCovEulerBlock::parse(&header, block_data)?)
653 }
654 block_ids::AUX_ANT_POSITIONS => {
655 SbfBlock::AuxAntPositions(AuxAntPositionsBlock::parse(&header, block_data)?)
656 }
657 block_ids::END_OF_ATT => SbfBlock::EndOfAtt(EndOfAttBlock::parse(&header, block_data)?),
658 block_ids::GPS_NAV => SbfBlock::GpsNav(GpsNavBlock::parse(&header, block_data)?),
659 block_ids::GPS_ALM => SbfBlock::GpsAlm(GpsAlmBlock::parse(&header, block_data)?),
660 block_ids::GPS_ION => SbfBlock::GpsIon(GpsIonBlock::parse(&header, block_data)?),
661 block_ids::GPS_UTC => SbfBlock::GpsUtc(GpsUtcBlock::parse(&header, block_data)?),
662 block_ids::GPS_CNAV => SbfBlock::GpsCNav(GpsCNavBlock::parse(&header, block_data)?),
663 block_ids::GAL_NAV => SbfBlock::GalNav(GalNavBlock::parse(&header, block_data)?),
664 block_ids::GAL_ALM => SbfBlock::GalAlm(GalAlmBlock::parse(&header, block_data)?),
665 block_ids::GAL_ION => SbfBlock::GalIon(GalIonBlock::parse(&header, block_data)?),
666 block_ids::GAL_UTC => SbfBlock::GalUtc(GalUtcBlock::parse(&header, block_data)?),
667 block_ids::GAL_GST_GPS => {
668 SbfBlock::GalGstGps(GalGstGpsBlock::parse(&header, block_data)?)
669 }
670 block_ids::GAL_SAR_RLM => {
671 SbfBlock::GalSarRlm(GalSarRlmBlock::parse(&header, block_data)?)
672 }
673 block_ids::GLO_NAV => SbfBlock::GloNav(GloNavBlock::parse(&header, block_data)?),
674 block_ids::GLO_ALM => SbfBlock::GloAlm(GloAlmBlock::parse(&header, block_data)?),
675 block_ids::GLO_TIME => SbfBlock::GloTime(GloTimeBlock::parse(&header, block_data)?),
676 block_ids::BDS_ION => SbfBlock::BdsIon(BdsIonBlock::parse(&header, block_data)?),
677 block_ids::BDS_NAV => SbfBlock::BdsNav(BdsNavBlock::parse(&header, block_data)?),
678 block_ids::BDS_ALM => SbfBlock::BdsAlm(BdsAlmBlock::parse(&header, block_data)?),
679 block_ids::BDS_UTC => SbfBlock::BdsUtc(BdsUtcBlock::parse(&header, block_data)?),
680 block_ids::BDS_CNAV1 => SbfBlock::BdsCNav1(BdsCNav1Block::parse(&header, block_data)?),
681 block_ids::BDS_CNAV2 => SbfBlock::BdsCNav2(BdsCNav2Block::parse(&header, block_data)?),
682 block_ids::BDS_CNAV3 => SbfBlock::BdsCNav3(BdsCNav3Block::parse(&header, block_data)?),
683 block_ids::QZS_NAV => SbfBlock::QzsNav(QzsNavBlock::parse(&header, block_data)?),
684 block_ids::QZS_ALM => SbfBlock::QzsAlm(QzsAlmBlock::parse(&header, block_data)?),
685 block_ids::GEO_IONO_DELAY => {
686 SbfBlock::GeoIonoDelay(GeoIonoDelayBlock::parse(&header, block_data)?)
687 }
688 block_ids::GPS_RAW_CA => SbfBlock::GpsRawCa(GpsRawCaBlock::parse(&header, block_data)?),
689 block_ids::GPS_RAW_L2C => {
690 SbfBlock::GpsRawL2C(GpsRawL2CBlock::parse(&header, block_data)?)
691 }
692 block_ids::GPS_RAW_L5 => SbfBlock::GpsRawL5(GpsRawL5Block::parse(&header, block_data)?),
693 block_ids::GAL_RAW_FNAV => {
694 SbfBlock::GalRawFnav(GalRawFnavBlock::parse(&header, block_data)?)
695 }
696 block_ids::GAL_RAW_INAV => {
697 SbfBlock::GalRawInav(GalRawInavBlock::parse(&header, block_data)?)
698 }
699 block_ids::GAL_RAW_CNAV => {
700 SbfBlock::GalRawCnav(GalRawCnavBlock::parse(&header, block_data)?)
701 }
702 block_ids::GEO_RAW_L1 => SbfBlock::GeoRawL1(GeoRawL1Block::parse(&header, block_data)?),
703 block_ids::GEO_RAW_L5 => SbfBlock::GeoRawL5(GeoRawL5Block::parse(&header, block_data)?),
704 block_ids::GLO_RAW_CA => SbfBlock::GloRawCa(GloRawCaBlock::parse(&header, block_data)?),
705 block_ids::CMP_RAW => SbfBlock::CmpRaw(CmpRawBlock::parse(&header, block_data)?),
706 block_ids::BDS_RAW_B1C => {
707 SbfBlock::BdsRawB1c(BdsRawB1cBlock::parse(&header, block_data)?)
708 }
709 block_ids::BDS_RAW_B2A => {
710 SbfBlock::BdsRawB2a(BdsRawB2aBlock::parse(&header, block_data)?)
711 }
712 block_ids::NAVIC_RAW => SbfBlock::IrnssRaw(IrnssRawBlock::parse(&header, block_data)?),
713 block_ids::QZS_RAW_L1CA => {
714 SbfBlock::QzsRawL1Ca(QzsRawL1CaBlock::parse(&header, block_data)?)
715 }
716 block_ids::QZS_RAW_L2C => {
717 SbfBlock::QzsRawL2C(QzsRawL2CBlock::parse(&header, block_data)?)
718 }
719 block_ids::QZS_RAW_L5 => SbfBlock::QzsRawL5(QzsRawL5Block::parse(&header, block_data)?),
720 block_ids::GEO_MT00 => SbfBlock::GeoMt00(GeoMt00Block::parse(&header, block_data)?),
721 block_ids::GEO_PRN_MASK => {
722 SbfBlock::GeoPrnMask(GeoPrnMaskBlock::parse(&header, block_data)?)
723 }
724 block_ids::GEO_FAST_CORR => {
725 SbfBlock::GeoFastCorr(GeoFastCorrBlock::parse(&header, block_data)?)
726 }
727 block_ids::GEO_FAST_CORR_DEGR => {
728 SbfBlock::GeoFastCorrDegr(GeoFastCorrDegrBlock::parse(&header, block_data)?)
729 }
730 block_ids::GEO_DEGR_FACTORS => {
731 SbfBlock::GeoDegrFactors(GeoDegrFactorsBlock::parse(&header, block_data)?)
732 }
733 block_ids::GEO_SERVICE_LEVEL => {
734 SbfBlock::GeoServiceLevel(GeoServiceLevelBlock::parse(&header, block_data)?)
735 }
736 block_ids::GEO_NAV => SbfBlock::GeoNav(GeoNavBlock::parse(&header, block_data)?),
737 block_ids::GEO_INTEGRITY => {
738 SbfBlock::GeoIntegrity(GeoIntegrityBlock::parse(&header, block_data)?)
739 }
740 block_ids::GEO_ALM => SbfBlock::GeoAlm(GeoAlmBlock::parse(&header, block_data)?),
741 block_ids::GEO_NETWORK_TIME => {
742 SbfBlock::GeoNetworkTime(GeoNetworkTimeBlock::parse(&header, block_data)?)
743 }
744 block_ids::GEO_IGP_MASK => {
745 SbfBlock::GeoIgpMask(GeoIgpMaskBlock::parse(&header, block_data)?)
746 }
747 block_ids::GEO_LONG_TERM_CORR => {
748 SbfBlock::GeoLongTermCorr(GeoLongTermCorrBlock::parse(&header, block_data)?)
749 }
750 block_ids::GEO_CLOCK_EPH_COV_MATRIX => SbfBlock::GeoClockEphCovMatrix(
751 GeoClockEphCovMatrixBlock::parse(&header, block_data)?,
752 ),
753 block_ids::RECEIVER_STATUS => {
754 SbfBlock::ReceiverStatus(ReceiverStatusBlock::parse(&header, block_data)?)
755 }
756 block_ids::TRACKING_STATUS => {
757 SbfBlock::TrackingStatus(ChannelStatusBlock::parse(&header, block_data)?)
758 }
759 block_ids::CHANNEL_STATUS => {
760 SbfBlock::ChannelStatus(ChannelStatusBlock::parse(&header, block_data)?)
761 }
762 block_ids::SAT_VISIBILITY => {
763 SbfBlock::SatVisibility(SatVisibilityBlock::parse(&header, block_data)?)
764 }
765 block_ids::QUALITY_IND => {
766 SbfBlock::QualityInd(QualityIndBlock::parse(&header, block_data)?)
767 }
768 block_ids::INPUT_LINK => {
769 SbfBlock::InputLink(InputLinkBlock::parse(&header, block_data)?)
770 }
771 block_ids::OUTPUT_LINK => {
772 SbfBlock::OutputLink(OutputLinkBlock::parse(&header, block_data)?)
773 }
774 block_ids::LBAND_TRACKER_STATUS => {
775 SbfBlock::LBandTrackerStatus(LBandTrackerStatusBlock::parse(&header, block_data)?)
776 }
777 block_ids::COMMANDS => SbfBlock::Commands(CommandsBlock::parse(&header, block_data)?),
778 block_ids::COMMENT => SbfBlock::Comment(CommentBlock::parse(&header, block_data)?),
779 block_ids::RECEIVER_SETUP => {
780 SbfBlock::ReceiverSetup(ReceiverSetupBlock::parse(&header, block_data)?)
781 }
782 block_ids::BB_SAMPLES => {
783 SbfBlock::BBSamples(BBSamplesBlock::parse(&header, block_data)?)
784 }
785 block_ids::ASCII_IN => SbfBlock::ASCIIIn(ASCIIInBlock::parse(&header, block_data)?),
786 block_ids::NTRIP_CLIENT_STATUS => {
787 SbfBlock::NtripClientStatus(NtripClientStatusBlock::parse(&header, block_data)?)
788 }
789 block_ids::NTRIP_SERVER_STATUS => {
790 SbfBlock::NtripServerStatus(NtripServerStatusBlock::parse(&header, block_data)?)
791 }
792 block_ids::RF_STATUS => SbfBlock::RfStatus(RfStatusBlock::parse(&header, block_data)?),
793 block_ids::RTCM_DATUM => SbfBlock::RtcmDatum(RtcmDatumBlock::parse(&header, block_data)?),
794 block_ids::LBAND_BEAMS => {
795 SbfBlock::LBandBeams(LBandBeamsBlock::parse(&header, block_data)?)
796 }
797 block_ids::DYN_DNS_STATUS => {
798 SbfBlock::DynDnsStatus(DynDnsStatusBlock::parse(&header, block_data)?)
799 }
800 block_ids::DISK_STATUS => {
801 SbfBlock::DiskStatus(DiskStatusBlock::parse(&header, block_data)?)
802 }
803 block_ids::P2PP_STATUS => {
804 SbfBlock::P2ppStatus(P2ppStatusBlock::parse(&header, block_data)?)
805 }
806 block_ids::COSMOS_STATUS => {
807 SbfBlock::CosmosStatus(CosmosStatusBlock::parse(&header, block_data)?)
808 }
809 block_ids::RX_MESSAGE => {
810 SbfBlock::RxMessage(RxMessageBlock::parse(&header, block_data)?)
811 }
812 block_ids::ENCAPSULATED_OUTPUT => SbfBlock::EncapsulatedOutput(
813 EncapsulatedOutputBlock::parse(&header, block_data)?,
814 ),
815 block_ids::GIS_ACTION => {
816 SbfBlock::GisAction(GisActionBlock::parse(&header, block_data)?)
817 }
818 block_ids::GIS_STATUS => {
819 SbfBlock::GisStatus(GisStatusBlock::parse(&header, block_data)?)
820 }
821 block_ids::RECEIVER_TIME => {
822 SbfBlock::ReceiverTime(ReceiverTimeBlock::parse(&header, block_data)?)
823 }
824 block_ids::PPS_OFFSET => {
825 SbfBlock::PpsOffset(PpsOffsetBlock::parse(&header, block_data)?)
826 }
827 block_ids::EXT_EVENT => SbfBlock::ExtEvent(ExtEventBlock::parse(&header, block_data)?),
828 block_ids::EXT_EVENT_PVT_CARTESIAN => SbfBlock::ExtEventPvtCartesian(
829 ExtEventPvtCartesianBlock::parse(&header, block_data)?,
830 ),
831 block_ids::EXT_EVENT_PVT_GEODETIC => {
832 SbfBlock::ExtEventPvtGeodetic(ExtEventPvtGeodeticBlock::parse(&header, block_data)?)
833 }
834 block_ids::EXT_EVENT_BASE_VECT_GEOD => SbfBlock::ExtEventBaseVectGeod(
835 ExtEventBaseVectGeodBlock::parse(&header, block_data)?,
836 ),
837 block_ids::EXT_EVENT_ATT_EULER => {
838 SbfBlock::ExtEventAttEuler(ExtEventAttEulerBlock::parse(&header, block_data)?)
839 }
840 block_ids::END_OF_PVT => SbfBlock::EndOfPvt(EndOfPvtBlock::parse(&header, block_data)?),
841 block_ids::INT_PV_CART => {
842 SbfBlock::IntPvCart(IntPvCartBlock::parse(&header, block_data)?)
843 }
844 block_ids::INT_PV_GEOD => {
845 SbfBlock::IntPvGeod(IntPvGeodBlock::parse(&header, block_data)?)
846 }
847 block_ids::INT_ATT_EULER => {
848 SbfBlock::IntAttEuler(IntAttEulerBlock::parse(&header, block_data)?)
849 }
850 block_ids::INT_POS_COV_CART => {
851 SbfBlock::IntPosCovCart(IntPosCovCartBlock::parse(&header, block_data)?)
852 }
853 block_ids::INT_VEL_COV_CART => {
854 SbfBlock::IntVelCovCart(IntVelCovCartBlock::parse(&header, block_data)?)
855 }
856 block_ids::INT_POS_COV_GEOD => {
857 SbfBlock::IntPosCovGeod(IntPosCovGeodBlock::parse(&header, block_data)?)
858 }
859 block_ids::INT_VEL_COV_GEOD => {
860 SbfBlock::IntVelCovGeod(IntVelCovGeodBlock::parse(&header, block_data)?)
861 }
862 block_ids::INT_ATT_COV_EULER => {
863 SbfBlock::IntAttCovEuler(IntAttCovEulerBlock::parse(&header, block_data)?)
864 }
865 block_ids::IP_STATUS => SbfBlock::IpStatus(IpStatusBlock::parse(&header, block_data)?),
866 block_ids::IQ_CORR => SbfBlock::IqCorr(IqCorrBlock::parse(&header, block_data)?),
867 block_ids::EXT_SENSOR_MEAS => {
868 SbfBlock::ExtSensorMeas(ExtSensorMeasBlock::parse(&header, block_data)?)
869 }
870 block_ids::EXT_SENSOR_STATUS => {
871 SbfBlock::ExtSensorStatus(ExtSensorStatusBlock::parse(&header, block_data)?)
872 }
873 block_ids::EXT_SENSOR_SETUP => {
874 SbfBlock::ExtSensorSetup(ExtSensorSetupBlock::parse(&header, block_data)?)
875 }
876 id if is_known_opaque_id(id) => SbfBlock::KnownOpaque {
877 id,
878 rev: header.block_rev,
879 data: data[8..total_len].to_vec(),
880 },
881 _ => SbfBlock::Unknown {
882 id: header.block_id,
883 rev: header.block_rev,
884 data: data[8..total_len].to_vec(),
885 },
886 };
887
888 Ok((block, total_len))
889 }
890
891 pub fn block_id(&self) -> u16 {
893 match self {
894 SbfBlock::MeasEpoch(_) => block_ids::MEAS_EPOCH,
895 SbfBlock::MeasExtra(_) => block_ids::MEAS_EXTRA,
896 SbfBlock::EndOfMeas(_) => block_ids::END_OF_MEAS,
897 SbfBlock::Meas3Ranges(_) => block_ids::MEAS3_RANGES,
898 SbfBlock::Meas3Cn0HiRes(_) => block_ids::MEAS3_CN0_HI_RES,
899 SbfBlock::Meas3Doppler(_) => block_ids::MEAS3_DOPPLER,
900 SbfBlock::Meas3Pp(_) => block_ids::MEAS3_PP,
901 SbfBlock::Meas3Mp(_) => block_ids::MEAS3_MP,
902 SbfBlock::PvtGeodetic(_) => block_ids::PVT_GEODETIC,
903 SbfBlock::PvtCartesian(_) => block_ids::PVT_CARTESIAN,
904 SbfBlock::Dop(_) => block_ids::DOP,
905 SbfBlock::PosCart(_) => block_ids::POS_CART,
906 SbfBlock::PvtSatCartesian(_) => block_ids::PVT_SAT_CARTESIAN,
907 SbfBlock::PvtResidualsV2(_) => block_ids::PVT_RESIDUALS_V2,
908 SbfBlock::RaimStatisticsV2(_) => block_ids::RAIM_STATISTICS_V2,
909 SbfBlock::BaseVectorCart(_) => block_ids::BASE_VECTOR_CART,
910 SbfBlock::BaseVectorGeod(_) => block_ids::BASE_VECTOR_GEOD,
911 SbfBlock::PosCovCartesian(_) => block_ids::POS_COV_CARTESIAN,
912 SbfBlock::PosCovGeodetic(_) => block_ids::POS_COV_GEODETIC,
913 SbfBlock::VelCovCartesian(_) => block_ids::VEL_COV_CARTESIAN,
914 SbfBlock::VelCovGeodetic(_) => block_ids::VEL_COV_GEODETIC,
915 SbfBlock::GeoCorrections(_) => block_ids::GEO_CORRECTIONS,
916 SbfBlock::BaseStation(_) => block_ids::BASE_STATION,
917 SbfBlock::DiffCorrIn(_) => block_ids::DIFF_CORR_IN,
918 SbfBlock::PvtSupport(_) => block_ids::PVT_SUPPORT,
919 SbfBlock::PvtSupportA(_) => block_ids::PVT_SUPPORT_A,
920 SbfBlock::PosLocal(_) => block_ids::POS_LOCAL,
921 SbfBlock::PosProjected(_) => block_ids::POS_PROJECTED,
922 SbfBlock::IntPvaaGeod(_) => block_ids::INT_PVA_AGEOD,
923 SbfBlock::AttEuler(_) => block_ids::ATT_EULER,
924 SbfBlock::AttCovEuler(_) => block_ids::ATT_COV_EULER,
925 SbfBlock::AuxAntPositions(_) => block_ids::AUX_ANT_POSITIONS,
926 SbfBlock::EndOfAtt(_) => block_ids::END_OF_ATT,
927 SbfBlock::GpsNav(_) => block_ids::GPS_NAV,
928 SbfBlock::GpsAlm(_) => block_ids::GPS_ALM,
929 SbfBlock::GpsIon(_) => block_ids::GPS_ION,
930 SbfBlock::GpsUtc(_) => block_ids::GPS_UTC,
931 SbfBlock::GpsCNav(_) => block_ids::GPS_CNAV,
932 SbfBlock::GalNav(_) => block_ids::GAL_NAV,
933 SbfBlock::GalAlm(_) => block_ids::GAL_ALM,
934 SbfBlock::GalIon(_) => block_ids::GAL_ION,
935 SbfBlock::GalUtc(_) => block_ids::GAL_UTC,
936 SbfBlock::GalGstGps(_) => block_ids::GAL_GST_GPS,
937 SbfBlock::GalSarRlm(_) => block_ids::GAL_SAR_RLM,
938 SbfBlock::GloNav(_) => block_ids::GLO_NAV,
939 SbfBlock::GloAlm(_) => block_ids::GLO_ALM,
940 SbfBlock::GloTime(_) => block_ids::GLO_TIME,
941 SbfBlock::BdsIon(_) => block_ids::BDS_ION,
942 SbfBlock::BdsNav(_) => block_ids::BDS_NAV,
943 SbfBlock::BdsAlm(_) => block_ids::BDS_ALM,
944 SbfBlock::BdsUtc(_) => block_ids::BDS_UTC,
945 SbfBlock::BdsCNav1(_) => block_ids::BDS_CNAV1,
946 SbfBlock::BdsCNav2(_) => block_ids::BDS_CNAV2,
947 SbfBlock::BdsCNav3(_) => block_ids::BDS_CNAV3,
948 SbfBlock::QzsNav(_) => block_ids::QZS_NAV,
949 SbfBlock::QzsAlm(_) => block_ids::QZS_ALM,
950 SbfBlock::GeoIonoDelay(_) => block_ids::GEO_IONO_DELAY,
951 SbfBlock::GpsRawCa(_) => block_ids::GPS_RAW_CA,
952 SbfBlock::GpsRawL2C(_) => block_ids::GPS_RAW_L2C,
953 SbfBlock::GpsRawL5(_) => block_ids::GPS_RAW_L5,
954 SbfBlock::GalRawFnav(_) => block_ids::GAL_RAW_FNAV,
955 SbfBlock::GalRawInav(_) => block_ids::GAL_RAW_INAV,
956 SbfBlock::GalRawCnav(_) => block_ids::GAL_RAW_CNAV,
957 SbfBlock::GeoRawL1(_) => block_ids::GEO_RAW_L1,
958 SbfBlock::GeoRawL5(_) => block_ids::GEO_RAW_L5,
959 SbfBlock::GloRawCa(_) => block_ids::GLO_RAW_CA,
960 SbfBlock::CmpRaw(_) => block_ids::CMP_RAW,
961 SbfBlock::BdsRawB1c(_) => block_ids::BDS_RAW_B1C,
962 SbfBlock::BdsRawB2a(_) => block_ids::BDS_RAW_B2A,
963 SbfBlock::IrnssRaw(_) => block_ids::NAVIC_RAW,
964 SbfBlock::QzsRawL1Ca(_) => block_ids::QZS_RAW_L1CA,
965 SbfBlock::QzsRawL2C(_) => block_ids::QZS_RAW_L2C,
966 SbfBlock::QzsRawL5(_) => block_ids::QZS_RAW_L5,
967 SbfBlock::GeoMt00(_) => block_ids::GEO_MT00,
968 SbfBlock::GeoPrnMask(_) => block_ids::GEO_PRN_MASK,
969 SbfBlock::GeoFastCorr(_) => block_ids::GEO_FAST_CORR,
970 SbfBlock::GeoFastCorrDegr(_) => block_ids::GEO_FAST_CORR_DEGR,
971 SbfBlock::GeoDegrFactors(_) => block_ids::GEO_DEGR_FACTORS,
972 SbfBlock::GeoServiceLevel(_) => block_ids::GEO_SERVICE_LEVEL,
973 SbfBlock::GeoNav(_) => block_ids::GEO_NAV,
974 SbfBlock::GeoIntegrity(_) => block_ids::GEO_INTEGRITY,
975 SbfBlock::GeoAlm(_) => block_ids::GEO_ALM,
976 SbfBlock::GeoNetworkTime(_) => block_ids::GEO_NETWORK_TIME,
977 SbfBlock::GeoIgpMask(_) => block_ids::GEO_IGP_MASK,
978 SbfBlock::GeoLongTermCorr(_) => block_ids::GEO_LONG_TERM_CORR,
979 SbfBlock::GeoClockEphCovMatrix(_) => block_ids::GEO_CLOCK_EPH_COV_MATRIX,
980 SbfBlock::ReceiverStatus(_) => block_ids::RECEIVER_STATUS,
981 SbfBlock::TrackingStatus(_) => block_ids::TRACKING_STATUS,
982 SbfBlock::ChannelStatus(_) => block_ids::CHANNEL_STATUS,
983 SbfBlock::SatVisibility(_) => block_ids::SAT_VISIBILITY,
984 SbfBlock::QualityInd(_) => block_ids::QUALITY_IND,
985 SbfBlock::InputLink(_) => block_ids::INPUT_LINK,
986 SbfBlock::OutputLink(_) => block_ids::OUTPUT_LINK,
987 SbfBlock::LBandTrackerStatus(_) => block_ids::LBAND_TRACKER_STATUS,
988 SbfBlock::Commands(_) => block_ids::COMMANDS,
989 SbfBlock::Comment(_) => block_ids::COMMENT,
990 SbfBlock::ReceiverSetup(_) => block_ids::RECEIVER_SETUP,
991 SbfBlock::BBSamples(_) => block_ids::BB_SAMPLES,
992 SbfBlock::ASCIIIn(_) => block_ids::ASCII_IN,
993 SbfBlock::NtripClientStatus(_) => block_ids::NTRIP_CLIENT_STATUS,
994 SbfBlock::NtripServerStatus(_) => block_ids::NTRIP_SERVER_STATUS,
995 SbfBlock::RfStatus(_) => block_ids::RF_STATUS,
996 SbfBlock::RtcmDatum(_) => block_ids::RTCM_DATUM,
997 SbfBlock::LBandBeams(_) => block_ids::LBAND_BEAMS,
998 SbfBlock::DynDnsStatus(_) => block_ids::DYN_DNS_STATUS,
999 SbfBlock::DiskStatus(_) => block_ids::DISK_STATUS,
1000 SbfBlock::P2ppStatus(_) => block_ids::P2PP_STATUS,
1001 SbfBlock::CosmosStatus(_) => block_ids::COSMOS_STATUS,
1002 SbfBlock::RxMessage(_) => block_ids::RX_MESSAGE,
1003 SbfBlock::EncapsulatedOutput(_) => block_ids::ENCAPSULATED_OUTPUT,
1004 SbfBlock::GisAction(_) => block_ids::GIS_ACTION,
1005 SbfBlock::GisStatus(_) => block_ids::GIS_STATUS,
1006 SbfBlock::ReceiverTime(_) => block_ids::RECEIVER_TIME,
1007 SbfBlock::PpsOffset(_) => block_ids::PPS_OFFSET,
1008 SbfBlock::ExtEvent(_) => block_ids::EXT_EVENT,
1009 SbfBlock::ExtEventPvtCartesian(_) => block_ids::EXT_EVENT_PVT_CARTESIAN,
1010 SbfBlock::ExtEventPvtGeodetic(_) => block_ids::EXT_EVENT_PVT_GEODETIC,
1011 SbfBlock::ExtEventBaseVectGeod(_) => block_ids::EXT_EVENT_BASE_VECT_GEOD,
1012 SbfBlock::ExtEventAttEuler(_) => block_ids::EXT_EVENT_ATT_EULER,
1013 SbfBlock::EndOfPvt(_) => block_ids::END_OF_PVT,
1014 SbfBlock::IntPvCart(_) => block_ids::INT_PV_CART,
1015 SbfBlock::IntPvGeod(_) => block_ids::INT_PV_GEOD,
1016 SbfBlock::IntAttEuler(_) => block_ids::INT_ATT_EULER,
1017 SbfBlock::IntPosCovCart(_) => block_ids::INT_POS_COV_CART,
1018 SbfBlock::IntVelCovCart(_) => block_ids::INT_VEL_COV_CART,
1019 SbfBlock::IntPosCovGeod(_) => block_ids::INT_POS_COV_GEOD,
1020 SbfBlock::IntVelCovGeod(_) => block_ids::INT_VEL_COV_GEOD,
1021 SbfBlock::IntAttCovEuler(_) => block_ids::INT_ATT_COV_EULER,
1022 SbfBlock::IpStatus(_) => block_ids::IP_STATUS,
1023 SbfBlock::IqCorr(_) => block_ids::IQ_CORR,
1024 SbfBlock::ExtSensorMeas(_) => block_ids::EXT_SENSOR_MEAS,
1025 SbfBlock::ExtSensorStatus(_) => block_ids::EXT_SENSOR_STATUS,
1026 SbfBlock::ExtSensorSetup(_) => block_ids::EXT_SENSOR_SETUP,
1027 SbfBlock::KnownOpaque { id, .. } => *id,
1028 SbfBlock::Unknown { id, .. } => *id,
1029 }
1030 }
1031
1032 pub fn name(&self) -> &'static str {
1034 block_name(self.block_id())
1035 }
1036
1037 pub fn unsupported_payload(&self) -> Option<&[u8]> {
1041 match self {
1042 SbfBlock::KnownOpaque { data, .. } | SbfBlock::Unknown { data, .. } => Some(data),
1043 _ => None,
1044 }
1045 }
1046}
1047
1048#[cfg(test)]
1049mod tests {
1050 use super::*;
1051
1052 fn build_min_block(block_id: u16, block_rev: u8) -> Vec<u8> {
1053 let total_len = 16u16;
1054 let mut data = vec![0u8; total_len as usize];
1055 data[0] = 0x24;
1056 data[1] = 0x40;
1057
1058 let id_rev = block_id | ((block_rev as u16 & 0x07) << 13);
1059 data[4..6].copy_from_slice(&id_rev.to_le_bytes());
1060 data[6..8].copy_from_slice(&total_len.to_le_bytes());
1061 data[8..12].copy_from_slice(&123_456u32.to_le_bytes());
1062 data[12..14].copy_from_slice(&2150u16.to_le_bytes());
1063 data[14] = 0xAA;
1064 data[15] = 0x55;
1065 data
1066 }
1067
1068 #[test]
1069 fn test_meas3_ranges_min_block_parse() {
1070 let total_len = 20u16;
1072 let mut data = vec![0u8; total_len as usize];
1073 data[0] = 0x24;
1074 data[1] = 0x40;
1075 let id_rev = block_ids::MEAS3_RANGES | ((2u16 & 0x07) << 13);
1076 data[4..6].copy_from_slice(&id_rev.to_le_bytes());
1077 data[6..8].copy_from_slice(&total_len.to_le_bytes());
1078 data[8..12].copy_from_slice(&123_456u32.to_le_bytes());
1079 data[12..14].copy_from_slice(&2150u16.to_le_bytes());
1080
1081 let (block, consumed) = SbfBlock::parse(&data).unwrap();
1082 assert_eq!(consumed, usize::from(total_len));
1083 match block {
1084 SbfBlock::Meas3Ranges(m) => {
1085 assert_eq!(m.tow_ms(), 123_456);
1086 assert_eq!(m.wnc(), 2150);
1087 assert_eq!(m.data, Vec::<u8>::new());
1088 }
1089 other => panic!("expected Meas3Ranges, got {:?}", other),
1090 }
1091 }
1092
1093 #[test]
1094 fn test_pvt_support_parse() {
1095 let data = build_min_block(block_ids::PVT_SUPPORT, 1);
1096 let (block, consumed) = SbfBlock::parse(&data).unwrap();
1097
1098 assert_eq!(consumed, 16);
1099 assert_eq!(block.block_id(), block_ids::PVT_SUPPORT);
1100 match block {
1101 SbfBlock::PvtSupport(pvt) => {
1102 assert_eq!(pvt.tow_ms(), 123_456);
1103 assert_eq!(pvt.wnc(), 2150);
1104 assert!((pvt.tow_seconds() - 123.456).abs() < 1e-6);
1105 }
1106 other => panic!("expected PvtSupport, got {:?}", other),
1107 }
1108 }
1109
1110 #[test]
1111 fn test_unknown_id_stays_unknown() {
1112 let data = build_min_block(4999, 0);
1113 let (block, _) = SbfBlock::parse(&data).unwrap();
1114
1115 match block {
1116 SbfBlock::Unknown { id, rev, data } => {
1117 assert_eq!(id, 4999);
1118 assert_eq!(rev, 0);
1119 assert_eq!(data, vec![0x40, 0xE2, 0x01, 0x00, 0x66, 0x08, 0xAA, 0x55]);
1120 }
1121 other => panic!("expected Unknown, got {:?}", other),
1122 }
1123 }
1124
1125 #[test]
1126 fn test_unsupported_payload_helper() {
1127 let known_data = build_min_block(block_ids::FUGRO_DDS, 0);
1128 let (known, _) = SbfBlock::parse(&known_data).unwrap();
1129 assert_eq!(
1130 known.unsupported_payload(),
1131 Some([0x40, 0xE2, 0x01, 0x00, 0x66, 0x08, 0xAA, 0x55].as_slice())
1132 );
1133
1134 let unknown_data = build_min_block(4998, 1);
1135 let (unknown, _) = SbfBlock::parse(&unknown_data).unwrap();
1136 assert_eq!(
1137 unknown.unsupported_payload(),
1138 Some([0x40, 0xE2, 0x01, 0x00, 0x66, 0x08, 0xAA, 0x55].as_slice())
1139 );
1140 }
1141}