DeterministicESPAsyncWebServer v6.28.0
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
hart.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 hart.cpp
6 * @brief HART / HART-IP protocol codec (see hart.h).
7 */
8
10
11#if DETWS_ENABLE_HART
12
13#include <string.h>
14
15uint8_t detws_hart_checksum(const uint8_t *bytes, size_t len)
16{
17 uint8_t x = 0;
18 for (size_t i = 0; i < len; i++)
19 x ^= bytes[i];
20 return x;
21}
22
23size_t detws_hart_build(uint8_t delimiter, const uint8_t *addr, size_t addr_len, uint8_t command, const uint8_t *data,
24 size_t data_len, uint8_t *out, size_t cap)
25{
26 if (addr_len != 1 && addr_len != 5)
27 return 0;
28 if (!addr || (data_len && !data))
29 return 0;
30 // delimiter + addr + command + byte-count + data + checksum
31 size_t n = 1 + addr_len + 1 + 1 + data_len + 1;
32 if (n > cap || data_len > 0xFF)
33 return 0;
34
35 size_t i = 0;
36 out[i++] = delimiter;
37 memcpy(out + i, addr, addr_len);
38 i += addr_len;
39 out[i++] = command;
40 out[i++] = (uint8_t)data_len; // byte count
41 if (data_len)
42 {
43 memcpy(out + i, data, data_len);
44 i += data_len;
45 }
46 out[i] = detws_hart_checksum(out, i); // XOR over delimiter..last data byte
47 i++;
48 return i;
49}
50
51bool detws_hart_parse(const uint8_t *frame, size_t len, HartFrame *out)
52{
53 if (!frame || !out)
54 return false;
55 size_t addr_len = (frame[0] & HartDelim::HART_DELIM_LONG_ADDR) ? 5 : 1;
56 // delimiter + addr + command + byte-count + checksum = minimum with no data
57 size_t min = 1 + addr_len + 1 + 1 + 1;
58 if (len < min)
59 return false;
60
61 size_t bc_idx = 1 + addr_len + 1; // index of the byte-count field
62 uint8_t byte_count = frame[bc_idx];
63 size_t expect = 1 + addr_len + 1 + 1 + byte_count + 1; // full frame incl checksum
64 if (len < expect)
65 return false;
66
67 uint8_t want = detws_hart_checksum(frame, expect - 1);
68 if (want != frame[expect - 1])
69 return false;
70
71 out->delimiter = frame[0];
72 out->addr = frame + 1;
73 out->addr_len = addr_len;
74 out->command = frame[1 + addr_len];
75 out->byte_count = byte_count;
76 out->data = byte_count ? (frame + bc_idx + 1) : nullptr;
77 out->data_len = byte_count;
78 return true;
79}
80
81size_t detws_hartip_build_header(uint8_t msg_type, uint8_t msg_id, uint8_t status, uint16_t seq, uint16_t total_len,
82 uint8_t *out, size_t cap)
83{
84 if (cap < HartIp::HARTIP_HEADER_LEN || !out)
85 return 0;
86 out[0] = 1; // HART-IP protocol version
87 out[1] = msg_type;
88 out[2] = msg_id;
89 out[3] = status;
90 out[4] = (uint8_t)(seq >> 8);
91 out[5] = (uint8_t)seq;
92 out[6] = (uint8_t)(total_len >> 8);
93 out[7] = (uint8_t)total_len;
94 return HartIp::HARTIP_HEADER_LEN;
95}
96
97#endif // DETWS_ENABLE_HART
HART / HART-IP process-instrument protocol codec (DETWS_ENABLE_HART).