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

Commit 4c1b826

Browse files
author
Dmitry Tatarinov
committed
Add GLO bitstream receiver
1 parent f4e5dc8 commit 4c1b826

File tree

3 files changed

+166
-31
lines changed

3 files changed

+166
-31
lines changed

include/libswiftnav/nav_msg_glo.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,29 @@
1818

1919
#define NAV_MSG_GLO_STRING_BITS_LEN 3 /* Buffer 96 nav bits. */
2020

21+
/** Time mark in GLO nav string, GLO ICD, pg. 16 */
22+
#define GLO_TM (0x3E375096)
23+
#define GLO_TM_LEN 30
24+
25+
typedef enum {
26+
INVALID = -1,
27+
SYNC_TM,
28+
GET_DATA_BIT
29+
} glo_decode_machine;
30+
2131
typedef struct {
2232
u32 string_bits[NAV_MSG_GLO_STRING_BITS_LEN];
33+
u32 tm_buff;
34+
u16 current_head_bit_index;
2335
u8 next_string_id;
36+
u8 meander_bits_cnt;
37+
u8 manchester;
38+
glo_decode_machine state;
2439
} nav_msg_glo_t;
2540

2641
void nav_msg_init_glo(nav_msg_glo_t *n);
2742
s8 process_string_glo(nav_msg_glo_t *n, ephemeris_t *e);
2843
u32 extract_word_glo(const nav_msg_glo_t *n, u16 bit_index, u8 n_bits); //TODO: remove after tests
44+
s8 nav_msg_update_glo(nav_msg_glo_t *n, bool bit_val);
2945

3046
#endif /* LIBSWIFTNAV_NAV_MSG_GLO_H */

src/nav_msg_glo.c

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ void nav_msg_init_glo(nav_msg_glo_t *n)
5151
/* Initialize the necessary parts of the nav message state structure. */
5252
memset(n, 0, sizeof(nav_msg_glo_t));
5353
n->next_string_id = 1; /* start parsing from string 1 */
54+
n->state = SYNC_TM;
5455
done_flag = false;
5556
}
5657

@@ -84,7 +85,70 @@ void nav_msg_init_glo(nav_msg_glo_t *n)
8485
return word;
8586
}
8687

87-
/** The function deccodes a GLO navigation string
88+
/** Navigation message GLO decoding update.
89+
* Called once per nav bit interval (10 ms).
90+
* Performs the necessary steps to store the nav bits in buffer.
91+
*
92+
* \param n GLO Nav message decode state struct
93+
* \param bit_val State of the nav bit to process, 0 or 1
94+
*
95+
* \return 1 if Glo nav string ready for decoding,
96+
* -1 otherwise.
97+
*/
98+
s8 nav_msg_update_glo(nav_msg_glo_t *n, bool bit_val)
99+
{
100+
s8 ret = -1;
101+
102+
switch (n->state) {
103+
case SYNC_TM: /* try to find time mark */
104+
/* put incoming bit at the tail of the buffer */
105+
n->string_bits[0] <<= 1; /* use one word of buffer for that purpose */
106+
n->string_bits[0] |= bit_val;
107+
/* collected bits match time mark? if not stay at this state */
108+
if(extract_word_glo(n, 1, GLO_TM_LEN) == GLO_TM) {
109+
/* time mark found, next time start collecting data bits */
110+
n->meander_bits_cnt = 0;
111+
n->manchester = 0;
112+
n->state = GET_DATA_BIT;
113+
n->string_bits[0] = 0;
114+
}
115+
break;
116+
case GET_DATA_BIT: /* collect data bits of string */
117+
n->meander_bits_cnt++;
118+
n->manchester <<= 1;
119+
n->manchester |= bit_val; /* store incoming bit */
120+
/* did we take 2 bits of line code?
121+
* if yes, remove meander and store bit in buffer,
122+
* if no, stay at the state */
123+
if (n->meander_bits_cnt == 2) {
124+
/* shift whole buffer by 1 bit left */
125+
for (u8 i = NAV_MSG_GLO_STRING_BITS_LEN - 1; i > 0; i--) {
126+
u32 tmp = (n->string_bits[i] << 1) | ((n->string_bits[i-1] & (1<<31)) >> 31);
127+
n->string_bits[i] = tmp;
128+
}
129+
n->string_bits[0] <<= 1;
130+
/* store bit after meander removal to buffer */
131+
n->string_bits[0] |= (n->manchester ^ 2) & 1;
132+
n->current_head_bit_index++;
133+
n->meander_bits_cnt = 0;
134+
n->manchester = 0;
135+
/* did we received all bits of a string?
136+
* if yes, notify user and start searching time mark again*/
137+
if (n->current_head_bit_index == 85) {
138+
n->current_head_bit_index = 0;
139+
n->state = SYNC_TM;
140+
ret = 1;
141+
}
142+
}
143+
break;
144+
default:
145+
nav_msg_init_glo(n); //TODO: probably not needed to initialize next_string_id
146+
break;
147+
}
148+
return ret;
149+
}
150+
151+
/** The function decodes a GLO navigation string
88152
* \param n Pointer to nav_msg_glo_t structure which contains GLO string
89153
* \param e Pointer to Ephemeris to store
90154
* \return 0 - decode not completed,
@@ -144,7 +208,7 @@ s8 process_string_glo(nav_msg_glo_t *n, ephemeris_t *e)
144208
sign = extract_word_glo(n, 36 + 4, 1);
145209
g_e.glo.acc[1] = sign ? -1.0 * ret * pow(2, -30) * 1000.0 :
146210
ret * pow(2, -30) * 1000.0;
147-
/* extract MSB of B */
211+
/* extract MSB of B (if the bit is clear the SV is OK ) */
148212
g_e.healthy = extract_word_glo(n, 80, 1);
149213
/* extract P1 */
150214
g_e.fit_interval = p1[extract_word_glo(n, 77, 2)];
@@ -172,7 +236,7 @@ s8 process_string_glo(nav_msg_glo_t *n, ephemeris_t *e)
172236
sign = extract_word_glo(n, 69 + 10, 1);
173237
g_e.glo.gamma = sign ? -1.0 * ret * pow(2, -40) :
174238
ret * pow(2, -40);
175-
/* extract l and add B */
239+
/* extract l, if the it is clear the SV is OK, so OR it with B */
176240
g_e.healthy |= extract_word_glo(n, 65, 1);
177241

