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