16static uint8_t checksum(
const uint8_t *p,
size_t n)
19 for (
size_t i = 0; i < n; i++)
20 s = (uint8_t)(s + p[i]);
24size_t mbus_build_ack(uint8_t *buf,
size_t cap)
32size_t mbus_build_short(uint8_t *buf,
size_t cap, uint8_t c, uint8_t a)
36 buf[0] = MBUS_START_SHORT;
39 buf[3] = (uint8_t)(c + a);
44size_t mbus_build_long(uint8_t *buf,
size_t cap, uint8_t c, uint8_t a, uint8_t ci,
const uint8_t *data,
47 if (!buf || data_len > MBUS_MAX_DATA || (data_len && !data))
49 uint8_t L = (uint8_t)(3 + data_len);
50 size_t total = (size_t)6 + L;
53 buf[0] = MBUS_START_LONG;
56 buf[3] = MBUS_START_LONG;
61 memcpy(buf + 7, data, data_len);
62 buf[4 + L] = checksum(buf + 4, L);
63 buf[5 + L] = MBUS_STOP;
67size_t mbus_build_snd_nke(uint8_t *buf,
size_t cap, uint8_t a)
69 return mbus_build_short(buf, cap, MBUS_C_SND_NKE, a);
72size_t mbus_build_req_ud2(uint8_t *buf,
size_t cap, uint8_t a,
bool fcb)
74 return mbus_build_short(buf, cap, (uint8_t)(fcb ? 0x7Bu : MBUS_C_REQ_UD2), a);
77bool mbus_parse(
const uint8_t *buf,
size_t len, MbusFrame *out,
size_t *consumed)
79 if (!buf || !out || len < 1)
81 out->type = MbusFrameType::MBUS_FRAME_NONE;
82 out->c = out->a = out->ci = 0;
86 if (buf[0] == MBUS_ACK)
88 out->type = MbusFrameType::MBUS_FRAME_ACK;
93 if (buf[0] == MBUS_START_SHORT)
95 if (len < 5 || buf[4] != MBUS_STOP)
97 if (buf[3] != (uint8_t)(buf[1] + buf[2]))
99 out->type = MbusFrameType::MBUS_FRAME_SHORT;
106 if (buf[0] == MBUS_START_LONG)
111 if (L < 3 || buf[2] != L || buf[3] != MBUS_START_LONG)
113 size_t total = (size_t)6 + L;
114 if (len < total || buf[5 + L] != MBUS_STOP)
116 if (checksum(buf + 4, L) != buf[4 + L])
118 out->type = MbusFrameType::MBUS_FRAME_LONG;
122 out->data_len = (uint8_t)(L - 3);
123 out->data = out->data_len ? buf + 7 :
nullptr;
131uint8_t mbus_dif_data_len(uint8_t coding)
133 switch ((MbusDifCoding)(coding & 0x0Fu))
135 case MbusDifCoding::MBUS_DIF_NONE:
137 case MbusDifCoding::MBUS_DIF_INT8:
139 case MbusDifCoding::MBUS_DIF_INT16:
141 case MbusDifCoding::MBUS_DIF_INT24:
143 case MbusDifCoding::MBUS_DIF_INT32:
145 case MbusDifCoding::MBUS_DIF_REAL32:
147 case MbusDifCoding::MBUS_DIF_INT48:
149 case MbusDifCoding::MBUS_DIF_INT64:
151 case MbusDifCoding::MBUS_DIF_READOUT:
153 case MbusDifCoding::MBUS_DIF_BCD2:
155 case MbusDifCoding::MBUS_DIF_BCD4:
157 case MbusDifCoding::MBUS_DIF_BCD6:
159 case MbusDifCoding::MBUS_DIF_BCD8:
161 case MbusDifCoding::MBUS_DIF_VARIABLE:
163 case MbusDifCoding::MBUS_DIF_BCD12:
170bool mbus_record_next(
const uint8_t *body,
size_t len,
size_t *pos, MbusRecord *out)
172 if (!body || !pos || !out || *pos >= len)
175 uint8_t dif = body[p++];
176 uint8_t coding = (uint8_t)(dif & 0x0Fu);
188 out->coding = coding;
193 if (coding == (uint8_t)MbusDifCoding::MBUS_DIF_SPECIAL)
202 out->vif = body[p++];
212 if (coding == (uint8_t)MbusDifCoding::MBUS_DIF_VARIABLE)
216 uint8_t lvar = body[p++];
223 dlen = mbus_dif_data_len(coding);
228 out->data = dlen ? body + p :
nullptr;
229 out->data_len = dlen;
Wired M-Bus (Meter-Bus, EN 13757-2/-3) frame codec (DETWS_ENABLE_MBUS).