15void pc_ubx_checksum(
const uint8_t *body,
size_t len, uint8_t *ck_a, uint8_t *ck_b)
18 for (
size_t i = 0; i < len; i++)
20 a = (uint8_t)(a + body[i]);
33size_t pc_ubx_build(uint8_t *buf,
size_t cap, uint8_t cls, uint8_t
id,
const uint8_t *payload, uint16_t len)
35 if (!buf || (len && !payload))
39 size_t total = 8u + (size_t)len;
45 buf[p++] = PC_UBX_SYNC1;
46 buf[p++] = PC_UBX_SYNC2;
49 buf[p++] = (uint8_t)(len & 0xFFu);
50 buf[p++] = (uint8_t)(len >> 8);
51 for (uint16_t i = 0; i < len; i++)
53 buf[p++] = payload[i];
56 pc_ubx_checksum(buf + 2, (
size_t)len + 4u, &a, &b);
62size_t pc_ubx_build_poll(uint8_t *buf,
size_t cap, uint8_t cls, uint8_t
id)
64 return pc_ubx_build(buf, cap, cls,
id,
nullptr, 0);
67bool pc_ubx_parse(
const uint8_t *s,
size_t len, pc_ubx *out)
69 if (!s || !out || len < 8)
73 if (s[0] != PC_UBX_SYNC1 || s[1] != PC_UBX_SYNC2)
77 uint16_t plen = (uint16_t)(s[4] | ((uint16_t)s[5] << 8));
78 if (len < 8u + (
size_t)plen)
83 pc_ubx_checksum(s + 2, (
size_t)plen + 4u, &a, &b);
84 if (a != s[6 + plen] || b != s[7 + plen])
95int pc_ubx_ack(
const pc_ubx *m, uint8_t *acked_cls, uint8_t *acked_id)
97 if (!m || m->cls != 0x05u || m->len < 2 || !m->payload)
101 if (m->id != 0x00u && m->id != 0x01u)
107 *acked_cls = m->payload[0];
111 *acked_id = m->payload[1];
113 return m->id == 0x01u ? 1 : 0;
116uint16_t pc_ubx_u16(
const uint8_t *p,
size_t off)
118 return (uint16_t)(p[off] | ((uint16_t)p[off + 1] << 8));
121uint32_t pc_ubx_u32(
const uint8_t *p,
size_t off)
123 return (uint32_t)p[off] | ((uint32_t)p[off + 1] << 8) | ((uint32_t)p[off + 2] << 16) | ((uint32_t)p[off + 3] << 24);
126int16_t pc_ubx_i16(
const uint8_t *p,
size_t off)
128 return (int16_t)pc_ubx_u16(p, off);
131int32_t pc_ubx_i32(
const uint8_t *p,
size_t off)
133 return (int32_t)pc_ubx_u32(p, off);
136bool pc_ubx_parse_nav_pvt(
const pc_ubx *m, pc_ubx_nav_pvt *out)
138 if (!m || !out || !m->payload)
142 if (m->cls != PC_UBX_CLASS_NAV || m->id != PC_UBX_NAV_PVT || m->len < PC_UBX_NAV_PVT_LEN)
146 const uint8_t *p = m->payload;
147 out->itow_ms = pc_ubx_u32(p, 0);
148 out->year = pc_ubx_u16(p, 4);
155 out->time_acc_ns = pc_ubx_u32(p, 12);
156 out->nano = pc_ubx_i32(p, 16);
157 out->fix_type = p[20];
160 out->lon_1e7 = pc_ubx_i32(p, 24);
161 out->lat_1e7 = pc_ubx_i32(p, 28);
162 out->height_mm = pc_ubx_i32(p, 32);
163 out->hmsl_mm = pc_ubx_i32(p, 36);
164 out->h_acc_mm = pc_ubx_u32(p, 40);
165 out->v_acc_mm = pc_ubx_u32(p, 44);
166 out->vel_n_mm_s = pc_ubx_i32(p, 48);
167 out->vel_e_mm_s = pc_ubx_i32(p, 52);
168 out->vel_d_mm_s = pc_ubx_i32(p, 56);
169 out->gspeed_mm_s = pc_ubx_i32(p, 60);
170 out->head_mot_1e5 = pc_ubx_i32(p, 64);
171 out->s_acc_mm_s = pc_ubx_u32(p, 68);
172 out->head_acc_1e5 = pc_ubx_u32(p, 72);
173 out->pdop_1e2 = pc_ubx_u16(p, 76);
178static bool ubx_nav_sat_ok(
const pc_ubx *m, uint8_t *num_svs_out)
180 if (!m || !m->payload || m->cls != PC_UBX_CLASS_NAV || m->id != PC_UBX_NAV_SAT)
184 if (m->len < PC_UBX_NAV_SAT_HDR_LEN)
188 uint8_t num = m->payload[5];
189 if ((
size_t)m->len < (
size_t)PC_UBX_NAV_SAT_HDR_LEN + (
size_t)num * PC_UBX_NAV_SAT_ENTRY_LEN)
200bool pc_ubx_parse_nav_sat(
const pc_ubx *m, pc_ubx_nav_sat_hdr *out)
203 if (!out || !ubx_nav_sat_ok(m, &num))
207 out->itow_ms = pc_ubx_u32(m->payload, 0);
208 out->version = m->payload[4];
213bool pc_ubx_nav_sat_get(
const pc_ubx *m, uint8_t index, pc_ubx_sat *out)
216 if (!out || !ubx_nav_sat_ok(m, &num) || index >= num)
220 const uint8_t *p = m->payload + PC_UBX_NAV_SAT_HDR_LEN + (size_t)index * PC_UBX_NAV_SAT_ENTRY_LEN;
223 out->cno_dbhz = p[2];
224 out->elev_deg = (int8_t)p[3];
225 out->azim_deg = pc_ubx_i16(p, 4);
226 out->pr_res_01m = pc_ubx_i16(p, 6);
227 out->flags = pc_ubx_u32(p, 8);
231bool pc_ubx_parse_nav_timeutc(
const pc_ubx *m, pc_ubx_nav_time_utc *out)
233 if (!m || !out || !m->payload)
237 if (m->cls != PC_UBX_CLASS_NAV || m->id != PC_UBX_NAV_TIMEUTC || m->len < PC_UBX_NAV_TIMEUTC_LEN)
241 const uint8_t *p = m->payload;
242 out->itow_ms = pc_ubx_u32(p, 0);
243 out->time_acc_ns = pc_ubx_u32(p, 4);
244 out->nano = pc_ubx_i32(p, 8);
245 out->year = pc_ubx_u16(p, 12);
252 out->utc_valid = (p[19] & PC_UBX_TIMEUTC_VALID_UTC) != 0;
256size_t pc_ubx_build_cfg_msg(uint8_t *buf,
size_t cap, uint8_t cls, uint8_t
id, uint8_t rate)
258 const uint8_t pl[3] = {cls, id, rate};
259 return pc_ubx_build(buf, cap, PC_UBX_CLASS_CFG, PC_UBX_CFG_MSG, pl,
sizeof(pl));
262size_t pc_ubx_build_cfg_rate(uint8_t *buf,
size_t cap, uint16_t meas_rate_ms, uint16_t nav_rate, uint16_t time_ref)
265 const uint8_t pl[6] = {(uint8_t)meas_rate_ms, (uint8_t)(meas_rate_ms >> 8),
266 (uint8_t)nav_rate, (uint8_t)(nav_rate >> 8),
267 (uint8_t)time_ref, (uint8_t)(time_ref >> 8)};
268 return pc_ubx_build(buf, cap, PC_UBX_CLASS_CFG, PC_UBX_CFG_RATE, pl,
sizeof(pl));
287void pc_ubx_stream_init(pc_ubx_stream *st)
291 memset(st, 0,
sizeof(*st));
295static void ck_add(pc_ubx_stream *st, uint8_t b)
297 st->ck_a = (uint8_t)(st->ck_a + b);
298 st->ck_b = (uint8_t)(st->ck_b + st->ck_a);
303static int ubx_feed_sync(pc_ubx_stream *st, uint8_t b, uint8_t *passthrough)
305 if (st->state == S_SYNC1)
307 if (b == PC_UBX_SYNC1)
316 return PC_UBX_PASSTHROUGH;
319 if (b == PC_UBX_SYNC2)
325 if (b == PC_UBX_SYNC1)
334 return PC_UBX_PASSTHROUGH;
337int pc_ubx_stream_feed(pc_ubx_stream *st, uint8_t b, pc_ubx *out, uint8_t *passthrough)
343 if (st->state == S_SYNC1 || st->state == S_SYNC2)
345 return ubx_feed_sync(st, b, passthrough);
358 st->state = S_LEN_LO;
363 st->state = S_LEN_HI;
366 st->len = (uint16_t)(st->len | ((uint16_t)b << 8));
369 if (st->len > PC_UBX_MAX_PAYLOAD)
371 st->skip = (uint32_t)st->len + 2u;
375 st->state = (st->len == 0) ? S_CK_A : S_PAYLOAD;
378 st->buf[st->idx++] = b;
380 if (st->idx >= st->len)
391 if (st->rx_ck_a == st->ck_a && b == st->ck_b)
398 out->payload = st->buf;
408 return PC_UBX_OVERFLOW;
u-blox UBX binary protocol codec (PC_ENABLE_UBX) - the GNSS receiver control/nav protocol.