DeterministicESPAsyncWebServer v6.28.0
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
profinet.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 profinet.cpp
6 * @brief PROFINET DCP frame codec (see profinet.h).
7 */
8
10
11#if DETWS_ENABLE_PROFINET
12
13#include <string.h>
14
15size_t detws_pn_dcp_header(uint16_t frame_id, uint8_t service_id, uint8_t service_type, uint32_t xid,
16 uint16_t data_length, uint8_t *out, size_t cap)
17{
18 if (!out || cap < Pn::PN_DCP_HDR_LEN)
19 return 0;
20 out[0] = (uint8_t)(frame_id >> 8);
21 out[1] = (uint8_t)frame_id;
22 out[2] = service_id;
23 out[3] = service_type;
24 out[4] = (uint8_t)(xid >> 24);
25 out[5] = (uint8_t)(xid >> 16);
26 out[6] = (uint8_t)(xid >> 8);
27 out[7] = (uint8_t)xid;
28 // octets 8..9 carry dataLength (the responseDelay of an Identify request shares this field slot).
29 out[8] = (uint8_t)(data_length >> 8);
30 out[9] = (uint8_t)data_length;
31 return Pn::PN_DCP_HDR_LEN;
32}
33
34size_t detws_pn_dcp_block(uint8_t option, uint8_t suboption, const uint8_t *value, size_t value_len, uint8_t *out,
35 size_t cap)
36{
37 if (!out || (value_len && !value) || value_len > 0xFFFF)
38 return 0;
39 bool pad = (value_len & 1) != 0; // pad to an even total length
40 size_t n = 4 + value_len + (pad ? 1 : 0);
41 if (n > cap)
42 return 0;
43 out[0] = option;
44 out[1] = suboption;
45 out[2] = (uint8_t)(value_len >> 8);
46 out[3] = (uint8_t)value_len;
47 if (value_len)
48 memcpy(out + 4, value, value_len);
49 if (pad)
50 out[4 + value_len] = 0x00;
51 return n;
52}
53
54bool detws_pn_dcp_parse_header(const uint8_t *frame, size_t len, PnDcpHeader *out)
55{
56 if (!frame || !out || len < Pn::PN_DCP_HDR_LEN)
57 return false;
58 out->frame_id = (uint16_t)((frame[0] << 8) | frame[1]);
59 out->service_id = frame[2];
60 out->service_type = frame[3];
61 out->xid = ((uint32_t)frame[4] << 24) | ((uint32_t)frame[5] << 16) | ((uint32_t)frame[6] << 8) | frame[7];
62 out->data_length = (uint16_t)((frame[8] << 8) | frame[9]);
63 return true;
64}
65
66bool detws_pn_dcp_walk(const uint8_t *blocks, size_t len, DetwsPnDcpBlockCb cb, void *arg)
67{
68 size_t off = 0;
69 while (off + 4 <= len)
70 {
71 uint8_t option = blocks[off];
72 uint8_t suboption = blocks[off + 1];
73 uint16_t blen = (uint16_t)((blocks[off + 2] << 8) | blocks[off + 3]);
74 if (off + 4 + blen > len)
75 return false;
76 if (cb)
77 cb(option, suboption, blen ? (blocks + off + 4) : nullptr, blen, arg);
78 size_t adv = 4 + blen + ((blen & 1) ? 1 : 0); // skip the even-pad filler
79 off += adv;
80 }
81 return true;
82}
83
84#endif // DETWS_ENABLE_PROFINET
PROFINET DCP (Discovery and Configuration Protocol) frame codec (DETWS_ENABLE_PROFINET).