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 #include "EngNav.hpp"
40 #include "TestUtil.hpp"
41 #include "TimeString.hpp"
42 #include "GPSWeekSecond.hpp"
43 #include <math.h>
44 #include <iostream>
45 
46 using namespace std;
47 
48 class EngNav_T
49 {
50 public:
EngNav_T()51    EngNav_T() // Default Constructor, set the precision value
52    {
53          // lower precision value, accuracy of some values is lost in
54          // binary conversion
55       eps = 1E-10;
56       b10 = 10;
57    }
~EngNav_T()58    ~EngNav_T() {}
59 
60 
getSubframePatternTest(void)61    unsigned getSubframePatternTest(void)
62    {
63       TUDEF("EngNav", "getSubframePattern");
64       string testMesg;
65 
66       const uint32_t subframe1P[10] =
67          { 0x22c000e4, 0x215ba160, 0x00180012, 0x1fffffc0, 0x3fffffc3,
68            0x3ffffffc, 0x3fffc009, 0x16d904f0, 0x003fdbac, 0x247c139c };
69       const uint32_t subframe2P[10] =
70          { 0x22c000e4, 0x215bc2f0, 0x16c2eb4d, 0x032c41a0, 0x26abc7e0,
71            0x0289c0dd, 0x0d5ecc38, 0x036b6842, 0x034f4df0, 0x1904c0b4 };
72       const uint32_t subframe3P[10] =
73          { 0x22c000e4, 0x215be378, 0x3ffcc344, 0x1a8441f1, 0x3ff80b74,
74            0x1c8deb5e, 0x0a34d52d, 0x14a5013e, 0x3fee8c2f, 0x16c35c80 };
75 
76       testMesg = "Subframe Pattern obtained was incorrect";
77       TUASSERTE(short,1,gpstk::EngNav::getSubframePattern(subframe1P));
78       TUASSERTE(short,2,gpstk::EngNav::getSubframePattern(subframe2P));
79       TUASSERTE(short,3,gpstk::EngNav::getSubframePattern(subframe3P));
80 
81       TURETURN();
82    }
83 
84 
computeParityTest(void)85    unsigned computeParityTest(void)
86    {
87       TUDEF("EngNav", "Compute Parity");
88       string testMesg;
89 
90          // data taken from
91          // http://www.gpscreations.com/NewFiles/GPS%20Parity%20Checking.pdf
92 
93          //Feed in 30bit word with 0's as the parity
94       uint32_t zero =  0x00000000;
95       uint32_t data1 = 0x22C000C0;
96       uint32_t data2 = 0x17344000;
97       uint32_t data3 = 0x2142EF00;
98       uint32_t data4 = 0x15E67180;
99 
100       testMesg = "Parity computed was incorrect";
101       TUASSERTE(uint32_t, 0x24, gpstk::EngNav::computeParity(data1, zero));
102 
103       data1 |= 0x24;
104 
105       TUASSERTE(uint32_t, 0x22, gpstk::EngNav::computeParity(data2, data1));
106 
107       data2 |= 0x22;
108 
109       TUASSERTE(uint32_t, 0x1b, gpstk::EngNav::computeParity(data3, data2));
110 
111       data3 |= 0x1B;
112 
113       TUASSERTE(uint32_t, 0x02,
114                 gpstk::EngNav::computeParity(data4, data3, false));
115 
116       TURETURN();
117    }
118 
fixParityTest(void)119    unsigned fixParityTest(void)
120    {
121       TUDEF("EngNav", "Fix Parity");
122       string testMesg;
123 
124          // 3 cases of regular parity computation
125       uint32_t data1 = 0x22C000C0;
126       uint32_t data2 = 0x17344000;
127       uint32_t data3 = 0x2142EF00;
128       uint32_t data4 = 0x15E67180;
129          // test word with the non-informational parity bits, set to 0
130       uint32_t data5 = 0x32098100; //taken from EngEphemeris
131       uint32_t CompareData1 = 0x22C000C0 | 0x0000024;
132       uint32_t CompareData2 = 0x17344000 | 0x0000022;
133       uint32_t CompareData3 = 0x2142EF00 | 0x000001B;
134       uint32_t CompareData4 = 0x15E67180 | 0x0000002;
135          // non-informational parity bits included in this
136       uint32_t CompareData5 = 0x32098100 | 0x00000DC;
137 
138          // (word to overwrite with parity, previous word, add 2
139          // parity computation bits(word 2 & 10))
140       testMesg = "Parity computed is incorrect";
141       TUASSERTE(uint32_t, CompareData1,
142                 gpstk::EngNav::fixParity(data1, 0, false));
143       TUASSERTE(uint32_t, CompareData2,
144                 gpstk::EngNav::fixParity(data2, CompareData1, false));
145       TUASSERTE(uint32_t, CompareData3,
146                 gpstk::EngNav::fixParity(data3, CompareData2, false));
147       TUASSERTE(uint32_t, CompareData4,
148                 gpstk::EngNav::fixParity(data4, CompareData3, false, false));
149       TUASSERTE(uint32_t, CompareData5,
150                 gpstk::EngNav::fixParity(data5, 0, true));
151 
152       TURETURN();
153    }
154 
155 
checkParityTest(void)156    unsigned checkParityTest(void)
157    {
158       TUDEF("EngNav", "Check Parity");
159       string testMesg;
160 
161          //Data is from EngEphemeris addSubframe test
162 
163       const uint32_t subframe1P[10] =
164          { 0x22c000e4, 0x215ba160, 0x00180012, 0x1fffffc0, 0x3fffffc3,
165            0x3fffffff, 0x3fffc035, 0x16d904f3, 0x003fdb90, 0x247c1339 };
166       const uint32_t subframe2P[10] =
167          { 0x22c000e4, 0x215bc2f0, 0x16c2eb4d, 0x032c41a3, 0x26abc7dc,
168            0x0289c0dd, 0x0d5ecc3b, 0x0036b67f, 0x034f4de5, 0x1904c0a1 };
169       const uint32_t subframe3P[10] =
170          { 0x22c000e4, 0x215be378, 0x3ffcc344, 0x1a8441f1, 0x3ff80b61,
171            0x1c8deb4b, 0x0a34d530, 0x14a50138, 0x3fee8c2f, 0x16c35c83 };
172 
173       testMesg = "Parity computed is incorrect";
174       testFramework.assert(gpstk::EngNav::checkParity(subframe1P, false),
175                            testMesg, __LINE__);
176       testFramework.assert(gpstk::EngNav::checkParity(subframe2P, false),
177                            testMesg, __LINE__);
178       testFramework.assert(gpstk::EngNav::checkParity(subframe3P, false),
179                            testMesg, __LINE__);
180 
181       TURETURN();
182    }
183 
184 
getHOWTimeTest(void)185    unsigned getHOWTimeTest(void)
186    {
187          //wrong, fix later
188       TUDEF("EngNav", "getHOWTime");
189       string testMesg;
190 
191       uint32_t how1 = 0x215ba160;
192       uint32_t how2 = 0x215bc2f0;
193       uint32_t how3 = 0x215be378;
194 
195       testMesg = "Returned TOW time from the HOW is incorrect";
196       TUASSERTE(unsigned long, 409902, gpstk::EngNav::getHOWTime(how1));
197       TUASSERTE(unsigned long, 409908, gpstk::EngNav::getHOWTime(how2));
198       TUASSERTE(unsigned long, 409914, gpstk::EngNav::getHOWTime(how3));
199 
200       TURETURN();
201    }
202 
203 
getSFIDTest(void)204    unsigned getSFIDTest(void)
205    {
206       TUDEF("EngNav", "getSFID");
207       string testMesg;
208 
209       uint32_t how1 = 0x215ba160;
210       uint32_t how2 = 0x215bc2f0;
211       uint32_t how3 = 0x215be378;
212 
213       testMesg = "Returned subframe ID was incorrect";
214       TUASSERTE(short, 1, gpstk::EngNav::getSFID(how1));
215       TUASSERTE(short, 2, gpstk::EngNav::getSFID(how2));
216       TUASSERTE(short, 3, gpstk::EngNav::getSFID(how3));
217 
218       TURETURN();
219    }
220 
221       //converts subframe binary data to FIC.
subframeConvertTest(void)222    unsigned subframeConvertTest(void) //calls getsubframePattern and convertQuant
223    {
224       TUDEF("EngNav", "Subframe Convert");
225       string testMesg;
226 
227       double output1[60], output2[60], output3[60];
228       const uint32_t subframe1P[10] =
229          { 0x22c000e4, 0x215ba160, 0x00180012, 0x1fffffc0, 0x3fffffc3,
230            0x3ffffffc, 0x3fffc009, 0x16d904f0, 0x003fdbac, 0x247c139c };
231       const uint32_t subframe2P[10] =
232          { 0x22c000e4, 0x215bc2f0, 0x16c2eb4d, 0x032c41a0, 0x26abc7e0,
233            0x0289c0dd, 0x0d5ecc38, 0x036b6842, 0x034f4df0, 0x1904c0b4 };
234       const uint32_t subframe3P[10] =
235          { 0x22c000e4, 0x215be378, 0x3ffcc344, 0x1a8441f1, 0x3ff80b76,
236            0x1c8deb5e, 0x0a34d52d, 0x14a5013e, 0x3fee8c2f, 0x16c35c80 };
237       gpstk::EngNav EngNavThing;
238 
239       testMesg = "Subframe Convert function failed";
240       testFramework.assert(
241          EngNavThing.subframeConvert(subframe1P, 1025, output1),
242          testMesg, __LINE__);
243 
244       testMesg = "TLM Preamble is incorrect";
245       testFramework.assert(output1[0] == 0x8B, testMesg, __LINE__);
246       testMesg = "TLM Message is incorrect";
247       testFramework.assert(output1[1] == 0, testMesg, __LINE__);
248       testMesg = "How Word (time?) is incorrect";
249       testFramework.assert(output1[2] == 409902, testMesg, __LINE__);
250       testMesg = "Alert flag is incorrect";
251       testFramework.assert(output1[3] == 0, testMesg, __LINE__);
252       testMesg = "Subframe ID is incorrect";
253       testFramework.assert(output1[4] == 1, testMesg, __LINE__);
254       testMesg = "Transmit Week Number is incorrect";
255       testFramework.assert(output1[5] == 1025, testMesg, __LINE__);
256       testMesg = "L2 code flag is incorrect";
257       testFramework.assert(output1[6] == 2, testMesg, __LINE__);
258       testMesg = "SV Accuracy is incorrect";
259       testFramework.assert(output1[7] == 0, testMesg, __LINE__);
260       testMesg = "SV Health is incorrect";
261       testFramework.assert(output1[8] == 0, testMesg, __LINE__);
262       testMesg = "IODC flag is incorrect";
263       testFramework.assert(output1[9]/2048 == 0x5B, testMesg,
264                            __LINE__); //AODC to IODC conversion, pg 15 of GR-SGL-99-14 FIC Definiton file
265       testMesg = "L2 code flag is incorrect";
266       testFramework.assert(output1[10] == 0, testMesg, __LINE__);
267       testMesg = "Group Delay Differential is incorrect";
268       testFramework.assert(output1[11] == 0, testMesg, __LINE__);
269       testMesg = "Clock Epoch is incorrect";
270       testFramework.assert(output1[12] == 409904, testMesg, __LINE__);
271       testMesg = "Clock Drift Rate is incorrect";
272       testFramework.assert(output1[13] == 0, testMesg, __LINE__);
273       testMesg = "Clock Drift is incorrect";
274       testFramework.assert(abs(output1[14] + .165982783074E-10)*pow(b10,10) < eps,
275                            testMesg, __LINE__);
276       testMesg = "Clock Bias is incorrect";
277       testFramework.assert(abs(output1[15] + .839701388031E-03)*pow(b10,3) < eps,
278                            testMesg, __LINE__);
279 
280       testMesg = "Subframe Convert function failed";
281       testFramework.assert(EngNavThing.subframeConvert(subframe2P, 1025, output2),
282                            testMesg, __LINE__);
283 
284       testMesg = "TLM Preamble is incorrect";
285       testFramework.assert(output2[0] == 0x8B, testMesg, __LINE__);
286       testMesg = "TLM Message is incorrect";
287       testFramework.assert(output2[1] == 0, testMesg, __LINE__);
288       testMesg = "How Word (time?) is incorrect";
289       testFramework.assert(output2[2] == 409908, testMesg, __LINE__);
290       testMesg = "Alert flag is incorrect";
291       testFramework.assert(output2[3] == 0, testMesg, __LINE__);
292       testMesg = "Subframe ID is incorrect";
293       testFramework.assert(output2[4] == 2, testMesg, __LINE__);
294       testMesg = "IODE is incorrect";
295       testFramework.assert(output2[5]/2048 == 91, testMesg,
296                            __LINE__); //AODE to IODE conversion, pg 15 of GR-SGL-99-14 FIC Definiton file
297       testMesg = "CRS is incorrect";
298       testFramework.assert(abs(output2[6] - 93.40625) < eps, testMesg, __LINE__);
299       testMesg = "Correction to Mean Motion is incorrect";
300       testFramework.assert(abs(output2[7] - (.11604054784E-8))*pow(b10,8) < eps,
301                            testMesg, __LINE__);
302       testMesg = "Mean Anomaly at Epoch is incorrect";
303       testFramework.assert(abs(output2[8] - 0.162092304801) < eps, testMesg,
304                            __LINE__);
305       testMesg = "CUC is incorrect";
306       testFramework.assert(abs(output2[9] - .484101474285E-5)*pow(b10,5) < eps,
307                            testMesg, __LINE__);
308       testMesg = "Eccentricity is incorrect";
309       testFramework.assert(abs(output2[10] - .626740418375E-2)*pow(b10,2) < eps,
310                            testMesg, __LINE__);
311       testMesg = "CUS is incorrect";
312       testFramework.assert(abs(output2[11] - .652112066746E-5)*pow(b10,5) < eps,
313                            testMesg, __LINE__);
314       testMesg = "Square Root of Semi-Major Axis is incorrect";
315       testFramework.assert(abs(output2[12] - .515365489006E4)*pow(b10,-4) < eps,
316                            testMesg, __LINE__);
317       testMesg = "Time of Epoch is incorrect";
318       testFramework.assert(output2[13] == 409904, testMesg, __LINE__);
319       testMesg = "Fit interval flag is incorrect";
320       testFramework.assert(output2[14] == 0, testMesg, __LINE__);
321 
322       testMesg = "Subframe Convert function failed";
323       testFramework.assert(EngNavThing.subframeConvert(subframe3P, 1025, output3),
324                            testMesg, __LINE__);
325 
326       testMesg = "TLM Preamble is incorrect";
327       testFramework.assert(output3[0] == 0x8B, testMesg, __LINE__);
328       testMesg = "TLM Message is incorrect";
329       testFramework.assert(output3[1] == 0, testMesg, __LINE__);
330       testMesg = "How Word (time?) is incorrect";
331       testFramework.assert(output3[2] == 409914, testMesg, __LINE__);
332       testMesg = "Alert flag is incorrect";
333       testFramework.assert(output3[3] == 0, testMesg, __LINE__);
334       testMesg = "Subframe ID is incorrect";
335       testFramework.assert(output3[4] == 3, testMesg, __LINE__);
336       testMesg = "CIC is incorrect";
337       testFramework.assert(abs(output3[5] + .242143869400E-7)*pow(b10,7) < eps,
338                            testMesg, __LINE__);
339       testMesg = "Right ascension of ascending node is incorrect";
340       testFramework.assert(abs(output3[6] - .329237003460) < eps, testMesg,
341                            __LINE__);
342       testMesg = "CIS is incorrect";
343       testFramework.assert(abs(output3[7] + .596046447754E-7)*pow(b10,7) < eps,
344                            testMesg, __LINE__);
345       testMesg = "Inclination is incorrect";
346       testFramework.assert(abs(output3[8] - 1.11541663136) < eps, testMesg,
347                            __LINE__);
348       testMesg = "CRC is incorrect";
349       testFramework.assert(abs(output3[9] - 326.59375)*pow(b10, -3) < eps, testMesg,
350                            __LINE__);
351       testMesg =
352          "Arguement of perigee is incorrect"; // All other values needed to be converted to semi-circles, IDK why this one wasn't
353       testFramework.assert(abs(output3[10] - 2.06958726335)*pow(b10, -1) < eps,
354                            testMesg, __LINE__);
355       testMesg = "Right ascension of ascending node time derivative is incorrect";
356       testFramework.assert(abs(output3[11] + .638312302555E-8)*pow(b10,10) < eps,
357                            testMesg, __LINE__);
358       testMesg = "AODE? is incorrect";
359       testFramework.assert(output3[12]/2048 == 91, testMesg, __LINE__);
360       testMesg = "Inclination time derivative is incorrect";
361       testFramework.assert(abs(output3[13] - .307155651409E-9)*pow(b10,9) < eps,
362                            testMesg, __LINE__);//AODE to IODE conversion, pg 15 of GR-SGL-99-14 FIC Definiton file
363 
364       TURETURN();
365    }
366 
367 
368       /** Reads a subframe 2 along with truth data from a file and
369        * makes sure everything matches up. */
nmctValidityTest()370    unsigned nmctValidityTest()
371    {
372       using gpstk::StringUtils::x2uint;
373       using gpstk::StringUtils::word;
374       using gpstk::StringUtils::numWords;
375       using gpstk::StringUtils::asUnsigned;
376       using gpstk::StringUtils::asDouble;
377       TUDEF("EngNav", "getNMCTValidity");
378          // Here's the input file to look at for the actual test data
379       string infilename = gpstk::getPathData() +
380          gpstk::getFileSep() + "test_getNMCTValidity.txt";
381       ifstream infile(infilename.c_str());
382       string line;
383       uint32_t sf2[10];
384       unsigned lineNo = 0;
385       unsigned howWeek;
386       uint32_t aodoExp, aodoGot;
387       gpstk::CommonTime tnmctExp, tnmctGot, toeExp, toeGot, totGot;
388       bool gotData = false; // make sure something was processed
389          // tmp values for reading from file
390       unsigned tmpU;
391       double tmpD;
392       while (infile)
393       {
394          lineNo++;
395          getline(infile, line);
396          if ((line[0] == '#') || (numWords(line) != 16))
397             continue;
398             //cout << "Line # " << lineNo << endl;
399          gotData = true;
400             // process the subframe data
401          for (unsigned wordnum = 0; wordnum < 10; wordnum++)
402          {
403             sf2[wordnum] = x2uint(word(line, wordnum));
404          }
405             // process the week number and expected values
406          howWeek  = asUnsigned(word(line, 10));
407          aodoExp  = asUnsigned(word(line, 11));
408          tmpU     = asUnsigned(word(line, 12));
409          tmpD     = asDouble(word(line, 13));
410          tnmctExp = gpstk::GPSWeekSecond(tmpU, tmpD);
411          tmpU     = asUnsigned(word(line, 14));
412          tmpD     = asDouble(word(line, 15));
413          toeExp   = gpstk::GPSWeekSecond(tmpU, tmpD);
414             // Compare the truth data with the results from the function
415          if (aodoExp == 27900)
416          {
417             testFramework.assert(
418                !gpstk::EngNav::getNMCTValidity(
419                   sf2, howWeek, aodoGot, tnmctGot, toeGot, totGot),
420                "Unexpected return value", __LINE__);
421             TUASSERTE(uint32_t, aodoExp, aodoGot);
422             TUASSERTE(gpstk::CommonTime, toeExp, toeGot);
423          }
424          else
425          {
426             testFramework.assert(
427                gpstk::EngNav::getNMCTValidity(
428                   sf2, howWeek, aodoGot, tnmctGot, toeGot, totGot),
429                "Unexpected return value", __LINE__);
430             TUASSERTE(uint32_t, aodoExp, aodoGot);
431             TUASSERTE(gpstk::CommonTime, tnmctExp, tnmctGot);
432             TUASSERTE(gpstk::CommonTime, toeExp, toeGot);
433          }
434       }
435       testFramework.assert(gotData, "Did not test any NMCT data", __LINE__);
436 
437       TURETURN();
438    }
439 
440 
441 private:
442    double eps;
443    double b10;
444 };
445 
446 
main()447 int main() //Main function to initialize and run all tests above
448 {
449    EngNav_T testClass;
450    unsigned errorTotal = 0;
451 
452    errorTotal += testClass.computeParityTest();
453    errorTotal += testClass.fixParityTest();
454    errorTotal += testClass.getHOWTimeTest();
455    errorTotal += testClass.getSFIDTest();
456    errorTotal += testClass.checkParityTest();
457    errorTotal += testClass.getSubframePatternTest();
458    errorTotal += testClass.subframeConvertTest();
459    errorTotal += testClass.nmctValidityTest();
460 
461    cout << "Total Failures for " << __FILE__ << ": " << errorTotal
462         << endl;
463 
464    return errorTotal;
465 }
466