11#if PC_ENABLE_NTRIP_CASTER
19uint32_t pc_rtcm3_crc24q(
const uint8_t *data,
size_t len)
22 for (
size_t i = 0; i < len; i++)
24 crc ^= (uint32_t)data[i] << 16;
25 for (
int b = 0; b < 8; b++)
34 return crc & 0xFFFFFFu;
41void pc_rtcm_bw_init(RtcmBitWriter *w, uint8_t *buf,
size_t cap)
44 w->cap_bits = cap * 8;
49void pc_rtcm_bw_u(RtcmBitWriter *w, uint64_t val, uint8_t nbits)
55 if (nbits == 0 || nbits > 64 || w->pos + nbits > w->cap_bits)
60 for (
int i = (
int)nbits - 1; i >= 0; i--)
65 w->buf[bp >> 3] |= (uint8_t)(0x80u >> (bp & 7u));
71void pc_rtcm_bw_s(RtcmBitWriter *w, int64_t val, uint8_t nbits)
73 uint64_t
mask = (nbits >= 64) ? ~0ULL : ((1ULL << nbits) - 1ULL);
74 pc_rtcm_bw_u(w, (uint64_t)val & mask, nbits);
77uint64_t pc_rtcm_br_u(
const uint8_t *buf,
size_t *pos, uint8_t nbits)
80 for (uint8_t i = 0; i < nbits; i++)
83 uint64_t bit = (buf[bp >> 3] >> (7u - (bp & 7u))) & 1u;
89int64_t pc_rtcm_br_s(
const uint8_t *buf,
size_t *pos, uint8_t nbits)
91 uint64_t v = pc_rtcm_br_u(buf, pos, nbits);
92 if (nbits < 64 && (v & (1ULL << (nbits - 1))))
94 v |= ~((1ULL << nbits) - 1ULL);
103size_t pc_rtcm3_sync(
const uint8_t *buf,
size_t len)
105 for (
size_t i = 0; i < len; i++)
107 if (buf[i] == RTCM3_PREAMBLE)
115size_t pc_rtcm3_frame_parse(
const uint8_t *buf,
size_t len, Rtcm3Frame *out)
117 if (len < RTCM3_HDR_LEN || buf[0] != RTCM3_PREAMBLE)
121 uint16_t payload_len = (uint16_t)(((buf[1] & 0x03u) << 8) | buf[2]);
122 size_t frame_len = (size_t)RTCM3_HDR_LEN + payload_len + RTCM3_CRC_LEN;
127 const uint8_t *payload = buf + RTCM3_HDR_LEN;
128 uint32_t crc_calc = pc_rtcm3_crc24q(buf, (
size_t)RTCM3_HDR_LEN + payload_len);
130 ((uint32_t)payload[payload_len] << 16) | ((uint32_t)payload[payload_len + 1] << 8) | payload[payload_len + 2];
133 out->payload = payload;
134 out->payload_len = payload_len;
135 out->crc_ok = (crc_calc == crc_frame);
137 out->msg_type = (payload_len >= 2) ? (uint16_t)pc_rtcm_br_u(payload, &p, 12) : 0;
142size_t pc_rtcm3_frame_build(uint8_t *out,
size_t cap,
const uint8_t *payload, uint16_t payload_len)
144 if (payload_len > RTCM3_MAX_PAYLOAD)
148 size_t frame_len = (size_t)RTCM3_HDR_LEN + payload_len + RTCM3_CRC_LEN;
149 if (!out || cap < frame_len)
153 out[0] = RTCM3_PREAMBLE;
154 out[1] = (uint8_t)((payload_len >> 8) & 0x03u);
155 out[2] = (uint8_t)(payload_len & 0xFFu);
156 if (payload_len && payload)
158 memcpy(out + RTCM3_HDR_LEN, payload, payload_len);
160 uint32_t crc = pc_rtcm3_crc24q(out, (
size_t)RTCM3_HDR_LEN + payload_len);
161 out[RTCM3_HDR_LEN + payload_len] = (uint8_t)((crc >> 16) & 0xFFu);
162 out[RTCM3_HDR_LEN + payload_len + 1] = (uint8_t)((crc >> 8) & 0xFFu);
163 out[RTCM3_HDR_LEN + payload_len + 2] = (uint8_t)(crc & 0xFFu);
173size_t build_arp(uint8_t *out,
size_t cap, uint16_t msg, uint16_t station_id, int64_t x, int64_t y, int64_t z,
174 bool with_h, uint16_t h)
177 memset(payload, 0,
sizeof payload);
179 pc_rtcm_bw_init(&w, payload,
sizeof payload);
180 pc_rtcm_bw_u(&w, msg, 12);
181 pc_rtcm_bw_u(&w, station_id & 0xFFF, 12);
182 pc_rtcm_bw_u(&w, 0, 6);
183 pc_rtcm_bw_u(&w, 1, 1);
184 pc_rtcm_bw_u(&w, 0, 1);
185 pc_rtcm_bw_u(&w, 0, 1);
186 pc_rtcm_bw_u(&w, 0, 1);
187 pc_rtcm_bw_s(&w, x, 38);
188 pc_rtcm_bw_u(&w, 0, 1);
189 pc_rtcm_bw_u(&w, 0, 1);
190 pc_rtcm_bw_s(&w, y, 38);
191 pc_rtcm_bw_u(&w, 0, 2);
192 pc_rtcm_bw_s(&w, z, 38);
193 uint16_t body_bytes = 19;
196 pc_rtcm_bw_u(&w, h, 16);
205 return pc_rtcm3_frame_build(out, cap, payload, body_bytes);
209size_t pc_rtcm3_build_1005(uint8_t *out,
size_t cap, uint16_t station_id, int64_t ecef_x_01mm, int64_t ecef_y_01mm,
212 return build_arp(out, cap, 1005, station_id, ecef_x_01mm, ecef_y_01mm, ecef_z_01mm,
false, 0);
215size_t pc_rtcm3_build_1006(uint8_t *out,
size_t cap, uint16_t station_id, int64_t ecef_x_01mm, int64_t ecef_y_01mm,
216 int64_t ecef_z_01mm, uint16_t antenna_height_01mm)
218 return build_arp(out, cap, 1006, station_id, ecef_x_01mm, ecef_y_01mm, ecef_z_01mm,
true, antenna_height_01mm);
221bool pc_rtcm3_parse_1005(
const uint8_t *payload, uint16_t payload_len, Rtcm3StationArp *out)
223 if (!payload || !out || payload_len < 19)
228 uint16_t msg = (uint16_t)pc_rtcm_br_u(payload, &p, 12);
229 if (msg != 1005 && msg != 1006)
233 if (msg == 1006 && payload_len < 21)
237 out->station_id = (uint16_t)pc_rtcm_br_u(payload, &p, 12);
238 pc_rtcm_br_u(payload, &p, 6);
239 pc_rtcm_br_u(payload, &p, 1);
240 pc_rtcm_br_u(payload, &p, 1);
241 pc_rtcm_br_u(payload, &p, 1);
242 pc_rtcm_br_u(payload, &p, 1);
243 out->ecef_x_01mm = pc_rtcm_br_s(payload, &p, 38);
244 pc_rtcm_br_u(payload, &p, 1);
245 pc_rtcm_br_u(payload, &p, 1);
246 out->ecef_y_01mm = pc_rtcm_br_s(payload, &p, 38);
247 pc_rtcm_br_u(payload, &p, 2);
248 out->ecef_z_01mm = pc_rtcm_br_s(payload, &p, 38);
251 out->antenna_height_01mm = (uint16_t)pc_rtcm_br_u(payload, &p, 16);
252 out->has_height =
true;
256 out->antenna_height_01mm = 0;
257 out->has_height =
false;
uint32_t mask(uint8_t width)
Mask of width low bits (width 32 handled without a 32-bit shift, which is UB).
RTCM 3.x framing + station-reference message codec (PC_ENABLE_NTRIP_CASTER).