Messaging#
Addressing (EPATH), Message Router requests/replies (explicit messaging, including Multiple_Service_Packet), Connection Manager services (Forward_Open/Forward_Close/Unconnected_Send), and Class 0/1 cyclic I/O.
CIP EPATH segment codecs.
- class icspacket.proto.cip.epath.EPATH(*segments: PortSegment | LogicalSegment | NetworkSegment | DataSegment | ElectronicKeySegment | SymbolicSegment)#
A sequence of CIP path segments.
paddedfollows the normal CIP path representation: each segment ends on a 16-bit boundary.packedis accepted as a convenience alias for the unpadded representation used by a few encapsulating services.- classmethod from_bytes(data: bytes, *, padded: bool = True, packed: bool | None = None, length: int | None = None) Self#
Decode a padded or packed EPATH byte string.
- to_bytes(*, padded: bool = True, packed: bool | None = None) bytes#
Encode the path as padded or packed EPATH bytes.
- property word_length: int#
Length of the padded EPATH in 16-bit words.
- class icspacket.proto.cip.epath.DataSegment(*, tag: int = 128, words: int = 0, data: bytes = b'')#
Simple data segment (See CIP Volume 1, §3.5.7).
wordscountsdatain 16-bit words, sodatais always word-aligned. A trailing zero octet is indistinguishable from a genuine data byte once round-tripped -new()pads an odd-length input itself, matching the wire format’s own inability to carry the original, pre-padding byte count.- static new(data: bytes) DataSegment#
Builds a data segment, padding odd-length input to a whole word.
- class icspacket.proto.cip.epath.ElectronicKeySegment(*, tag: int = 52, key_format: int = 4, vendor_id: int = 0, device_type: int = 0, product_code: int = 0, major_revision: int = 0, minor_revision: int = 0)#
Electronic key segment (See CIP Volume 1, §3.5.8).
- class icspacket.proto.cip.epath.LogicalSegment(s_type: int = 1, logical_type: LogicalType = LogicalType.CLASS, format_bits: int = 0, value: int = 0)#
Logical segment for class, instance, member, and related identifiers.
(See CIP Volume 1, §3.5.3.)
format_bitsselectsvalue’s wire width (0/1/2for 8-/16-/32-bit). Usenew()or one of the per-kind factories below instead of settingformat_bitsdirectly - they derive it from a plainwidthin octets, or pick the narrowest fit automatically whenwidthis omitted.- static attribute_id(value: int, width: int | None = None) LogicalSegment#
Construct an Attribute ID logical segment.
- static class_id(value: int, width: int | None = None) LogicalSegment#
Construct a Class ID logical segment.
- static connection_point(value: int, width: int | None = None) LogicalSegment#
Construct a Connection Point logical segment.
- static instance_id(value: int, width: int | None = None) LogicalSegment#
Construct an Instance ID logical segment.
- static member_id(value: int, width: int | None = None) LogicalSegment#
Construct a Member ID logical segment.
- static new(kind: LogicalType | int, value: int, width: int | None = None) LogicalSegment#
Builds a logical segment, auto-selecting the narrowest value width.
- static service_id(value: int, width: int | None = None) LogicalSegment#
Construct a Service ID logical segment.
- static special(value: int, width: int | None = None) LogicalSegment#
Construct a Special logical segment.
- property width: int#
The width of
valueon the wire, in octets.
- class icspacket.proto.cip.epath.LogicalType(*values)#
Logical segment identifier (See CIP Volume 1, §3.5.3).
- class icspacket.proto.cip.epath.NetworkSegment(s_type: int = 2, subtype: int = 0, words: int | None = None, data: bytes = b'')#
Network segment with a subtype and opaque network-specific data.
(See CIP Volume 1, §3.5.4.) A
subtypebelow0x10(“fixed”) always carries exactly one data octet with no length prefix;0x10and above (“variable”) is preceded by awordsoctet counting the trailingdatain 16-bit words.- static new(subtype: int, data: bytes = b'') NetworkSegment#
Builds a network segment from a subtype and its payload.
- class icspacket.proto.cip.epath.PortSegment(s_type: int = 0, ext_link: bool = False, port_low: int = 0, ext_len: int | None = None, ext_port: int | None = None, link_address: bytes = b'\x00')#
Port segment, including short and extended link addresses.
(See CIP Volume 1, §3.5.5.2.)
port_lowequal to0x0Fis a reserved marker meaning the real port number is carried in the following 16-bitext_portfield instead of these 4 bits;ext_linkmarks a length-prefixed variable link address instead of the fixed single octet.This class does not subclass
Segment– a@bitfieldmodel can never be a frozen dataclass, andSegmentis frozen – but it carries the sameTYPE_IDtagEPATHdispatches on, andStructDefMixingives itto_bytes()/from_bytes()directly, with no separate encode/decode step.- static new(port_id: int, link_address: int | bytes = 0) PortSegment#
Builds a port segment from a
(port_id, link_address)pair.
- property port_id: int#
The logical port number, reassembled from
port_low/ext_port.
- class icspacket.proto.cip.epath.SymbolicSegment(*, tag: int = 145, value: bytes = b'')#
ANSI extended symbolic segment (See CIP Volume 1, §3.5.6).
- static new(symbol: str | bytes) SymbolicSegment#
Builds a symbolic segment from a
stror rawbytesname.
- property symbol: str | bytes#
The symbol name, decoded as ASCII when possible.
- icspacket.proto.cip.epath.decode_epath(data: bytes, *, padded: bool = True, packed: bool | None = None, length: int | None = None) EPATH#
Decode an EPATH byte string into segment objects.
- icspacket.proto.cip.epath.encode_epath(*segments: PortSegment | LogicalSegment | NetworkSegment | DataSegment | ElectronicKeySegment | SymbolicSegment, padded: bool = True, packed: bool | None = None) bytes#
Encode segments into an EPATH byte string.
[ODVA CIP Vol 1] CIP Message Router request and response codecs.
The layouts implemented here are defined according to CIP Volume 1, clause 2-4, Tables 2-4.1 and 2-4.2.
- class icspacket.proto.cip.msgrouter.MessageRouterRequest(*, service: int = 0, path_size: int = 0, path: bytes = b'', request_data: bytes = b'')[source]#
A Message Router request (See CIP Vol 1, clause 2-4, Table 2-4.1).
- service: int = 0#
Numeric code naming the CIP service this request invokes.
- path: bytes = b''#
Raw, padded EPATH bytes naming the request’s target. Use
new()/epathfor the richEPATHview.
- request_data: bytes = b''#
Service-specific request data following the request path.
- classmethod new(service: int, path: EPATH | bytes | bytearray | Iterable[PortSegment | LogicalSegment | NetworkSegment | SymbolicSegment | DataSegment | ElectronicKeySegment] = b'', request_data: bytes = b'') Self[source]#
Builds a request, accepting a rich
path(EPATH, raw bytes, or an iterable of segments) instead of pre-encoded, word-counted bytes.
- class icspacket.proto.cip.msgrouter.MessageRouterResponse(*, reply_service: int = 0, reserved: int = 0, general_status: int = 0, additional_status: list[int] = <factory>, response_data: bytes = b'')[source]#
A Message Router response (See CIP Vol 1, clause 2-4, Table 2-4.2).
- reply_service: int = 0#
Service code being answered, echoed back with its top reply bit set.
- reserved: int = 0#
Byte reserved for future use; must always be encoded as zero.
- general_status: int = 0#
Outcome of the request; compare against
GeneralStatusvalues.
- additional_status: list[int]#
Extra 16-bit status words supplying detail beyond the single general-status byte, when the responder provides any.
- response_data: bytes = b''#
Service-specific reply data following the fixed status fields.
- property service: int#
Original request service code with the reply bit removed.
- property is_success: bool#
Whether the response general status is Success.
- classmethod new(service: int, general_status: GeneralStatus | int = GeneralStatus.SUCCESS, additional_status: Iterable[int] = (), response_data: bytes = b'') Self[source]#
Builds a response, deriving
reply_servicefromservice(i.e.servicewith the reply bit set).
- class icspacket.proto.cip.msgrouter.MultipleServicePacket(*, offsets: list[int] = <factory>, payload: bytes = b'')[source]#
Helper for common service
0x0A(See CIP Vol 1, clause A-4.10, Tables A-4.17 and A-4.18).Each embedded Message Router request/reply carries no length of its own on the wire, so
payloadcannot be split back into individual entries by a declarative field alone; usebuild()/decode_requests()/decode_replies()to move betweenpayloadand rich request/reply lists.- offsets: list[int]#
Byte offset of each embedded service, measured from the start of this packet. Populated by
build().
- payload: bytes = b''#
Raw, concatenated embedded-service bytes. Populated by
build(); split back into entries viadecode_requests()/decode_replies().
- build(requests: Iterable[MessageRouterRequest]) bytes[source]#
Encodes
requests, recomputingoffsets/payload, and returns the fully encoded packet.
- request(path: EPATH | bytes | bytearray | Iterable[PortSegment | LogicalSegment | NetworkSegment | SymbolicSegment | DataSegment | ElectronicKeySegment] = b'') MessageRouterRequest[source]#
Wrap this packet in a Message Router service
0x0Arequest.
- decode_requests() list[MessageRouterRequest][source]#
Splits
payloadback into individual embedded requests.
- decode_replies() list[MessageRouterResponse][source]#
Splits
payloadback into individual embedded replies (See CIP Volume 1, clause A-4.10.3, Table A-4.18).
[ODVA CIP Vol 1] CIP Connection Manager service codecs.
The request and response layouts are defined according to CIP Volume 1, clause 3-5.5, Tables 3-5.8 through 3-5.24. Connection Manager fields are little-endian and all EPATHs are represented as an even number of octets.
- class icspacket.proto.cip.connmgr.ForwardCloseRequest(*, priority: int = 0, timeout_ticks: int = 0, connection_serial_number: int = 0, originator_vendor_id: int = 0, originator_serial_number: int = 0, connection_path_size: int = 0, reserved: int = 0, connection_path: bytes = b'')[source]#
Builds and parses the body of a Forward_Close request used to tear down a previously opened CIP connection (See CIP Vol 1, clause 3-5.5.3, Table 3-5.19).
- priority: int = 0#
Priority/Time_tick value that, together with
timeout_ticks, determines how long the target waits before this request times out.
- timeout_ticks: int = 0#
Tick count that, together with
priority’s Time_tick value, determines how long the target waits before this request times out.
- connection_serial_number: int = 0#
Serial number identifying the specific connection instance being closed.
- originator_vendor_id: int = 0#
Vendor ID identifying the originating device.
- originator_serial_number: int = 0#
Serial number identifying the originating device.
- connection_path_size: int = 0#
Length of
connection_path, counted in 16-bit words.
- reserved: int = 0#
Byte reserved for future use; must always be encoded as zero.
- connection_path: bytes = b''#
Raw, padded EPATH bytes identifying the route to close. Use
new()/connection_epathfor the richEPATHview.
- class icspacket.proto.cip.connmgr.ForwardCloseResponse(*, connection_serial_number: int = 0, originator_vendor_id: int = 0, originator_serial_number: int = 0, application_reply_data_size: int = 0, reserved: int = 0, application_reply_data: bytes = b'')[source]#
Builds and parses the body of a successful Forward_Close reply (See CIP Vol 1, clause 3-5.5.3, Table 3-5.20).
- connection_serial_number: int = 0#
Echo of the
connection_serial_numbersent in the matching Forward_Close request.
- originator_vendor_id: int = 0#
Echo of the
originator_vendor_idsent in the matching Forward_Close request.
- originator_serial_number: int = 0#
Echo of the
originator_serial_numbersent in the matching Forward_Close request.
- application_reply_data_size: int = 0#
Length of
application_reply_data, counted in 16-bit words.
- reserved: int = 0#
Byte reserved for future use; must always be encoded as zero.
- application_reply_data: bytes = b''#
Application-specific reply data following the fixed header. Use
new()to pad odd-length input automatically.
- class icspacket.proto.cip.connmgr.ForwardOpenRequest(*, priority: int = 0, timeout_ticks: int = 0, o_to_t_connection_id: int = 0, t_to_o_connection_id: int = 0, connection_serial_number: int = 0, originator_vendor_id: int = 0, originator_serial_number: int = 0, timeout_multiplier: int = 0, reserved_timeout: list[int] = <factory>, o_to_t_rpi: int = 0, o_to_t_parameters: NetworkConnectionParameters = <factory>, t_to_o_rpi: int = 0, t_to_o_parameters: NetworkConnectionParameters = <factory>, transport_trigger: int = 0, connection_path_size: int = 0, connection_path: bytes = b'')[source]#
Builds and parses the standard-size Forward_Open request body used to open a new CIP connection (See CIP Vol 1, clause 3-5.5.2, Table 3-5.16).
- o_to_t_parameters: NetworkConnectionParameters#
Network Connection Parameters bitfield describing the originator-to-target data flow.
- t_to_o_rpi: int = 0#
Requested packet interval, in microseconds, for data flowing from target to originator.
- t_to_o_parameters: NetworkConnectionParameters#
Network Connection Parameters bitfield describing the target-to-originator data flow.
- transport_trigger: int = 0#
Byte selecting this connection’s transport class together with its production trigger behavior.
- connection_path_size: int = 0#
Length of
connection_path, counted in 16-bit words.
- connection_path: bytes = b''#
Raw, padded EPATH bytes identifying the route to establish. Use
new()/connection_epathfor the richEPATHview.
- class icspacket.proto.cip.connmgr.ForwardOpenResponse(*, o_to_t_connection_id: int = 0, t_to_o_connection_id: int = 0, connection_serial_number: int = 0, originator_vendor_id: int = 0, originator_serial_number: int = 0, o_to_t_api: int = 0, t_to_o_api: int = 0, application_reply_data_size: int = 0, reserved: int = 0, application_reply_data: bytes = b'')[source]#
Builds and parses the body of a successful Forward_Open or Large_Forward_Open reply, shared by both request sizes (See CIP Vol 1, clause 3-5.5.2, Table 3-5.17).
- o_to_t_connection_id: int = 0#
Connection ID the target assigned to the originator-to-target direction; the target’s Consumed Connection ID.
- t_to_o_connection_id: int = 0#
Connection ID the target assigned to the target-to-originator direction; the target’s Produced Connection ID.
- connection_serial_number: int = 0#
Echo of the
connection_serial_numbersent in the matching Forward_Open request.
- originator_vendor_id: int = 0#
Echo of the
originator_vendor_idsent in the matching Forward_Open request.
- originator_serial_number: int = 0#
Echo of the
originator_serial_numbersent in the matching Forward_Open request.
- o_to_t_api: int = 0#
Actual packet rate, in microseconds, that will be used from originator to target.
- t_to_o_api: int = 0#
Actual packet rate, in microseconds, that will be used from target to originator.
- application_reply_data_size: int = 0#
Length of
application_reply_data, counted in 16-bit words.
- reserved: int = 0#
Byte reserved for future use; must always be encoded as zero.
- application_reply_data: bytes = b''#
Application-specific reply data following the fixed header. Use
new()to pad odd-length input automatically.
- class icspacket.proto.cip.connmgr.LargeForwardOpenRequest(*, priority: int = 0, timeout_ticks: int = 0, o_to_t_connection_id: int = 0, t_to_o_connection_id: int = 0, connection_serial_number: int = 0, originator_vendor_id: int = 0, originator_serial_number: int = 0, timeout_multiplier: int = 0, reserved_timeout: list[int] = <factory>, o_to_t_rpi: int = 0, o_to_t_parameters: LargeNetworkConnectionParameters = <factory>, t_to_o_rpi: int = 0, t_to_o_parameters: LargeNetworkConnectionParameters = <factory>, transport_trigger: int = 0, connection_path_size: int = 0, connection_path: bytes = b'')[source]#
Builds and parses the Forward_Open request body used when the connection needs a larger connection-size range than the standard format allows (See CIP Vol 1, clause 3-5.5.2, Table 3-5.16).
- o_to_t_parameters: LargeNetworkConnectionParameters#
Large-format Network Connection Parameters bitfield describing the originator-to-target data flow.
- t_to_o_rpi: int = 0#
Requested packet interval, in microseconds, for data flowing from target to originator.
- t_to_o_parameters: LargeNetworkConnectionParameters#
Large-format Network Connection Parameters bitfield describing the target-to-originator data flow.
- transport_trigger: int = 0#
Byte selecting this connection’s transport class together with its production trigger behavior.
- connection_path_size: int = 0#
Length of
connection_path, counted in 16-bit words.
- connection_path: bytes = b''#
Raw, padded EPATH bytes identifying the route to establish. Use
new()/connection_epathfor the richEPATHview.
- class icspacket.proto.cip.connmgr.LargeNetworkConnectionParameters(redundant_owner: bool = False, connection_type: NetworkConnectionType = NetworkConnectionType.NULL, reserved_high: int = 0, priority: int = 0, variable: bool = False, reserved_low: int = 0, connection_size: int = 0)[source]#
Wire layout for the UDINT-sized form of Network Connection Parameters, as carried by a Large_Forward_Open (See CIP Vol 1, clause 3-5.5.1.1, Table 3-5.9).
- redundant_owner: bool = False#
True allows this connection to be held open by more than one owner at the same time.
- connection_type: NetworkConnectionType = 0#
Selects the
NetworkConnectionTypevalue (Null, Multicast, or Point to Point) for this connection.
- reserved_high: int = 0#
High-order bits reserved for future use; must always be encoded as zero.
- priority: int = 0#
Connection priority level: one of Low, High, Scheduled, or Urgent.
- variable: bool = False#
Data-size framing mode for the connection:
Falsefor fixed size,Truefor variable size.
- reserved_low: int = 0#
Low-order bits reserved for future use; must always be encoded as zero.
- connection_size: int = 0#
Largest data size, in bytes, that this connection will carry.
- class icspacket.proto.cip.connmgr.NetworkConnectionParameters(redundant_owner: bool = False, connection_type: NetworkConnectionType = NetworkConnectionType.NULL, reserved: bool = False, priority: int = 0, variable: bool = False, connection_size: int = 0)[source]#
Wire layout for the UINT-sized form of Network Connection Parameters, as carried by a standard Forward_Open (See CIP Vol 1, clause 3-5.5.1.1, Table 3-5.8).
- redundant_owner: bool = False#
True allows this connection to be held open by more than one owner at the same time.
- connection_type: NetworkConnectionType = 0#
Selects the
NetworkConnectionTypevalue (Null, Multicast, or Point to Point) for this connection.
- reserved: bool = False#
Reserved for future use; must always be encoded as zero.
- priority: int = 0#
Connection priority level: one of Low, High, Scheduled, or Urgent.
- variable: bool = False#
Data-size framing mode for the connection:
Falsefor fixed size,Truefor variable size.
- connection_size: int = 0#
Largest data size, in bytes, that this connection will carry.
- class icspacket.proto.cip.connmgr.NetworkConnectionType(*values)[source]#
Values this library accepts for the Connection Type subfield packed into Network Connection Parameters (See CIP Vol 1, clause 3-5.5.1.1, Tables 3-5.8 and 3-5.9).
- class icspacket.proto.cip.connmgr.UnconnectedSendRequest(*, priority: int = 0, timeout_ticks: int = 0, message_request_size: int = 0, message_request: bytes = b'', route_path_size: int = 0, reserved: int = 0, route_path: bytes = b'')[source]#
Builds and parses the body of an Unconnected_Send request, which wraps another Message Router request for routing over an unconnected path (See CIP Vol 1, clause 3-5.5.4, Table 3-5.22).
- priority: int = 0#
Priority/Time_tick value that, together with
timeout_ticks, determines how long the target waits before this request times out.
- timeout_ticks: int = 0#
Tick count that, together with
priority’s Time_tick value, determines how long the target waits before this request times out.
- message_request_size: int = 0#
Length, in bytes, of
message_request(not 16-bit words, asroute_path_sizebelow counts).
- message_request: bytes = b''#
Embedded Message Router request bytes; a pad byte follows on the wire whenever
message_request_sizeis odd.
- route_path_size: int = 0#
Length of
route_path, counted in 16-bit words.
- reserved: int = 0#
Byte reserved for future use; must always be encoded as zero.
- route_path: bytes = b''#
Raw, padded EPATH bytes identifying the route to the embedded request’s target. Use
new()/route_epathfor the richEPATHview.
- property route_epath: EPATH#
route_path, parsed into anEPATH.
- classmethod new(message_request: MessageRouterRequest | bytes | bytearray = b'', route_path: EPATH | bytes | bytearray | Iterable[PortSegment | LogicalSegment | NetworkSegment | SymbolicSegment | DataSegment | ElectronicKeySegment] = b'', *, priority: int = 0, timeout_ticks: int = 0) Self[source]#
Builds a request from a
MessageRouterRequest(or raw bytes) and a richroute_path(EPATH, raw bytes, or an iterable of segments).
EtherNet/IP Class 0/1 cyclic I/O connections (UDP transport).
A Class 0/1 connection carries the raw I/O data negotiated by a prior
Forward_Open/Large_Forward_Open exchange (see
icspacket.proto.cip.connmgr); this module does not perform any Connection
Manager services itself, it only transports the cyclic data once a connection
has been opened.
- exception icspacket.proto.cip.io.CIPIOError[source]#
Raised for malformed or failed Class 0/1 I/O exchanges.
- class icspacket.proto.cip.io.CIPIO_Connection(timeout: float = 1.0, *, header_format: bool = True, sequence_format: bool = True, bind_address: str | None = None)[source]#
UDP transport for a Class 0/1 (cyclic) CIP I/O connection.
- RUN: ClassVar[int] = 1#
Value this class writes into the Run/Idle header to mark the O->T payload as live data the target should act on (the “Run” state).
- IDLE: ClassVar[int] = 0#
Value this class writes into the Run/Idle header to tell the target to disregard the accompanying O->T payload (the “Idle” state).
- header_format: bool#
Whether O->T datagrams carry a 4-byte Run/Idle header (See CIP Volume 1, clause 3-6.1.4 “32-Bit Header Format”), as used by exclusive-owner/input-output connections. Disable for connections that use the plain “Modeless” O->T format.
- sequence_format: bool#
Whether O->T datagrams carry a 16-bit connected sequence count prefix identifying a class 1 real-time format (See CIP Volume 1, clause 3-6.1). Some targets omit this prefix and rely solely on the CPF-level sequence number instead; disable for those connections.
- classmethod from_forward_open(response: ForwardOpenResponse, address: tuple[str, int], *, timeout: float = 1.0, header_format: bool = True, sequence_format: bool = True) CIPIO_Connection[source]#
Open a Class 0/1 connection using connection IDs from a Forward_Open response.
- open(response: ForwardOpenResponse, address: tuple[str, int]) None[source]#
Open the UDP socket using connection IDs from
response.
- send(data: bytes, *, run_idle: int | None = None) None[source]#
Send one cyclic O->T datagram carrying
dataas the assembly payload.run_idleoverridesheader_format’s defaultRUNvalue for this datagram only; pass it explicitly to send anIDLEdatagram. Ignored entirely whenheader_formatisFalse.