1 //==============================================================================
2 //
3 //  This file is part of GPSTk, the GPS Toolkit.
4 //
5 //  The GPSTk is free software; you can redistribute it and/or modify
6 //  it under the terms of the GNU Lesser General Public License as published
7 //  by the Free Software Foundation; either version 3.0 of the License, or
8 //  any later version.
9 //
10 //  The GPSTk is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU Lesser General Public License for more details.
14 //
15 //  You should have received a copy of the GNU Lesser General Public
16 //  License along with GPSTk; if not, write to the Free Software Foundation,
17 //  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
18 //
19 //  This software was developed by Applied Research Laboratories at the
20 //  University of Texas at Austin.
21 //  Copyright 2004-2020, The Board of Regents of The University of Texas System
22 //
23 //==============================================================================
24 
25 //==============================================================================
26 //
27 //  This software was developed by Applied Research Laboratories at the
28 //  University of Texas at Austin, under contract to an agency or agencies
29 //  within the U.S. Department of Defense. The U.S. Government retains all
30 //  rights to use, duplicate, distribute, disclose, or release this software.
31 //
32 //  Pursuant to DoD Directive 523024
33 //
34 //  DISTRIBUTION STATEMENT A: This software has been approved for public
35 //                            release, distribution is unlimited.
36 //
37 //==============================================================================
38 /*
39 *   The Galileo health status is determined from several pieces of data in the
40 *   message.  This is defined the Galileo Service Definition Document (SDD) in
41 *   section 2.3.1.4.  In order to test the various combinations, a
42 *   RINEX 3 nav file was hand edited to cover the various combinations.
43 *   A different SV was assigned to each combination in order to simplify the
44 *   test process.
45 *
46 *   Note that the full complement of possible combinations do not need to be
47 *   tested.   SHS is the highest priority in the decision tree.   Unless
48 *   SHS==0, the other parameters do not matter.   Similarly, DVS is higher
49 *   prioity than SISA.
50 *
51 *   The RINEX "health" word is actually bit-encoded and contains
52 *   the DVS (1 bit) and the SHS (three bits).  This is described in the
53 *   RINEX 3.04 specification in Table A8.  The exact location of
54 *   the three bits varies by signal type.  As a result, the reconstruted
55 *   "health" word is provided to aid confirmation.
56 *
57 *        Bit    8 7 6 5 4 3 2 1 0
58 *   Quantity    S S D S S D S S D
59 *               ----- ----- -----
60 *     Signal      E5b   E5a   E1B
61 *
62 *                     Data Source                     "Health" word    Expected
63 *   PRN ID  Signal    dec.   hex.  SISA   DVS    SHS     hex.   dec.     Result     Notes
64 *   ------  ------    -----------  ----   ---    ---   -------------   --------   -----
65 *      E01     E5b    516, 0x0204  !=255    0      0     0x000     0   Healthy    As broadcast
66 *      E02                         !=255    0      1     0x080   128   Unhealthy  SHS = Out of service
67 *      E03                         !=255    0      2     0x100   256   Marginal   SHS = Will be out of service
68 *      E04                         !=255    0      3     0x180   384   Unhealthy  SHS = Under test
69 *      E05                         !=255    1      0     0x040    64   Marginal   DVS = Working without guarantee
70 *      E06                            -1    0      0     0x000     0   Marginal   SISA = no accuracy predication available
71 *      E07     E1B    513, 0x0201  !=255    0      0     0x000     0   Healthy
72 *      E08            513, 0x0201  !=255    0      3     0x006     6   Unhealthy
73 *      E09            513, 0x0201     -1    0      0     0x000     0   Marginal
74 *      E10     E5a    258, 0x0102  !=255    0      0     0x000     0   Healthy    High order bit in data source changes due to E5a
75 *      E11            258, 0x0102  !=255    0      3     0x030    48   Unhealthy
76 *      E12            258, 0x0102     -1    0      0     0x000     0   Marginal
77 *      E14   E1B+E5b  517, 0x0205  !=255    0      3     0x186   390   Unhealthy   As broadcast. Both E1B and E5b
78 */
79 #include "OrbitEphStore.hpp"
80 #include "CivilTime.hpp"
81 #include "Exception.hpp"
82 #include "TimeString.hpp"
83 #include "TestUtil.hpp"
84 
85 #include "OrbitEphStore.hpp"
86 #include "GalEphemeris.hpp"
87 #include "SatelliteSystem.hpp"
88 #include "Xvt.hpp"
89 
90 // Rinex3 Nav Loading
91 #include "Rinex3NavStream.hpp"
92 #include "Rinex3NavHeader.hpp"
93 #include "Rinex3NavData.hpp"
94 
95 using namespace std;
96 
97 class GalEphemeris_T
98 {
99 public:
100 
101   gpstk::OrbitEphStore store;
102 
103       /** This loads the test file into an OrbitEphStore.
104         * OrbitEphStore is tested elsewhere
105         */
loadRinexNavData()106    unsigned loadRinexNavData()
107    {
108       TUDEF("GalEphemeris_T","Load Rinex Nav Data");
109 
110       std::string dataFilePath = gpstk::getPathData();
111       std::string file_sep = "/";
112       string fn = dataFilePath + file_sep + "test_input_rinex3_nav_gal.20n";
113 
114       gpstk::Rinex3NavStream strm;
115       strm.open(fn.c_str(),ios::in);
116       if (!strm.is_open())
117       {
118           stringstream ss;
119           ss << "Failed to open " << fn << " for input.";
120           TUFAIL(ss.str());
121           TURETURN();
122       }
123 
124       try
125       {
126          gpstk::Rinex3NavHeader Rhead;
127          strm >> Rhead;
128       }
129       catch (gpstk::Exception e)
130       {
131          stringstream ss;
132          ss << "Failed to read header from " << fn << ".";
133          TUFAIL(ss.str());
134          TURETURN();
135       }
136 
137       gpstk::Rinex3NavData  Rdata;
138       bool done = false;
139       while (!done)
140       {
141          try
142          {
143             if (strm >> Rdata)
144             {
145                if (Rdata.satSys=="E")
146                {
147                   gpstk::GalEphemeris eph(Rdata);
148                   store.addEphemeris(dynamic_cast<gpstk::OrbitEph*>(&eph));
149                }
150             }
151             else
152             {
153                done = true;
154             }
155          }
156          catch (gpstk::Exception e)
157          {
158             TUFAIL("Caught exception attempting to load test_input");
159             done = true;
160          }
161       }
162       TURETURN();
163    }
164 
165       /** This tests the known health status of selected
166         * SVs.
167         */
testHealthSettings()168    unsigned testHealthSettings()
169    {
170       TUDEF("GalEphemeris","Test health contents");
171 
172       const int prnId[] =
173       {
174         1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14
175       };
176       const gpstk::Xvt::HealthStatus fullHealth[] =
177       {
178          gpstk::Xvt::Healthy,
179          gpstk::Xvt::Unhealthy,
180          gpstk::Xvt::Degraded,
181          gpstk::Xvt::Unhealthy,
182          gpstk::Xvt::Degraded,
183          gpstk::Xvt::Degraded,
184          gpstk::Xvt::Healthy,
185          gpstk::Xvt::Unhealthy,
186          gpstk::Xvt::Degraded,
187          gpstk::Xvt::Healthy,
188          gpstk::Xvt::Unhealthy,
189          gpstk::Xvt::Degraded,
190          gpstk::Xvt::Unhealthy
191       };
192       const gpstk::Xvt::HealthStatus binaryNealth[] =
193       {
194          gpstk::Xvt::Healthy,
195          gpstk::Xvt::Unhealthy,
196          gpstk::Xvt::Unhealthy,
197          gpstk::Xvt::Unhealthy,
198          gpstk::Xvt::Unhealthy,
199          gpstk::Xvt::Unhealthy,
200          gpstk::Xvt::Healthy,
201          gpstk::Xvt::Unhealthy,
202          gpstk::Xvt::Unhealthy,
203          gpstk::Xvt::Healthy,
204          gpstk::Xvt::Unhealthy,
205          gpstk::Xvt::Unhealthy,
206          gpstk::Xvt::Unhealthy
207       };
208 
209       int CASE_COUNT = 13;
210 
211       gpstk::CommonTime ctTest = gpstk::CivilTime(2020, 5, 29, 0, 30, 0.0, gpstk::TimeSystem::GAL);
212       for (int i=0; i<CASE_COUNT; i++)
213       {
214          gpstk::SatID sid(prnId[i],gpstk::SatelliteSystem::Galileo);
215          gpstk::Xvt::HealthStatus health;
216          TUCATCH(health = store.getSVHealth(sid, ctTest));
217          TUASSERTE(gpstk::Xvt::HealthStatus,
218                    binaryNealth[i], health);
219          const gpstk::OrbitEph* eph = store.findOrbitEph(sid,ctTest);
220          const gpstk::GalEphemeris* geph = dynamic_cast<const gpstk::GalEphemeris*>(eph);
221          TUASSERTE(gpstk::Xvt::HealthStatus,
222                    fullHealth[i], geph->health);
223       }
224       TURETURN();
225    }
226 };
227 
main(int argc,char * argv[])228 int main(int argc, char *argv[])
229 {
230    unsigned total = 0;
231    GalEphemeris_T testClass;
232    total += testClass.loadRinexNavData();
233    total += testClass.testHealthSettings();
234 
235    cout << "Total Failures for " << __FILE__ << ": " << total << endl;
236    return total;
237 }
238