Changeset 11130 in ntrip
- Timestamp:
- Oct 28, 2026, 9:32:30 AM (17 hours ago)
- Location:
- trunk/BNC
- Files:
-
- 20 edited
-
scripts/cmbPlot.pl (modified) (7 diffs)
-
scripts/compareSP3Plot.pl (modified) (5 diffs)
-
scripts/pppPlot.pl (modified) (15 diffs)
-
src/RTCM/RTCM2.cpp (modified) (2 diffs)
-
src/RTCM3/RTCM3Decoder.cpp (modified) (4 diffs)
-
src/RTCM3/bits.h (modified) (2 diffs)
-
src/RTCM3/clock_and_orbit/clock_orbit.h (modified) (1 diff)
-
src/RTCM3/clock_and_orbit/clock_orbit_rtcm_new.cpp (modified) (1 diff)
-
src/bnchelp.html (modified) (4 diffs)
-
src/bncmain.cpp (modified) (1 diff)
-
src/bncnetqueryrtp.cpp (modified) (3 diffs)
-
src/bncnetqueryv1.cpp (modified) (2 diffs)
-
src/src.pri (modified) (1 diff)
-
tests/README.md (modified) (4 diffs)
-
tests/cases/decoder_limits/expected/BrdcCorr.log.gz (modified) ( previous)
-
tests/data/crafted_limits.raw (modified) ( previous)
-
tests/tools/bncraw.py (modified) (3 diffs)
-
tests/tools/fakecaster.py (modified) (8 diffs)
-
tests/tools/mkcrafted.py (modified) (6 diffs)
-
tests/tools/ssr_harness.cpp (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/BNC/scripts/cmbPlot.pl
r10491 r11130 74 74 # for pdf generation 75 75 my ( $png, $page, $headline, $headline_text ); 76 my @pngFiles; # images to be deleted after inclusion in the PDF 76 77 my $y0 = 180 / mm; 77 78 my ( $x, $y, $width, $height ) = ( 40 / mm, $y0, 130 / mm, 80 / mm ); … … 179 180 my @datasets; # init datasets 180 181 my $pngName = sprintf ( "%s_CLK_CORR_%s.png", $inputFilename, $key_sys ); 182 push @pngFiles, $pngName; 181 183 my $chart = Chart::Gnuplot->new( 182 184 output => $pngName, … … 232 234 my @datasets; # init datasets 233 235 my $pngName = sprintf ( "%s_CLK_FULL_%s.png", $inputFilename, $key_sys ); 236 push @pngFiles, $pngName; 234 237 my $chart = Chart::Gnuplot->new( 235 238 output => $pngName, … … 287 290 my @datasets; # init datasets 288 291 my $pngName = sprintf ( "%s_OFFSETSAT_%s_%s.png", $inputFilename, $key_ac, $key_sys ); 292 push @pngFiles, $pngName; 289 293 my $chartOFFSETSAT = Chart::Gnuplot->new( 290 294 output => $pngName, … … 340 344 my @datasets; # init datasets 341 345 my $pngName = sprintf ( "%s_OFFSETAC_%s.png", $inputFilename, $key_sys ); 346 push @pngFiles, $pngName; 342 347 my $chart = Chart::Gnuplot->new( 343 348 output => $pngName, … … 393 398 my @datasets; # init datasets 394 399 my $pngName = sprintf ( "%s_RES_%s_%s.png", $inputFilename, $key_ac, $key_sys ); 400 push @pngFiles, $pngName; 395 401 my $chart = Chart::Gnuplot->new( 396 402 output => $pngName, … … 432 438 $pdf->save(); 433 439 $pdf->end(); 434 system ("rm $inputDir/*png"); 435 system("evince$inputDir/$pdf_name&");440 unlink @pngFiles; # only the images written here 441 if ( !fork() ) { exec( "evince", "$inputDir$pdf_name" ) or exit 1; } 436 442 437 443 #foreach my $t(@array) {print"$t \n ";} -
trunk/BNC/scripts/compareSP3Plot.pl
r11083 r11130 66 66 # for pdf generation 67 67 my ($png, $page, $headline, $headline_text); 68 my @pngFiles; # images to be deleted after inclusion in the PDF 68 69 my $y0 = 190/mm; 69 70 my ($x, $y, $width, $height) = (40/mm, $y0, 130/mm, 70/mm); … … 134 135 my (@datasets_r, @datasets_a, @datasets_o); # init datasets 135 136 my $pngName_r = sprintf ("%s_RADIAL_%s.png", $inputFilename, $key_sys); 137 push @pngFiles, $pngName_r; 136 138 my $pngName_a = sprintf ("%s_ALONG_%s.png", $inputFilename, $key_sys); 139 push @pngFiles, $pngName_a; 137 140 my $pngName_o = sprintf ("%s_OUT_%s.png", $inputFilename, $key_sys); 141 push @pngFiles, $pngName_o; 138 142 my $chart_r = Chart::Gnuplot->new( 139 143 output => $pngName_r, terminal => 'png', title => "Radial component", … … 231 235 my (@datasets_c, @datasets_r); # init datasets 232 236 my $pngName_c = sprintf ("%s_CLK_%s.png", $inputFilename, $key_sys); 237 push @pngFiles, $pngName_c; 233 238 my $pngName_r = sprintf ("%s_CLKRED_%s.png", $inputFilename, $key_sys); 239 push @pngFiles, $pngName_r; 234 240 my $chart_c = Chart::Gnuplot->new( 235 241 output => $pngName_c, terminal => 'png',title => "Clock only", … … 305 311 my @datasets_s; # init datasets 306 312 my $pngName_s = sprintf ("%s_SIS_%s.png", $inputFilename, $key_sys); 313 push @pngFiles, $pngName_s; 307 314 # SIS contains the satellite offsets: y range from the data 308 315 my $maxAbs = 0.1; … … 342 349 $pdf->save(); 343 350 $pdf->end(); 344 system("rm *png"); 351 unlink @pngFiles; # only the images written here 352 @pngFiles = (); 345 353 #system("evince $inputDir/$pdf_name&"); 346 354 } -
trunk/BNC/scripts/pppPlot.pl
r10879 r11130 87 87 # for pdf gerneration 88 88 my ( $png, $page, $headline, $headline_text ); 89 my @pngFiles; # images to be deleted after inclusion in the PDF 89 90 my $y0 = 180 / mm; 90 91 my ( $x, $y, $width, $height ) = ( 40 / mm, $y0, 130 / mm, 80 / mm ); … … 170 171 DEBUG "Plot NEU "; 171 172 my $pngNameNEU = sprintf( "%s_NEU.png", $station ); 173 push @pngFiles, $pngNameNEU; 172 174 my $chartNEU = newChart("$station ($dateStr)"); 173 175 $chartNEU->set( … … 207 209 DEBUG "Plot FIX"; 208 210 my $pngNameFIX = sprintf( "%s_FIX.png", $station ); 211 push @pngFiles, $pngNameFIX; 209 212 my $chartFIX = newChart("$station ($dateStr)"); 210 213 $chartFIX->set( … … 236 239 DEBUG "Plot TRP"; 237 240 my $pngNameTRP = sprintf( "%s_TRP.png", $station ); 241 push @pngFiles, $pngNameTRP; 238 242 my $chartTRP = newChart("$station ($dateStr)"); 239 243 $chartTRP->set( output => $pngNameTRP ); … … 278 282 my @datasets = (); # init datasets 279 283 my $pngNameRECCLK = sprintf( "%s_RECCLK.png", $station ); 284 push @pngFiles, $pngNameRECCLK; 280 285 $chartRECCLK->set( output => $pngNameRECCLK ); 281 286 $chartRECCLK->set( ylabel => "Receiver Clocks [m]" ); … … 323 328 my @datasets = (); # init datasets 324 329 my $pngNameELE = sprintf( "%s_ELE_%s.png", $station, $key_sys ); 330 push @pngFiles, $pngNameELE; 325 331 $chartELE->set( output => $pngNameELE ); 326 332 $chartELE->set( … … 370 376 my ( @datasets_amb, @datasets_epo ); # init datasets 371 377 my $pngNameAMB = sprintf( "%s_AMB_%s_%s.png", $station, $key_ambType, $key_sys ); 378 push @pngFiles, $pngNameAMB; 372 379 my $pngNameEPO = sprintf( "%s_EPO_%s_%s.png", $station, $key_ambType, $key_sys ); 380 push @pngFiles, $pngNameEPO; 373 381 my $chartAMB = Chart::Gnuplot->new( 374 382 output => $pngNameAMB, … … 458 466 my @datasets; # init datasets 459 467 my $pngNameION = sprintf( "%s_ION_%s.png", $station, $ksys ); 468 push @pngFiles, $pngNameION; 460 469 $chartION->set( output => $pngNameION ); 461 470 # SATELLITE … … 504 513 my $pngNameBIA = sprintf( "%s_BIAS_%s_%s.png", 505 514 $station, $key_biasType, $key_sys ); 515 push @pngFiles, $pngNameBIA; 506 516 $chartBIAS->set( output => $pngNameBIA ); 507 517 $chartBIAS->set( ylabel => "Receiver Bias $key_biasType [m]" ); … … 548 558 my @datasets; 549 559 my $pngNameRES = sprintf( "%s_RES_%s_%s.png", $station, $key_resType, $key_sys ); 560 push @pngFiles, $pngNameRES; 550 561 $chartRES->set( output => $pngNameRES ); 551 562 $chartRES->set(ylabel => "Residuals $key_resType [m]" ); … … 603 614 my @datasets; 604 615 my $pngNameCLKCORR = sprintf( "%s_CLKCORR_%s.png", $station, $ksys ); 616 push @pngFiles, $pngNameCLKCORR; 605 617 $chartCLKCORR->set( output => $pngNameCLKCORR ); 606 618 # SATELLITE … … 647 659 $chartYAW->set( legend => { position => "outside right" } ); 648 660 my $pngNameYAW = sprintf( "%s_YAW_%s.png", $station, $sat ); 661 push @pngFiles, $pngNameYAW; 649 662 $chartYAW->set( output => $pngNameYAW ); 650 663 # YAW from SSR data … … 696 709 my @datasets; 697 710 my $pngNameCB = sprintf( "%s_CB_%s_%s.png", $station, $key_type, $key_sys ); 711 push @pngFiles, $pngNameCB; 698 712 $chartCB->set( output => $pngNameCB ); 699 713 $chartCB->set( ylabel => "Code Biases $key_type [m]" ); … … 740 754 my (@datasetsJC, $datasetJC); 741 755 my $pngNamePB = sprintf( "%s_PB_%s_%s.png", $station, $key_type, $key_sys ); 756 push @pngFiles, $pngNamePB; 742 757 my $pngNameJC = sprintf( "%s_JC_%s_%s.png", $station, $key_type, $key_sys ); 758 push @pngFiles, $pngNameJC; 743 759 my $chartPB = newChart("$ssrData ($dateStr)"); 744 760 $chartPB->set( legend => { position => "outside right" } ); … … 799 815 $pdf->end(); 800 816 801 system("rm *.png"); 817 unlink @pngFiles; # only the images written here 818 @pngFiles = (); 802 819 if (Common::amInteractiv) { 803 system( "evince$inputDir/$pdf_name");820 system( "evince", "$inputDir$pdf_name" ); 804 821 } 805 822 -
trunk/BNC/src/RTCM/RTCM2.cpp
r7629 r11130 667 667 }; 668 668 669 if ( 24*DW.size() < start+n -1 ) {669 if ( 24*DW.size() < start+n ) { // last bit read: start+n-1 670 670 #if (DEBUG>0) 671 671 cerr << "Debug output RTCM2packet::getUnsignedBits" << endl … … 727 727 }; 728 728 729 if ( 24*DW.size() < start+n -1 ) {729 if ( 24*DW.size() < start+n ) { // last bit read: start+n-1 730 730 #if (DEBUG>0) 731 731 cerr << "Debug output RTCM2packet::getUnsignedBits" << endl -
trunk/BNC/src/RTCM3/RTCM3Decoder.cpp
r11124 r11130 39 39 * -----------------------------------------------------------------------*/ 40 40 41 #include <atomic> 41 42 #include <iostream> 42 43 #include <iomanip> … … 241 242 /** 242 243 * Frequency numbers of GLONASS with an offset of 100 to detect unset values. 243 * Gets filled by ephemeris and data blocks and shared between different streams. 244 * Gets filled by ephemeris and data blocks and shared between different streams 245 * (MSM4/6 streams without channel numbers use those of an ephemeris stream). 246 * Atomic, as the streams are decoded in different threads. 244 247 */ 245 static intGLOFreq[RTCM3_MSM_NUMSAT];248 static std::atomic<int> GLOFreq[RTCM3_MSM_NUMSAT]; 246 249 247 250 /* … … 1998 2001 GETSTRING(antnum, antenna) 1999 2002 if ((antnum > -1 && antnum < 265) && 2000 (_antType.empty() || strncmp(_antType.back()._descriptor, antenna, recnum) != 0)) { 2003 (_antType.empty() || int(strlen(_antType.back()._descriptor)) != antnum || 2004 strncmp(_antType.back()._descriptor, antenna, antnum) != 0)) { 2001 2005 _antType.push_back(t_antInfo()); 2002 2006 memcpy(_antType.back()._descriptor, antenna, antnum); … … 2017 2021 GETSTRING(recsernum, recserialnum) 2018 2022 if ((recnum > -1 && recnum < 265) && 2019 (_recType.empty() || strncmp(_recType.back()._descriptor, receiver, recnum) != 0)) { 2023 (_recType.empty() || int(strlen(_recType.back()._descriptor)) != recnum || 2024 strncmp(_recType.back()._descriptor, receiver, recnum) != 0)) { 2020 2025 _recType.push_back(t_recInfo()); 2021 2026 memcpy(_recType.back()._descriptor, receiver, recnum); -
trunk/BNC/src/RTCM3/bits.h
r11023 r11130 104 104 b = variable to store size, s = variable to store string pointer */ 105 105 #define GETSTRING(b, s) { \ 106 if(size < 1) return false; \ 106 107 b = *(data++); \ 108 --size; \ 109 if((b) > size) return false; \ 107 110 s = (char *) data; \ 108 111 data += b; \ 109 size -= b +1; \112 size -= b; \ 110 113 } 111 114 … … 126 129 } 127 130 131 /* up to 56 bits: less than 8 bits are pending in the 64-bit bitbuffer */ 128 132 #define ADDBITS(a, b) { \ 129 bitbuffer = (bitbuffer<<(a))|(( b)&((1<<a)-1)); \133 bitbuffer = (bitbuffer<<(a))|((uint64_t)(b)&((1ULL<<(a))-1)); \ 130 134 numbits += (a); \ 131 135 STOREBITS \ -
trunk/BNC/src/RTCM3/clock_and_orbit/clock_orbit.h
r11124 r11130 605 605 #define E_NADIR_ANGLE_DEPENDENT_CORR_RANGE_EXTENSION(a) ADDBITS(4, a) /* DF+015 (new RTCM) to extend DF+021*/ 606 606 #define E_SATELLITE_SET_INDICATOR(a) ADDBITS(1, a) /* DF+016 (new RTCM) */ 607 /* ADDBITS' mask "(1<<a)-1" uses a 32-bit int literal, so a plain 608 ADDBITS(64, a) is broken the same way GETSSRBITS(a, 64) was on decode 609 (see D_SATELLITE_MASK) - here even ADDBITS(32, ...) is unsafe, since 610 shifting a 32-bit int by exactly its own width is undefined behavior 611 too. Stay well clear of that edge by writing four 16-bit chunks. */ 607 /* ADDBITS handles up to 56 bits, so the 64-bit mask is written as two 608 32-bit halves (as GETSSRBITS(a, 64) does not work either, see 609 D_SATELLITE_MASK). */ 612 610 #define E_SATELLITE_MASK(a) { \ 613 611 uint64_t mask64_ = (a); \ 614 ADDBITS(16, (mask64_ >> 48) & 0xFFFFU) \ 615 ADDBITS(16, (mask64_ >> 32) & 0xFFFFU) \ 616 ADDBITS(16, (mask64_ >> 16) & 0xFFFFU) \ 617 ADDBITS(16, mask64_ & 0xFFFFU) \ 612 ADDBITS(32, mask64_ >> 32) \ 613 ADDBITS(32, mask64_ & 0xFFFFFFFFU) \ 618 614 } /* DF394 */ 619 615 #define E_FREQUENCY_SET_INDICATOR(a) ADDBITS(1, a) /* DF+017 (new RTCM) */ -
trunk/BNC/src/RTCM3/clock_and_orbit/clock_orbit_rtcm_new.cpp
r11126 r11130 489 489 if (md->Entries[i].nonDefaultIndicator && 490 490 md->Entries[i].additionalParameterIndicator) { 491 /* up to 255 bits, only 32 stored (leadingbits zero); in pieces of492 16 bits, as ADDBITS cannot handle more than 30 bits*/491 /* up to 255 bits, only 32 stored: leading zero bits (ADDBITS 492 handles at most 56 bits at a time), then the value */ 493 493 unsigned int k = md->Entries[i].additionalParameterNumBits; 494 while (k) { 495 unsigned int n = (k > 16) ? 16 : k; 494 while (k > 32) { 495 unsigned int n = (k - 32 > 56) ? 56 : k - 32; 496 ADDBITS(n, 0) 496 497 k -= n; 497 E_ADDITIONAL_MODEL_PARAMETER_DATA((k < 32) ? (md->Entries[i].additionalParameterData >> k) : 0, n) 498 } 498 } 499 if (k) 500 E_ADDITIONAL_MODEL_PARAMETER_DATA(md->Entries[i].additionalParameterData, k) 499 501 } 500 502 } -
trunk/BNC/src/bnchelp.html
r11128 r11130 147 147 2.8.2 <a href="#corrint">Interval</a><br> 148 148 2.8.3 <a href="#corrport">Port</a><br> 149 2.8.4 <a href="#ssrqc">QC Directory, QC Streams, QC Reference, QC Interval, QC Bias File</a><br> 149 2.8.4 <a href="#ssrqc">QC Directory, QC Streams, QC Reference, QC Interval, QC Bias File, QC ANTEX File</a><br> 150 150 2.8.4 <a href="#corrwait">Wait for Full Corr Epoch</a><br> 151 151 2.9 <a href="#syncout"><b>Feed Engine</b></a><br> … … 5097 5097 5098 5098 <p> 5099 <h4 id="ssrqc">2.8.4 QC Directory, QC Streams, QC Reference, QC Interval, QC Bias File - optional</h4> 5099 <h4 id="ssrqc">2.8.4 QC Directory, QC Streams, QC Reference, QC Interval, QC Bias File, QC ANTEX File - optional</h4> 5100 5100 </p> 5101 5101 <p> … … 5106 5106 e.g. 'ALL,!SIRGAS200001' for a stream referring to another reference frame than the ITRF. 'QC Reference' selects the reference of the stream comparison (see below). Select 5107 5107 the 'QC Interval' for the reports (default: 1 hour). A 'QC Bias File' (Bias SINEX, OSB or DSB, e.g. a CAS DCB or 5108 a GFZ OSB product) is an optional reference for the code bias check (see below). One daily file 5108 a GFZ OSB product) is an optional reference for the code bias check (see below). A 'QC ANTEX File' (e.g. the 5109 current igs20.atx) enables the attitude check (see below). One daily file 5109 5110 '<stream>_S_<YYYYDDD>0000_01D_QC.txt' is written per stream; at the end of each interval and at the 5110 5111 end of the program, a report per system is appended. Broadcast ephemerides must be received as well, e.g. via … … 5241 5242 clock 0.689 (STD 0.008), radial 0.020, along 0.036, cross 0.022, SIS (radial - clock) 0.687 (STD 0.008) 5242 5243 G satellites deviating from the reference, RMS SIS [m]: G02(0.38) G16(0.33) G20(0.91) G26(3.36) 5244 </pre> 5245 <p> 5246 <b>Attitude check:</b> With a 'QC ANTEX File', BNC checks for every stream sending the satellite yaw angle whether 5247 its clocks are consistent with its yaw angles during noon and midnight turns. In every stream comparison (30 5248 seconds), the difference of the yaw angle of BNC's attitude model ('Computed', see section 'Combination') minus the 5249 yaw angle of the stream is followed continuously over time; the phase wind-up predicts a clock difference of the 5250 stream to an AC following the model of lambda_IF * dpsi / 2pi (lambda_IF: ionosphere-free wavelength of the 5251 reference signals, about 10.7 cm for GPS). A turn starts when the yaw difference changes by more than 20 degrees 5252 against the samples 5 to 15 minutes before, and ends when it is stable again within 2 degrees for 10 minutes. For 5253 each turn, the observed clock change of the stream relative to the consensus is compared with the predicted one: 5254 the changes at the end of the turn, the regression slope of the observed on the predicted changes, and the clock 5255 RMS during the turn without and with the predicted change. A slope between 0.7 and 1.3 with the RMS reduced by 5256 at least half means that the yaw angles in the stream describe the attitude the AC used for its clocks - the 5257 condition for selecting the attitude 'SSR' for this AC in the combination. Turns with a predicted change below 3 5258 cm are not assessed; a clock change of at least 3 cm is then reported as not explained by the yaw difference, 5259 which shows that the other ACs model this turn differently from BNC's model (the check assumes that the consensus 5260 follows it), e.g. 5261 </p> 5262 <pre> 5263 G attitude check G14 09:42:30-10:25:30: yaw difference to the model 362 deg, clock change vs. consensus 8.2 cm, predicted 10.7 cm (max 10.7 cm), slope 0.77, clock RMS 6.1 -> 2.0 cm: SSR yaw consistent with the clocks 5264 G attitude check G25 07:53:00-08:51:30: yaw difference to the model 39 deg, clock change vs. consensus -9.8 cm, predicted -0.0 cm (max 1.2 cm), slope 1.84, clock RMS 5.9 -> 5.8 cm: clock change not explained by the yaw difference (the other ACs model this turn differently?) 5243 5265 </pre> 5244 5266 <p> -
trunk/BNC/src/bncmain.cpp
r11087 r11130 215 215 " ssrQcIntr {SSR QC report interval [character string: 5 min|15 min|30 min|1 hour|1 day]}\n" 216 216 " ssrQcBiasFile {Bias SINEX file (OSB or DSB) as reference for the SSR QC code bias check, full path [character string]}\n" 217 " ssrQcAntexFile {ANTEX file for the SSR QC attitude check (SSR yaw vs. clocks during turns), full path [character string]}\n" 217 218 "\n" 218 219 "Feed Engine Panel keys:\n" -
trunk/BNC/src/bncnetqueryrtp.cpp
r11128 r11130 110 110 111 111 const int timeOut = 5000; 112 const int maxHeaderLines = 100; // of an RTSP answer 112 113 113 114 _status = running; … … 177 178 QByteArray serverPort; 178 179 QString line = in.readLine(); 179 while (!line.isEmpty()) { 180 int nLines = 0; 181 while (!line.isEmpty() && ++nLines <= maxHeaderLines) { 180 182 if (line.indexOf("Session:") == 0) { 181 183 _session = line.mid(9).toLatin1(); … … 226 228 QTextStream in(_socket); 227 229 line = in.readLine(); 228 while (!line.isEmpty()) { 230 nLines = 0; 231 while (!line.isEmpty() && ++nLines <= maxHeaderLines) { 229 232 if (line.indexOf("200 OK") != -1) { 230 233 emit newMessage(_url.toEncoded(QUrl::RemoveUserInfo).replace(0,1,"") -
trunk/BNC/src/bncnetqueryv1.cpp
r11124 r11130 253 253 bool proxyResponse = false; 254 254 QStringList response; 255 const int maxResponseSize = 16384; 256 int responseSize = 0; 255 257 while (true) { 256 258 if (_socket->canReadLine()) { 257 259 QString line = _socket->readLine(); 260 261 // a caster response header is short; do not collect an endless one 262 responseSize += line.size(); 263 if (responseSize > maxResponseSize) { 264 delete _socket; 265 _socket = 0; 266 _status = error; 267 emit newMessage(_url.path().toLatin1().replace(0,1,"") 268 + ": Caster response header too long", true); 269 return; 270 } 258 271 259 272 if (line.indexOf("ICY 200 OK") == -1 && … … 289 302 break; 290 303 } 304 } 305 else if (_socket->bytesAvailable() > maxResponseSize) { // no line end 306 delete _socket; 307 _socket = 0; 308 _status = error; 309 emit newMessage(_url.path().toLatin1().replace(0,1,"") 310 + ": Caster response header too long", true); 311 return; 291 312 } 292 313 else if (!_socket->waitForReadyRead(_timeOut)) { -
trunk/BNC/src/src.pri
r11087 r11130 19 19 20 20 win32:QMAKE_CXXFLAGS += /std:c++17 21 22 # Hardening, independent of the distribution's compiler defaults: stack 23 # protector, bounds checks of the std containers (abort instead of memory 24 # corruption), read-only relocations. _FORTIFY_SOURCE is not set, it requires 25 # optimization, which is switched off above. 26 linux:QMAKE_CXXFLAGS += -fstack-protector-strong -D_GLIBCXX_ASSERTIONS 27 linux:QMAKE_LFLAGS += -Wl,-z,relro,-z,now 21 28 22 29 debug:OBJECTS_DIR=.obj/debug -
trunk/BNC/tests/README.md
r11127 r11130 31 31 | `tools/ssr_harness.sh` | builds `tools/ssr_harness.cpp` with the SSR decoders under ASan/UBSan and runs it | 32 32 | `tools/ssl_check.py` | TLS checks of the Ntrip 2s client and upload (not part of `run_tests.py`) | 33 | `tools/net_check.py` | UDP/RTP sender filter and upload status checks on loopback (not part of `run_tests.py`) | 33 34 | `work/` | scratch output, not versioned | 34 35 … … 100 101 coefficients are C(d,o) = (100*d+o)/200 TECU and S = -C, both `.ssr` files 101 102 are identical apart from the station ID. These frames overflowed the 102 coefficient and name arrays; the 4-layer VTEC crashed BNC. 103 coefficient and name arrays; the 4-layer VTEC crashed BNC. Also two RTCM 104 1033: a complete one and one whose receiver descriptor length runs beyond 105 the message (rejected; before, stale buffer content was logged). 106 107 * `rawfile_hostile`: raw file with hostile chunk headers from 108 `tools/mkcrafted.py --rawfile`: the station ID `../ESCAPE0` must give 109 `Output/.._ESCAPE0_*.ssr` (no file outside the output directory), a chunk 110 header announcing 2000000000 bytes is rejected with a log message. 103 111 104 112 ## Sanitizer check of the SSR decoders … … 115 123 also covers the new RTCM-SSR metadata (message 60 in 116 124 `crafted_limits.raw`: 7 entries with additional parameters of 40 and 0 bits, 117 and 31 entries, which must be rejected), which `RTCM3Decoder.cpp` does not 118 dispatch at present. Every decoded VTEC and metadata message is encoded 119 again with the `Make*` function of the same class and decoded once more; the 120 result must be identical. Exit code 0 only without sanitizer errors and 125 and 31 entries, which must be rejected) and satellite antenna messages 126 (BDS with mask bits in all four 16-bit quarters, GPS with shared blocks), 127 which `RTCM3Decoder.cpp` does not dispatch at present. Every decoded VTEC, metadata and antenna message is 128 encoded again with the `Make*` function of the same class and decoded once 129 more; the result must be identical, for the antenna messages also the bytes. Exit code 0 only without sanitizer errors and 121 130 differences. 122 131 … … 135 144 certificate for another host name (rejected) and a client certificate 136 145 required by the caster, with and without `sslIgnoreErrors`. Takes about 3 min. 146 147 ## Network check 148 149 ``` 150 tests/tools/net_check.py [--bnc PATH] 151 ``` 152 153 Runs BNC live against fake servers on loopback addresses (no root needed). 154 A second sender on another address sends spoofed datagrams to BNC's port: in 155 the modes 'U' (Ntrip 2 UDP) and 'R' (RTSP/RTP) and in 'UN' with a sender 156 address in the URL, BNC's raw output must contain only the server's data; 157 'UN' with 127.0.0.1 accepts any sender, as before. An Ntrip 1 caster sending an endless 158 response header is cut off, a normal Ntrip 1 stream still works. An upload 159 answered with `HTTP/1.1 401` and a header containing `200` must be reported 160 as broken. Takes about 2 min. 137 161 138 162 ## Adding a replay case -
trunk/BNC/tests/tools/bncraw.py
r11127 r11130 197 197 198 198 199 def frame(payload): 200 """RTCM3 frame (preamble, length, payload, CRC24Q) of a payload.""" 201 head = bytes([0xD3, (len(payload) >> 8) & 0x03, len(payload) & 0xFF]) 202 return head + payload + crc24q(head + payload).to_bytes(3, "big") 203 204 199 205 def cmd_slice(args): 200 206 stations = set(args.stations.split(",")) if args.stations else None 207 types = args.types.split(",") if args.types else None 208 parsers = {} 201 209 202 210 def selected(): … … 208 216 if args.end and t >= args.end: 209 217 continue 218 if types: 219 # keep only the RTCM3 messages of the given types (or type prefixes) 220 frames = parsers.setdefault(sta, Rtcm3Framer()).feed(data) 221 kept = b"".join(frame(pl) for pl in frames 222 if any(msg_type(pl).startswith(tt) for tt in types)) 223 if not kept: 224 continue 225 data = kept 210 226 yield t, sta, fmt, data 211 227 … … 245 261 p.add_argument("--end", help="ISO time, exclusive") 246 262 p.add_argument("--stations", help="comma separated staIDs to keep") 263 p.add_argument("--types", help="comma separated RTCM3 message types or prefixes to keep, " 264 "e.g. 1019,4076_02 (GPS ephemerides and IGS-SSR GPS messages)") 247 265 p.set_defaults(func=cmd_slice) 248 266 -
trunk/BNC/tests/tools/fakecaster.py
r11127 r11130 15 15 additionally requires a client certificate signed by that CA. With --serve 16 16 a GET request (BNC as Ntrip client) is answered with the RTCM bytes of the 17 given raw file. Failed TLS handshakes are reported on stdout. 17 given raw file. With --reply an upload is answered with this text instead 18 of the 200 status (e.g. a rejection), and the connection is closed. Failed 19 TLS handshakes are reported on stdout. 18 20 """ 19 21 … … 55 57 self.total = 0 56 58 self.handshakes = 0 59 self.rejected = 0 57 60 self.served = 0 58 61 … … 67 70 68 71 69 def serve(conn, store, timeout, tls=None, served=None): 72 def serve(conn, store, timeout, tls=None, served=None, reply=None): 70 73 conn.settimeout(timeout) 71 74 buf = b"" … … 89 92 b"Content-Type: gnss/data\r\nConnection: close\r\n\r\n" + served) 90 93 store.served += len(served) 94 return 95 if reply is not None: 96 conn.sendall(reply) 97 store.rejected += 1 91 98 return 92 99 if header.startswith(b"SOURCE"): … … 127 134 ap.add_argument("--tls-client-ca", help="require a client certificate of this CA") 128 135 ap.add_argument("--serve", help="raw file whose RTCM bytes are sent on GET") 136 ap.add_argument("--reply", help="answer to uploads instead of 200 ('\\r\\n' escapes allowed)") 129 137 args = ap.parse_args() 130 138 … … 136 144 tls.verify_mode = ssl.CERT_REQUIRED 137 145 tls.load_verify_locations(args.tls_client_ca) 146 reply = None 147 if args.reply is not None: 148 reply = args.reply.encode("latin-1").decode("unicode_escape").encode("latin-1") 138 149 served = None 139 150 if args.serve: … … 155 166 except socket.timeout: 156 167 break 157 t = threading.Thread(target=serve, args=(conn, store, args.timeout, tls, served), 168 t = threading.Thread(target=serve, args=(conn, store, args.timeout, tls, served, reply), 158 169 daemon=True) 159 170 t.start() … … 166 177 if served is not None: 167 178 print("served %d bytes" % store.served, flush=True) 179 if reply is not None: 180 print("%d upload(s) answered with --reply" % store.rejected, flush=True) 168 181 return 0 169 182 -
trunk/BNC/tests/tools/mkcrafted.py
r11125 r11130 6 6 CRAFT0IGS0 IGS-SSR VTEC (4076/201), decoded by SsrCorrIgs, followed by 7 7 RTCM 1300/1301/1302 with 31-character names (BNC's RTCM scan 8 lists them only for streams that also decode successfully) 8 lists them only for streams that also decode successfully); 9 in the first epoch also two RTCM 1033 (antenna and receiver 10 descriptors): a complete one and one whose receiver descriptor 11 length (200) runs beyond the end of the message 9 12 CRAFT0RTC0 RTCM-SSR VTEC (1264), decoded by SsrCorrRtcm 10 13 CRAFT0NEW0 new RTCM-SSR metadata (60), not dispatched by BNC at present; … … 12 15 - 7 entries (maximum), additional parameter of 40 and 0 bits 13 16 - 31 entries (5-bit count, more than META_MAXNUMENTRIES=7) 17 and satellite antenna messages (DF+010-DF+021): 18 - BDS (83): C01, C17, C33, C49, C64 (mask bits in all four 19 16-bit quarters of DF394), individual blocks 20 - GPS (80): G01, G02, G32 sharing one block and one frequency 21 block; nadir angle corrections incl. the invalid value 14 22 15 23 VTEC epochs (every 5 s): … … 22 30 by eye; the heights are 100 km * layer number. 23 31 32 With --rawfile, a raw file with hostile chunk headers is written instead 33 (test of the raw file reader, data/crafted_rawfile.raw): 34 ../ESCAPE0 station ID with a path: RTCM-SSR VTEC whose .ssr file must be 35 written inside the output directory 36 CRAFT0RTC0 RTCM-SSR VTEC, 5 s later 37 then a chunk header announcing 2000000000 bytes, which must be rejected 38 24 39 Usage: mkcrafted.py <out.raw> 40 mkcrafted.py --rawfile <out.raw> 25 41 """ 26 42 … … 140 156 141 157 158 def descriptors(strings, truncate=False): 159 """RTCM 1033: antenna, setup ID, serial, receiver, firmware, serial.""" 160 w = BitWriter() 161 w.u(1033, 12) 162 w.u(0, 12) # reference station ID 163 ant, antser, rec, firm, recser = strings 164 w.text(ant, 8) 165 w.u(0, 8) # antenna setup ID 166 w.text(antser, 8) 167 if truncate: 168 w.u(200, 8) # receiver descriptor length beyond the message 169 for c in rec.encode("ascii"): 170 w.u(c, 8) 171 else: 172 w.text(rec, 8) 173 w.text(firm, 8) 174 w.text(recser, 8) 175 return frame(w.payload()) 176 177 142 178 def metadata(entries): 143 179 """entries: list of None (default model) or number of additional bits.""" … … 163 199 164 200 201 def antenna(msg, sats, shared, nadir): 202 """Satellite antenna message; sats: PRNs (1..64) of the mask.""" 203 w = BitWriter() 204 w.u(msg, 12) 205 w.u(4711, 16) # provider ID 206 w.u(5, 6) # satellite antenna IOD 207 w.u(1, 1) # phase center information 208 w.u(0, 1) # group delay information 209 w.u(1, 1) # nadir angle dependent corrections follow 210 w.u(3, 5) # maximum off-nadir angle: corrections 0..3 deg 211 w.u(1, 4) # range extension: 3 + 1 = 4 bits 212 w.u(shared, 1) # satellite set indicator 213 mask = 0 214 for prn in sats: 215 mask |= 1 << (64 - prn) 216 w.u(mask, 64) 217 for n in range(1 if shared else len(sats)): 218 w.u(shared, 1) # frequency set indicator 219 w.u(0b101000, 6) # frequencies 0 and 2 220 for f in range(1 if shared else 2): 221 w.u(1, 1) # nadir correction follows 222 w.s(100 * n + 10 * f + 1, 12) # mm 223 for deg in range(4): 224 w.s(nadir[(n + f + deg) % len(nadir)], 4) # mm, -8: invalid 225 return frame(w.payload()) 226 227 228 def rawfile(path): 229 chunks = [] 230 for i, sta in enumerate(["../ESCAPE0", "CRAFT0RTC0"]): 231 t = T0 + datetime.timedelta(seconds=5 * i) 232 chunks.append((t.isoformat(), sta, "RTCM_3", vtec_rtcm(t, [(2, 2)]))) 233 write_chunks(path, chunks) 234 t = T0 + datetime.timedelta(seconds=10) 235 with open(path, "ab") as o: 236 o.write(("%s CRAFT0RTC0 RTCM_3 2000000000\n" % t.isoformat()).encode()) 237 o.write(vtec_rtcm(t, [(2, 2)]) + b"\n") 238 239 165 240 def main(): 241 if len(sys.argv) == 3 and sys.argv[1] == "--rawfile": 242 rawfile(sys.argv[2]) 243 return 166 244 if len(sys.argv) != 2: 167 245 sys.exit(__doc__) … … 175 253 t = T0 + datetime.timedelta(seconds=5 * i) 176 254 stamp = t.isoformat() 177 chunks.append((stamp, "CRAFT0IGS0", "RTCM_3", vtec_igs(t, layers) 178 + service_crs() + helmert() + rtcm_crs())) 255 data = vtec_igs(t, layers) + service_crs() + helmert() + rtcm_crs() 256 if i == 0: 257 data += descriptors(["LEIAR25.R4 LEIT", "12345", "SEPT POLARX5", 258 "5.5.0", "3001234"]) 259 data += descriptors(["TRUNCATED ANTENNA", "9", "RECEIVER", "", ""], 260 truncate=True) 261 chunks.append((stamp, "CRAFT0IGS0", "RTCM_3", data)) 179 262 chunks.append((stamp, "CRAFT0RTC0", "RTCM_3", vtec_rtcm(t, layers))) 180 263 stamp = (T0 + datetime.timedelta(seconds=15)).isoformat() 181 264 chunks.append((stamp, "CRAFT0NEW0", "RTCM_3", 182 metadata([40, 0] + [None] * 5) + metadata([None] * 31))) 265 metadata([40, 0] + [None] * 5) + metadata([None] * 31) 266 + antenna(83, [1, 17, 33, 49, 64], 0, [-7, 0, 7, 3]) 267 + antenna(80, [1, 2, 32], 1, [5, -8, -1, 2]))) 183 268 write_chunks(sys.argv[1], chunks) 184 269 -
trunk/BNC/tests/tools/ssr_harness.cpp
r11127 r11130 7 7 // reported by AddressSanitizer instead of silently corrupting the next member. 8 8 // 9 // Every decoded VTEC (all formats) and metadata message (new RTCM-SSR) is 10 // encoded again with the Make* function of the same class and decoded once 11 // more; the result must be identical (exit code 1 otherwise). 9 // Every decoded VTEC (all formats), metadata and satellite antenna message 10 // (new RTCM-SSR) is encoded again with the Make* function of the same class 11 // and decoded once more; the result must be identical, for the antenna 12 // messages also the bytes of the frame (exit code 1 otherwise). 12 13 // 13 14 // Usage: ssr_harness <file> (BNC raw file or plain RTCM3 byte stream) … … 96 97 int irc = t1.decode(ssr, frame, size); 97 98 printf(" %-8s irc %3d", name, irc); 99 SsrCorrRtcmNew* rtcmNew = dynamic_cast<SsrCorrRtcmNew*>(ssr); 98 100 if (irc >= 0 && t1.v->NumLayers) { 99 101 double sum = 0.0; … … 125 127 } 126 128 } 127 SsrCorrRtcmNew* rtcmNew = dynamic_cast<SsrCorrRtcmNew*>(ssr);128 129 if (rtcmNew) { 129 130 char buffer[CLOCKORBIT_BUFFERSIZE]; … … 134 135 nFailed += !ok; 135 136 } 137 } 138 for (unsigned s = 0; rtcmNew && irc >= 0 && s < CLOCKORBIT_SATNUM; s++) { 139 if (!t1.a->SatelliteMask[s]) { 140 continue; 141 } 142 printf(" ANT type %u mask %016llx", t1.a->messageType[s], 143 (unsigned long long)t1.a->SatelliteMask[s]); 144 char buffer[CLOCKORBIT_BUFFERSIZE]; 145 size_t len = rtcmNew->MakeAntenna(t1.a, t1.a->messageType[s], buffer, sizeof(buffer)); 146 t_target t2; 147 bool sameBytes = len == size && memcmp(buffer, frame, size) == 0; 148 bool ok = len > 0 && t2.decode(ssr, (const unsigned char*)buffer, len) >= 0 && 149 memcmp(t1.a, t2.a, sizeof(*t1.a)) == 0; 150 printf(" re-encoded: %s, %s", ok ? "identical" : "DIFFERENT", 151 sameBytes ? "same bytes" : "OTHER BYTES"); 152 nFailed += !ok || !sameBytes; 136 153 } 137 154 printf("\n");
Note:
See TracChangeset
for help on using the changeset viewer.
