Skip to content
This repository was archived by the owner on Apr 13, 2021. It is now read-only.

Commit 261a786

Browse files
author
Dmitry Tatarinov
committed
Add error detection functionality for GLO nav message
1 parent 8329e63 commit 261a786

File tree

3 files changed

+160
-2
lines changed

3 files changed

+160
-2
lines changed

include/libswiftnav/nav_msg_glo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,6 @@ void nav_msg_init_glo(nav_msg_glo_t *n);
4949
s8 process_string_glo(nav_msg_glo_t *n, ephemeris_t *e);
5050
u32 extract_word_glo(const nav_msg_glo_t *n, u16 bit_index, u8 n_bits);
5151
s8 nav_msg_update_glo(nav_msg_glo_t *n, bool bit_val);
52+
s8 error_detection_glo(nav_msg_glo_t *n);
5253

5354
#endif /* LIBSWIFTNAV_NAV_MSG_GLO_H */

src/nav_msg_glo.c

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <math.h>
1616
#include <libswiftnav/nav_msg_glo.h>
1717
#include <libswiftnav/time.h>
18+
#include <libswiftnav/logging.h>
1819

1920
/* Word Ft (accuracy of measurements), refer to GLO ICD, Table 4.4 */
2021
const float f_t[] = { 1.0f, 2.0f, 2.5f, 4.0f, 5.0f, 7.0f, 10.0f, 12.0f, 14.0f,
@@ -23,6 +24,18 @@ const float f_t[] = { 1.0f, 2.0f, 2.5f, 4.0f, 5.0f, 7.0f, 10.0f, 12.0f, 14.0f,
2324
/* Word P1 (Time interval between adjacent values of tb, minutes), refer Table 4.3 */
2425
const u8 p1[] = { 0, 30, 45, 60 }; /* min */
2526

27+
/* These bit masks (for data bits 9..85) correspond to table 4.13 of GLO ICD
28+
* used in error correction algorithm */
29+
const u32 e_masks[7][3] = {
30+
{ 0xaaad5b00, 0x55555556, 0xaaaab },
31+
{ 0x33366d00, 0x9999999b, 0xccccd },
32+
{ 0xc3c78e00, 0xe1e1e1e3, 0x10f0f1 },
33+
{ 0xfc07f000, 0xfe01fe03, 0xff01 },
34+
{ 0xfff80000, 0xfffe0003, 0x1f0001 },
35+
{ 0, 0xfffffffc, 1 },
36+
{ 0, 0, 0x1ffffe },
37+
};
38+
2639
/** Initialize the necessary parts of the nav message state structure.
2740
* \param n Pointer to GLO nav message structure to be initialized
2841
*/
@@ -33,6 +46,97 @@ void nav_msg_init_glo(nav_msg_glo_t *n)
3346
n->state = SYNC_TM;
3447
}
3548

49+
/* The algorithm based on
50+
* https://graphics.stanford.edu/~seander/bithacks.html#ParityParallel
51+
* \param in input data to calculate parity
52+
* \param word if true, calculate parity for 32 bits otherwise for 8 bits
53+
* \return parity bit */
54+
static bool parity(u32 in, bool word)
55+
{
56+
u32 a = in;
57+
if (word) {
58+
a ^= a >> 16;
59+
a ^= a >> 8;
60+
} else
61+
a &= 0x000000ff;
62+
a ^= a >> 4;
63+
a &= 0xf;
64+
return (0x6996 >> a) & 1;
65+
}
66+
67+
/** The function performs data verification and error correction
68+
* in received GLO navigation string. Refer to GLO ICD, section 4.7
69+
* \param n pointer to GLO nav message structure
70+
* \return -1 -- received string is bad and should be dropped out,
71+
* 0 -- received string is good
72+
* >0 -- number of bit in n->string_bits to be corrected (inverted)
73+
* range[9..85]*/
74+
s8 error_detection_glo(nav_msg_glo_t *n)
75+
{
76+
u8 c = 0;
77+
u32 data1, data2, data3;
78+
bool p0, p1, p2, p3, beta, c_sum;
79+
u8 bit_set = 0;
80+
u8 k = 0;
81+
82+
/* calculate C1..7 */
83+
for (u8 i = 0; i < 7; i++) {
84+
/* extract corresponding check bit of Hamming code */
85+
beta = extract_word_glo(n, i+1, 1);
86+
/* extract data bits and apply mask */
87+
data1 = extract_word_glo(n, 1, 32) & e_masks[i][0];
88+
data2 = extract_word_glo(n, 33, 32) & e_masks[i][1];
89+
data3 = extract_word_glo(n, 65, 32) & e_masks[i][2];
90+
/* calculate parity for data[1..3] */
91+
p1 = parity(data1, true);
92+
p2 = parity(data2, true);
93+
p3 = parity(data3, true);
94+
bool p = beta ^ p1 ^ p2 ^ p3;
95+
/* calculate common parity and set according C bit */
96+
c |= p << i;
97+
if (p) {
98+
bit_set++; /* how many bits are set, used in error criteria */
99+
k = i + 1; /* store number of most significant checksum not equal to 0,
100+
used in error criteria */
101+
}
102+
}
103+
104+
/* calculate C sum */
105+
data1 = extract_word_glo(n, 1, 32) & 0xffffff00;
106+
data2 = extract_word_glo(n, 33, 32);
107+
data3 = extract_word_glo(n, 65, 32);
108+
p1 = parity(data1, true);
109+
p2 = parity(data2, true);
110+
p3 = parity(data3, true);
111+
p0 = parity(extract_word_glo(n, 1, 8), false);
112+
c_sum = p0 ^ p1 ^ p2 ^ p3;
113+
114+
/* Now check C word to figure out is the string good, bad or
115+
* correction is needed */
116+
if ((!c_sum && !bit_set) || (1 == bit_set && c_sum)) /* case a) from ICD */
117+
118+
return 0; /* The string is good */
119+
120+
else if ((bit_set > 0 && !c_sum)
121+
|| (0 == bit_set && c_sum)) /* case c) from ICD */
122+
123+
return -1; /* multiple errors, bad string */
124+
125+
else if (bit_set > 1 && c_sum) { /* case b) from ICD */
126+
127+
u8 i_corr = (c & 0x7f) + 8 - k; /* define number of bit to be corrected */
128+
129+
if (i_corr > 85)
130+
return -1; /* odd number of multiple errors, bad string */
131+
132+
return i_corr; /* return the bit to be corrected */
133+
134+
} else {/* should not be here */
135+
log_error("GLO error correction: unexpected case");
136+
return -1;
137+
}
138+
}
139+
36140
/** Extract a word of n_bits length (n_bits <= 32) at position bit_index into
37141
* the subframe. Refer to bit index to Table 4.6 and 4.11 in GLO ICD 5.1 (pg. 34)
38142
* \param n pointer to GLO nav message structure to be parsed

tests/check_glo_decoder.c

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
1010
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
1111
*/
12-
#define DEBUG 1
12+
//#define DEBUG 1
1313

1414
#include <stdio.h>
1515
#include <check.h>
@@ -168,7 +168,7 @@ START_TEST(test_nav_msg_update_glo)
168168
nav_msg_init_glo(&a);
169169
/* write test string to temporary buffer */
170170
memcpy(a.string_bits, strings_in[i], sizeof(n.string_bits));
171-
/* transmit data bits, 85 bit */
171+
/* transmit data bits, 85 bits */
172172
for (j = 85; j > 0; j--) {
173173
bool one_bit = extract_word_glo(&a, j, 1); /* get bit to be transmitted */
174174
manchester = (one_bit << 1 | one_bit) ^ 2; /* transform to line code */
@@ -188,6 +188,7 @@ START_TEST(test_nav_msg_update_glo)
188188

189189
if (process_string_glo(&n, &e) == 1)
190190
e_out();
191+
191192
}
192193
/* now pass time mark bit by bit to receiver (MSB first),
193194
* no line code needed */
@@ -199,13 +200,65 @@ START_TEST(test_nav_msg_update_glo)
199200
}
200201
END_TEST
201202

