Documentation
¶
Overview ¶
Package enip is an EtherNet/IP client with CIP explicit messaging, in pure Go: the encapsulation layer (sessions, SendRRData, SendUnitData, ListIdentity over TCP and UDP), CIP requests and replies with paths, routes and Multiple Service Packets, Unconnected Send, Forward Open and Large Forward Open (class 3 connections), the Logix tag services with fragmentation, the attribute services, and the Logix atomic, STRING and structure type encodings.
The simulator in package sim behaves like a Logix controller and is used by the tests.
Index ¶
- Constants
- func AtomicTypeCode(name string) (code uint16, ok bool)
- func Decode(t Type, data []byte, elements int, members []Member) (any, error)
- func DecodeAtomic(code uint16, b []byte) (any, error)
- func DecodeString(b []byte) (string, error)
- func Element(b []byte, i uint32) []byte
- func EncapStatusText(s uint32) string
- func Encode(t Type, v any, elements int) ([]byte, error)
- func EncodeAtomic(code uint16, v any) ([]byte, error)
- func EncodeString(s string) ([]byte, error)
- func ExtStatusText(general byte, ext uint16) string
- func IOPacket(connID, encapSeq uint32, cipSeq uint16, data []byte) []byte
- func IdentityItem(id Identity, major, minor uint8, serial uint32) []byte
- func IsCIP(err error) bool
- func Logical(class, instance uint16, attr int) []byte
- func MarshalCPF(items ...Item) []byte
- func MarshalResponse(service, status byte, ext []uint16, data []byte) []byte
- func MultipleService(reqs [][]byte) []byte
- func ParseIOPacket(b []byte) (connID, encapSeq uint32, cipSeq uint16, data []byte, err error)
- func ParseRequest(b []byte) (service byte, path, data []byte, err error)
- func ParseUnconnectedSend(b []byte) (msg, route []byte, err error)
- func PortSegment(b []byte, port uint16, link string) ([]byte, error)
- func RRData(timeout uint16, items ...Item) []byte
- func RegisterSessionData() []byte
- func Request(service byte, path, data []byte) []byte
- func Route(s string) ([]byte, error)
- func SplitMultiple(b []byte) ([][]byte, error)
- func StatusText(s byte) string
- func Symbolic(b []byte, name string) []byte
- func TagPath(tag string) ([]byte, error)
- type Client
- func (c *Client) Close()
- func (c *Client) Do(ctx context.Context, service byte, path, data []byte) (*Response, error)
- func (c *Client) GetAttribute(ctx context.Context, class, instance uint16, attr int) ([]byte, error)
- func (c *Client) Identity() *Identity
- func (c *Client) ListIdentity(ctx context.Context) (*Identity, error)
- func (c *Client) ListTags(ctx context.Context, program string) ([]TagInfo, error)
- func (c *Client) MaxMessage() int
- func (c *Client) Mode() (string, error)
- func (c *Client) OpenIO(ctx context.Context, cfg IOConfig) (*IOConn, error)
- func (c *Client) ReadTag(ctx context.Context, tag string, elements int) (Type, []byte, error)
- func (c *Client) ReadTags(ctx context.Context, reads []*TagRead) error
- func (c *Client) ReadTemplate(ctx context.Context, instance uint16) (Template, error)
- func (c *Client) SetAttribute(ctx context.Context, class, instance uint16, attr int, data []byte) error
- func (c *Client) WriteTag(ctx context.Context, tag string, t Type, elements int, data []byte) error
- type Error
- type Header
- type IOConfig
- type IOConn
- type Identity
- type Item
- type Member
- type Response
- type TagInfo
- type TagRead
- type Template
- type TemplateMember
- type Type
Examples ¶
Constants ¶
const ( ClassSymbol uint16 = 0x6B ClassTemplate uint16 = 0x6C SvcGetAttributeList byte = 0x03 SvcGetInstanceAttributeList byte = 0x55 )
Logix objects used to browse tags and structures.
const ( SvcGetAttributesAll byte = 0x01 SvcMultipleService byte = 0x0A SvcGetAttributeSingle byte = 0x0E SvcSetAttributeSingle byte = 0x10 SvcForwardClose byte = 0x4E SvcReadTag byte = 0x4C SvcWriteTag byte = 0x4D SvcReadTagFragmented byte = 0x52 // to a symbol SvcUnconnectedSend byte = 0x52 // to the connection manager SvcWriteTagFragmented byte = 0x53 SvcForwardOpen byte = 0x54 SvcLargeForwardOpen byte = 0x5B ReplyBit byte = 0x80 ClassIdentity uint16 = 0x01 ClassMessageRouter uint16 = 0x02 ClassConnectionManager uint16 = 0x06 )
CIP service codes used here.
const ( StatusSuccess byte = 0x00 StatusConnFailure byte = 0x01 StatusPathSegment byte = 0x04 StatusPathUnknown byte = 0x05 StatusPartial byte = 0x06 StatusServiceNotSup byte = 0x08 StatusNotSettable byte = 0x0E StatusReplyTooLarge byte = 0x11 StatusNotEnoughData byte = 0x13 StatusAttrNotSupported byte = 0x14 StatusTooMuchData byte = 0x15 StatusObjectMissing byte = 0x16 StatusEmbeddedError byte = 0x1E StatusVendor byte = 0xFF )
General status codes this package acts on.
const ( CmdNOP uint16 = 0x0000 CmdListServices uint16 = 0x0004 CmdListIdentity uint16 = 0x0063 CmdListInterfaces uint16 = 0x0064 CmdRegisterSession uint16 = 0x0065 CmdUnRegisterSession uint16 = 0x0066 CmdSendRRData uint16 = 0x006F CmdSendUnitData uint16 = 0x0070 )
Encapsulation commands (the 16-bit command field of the 24-byte header).
const ( ItemNullAddress uint16 = 0x0000 ItemIdentity uint16 = 0x000C ItemConnectedAddress uint16 = 0x00A1 ItemConnectedData uint16 = 0x00B1 ItemUnconnectedData uint16 = 0x00B2 ItemSockaddrOT uint16 = 0x8000 ItemSockaddrTO uint16 = 0x8001 )
Common packet format item type IDs.
const ( // ItemSequencedAddress is the CPF item of a class 0/1 packet. ItemSequencedAddress uint16 = 0x8002 // ClassAssembly is the Assembly object. ClassAssembly uint16 = 0x04 // IOPort is the UDP port of class 0/1 I/O. IOPort = 2222 )
const ( TypeBOOL uint16 = 0xC1 TypeSINT uint16 = 0xC2 TypeINT uint16 = 0xC3 TypeDINT uint16 = 0xC4 TypeLINT uint16 = 0xC5 TypeUSINT uint16 = 0xC6 TypeUINT uint16 = 0xC7 TypeUDINT uint16 = 0xC8 TypeULINT uint16 = 0xC9 TypeREAL uint16 = 0xCA TypeLREAL uint16 = 0xCB TypeBYTE uint16 = 0xD1 TypeWORD uint16 = 0xD2 TypeDWORD uint16 = 0xD3 TypeLWORD uint16 = 0xD4 TypeStruct uint16 = 0x02A0 // followed by a structure handle // HandleSTRING is the structure handle of the built-in Logix STRING // (LEN DINT + DATA SINT[82], 88 bytes with padding). HandleSTRING uint16 = 0x0FCE // StringSize is the Logix STRING's size in bytes and StringChars its // character capacity. StringSize = 88 StringChars = 82 )
Atomic data type codes (the Logix tag type word).
const DefaultConnSize = 500
DefaultConnSize is the class 3 connection size, in bytes, used when a Client does not set one.
const DefaultPort = 44818
DefaultPort is the EtherNet/IP explicit messaging port (TCP and UDP).
const HeaderLen = 24
HeaderLen is the size of the encapsulation header.
Variables ¶
This section is empty.
Functions ¶
func AtomicTypeCode ¶
AtomicTypeCode returns the code of the atomic type with exactly this name (upper case: "DINT", "REAL" …); ok is false otherwise, including for STRING.
func Decode ¶
Decode turns a read reply's data into a JSON-able value: one element is a scalar, several an array. A structure without members is {"handle": "0x…", "hex": "…"}.
func DecodeAtomic ¶
DecodeAtomic reads one atomic value; BOOL gives a bool, integers and reals a float64 (LINT/ULINT beyond 2^53 lose precision).
func DecodeString ¶
DecodeString reads a Logix STRING (LEN then characters).
func EncapStatusText ¶
EncapStatusText names encapsulation status codes.
func Encode ¶
Encode turns a JSON value into tag data for elements elements of type t: numbers/booleans for atomics, text for STRING, arrays for several elements, {"hex": "…"} or a hex string for structures.
func EncodeAtomic ¶
EncodeAtomic writes one atomic value (bool or number), refusing values out of the type's range.
func EncodeString ¶
EncodeString writes a Logix STRING of StringSize bytes.
Example ¶
Encode a string for a write and decode it again.
package main
import (
"fmt"
"github.com/cB-Sigma/enip"
)
func main() {
b, _ := enip.EncodeString("Pump 7")
s, _ := enip.DecodeString(b)
fmt.Println(s)
}
Output: Pump 7
func ExtStatusText ¶
ExtStatusText names the extended status of connection manager errors (general 0x01) and Logix tag errors (general 0xFF).
func IdentityItem ¶
IdentityItem encodes an identity item's data (socket address fields are big-endian, the rest little-endian).
func Logical ¶
Logical appends class, instance and (when attr >= 0) attribute segments, each 8-bit when it fits and 16-bit otherwise.
func MarshalCPF ¶
MarshalCPF encodes an item count followed by the items.
func MarshalResponse ¶
MarshalResponse encodes a CIP reply.
func MultipleService ¶
MultipleService packs requests into one Multiple Service Packet body.
func ParseIOPacket ¶ added in v0.2.0
ParseIOPacket reads a class 0/1 UDP packet.
func ParseRequest ¶
ParseRequest splits a CIP request.
func ParseUnconnectedSend ¶
ParseUnconnectedSend splits an Unconnected Send body (for simulators).
func PortSegment ¶
PortSegment appends one port segment.
func RRData ¶
RRData builds the body of SendRRData or SendUnitData: interface handle 0, a timeout in seconds and the items.
func RegisterSessionData ¶
func RegisterSessionData() []byte
RegisterSessionData is the request/reply body of RegisterSession: protocol version 1, options 0.
func Route ¶
Route parses a route such as "1,0" (backplane port 1, slot 0) or "1,0,2,10.0.0.9,1,2" into port segments. Links that are IP addresses (or above 255) use the extended link address form.
Example ¶
The route to the CPU in slot 2 of a ControlLogix chassis (backplane port 1), and the symbolic path of a program-scoped tag.
package main
import (
"fmt"
"github.com/cB-Sigma/enip"
)
func main() {
route, _ := enip.Route("1,2")
path, _ := enip.TagPath("Program:Main.Count")
fmt.Printf("% x\n% x\n", route, path)
}
Output: 01 02 91 0c 50 72 6f 67 72 61 6d 3a 4d 61 69 6e 91 05 43 6f 75 6e 74 00
func SplitMultiple ¶
SplitMultiple splits a Multiple Service Packet body (request or reply) into its embedded messages.
Types ¶
type Client ¶
type Client struct {
Addr string // host:port
Route []byte // port segments to the CPU; nil talks to the target itself
Timeout time.Duration // per exchange
Connected bool // try a Forward Open
ConnSize int // connection size; above 511 uses Large Forward Open
// KeepAlive is how long the connection must survive without traffic
// (it sets the RPI × multiplier timeout); default 1 minute.
KeepAlive time.Duration
// contains filtered or unexported fields
}
Client is one EtherNet/IP session with a target, optionally with a class 3 connection. It is safe for concurrent use; requests are serialised.
func (*Client) Do ¶
Do sends one CIP request and returns the reply. A transport failure closes the session (the next call reconnects); a CIP error status comes back in the reply, not as the error.
func (*Client) GetAttribute ¶
func (c *Client) GetAttribute(ctx context.Context, class, instance uint16, attr int) ([]byte, error)
GetAttribute reads one attribute (Get_Attribute_Single), or every attribute of the instance when attr < 0 (Get_Attribute_All).
func (*Client) ListIdentity ¶
ListIdentity asks the target for its identity over TCP.
func (*Client) ListTags ¶ added in v0.2.0
ListTags lists the tags of the controller (program "") or of one program, reading the Symbol object's instances (Get_Instance_Attribute_List, repeated until the controller says the list is complete).
func (*Client) MaxMessage ¶
MaxMessage is the largest CIP message (request or reply) the current transport carries.
func (*Client) Mode ¶
Mode reports "connected", "unconnected" or "" when not connected, and why connected messaging was refused, if it was.
func (*Client) OpenIO ¶ added in v0.2.0
OpenIO opens a class 1 connection through the client's session (its Route, if any, reaches the adapter) and starts sending outputs at the RPI. The outputs start zeroed and in idle mode; SetOutput and SetRun change them.
func (*Client) ReadTag ¶
ReadTag reads elements elements of a tag, continuing with Read Tag Fragmented when the value does not fit in one reply.
func (*Client) ReadTags ¶
ReadTags reads several tags in one Multiple Service Packet (the caller keeps the batch within MaxMessage); replies that were cut short are completed with fragmented reads. The error is for the whole batch.
func (*Client) ReadTemplate ¶ added in v0.2.0
ReadTemplate reads a structure's definition from its template instance (TagInfo.Template): its attributes, then the definition itself.
type Header ¶
type Header struct {
Command uint16
Length uint16 // bytes of data after the header
Session uint32
Status uint32
Context [8]byte
Options uint32
}
Header is the encapsulation header; every field is little-endian.
func ParseHeader ¶
ParseHeader decodes the first 24 bytes of b.
func ReadPacket ¶
ReadPacket reads one encapsulation packet from a stream.
type IOConfig ¶ added in v0.2.0
type IOConfig struct {
// ConfigInstance, OutputInstance (O→T, consumed by the adapter) and
// InputInstance (T→O, produced by it) are assembly instances.
ConfigInstance, OutputInstance, InputInstance uint16
// OutputSize and InputSize are the data sizes in bytes (without the
// sequence count and run/idle header).
OutputSize, InputSize int
// RPI is the requested packet interval of both directions (default
// 100 ms); the connection times out after RPI × 4 << Multiplier.
RPI time.Duration
Multiplier byte // default 2 (16 × RPI)
// LocalUDP is where this side receives T→O data (default ":2222");
// the adapter is told the port.
LocalUDP string
// AdapterUDPPort is the adapter's I/O port when it does not say it in
// its Forward Open reply (default 2222).
AdapterUDPPort int
}
IOConfig describes a class 1 connection to an adapter's assemblies.
type IOConn ¶ added in v0.2.0
type IOConn struct {
// contains filtered or unexported fields
}
IOConn is an open class 1 connection; this side is the scanner (originator). Its methods are safe for concurrent use.
func (*IOConn) Close ¶ added in v0.2.0
func (io *IOConn) Close()
Close stops sending and closes the UDP socket. The adapter drops the connection when its timeout passes (a Forward Close is not sent).
func (*IOConn) Err ¶ added in v0.2.0
Err is why the connection ended (nil while it runs or after Close).
func (*IOConn) Input ¶ added in v0.2.0
Input is the latest T→O data, its sequence count and when it came.
type Identity ¶
type Identity struct {
Protocol uint16 `json:"protocol"`
IP string `json:"ip"`
Port uint16 `json:"port"`
Vendor uint16 `json:"vendor"`
DeviceType uint16 `json:"deviceType"`
ProductCode uint16 `json:"productCode"`
Revision string `json:"revision"`
Status uint16 `json:"status"`
Serial string `json:"serial"`
ProductName string `json:"productName"`
State uint8 `json:"state"`
}
Identity is a ListIdentity reply item (the identity object's key attributes plus the device's socket address).
func Discover ¶
Discover sends ListIdentity over UDP to addr (a broadcast or unicast host:port) and collects replies for wait.
func ParseIdentity ¶
ParseIdentity decodes an identity item.
func ParseListIdentity ¶
ParseListIdentity decodes a ListIdentity reply body.
type Item ¶
Item is one common packet format item.
func ParseRRData ¶
ParseRRData splits the body of SendRRData/SendUnitData into its items.
type Member ¶
type Member struct {
Name string `json:"name"`
Offset int `json:"offset"`
Type string `json:"type"`
Bit int `json:"bit,omitempty"` // for BOOL members packed in a host word
}
Member is a structure member the configuration names, for decoding a structure's bytes without the controller's template.
type Response ¶
Response is a decoded CIP reply.
func ParseResponse ¶
ParseResponse decodes a CIP reply.
type TagInfo ¶ added in v0.2.0
type TagInfo struct {
Name string
Instance uint32 // the Symbol object instance
// Type is the tag's data type: an atomic code, or TypeStruct with
// Template set (the structure's template instance; ReadTemplate gives
// its definition and handle).
Type Type
Template uint16
Dims [3]int // array dimensions; zero for a scalar
ReadOnly bool // external access read only (or none)
// System marks entries a controller lists that are not user tags:
// programs ("Program:<name>"), routines, tasks, module and system
// tags.
System bool
}
TagInfo is one entry of a controller's (or program's) tag list.
type Template ¶ added in v0.2.0
type Template struct {
Instance uint16
Name string
Handle uint16 // the structure handle in reads and writes
Size int // bytes of one value
Members []TemplateMember
}
Template is a structure (UDT) definition read from the controller.
func (Template) DecodeStruct ¶ added in v0.2.0
func (t Template) DecodeStruct(b []byte, lookup func(instance uint16) (Template, bool)) (map[string]any, error)
DecodeStruct decodes one value of the template's structure into a map of member name to value, nested templates read through lookup (nil leaves nested structures as raw bytes). Hidden members are left out.
type TemplateMember ¶ added in v0.2.0
type TemplateMember struct {
Name string
Type Type // atomic, or TypeStruct with Template set
Template uint16 // a nested structure's template instance
Offset int
Array int // element count of an array member (0: scalar)
Bit int // a BOOL member's bit at Offset
Hidden bool
}
TemplateMember is one member of a structure definition.
type Type ¶
Type is a tag's data type: an atomic code, or TypeStruct and a handle.
func ParseTypeName ¶
ParseTypeName turns "DINT", "REAL", "STRING" … into a Type. ok is false for unknown names.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package server is the EtherNet/IP adapter (target) role, answering like a Logix controller: a tag table with program scopes and structures, the identity object, sessions, Unconnected Send routing to a CPU slot, class 3 connections (Forward Open and Large Forward Open, Forward Close, SendUnitData), Multiple Service Packets, Read and Write Tag with fragmentation, member access in structures, tag browsing (the Symbol and Template objects, symbol instance addressing), attribute services, and ListIdentity over TCP and UDP.
|
Package server is the EtherNet/IP adapter (target) role, answering like a Logix controller: a tag table with program scopes and structures, the identity object, sessions, Unconnected Send routing to a CPU slot, class 3 connections (Forward Open and Large Forward Open, Forward Close, SendUnitData), Multiple Service Packets, Read and Write Tag with fragmentation, member access in structures, tag browsing (the Symbol and Template objects, symbol instance addressing), attribute services, and ListIdentity over TCP and UDP. |