1515#include <math.h>
1616#include <libswiftnav/nav_msg_glo.h>
1717#include <libswiftnav/time.h>
18+ #include <libswiftnav/logging.h>
19+ #include <libswiftnav/bits.h>
1820
1921/* Word Ft (accuracy of measurements), refer to GLO ICD, Table 4.4 */
2022const float f_t [] = { 1.0f , 2.0f , 2.5f , 4.0f , 5.0f , 7.0f , 10.0f , 12.0f , 14.0f ,
@@ -23,6 +25,20 @@ const float f_t[] = { 1.0f, 2.0f, 2.5f, 4.0f, 5.0f, 7.0f, 10.0f, 12.0f, 14.0f,
2325/* Word P1 (Time interval between adjacent values of tb, minutes), refer Table 4.3 */
2426const u8 p1 [] = { 0 , 30 , 45 , 60 }; /* min */
2527
28+ /* These bit masks (for data bits 9..85) correspond to table 4.13 of GLO ICD
29+ * used in error correction algorithm */
30+ const u32 e_masks [7 ][3 ] = {
31+ { 0xaaad5b00 , 0x55555556 , 0xaaaab },
32+ { 0x33366d00 , 0x9999999b , 0xccccd },
33+ { 0xc3c78e00 , 0xe1e1e1e3 , 0x10f0f1 },
34+ { 0xfc07f000 , 0xfe01fe03 , 0xff01 },
35+ { 0xfff80000 , 0xfffe0003 , 0x1f0001 },
36+ { 0 , 0xfffffffc , 1 },
37+ { 0 , 0 , 0x1ffffe },
38+ };
39+
40+ static u32 extract_word_glo (const nav_msg_glo_t * n , u16 bit_index , u8 n_bits );
41+
2642/** Initialize the necessary parts of the nav message state structure.
2743 * \param n Pointer to GLO nav message structure to be initialized
2844 */
@@ -33,17 +49,97 @@ void nav_msg_init_glo(nav_msg_glo_t *n)
3349 n -> state = SYNC_TM ;
3450}
3551
52+ /** The function performs data verification and error correction
53+ * in received GLO navigation string. Refer to GLO ICD, section 4.7
54+ * \param n pointer to GLO nav message structure
55+ * \return -1 -- received string is bad and should be dropped out,
56+ * 0 -- received string is good
57+ * >0 -- number of bit in n->string_bits to be corrected (inverted)
58+ * range[9..85]*/
59+ s8 error_detection_glo (const nav_msg_glo_t * n )
60+ {
61+ u8 c = 0 ;
62+ u32 data1 , data2 , data3 ;
63+ bool p0 , p1 , p2 , p3 , beta , c_sum ;
64+ u8 bit_set = 0 ;
65+ u8 k = 0 ;
66+
67+ /* calculate C1..7 */
68+ for (u8 i = 0 ; i < 7 ; i ++ ) {
69+ /* extract corresponding check bit of Hamming code */
70+ beta = extract_word_glo (n , i + 1 , 1 );
71+ /* extract data bits and apply mask */
72+ data1 = extract_word_glo (n , 1 , 32 ) & e_masks [i ][0 ];
73+ data2 = extract_word_glo (n , 33 , 32 ) & e_masks [i ][1 ];
74+ data3 = extract_word_glo (n , 65 , 32 ) & e_masks [i ][2 ];
75+ /* calculate parity for data[1..3] */
76+ p1 = parity (data1 );
77+ p2 = parity (data2 );
78+ p3 = parity (data3 );
79+ bool p = beta ^ p1 ^ p2 ^ p3 ;
80+ /* calculate common parity and set according C bit */
81+ c |= p << i ;
82+ if (p ) {
83+ bit_set ++ ; /* how many bits are set, used in error criteria */
84+ k = i + 1 ; /* store number of most significant checksum not equal to 0,
85+ used in error criteria */
86+ }
87+ }
88+
89+ /* calculate C sum */
90+ data1 = extract_word_glo (n , 1 , 32 ) & 0xffffff00 ;
91+ data2 = extract_word_glo (n , 33 , 32 );
92+ data3 = extract_word_glo (n , 65 , 32 );
93+ p1 = parity (data1 );
94+ p2 = parity (data2 );
95+ p3 = parity (data3 );
96+ p0 = parity (extract_word_glo (n , 1 , 8 ));
97+ c_sum = p0 ^ p1 ^ p2 ^ p3 ;
98+
99+ /* Now check C word to figure out is the string good, bad or
100+ * correction is needed */
101+ if ((!c_sum && !bit_set ) || (1 == bit_set && c_sum )) /* case a) from ICD */
102+
103+ return 0 ; /* The string is good */
104+
105+ if ((bit_set > 0 && !c_sum )
106+ || (0 == bit_set && c_sum )) /* case c) from ICD */
107+
108+ return -1 ; /* multiple errors, bad string */
109+
110+ if (bit_set > 1 && c_sum ) { /* case b) from ICD */
111+
112+ u8 i_corr = (c & 0x7f ) + 8 - k ; /* define number of bit to be corrected */
113+
114+ if (i_corr > GLO_STR_LEN )
115+ return -1 ; /* odd number of multiple errors, bad string */
116+
117+ return i_corr ; /* return the bit to be corrected */
118+ }
119+
120+ /* should not be here */
121+ log_error ("GLO error correction: unexpected case" );
122+ return -1 ;
123+ }
124+
36125/** Extract a word of n_bits length (n_bits <= 32) at position bit_index into
37126 * the subframe. Refer to bit index to Table 4.6 and 4.11 in GLO ICD 5.1 (pg. 34)
38127 * \param n pointer to GLO nav message structure to be parsed
39128 * \param bit_index number of bit the extract process start with. Range [1..85]
40129 * \param n_bits how many bits should be extracted [1..32]
41130 * \return word extracted from navigation string
42131 */
43- u32 extract_word_glo (const nav_msg_glo_t * n , u16 bit_index , u8 n_bits )
132+ static u32 extract_word_glo (const nav_msg_glo_t * n , u16 bit_index , u8 n_bits )
44133{
45- assert (n_bits <= 32 && n_bits > 0 );
46- assert (bit_index <= 85 && bit_index > 0 );
134+ if (bit_index > GLO_STR_LEN || !bit_index ) {
135+ log_error ("Incorrect bit index %d\n" , bit_index );
136+ return 0 ;
137+ }
138+
139+ if (n_bits > 32 || !n_bits ) {
140+ log_error ("Incorrect number of bits to be extracted %d\n" , n_bits );
141+ return 0 ;
142+ }
47143
48144 /* Extract a word of n_bits length (n_bits <= 32) at position bit_index into
49145 * the GLO string.*/
@@ -83,12 +179,17 @@ s8 nav_msg_update_glo(nav_msg_glo_t *n, bool bit_val)
83179 n -> string_bits [0 ] <<= 1 ; /* use one word of buffer for that purpose */
84180 n -> string_bits [0 ] |= bit_val ;
85181 /* collected bits match time mark? if not stay at this state */
86- if (extract_word_glo (n , 1 , GLO_TM_LEN ) == GLO_TM ) {
182+ u32 tm = extract_word_glo (n , 1 , GLO_TM_LEN );
183+ if (tm == GLO_TM || tm == (u32 )(~GLO_TM & 0x3fffffff )) {
87184 /* time mark found, next time start collecting data bits */
88185 n -> meander_bits_cnt = 0 ;
89186 n -> manchester = 0 ;
90187 n -> state = GET_DATA_BIT ;
91188 n -> string_bits [0 ] = 0 ;
189+ if (tm == GLO_TM )
190+ n -> inverted = 0 ;
191+ else if (tm == (u32 )(~GLO_TM & 0x3fffffff ))
192+ n -> inverted = 1 ;
92193 }
93194 break ;
94195 case GET_DATA_BIT : /* collect data bits of string */
@@ -106,14 +207,17 @@ s8 nav_msg_update_glo(nav_msg_glo_t *n, bool bit_val)
106207 n -> string_bits [i ] = tmp ;
107208 }
108209 n -> string_bits [0 ] <<= 1 ;
210+
211+ /* set type of meander depending on inversion */
212+ u8 meander = n -> inverted ? 1 : 2 ;
109213 /* store bit after meander removal to buffer */
110- n -> string_bits [0 ] |= (n -> manchester ^ 2 ) & 1 ;
214+ n -> string_bits [0 ] |= (n -> manchester ^ meander ) & 1 ;
111215 n -> current_head_bit_index ++ ;
112216 n -> meander_bits_cnt = 0 ;
113217 n -> manchester = 0 ;
114218 /* did we received all bits of a string?
115219 * if yes, notify user and start searching time mark again*/
116- if (n -> current_head_bit_index == 85 ) {
220+ if (n -> current_head_bit_index == GLO_STR_LEN ) {
117221 n -> current_head_bit_index = 0 ;
118222 n -> state = SYNC_TM ;
119223 ret = 1 ;
@@ -138,7 +242,7 @@ s8 nav_msg_update_glo(nav_msg_glo_t *n, bool bit_val)
138242s8 process_string_glo (nav_msg_glo_t * n , ephemeris_t * e )
139243{
140244 /* Extract and check dummy bit from GLO string, bit 85 in GLO string */
141- if (extract_word_glo (n , 85 , 1 ) != 0 ) {
245+ if (extract_word_glo (n , GLO_STR_LEN , 1 ) != 0 ) {
142246 log_error ("GLO dummy bit is not 0." );
143247 return -1 ;
144248 }
@@ -148,6 +252,7 @@ s8 process_string_glo(nav_msg_glo_t *n, ephemeris_t *e)
148252 u8 sign ;
149253 /* is the string we need? */
150254 if (n -> next_string_id == m ) {
255+ n -> decode_done = 0 ;
151256 switch (m ) {
152257 case 1 : /* string 1 */
153258 /* extract x */
@@ -238,24 +343,38 @@ s8 process_string_glo(nav_msg_glo_t *n, ephemeris_t *e)
238343 /* extract N4 */
239344 n -> n4 = (u8 ) extract_word_glo (n , 32 , 5 );
240345
241- n -> next_string_id = 0 ; /* all string parsed */
346+ n -> next_string_id = 1 ; /* start decode from 1st string next time */
347+ n -> decode_done = 1 ; /* all string parsed */
242348 break ;
243349 default :
244350 break ;
245351 }
246352 }
247353 /* all needed strings decoded?
248354 * fill ephemeris structure if we was not able to do it before*/
249- if (n -> next_string_id == 0 ) {
355+ if (n -> decode_done ) {
250356 e -> sid .code = CODE_GLO_L1CA ;
251357 /* convert GLO TOE to GPS TOE */
252358 e -> toe = glo_time2gps_time (n -> nt , n -> n4 , n -> hrs , n -> min , n -> sec );
253359 e -> healthy ^= 1 ; /* invert healthy bit */
254360 e -> valid = e -> healthy ; //NOTE: probably Valid needs to be defined by other way
255- n -> next_string_id = 1 ; /* start from string 1 */
256361 return 1 ;
257362 }
258363
259-
260364 return 0 ;
261365}
366+
367+ /** This function just a wrapper for glo_time2gps_time
368+ * \param n pointer to GLO nav message
369+ * \return time of GLO referenced to the end of the 5th GLO nav string presented as
370+ * GPS time, -1 if ephemeris cannot be decoded */
371+ double nav_msg_get_tow_glo (const nav_msg_glo_t * n )
372+ {
373+ /* + 10 sec for the end of 5th string */
374+ if (!n -> decode_done )
375+ return -1 ;
376+ else {
377+ gps_time_t t = glo_time2gps_time (n -> nt , n -> n4 , n -> hrs , n -> min , n -> sec + 10 );
378+ return t .tow ;
379+ }
380+ }
0 commit comments