DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
melsec.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file melsec.cpp
6 * @brief Mitsubishi MELSEC MC binary 3E builder + parser (pure, host-tested).
7 */
8
10
11#if DETWS_ENABLE_MELSEC
12
13#include <string.h>
14
15// MC binary multi-octet fields are little-endian.
16static size_t put16le(uint8_t *p, uint16_t v)
17{
18 p[0] = (uint8_t)(v & 0xFF);
19 p[1] = (uint8_t)(v >> 8);
20 return 2;
21}
22
23static uint16_t get16le(const uint8_t *p)
24{
25 return (uint16_t)(p[0] | ((uint16_t)p[1] << 8));
26}
27
28size_t melsec_build_read(uint8_t *buf, size_t cap, uint8_t device_code, uint32_t head_device, uint16_t points,
29 uint16_t monitoring_timer)
30{
31 if (!buf || cap < MELSEC_3E_READ_REQ_LEN)
32 return 0;
33 size_t p = 0;
34 buf[p++] = MELSEC_3E_REQ_SUBHEADER0;
35 buf[p++] = MELSEC_3E_REQ_SUBHEADER1;
36 buf[p++] = MELSEC_NETWORK_DEFAULT;
37 buf[p++] = MELSEC_PC_DEFAULT;
38 p += put16le(buf + p, MELSEC_DEST_IO_DEFAULT);
39 buf[p++] = MELSEC_DEST_MULTIDROP_DEFAULT;
40 // request data length = the octets from the monitoring timer onward:
41 // timer(2) + command(2) + subcommand(2) + head device(3) + device code(1) + points(2) = 12
42 p += put16le(buf + p, MELSEC_3E_READ_REQ_DATA_LEN);
43 p += put16le(buf + p, monitoring_timer);
44 p += put16le(buf + p, MELSEC_CMD_BATCH_READ);
45 p += put16le(buf + p, MELSEC_SUBCMD_WORD);
46 buf[p++] = (uint8_t)(head_device & 0xFF); // head device number, 3 octets little-endian
47 buf[p++] = (uint8_t)((head_device >> 8) & 0xFF);
48 buf[p++] = (uint8_t)((head_device >> 16) & 0xFF);
49 buf[p++] = device_code;
50 p += put16le(buf + p, points);
51 return p; // == MELSEC_3E_READ_REQ_LEN
52}
53
54bool melsec_parse_response(const uint8_t *buf, size_t len, MelsecResponse *out)
55{
56 // subheader(2)+net(1)+pc(1)+io(2)+multidrop(1)+length(2)+endcode(2) = MELSEC_3E_RES_MIN_LEN
57 if (!buf || !out || len < MELSEC_3E_RES_MIN_LEN)
58 return false;
59 if (buf[0] != MELSEC_3E_RES_SUBHEADER0 || buf[1] != MELSEC_3E_RES_SUBHEADER1)
60 return false;
61 uint16_t data_length = get16le(buf + MELSEC_3E_RES_LEN_OFFSET); // covers the end code + the response data
62 if (data_length < MELSEC_ENDCODE_LEN)
63 return false;
64 if (MELSEC_3E_RES_DATALEN_BASE + (size_t)data_length > len)
65 return false;
66 out->end_code = get16le(buf + MELSEC_3E_RES_DATALEN_BASE);
67 out->data = buf + MELSEC_3E_RES_DATA_OFFSET;
68 out->data_len = (size_t)data_length - MELSEC_ENDCODE_LEN; // minus the 2-octet end code
69 return true;
70}
71
72#endif // DETWS_ENABLE_MELSEC
Mitsubishi MELSEC MC protocol (binary 3E frame) codec (DETWS_ENABLE_MELSEC) - zero-heap batch-read re...