1+ #ifndef ETHERNET_IP_EXAMPLE_H
2+ #define ETHERNET_IP_EXAMPLE_H
3+
4+ #include "ptk_pdu_custom.h"
5+ #include <stdio.h>
6+
7+ /**
8+ * EtherNet/IP Protocol Example using Extended PDU System
9+ *
10+ * This demonstrates how to handle complex, variable-sized protocols
11+ * like EtherNet/IP with the extended PDU macro system.
12+ */
13+
14+ /**
15+ * Custom types for EtherNet/IP
16+ */
17+
18+ /* CIP Path - variable length routing path */
19+ typedef struct {
20+ uint8_t path_size ; // Size in 16-bit words
21+ uint8_t * path_data ; // Variable-length path data
22+ size_t capacity ; // Allocated capacity
23+ } cip_path_t ;
24+
25+ /* CIP Data - variable length application data */
26+ typedef struct {
27+ uint16_t data_length ;
28+ uint8_t * data ;
29+ size_t capacity ;
30+ } cip_data_t ;
31+
32+ /* CIP Service codes */
33+ typedef enum {
34+ CIP_SERVICE_GET_ATTRIBUTE_ALL = 0x01 ,
35+ CIP_SERVICE_SET_ATTRIBUTE_ALL = 0x02 ,
36+ CIP_SERVICE_GET_ATTRIBUTE_SINGLE = 0x0E ,
37+ CIP_SERVICE_SET_ATTRIBUTE_SINGLE = 0x10 ,
38+ CIP_SERVICE_MULTIPLE_SERVICE_PACKET = 0x0A
39+ } cip_service_t ;
40+
41+ /* CIP Status codes */
42+ typedef enum {
43+ CIP_STATUS_SUCCESS = 0x00 ,
44+ CIP_STATUS_CONNECTION_FAILURE = 0x01 ,
45+ CIP_STATUS_RESOURCE_UNAVAILABLE = 0x02 ,
46+ CIP_STATUS_INVALID_PARAMETER = 0x09 ,
47+ CIP_STATUS_PATH_SEGMENT_ERROR = 0x04
48+ } cip_status_t ;
49+
50+ /**
51+ * EtherNet/IP Encapsulation Header
52+ */
53+ #define PTK_PDU_FIELDS_enip_header (X ) \
54+ X(PTK_PDU_U16, command) \
55+ X(PTK_PDU_U16, length) \
56+ X(PTK_PDU_U32, session_handle) \
57+ X(PTK_PDU_U32, status) \
58+ X(PTK_PDU_U64, sender_context) \
59+ X(PTK_PDU_U32, options)
60+
61+ PTK_DECLARE_PDU (enip_header )
62+
63+ /**
64+ * CIP Request - demonstrates custom types
65+ */
66+ #define PTK_PDU_FIELDS_cip_request (X ) \
67+ X (PTK_PDU_U8 , service ) \
68+ X (PTK_PDU_CUSTOM , path , cip_path_t ) \
69+ X (PTK_PDU_CUSTOM , data , cip_data_t )
70+
71+ PTK_DECLARE_PDU_CUSTOM (cip_request )
72+
73+ /**
74+ * CIP Response with conditional error data
75+ */
76+ #define PTK_PDU_FIELDS_cip_response (X ) \
77+ X (PTK_PDU_U8 , service ) \
78+ X (PTK_PDU_U8 , reserved ) \
79+ X (PTK_PDU_U8 , general_status ) \
80+ X (PTK_PDU_U8 , additional_status_size ) \
81+ X (PTK_PDU_CONDITIONAL , general_status , 0x00 , PTK_PDU_CUSTOM , response_data , cip_data_t ) \
82+ X (PTK_PDU_CONDITIONAL , general_status , !0x00 , PTK_PDU_U16 , extended_status )
83+
84+ PTK_DECLARE_PDU_CUSTOM (cip_response )
85+
86+ /**
87+ * Multiple Service Packet - demonstrates arrays
88+ */
89+ typedef struct {
90+ uint16_t service_offset ;
91+ } service_offset_t ;
92+
93+ #define PTK_PDU_FIELDS_multiple_service_packet (X ) \
94+ X(PTK_PDU_U16, number_of_services) \
95+ X(PTK_PDU_ARRAY, service_offsets, service_offset_t, number_of_services) \
96+ /* Variable-length service data follows */
97+
98+ PTK_DECLARE_PDU_CUSTOM (multiple_service_packet )
99+
100+ /**
101+ * Forward/Open Request - complex EtherNet/IP example
102+ */
103+ #define PTK_PDU_FIELDS_forward_open_request (X ) \
104+ X (PTK_PDU_U8 , priority_tick_time ) \
105+ X (PTK_PDU_U8 , timeout_ticks ) \
106+ X (PTK_PDU_U32 , originator_to_target_connection_id ) \
107+ X (PTK_PDU_U32 , target_to_originator_connection_id ) \
108+ X (PTK_PDU_U16 , connection_serial_number ) \
109+ X (PTK_PDU_U16 , originator_vendor_id ) \
110+ X (PTK_PDU_U32 , originator_serial_number ) \
111+ X (PTK_PDU_U8 , connection_timeout_multiplier ) \
112+ X (PTK_PDU_U8 , reserved1 ) \
113+ X (PTK_PDU_U8 , reserved2 ) \
114+ X (PTK_PDU_U8 , reserved3 ) \
115+ X (PTK_PDU_U32 , originator_to_target_rpi ) \
116+ X (PTK_PDU_U16 , originator_to_target_connection_parameters ) \
117+ X (PTK_PDU_U32 , target_to_originator_rpi ) \
118+ X (PTK_PDU_U16 , target_to_originator_connection_parameters ) \
119+ X (PTK_PDU_U8 , transport_type_trigger ) \
120+ X (PTK_PDU_U8 , connection_path_size ) \
121+ X (PTK_PDU_CUSTOM , connection_path , cip_path_t )
122+
123+ PTK_DECLARE_PDU_CUSTOM (forward_open_request )
124+
125+ /**
126+ * Identity Object Response - demonstrates nested structures
127+ */
128+ typedef struct {
129+ uint16_t vendor_id ;
130+ uint16_t device_type ;
131+ uint16_t product_code ;
132+ uint8_t major_revision ;
133+ uint8_t minor_revision ;
134+ uint16_t status ;
135+ uint32_t serial_number ;
136+ uint8_t product_name_length ;
137+ char product_name [32 ];
138+ } identity_object_t ;
139+
140+ #define PTK_PDU_FIELDS_identity_response (X ) \
141+ X(PTK_PDU_CUSTOM, identity, identity_object_t)
142+
143+ PTK_DECLARE_PDU_CUSTOM (identity_response )
144+
145+ /**
146+ * Custom type implementations
147+ */
148+
149+ /* CIP Path functions */
150+ ptk_status_t cip_path_serialize (ptk_slice_bytes_t * slice , const cip_path_t * path , ptk_endian_t endian );
151+ ptk_status_t cip_path_deserialize (ptk_slice_bytes_t * slice , cip_path_t * path , ptk_endian_t endian );
152+ size_t cip_path_size (const cip_path_t * path );
153+ void cip_path_init (cip_path_t * path , size_t capacity );
154+ void cip_path_destroy (cip_path_t * path );
155+ void cip_path_print (const cip_path_t * path );
156+
157+ /* CIP Data functions */
158+ ptk_status_t cip_data_serialize (ptk_slice_bytes_t * slice , const cip_data_t * data , ptk_endian_t endian );
159+ ptk_status_t cip_data_deserialize (ptk_slice_bytes_t * slice , cip_data_t * data , ptk_endian_t endian );
160+ size_t cip_data_size (const cip_data_t * data );
161+ void cip_data_init (cip_data_t * data , size_t capacity );
162+ void cip_data_destroy (cip_data_t * data );
163+ void cip_data_print (const cip_data_t * data );
164+
165+ /* Identity Object functions */
166+ ptk_status_t identity_object_serialize (ptk_slice_bytes_t * slice , const identity_object_t * obj , ptk_endian_t endian );
167+ ptk_status_t identity_object_deserialize (ptk_slice_bytes_t * slice , identity_object_t * obj , ptk_endian_t endian );
168+ size_t identity_object_size (const identity_object_t * obj );
169+ void identity_object_init (identity_object_t * obj );
170+ void identity_object_destroy (identity_object_t * obj );
171+ void identity_object_print (const identity_object_t * obj );
172+
173+ /**
174+ * Helper functions for EtherNet/IP protocols
175+ */
176+
177+ /* Build a simple class/instance/attribute path */
178+ ptk_status_t cip_path_build_simple (cip_path_t * path , uint16_t class_id , uint16_t instance_id , uint16_t attribute_id );
179+
180+ /* Parse a CIP path and extract routing information */
181+ ptk_status_t cip_path_parse (const cip_path_t * path , uint16_t * class_id , uint16_t * instance_id , uint16_t * attribute_id );
182+
183+ /* Build CIP data from raw bytes */
184+ ptk_status_t cip_data_from_bytes (cip_data_t * data , const uint8_t * bytes , size_t length );
185+
186+ /* EtherNet/IP command constants */
187+ #define ENIP_CMD_NOP 0x0000
188+ #define ENIP_CMD_LIST_SERVICES 0x0004
189+ #define ENIP_CMD_LIST_IDENTITY 0x0063
190+ #define ENIP_CMD_LIST_INTERFACES 0x0064
191+ #define ENIP_CMD_REGISTER_SESSION 0x0065
192+ #define ENIP_CMD_UNREGISTER_SESSION 0x0066
193+ #define ENIP_CMD_SEND_RR_DATA 0x006F
194+ #define ENIP_CMD_SEND_UNIT_DATA 0x0070
195+
196+ /* EtherNet/IP status constants */
197+ #define ENIP_STATUS_SUCCESS 0x0000
198+ #define ENIP_STATUS_INVALID_COMMAND 0x0001
199+ #define ENIP_STATUS_INSUFFICIENT_MEMORY 0x0002
200+ #define ENIP_STATUS_INCORRECT_DATA 0x0003
201+ #define ENIP_STATUS_INVALID_SESSION 0x0064
202+ #define ENIP_STATUS_INVALID_LENGTH 0x0065
203+ #define ENIP_STATUS_UNSUPPORTED_PROTOCOL 0x0069
204+
205+ /**
206+ * Utility macros for common EtherNet/IP patterns
207+ */
208+
209+ /* Create a Get Attribute All request */
210+ #define ENIP_CREATE_GET_ATTR_ALL_REQUEST (class_id , instance_id ) \
211+ do { \
212+ cip_request_t request; \
213+ cip_request_init(&request); \
214+ request.service = CIP_SERVICE_GET_ATTRIBUTE_ALL; \
215+ cip_path_build_simple(&request.path, class_id, instance_id, 0); \
216+ cip_data_init(&request.data, 0); \
217+ } while(0)
218+
219+ /* Create an identity request */
220+ #define ENIP_CREATE_IDENTITY_REQUEST () \
221+ ENIP_CREATE_GET_ATTR_ALL_REQUEST(0x01, 0x01)
222+
223+ #endif /* ETHERNET_IP_EXAMPLE_H */
0 commit comments