18size_t len_octets(
size_t len)
28size_t write_len(uint8_t *p,
size_t len)
44 p[1] = (uint8_t)(len >> 8);
51size_t tlv(uint8_t tag,
const uint8_t *val,
size_t val_len, uint8_t *out,
size_t cap)
55 size_t k = 1 + len_octets(val_len);
56 size_t n = k + val_len;
60 write_len(out + 1, val_len);
67 memcpy(out + k, val, n - k);
72size_t int_content(uint32_t v, uint8_t *buf)
79 for (uint32_t x = v; x; x >>= 8)
80 tmp[t++] = (uint8_t)x;
82 if (tmp[t - 1] & 0x80)
84 for (
size_t i = 0; i < t; i++)
85 buf[k++] = tmp[t - 1 - i];
92bool ber_len(
const uint8_t *pdu,
size_t len,
size_t at,
size_t *value,
size_t *hdr)
100 if (nb == 0 || nb > 2 || at + 1 + nb > len)
103 for (
size_t i = 0; i < nb; i++)
104 v = (v << 8) | pdu[at + 1 + i];
114size_t detws_mms_read_request(uint32_t invoke_id,
const char *item_name, uint8_t *out,
size_t cap)
116 if (!out || !item_name)
118 size_t name_len = strnlen(item_name, 128 + 1);
125 uint8_t scratch[256];
127 size_t n = tlv(0x1A, (
const uint8_t *)item_name, name_len, scratch,
sizeof(scratch));
132 n = tlv(0xA0, scratch, n, a0,
sizeof(a0));
136 n = tlv(0x30, a0, n, scratch,
sizeof(scratch));
140 n = tlv(0xA0, scratch, n, a0,
sizeof(a0));
144 n = tlv(0xA1, a0, n, scratch,
sizeof(scratch));
148 n = tlv(Mms::MMS_SERVICE_READ, scratch, n, a0,
sizeof(a0));
154 size_t idlen = int_content(invoke_id, idc);
156 size_t bn = tlv(Mms::MMS_TAG_INVOKE_ID, idc, idlen, body,
sizeof(body));
157 if (!bn || bn + n >
sizeof(body))
159 memcpy(body + bn, a0, n);
161 return tlv(Mms::MMS_PDU_CONFIRMED_REQUEST, body, bn, out, cap);
164size_t detws_mms_read_response(uint32_t invoke_id,
const uint8_t *data,
size_t data_len, uint8_t *out,
size_t cap)
166 if (!out || (data_len && !data))
168 uint8_t scratch[256];
170 size_t n = tlv(0xA1, data, data_len, scratch,
sizeof(scratch));
175 n = tlv(Mms::MMS_SERVICE_READ, scratch, n, svc,
sizeof(svc));
180 size_t idlen = int_content(invoke_id, idc);
182 size_t bn = tlv(Mms::MMS_TAG_INVOKE_ID, idc, idlen, body,
sizeof(body));
183 if (!bn || bn + n >
sizeof(body))
185 memcpy(body + bn, svc, n);
187 return tlv(Mms::MMS_PDU_CONFIRMED_RESPONSE, body, bn, out, cap);
190bool detws_mms_parse(
const uint8_t *pdu,
size_t len, MmsPdu *out)
192 if (!pdu || !out || len < 2)
194 out->pdu_tag = pdu[0];
195 if (out->pdu_tag != Mms::MMS_PDU_CONFIRMED_REQUEST && out->pdu_tag != Mms::MMS_PDU_CONFIRMED_RESPONSE &&
196 out->pdu_tag != Mms::MMS_PDU_CONFIRMED_ERROR)
202 if (!ber_len(pdu, len, off, &body_len, &lhdr))
205 if (off + body_len > len)
209 if (off + 2 > len || pdu[off] != Mms::MMS_TAG_INVOKE_ID)
211 size_t idlen = pdu[off + 1];
212 if (idlen > 4 || off + 2 + idlen > len)
215 for (
size_t i = 0; i < idlen; i++)
216 id = (
id << 8) | pdu[off + 2 + i];
218 size_t p = off + 2 + idlen;
221 if (p < off + body_len && p < len)
223 out->service_tag = pdu[p];
227 if (!ber_len(pdu, len, sp, &slen, &hdr))
229 if (sp + hdr + slen > len)
231 out->service_body = pdu + sp + hdr;
232 out->service_len = slen;
236 out->service_tag = 0;
237 out->service_body =
nullptr;
238 out->service_len = 0;
IEC 61850 MMS (Manufacturing Message Specification) PDU codec (DETWS_ENABLE_MMS).