ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
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 PC_ENABLE_PROFINET
12
13#include <string.h>
14
15size_t pc_pn_dcp_header(uint16_t frame_id, uint8_t service_id, uint8_t service_type, uint32_t xid, uint16_t data_length,
16 uint8_t *out, size_t cap)
17{
18 if (!out || cap < Pn::PN_DCP_HDR_LEN)
19 {
20 return 0;
21 }
22 out[0] = (uint8_t)(frame_id >> 8);
23 out[1] = (uint8_t)frame_id;
24 out[2] = service_id;
25 out[3] = service_type;
26 out[4] = (uint8_t)(xid >> 24);
27 out[5] = (uint8_t)(xid >> 16);
28 out[6] = (uint8_t)(xid >> 8);
29 out[7] = (uint8_t)xid;
30 // octets 8..9 carry dataLength (the responseDelay of an Identify request shares this field slot).
31 out[8] = (uint8_t)(data_length >> 8);
32 out[9] = (uint8_t)data_length;
33 return Pn::PN_DCP_HDR_LEN;
34}
35
36size_t pc_pn_dcp_block(uint8_t option, uint8_t suboption, const uint8_t *value, size_t value_len, uint8_t *out,
37 size_t cap)
38{
39 if (!out || (value_len && !value) || value_len > 0xFFFF)
40 {
41 return 0;
42 }
43 bool pad = (value_len & 1) != 0; // pad to an even total length
44 size_t n = 4 + value_len + (pad ? 1 : 0);
45 if (n > cap)
46 {
47 return 0;
48 }
49 out[0] = option;
50 out[1] = suboption;
51 out[2] = (uint8_t)(value_len >> 8);
52 out[3] = (uint8_t)value_len;
53 if (value_len)
54 {
55 memcpy(out + 4, value, value_len);
56 }
57 if (pad)
58 {
59 out[4 + value_len] = 0x00;
60 }
61 return n;
62}
63
64bool pc_pn_dcp_parse_header(const uint8_t *frame, size_t len, PnDcpHeader *out)
65{
66 if (!frame || !out || len < Pn::PN_DCP_HDR_LEN)
67 {
68 return false;
69 }
70 out->frame_id = (uint16_t)((frame[0] << 8) | frame[1]);
71 out->service_id = frame[2];
72 out->service_type = frame[3];
73 out->xid = ((uint32_t)frame[4] << 24) | ((uint32_t)frame[5] << 16) | ((uint32_t)frame[6] << 8) | frame[7];
74 out->data_length = (uint16_t)((frame[8] << 8) | frame[9]);
75 return true;
76}
77
78bool pc_pn_dcp_walk(const uint8_t *blocks, size_t len, pc_pn_dcp_block_cb cb, void *arg)
79{
80 size_t off = 0;
81 while (off + 4 <= len)
82 {
83 uint8_t option = blocks[off];
84 uint8_t suboption = blocks[off + 1];
85 uint16_t blen = (uint16_t)((blocks[off + 2] << 8) | blocks[off + 3]);
86 if (off + 4 + blen > len)
87 {
88 return false;
89 }
90 if (cb)
91 {
92 cb(option, suboption, blen ? (blocks + off + 4) : nullptr, blen, arg);
93 }
94 size_t adv = 4 + blen + ((blen & 1) ? 1 : 0); // skip the even-pad filler
95 off += adv;
96 }
97 return true;
98}
99
100#endif // PC_ENABLE_PROFINET
PROFINET DCP (Discovery and Configuration Protocol) frame codec (PC_ENABLE_PROFINET).