gps_pvt 0.1.7 → 0.2.3

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,17 +841,25 @@ 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}){
734
- int res(-1);
735
849
  RINEX_NAV_Reader reader(in);
850
+ if(reader.version_type.file_type != version_type_t::FTYPE_NAVIGATION){
851
+ return -1;
852
+ }
736
853
  if(space_nodes.gps){
737
854
  (reader.version_type.version >= 300)
738
855
  ? reader.extract_iono_utc_v3(*space_nodes.gps)
739
856
  : reader.extract_iono_utc_v2(*space_nodes.gps);
740
857
  }
741
- res++;
858
+ if(space_nodes.qzss && (space_nodes.gps != space_nodes.qzss)
859
+ && (reader.version_type.version >= 302)){
860
+ reader.extract_iono_utc_v3(*space_nodes.qzss);
861
+ }
862
+ int res(0);
742
863
  for(; reader.has_next(); reader.next()){
743
864
  switch(reader.sys_of_msg){
744
865
  case super_t::version_type_t::SYS_GPS:
@@ -746,6 +867,20 @@ class RINEX_NAV_Reader : public RINEX_Reader<> {
746
867
  space_nodes.gps->satellite(reader.msg.eph.svid).register_ephemeris(reader.msg.eph);
747
868
  res++;
748
869
  break;
870
+ case super_t::version_type_t::SYS_SBAS: {
871
+ if(!space_nodes.sbas){break;}
872
+ typename message_sbas_t::eph_t eph(reader.msg_sbas);
873
+ space_nodes.sbas->satellite(eph.svid).register_ephemeris(eph);
874
+ res++;
875
+ break;
876
+ }
877
+ case super_t::version_type_t::SYS_QZSS: {
878
+ if(!space_nodes.qzss){break;}
879
+ typename RINEX_NAV<FloatT>::ephemeris_t eph(reader.msg.eph_qzss());
880
+ space_nodes.qzss->satellite(eph.svid).register_ephemeris(eph);
881
+ res++;
882
+ break;
883
+ }
749
884
  default: break;
750
885
  }
751
886
  }
@@ -1007,6 +1142,9 @@ class RINEX_OBS_Reader : public RINEX_Reader<> {
1007
1142
  RINEX_OBS_Reader(std::istream &in)
1008
1143
  : super_t(in, self_t::modify_header),
1009
1144
  obs_types() {
1145
+ if(super_t::version_type.file_type != version_type_t::FTYPE_OBSERVATION){
1146
+ return;
1147
+ }
1010
1148
  typedef super_t::header_t::const_iterator it_t;
1011
1149
  typedef super_t::header_t::mapped_type::const_iterator it2_t;
1012
1150
  it_t it;
@@ -1190,14 +1328,14 @@ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>
1190
1328
  template <class FloatT>
1191
1329
  const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph6_v2[] = {
1192
1330
  GEN_E ( 3, 19, 12, message_t, ura_meter),
1193
- GEN_E (22, 19, 12, message_t, SV_health_f),
1331
+ GEN_E2(22, 19, 12, message_t, eph.SV_health, unsigned int),
1194
1332
  GEN_E (41, 19, 12, message_t, eph.t_GD),
1195
1333
  GEN_E2(60, 19, 12, message_t, eph.iodc, int),
1196
1334
  };
1197
1335
  template <class FloatT>
1198
1336
  const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph6_v3[] = {
1199
1337
  GEN_E ( 4, 19, 12, message_t, ura_meter),
1200
- GEN_E (23, 19, 12, message_t, SV_health_f),
1338
+ GEN_E2(23, 19, 12, message_t, eph.SV_health, unsigned int),
1201
1339
  GEN_E (42, 19, 12, message_t, eph.t_GD),
1202
1340
  GEN_E2(61, 19, 12, message_t, eph.iodc, int),
1203
1341
  };
@@ -1213,6 +1351,80 @@ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>
1213
1351
  GEN_E(23, 19, 12, message_t, fit_interval_hr),
1214
1352
  };
1215
1353
 
1354
+
1355
+ template <class FloatT>
1356
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph0_sbas_v2[] = {
1357
+ GEN_D( 0, 2, message_sbas_t, svid, int),
1358
+ GEN_D( 3, 2, message_sbas_t, t_year2, int),
1359
+ GEN_D( 6, 2, message_sbas_t, t_mon12, int),
1360
+ GEN_D( 9, 2, message_sbas_t, date_tm.tm_mday, int),
1361
+ GEN_D(12, 2, message_sbas_t, date_tm.tm_hour, int),
1362
+ GEN_D(15, 2, message_sbas_t, date_tm.tm_min, int),
1363
+ GEN_F(17, 5, 1, message_sbas_t, t_sec),
1364
+ GEN_E(22, 19, 12, message_sbas_t, a_Gf0),
1365
+ GEN_E(41, 19, 12, message_sbas_t, a_Gf1),
1366
+ GEN_E(60, 19, 12, message_sbas_t, t_t),
1367
+ };
1368
+ template <class FloatT>
1369
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph0_sbas_v3[] = {
1370
+ GEN_I( 1, 2, message_sbas_t, svid, int),
1371
+ GEN_I( 4, 4, message_sbas_t, t_year4, int),
1372
+ GEN_I( 9, 2, message_sbas_t, t_mon12, int),
1373
+ GEN_I(12, 2, message_sbas_t, date_tm.tm_mday, int),
1374
+ GEN_I(15, 2, message_sbas_t, date_tm.tm_hour, int),
1375
+ GEN_I(18, 2, message_sbas_t, date_tm.tm_min, int),
1376
+ GEN_I(21, 2, message_sbas_t, date_tm.tm_sec, int),
1377
+ GEN_E(23, 19, 12, message_sbas_t, a_Gf0),
1378
+ GEN_E(42, 19, 12, message_sbas_t, a_Gf1),
1379
+ GEN_E(61, 19, 12, message_sbas_t, t_t),
1380
+ };
1381
+
1382
+ template <class FloatT>
1383
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph1_sbas_v2[] = {
1384
+ GEN_E( 3, 19, 12, message_sbas_t, x_km),
1385
+ GEN_E(22, 19, 12, message_sbas_t, dx_km_s),
1386
+ GEN_E(41, 19, 12, message_sbas_t, ddx_km_s2),
1387
+ GEN_E2(60, 19, 12, message_sbas_t, health, unsigned int),
1388
+ };
1389
+ template <class FloatT>
1390
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph1_sbas_v3[] = {
1391
+ GEN_E( 4, 19, 12, message_sbas_t, x_km),
1392
+ GEN_E(23, 19, 12, message_sbas_t, dx_km_s),
1393
+ GEN_E(42, 19, 12, message_sbas_t, ddx_km_s2),
1394
+ GEN_E2(61, 19, 12, message_sbas_t, health, unsigned int),
1395
+ };
1396
+
1397
+ template <class FloatT>
1398
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph2_sbas_v2[] = {
1399
+ GEN_E( 3, 19, 12, message_sbas_t, y_km),
1400
+ GEN_E(22, 19, 12, message_sbas_t, dy_km_s),
1401
+ GEN_E(41, 19, 12, message_sbas_t, ddy_km_s2),
1402
+ GEN_E(60, 19, 12, message_sbas_t, URA),
1403
+ };
1404
+ template <class FloatT>
1405
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph2_sbas_v3[] = {
1406
+ GEN_E( 4, 19, 12, message_sbas_t, y_km),
1407
+ GEN_E(23, 19, 12, message_sbas_t, dy_km_s),
1408
+ GEN_E(42, 19, 12, message_sbas_t, ddy_km_s2),
1409
+ GEN_E(61, 19, 12, message_sbas_t, URA),
1410
+ };
1411
+
1412
+ template <class FloatT>
1413
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph3_sbas_v2[] = {
1414
+ GEN_E( 3, 19, 12, message_sbas_t, z_km),
1415
+ GEN_E(22, 19, 12, message_sbas_t, dz_km_s),
1416
+ GEN_E(41, 19, 12, message_sbas_t, ddz_km_s2),
1417
+ GEN_E2(60, 19, 12, message_sbas_t, iodn, unsigned int),
1418
+ };
1419
+ template <class FloatT>
1420
+ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph3_sbas_v3[] = {
1421
+ GEN_E( 4, 19, 12, message_sbas_t, z_km),
1422
+ GEN_E(23, 19, 12, message_sbas_t, dz_km_s),
1423
+ GEN_E(42, 19, 12, message_sbas_t, ddz_km_s2),
1424
+ GEN_E2(61, 19, 12, message_sbas_t, iodn, unsigned int),
1425
+ };
1426
+
1427
+
1216
1428
  template <class FloatT>
1217
1429
  const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::iono_alpha_v2[] = {
1218
1430
  GEN_E( 2, 12, 4, iono_utc_t, alpha[0]),
@@ -1511,6 +1723,7 @@ class RINEX_NAV_Writer : public RINEX_Writer<> {
1511
1723
  public:
1512
1724
  typedef typename RINEX_NAV<FloatT>::space_node_t space_node_t;
1513
1725
  typedef typename RINEX_NAV<FloatT>::message_t message_t;
1726
+ typedef typename RINEX_NAV<FloatT>::message_sbas_t message_sbas_t;
1514
1727
 
1515
1728
  static const typename super_t::header_item_t default_header[];
1516
1729
  static const int default_header_size;
@@ -1569,7 +1782,7 @@ class RINEX_NAV_Writer : public RINEX_Writer<> {
1569
1782
  : super_t(out, default_header, default_header_size) {}
1570
1783
  ~RINEX_NAV_Writer(){}
1571
1784
 
1572
- self_t &operator<<(const message_t &msg){
1785
+ self_t &dump(const message_t &msg, const bool &is_qzss = false){
1573
1786
  std::stringstream buf;
1574
1787
  switch(super_t::_version_type.version / 100){
1575
1788
  case 2:
@@ -1592,7 +1805,8 @@ class RINEX_NAV_Writer : public RINEX_Writer<> {
1592
1805
  for(int i(0); i < 8; ++i){
1593
1806
  std::string s(80, ' ');
1594
1807
  switch(i){
1595
- case 0: super_t::convert(reader_t::eph0_v3, s, &msg); s[0] = 'G'; break;
1808
+ case 0: super_t::convert(reader_t::eph0_v3, s, &msg);
1809
+ s[0] = is_qzss ? 'J' : 'G'; break;
1596
1810
  case 1: super_t::convert(reader_t::eph1_v3, s, &msg); break;
1597
1811
  case 2: super_t::convert(reader_t::eph2_v3, s, &msg); break;
1598
1812
  case 3: super_t::convert(reader_t::eph3_v3, s, &msg); break;
@@ -1608,6 +1822,40 @@ class RINEX_NAV_Writer : public RINEX_Writer<> {
1608
1822
  dist << buf.str();
1609
1823
  return *this;
1610
1824
  }
1825
+ self_t &operator<<(const message_t &msg){
1826
+ return dump(msg);
1827
+ }
1828
+ self_t &operator<<(const message_sbas_t &msg){
1829
+ std::stringstream buf;
1830
+ switch(super_t::_version_type.version / 100){
1831
+ case 2:
1832
+ for(int i(0); i < 8; ++i){
1833
+ std::string s(80, ' ');
1834
+ switch(i){
1835
+ case 0: super_t::convert(reader_t::eph0_sbas_v2, s, &msg); break;
1836
+ case 1: super_t::convert(reader_t::eph1_sbas_v2, s, &msg); break;
1837
+ case 2: super_t::convert(reader_t::eph2_sbas_v2, s, &msg); break;
1838
+ case 3: super_t::convert(reader_t::eph3_sbas_v2, s, &msg); break;
1839
+ }
1840
+ buf << s << std::endl;
1841
+ }
1842
+ break;
1843
+ case 3:
1844
+ for(int i(0); i < 8; ++i){
1845
+ std::string s(80, ' ');
1846
+ switch(i){
1847
+ case 0: super_t::convert(reader_t::eph0_sbas_v3, s, &msg); s[0] = 'S'; break;
1848
+ case 1: super_t::convert(reader_t::eph1_sbas_v3, s, &msg); break;
1849
+ case 2: super_t::convert(reader_t::eph2_sbas_v3, s, &msg); break;
1850
+ case 3: super_t::convert(reader_t::eph3_sbas_v3, s, &msg); break;
1851
+ }
1852
+ buf << s << std::endl;
1853
+ }
1854
+ break;
1855
+ }
1856
+ dist << buf.str();
1857
+ return *this;
1858
+ }
1611
1859
 
1612
1860
  public:
1613
1861
  void set_version(
@@ -1617,15 +1865,22 @@ class RINEX_NAV_Writer : public RINEX_Writer<> {
1617
1865
  version, super_t::version_type_t::FTYPE_NAVIGATION, sys));
1618
1866
  }
1619
1867
 
1868
+ struct space_node_list_t {
1869
+ const space_node_t *gps;
1870
+ const SBAS_SpaceNode<FloatT> *sbas;
1871
+ const space_node_t *qzss;
1872
+ };
1620
1873
  int write_all(
1621
- const typename reader_t::space_node_list_t &space_nodes,
1874
+ const space_node_list_t &space_nodes,
1622
1875
  const int &version = 304){
1623
1876
  int res(-1);
1624
1877
  int systems(0);
1625
1878
  set_version(version, super_t::version_type_t::SYS_UNKNOWN);
1626
- if(space_nodes.gps && space_nodes.gps->is_valid_iono_utc()){
1879
+ do{
1880
+ if(!space_nodes.gps){break;}
1627
1881
  ++systems;
1628
1882
  set_version(version, super_t::version_type_t::SYS_GPS);
1883
+ if(!space_nodes.gps->is_valid_iono_utc()){break;}
1629
1884
  switch(version / 100){
1630
1885
  case 2:
1631
1886
  if(_header["ION ALPHA"].entries() == 0){iono_alpha(*space_nodes.gps);}
@@ -1640,7 +1895,26 @@ class RINEX_NAV_Writer : public RINEX_Writer<> {
1640
1895
  if(_header["LEAP SECONDS"].entries() == 0){leap_seconds(*space_nodes.gps);}
1641
1896
  break;
1642
1897
  }
1643
- }
1898
+ }while(false);
1899
+ do{
1900
+ if(!space_nodes.sbas){break;}
1901
+ ++systems;
1902
+ set_version(version, super_t::version_type_t::SYS_SBAS);
1903
+ }while(false);
1904
+ do{
1905
+ if((version < 302) || (!space_nodes.qzss)){break;}
1906
+ ++systems;
1907
+ set_version(version, super_t::version_type_t::SYS_QZSS);
1908
+ if(!space_nodes.qzss->is_valid_iono_utc()){break;}
1909
+ switch(version / 100){
1910
+ case 3:
1911
+ if(_header["IONOSPHERIC CORR"].find("GPSA") == _header.end()){iono_alpha(*space_nodes.qzss);}
1912
+ if(_header["IONOSPHERIC CORR"].find("GPSB") == _header.end()){iono_beta(*space_nodes.qzss);}
1913
+ if(_header["TIME SYSTEM CORR"].find("QZUT") == _header.end()){utc_params(*space_nodes.qzss);}
1914
+ if(_header["LEAP SECONDS"].entries() == 0){leap_seconds(*space_nodes.qzss);}
1915
+ break;
1916
+ }
1917
+ }while(false);
1644
1918
  if(systems > 1){
1645
1919
  set_version(version, super_t::version_type_t::SYS_MIXED);
1646
1920
  }
@@ -1650,12 +1924,25 @@ class RINEX_NAV_Writer : public RINEX_Writer<> {
1650
1924
  struct {
1651
1925
  RINEX_NAV_Writer &w;
1652
1926
  int &counter;
1927
+ bool gps, qzss;
1653
1928
  void operator()(const typename space_node_t::Satellite::Ephemeris &eph) {
1654
- w << message_t(eph);
1929
+ if(gps && (eph.svid <= 32)){
1930
+ w << message_t(eph);
1931
+ }else if(qzss && (eph.svid >= 193) && (eph.svid < 202)){
1932
+ w.dump(message_t::from_qzss(eph), true);
1933
+ }else{
1934
+ return;
1935
+ }
1936
+ counter++;
1937
+ }
1938
+ void operator()(const typename message_sbas_t::eph_t &eph) {
1939
+ w << message_sbas_t(eph);
1655
1940
  counter++;
1656
1941
  }
1657
- } functor = {*this, res};
1942
+ } functor = {*this, res, false, false};
1658
1943
  if(space_nodes.gps){
1944
+ functor.gps = true;
1945
+ if(space_nodes.gps == space_nodes.qzss){functor.qzss = true;}
1659
1946
  for(typename space_node_t::satellites_t::const_iterator
1660
1947
  it(space_nodes.gps->satellites().begin()), it_end(space_nodes.gps->satellites().end());
1661
1948
  it != it_end; ++it){
@@ -1664,16 +1951,37 @@ class RINEX_NAV_Writer : public RINEX_Writer<> {
1664
1951
  space_node_t::Satellite::eph_list_t::EACH_ALL_INVERTED);
1665
1952
  }
1666
1953
  }
1954
+ if(space_nodes.sbas){
1955
+ for(typename SBAS_SpaceNode<FloatT>::satellites_t::const_iterator
1956
+ it(space_nodes.sbas->satellites().begin()),
1957
+ it_end(space_nodes.sbas->satellites().end());
1958
+ it != it_end; ++it){
1959
+ it->second.each_ephemeris(
1960
+ functor,
1961
+ SBAS_SpaceNode<FloatT>::Satellite::eph_list_t::EACH_ALL_INVERTED);
1962
+ }
1963
+ }
1964
+ if((version >= 302) && (!functor.qzss) && (space_nodes.qzss)){
1965
+ functor.qzss = true;
1966
+ functor.gps = false;
1967
+ for(typename space_node_t::satellites_t::const_iterator
1968
+ it(space_nodes.qzss->satellites().begin()), it_end(space_nodes.qzss->satellites().end());
1969
+ it != it_end; ++it){
1970
+ it->second.each_ephemeris(
1971
+ functor,
1972
+ space_node_t::Satellite::eph_list_t::EACH_ALL_INVERTED);
1973
+ }
1974
+ }
1667
1975
  return res;
1668
1976
  }
1669
1977
  static int write_all(
1670
1978
  std::ostream &out,
1671
- const typename reader_t::space_node_list_t &space_nodes,
1979
+ const space_node_list_t &space_nodes,
1672
1980
  const int &version = 304){
1673
1981
  return RINEX_NAV_Writer(out).write_all(space_nodes, version);
1674
1982
  }
1675
1983
  int write_all(const space_node_t &space_node, const int &version = 304){
1676
- const typename reader_t::space_node_list_t list = {&const_cast<space_node_t &>(space_node)};
1984
+ space_node_list_t list = {&space_node};
1677
1985
  return write_all(list, version);
1678
1986
  }
1679
1987
  static int write_all(std::ostream &out, const space_node_t &space_node, const int &version = 304){