203+
START_TEST(test_error_correction_glo)
204+
{
205+
const struct {
206+
u32 str_in[3]; /**< input string for test */
207+
s8 ret; /** result of the test */
208+
} test_case[] = {
209+
/* First, simply test one GLO nav message received from Novatel,
210+
* we trust Novatel, so no errors must be */
211+
{ {0xc90cfb3e, 0x9743a301, 0x010749}, 0}, /* case 0 */
212+
{ {0xdd39f5fc, 0x24542d0c, 0x021760}, 0},
213+
{ {0x653bc7e9, 0x1e8ead92, 0x038006}, 0},
214+
{ {0x60342dfc, 0x41000002, 0x0481c7}, 0},
215+
{ {0x40000895, 0x00000003, 0x050d10}, 0},
216+
{ {0x530a7ecf, 0x059c4415, 0x06b082}, 0},
217+
{ {0xfd94beb6, 0x7a577e97, 0x070f46}, 0},
218+
{ {0xba02de6f, 0x988e6814, 0x08b101}, 0},
219+
{ {0x12064831, 0x87767698, 0x09e1a6}, 0},
220+
{ {0xaf870be5, 0x54ef2617, 0x0ab286}, 0},
221+
{ {0x0f06ba41, 0x9a3f2698, 0x0b8f7c}, 0},
222+
{ {0x2f012204, 0xf0c3c81a, 0x0cb309}, 0},
223+
{ {0x1c858601, 0x10c47e98, 0x0da065}, 0},
224+
{ {0x5205980b, 0xf49abc1a, 0x0eb40e}, 0},
225+
{ {0x15454437, 0x2504e698, 0x0f8c09}, 0},
226+
/* Second, take 1st string from other GLO nav message and introduce an error
227+
* in data bits */
228+
{ {0xc90cfb81, 0x9743a301, 0x010748}, 0}, /* case 15, no errors */
229+
{ {0xc90cfb81, 0x9743a301, 0x110748}, 85},
230+
{ {0xc90cfb81, 0x1743a301, 0x010748}, 64},
231+
{ {0x490cfb81, 0x9743a301, 0x010748}, 32},
232+
{ {0xc90cfb81, 0x9743a300, 0x010748}, 33},
233+
{ {0xc90cfb81, 0x9743a301, 0x010749}, 65},
234+
{ {0xc90cfb81, 0x9743a301, 0x000748}, 81},
235+
{ {0xc90c3b81, 0x9743a301, 0x010748}, -1},
236+
{ {0xc90cfb81, 0x974fa301, 0x010748}, -1},
237+
{ {0xc90cfb81, 0x9743a301, 0x01074b}, -1},
238+
{ {0xc90cfb81, 0x9743a301, 0x010744}, -1},
239+
{ {0xc90cfb81, 0x9aaaa301, 0x010748}, -1},
240+
{ {0xc90cfb81, 0x9743a301, 0x010748}, 0}, /* no errors here */
241+
};
242+
243+
nav_msg_glo_t n;
244+
245+
for(u8 i = 0; i < sizeof(test_case) / sizeof(test_case[0]); i++) {
246+
memcpy(n.string_bits, test_case[i].str_in, sizeof(n.string_bits));
247+
s8 ret = error_detection_glo(&n);
248+
fail_unless(test_case[i].ret == ret, "Case %u: ret = %d, expected %d",
249+
i, ret, test_case[i].ret);
250+
}
251+
}
252+
END_TEST
253+
202254
Suite* glo_decoder_test_suite(void)
203255
{
204256
Suite *s = suite_create("GLO decoder");
205257
TCase *tc_core = tcase_create("Core");
206258
tcase_add_test(tc_core, test_extract_glo_word);
207259
tcase_add_test(tc_core, test_process_string_glo);
208260
tcase_add_test(tc_core, test_nav_msg_update_glo);
261+
tcase_add_test(tc_core, test_error_correction_glo);
209262
suite_add_tcase(s, tc_core);
210263

211264
return s;

0 commit comments

Comments
 (0)