178242
n->next_string_id = 4;
@@ -208,6 +272,7 @@ s8 process_string_glo(nav_msg_glo_t *n, ephemeris_t *e)
208272
g_e.sid.code = CODE_GLO_L1CA;
209273
/* convert GLO TOE to GPS TOE */
210274
g_e.toe = glo_time2gps_time(nt, n4, hrs, min, sec);
275+
g_e.healthy ^= 1; /* invert healthy bit */
211276
g_e.valid = g_e.healthy; //NOTE: probably Valid needs to be defined by other way
212277
memcpy(e, &g_e, sizeof(g_e));
213278
done_flag = false;

tests/check_glo_decoder.c

Lines changed: 82 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <stdio.h>
1515
#include <check.h>
1616
#include <math.h>
17+
#include <string.h>
1718
#include <libswiftnav/nav_msg_glo.h>
1819
#include <libswiftnav/logging.h>
1920

@@ -29,7 +30,8 @@ ephemeris_t e;
2930
* 0aad8090a54019cb035d3f,0,0b3e2240201e97fc34fc39,0,0cae940cdc3c1e2786da9b,0,
3031
* 0d68bf54a4c697f115320b,0,0eaf8449b38c1e228932d8,0,0f815b653eee981314802a,0*f3837a1c
3132
*/
32-
u32 strings_in[5][3] = {
33+
u32 strings_in[6][3] = {
34+
{1,1,1}, /* dummy words used in test_nav_msg_update_glo only */
3335
{0xc3a850b5, 0x96999b05, 0x010743}, /* 01074396999b05c3a850b5 */
3436
{0xd9c15f66, 0xa5256204, 0x021760}, /* 021760a5256204d9c15f66 */
3537
{0x6d0e3123, 0x9d60899a, 0x038026}, /* 0380269d60899a6d0e3123 */
@@ -60,6 +62,36 @@ double AZ = -2.79396772384643555e-06;
6062
double GAMMA = 1.81898940354585648e-12;
6163
double TAU = -9.71024855971336365e-05;
6264

65+
void e_out(void)
66+
{
67+
log_debug("GLO Ephemeris:\n");
68+
log_debug("\tSID: %u (code %u)\n", e.sid.sat, e.sid.code);
69+
log_debug("\tGPS time: TOE %f, WN %d\n", e.toe.tow, e.toe.wn);
70+
log_debug("\tURA: %f\n", e.ura);
71+
log_debug("\tFit interval: %u\n", e.fit_interval);
72+
log_debug("\tValid: %u\n", e.valid);
73+
log_debug("\tHealthy: %u\n", e.healthy);
74+
log_debug("\tgamma: %25.18f\n", e.glo.gamma);
75+
log_debug("\ttau: %25.18f\n", e.glo.tau);
76+
log_debug("\tX, Y, Z: %25.18f, %25.18f, %25.18f\n",
77+
e.glo.pos[0], e.glo.pos[1], e.glo.pos[2]);
78+
log_debug("\tVX, VY, VZ: %25.18f, %25.18f, %25.18f\n",
79+
e.glo.vel[0], e.glo.vel[1], e.glo.vel[2]);
80+
log_debug("\tAX, AY, AZ: %25.18f, %25.18f, %25.18f\n",
81+
e.glo.acc[0], e.glo.acc[1], e.glo.acc[2]);
82+
fail_unless(e.glo.pos[0]-X == 0, "dX %25.18f, expected %25.18f", e.glo.pos[0], X);
83+
fail_unless(e.glo.pos[1]-Y == 0, "dY %25.18f, expected %25.18f", e.glo.pos[1], Y);
84+
fail_unless(e.glo.pos[2]-Z == 0, "dZ %25.18f, expected %25.18f", e.glo.pos[2], Z);
85+
fail_unless(e.glo.vel[0]-VX == 0, "dVX %25.18f, expected %25.18f", e.glo.vel[0], VX);
86+
fail_unless(e.glo.vel[1]-VY == 0, "dVY %25.18f, expected %25.18f", e.glo.vel[1], VY);
87+
fail_unless(e.glo.vel[2]-VZ == 0, "dVZ %25.18f, expected %25.18f", e.glo.vel[2], VZ);
88+
fail_unless(e.glo.acc[0]-AX == 0, "dAX %25.18f, expected %25.18f", e.glo.acc[0], AX);
89+
fail_unless(e.glo.acc[1]-AY == 0, "dAY %25.18f, expected %25.18f", e.glo.acc[1], AY);
90+
fail_unless(e.glo.acc[2]-AZ == 0, "dAZ %25.18f, expected %25.18f", e.glo.acc[2], AZ);
91+
fail_unless(e.glo.tau-TAU == 0, "dTAU %25.18f, expected %25.18f", e.glo.tau, TAU);
92+
fail_unless(e.glo.gamma-GAMMA == 0, "dGAMMA %25.18f, expected %25.18f", e.glo.gamma, GAMMA);
93+
}
94+
6395
START_TEST(test_extract_glo_word)
6496
{
6597
u32 ret = 0;
@@ -101,44 +133,66 @@ END_TEST
101133
START_TEST(test_process_string_glo)
102134
{
103135
nav_msg_init_glo(&n);
104-
for(u8 i = 0; i < sizeof(strings_in)/sizeof(strings_in[0]); i++) {
136+
memset(&e,0,sizeof(e));
137+
for(u8 i = 1; i < sizeof(strings_in)/sizeof(strings_in[1]); i++) {
105138
memcpy(n.string_bits, strings_in[i], sizeof(n.string_bits));
106139
process_string_glo(&n, &e);
107140
}
108-
log_debug("GLO Ephemeris:\n");
109-
log_debug("\tSID: %u (code %u)\n", e.sid.sat, e.sid.code);
110-
log_debug("\tGPS time: TOE %f, WN %d\n", e.toe.tow, e.toe.wn);
111-
log_debug("\tURA: %f\n", e.ura);
112-
log_debug("\tFit interval: %u\n", e.fit_interval);
113-
log_debug("\tValid: %u\n", e.valid);
114-
log_debug("\tHealthy: %u\n", e.healthy);
115-
log_debug("\tgamma: %25.18f\n", e.glo.gamma);
116-
log_debug("\ttau: %25.18f\n", e.glo.tau);
117-
log_debug("\tX, Y, Z: %25.18f, %25.18f, %25.18f\n",
118-
e.glo.pos[0], e.glo.pos[1], e.glo.pos[2]);
119-
log_debug("\tVX, VY, VZ: %25.18f, %25.18f, %25.18f\n",
120-
e.glo.vel[0], e.glo.vel[1], e.glo.vel[2]);
121-
log_debug("\tAX, AY, AZ: %25.18f, %25.18f, %25.18f\n",
122-
e.glo.acc[0], e.glo.acc[1], e.glo.acc[2]);
123-
fail_unless(e.glo.pos[0]-X == 0, "dX %25.18f, expected %25.18f", e.glo.pos[0], X);
124-
fail_unless(e.glo.pos[1]-Y == 0, "dY %25.18f, expected %25.18f", e.glo.pos[1], Y);
125-
fail_unless(e.glo.pos[2]-Z == 0, "dZ %25.18f, expected %25.18f", e.glo.pos[2], Z);
126-
fail_unless(e.glo.vel[0]-VX == 0, "dVX %25.18f, expected %25.18f", e.glo.vel[0], VX);
127-
fail_unless(e.glo.vel[1]-VY == 0, "dVY %25.18f, expected %25.18f", e.glo.vel[1], VY);
128-
fail_unless(e.glo.vel[2]-VZ == 0, "dVZ %25.18f, expected %25.18f", e.glo.vel[2], VZ);
129-
fail_unless(e.glo.acc[0]-AX == 0, "dAX %25.18f, expected %25.18f", e.glo.acc[0], AX);
130-
fail_unless(e.glo.acc[1]-AY == 0, "dAY %25.18f, expected %25.18f", e.glo.acc[1], AY);
131-
fail_unless(e.glo.acc[2]-AZ == 0, "dAZ %25.18f, expected %25.18f", e.glo.acc[2], AZ);
132-
fail_unless(e.glo.tau-TAU == 0, "dTAU %25.18f, expected %25.18f", e.glo.tau, TAU);
133-
fail_unless(e.glo.gamma-GAMMA == 0, "dGAMMA %25.18f, expected %25.18f", e.glo.gamma, GAMMA);
141+
e_out();
142+
}
143+
END_TEST
144+
145+
START_TEST(test_nav_msg_update_glo)
146+
{
147+
/* the unit test encodes strings_in to generate glo bitstream, calls
148+
* nav_msg_update_glo to receive and finally decodes received string */
149+
nav_msg_init_glo(&n);
150+
memset(&e,0,sizeof(e));
151+
/* get string one by one */
152+
for(u8 i = 0; i < sizeof(strings_in)/sizeof(strings_in[0]); i++) {
153+
u8 manchester = 0;
154+
nav_msg_glo_t a;
155+
s8 ret;
156+
u8 j;
157+
nav_msg_init_glo(&a);
158+
/* write test string to temporary buffer */
159+
memcpy(a.string_bits, strings_in[i], sizeof(n.string_bits));
160+
/* transmit data bits, 85 bit */
161+
for(j = 85; j > 0; j--) {
162+
bool one_bit = extract_word_glo(&a,j,1); /* get bit to be transmitted */
163+
manchester = (one_bit << 1 | one_bit) ^ 2; /* transform to line code */
164+
/* now pass it to receiver MSB first, receiver must return -1 */
165+
ret = nav_msg_update_glo(&n, (manchester >> 1) & 1);
166+
fail_unless(ret == -1, "ret = %d, expected -1", ret);
167+
/* now LSB, receiver must return -1 */
168+
ret = nav_msg_update_glo(&n, manchester & 1);
169+
}
170+
/* try to decode the string */
171+
if (ret == 1) {
172+
fail_unless(memcmp(a.string_bits, n.string_bits, sizeof(a.string_bits)) == 0,
173+
"Received string %x%x%x not equal to trasmitted one %x%x%x",
174+
n.string_bits[2],n.string_bits[1],n.string_bits[0],
175+
a.string_bits[2],a.string_bits[1],a.string_bits[0]);
176+
177+
if(process_string_glo(&n, &e) == 1)
178+
e_out();
179+
}
180+
/* now pass time mark bit by bit to receiver (MSB first), no line code needed */
181+
for (u8 j = 30; j > 0; j--) {
182+
ret = nav_msg_update_glo(&n, (GLO_TM >> (j-1)) & 1);
183+
fail_unless(ret == -1, "ret = %d, expected -1", ret);
184+
}
185+
}
134186
}
135187
END_TEST
188+
136189
Suite* glo_decoder_test_suite(void)
137190
{
138191
Suite *s = suite_create("GLO decoder");
139192
TCase *tc_core = tcase_create("Core");
140193
tcase_add_test(tc_core, test_extract_glo_word);
141194
tcase_add_test(tc_core, test_process_string_glo);
195+
tcase_add_test(tc_core, test_nav_msg_update_glo);
142196
suite_add_tcase(s, tc_core);
143197

144198
return s;

0 commit comments

Comments
 (0)