18size_t len_octets(
size_t len)
34size_t write_len(uint8_t *p,
size_t len)
51 p[1] = (uint8_t)(len >> 8);
57size_t tlv(uint8_t tag,
const uint8_t *val,
size_t val_len, uint8_t *out,
size_t cap)
61 size_t k = 1 + len_octets(val_len);
62 size_t n = k + val_len;
68 write_len(out + 1, val_len);
76 memcpy(out + k, val, n - k);
82size_t int_content(uint32_t v, uint8_t *buf)
92 for (uint32_t x = v; x; x >>= 8)
94 tmp[t++] = (uint8_t)x;
98 if (tmp[t - 1] & 0x80)
102 for (
size_t i = 0; i < t; i++)
104 buf[k++] = tmp[t - 1 - i];
112bool pc_ber_len(
const uint8_t *pdu,
size_t len,
size_t at,
size_t *value,
size_t *hdr)
121 size_t nb = v & 0x7F;
122 if (nb == 0 || nb > 2 || at + 1 + nb > len)
127 for (
size_t i = 0; i < nb; i++)
129 v = (v << 8) | pdu[at + 1 + i];
142size_t pc_mms_read_request(uint32_t invoke_id,
const char *item_name, uint8_t *out,
size_t cap)
144 if (!out || !item_name)
148 size_t name_len = strnlen(item_name, 128 + 1);
158 uint8_t scratch[256];
160 size_t n = tlv(0x1A, (
const uint8_t *)item_name, name_len, scratch,
sizeof(scratch));
167 n = tlv(0xA0, scratch, n, a0,
sizeof(a0));
173 n = tlv(0x30, a0, n, scratch,
sizeof(scratch));
179 n = tlv(0xA0, scratch, n, a0,
sizeof(a0));
185 n = tlv(0xA1, a0, n, scratch,
sizeof(scratch));
191 n = tlv(Mms::MMS_SERVICE_READ, scratch, n, a0,
sizeof(a0));
199 size_t idlen = int_content(invoke_id, idc);
201 size_t bn = tlv(Mms::MMS_TAG_INVOKE_ID, idc, idlen, body,
sizeof(body));
204 if (!bn || bn + n >
sizeof(body))
208 memcpy(body + bn, a0, n);
210 return tlv(Mms::MMS_PDU_CONFIRMED_REQUEST, body, bn, out, cap);
213size_t pc_mms_read_response(uint32_t invoke_id,
const uint8_t *data,
size_t data_len, uint8_t *out,
size_t cap)
215 if (!out || (data_len && !data))
219 uint8_t scratch[256];
221 size_t n = tlv(0xA1, data, data_len, scratch,
sizeof(scratch));
228 n = tlv(Mms::MMS_SERVICE_READ, scratch, n, svc,
sizeof(svc));
235 size_t idlen = int_content(invoke_id, idc);
237 size_t bn = tlv(Mms::MMS_TAG_INVOKE_ID, idc, idlen, body,
sizeof(body));
241 if (!bn || bn + n >
sizeof(body))
245 memcpy(body + bn, svc, n);
247 return tlv(Mms::MMS_PDU_CONFIRMED_RESPONSE, body, bn, out, cap);
250bool pc_mms_parse(
const uint8_t *pdu,
size_t len, MmsPdu *out)
252 if (!pdu || !out || len < 2)
256 out->pdu_tag = pdu[0];
257 if (out->pdu_tag != Mms::MMS_PDU_CONFIRMED_REQUEST && out->pdu_tag != Mms::MMS_PDU_CONFIRMED_RESPONSE &&
258 out->pdu_tag != Mms::MMS_PDU_CONFIRMED_ERROR)
266 if (!pc_ber_len(pdu, len, off, &body_len, &lhdr))
271 if (off + body_len > len)
277 if (off + 2 > len || pdu[off] != Mms::MMS_TAG_INVOKE_ID)
281 size_t idlen = pdu[off + 1];
282 if (idlen > 4 || off + 2 + idlen > len)
287 for (
size_t i = 0; i < idlen; i++)
289 id = (
id << 8) | pdu[off + 2 + i];
292 size_t p = off + 2 + idlen;
298 if (p < off + body_len && p < len)
300 out->service_tag = pdu[p];
304 if (!pc_ber_len(pdu, len, sp, &slen, &hdr))
308 if (sp + hdr + slen > len)
312 out->service_body = pdu + sp + hdr;
313 out->service_len = slen;
317 out->service_tag = 0;
318 out->service_body =
nullptr;
319 out->service_len = 0;
IEC 61850 MMS (Manufacturing Message Specification) PDU codec (PC_ENABLE_MMS).