|
| 1 | +/* |
| 2 | + * Copyright (C) 2016 Swift Navigation Inc. |
| 3 | + * Contact: Dmitry Tatarinov <[email protected]> |
| 4 | + * |
| 5 | + * This source is subject to the license found in the file 'LICENSE' which must |
| 6 | + * be be distributed together with this source. All other rights reserved. |
| 7 | + * |
| 8 | + * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, |
| 9 | + * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED |
| 10 | + * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. |
| 11 | + */ |
| 12 | +#include <assert.h> |
| 13 | +#include <string.h> |
| 14 | +#include <stdio.h> |
| 15 | +#include <math.h> |
| 16 | +#include <libswiftnav/nav_msg_glo.h> |
| 17 | +#include <libswiftnav/time.h> |
| 18 | + |
| 19 | +/* Word Ft (accuracy of measurements), refer to GLO ICD, Table 4.4 */ |
| 20 | +const float f_t[] = { 1.0f, 2.0f, 2.5f, 4.0f, 5.0f, 7.0f, 10.0f, 12.0f, 14.0f, |
| 21 | + 16.0f, 32.0f, 64.0f, 128.0f, 256.0f, 512.0f, -1.0f }; |
| 22 | + |
| 23 | +/* Word P1 (Time interval between adjacent values of tb, minutes), refer Table 4.3 */ |
| 24 | +const u8 p1[] = { 0, 30, 45, 60 }; /* min */ |
| 25 | + |
| 26 | +/** Initialize the necessary parts of the nav message state structure. |
| 27 | + * \param n Pointer to GLO nav message structure to be initialized |
| 28 | + */ |
| 29 | +void nav_msg_init_glo(nav_msg_glo_t *n) |
| 30 | +{ |
| 31 | + memset(n, 0, sizeof(nav_msg_glo_t)); |
| 32 | + n->next_string_id = 1; /* start parsing from string 1 */ |
| 33 | + n->state = SYNC_TM; |
| 34 | +} |
| 35 | + |
| 36 | +/** Extract a word of n_bits length (n_bits <= 32) at position bit_index into |
| 37 | + * the subframe. Refer to bit index to Table 4.6 and 4.11 in GLO ICD 5.1 (pg. 34) |
| 38 | + * \param n pointer to GLO nav message structure to be parsed |
| 39 | + * \param bit_index number of bit the extract process start with. Range [1..85] |
| 40 | + * \param n_bits how many bits should be extracted [1..32] |
| 41 | + * \return word extracted from navigation string |
| 42 | + */ |
| 43 | +u32 extract_word_glo(const nav_msg_glo_t *n, u16 bit_index, u8 n_bits) |
| 44 | +{ |
| 45 | + assert(n_bits <= 32 && n_bits > 0); |
| 46 | + assert(bit_index <= 85 && bit_index > 0); |
| 47 | + |
| 48 | + /* Extract a word of n_bits length (n_bits <= 32) at position bit_index into |
| 49 | + * the GLO string.*/ |
| 50 | + bit_index--; |
| 51 | + u32 word = 0; |
| 52 | + u8 bix_hi = bit_index >> 5; |
| 53 | + u8 bix_lo = bit_index & 0x1F; |
| 54 | + if (bix_lo + n_bits <= 32) { |
| 55 | + word = n->string_bits[bix_hi] >> bix_lo; |
| 56 | + word &= (0xffffffff << (32 - n_bits)) >> (32 - n_bits); |
| 57 | + } else { |
| 58 | + u8 s = 32 - bix_lo; |
| 59 | + word = extract_word_glo(n, bit_index + 1, s) |
| 60 | + | extract_word_glo(n, bit_index + 1 + s, n_bits - s) << s; |
| 61 | + } |
| 62 | + |
| 63 | + return word; |
| 64 | +} |
| 65 | + |
| 66 | +/** Navigation message GLO decoding update. |
| 67 | + * Called once per nav bit interval (10 ms). |
| 68 | + * Performs the necessary steps to store the nav bits in buffer. |
| 69 | + * |
| 70 | + * \param n GLO Nav message decode state struct |
| 71 | + * \param bit_val State of the nav bit to process, 0 or 1 |
| 72 | + * |
| 73 | + * \return 1 if Glo nav string ready for decoding, |
| 74 | + * -1 otherwise. |
| 75 | + */ |
| 76 | +s8 nav_msg_update_glo(nav_msg_glo_t *n, bool bit_val) |
| 77 | +{ |
| 78 | + s8 ret = -1; |
| 79 | + |
| 80 | + switch (n->state) { |
| 81 | + case SYNC_TM: /* try to find time mark */ |
| 82 | + /* put incoming bit at the tail of the buffer */ |
| 83 | + n->string_bits[0] <<= 1; /* use one word of buffer for that purpose */ |
| 84 | + n->string_bits[0] |= bit_val; |
| 85 | + /* collected bits match time mark? if not stay at this state */ |
| 86 | + if (extract_word_glo(n, 1, GLO_TM_LEN) == GLO_TM) { |
| 87 | + /* time mark found, next time start collecting data bits */ |
| 88 | + n->meander_bits_cnt = 0; |
| 89 | + n->manchester = 0; |
| 90 | + n->state = GET_DATA_BIT; |
| 91 | + n->string_bits[0] = 0; |
| 92 | + } |
| 93 | + break; |
| 94 | + case GET_DATA_BIT: /* collect data bits of string */ |
| 95 | + n->meander_bits_cnt++; |
| 96 | + n->manchester <<= 1; |
| 97 | + n->manchester |= bit_val; /* store incoming bit */ |
| 98 | + /* did we take 2 bits of line code? |
| 99 | + * if yes, remove meander and store bit in buffer, |
| 100 | + * if no, stay at the state */ |
| 101 | + if (n->meander_bits_cnt == 2) { |
| 102 | + /* shift whole buffer by 1 bit left */ |
| 103 | + for (u8 i = NAV_MSG_GLO_STRING_BITS_LEN - 1; i > 0; i--) { |
| 104 | + u32 tmp = (n->string_bits[i] << 1) |
| 105 | + | ((n->string_bits[i - 1] & (1 << 31)) >> 31); |
| 106 | + n->string_bits[i] = tmp; |
| 107 | + } |
| 108 | + n->string_bits[0] <<= 1; |
| 109 | + /* store bit after meander removal to buffer */ |
| 110 | + n->string_bits[0] |= (n->manchester ^ 2) & 1; |
| 111 | + n->current_head_bit_index++; |
| 112 | + n->meander_bits_cnt = 0; |
| 113 | + n->manchester = 0; |
| 114 | + /* did we received all bits of a string? |
| 115 | + * if yes, notify user and start searching time mark again*/ |
| 116 | + if (n->current_head_bit_index == 85) { |
| 117 | + n->current_head_bit_index = 0; |
| 118 | + n->state = SYNC_TM; |
| 119 | + ret = 1; |
| 120 | + } |
| 121 | + } |
| 122 | + break; |
| 123 | + default: |
| 124 | + nav_msg_init_glo(n); //TODO: probably not needed to initialize next_string_id |
| 125 | + break; |
| 126 | + } |
| 127 | + return ret; |
| 128 | +} |
| 129 | + |
| 130 | +/** The function decodes a GLO navigation string. |
| 131 | + * Assume we receive signal from GLONASS-M |
| 132 | + * \param n Pointer to nav_msg_glo_t structure which contains GLO string |
| 133 | + * \param e Pointer to Ephemeris to store |
| 134 | + * \return 0 - decode not completed, |
| 135 | + * 1 -- decode completed, all ephemeris data stored |
| 136 | + * <0 -- in case of an error. |
| 137 | + */ |
| 138 | +s8 process_string_glo(nav_msg_glo_t *n, ephemeris_t *e) |
| 139 | +{ |
| 140 | + /* Extract and check dummy bit from GLO string, bit 85 in GLO string */ |
| 141 | + if (extract_word_glo(n, 85, 1) != 0) { |
| 142 | + log_error("GLO dummy bit is not 0."); |
| 143 | + return -1; |
| 144 | + } |
| 145 | + /* Extract string number */ |
| 146 | + u32 m = extract_word_glo(n, 81, 4); |
| 147 | + u32 ret; |
| 148 | + u8 sign; |
| 149 | + /* is the string we need? */ |
| 150 | + if (n->next_string_id == m) { |
| 151 | + switch (m) { |
| 152 | + case 1: /* string 1 */ |
| 153 | + /* extract x */ |
| 154 | + ret = extract_word_glo(n, 9, 26); |
| 155 | + sign = extract_word_glo(n, 9 + 26, 1); |
| 156 | + e->glo.pos[0] = sign ? |
| 157 | + -1.0 * ret * pow(2, -11) * 1000.0 : ret * pow(2, -11) * 1000.0; |
| 158 | + /* extract Vx */ |
| 159 | + ret = extract_word_glo(n, 41, 23); |
| 160 | + sign = extract_word_glo(n, 41 + 23, 1); |
| 161 | + e->glo.vel[0] = sign ? |
| 162 | + -1.0 * ret * pow(2, -20) * 1000.0 : ret * pow(2, -20) * 1000.0; |
| 163 | + /* extract Ax */ |
| 164 | + ret = extract_word_glo(n, 36, 4); |
| 165 | + sign = extract_word_glo(n, 36 + 4, 1); |
| 166 | + e->glo.acc[0] = sign ? |
| 167 | + -1.0 * ret * pow(2, -30) * 1000.0 : ret * pow(2, -30) * 1000.0; |
| 168 | + /* extract tk */ |
| 169 | + n->hrs = (u8) extract_word_glo(n, 65, 5); |
| 170 | + n->min = (u8) extract_word_glo(n, 70, 6); |
| 171 | + n->sec = (u8) extract_word_glo(n, 76, 1); |
| 172 | + |
| 173 | + n->next_string_id = 2; |
| 174 | + break; |
| 175 | + case 2: /* string 2 */ |
| 176 | + /* extract y */ |
| 177 | + ret = extract_word_glo(n, 9, 26); |
| 178 | + sign = extract_word_glo(n, 9 + 26, 1); |
| 179 | + e->glo.pos[1] = sign ? |
| 180 | + -1.0 * ret * pow(2, -11) * 1000.0 : ret * pow(2, -11) * 1000.0; |
| 181 | + /* extract Vy */ |
| 182 | + ret = extract_word_glo(n, 41, 23); |
| 183 | + sign = extract_word_glo(n, 41 + 23, 1); |
| 184 | + e->glo.vel[1] = sign ? |
| 185 | + -1.0 * ret * pow(2, -20) * 1000.0 : ret * pow(2, -20) * 1000.0; |
| 186 | + /* extract Ay */ |
| 187 | + ret = extract_word_glo(n, 36, 4); |
| 188 | + sign = extract_word_glo(n, 36 + 4, 1); |
| 189 | + e->glo.acc[1] = sign ? |
| 190 | + -1.0 * ret * pow(2, -30) * 1000.0 : ret * pow(2, -30) * 1000.0; |
| 191 | + /* extract MSB of B (if the bit is clear the SV is OK ) */ |
| 192 | + e->healthy = extract_word_glo(n, 80, 1); |
| 193 | + /* extract P1 */ |
| 194 | + e->fit_interval = p1[extract_word_glo(n, 77, 2)]; |
| 195 | + |
| 196 | + n->next_string_id = 3; |
| 197 | + break; |
| 198 | + case 3: /* string 3 */ |
| 199 | + /* extract z */ |
| 200 | + ret = extract_word_glo(n, 9, 26); |
| 201 | + sign = extract_word_glo(n, 9 + 26, 1); |
| 202 | + e->glo.pos[2] = sign ? |
| 203 | + -1.0 * ret * pow(2, -11) * 1000.0 : ret * pow(2, -11) * 1000.0; |
| 204 | + /* extract Vz */ |
| 205 | + ret = extract_word_glo(n, 41, 23); |
| 206 | + sign = extract_word_glo(n, 41 + 23, 1); |
| 207 | + e->glo.vel[2] = sign ? |
| 208 | + -1.0 * ret * pow(2, -20) * 1000.0 : ret * pow(2, -20) * 1000.0; |
| 209 | + /* extract Az */ |
| 210 | + ret = extract_word_glo(n, 36, 4); |
| 211 | + sign = extract_word_glo(n, 36 + 4, 1); |
| 212 | + e->glo.acc[2] = sign ? |
| 213 | + -1.0 * ret * pow(2, -30) * 1000.0 : ret * pow(2, -30) * 1000.0; |
| 214 | + /* extract gamma */ |
| 215 | + ret = extract_word_glo(n, 69, 10); |
| 216 | + sign = extract_word_glo(n, 69 + 10, 1); |
| 217 | + e->glo.gamma = sign ? -1.0 * ret * pow(2, -40) : ret * pow(2, -40); |
| 218 | + /* extract l, if the it is clear the SV is OK, so OR it with B */ |
| 219 | + e->healthy |= extract_word_glo(n, 65, 1); |
| 220 | + |
| 221 | + n->next_string_id = 4; |
| 222 | + break; |
| 223 | + case 4: /* string 4 */ |
| 224 | + /* extract tau */ |
| 225 | + ret = extract_word_glo(n, 59, 21); |
| 226 | + sign = extract_word_glo(n, 59 + 21, 1); |
| 227 | + e->glo.tau = sign ? -1.0 * ret * pow(2, -30) : ret * pow(2, -30); |
| 228 | + /* extract n */ |
| 229 | + e->sid.sat = extract_word_glo(n, 11, 5); |
| 230 | + /* extract Ft (URA) */ |
| 231 | + e->ura = f_t[extract_word_glo(n, 30, 4)]; |
| 232 | + /*extract Nt*/ |
| 233 | + n->nt = (u16) extract_word_glo(n, 16, 11); |
| 234 | + |
| 235 | + n->next_string_id = 5; |
| 236 | + break; |
| 237 | + case 5: /* string 5 */ |
| 238 | + /* extract N4 */ |
| 239 | + n->n4 = (u8) extract_word_glo(n, 32, 5); |
| 240 | + |
| 241 | + n->next_string_id = 0; /* all string parsed */ |
| 242 | + break; |
| 243 | + default: |
| 244 | + break; |
| 245 | + } |
| 246 | + } |
| 247 | + /* all needed strings decoded? |
| 248 | + * fill ephemeris structure if we was not able to do it before*/ |
| 249 | + if (n->next_string_id == 0) { |
| 250 | + e->sid.code = CODE_GLO_L1CA; |
| 251 | + /* convert GLO TOE to GPS TOE */ |
| 252 | + e->toe = glo_time2gps_time(n->nt, n->n4, n->hrs, n->min, n->sec); |
| 253 | + e->healthy ^= 1; /* invert healthy bit */ |
| 254 | + e->valid = e->healthy; //NOTE: probably Valid needs to be defined by other way |
| 255 | + n->next_string_id = 1; /* start from string 1 */ |
| 256 | + return 1; |
| 257 | + } |
| 258 | + |
| 259 | + |
| 260 | + return 0; |
| 261 | +} |
0 commit comments