gps_pvt 0.1.7 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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(