ProtoCore v0.0.1
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
cip.h
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 cip.h
6 * @brief CIP (Common Industrial Protocol) message codec (PC_ENABLE_CIP) - zero-heap
7 * request builder + response parser for the message that rides inside an EtherNet/IP
8 * Unconnected Data item (services/fieldbus/enip). Together they form a working CIP read path.
9 *
10 * A CIP message request is:
11 * @code
12 * Service(1) RequestPathSize(1, in 16-bit words) RequestPath(EPATH) ServiceData
13 * @endcode
14 * The EPATH addresses an object with logical segments. A logical segment byte is
15 * `0x20 | logical-type | format`, where logical-type is class (0x00), instance (0x04), or
16 * attribute (0x10), and format is 8-bit (0x00, then a 1-octet id) or 16-bit (0x01, then a
17 * pad octet and a little-endian 2-octet id). A response is `Service|0x80 reserved(0)
18 * GeneralStatus(1) AdditionalStatusSize(1, words) [additional status] ServiceData`.
19 *
20 * Service codes + the logical-segment encoding are verified against the Wireshark CIP
21 * dissector. This codec is the CIP message; wrap it with `pc_eip_build_send_rr_data`.
22 *
23 * @author Douglas Quigg (dstroy0)
24 * @date 2026
25 */
26
27#ifndef PROTOCORE_CIP_H
28#define PROTOCORE_CIP_H
29
30#include "protocore_config.h"
31
32#if PC_ENABLE_CIP
33
34#include <stddef.h>
35#include <stdint.h>
36
37// Common service codes.
38#define CIP_SC_GET_ATTR_ALL 0x01
39#define CIP_SC_GET_ATTR_LIST 0x03
40#define CIP_SC_SET_ATTR_LIST 0x04
41#define CIP_SC_GET_ATTR_SINGLE 0x0E
42#define CIP_SC_SET_ATTR_SINGLE 0x10
43#define CIP_REPLY_FLAG 0x80 ///< OR'd into the service code in a reply
44
45// Logical-segment EPATH encoding (segment byte = base | logical-type | format).
46#define CIP_SEG_LOGICAL 0x20 ///< logical segment, segment-type bits
47#define CIP_SEG_CLASS 0x00 ///< logical type: class id
48#define CIP_SEG_INSTANCE 0x04 ///< logical type: instance id
49#define CIP_SEG_ATTRIBUTE 0x10 ///< logical type: attribute id
50#define CIP_SEG_8BIT 0x00 ///< format: an 8-bit id follows
51#define CIP_SEG_16BIT 0x01 ///< format: a pad octet then a 16-bit (LE) id follows
52
53#define CIP_STATUS_SUCCESS 0x00 ///< General Status: success
54
55/**
56 * @brief Build a class/instance[/attribute] EPATH (logical segments) into @p buf.
57 * @param with_attribute include the attribute segment.
58 * @return EPATH length in octets (always even / word-aligned), or 0 on overflow.
59 */
60size_t pc_cip_build_epath(uint8_t *buf, size_t cap, uint16_t class_id, uint16_t instance_id, uint16_t attribute_id,
61 bool with_attribute);
62
63/** @brief Build a CIP request: service + path size (words) + EPATH + service data. */
64size_t pc_cip_build_request(uint8_t *buf, size_t cap, uint8_t service, const uint8_t *epath, size_t epath_len,
65 const uint8_t *data, size_t data_len);
66
67/** @brief Build a Get_Attribute_Single request for class/instance/attribute. */
68size_t pc_cip_build_get_attr_single(uint8_t *buf, size_t cap, uint16_t class_id, uint16_t instance_id,
69 uint16_t attribute_id);
70
71/**
72 * @brief Build a Get_Attributes_All request for class/instance: service 0x01 over a class/instance EPATH with
73 * no attribute segment and no service data - reads every attribute of the object at once (e.g. the
74 * whole Identity object). @return the request length, or 0 on overflow.
75 */
76size_t pc_cip_build_get_attr_all(uint8_t *buf, size_t cap, uint16_t class_id, uint16_t instance_id);
77
78/**
79 * @brief Build a Set_Attribute_Single request for class/instance/attribute carrying @p value_len octets of
80 * attribute data (the value to write).
81 * @return the request length, or 0 on a null value with a nonzero length, or an overflow.
82 */
83size_t pc_cip_build_set_attr_single(uint8_t *buf, size_t cap, uint16_t class_id, uint16_t instance_id,
84 uint16_t attribute_id, const uint8_t *value, size_t value_len);
85
86/** @brief A parsed CIP response. @ref data points INTO the source buffer. */
87struct CipResponse
88{
89 uint8_t service; ///< reply service (the 0x80 reply bit is set)
90 uint8_t general_status; ///< CIP_STATUS_SUCCESS on success
91 const uint8_t *data; ///< service data (the attribute value on a read)
92 size_t data_len;
93};
94
95/** @brief Parse a CIP response (service + status + additional status + data). */
96bool pc_cip_parse_response(const uint8_t *buf, size_t len, CipResponse *out);
97
98#endif // PC_ENABLE_CIP
99
100#endif // PROTOCORE_CIP_H
User-facing configuration for ProtoCore.