Changeset 11047 in ntrip for trunk/BNC/src/RTCM3/RTCM3coDecoder.cpp
- Timestamp:
- Sep 28, 2026, 11:17:34 AM (5 hours ago)
- File:
-
- 1 edited
-
trunk/BNC/src/RTCM3/RTCM3coDecoder.cpp (modified) (13 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/BNC/src/RTCM3/RTCM3coDecoder.cpp
r11041 r11047 105 105 106 106 for (unsigned s = 0; s < CLOCKORBIT_SATNUM; s++) { 107 _antennaSentIOD[s] = UINT_MAX; // "never sent" 107 _antennaReceived[s] = false; 108 _antennaIODKnown[s] = false; 109 _antennaIODProvider[s] = 0; 110 _antennaIODCur[s] = 0; 111 _antennaIODPrev[s] = 0; 112 } 113 for (unsigned i = 0; i < CLOCKORBIT_COUNTSAT; i++) { 114 _antennaSentProviderID[i] = 0; 115 _antennaSentIOD[i] = 0; // meaningless while _antennaSentTime[i] is invalid ("never sent") 108 116 } 109 117 … … 203 211 memcpy(&_stateSnapshot->antenna, &_antenna, sizeof(_antenna)); 204 212 213 // _antenna persists across messages, so its content alone can't tell 214 // whether a Satellite Antenna message arrived in this frame (an unchanged 215 // retransmission looks identical). Clear messageType[] as a marker: the 216 // COBOFS_SATANT decoder sets it (always non-zero) for each system it 217 // decodes. Restored with the snapshot if the frame turns out incomplete. 218 for (unsigned s = 0; s < CLOCKORBIT_SATNUM; s++) { 219 _antenna.messageType[s] = 0; 220 } 221 205 222 int bytesused = 0; 206 223 … … 240 257 241 258 if (irc == GCOBR_OK || irc == GCOBR_MESSAGEFOLLOWS ) { 259 // Latch the reception until sendResults() consumes it - it may not 260 // run for this frame if _lastTime is still invalid. 261 for (unsigned s = 0; s < CLOCKORBIT_SATNUM; s++) { 262 if (_antenna.messageType[s] != 0) { 263 _antennaReceived[s] = true; 264 checkAntennaIOD(s); 265 } 266 } 242 267 setEpochTime(); // sets _lastTime 243 268 … … 342 367 t_orbCorr orbCorr; 343 368 orbCorr._prn.set(sys, num, flag); 369 checkPrnRange(orbCorr._prn); 344 370 orbCorr._staID = _staID.toStdString(); 345 371 orbCorr._iod = _clkOrb.Sat[ii].IOD; … … 378 404 t_clkCorr clkCorr; 379 405 clkCorr._prn.set(sys, _clkOrb.Sat[ii].ID, flag); 406 checkPrnRange(clkCorr._prn); 380 407 clkCorr._staID = _staID.toStdString(); 381 408 clkCorr._time = _lastTime; … … 470 497 t_satCodeBias satCodeBias; 471 498 satCodeBias._prn.set(sys, num, flag); 499 checkPrnRange(satCodeBias._prn); 472 500 satCodeBias._staID = _staID.toStdString(); 473 501 satCodeBias._time = _lastTime; 474 502 satCodeBias._updateInt = _codeBias.UpdateInterval; 503 satCodeBias._ssrIOD = _codeBias.SSRIOD; 504 satCodeBias._ssrProviderID = _codeBias.SSRProviderID; 475 505 for (unsigned jj = 0; jj < _codeBias.Sat[ii].NumberOfCodeBiases; jj++) { 476 506 const SsrCorr::CodeBias::BiasSat::CodeBiasEntry& biasEntry = _codeBias.Sat[ii].Biases[jj]; … … 560 590 t_satPhaseBias satPhaseBias; 561 591 satPhaseBias._prn.set(sys, num, flag); 592 checkPrnRange(satPhaseBias._prn); 562 593 satPhaseBias._staID = _staID.toStdString(); 563 594 satPhaseBias._time = _lastTime; 564 595 satPhaseBias._updateInt = _phaseBias.UpdateInterval; 596 satPhaseBias._ssrIOD = _phaseBias.SSRIOD; 597 satPhaseBias._ssrProviderID = _phaseBias.SSRProviderID; 565 598 satPhaseBias._ssrFormat = (_type == RTCMssr) ? ssrRtcmOld : 566 599 (_type == RTCMnewssr) ? ssrRtcmNew : ssrUnknown; … … 649 682 // _antenna, like _metaData, carries no epoch field of its own and is never 650 683 // wiped by reset(), so each system's data persists across unrelated 651 // messages. _antennaSentIOD tracks the last SatelliteAntennaIOD actually 652 // emitted per system, so unrelated messages (and unchanged retransmissions 653 // of the same antenna data) don't cause duplicate output - the same 654 // freshness problem _phaseBiasSentEpoch solves for phase biases. 684 // messages. Only a system for which an Antenna message was actually 685 // received (_antennaReceived, latched in Decode()) is considered, so 686 // persisted data is never re-stamped with a newer time. 687 // 688 // The SatelliteAntennaIOD is unique only per SSR Provider ID (DF414) and 689 // only within 64 days, and a client that has not received the stream for 690 // 64 days must discard cached antenna data (enforced downstream against 691 // t_satAntenna::_time, see ssrSatAntennaTrusted() in pppSatObs.cpp). So an 692 // unchanged (provider ID, IOD) retransmission is suppressed only if it was 693 // last emitted less than ANT_REFRESH_SEC ago. Re-emitting it after that 694 // keeps _time close to the last reception - not the first - so continuously 695 // received data never ages out. It also means a reception after a long 696 // gap is always emitted, even when the provider has legitimately reused 697 // the IOD for different content, and each .ssr file contains the antenna 698 // data at least once per refresh interval. 699 // 700 // This is tracked per satellite, not per system: providers may split a 701 // system's satellites across several messages with rotating satellite 702 // masks (DF394), all carrying the same IOD - a per-system check would 703 // emit only whichever subset happened to arrive first. 655 704 { 705 const double ANT_REFRESH_SEC = 3600.0; 656 706 struct SysInfo { unsigned sysIdx; char sysChar; unsigned numSat; unsigned offset; }; 657 707 const SysInfo sysInfos[] = { … … 664 714 for (const SysInfo& si : sysInfos) { 665 715 unsigned s = si.sysIdx; 666 if (_antenna.SatelliteAntennaIOD[s] == _antennaSentIOD[s]) { 667 continue; // nothing new for this system since the last emit 668 } 716 if (!_antennaReceived[s]) { 717 continue; // no Antenna message received for this system since the last check 718 } 719 _antennaReceived[s] = false; 669 720 if (_antenna.SatelliteMask[s] == 0) { 670 continue; // this system's antenna data was never decoded721 continue; // no satellites in this system's antenna data 671 722 } 672 723 for (unsigned k = 0; k < si.numSat; k++) { … … 674 725 continue; 675 726 } 727 unsigned i = si.offset + k; 728 if (_antennaSentTime[i].valid() && 729 _antenna.SSRProviderID[s] == _antennaSentProviderID[i] && 730 _antenna.SatelliteAntennaIOD[s] == _antennaSentIOD[i] && 731 _lastTime - _antennaSentTime[i] < ANT_REFRESH_SEC) { 732 continue; // unchanged retransmission, emitted recently 733 } 734 _antennaSentProviderID[i] = _antenna.SSRProviderID[s]; 735 _antennaSentIOD[i] = _antenna.SatelliteAntennaIOD[s]; 736 _antennaSentTime[i] = _lastTime; 676 737 int num = k + 1; // PRN within this system, DF394 MSB-first convention 677 738 int flag = 0; … … 696 757 satAntenna._nadirAngleRangeExtension = _antenna.NadirAngleDependentCorrectionRangeExtension[s]; 697 758 698 const SsrCorr::Antenna::SatellitePart& satPart = _antenna.Sat[ si.offset + k];759 const SsrCorr::Antenna::SatellitePart& satPart = _antenna.Sat[i]; 699 760 for (unsigned f = 0; f < ANT_MAXFREQUENCIES; f++) { 700 761 if (!((satPart.GnssFrequencyMask >> (ANT_MAXFREQUENCIES - 1 - f)) & 1U)) { … … 718 779 _satAntennas[_lastTime].append(satAntenna); 719 780 } 720 _antennaSentIOD[s] = _antenna.SatelliteAntennaIOD[s];721 781 } 722 782 } … … 1109 1169 } 1110 1170 } 1171 1172 // Satellite numbers on the wire can exceed BNC's supported range (e.g. 6-bit 1173 // IDs up to 63, while t_prn supports G01-G32). They are passed on unchanged, 1174 // but t_prn::toInt() maps them to the unused index 0, so they are not usable 1175 // for per-satellite processing - report that once per satellite. 1176 //////////////////////////////////////////////////////////////////////////// 1177 void RTCM3coDecoder::checkPrnRange(const t_prn& prn) { 1178 if (prn.toInt() != 0) { 1179 return; 1180 } 1181 QString prnStr = QString::fromStdString(prn.toString()); 1182 if (!_prnOutOfRangeLogged.contains(prnStr)) { 1183 _prnOutOfRangeLogged.insert(prnStr); 1184 emit newMessage(QString("%1: satellite %2 outside the range supported by BNC - not usable for processing") 1185 .arg(_staID).arg(prnStr).toLatin1(), true); 1186 } 1187 } 1188 1189 // All Satellite Antenna messages of one GNSS must use the same Satellite 1190 // Antenna IOD (a satellite set may be split over several messages). During 1191 // a legitimate IOD change old and new IOD are both seen for a while, until 1192 // every message has been sent with the new one - but the IOD never returns 1193 // to a replaced value within 64 days (uniqueness per SSR Provider ID), so a 1194 // switch back to the replaced IOD within that period reveals messages of the 1195 // same GNSS using different IODs. Reported once per GNSS and IOD pair; the 1196 // data itself is not changed (PPP checks each satellite's IOD individually). 1197 //////////////////////////////////////////////////////////////////////////// 1198 void RTCM3coDecoder::checkAntennaIOD(unsigned s) { 1199 const double MAX_AGE_SEC = 64.0 * 86400.0; 1200 unsigned int iod = _antenna.SatelliteAntennaIOD[s]; 1201 unsigned int provider = _antenna.SSRProviderID[s]; 1202 1203 int currentWeek = 0; 1204 double currentSec = 0.0; 1205 currentGPSWeeks(currentWeek, currentSec); 1206 bncTime currentTime(currentWeek, currentSec); 1207 1208 if (!_antennaIODKnown[s] || provider != _antennaIODProvider[s]) { 1209 _antennaIODKnown[s] = true; 1210 _antennaIODProvider[s] = provider; 1211 _antennaIODCur[s] = iod; 1212 _antennaIODPrevTime[s].reset(); // no replaced IOD yet 1213 return; 1214 } 1215 if (iod == _antennaIODCur[s]) { 1216 return; 1217 } 1218 if (_antennaIODPrevTime[s].valid() && iod == _antennaIODPrev[s] && 1219 currentTime - _antennaIODPrevTime[s] < MAX_AGE_SEC) { 1220 const char sysChars[CLOCKORBIT_SATNUM] = {'G', 'R', 'E', 'J', 'S', 'C'}; 1221 char sys = (s < CLOCKORBIT_SATNUM) ? sysChars[s] : '?'; 1222 QString key = QString("%1_%2_%3").arg(sys).arg(_antennaIODCur[s]).arg(iod); 1223 if (!_antennaIODLogged.contains(key)) { 1224 _antennaIODLogged.insert(key); 1225 emit newMessage(QString("%1: GNSS %2 Satellite Antenna IOD switches back %3 -> %4" 1226 " - messages of one GNSS must use the same IOD") 1227 .arg(_staID).arg(sys).arg(_antennaIODCur[s]).arg(iod).toLatin1(), true); 1228 } 1229 } 1230 _antennaIODPrev[s] = _antennaIODCur[s]; 1231 _antennaIODPrevTime[s] = currentTime; 1232 _antennaIODCur[s] = iod; 1233 }
Note:
See TracChangeset
for help on using the changeset viewer.
