gps_pvt 0.1.7 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -53,6 +53,7 @@
53
53
  #include <limits>
54
54
 
55
55
  #include "GPS.h"
56
+ #include "SBAS.h"
56
57
 
57
58
  template <class U = void>
58
59
  class RINEX_Reader {
@@ -452,7 +453,6 @@ struct RINEX_NAV {
452
453
  FloatT t_oc_sec;
453
454
  FloatT t_oe_WN;
454
455
  FloatT ura_meter;
455
- FloatT SV_health_f;
456
456
  FloatT t_ot; ///< Transmitting time [s]
457
457
  FloatT fit_interval_hr;
458
458
  FloatT dummy;
@@ -467,7 +467,6 @@ struct RINEX_NAV {
467
467
  t_oc_sec(std::fmod(eph.t_oc, 60)),
468
468
  t_oe_WN(eph.WN),
469
469
  ura_meter(ephemeris_t::URA_meter(eph.URA)),
470
- SV_health_f(((eph.SV_health & 0x20) && (eph.SV_health & 0x1F == 0)) ? 1 : eph.SV_health),
471
470
  t_ot(0), // TODO
472
471
  fit_interval_hr(eph.fit_interval / (60 * 60)),
473
472
  dummy(0) {
@@ -485,17 +484,69 @@ struct RINEX_NAV {
485
484
  * RINEX Value: 0 Health OK
486
485
  * RINEX Value: 1 Health not OK (bits 18-22 not stored)
487
486
  * RINEX Value: >32 Health not OK (bits 18-22 stored)
487
+ * eph.SV_health may have a value greater than 32
488
488
  */
489
- eph.SV_health = (unsigned int)SV_health_f;
490
- if(eph.SV_health > 32){
491
- eph.SV_health &= 0x3F; // 0b111111
492
- }else if(eph.SV_health > 0){
493
- eph.SV_health = 0x20; // 0b100000
494
- }
495
489
 
496
490
  // At least 4 hour validity, then, hours => seconds;
497
491
  eph.fit_interval = ((fit_interval_hr < 4) ? 4 : fit_interval_hr) * 60 * 60;
498
492
  }
493
+ static message_t from_qzss(const ephemeris_t &eph_){
494
+ message_t res(eph_);
495
+ res.eph.svid -= 192;
496
+ res.fit_interval_hr = (res.fit_interval_hr) > 2 ? 1 : 0;
497
+ return res;
498
+ }
499
+ ephemeris_t eph_qzss() const {
500
+ ephemeris_t res(eph);
501
+ res.svid += 192;
502
+ res.fit_interval = ((fit_interval_hr > 0) ? 4 : 2) * 60 * 60;
503
+ return res;
504
+ }
505
+ };
506
+ struct message_sbas_t {
507
+ typedef typename SBAS_SpaceNode<FloatT>
508
+ ::SatelliteProperties::Ephemeris eph_t;
509
+ int svid;
510
+ std::tm date_tm;
511
+ int t_year4, t_year2, t_mon12;
512
+ FloatT t_sec;
513
+ FloatT a_Gf0, a_Gf1;
514
+ FloatT t_t; // Transmission time of message (start of the message) in GPS seconds of the week
515
+ FloatT x_km, dx_km_s, ddx_km_s2;
516
+ FloatT y_km, dy_km_s, ddy_km_s2;
517
+ FloatT z_km, dz_km_s, ddz_km_s2;
518
+ unsigned int health;
519
+ FloatT URA;
520
+ unsigned int iodn;
521
+ message_sbas_t() {}
522
+ message_sbas_t(const eph_t &eph)
523
+ : svid((int)eph.svid - 100),
524
+ date_tm(eph.base_time().c_tm()),
525
+ t_year4(date_tm.tm_year + 1900),
526
+ t_year2(date_tm.tm_year % 100),
527
+ t_mon12(date_tm.tm_mon + 1),
528
+ t_sec(date_tm.tm_sec),
529
+ a_Gf0(eph.a_Gf0), a_Gf1(eph.a_Gf1),
530
+ t_t(eph.t_0), // TODO maybe differ from t_e slightly
531
+ x_km(1E-3 * eph.x), dx_km_s(1E-3 * eph.dx), ddx_km_s2(1E-3 * eph.ddx),
532
+ y_km(1E-3 * eph.y), dy_km_s(1E-3 * eph.dy), ddy_km_s2(1E-3 * eph.ddy),
533
+ z_km(1E-3 * eph.z), dz_km_s(1E-3 * eph.dz), ddz_km_s2(1E-3 * eph.ddz),
534
+ health(0), URA(eph.URA), iodn(0) {
535
+ }
536
+ operator eph_t() const {
537
+ eph_t eph = {0};
538
+ eph.svid = (unsigned int)svid + 100;
539
+ typename space_node_t::gps_time_t t(date_tm);
540
+ t += (t_sec - date_tm.tm_sec);
541
+ eph.WN = t.week;
542
+ eph.t_0 = t.seconds;
543
+ eph.a_Gf0 = a_Gf0; eph.a_Gf1 = a_Gf1;
544
+ eph.x = 1E3 * x_km; eph.dx = 1E3 * dx_km_s; eph.ddx = 1E3 * ddx_km_s2;
545
+ eph.y = 1E3 * y_km; eph.dy = 1E3 * dy_km_s; eph.ddy = 1E3 * ddy_km_s2;
546
+ eph.z = 1E3 * z_km; eph.dz = 1E3 * dz_km_s; eph.ddz = 1E3 * ddz_km_s2;
547
+ eph.URA = URA;
548
+ return eph;
549
+ }
499
550
  };
500
551
  };
501
552
 
@@ -507,6 +558,7 @@ class RINEX_NAV_Reader : public RINEX_Reader<> {
507
558
  public:
508
559
  typedef typename RINEX_NAV<FloatT>::space_node_t space_node_t;
509
560
  typedef typename RINEX_NAV<FloatT>::message_t message_t;
561
+ typedef typename RINEX_NAV<FloatT>::message_sbas_t message_sbas_t;
510
562
  typedef typename space_node_t::Ionospheric_UTC_Parameters iono_utc_t;
511
563
 
512
564
  static const typename super_t::convert_item_t eph0_v2[10], eph0_v3[10];
@@ -518,9 +570,15 @@ class RINEX_NAV_Reader : public RINEX_Reader<> {
518
570
  static const typename super_t::convert_item_t eph6_v2[4], eph6_v3[4];
519
571
  static const typename super_t::convert_item_t eph7_v2[2], eph7_v3[2];
520
572
 
573
+ static const typename super_t::convert_item_t eph0_sbas_v2[10], eph0_sbas_v3[10];
574
+ static const typename super_t::convert_item_t eph1_sbas_v2[4], eph1_sbas_v3[4];
575
+ static const typename super_t::convert_item_t eph2_sbas_v2[4], eph2_sbas_v3[4];
576
+ static const typename super_t::convert_item_t eph3_sbas_v2[4], eph3_sbas_v3[4];
577
+
521
578
  protected:
522
579
  typename super_t::version_type_t::sat_system_t sys_of_msg;
523
580
  message_t msg;
581
+ message_sbas_t msg_sbas;
524
582
 
525
583
  void seek_next_v2_gps() {
526
584
  char buf[256];
@@ -564,10 +622,36 @@ class RINEX_NAV_Reader : public RINEX_Reader<> {
564
622
  super_t::_has_next = true;
565
623
  }
566
624
 
625
+ void seek_next_v2_sbas() {
626
+ char buf[256];
627
+
628
+ for(int i(0); i < 4; i++){
629
+ if((!super_t::src.good())
630
+ || super_t::src.getline(buf, sizeof(buf)).fail()){return;}
631
+ std::string line(buf);
632
+
633
+ switch(i){
634
+ case 0: {
635
+ super_t::convert(eph0_sbas_v2, line, &msg_sbas);
636
+ msg_sbas.date_tm.tm_year = msg_sbas.t_year2 + (msg_sbas.t_year2 < 80 ? 100 : 0); // greater than 1980
637
+ msg_sbas.date_tm.tm_mon = msg_sbas.t_mon12 - 1; // month [0, 11]
638
+ msg_sbas.date_tm.tm_sec = (int)msg_sbas.t_sec;
639
+ break;
640
+ }
641
+ case 1: super_t::convert(eph1_sbas_v2, line, &msg_sbas); break;
642
+ case 2: super_t::convert(eph2_sbas_v2, line, &msg_sbas); break;
643
+ case 3: super_t::convert(eph3_sbas_v2, line, &msg_sbas); break;
644
+ }
645
+ }
646
+ sys_of_msg = super_t::version_type_t::SYS_SBAS;
647
+ super_t::_has_next = true;
648
+ }
649
+
567
650
  void seek_next_v2() {
568
651
  switch(super_t::version_type.sat_system){
569
652
  case super_t::version_type_t::SYS_GPS: seek_next_v2_gps(); return;
570
653
  case super_t::version_type_t::SYS_GLONASS: seek_next_v2_glonass(); return;
654
+ case super_t::version_type_t::SYS_SBAS: seek_next_v2_sbas(); return;
571
655
  default: break;
572
656
  }
573
657
  }
@@ -599,6 +683,35 @@ class RINEX_NAV_Reader : public RINEX_Reader<> {
599
683
  super_t::_has_next = true;
600
684
  }
601
685
 
686
+ template <std::size_t N>
687
+ void seek_next_v3_sbas(char (&buf)[N]) {
688
+ super_t::convert(eph0_sbas_v3, std::string(buf), &msg_sbas);
689
+ msg_sbas.date_tm.tm_year = msg_sbas.t_year4 - 1900; // tm_year base is 1900
690
+ msg_sbas.date_tm.tm_mon = msg_sbas.t_mon12 - 1; // month [0, 11]
691
+ msg_sbas.t_sec = msg_sbas.date_tm.tm_sec;
692
+
693
+ for(int i(1); i < 4; i++){
694
+ if((!super_t::src.good())
695
+ || super_t::src.getline(buf, sizeof(buf)).fail()){return;}
696
+ std::string line(buf);
697
+
698
+ switch(i){
699
+ case 1: super_t::convert(eph1_sbas_v3, line, &msg_sbas); break;
700
+ case 2: super_t::convert(eph2_sbas_v3, line, &msg_sbas); break;
701
+ case 3: super_t::convert(eph3_sbas_v3, line, &msg_sbas); break;
702
+ }
703
+ }
704
+ sys_of_msg = super_t::version_type_t::SYS_SBAS;
705
+ super_t::_has_next = true;
706
+ }
707
+
708
+ template <std::size_t N>
709
+ void seek_next_v3_qzss(char (&buf)[N]) {
710
+ seek_next_v3_gps(buf);
711
+ if(!super_t::_has_next){return;}
712
+ sys_of_msg = super_t::version_type_t::SYS_QZSS;
713
+ }
714
+
602
715
  template <std::size_t N>
603
716
  void seek_next_v3_not_implemented(char (&buf)[N], const int &lines) {
604
717
  for(int i(1); i < lines; i++){
@@ -619,9 +732,9 @@ class RINEX_NAV_Reader : public RINEX_Reader<> {
619
732
  case 'G': seek_next_v3_gps(buf); return; // GPS
620
733
  case 'E': seek_next_v3_not_implemented(buf, 8); return; // Galileo
621
734
  case 'R': seek_next_v3_not_implemented(buf, 4); return; // Glonass
622
- case 'J': seek_next_v3_not_implemented(buf, 8); return; // QZSS
735
+ case 'J': seek_next_v3_qzss(buf); return; // QZSS
623
736
  case 'C': seek_next_v3_not_implemented(buf, 8); return; // Beido
624
- case 'S': seek_next_v3_not_implemented(buf, 4); return; // SBAS
737
+ case 'S': seek_next_v3_sbas(buf); return; // SBAS
625
738
  case 'T': seek_next_v3_not_implemented(buf, 8); return; // IRNSS
626
739
  default: break;
627
740
  }
@@ -659,19 +772,19 @@ class RINEX_NAV_Reader : public RINEX_Reader<> {
659
772
  bool alpha, beta, utc, leap;
660
773
  super_t::header_t::const_iterator it;
661
774
 
662
- if(alpha = ((it = _header.find("ION ALPHA")) != _header.end())){
775
+ if((alpha = ((it = _header.find("ION ALPHA")) != _header.end()))){
663
776
  super_t::convert(iono_alpha_v2, it->second.front(), &iono_utc);
664
777
  }
665
778
 
666
- if(beta = ((it = _header.find("ION BETA")) != _header.end())){
779
+ if((beta = ((it = _header.find("ION BETA")) != _header.end()))){
667
780
  super_t::convert(iono_beta_v2, it->second.front(), &iono_utc);
668
781
  }
669
782
 
670
- if(utc = ((it = _header.find("DELTA-UTC: A0,A1,T,W")) != _header.end())){
783
+ if((utc = ((it = _header.find("DELTA-UTC: A0,A1,T,W")) != _header.end()))){
671
784
  super_t::convert(utc_v2, it->second.front(), &iono_utc);
672
785
  }
673
786
 
674
- if(leap = ((it = _header.find("LEAP SECONDS")) != _header.end())){
787
+ if((leap = ((it = _header.find("LEAP SECONDS")) != _header.end()))){
675
788
  super_t::convert(utc_leap_v2, it->second.front(), &iono_utc);
676
789
  }
677
790
 
@@ -728,6 +841,8 @@ class RINEX_NAV_Reader : public RINEX_Reader<> {
728
841
 
729
842
  struct space_node_list_t {
730
843
  space_node_t *gps;
844
+ SBAS_SpaceNode<FloatT> *sbas;
845
+ space_node_t *qzss;
731
846
  };
732
847
 
733
848
  static int read_all(std::istream &in, space_node_list_t &space_nodes = {0}){
@@ -738,6 +853,10 @@ class RINEX_NAV_Reader : public RINEX_Reader<> {
738
853
  ? reader.extract_iono_utc_v3(*space_nodes.gps)
739
854
  : reader.extract_iono_utc_v2(*space_nodes.gps);
740
855
  }
856
+ if(space_nodes.qzss && (space_nodes.gps != space_nodes.qzss)
857
+ && (reader.version_type.version >= 302)){
858
+ reader.extract_iono_utc_v3(*space_nodes.qzss);
859
+ }
741
860
  res++;
742
861
  for(; reader.has_next(); reader.next()){
743
862
  switch(reader.sys_of_msg){
@@ -746,6 +865,20 @@ class RINEX_NAV_Reader : public RINEX_Reader<> {
746
865
  space_nodes.gps->satellite(reader.msg.eph.svid).register_ephemeris(reader.msg.eph);
747
866
  res++;
748
867
  break;
868
+ case super_t::version_type_t::SYS_SBAS: {
869
+ if(!space_nodes.sbas){break;}
870
+ typename message_sbas_t::eph_t eph(reader.msg_sbas);
871
+ space_nodes.sbas->satellite(eph.svid).register_ephemeris(eph);
872
+ res++;
873
+ break;
874
+ }
875
+ case super_t::version_type_t::SYS_QZSS: {
876
+ if(!space_nodes.qzss){break;}
877
+ typename RINEX_NAV<FloatT>::ephemeris_t eph(reader.msg.eph_qzss());
878
+ space_nodes.qzss->satellite(eph.svid).register_ephemeris(eph);
879
+ res++;
880
+ break;
881
+ }
749
882
  default: break;
750
883
  }
751
884
  }
@@ -1190,14 +1323,14 @@ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>
1190
1323
  template <class FloatT>
1191
1324
  const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph6_v2[] = {
1192
1325
  GEN_E ( 3, 19, 12, message_t, ura_meter),
1193
- GEN_E (22, 19, 12, message_t, SV_health_f),
1326
+ GEN_E2(22, 19, 12, message_t, eph.SV_health, unsigned int),
1194
1327
  GEN_E (41, 19, 12, message_t, eph.t_GD),
1195
1328
  GEN_E2(60, 19, 12, message_t, eph.iodc, int),
1196
1329
  };
1197
1330
  template <class FloatT>
1198
1331
  const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph6_v3[] = {
1199
1332
  GEN_E ( 4, 19, 12, message_t, ura_meter),
1200
- GEN_E (23, 19, 12, message_t, SV_health_f),
1333
+ GEN_E2(23, 19, 12, message_t, eph.SV_health, unsigned int),
1201
1334
  GEN_E (42, 19, 12, message_t, eph.t_GD),
1202
1335
  GEN_E2(61, 19, 12, message_t, eph.iodc, int),
1203
1336
  };
@@ -1213,6 +1346,80 @@ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>
1213
1346
  GEN_E(23, 19, 12, message_t, fit_interval_hr),
1214
1347
  };
1215
1348
 
1349
+
1350
+ template <class FloatT>
1351
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph0_sbas_v2[] = {
1352
+ GEN_D( 0, 2, message_sbas_t, svid, int),
1353
+ GEN_D( 3, 2, message_sbas_t, t_year2, int),
1354
+ GEN_D( 6, 2, message_sbas_t, t_mon12, int),
1355
+ GEN_D( 9, 2, message_sbas_t, date_tm.tm_mday, int),
1356
+ GEN_D(12, 2, message_sbas_t, date_tm.tm_hour, int),
1357
+ GEN_D(15, 2, message_sbas_t, date_tm.tm_min, int),
1358
+ GEN_F(17, 5, 1, message_sbas_t, t_sec),
1359
+ GEN_E(22, 19, 12, message_sbas_t, a_Gf0),
1360
+ GEN_E(41, 19, 12, message_sbas_t, a_Gf1),
1361
+ GEN_E(60, 19, 12, message_sbas_t, t_t),
1362
+ };
1363
+ template <class FloatT>
1364
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph0_sbas_v3[] = {
1365
+ GEN_I( 1, 2, message_sbas_t, svid, int),
1366
+ GEN_I( 4, 4, message_sbas_t, t_year4, int),
1367
+ GEN_I( 9, 2, message_sbas_t, t_mon12, int),
1368
+ GEN_I(12, 2, message_sbas_t, date_tm.tm_mday, int),
1369
+ GEN_I(15, 2, message_sbas_t, date_tm.tm_hour, int),
1370
+ GEN_I(18, 2, message_sbas_t, date_tm.tm_min, int),
1371
+ GEN_I(21, 2, message_sbas_t, date_tm.tm_sec, int),
1372
+ GEN_E(23, 19, 12, message_sbas_t, a_Gf0),
1373
+ GEN_E(42, 19, 12, message_sbas_t, a_Gf1),
1374
+ GEN_E(61, 19, 12, message_sbas_t, t_t),
1375
+ };
1376
+
1377
+ template <class FloatT>
1378
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph1_sbas_v2[] = {
1379
+ GEN_E( 3, 19, 12, message_sbas_t, x_km),
1380
+ GEN_E(22, 19, 12, message_sbas_t, dx_km_s),
1381
+ GEN_E(41, 19, 12, message_sbas_t, ddx_km_s2),
1382
+ GEN_E2(60, 19, 12, message_sbas_t, health, unsigned int),
1383
+ };
1384
+ template <class FloatT>
1385
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph1_sbas_v3[] = {
1386
+ GEN_E( 4, 19, 12, message_sbas_t, x_km),
1387
+ GEN_E(23, 19, 12, message_sbas_t, dx_km_s),
1388
+ GEN_E(42, 19, 12, message_sbas_t, ddx_km_s2),
1389
+ GEN_E2(61, 19, 12, message_sbas_t, health, unsigned int),
1390
+ };
1391
+
1392
+ template <class FloatT>
1393
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph2_sbas_v2[] = {
1394
+ GEN_E( 3, 19, 12, message_sbas_t, y_km),
1395
+ GEN_E(22, 19, 12, message_sbas_t, dy_km_s),
1396
+ GEN_E(41, 19, 12, message_sbas_t, ddy_km_s2),
1397
+ GEN_E(60, 19, 12, message_sbas_t, URA),
1398
+ };
1399
+ template <class FloatT>
1400
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph2_sbas_v3[] = {
1401
+ GEN_E( 4, 19, 12, message_sbas_t, y_km),
1402
+ GEN_E(23, 19, 12, message_sbas_t, dy_km_s),
1403
+ GEN_E(42, 19, 12, message_sbas_t, ddy_km_s2),
1404
+ GEN_E(61, 19, 12, message_sbas_t, URA),
1405
+ };
1406
+
1407
+ template <class FloatT>
1408
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph3_sbas_v2[] = {
1409
+ GEN_E( 3, 19, 12, message_sbas_t, z_km),
1410
+ GEN_E(22, 19, 12, message_sbas_t, dz_km_s),
1411
+ GEN_E(41, 19, 12, message_sbas_t, ddz_km_s2),
1412
+ GEN_E2(60, 19, 12, message_sbas_t, iodn, unsigned int),
1413
+ };
1414
+ template <class FloatT>
1415
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph3_sbas_v3[] = {
1416
+ GEN_E( 4, 19, 12, message_sbas_t, z_km),
1417
+ GEN_E(23, 19, 12, message_sbas_t, dz_km_s),
1418
+ GEN_E(42, 19, 12, message_sbas_t, ddz_km_s2),
1419
+ GEN_E2(61, 19, 12, message_sbas_t, iodn, unsigned int),
1420
+ };
1421
+
1422
+
1216
1423
  template <class FloatT>
1217
1424
  const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::iono_alpha_v2[] = {
1218
1425
  GEN_E( 2, 12, 4, iono_utc_t, alpha[0]),
@@ -1511,6 +1718,7 @@ class RINEX_NAV_Writer : public RINEX_Writer<> {
1511
1718
  public:
1512
1719
  typedef typename RINEX_NAV<FloatT>::space_node_t space_node_t;
1513
1720
  typedef typename RINEX_NAV<FloatT>::message_t message_t;
1721
+ typedef typename RINEX_NAV<FloatT>::message_sbas_t message_sbas_t;
1514
1722
 
1515
1723
  static const typename super_t::header_item_t default_header[];
1516
1724
  static const int default_header_size;
@@ -1569,7 +1777,7 @@ class RINEX_NAV_Writer : public RINEX_Writer<> {
1569
1777
  : super_t(out, default_header, default_header_size) {}
1570
1778
  ~RINEX_NAV_Writer(){}
1571
1779
 
1572
- self_t &operator<<(const message_t &msg){
1780
+ self_t &dump(const message_t &msg, const bool &is_qzss = false){
1573
1781
  std::stringstream buf;
1574
1782
  switch(super_t::_version_type.version / 100){
1575
1783
  case 2:
@@ -1592,7 +1800,8 @@ class RINEX_NAV_Writer : public RINEX_Writer<> {
1592
1800
  for(int i(0); i < 8; ++i){
1593
1801
  std::string s(80, ' ');
1594
1802
  switch(i){
1595
- case 0: super_t::convert(reader_t::eph0_v3, s, &msg); s[0] = 'G'; break;
1803
+ case 0: super_t::convert(reader_t::eph0_v3, s, &msg);
1804
+ s[0] = is_qzss ? 'J' : 'G'; break;
1596
1805
  case 1: super_t::convert(reader_t::eph1_v3, s, &msg); break;
1597
1806
  case 2: super_t::convert(reader_t::eph2_v3, s, &msg); break;
1598
1807
  case 3: super_t::convert(reader_t::eph3_v3, s, &msg); break;
@@ -1608,6 +1817,40 @@ class RINEX_NAV_Writer : public RINEX_Writer<> {
1608
1817
  dist << buf.str();
1609
1818
  return *this;
1610
1819
  }
1820
+ self_t &operator<<(const message_t &msg){
1821
+ return dump(msg);
1822
+ }
1823
+ self_t &operator<<(const message_sbas_t &msg){
1824
+ std::stringstream buf;
1825
+ switch(super_t::_version_type.version / 100){
1826
+ case 2:
1827
+ for(int i(0); i < 8; ++i){
1828
+ std::string s(80, ' ');
1829
+ switch(i){
1830
+ case 0: super_t::convert(reader_t::eph0_sbas_v2, s, &msg); break;
1831
+ case 1: super_t::convert(reader_t::eph1_sbas_v2, s, &msg); break;
1832
+ case 2: super_t::convert(reader_t::eph2_sbas_v2, s, &msg); break;
1833
+ case 3: super_t::convert(reader_t::eph3_sbas_v2, s, &msg); break;
1834
+ }
1835
+ buf << s << std::endl;
1836
+ }
1837
+ break;
1838
+ case 3:
1839
+ for(int i(0); i < 8; ++i){
1840
+ std::string s(80, ' ');
1841
+ switch(i){
1842
+ case 0: super_t::convert(reader_t::eph0_sbas_v3, s, &msg); s[0] = 'S'; break;
1843
+ case 1: super_t::convert(reader_t::eph1_sbas_v3, s, &msg); break;
1844
+ case 2: super_t::convert(reader_t::eph2_sbas_v3, s, &msg); break;
1845
+ case 3: super_t::convert(reader_t::eph3_sbas_v3, s, &msg); break;
1846
+ }
1847
+ buf << s << std::endl;
1848
+ }
1849
+ break;
1850
+ }
1851
+ dist << buf.str();
1852
+ return *this;
1853
+ }
1611
1854
 
1612
1855
  public:
1613
1856
  void set_version(
@@ -1623,9 +1866,11 @@ class RINEX_NAV_Writer : public RINEX_Writer<> {
1623
1866
  int res(-1);
1624
1867
  int systems(0);
1625
1868
  set_version(version, super_t::version_type_t::SYS_UNKNOWN);
1626
- if(space_nodes.gps && space_nodes.gps->is_valid_iono_utc()){
1869
+ do{
1870
+ if(!space_nodes.gps){break;}
1627
1871
  ++systems;
1628
1872
  set_version(version, super_t::version_type_t::SYS_GPS);
1873
+ if(!space_nodes.gps->is_valid_iono_utc()){break;}
1629
1874
  switch(version / 100){
1630
1875
  case 2:
1631
1876
  if(_header["ION ALPHA"].entries() == 0){iono_alpha(*space_nodes.gps);}
@@ -1640,7 +1885,26 @@ class RINEX_NAV_Writer : public RINEX_Writer<> {
1640
1885
  if(_header["LEAP SECONDS"].entries() == 0){leap_seconds(*space_nodes.gps);}
1641
1886
  break;
1642
1887
  }
1643
- }
1888
+ }while(false);
1889
+ do{
1890
+ if(!space_nodes.sbas){break;}
1891
+ ++systems;
1892
+ set_version(version, super_t::version_type_t::SYS_SBAS);
1893
+ }while(false);
1894
+ do{
1895
+ if((version < 302) || (!space_nodes.qzss)){break;}
1896
+ ++systems;
1897
+ set_version(version, super_t::version_type_t::SYS_QZSS);
1898
+ if(!space_nodes.qzss->is_valid_iono_utc()){break;}
1899
+ switch(version / 100){
1900
+ case 3:
1901
+ if(_header["IONOSPHERIC CORR"].find("GPSA") == _header.end()){iono_alpha(*space_nodes.qzss);}
1902
+ if(_header["IONOSPHERIC CORR"].find("GPSB") == _header.end()){iono_beta(*space_nodes.qzss);}
1903
+ if(_header["TIME SYSTEM CORR"].find("QZUT") == _header.end()){utc_params(*space_nodes.qzss);}
1904
+ if(_header["LEAP SECONDS"].entries() == 0){leap_seconds(*space_nodes.qzss);}
1905
+ break;
1906
+ }
1907
+ }while(false);
1644
1908
  if(systems > 1){
1645
1909
  set_version(version, super_t::version_type_t::SYS_MIXED);
1646
1910
  }
@@ -1650,12 +1914,25 @@ class RINEX_NAV_Writer : public RINEX_Writer<> {
1650
1914
  struct {
1651
1915
  RINEX_NAV_Writer &w;
1652
1916
  int &counter;
1917
+ bool gps, qzss;
1653
1918
  void operator()(const typename space_node_t::Satellite::Ephemeris &eph) {
1654
- w << message_t(eph);
1919
+ if(gps && (eph.svid <= 32)){
1920
+ w << message_t(eph);
1921
+ }else if(qzss && (eph.svid >= 193) && (eph.svid < 202)){
1922
+ w.dump(message_t::from_qzss(eph), true);
1923
+ }else{
1924
+ return;
1925
+ }
1655
1926
  counter++;
1656
1927
  }
1657
- } functor = {*this, res};
1928
+ void operator()(const typename message_sbas_t::eph_t &eph) {
1929
+ w << message_sbas_t(eph);
1930
+ counter++;
1931
+ }
1932
+ } functor = {*this, res, false, false};
1658
1933
  if(space_nodes.gps){
1934
+ functor.gps = true;
1935
+ if(space_nodes.gps == space_nodes.qzss){functor.qzss = true;}
1659
1936
  for(typename space_node_t::satellites_t::const_iterator
1660
1937
  it(space_nodes.gps->satellites().begin()), it_end(space_nodes.gps->satellites().end());
1661
1938
  it != it_end; ++it){
@@ -1664,6 +1941,27 @@ class RINEX_NAV_Writer : public RINEX_Writer<> {
1664
1941
  space_node_t::Satellite::eph_list_t::EACH_ALL_INVERTED);
1665
1942
  }
1666
1943
  }
1944
+ if(space_nodes.sbas){
1945
+ for(typename SBAS_SpaceNode<FloatT>::satellites_t::const_iterator
1946
+ it(space_nodes.sbas->satellites().begin()),
1947
+ it_end(space_nodes.sbas->satellites().end());
1948
+ it != it_end; ++it){
1949
+ it->second.each_ephemeris(
1950
+ functor,
1951
+ SBAS_SpaceNode<FloatT>::Satellite::eph_list_t::EACH_ALL_INVERTED);
1952
+ }
1953
+ }
1954
+ if((version >= 302) && (!functor.qzss) && (space_nodes.qzss)){
1955
+ functor.qzss = true;
1956
+ functor.gps = false;
1957
+ for(typename space_node_t::satellites_t::const_iterator
1958
+ it(space_nodes.qzss->satellites().begin()), it_end(space_nodes.qzss->satellites().end());
1959
+ it != it_end; ++it){
1960
+ it->second.each_ephemeris(
1961
+ functor,
1962
+ space_node_t::Satellite::eph_list_t::EACH_ALL_INVERTED);
1963
+ }
1964
+ }
1667
1965
  return res;
1668
1966
  }
1669
1967
  static int write_all(