Documentation
¶
Overview ¶
Package wire provides S7 PDU encoding and parsing (headers, read/write, setup, SZL, blocks) plus S7 TSAP helpers. Live transport uses go-cotp TSDUs; this package does not own TPKT or COTP framing.
Parsing philosophy: the wire layer is strict on framing and declared lengths—buffers are validated, lengths are checked, and overruns or mismatches return errors. Semantic interpretation (e.g. best-effort field extraction, device-dependent layouts) is left to the client and model layers.
Index ¶
- Constants
- Variables
- func AreaString(area byte) string
- func BuildTSAP(connType, rack, slot int) (uint16, error)
- func DecodeAsBit(item ReadVarItem) (bool, error)
- func DecodeAsByte(item ReadVarItem) (byte, error)
- func DecodeAsDInt(item ReadVarItem) (int32, error)
- func DecodeAsDWord(item ReadVarItem) (uint32, error)
- func DecodeAsInt(item ReadVarItem) (int16, error)
- func DecodeAsReal(item ReadVarItem) (float32, error)
- func DecodeAsWord(item ReadVarItem) (uint16, error)
- func EncodeBlockListRequest(pduRef uint16, blockType byte) []byte
- func EncodeEndUploadRequest(pduRef uint16, sessionID string) []byte
- func EncodeRackSlotTSAP(rack, slot byte) byte
- func EncodeReadVarBitRequest(pduRef uint16, addr S7AnyBitAddress) []byte
- func EncodeReadVarRequest(pduRef uint16, addrs []S7AnyAddress) []byte
- func EncodeS7Any(addr S7AnyAddress) []byte
- func EncodeS7AnyBit(addr S7AnyBitAddress) []byte
- func EncodeS7Header(rosctr ROSCTR, pduRef uint16, paramLen, dataLen int) []byte
- func EncodeSZLRequest(pduRef, szlID, szlIndex uint16) []byte
- func EncodeSetupCommRequest(pduRef uint16, maxAmqCalling, maxAmqCalled, pduSize int) []byte
- func EncodeStartUploadRequest(pduRef uint16, blockType byte, blockNum int) []byte
- func EncodeUploadRequest(pduRef uint16, sessionID string) []byte
- func EncodeWriteVarBitRequest(pduRef uint16, addr S7AnyBitAddress, value bool) []byte
- func EncodeWriteVarRequest(pduRef uint16, addr S7AnyAddress, value []byte) []byte
- func ErrClassString(class byte) string
- func FunctionCodeString(code byte) string
- func HeaderErrorString(class, code byte) string
- func ItemReturnCodeString(code byte) string
- func NormalizeResponseDataLength(transportSize ResponseTransportSize, rawLength uint16) (payloadBytes int, err error)
- func ParamErrorCodeString(code uint16) string
- func ParamErrorFromParam(param []byte) (code uint16, ok bool)
- func ParseStartUploadResponse(param []byte) (string, error)
- func ParseWriteVarResponse(param, data []byte) error
- func ReturnCodeError(code byte) error
- func SZLIDString(id uint16) string
- func SyntaxIDString(syntax byte) string
- func ValidateArea(area byte) error
- func ValidateRackSlot(rack, slot int) error
- func ValidateRequestSyntax(syntax byte) error
- type BlockInfoData
- type BlockListEntry
- type FrameSummary
- type ROSCTR
- type ReadVarItem
- type ResponseTransportSize
- type S7AnyAddress
- type S7AnyBitAddress
- type S7Error
- type S7Header
- type SZLResponse
- type SetupCommResponse
- type UnsupportedSyntaxError
- type UploadChunk
Constants ¶
const ( ErrClassNoError = 0x00 ErrClassApp = 0x81 ErrClassObject = 0x82 ErrClassResource = 0x83 ErrClassService = 0x84 ErrClassSupplies = 0x85 ErrClassAccess = 0x87 )
S7 Error classes
const ( RetCodeSuccess = 0xFF // Success RetCodeHWFault = 0x01 // Hardware fault RetCodeAccessFault = 0x03 // Illegal object access RetCodeAddressFault = 0x05 // Invalid address RetCodeDataTypeFault = 0x06 // Data type not supported RetCodeDataSizeFault = 0x07 // Data size mismatch RetCodeBusy = 0x09 // Object is busy RetCodeNotAvailable = 0x0A // Object not available )
Return codes for Read/Write operations
const ( BlockTypeOB = 0x38 BlockTypeDB = 0x41 BlockTypeSDB = 0x42 BlockTypeFC = 0x43 BlockTypeSFC = 0x44 BlockTypeFB = 0x45 BlockTypeSFB = 0x46 )
Block type codes for S7
const ( AreaDataRecord = 0x01 // Data record (optional; not all targets) AreaSysInfo = 0x03 AreaSysFlags = 0x05 AreaS7200AN = 0x06 // Analog in 200 AreaS7200AO = 0x07 // Analog out 200 (S7-200 style) AreaInputs = 0x81 // I AreaOutputs = 0x82 // Q AreaMerkers = 0x83 // M AreaDB = 0x84 // DB AreaDI = 0x85 // DI (instance DB) AreaLocal = 0x86 AreaV = 0x87 AreaCounter = 0x1C // C (counter) AreaTimer = 0x1D // T (timer) AreaIECCounter200 = 30 // IEC counters (S7-200 family) AreaIECTimer200 = 31 // IEC timers (S7-200 family) AreaPeripheral = 0x80 // P )
S7 Area codes (classic subset). C and T are timer/counter, not generic byte/bit addresses.
const ( SyntaxIDS7Any = 0x10 // Supported SyntaxIDDBRead = 0xB0 // Recognized, rejected SyntaxID1200Symbolic = 0xB2 SyntaxIDNCK = 0x82 // 0x82/0x83/0x84 SyntaxIDDriveES = 0xA2 )
Syntax IDs for variable specification. Only S7Any is supported for encoding.
const ( TransportSizeBit = 0x01 TransportSizeByte = 0x02 TransportSizeChar = 0x03 TransportSizeWord = 0x04 TransportSizeInt = 0x05 TransportSizeDWord = 0x06 TransportSizeDInt = 0x07 TransportSizeReal = 0x08 )
Transport size codes for request (address specification in S7Any). Do not use in response payload length normalization; use ResponseTransportSize there.
const ( SZLModuleID = 0x0011 // Module identification SZLComponentID = 0x001C // Component identification SZLCPUState = 0x0424 // CPU state SZLProtectionInfo = 0x0232 // Protection level SZLDiagBuffer = 0x00A0 // Diagnostic buffer SZLBlockList = 0x0111 // Block list SZLBlockInfo = 0x0113 // Block info )
SZL ID constants
const ( UserdataReq = 0x11 UserdataRes = 0x12 UserdataSubParam = 0x44 // With parameters UserdataSZL = 0x01 // SZL read )
Userdata function codes
const ( FuncSetupComm = 0xF0 // Setup communication FuncReadVar = 0x04 // Read variable FuncWriteVar = 0x05 // Write variable FuncDownloadStart = 0x1A FuncDownload = 0x1B FuncDownloadEnd = 0x1C FuncUploadStart = 0x1D FuncUpload = 0x1E FuncUploadEnd = 0x1F FuncPIService = 0x28 // Program invocation FuncPLCStop = 0x29 FuncPLCControl = 0x28 )
S7 function codes
const DataTransportSizeBit = 0x03
DataTransportSizeBit is the BIT transport size in Read/Write Var data sections (0x03). Distinct from request S7ANY TransportSizeBit (0x01).
const ReadVarRequestOverhead = S7HeaderSize + 2 + 12
ReadVarRequestOverhead is the minimum PDU bytes for one read-var item: S7 header (10) + param (2) + S7Any (12).
const S7HeaderSize = 10
const WriteVarRequestOverhead = S7HeaderSize + 2 + 12 + 4
WriteVarRequestOverhead is the minimum PDU bytes for one write-var item: S7 header (10) + param (2) + S7Any (12) + data header (4).
Variables ¶
var ( ErrShortS7Header = errors.New("data too short for S7 header") ErrInvalidS7ProtocolID = errors.New("invalid S7 protocol ID") ErrShortS7AckHeader = errors.New("data too short for S7 ack header") ErrS7PayloadLength = errors.New("S7 payload shorter than parameter/data lengths") ErrTruncatedItemHeader = errors.New("read response item header truncated") ErrTruncatedItemPayload = errors.New("read response item payload truncated or overrun") ErrInvalidParamLength = errors.New("invalid parameter section length") ErrInvalidDataLength = errors.New("invalid data section length") )
Functions ¶
func AreaString ¶
AreaString returns a short display name for the area code (e.g. "I", "DB", "M"). Unknown codes return hex.
func BuildTSAP ¶
BuildTSAP creates a TSAP from connection type, rack, and slot (S7 convention). Connection type: 1=PG, 2=OP, 3=S7Basic. Rack must be 0..7, slot 0..31; returns error if out of range.
func DecodeAsBit ¶
func DecodeAsBit(item ReadVarItem) (bool, error)
DecodeAsBit interprets a successful one-bit Read Var item as a bool. Requires return code success, data transport BIT (0x03), and a one-byte payload. Any nonzero low bit is treated as true (Snap7-compatible).
func DecodeAsByte ¶
func DecodeAsByte(item ReadVarItem) (byte, error)
DecodeAsByte returns the first byte. For BIT/BYTE transport size.
func DecodeAsDInt ¶
func DecodeAsDInt(item ReadVarItem) (int32, error)
DecodeAsDInt returns the first 4 bytes as big-endian int32.
func DecodeAsDWord ¶
func DecodeAsDWord(item ReadVarItem) (uint32, error)
DecodeAsDWord returns the first 4 bytes as big-endian uint32.
func DecodeAsInt ¶
func DecodeAsInt(item ReadVarItem) (int16, error)
DecodeAsInt returns the first 2 bytes as big-endian int16.
func DecodeAsReal ¶
func DecodeAsReal(item ReadVarItem) (float32, error)
DecodeAsReal returns the first 4 bytes as big-endian float32.
func DecodeAsWord ¶
func DecodeAsWord(item ReadVarItem) (uint16, error)
DecodeAsWord returns the first 2 bytes as big-endian uint16.
func EncodeBlockListRequest ¶
EncodeBlockListRequest creates a block list request (via SZL)
func EncodeEndUploadRequest ¶
EncodeEndUploadRequest ends an upload session.
func EncodeRackSlotTSAP ¶
EncodeRackSlotTSAP returns the low byte of a classic S7 TSAP for rack/slot. Protocol: bits 0..4 = slot, bits 5..7 = rack. Rack must be 0..7, slot 0..31. This is the single canonical TSAP rack/slot encoder; do not duplicate bit-packing elsewhere.
func EncodeReadVarBitRequest ¶
func EncodeReadVarBitRequest(pduRef uint16, addr S7AnyBitAddress) []byte
EncodeReadVarBitRequest creates a Read Var request for one bit.
func EncodeReadVarRequest ¶
func EncodeReadVarRequest(pduRef uint16, addrs []S7AnyAddress) []byte
EncodeReadVarRequest creates a read variable request
func EncodeS7Any ¶
func EncodeS7Any(addr S7AnyAddress) []byte
EncodeS7Any encodes an S7Any address specification (syntax SyntaxIDS7Any only). Call ValidateArea(addr.Area) before encoding if area comes from untrusted input. Byte-oriented: Start is a byte offset; Size is a byte count; transport size is BYTE.
func EncodeS7AnyBit ¶
func EncodeS7AnyBit(addr S7AnyBitAddress) []byte
EncodeS7AnyBit encodes a one-bit S7ANY address (transport BIT, element count 1). Start is ByteOffset*8+BitOffset (already in bits; not multiplied again).
func EncodeS7Header ¶
EncodeS7Header creates an S7 protocol header
func EncodeSZLRequest ¶
EncodeSZLRequest creates a SZL read request
func EncodeSetupCommRequest ¶
EncodeSetupCommRequest creates a Setup Communication request with the given PDU reference.
func EncodeStartUploadRequest ¶
EncodeStartUploadRequest creates a start upload request
func EncodeUploadRequest ¶
EncodeUploadRequest requests next upload segment for a started upload session.
func EncodeWriteVarBitRequest ¶
func EncodeWriteVarBitRequest(pduRef uint16, addr S7AnyBitAddress, value bool) []byte
EncodeWriteVarBitRequest creates a Write Var request for one bit using native BIT data transport. Data section: reserved 0x00, transport BIT (0x03), length 1 bit, payload 0x00/0x01.
func EncodeWriteVarRequest ¶
func EncodeWriteVarRequest(pduRef uint16, addr S7AnyAddress, value []byte) []byte
EncodeWriteVarRequest creates a write variable request
func ErrClassString ¶
ErrClassString returns a short display name for the S7 header error class only (e.g. "Access error").
func FunctionCodeString ¶
FunctionCodeString returns a display name for the S7 parameter function code (e.g. "Read Var", "Upload").
func HeaderErrorString ¶
HeaderErrorString returns a human-readable string for S7 header error class/code. Preserves raw values in S7Error; this is for display only.
func ItemReturnCodeString ¶
ItemReturnCodeString returns a human-readable string for Read/Write item return code.
func NormalizeResponseDataLength ¶
func NormalizeResponseDataLength(transportSize ResponseTransportSize, rawLength uint16) (payloadBytes int, err error)
NormalizeResponseDataLength converts the raw length field of a Read Var response item to payload byte count. Use ResponseTransportSize only; do not pass request transport size.
func ParamErrorCodeString ¶
ParamErrorCodeString returns a human-readable string for the 16-bit S7 parameter error code. Codes are from the S7 parameter section of responses (block, upload, diagnostics, etc.). Unknown codes return a formatted hex string.
func ParamErrorFromParam ¶
ParamErrorFromParam reads the 16-bit parameter error code at the standard offset (bytes 2-3, big-endian). Many S7 Ack-Data parameter sections carry this code when the response indicates an error. Returns (code, true) if param has at least 4 bytes; otherwise (0, false).
func ParseStartUploadResponse ¶
ParseStartUploadResponse extracts upload session ID from upload start response parameters.
func ParseWriteVarResponse ¶
ParseWriteVarResponse parses a write variable response
func ReturnCodeError ¶
ReturnCodeError returns an error for an item return code. Preserves raw Code in S7Error (Class zero).
func SZLIDString ¶
SZLIDString returns a human-readable name for the SZL ID when known (S7 SZL catalog). Use in logging and diagnostics. Unknown IDs return a formatted hex string.
func SyntaxIDString ¶
SyntaxIDString returns a display name for the variable specification syntax ID. Unknown IDs return hex.
func ValidateArea ¶
ValidateArea returns nil for supported classic areas, S7Error for unsupported.
func ValidateRackSlot ¶
ValidateRackSlot returns an error if rack or slot are outside classic S7 range (rack 0..7, slot 0..31).
func ValidateRequestSyntax ¶
ValidateRequestSyntax returns nil for SyntaxIDS7Any, UnsupportedSyntaxError for known-unsupported syntaxes.
Types ¶
type BlockInfoData ¶
BlockInfoData holds block info fields parsed from SZL 0x0113 response data. Layout is heuristic and may vary by PLC; only LoadMemory, LocalData, MC7Size are parsed confidently.
func ParseBlockInfoResponse ¶
func ParseBlockInfoResponse(szlData []byte) (BlockInfoData, error)
ParseBlockInfoResponse parses block info from SZL 0x0113 response data (resp.Data). Permissive/partial: requires at least 6 bytes; only the first three 16-bit fields are interpreted. SZL block info layout can vary by device; treat as heuristic for interoperability.
type BlockListEntry ¶
BlockListEntry represents an entry in the block list response
func ParseBlockListResponse ¶
func ParseBlockListResponse(szlData []byte) ([]BlockListEntry, error)
ParseBlockListResponse parses a block list response. Strict: szlData length must be a multiple of 4 (no trailing garbage). Each entry is 4 bytes: block number, type, language/flags.
type FrameSummary ¶
type FrameSummary struct {
TPDULength int
COTPType byte
ROSCTR byte
Function byte
ParamLength int
DataLength int
ErrorClass byte
ErrorCode byte
}
FrameSummary captures key protocol fields from one COTP TPDU that may carry an S7 PDU.
func InspectTPDU ¶
func InspectTPDU(tpdu []byte) (*FrameSummary, error)
InspectTPDU decodes a COTP TPDU payload (no TPKT header) and extracts high-level S7 metadata when present. This is a diagnostic helper for offline captures; the live client path uses cotp.Conn TSDUs. For full TPKT captures, peel the TPKT header with go-tpkt first, then pass the TPDU payload here.
type ROSCTR ¶
type ROSCTR byte
ROSCTR is the S7 message type (Remote Operating Service Control).
const ( ROSCTRJob ROSCTR = 0x01 // Job request ROSCTRAck ROSCTR = 0x02 // Acknowledgement without data ROSCTRAckData ROSCTR = 0x03 // Acknowledgement with data ROSCTRUserdata ROSCTR = 0x07 // Userdata (for SZL, etc.) )
S7 ROSCTR constants. ACK and ACK_DATA are distinct: ACK has no payload, ACK_DATA carries param+data.
func (ROSCTR) IsUserdata ¶
IsUserdata returns true for ROSCTRUserdata.
type ReadVarItem ¶
type ReadVarItem struct {
ReturnCode byte // Item return code
RawTransportSize byte // Transport size from wire
RawLength uint16 // Length from wire (bits or bytes per transport size)
Data []byte // Normalized payload bytes (only when ReturnCode == RetCodeSuccess)
}
ReadVarItem represents a single read result. Raw fields are preserved; Data is normalized payload (success only).
func ParseReadVarResponse ¶
func ParseReadVarResponse(param, data []byte) ([]ReadVarItem, error)
ParseReadVarResponse parses a read variable response. Strict: requires exactly itemCount items; fails on truncated item headers, length overrun, unknown transport size, or count mismatch.
type ResponseTransportSize ¶
type ResponseTransportSize byte
ResponseTransportSize is the data transport size in a Read Var response item. Distinct type to prevent using request transport size in response length normalization.
const ( RespTransportSizeBit ResponseTransportSize = 0x01 RespTransportSizeByte ResponseTransportSize = 0x02 RespTransportSizeChar ResponseTransportSize = 0x03 RespTransportSizeWord ResponseTransportSize = 0x04 RespTransportSizeInt ResponseTransportSize = 0x05 RespTransportSizeDWord ResponseTransportSize = 0x06 RespTransportSizeDInt ResponseTransportSize = 0x07 RespTransportSizeReal ResponseTransportSize = 0x08 RespTransportSizeDATE ResponseTransportSize = 0x09 // 2 bytes RespTransportSizeTOD ResponseTransportSize = 0x0A // 4 bytes (time of day) RespTransportSizeTIME ResponseTransportSize = 0x0B // 4 bytes RespTransportSizeS5TIME ResponseTransportSize = 0x0C // 2 bytes RespTransportSizeDT ResponseTransportSize = 0x0F // 8 bytes (date and time) RespTransportSizeCount ResponseTransportSize = 0x1C // COUNTER (2 bytes) RespTransportSizeTimer ResponseTransportSize = 0x1D // TIMER (2 bytes) RespTransportSizeIECCount ResponseTransportSize = 30 // IEC counter (S7-200) RespTransportSizeIECTimer ResponseTransportSize = 31 // IEC timer (S7-200) RespTransportSizeHSCounter ResponseTransportSize = 32 // High-speed counter )
func (ResponseTransportSize) String ¶
func (r ResponseTransportSize) String() string
String returns the transport size name for logging/diagnostics (e.g. "BYTE", "DATE", "COUNTER").
type S7AnyAddress ¶
type S7AnyAddress struct {
Area byte
DBNumber int
Start int // Byte offset
Size int // Number of bytes
}
S7AnyAddress is a specification of an S7 variable address
type S7AnyBitAddress ¶
S7AnyBitAddress is a single-bit S7ANY address. BitOffset must be 0..7 (caller validated).
type S7Error ¶
S7Error represents an S7 protocol error
func NewS7Error ¶
NewS7Error creates a new S7 error preserving raw Class and Code, with a string mapping when known. Header-level errors use Class and Code; item-level return codes use Code only (Class zero).
func NewS7ErrorWithParam ¶
NewS7ErrorWithParam is like NewS7Error but when param contains a 16-bit parameter error code at the standard offset (bytes 2-3), uses ParamErrorCodeString for the message when that code is non-zero. This yields clearer errors (e.g. "block not found", "invalid request length") for block/upload/diagnostic responses.
type S7Header ¶
type S7Header struct {
ProtocolID byte // Always 0x32
ROSCTR ROSCTR // Message type (Job, Ack, AckData, Userdata)
RedundancyID uint16
PDURef uint16 // PDU reference for request/response correlation
ParamLength uint16 // Declared parameter section length
DataLength uint16 // Declared data section length
ErrorClass byte // Error class (for Ack/AckData)
ErrorCode byte // Error code (for Ack/AckData)
}
S7Header represents an S7 protocol header. All fields are raw wire values.
type SZLResponse ¶
SZLResponse holds a parsed SZL response
func ParseSZLResponse ¶
func ParseSZLResponse(data []byte) (*SZLResponse, error)
ParseSZLResponse parses a SZL read response from the S7 data payload. Strict: validates return code, data length, and minimum 8-byte header.
type SetupCommResponse ¶
SetupCommResponse holds the response from Setup Communication
func ParseSetupCommResponse ¶
func ParseSetupCommResponse(data []byte) (*SetupCommResponse, error)
ParseSetupCommResponse parses a Setup Communication response
type UnsupportedSyntaxError ¶
type UnsupportedSyntaxError struct {
RawSyntaxID byte
}
UnsupportedSyntaxError indicates a request syntax ID that is recognized but not supported.
func (*UnsupportedSyntaxError) Error ¶
func (e *UnsupportedSyntaxError) Error() string
type UploadChunk ¶
UploadChunk is one chunk returned by upload continuation responses.
func ParseUploadResponse ¶
func ParseUploadResponse(param, data []byte) (*UploadChunk, error)
ParseUploadResponse parses upload continuation response and chunk payload. Strict: declared length must not overrun the data buffer; overrun returns an error.