11#if DETWS_ENABLE_C37118
15uint16_t c37118_crc(
const uint8_t *data,
size_t len)
17 uint16_t crc = 0xFFFF;
18 for (
size_t i = 0; i < len; i++)
20 crc ^= (uint16_t)data[i] << 8;
21 for (
int b = 0; b < 8; b++)
22 crc = (crc & 0x8000) ? (uint16_t)((crc << 1) ^ 0x1021) : (uint16_t)(crc << 1);
27static size_t put16(uint8_t *p, uint16_t v)
29 p[0] = (uint8_t)(v >> 8);
34static size_t put32(uint8_t *p, uint32_t v)
36 p[0] = (uint8_t)(v >> 24);
37 p[1] = (uint8_t)(v >> 16);
38 p[2] = (uint8_t)(v >> 8);
43static uint16_t get16(
const uint8_t *p)
45 return (uint16_t)(((uint16_t)p[0] << 8) | p[1]);
48static uint32_t get32(
const uint8_t *p)
50 return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | p[3];
53size_t c37118_build_frame(uint8_t *buf,
size_t cap, uint8_t type, uint8_t version, uint16_t idcode, uint32_t soc,
54 uint32_t fracsec,
const uint8_t *payload,
size_t payload_len)
56 if (!buf || (payload_len && !payload))
58 size_t total = C37118_MIN_FRAME + payload_len;
59 if (total > 0xFFFF || total > cap)
62 buf[p++] = C37118_SYNC_LEADER;
63 buf[p++] = (uint8_t)(((type & C37118_TYPE_MASK) << C37118_TYPE_SHIFT) | (version & C37118_VERSION_MASK));
64 p += put16(buf + p, (uint16_t)total);
65 p += put16(buf + p, idcode);
66 p += put32(buf + p, soc);
67 p += put32(buf + p, fracsec);
70 memcpy(buf + p, payload, payload_len);
73 uint16_t crc = c37118_crc(buf, p);
74 p += put16(buf + p, crc);
78size_t c37118_build_command(uint8_t *buf,
size_t cap, uint16_t idcode, uint32_t soc, uint32_t fracsec, uint16_t cmd)
82 return c37118_build_frame(buf, cap, C37118_TYPE_CMD, C37118_VERSION_2011, idcode, soc, fracsec, payload, 2);
85bool c37118_parse_frame(
const uint8_t *buf,
size_t len, C37118Frame *out)
87 if (!buf || !out || len < C37118_MIN_FRAME)
89 if (buf[0] != C37118_SYNC_LEADER)
91 uint16_t framesize = get16(buf + 2);
92 if (framesize < C37118_MIN_FRAME || framesize > len)
94 uint16_t want = c37118_crc(buf, (
size_t)framesize - 2);
95 uint16_t got = get16(buf + framesize - 2);
98 out->type = (uint8_t)((buf[1] >> C37118_TYPE_SHIFT) & C37118_TYPE_MASK);
99 out->version = (uint8_t)(buf[1] & C37118_VERSION_MASK);
100 out->framesize = framesize;
101 out->idcode = get16(buf + 4);
102 out->soc = get32(buf + 6);
103 out->fracsec = get32(buf + 10);
104 out->data = buf + 14;
105 out->data_len = (size_t)framesize - C37118_MIN_FRAME;
109bool c37118_parse_command(
const C37118Frame *f, uint16_t *cmd)
111 if (!f || f->type != C37118_TYPE_CMD || f->data_len < 2)
114 *cmd = get16(f->data);
IEEE C37.118.2 synchrophasor frame codec (DETWS_ENABLE_C37118) - zero-heap frame builder + parser for...