goadstc

package module
v0.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 16, 2025 License: MIT Imports: 17 Imported by: 0

README

goadstc

Go Reference Go Report Card

A production-quality Go library for TwinCAT ADS/AMS communication over TCP.

What is ADS/AMS?

ADS (Automation Device Specification) is a device- and fieldbus-independent protocol developed by Beckhoff for communication with TwinCAT devices. AMS (Automation Message Specification) provides the underlying message routing and addressing layer.

This library implements the ADS/AMS protocol specification for TCP transport, enabling Go applications to communicate with TwinCAT PLCs and other ADS-compatible devices.

Features

Core Protocol
  • ✅ Full AMS/TCP and AMS header encoding/decoding
  • ✅ Core ADS commands: Read, Write, ReadWrite, ReadState, ReadDeviceInfo, WriteControl
  • ✅ Symbol resolution: Read/write PLC variables by name
  • ✅ Symbol table caching: Automatic symbol upload and parsing
  • ✅ ADS notifications for real-time variable monitoring
  • ✅ Correct binary protocol implementation (little-endian, exact field sizes)
  • ✅ Type-safe Go API with functional options
  • ✅ Zero external dependencies (standard library only)
  • ✅ Production-ready error handling
Advanced Features
  • Automatic Type Detection: Read any symbol and get properly parsed Go values automatically
  • Automatic Type Encoding: Write values with auto-encoding based on symbol type
  • 34 Type-Safe Methods: Read/write all TwinCAT data types with native Go types
  • Data Type Upload: Fetch complete struct definitions from PLC automatically
  • Struct Auto-Parsing: Automatically parse nested structs with full field information
  • Batch Reading: Read multiple symbols efficiently (ready for SumCommand optimization)
  • Struct Field Access: Direct access to struct fields using dot notation
  • Array Element Access: Access array elements with bracket notation
  • Complex Arrays: Support for struct arrays and nested field access
  • Time/Date Types: Native Go time.Time and time.Duration conversions
  • Unicode Strings: Full WSTRING support with UTF-16LE encoding
  • Symbol-Based Notifications: Subscribe to PLC variables by name
Connection Stability
  • TCP Keepalive: 30-second intervals with NoDelay optimization
  • Graceful Shutdown: 5-second timeout for pending operations
  • Connection State Tracking: Monitor connection lifecycle with callbacks
  • Automatic Reconnection: Exponential backoff with configurable max delay
  • Health Monitoring: Periodic connection health checks
  • Request Retry Logic: Automatic retry with backoff for transient failures
  • Subscription Re-establishment: Automatic restoration after reconnect
Observability
  • Structured Logging: JSON-based logging using Go's standard log/slog
  • Error Classification: Automatic categorization of errors (Network, ADS, Protocol, etc.)
  • Metrics Collection: Track operations, performance, and connection health
  • Custom Integrations: Plugin your own logger or metrics backend
  • In-Memory Metrics: Built-in metrics collector for testing and debugging
  • Zero Overhead: No-op implementations by default for minimal performance impact

See OBSERVABILITY.md for detailed documentation.

What This Library Does NOT Support

  • UDP transport (TCP only)
  • Router/routing table management (direct TCP connection only)

Installation

go get github.com/mrpasztoradam/goadstc

Version Information

The library follows Semantic Versioning. You can query version information programmatically:

import "github.com/mrpasztoradam/goadstc"

// Get version string
version := goadstc.Version() // e.g., "0.1.0"

// Get detailed build information
info := goadstc.GetBuildInfo()
fmt.Println(info.String()) // Includes git commit, tag, Go version, etc.

See examples/version/ for a complete example.

Project Structure

/
├── client.go              # Public API
├── internal/
│   ├── ams/              # AMS protocol implementation
│   ├── ads/              # ADS command handling
│   └── transport/        # TCP transport layer
├── tests/                # Test suite (gitignored)
├── examples/             # Usage examples
└── testdata/             # Test fixtures

Quick Start

Automatic Type Detection (Easiest)
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/mrpasztoradam/goadstc"
)

func main() {
    // Create client with target configuration
    client, err := goadstc.NewClient(
        goadstc.WithTarget("192.168.1.100:48898"),
        goadstc.WithTargetNetID("192.168.1.100.1.1"),
        goadstc.WithTargetPort(851),
        goadstc.WithAutoReconnect(true),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()

    ctx := context.Background()
    if err := client.Connect(ctx); err != nil {
        log.Fatal(err)
    }

    // Read any symbol - type is automatically detected and parsed
    value, err := client.ReadSymbolValue(ctx, "MAIN.counter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Counter: %v (type: %T)\n", value, value)

    // Read a struct - returns map[string]interface{} with all fields
    config, err := client.ReadSymbolValue(ctx, "MAIN.config")
    if err != nil {
        log.Fatal(err)
    }
    if m, ok := config.(map[string]interface{}); ok {
        for name, val := range m {
            fmt.Printf("  %s: %v\n", name, val)
        }
    }

    // Write with automatic type encoding
    err = client.WriteSymbolValue(ctx, "MAIN.counter", int16(42))
    if err != nil {
        log.Fatal(err)
    }

    // Read multiple symbols at once
    values, _ := client.ReadMultipleSymbolValues(ctx,
        "MAIN.counter",
        "MAIN.enabled",
        "MAIN.temperature",
    )
    for name, val := range values {
        fmt.Printf("%s: %v\n", name, val)
    }
}
Type-Safe API (More Control)
func main() {
    client, err := goadstc.NewClient(
        goadstc.WithTarget("192.168.1.100:48898"),
        goadstc.WithTargetNetID("192.168.1.100.1.1"),
        goadstc.WithTargetPort(851),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()

    ctx := context.Background()
    if err := client.Connect(ctx); err != nil {
        log.Fatal(err)
    }

    // Type-safe operations with exact types
    value, err := client.ReadUint16(ctx, "MAIN.counter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Counter: %d\n", value)

    // Write with type safety
    err = client.WriteUint16(ctx, "MAIN.counter", 42)
    if err != nil {
        log.Fatal(err)
    }

    // Access struct fields with dot notation
    temperature, err := client.ReadFloat32(ctx, "MAIN.sensor.temperature")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Temperature: %.2f°C\n", temperature)

    // Access array elements
    arrayValue, err := client.ReadInt32(ctx, "MAIN.dataArray[5]")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Array[5]: %d\n", arrayValue)
}

API Overview

Client Configuration Options

Basic Configuration:

  • WithTarget(address) - Target TCP address (required)
  • WithAMSNetID(netID) - Target AMS NetID (required)
  • WithAMSPort(port) - Target AMS port (default: 851)
  • WithSourceNetID(netID) - Source AMS NetID (optional)
  • WithSourcePort(port) - Source AMS port (default: 32905)
  • WithTimeout(duration) - Request timeout (default: 5s)

Connection Stability:

  • WithAutoReconnect(enabled) - Enable automatic reconnection on connection loss
  • WithMaxReconnectDelay(duration) - Maximum delay between reconnect attempts (default: 60s)
  • WithHealthCheck(interval) - Periodic connection health check interval (0 = disabled)
  • WithStateCallback(callback) - Receive connection state change notifications
Core Methods

Basic Operations:

  • ReadDeviceInfo(ctx) - Read device name and version
  • Read(ctx, indexGroup, indexOffset, length) - Read data from device
  • Write(ctx, indexGroup, indexOffset, data) - Write data to device
  • ReadState(ctx) - Read ADS and device state
  • WriteControl(ctx, adsState, deviceState, data) - Change ADS state (start/stop/reset PLC)
  • ReadWrite(ctx, indexGroup, indexOffset, readLength, writeData) - Combined read/write operation

Symbol Resolution:

  • RefreshSymbols(ctx) - Download and cache symbol table from PLC
  • GetSymbol(name) - Get cached symbol information
  • ListSymbols(ctx) - List all symbols in cache
  • FindSymbols(ctx, pattern) - Search symbols by pattern
  • ReadSymbol(ctx, name) - Read PLC variable by name (auto-loads symbols)
  • WriteSymbol(ctx, name, data) - Write PLC variable by name

Notifications:

  • Subscribe(ctx, opts) - Create a notification subscription for real-time PLC data monitoring
  • SubscribeSymbol(ctx, symbolName, opts) - Subscribe to a symbol by name
Automatic Type Detection (Easiest)

Automatic Read/Write with Type Detection:

  • ReadSymbolValue(ctx, symbolName) (interface{}, error) - Automatically detects type and parses value

    • Returns appropriate Go type: int16, float32, bool, string, map[string]interface{} (structs), []interface{} (arrays)
    • Fetches type information from PLC automatically
    • Handles nested structs and arrays recursively
  • WriteSymbolValue(ctx, symbolName, value interface{}) error - Automatically encodes value based on symbol type

    • Accepts Go primitives: bool, int8-int64, uint8-uint64, float32, float64, string
    • Supports time.Duration and time.Time
    • Automatic type validation and encoding
  • ReadMultipleSymbolValues(ctx, symbolNames...string) (map[string]interface{}, error) - Read multiple symbols

    • Returns map with symbol names as keys
    • Individual errors stored in result map
Type-Safe Operations (More Control)

All methods automatically resolve symbols and handle type conversions:

Boolean:

  • ReadBool(ctx, symbolName) (bool, error)
  • WriteBool(ctx, symbolName, value bool) error

Integers (Signed):

  • ReadInt8/ReadInt16/ReadInt32/ReadInt64(ctx, symbolName)
  • WriteInt8/WriteInt16/WriteInt32/WriteInt64(ctx, symbolName, value)

Integers (Unsigned):

  • ReadUint8/ReadUint16/ReadUint32/ReadUint64(ctx, symbolName)
  • WriteUint8/WriteUint16/WriteUint32/WriteUint64(ctx, symbolName, value)

Floating Point:

  • ReadFloat32/ReadFloat64(ctx, symbolName)
  • WriteFloat32/WriteFloat64(ctx, symbolName, value)

Strings:

  • ReadString(ctx, symbolName) (string, error) - ASCII strings
  • WriteString(ctx, symbolName, value string) error
  • ReadWString(ctx, symbolName) (string, error) - Unicode (UTF-16LE)
  • WriteWString(ctx, symbolName, value string) error

Time/Date Types:

  • ReadTime(ctx, symbolName) (time.Duration, error) - TIME (milliseconds)
  • WriteTime(ctx, symbolName, value time.Duration) error
  • ReadDate(ctx, symbolName) (time.Time, error) - DATE (Unix timestamp)
  • WriteDate(ctx, symbolName, value time.Time) error
  • ReadTimeOfDay(ctx, symbolName) (time.Duration, error) - TIME_OF_DAY (ms since midnight)
  • WriteTimeOfDay(ctx, symbolName, value time.Duration) error
  • ReadDateAndTime(ctx, symbolName) (time.Time, error) - DATE_AND_TIME (Unix timestamp)
  • WriteDateAndTime(ctx, symbolName, value time.Time) error
Advanced Symbol Access

Struct Field Access (dot notation):

// Direct field access
value, err := client.ReadInt32(ctx, "MAIN.myStruct.field1")
err = client.WriteFloat32(ctx, "MAIN.sensor.temperature", 25.5)

Array Element Access (bracket notation):

// Array indexing
value, err := client.ReadUint16(ctx, "MAIN.dataArray[5]")
err = client.WriteInt32(ctx, "MAIN.buffer[10]", 42)

Combined Access (arrays of structs):

// Access struct field in array element
value, err := client.ReadFloat32(ctx, "MAIN.sensors[2].temperature")
err = client.WriteUint16(ctx, "MAIN.devices[0].status", 1)

Automatic Struct Parsing:

// Automatically fetch type info from PLC and parse all fields
structData, err := client.ReadStructAsMap(ctx, "MAIN.myStruct")
if err != nil {
    log.Fatal(err)
}

// Access parsed fields
field1 := structData["field1"].(int32)
field2 := structData["temperature"].(float32)
nested := structData["subStruct"].(map[string]interface{})

Usage Examples

Type-Safe Operations
// Read various data types
boolVal, err := client.ReadBool(ctx, "MAIN.running")
intVal, err := client.ReadInt32(ctx, "MAIN.counter")
floatVal, err := client.ReadFloat32(ctx, "MAIN.temperature")
strVal, err := client.ReadString(ctx, "MAIN.message")

// Write various data types
err = client.WriteBool(ctx, "MAIN.enable", true)
err = client.WriteInt32(ctx, "MAIN.setpoint", 100)
err = client.WriteFloat32(ctx, "MAIN.pressure", 1.5)
err = client.WriteString(ctx, "MAIN.status", "OK")

// Time and date operations
duration := 5*time.Second + 250*time.Millisecond
err = client.WriteTime(ctx, "MAIN.delay", duration)

timestamp := time.Now()
err = client.WriteDateAndTime(ctx, "MAIN.lastUpdate", timestamp)

// Unicode strings
err = client.WriteWString(ctx, "MAIN.unicodeText", "Hello 世界 🌍!")
text, err := client.ReadWString(ctx, "MAIN.unicodeText")
Struct and Array Access
// Struct field access (dot notation)
temp, err := client.ReadFloat32(ctx, "MAIN.sensor.temperature")
err = client.WriteUint16(ctx, "MAIN.config.timeout", 5000)

// Array element access (bracket notation)
value, err := client.ReadInt32(ctx, "MAIN.dataBuffer[10]")
err = client.WriteUint16(ctx, "MAIN.statusArray[5]", 42)

// Struct arrays (combined notation)
sensorTemp, err := client.ReadFloat32(ctx, "MAIN.sensors[2].temperature")
err = client.WriteString(ctx, "MAIN.devices[0].name", "Device1")

// Automatic struct parsing (fetches type info from PLC)
data, err := client.ReadStructAsMap(ctx, "MAIN.myStruct")
if err != nil {
    log.Fatal(err)
}

// Access parsed fields by name
field1 := data["field1"].(int32)
field2 := data["temperature"].(float32)
field3 := data["name"].(string)

// Works with struct arrays too!
structData, err := client.ReadStructAsMap(ctx, "MAIN.structArray[3]")
Notifications (Real-Time Monitoring)
// Subscribe to a variable by name (easiest)
sub, err := client.SubscribeSymbol(ctx, "MAIN.counter", goadstc.SymbolNotificationOptions{
    TransmissionMode: ads.TransModeOnChange,  // Notify on change
    MaxDelay:         100 * time.Millisecond,
    CycleTime:        50 * time.Millisecond,
})
if err != nil {
    log.Fatal(err)
}
defer sub.Close()

// Process notifications
go func() {
    for notif := range sub.Notifications() {
        value := binary.LittleEndian.Uint32(notif.Data)
        fmt.Printf("Counter changed to %d at %s\n", value, notif.Timestamp)
    }
}()

// Supported transmission modes:
// - TransModeCyclic: Send at fixed intervals
// - TransModeOnChange: Send only when value changes
// - TransModeCyclicOnChange: Combination of both
Symbol Table Operations
// List all symbols
symbols, err := client.ListSymbols(ctx)
for _, sym := range symbols {
    fmt.Printf("%s: %s (%d bytes)\n", sym.Name, sym.Type.Name, sym.Size)
}

// Search for symbols
mainSymbols, err := client.FindSymbols(ctx, "MAIN")
for _, sym := range mainSymbols {
    fmt.Printf("Found: %s\n", sym.Name)
}

// Get specific symbol info
symbol, err := client.GetSymbol("MAIN.counter")
fmt.Printf("Type: %s, Size: %d, IndexGroup: 0x%X\n",
    symbol.Type.Name, symbol.Size, symbol.IndexGroup)

// Refresh symbol table (if PLC program changes)
err = client.RefreshSymbols(ctx)
Low-Level Operations
// Direct memory access (if you need it)
data, err := client.Read(ctx, 0x4020, 0, 4) // Read 4 bytes from %M0
err = client.Write(ctx, 0x4020, 0, []byte{0x01, 0x02, 0x03, 0x04})

// Combined read-write
result, err := client.ReadWrite(ctx, 0xF003, 0, 4, []byte("MAIN.var\x00"))

// PLC control
state, err := client.ReadState(ctx)
err = client.WriteControl(ctx, ads.StateRun, 0, nil) // Start PLC

Data Type Mapping

TwinCAT Type Go Type Size Read Method Write Method
BOOL bool 1 byte ReadBool WriteBool
BYTE, USINT, UINT8 uint8 1 byte ReadUint8 WriteUint8
SINT, INT8 int8 1 byte ReadInt8 WriteInt8
WORD, UINT, UINT16 uint16 2 bytes ReadUint16 WriteUint16
INT, INT16 int16 2 bytes ReadInt16 WriteInt16
DWORD, UDINT, UINT32 uint32 4 bytes ReadUint32 WriteUint32
DINT, INT32 int32 4 bytes ReadInt32 WriteInt32
LWORD, ULINT, UINT64 uint64 8 bytes ReadUint64 WriteUint64
LINT, INT64 int64 8 bytes ReadInt64 WriteInt64
REAL, FLOAT float32 4 bytes ReadFloat32 WriteFloat32
LREAL, DOUBLE float64 8 bytes ReadFloat64 WriteFloat64
STRING string Variable ReadString WriteString
WSTRING string Variable ReadWString WriteWString
TIME time.Duration 4 bytes ReadTime WriteTime
DATE time.Time 4 bytes ReadDate WriteDate
TIME_OF_DAY, TOD time.Duration 4 bytes ReadTimeOfDay WriteTimeOfDay
DATE_AND_TIME, DT time.Time 4 bytes ReadDateAndTime WriteDateAndTime
Common Index Groups (Low-Level Access)
Index Group Description
0x00004020 PLC memory (%M)
0x0000F020 Physical inputs (%I)
0x0000F030 Physical outputs (%Q)
0xF003 Get symbol handle by name
0xF006 Release symbol handle
0xF00B Upload symbol table
0xF00C Get symbol upload info
0xF010 Get data type upload info
0xF011 Upload data type info

Examples

See the examples/ directory for complete working examples:

Project Structure

/
├── client.go                  # Core client API
├── client_types.go            # Type-safe read/write methods
├── client_structs.go          # Struct parsing and type discovery
├── client_notifications.go    # Notification subscriptions
├── subscription.go            # Subscription management
├── internal/
│   ├── ams/                   # AMS protocol implementation
│   ├── ads/                   # ADS command handling
│   ├── symbols/               # Symbol table parsing
│   └── transport/             # TCP transport layer
├── examples/                  # Usage examples
└── tests/                     # Test suite

Development

Building
go build ./...
Running Examples
# Configure your PLC connection in the example
go run ./examples/typesafe/.
go run ./examples/arrays/.
go run ./examples/timedate/.
Testing
go test ./...

Protocol Implementation

This library implements the TwinCAT ADS/AMS protocol according to the official Beckhoff specification:

  • AMS/TCP Header: 6 bytes (reserved + length)
  • AMS Header: 32 bytes (routing and control information)
  • ADS Data: Variable length payload
  • Byte Order: Little-endian for all multi-byte fields
  • Transport: TCP only (UDP not supported)
  • Automatic Type Discovery: Fetches struct definitions from PLC using command 0xF011
  • Symbol Resolution: Caches symbol table for fast lookups

Limitations

  • UDP Transport: Not supported (TCP only)
  • Router Management: Direct TCP connection only, no routing table management
  • Multi-Dimensional Arrays: Currently supports single dimension (e.g., array[5])

Contributing

Contributions are welcome! Please ensure:

  • Code follows Go conventions
  • All examples compile and run
  • Documentation is updated for new features

License

MIT

References

Support

For issues, questions, or contributions, please visit the GitHub repository.

Documentation

Overview

Package goadstc provides a Go client library for TwinCAT ADS/AMS communication over TCP.

Index

Constants

View Source
const (
	StateConnecting    = transport.StateConnecting
	StateConnected     = transport.StateConnected
	StateDisconnecting = transport.StateDisconnecting
	StateClosed        = transport.StateClosed
	StateError         = transport.StateError
)

Connection state constants

View Source
const (
	// VersionMajor is the major version number.
	VersionMajor = 0

	// VersionMinor is the minor version number.
	VersionMinor = 2

	// VersionPatch is the patch version number.
	VersionPatch = 2

	// VersionPrerelease is the pre-release version string (e.g., "alpha", "beta", "rc.1").
	// Empty string for stable releases.
	VersionPrerelease = ""
)

Variables

This section is empty.

Functions

func ContextWithLogFields

func ContextWithLogFields(ctx context.Context, args ...any) context.Context

ContextWithLogFields adds log fields to a context that will be automatically included in log messages when using LoggerFromContext.

func NewADSError

func NewADSError(operation string, adsErr ads.Error) error

NewADSError creates a classified ADS error.

func NewNetworkError

func NewNetworkError(operation string, err error) error

NewNetworkError creates a classified network error.

func NewStateError

func NewStateError(operation, message string) error

NewStateError creates a classified state error.

func NewValidationError

func NewValidationError(operation, message string) error

NewValidationError creates a classified validation error.

func Version

func Version() string

Version returns the semantic version string of the library.

Types

type BuildInfo

type BuildInfo struct {
	Version   string
	GitCommit string
	GitTag    string
	BuildTime string
	GoVersion string
	Dirty     bool
}

BuildInfo contains version and build information.

func GetBuildInfo

func GetBuildInfo() BuildInfo

GetBuildInfo returns detailed build information including version and VCS details. When built with build info, it includes git commit hash and other metadata.

func (BuildInfo) String

func (b BuildInfo) String() string

String returns a human-readable string representation of BuildInfo.

type ClassifiedError

type ClassifiedError struct {
	Category    ErrorCategory
	Operation   string // The operation that failed (e.g., "read", "write", "connect")
	Err         error
	Retryable   bool // Whether the operation can be retried
	ADSError    *ads.Error
	SymbolName  string  // Optional: the symbol name if relevant
	IndexGroup  *uint32 // Optional: index group if relevant
	IndexOffset *uint32 // Optional: index offset if relevant
}

ClassifiedError wraps an error with additional classification metadata.

func ClassifyError

func ClassifyError(err error, operation string) *ClassifiedError

ClassifyError attempts to classify an error into a category.

func (*ClassifiedError) Error

func (e *ClassifiedError) Error() string

func (*ClassifiedError) IsRetryable

func (e *ClassifiedError) IsRetryable() bool

IsRetryable returns whether the error indicates a retryable condition.

func (*ClassifiedError) Unwrap

func (e *ClassifiedError) Unwrap() error

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client represents an ADS client connection.

func New

func New(opts ...Option) (*Client, error)

New creates a new ADS client with the given options.

func (*Client) Close

func (c *Client) Close() error

Close closes the client connection and all active subscriptions.

func (*Client) FindSymbols

func (c *Client) FindSymbols(ctx context.Context, pattern string) ([]*symbols.Symbol, error)

FindSymbols searches for symbols matching the pattern (case-insensitive substring).

func (*Client) GetDataTypeUploadInfo

func (c *Client) GetDataTypeUploadInfo(ctx context.Context) (dataTypeCount, dataTypeSize uint32, err error)

GetDataTypeUploadInfo retrieves information about the data type table.

func (*Client) GetRegisteredType

func (c *Client) GetRegisteredType(typeName string) (symbols.TypeInfo, bool)

GetRegisteredType retrieves a registered type definition.

func (*Client) GetSymbol

func (c *Client) GetSymbol(name string) (*symbols.Symbol, error)

GetSymbol retrieves symbol information by name.

func (*Client) GetSymbolHandle

func (c *Client) GetSymbolHandle(ctx context.Context, symbolName string) (uint32, error)

GetSymbolHandle retrieves a handle for the given symbol name. The handle can be used with Read/Write operations using the handle's IndexGroup/IndexOffset. Handles should be released with ReleaseSymbolHandle when no longer needed.

func (*Client) GetSymbolUploadInfo

func (c *Client) GetSymbolUploadInfo(ctx context.Context) (symbolCount, symbolLength uint32, err error)

GetSymbolUploadInfo retrieves information about the PLC symbol table. Returns the number of symbols and total size of symbol data.

func (*Client) ListRegisteredTypes

func (c *Client) ListRegisteredTypes() []string

ListRegisteredTypes returns all registered type names.

func (*Client) ListSymbols

func (c *Client) ListSymbols(ctx context.Context) ([]*symbols.Symbol, error)

ListSymbols returns all symbols in the cache. Calls RefreshSymbols automatically if symbols not loaded.

func (*Client) Read

func (c *Client) Read(ctx context.Context, indexGroup, indexOffset, length uint32) ([]byte, error)

Read reads data from the ADS device.

func (*Client) ReadBool

func (c *Client) ReadBool(ctx context.Context, symbolName string) (bool, error)

ReadBool reads a BOOL value from a symbol by name.

func (*Client) ReadDate

func (c *Client) ReadDate(ctx context.Context, symbolName string) (time.Time, error)

ReadDate reads a DATE value from a symbol and returns it as time.Time. DATE is stored as a 32-bit unsigned integer representing seconds since 1970-01-01.

func (*Client) ReadDateAndTime

func (c *Client) ReadDateAndTime(ctx context.Context, symbolName string) (time.Time, error)

ReadDateAndTime reads a DATE_AND_TIME value from a symbol and returns it as time.Time. DATE_AND_TIME is stored as a 32-bit unsigned integer representing seconds since 1970-01-01.

func (*Client) ReadDeviceInfo

func (c *Client) ReadDeviceInfo(ctx context.Context) (*DeviceInfo, error)

ReadDeviceInfo reads the device name and version.

func (*Client) ReadFloat32

func (c *Client) ReadFloat32(ctx context.Context, symbolName string) (float32, error)

ReadFloat32 reads a REAL/FLOAT value from a symbol by name.

func (*Client) ReadFloat64

func (c *Client) ReadFloat64(ctx context.Context, symbolName string) (float64, error)

ReadFloat64 reads an LREAL/DOUBLE value from a symbol by name.

func (*Client) ReadInt8

func (c *Client) ReadInt8(ctx context.Context, symbolName string) (int8, error)

ReadInt8 reads an INT8/SINT value from a symbol by name.

func (*Client) ReadInt16

func (c *Client) ReadInt16(ctx context.Context, symbolName string) (int16, error)

ReadInt16 reads an INT16/INT value from a symbol by name.

func (*Client) ReadInt32

func (c *Client) ReadInt32(ctx context.Context, symbolName string) (int32, error)

ReadInt32 reads an INT32/DINT value from a symbol by name.

func (*Client) ReadInt64

func (c *Client) ReadInt64(ctx context.Context, symbolName string) (int64, error)

ReadInt64 reads an INT64/LINT value from a symbol by name.

func (*Client) ReadMultipleSymbolValues added in v0.2.2

func (c *Client) ReadMultipleSymbolValues(ctx context.Context, symbolNames ...string) (map[string]interface{}, error)

ReadMultipleSymbolValues reads multiple symbols in individual requests and returns a map of results. TODO: Future enhancement - use SumCommand (0xF080) for batched reads in single request.

func (*Client) ReadState

func (c *Client) ReadState(ctx context.Context) (*DeviceState, error)

ReadState reads the ADS and device state.

func (*Client) ReadString

func (c *Client) ReadString(ctx context.Context, symbolName string) (string, error)

ReadString reads a STRING value from a symbol by name. TwinCAT strings are null-terminated and may have a fixed buffer size. Returns the string up to the first null byte.

func (*Client) ReadStructAsMap deprecated

func (c *Client) ReadStructAsMap(ctx context.Context, symbolName string) (map[string]interface{}, error)

ReadStructAsMap reads a struct symbol and returns its fields as a map. The map keys are field names and values are interface{} containing the parsed values. If the struct type is registered via RegisterType, it will use that information for parsing.

Deprecated: Use ReadSymbolValue instead, which automatically detects and parses all types. ReadSymbolValue provides the same functionality with better ergonomics and no manual type registration needed.

func (*Client) ReadStructFieldBool deprecated

func (c *Client) ReadStructFieldBool(ctx context.Context, fieldPath string) (bool, error)

Deprecated: Use ReadSymbolValue or ReadBool with dot notation

func (*Client) ReadStructFieldInt16 deprecated

func (c *Client) ReadStructFieldInt16(ctx context.Context, fieldPath string) (int16, error)

Deprecated: Use ReadSymbolValue or type-safe Read methods with dot notation (e.g., ReadInt16(ctx, "MAIN.struct.field"))

func (*Client) ReadStructFieldInt32 deprecated

func (c *Client) ReadStructFieldInt32(ctx context.Context, fieldPath string) (int32, error)

Deprecated: Use ReadSymbolValue or ReadInt32 with dot notation

func (*Client) ReadStructFieldUint16 deprecated

func (c *Client) ReadStructFieldUint16(ctx context.Context, fieldPath string) (uint16, error)

Deprecated: Use ReadSymbolValue or ReadUint16 with dot notation

func (*Client) ReadStructFieldUint32 deprecated

func (c *Client) ReadStructFieldUint32(ctx context.Context, fieldPath string) (uint32, error)

Deprecated: Use ReadSymbolValue or ReadUint32 with dot notation

func (*Client) ReadSymbol

func (c *Client) ReadSymbol(ctx context.Context, symbolName string) ([]byte, error)

ReadSymbol reads data from a PLC symbol by name. Supports array element access using bracket notation: "MAIN.myArray[5]" Automatically loads symbol table on first call.

func (*Client) ReadSymbolValue added in v0.2.2

func (c *Client) ReadSymbolValue(ctx context.Context, symbolName string) (interface{}, error)

ReadSymbolValue automatically detects the type of a symbol and returns its parsed value. For basic types (INT, REAL, BOOL, etc.), it returns the appropriate Go primitive type. For arrays, it returns []interface{} with all elements. For structs, it returns map[string]interface{} with all fields. This method uses the symbol table to determine the type and reads/parses in one call.

func (*Client) ReadTime

func (c *Client) ReadTime(ctx context.Context, symbolName string) (time.Duration, error)

ReadTime reads a TIME value from a symbol and returns it as time.Duration. TIME is stored as a 32-bit signed integer representing milliseconds.

func (*Client) ReadTimeOfDay

func (c *Client) ReadTimeOfDay(ctx context.Context, symbolName string) (time.Duration, error)

ReadTimeOfDay reads a TIME_OF_DAY value from a symbol and returns it as time.Duration. TIME_OF_DAY is stored as a 32-bit unsigned integer representing milliseconds since midnight.

func (*Client) ReadUint8

func (c *Client) ReadUint8(ctx context.Context, symbolName string) (uint8, error)

ReadUint8 reads a UINT8/USINT/BYTE value from a symbol by name.

func (*Client) ReadUint16

func (c *Client) ReadUint16(ctx context.Context, symbolName string) (uint16, error)

ReadUint16 reads a UINT16/UINT/WORD value from a symbol by name.

func (*Client) ReadUint32

func (c *Client) ReadUint32(ctx context.Context, symbolName string) (uint32, error)

ReadUint32 reads a UINT32/UDINT/DWORD value from a symbol by name.

func (*Client) ReadUint64

func (c *Client) ReadUint64(ctx context.Context, symbolName string) (uint64, error)

ReadUint64 reads a UINT64/ULINT/LWORD value from a symbol by name.

func (*Client) ReadWString

func (c *Client) ReadWString(ctx context.Context, symbolName string) (string, error)

ReadWString reads a WSTRING (wide string, UTF-16LE) value from a symbol. Returns the string as UTF-8.

func (*Client) ReadWrite

func (c *Client) ReadWrite(ctx context.Context, indexGroup, indexOffset, readLength uint32, writeData []byte) ([]byte, error)

ReadWrite writes and reads data in a single operation.

func (*Client) ReconnectAttempts

func (c *Client) ReconnectAttempts() int

ReconnectAttempts returns the current number of reconnection attempts. Returns 0 if connected or auto-reconnect is disabled.

func (*Client) RefreshSymbols

func (c *Client) RefreshSymbols(ctx context.Context) error

RefreshSymbols downloads and parses the symbol table from the PLC. This method should be called before using symbol-based operations. It can be called multiple times to refresh the cache if the PLC program changes.

func (*Client) RegisterType

func (c *Client) RegisterType(typeInfo symbols.TypeInfo)

RegisterType registers a custom type definition for automatic struct parsing. This allows ReadStructAsMap to automatically parse structs based on registered type information.

func (*Client) ReleaseSymbolHandle

func (c *Client) ReleaseSymbolHandle(ctx context.Context, handle uint32) error

ReleaseSymbolHandle releases a previously acquired symbol handle.

func (*Client) SetStateCallback

func (c *Client) SetStateCallback(callback ConnectionStateCallback)

SetStateCallback sets or updates the connection state callback.

func (*Client) Subscribe

func (c *Client) Subscribe(ctx context.Context, opts NotificationOptions) (*Subscription, error)

Subscribe creates a new notification subscription. The returned Subscription will deliver notifications via its Notifications() channel. Call Close() on the Subscription when done to clean up resources.

func (*Client) SubscribeSymbol

func (c *Client) SubscribeSymbol(ctx context.Context, symbolName string, opts SymbolNotificationOptions) (*Subscription, error)

SubscribeSymbol creates a notification subscription using a symbol name. This is a convenience method that automatically looks up the symbol's index group, offset, and length. The returned Subscription will deliver notifications via its Notifications() channel. Call Close() on the Subscription when done.

func (*Client) UploadDataTypeTable

func (c *Client) UploadDataTypeTable(ctx context.Context) ([]byte, error)

UploadDataTypeTable retrieves the complete data type table from the PLC.

func (*Client) UploadSymbolTable

func (c *Client) UploadSymbolTable(ctx context.Context) ([]byte, error)

UploadSymbolTable downloads the complete symbol table from the PLC. The returned data is in raw TwinCAT format and needs parsing.

func (*Client) Write

func (c *Client) Write(ctx context.Context, indexGroup, indexOffset uint32, data []byte) error

Write writes data to the ADS device.

func (*Client) WriteBool

func (c *Client) WriteBool(ctx context.Context, symbolName string, value bool) error

WriteBool writes a BOOL value to a symbol by name.

func (*Client) WriteControl

func (c *Client) WriteControl(ctx context.Context, adsState ads.ADSState, deviceState uint16, data []byte) error

WriteControl changes the ADS state of the device. This can be used to start, stop, reset the PLC, or perform other state transitions. The data parameter is optional and can be nil for most operations.

func (*Client) WriteDate

func (c *Client) WriteDate(ctx context.Context, symbolName string, value time.Time) error

WriteDate writes a time.Time value to a DATE symbol. DATE is stored as a 32-bit unsigned integer representing seconds since 1970-01-01.

func (*Client) WriteDateAndTime

func (c *Client) WriteDateAndTime(ctx context.Context, symbolName string, value time.Time) error

WriteDateAndTime writes a time.Time value to a DATE_AND_TIME symbol. DATE_AND_TIME is stored as a 32-bit unsigned integer representing seconds since 1970-01-01.

func (*Client) WriteFloat32

func (c *Client) WriteFloat32(ctx context.Context, symbolName string, value float32) error

WriteFloat32 writes a REAL/FLOAT value to a symbol by name.

func (*Client) WriteFloat64

func (c *Client) WriteFloat64(ctx context.Context, symbolName string, value float64) error

WriteFloat64 writes an LREAL/DOUBLE value to a symbol by name.

func (*Client) WriteInt8

func (c *Client) WriteInt8(ctx context.Context, symbolName string, value int8) error

WriteInt8 writes an INT8/SINT value to a symbol by name.

func (*Client) WriteInt16

func (c *Client) WriteInt16(ctx context.Context, symbolName string, value int16) error

WriteInt16 writes an INT16/INT value to a symbol by name.

func (*Client) WriteInt32

func (c *Client) WriteInt32(ctx context.Context, symbolName string, value int32) error

WriteInt32 writes an INT32/DINT value to a symbol by name.

func (*Client) WriteInt64

func (c *Client) WriteInt64(ctx context.Context, symbolName string, value int64) error

WriteInt64 writes an INT64/LINT value to a symbol by name.

func (*Client) WriteString

func (c *Client) WriteString(ctx context.Context, symbolName string, value string) error

WriteString writes a STRING value to a symbol by name. TwinCAT strings have a fixed buffer size. The value is null-terminated and padded with zeros to fill the buffer.

func (*Client) WriteStructFieldBool deprecated

func (c *Client) WriteStructFieldBool(ctx context.Context, fieldPath string, value bool) error

Deprecated: Use WriteSymbolValue or WriteBool with dot notation

func (*Client) WriteStructFieldInt16 deprecated

func (c *Client) WriteStructFieldInt16(ctx context.Context, fieldPath string, value int16) error

Deprecated: Use WriteSymbolValue or WriteInt16 with dot notation

func (*Client) WriteStructFieldInt32 deprecated

func (c *Client) WriteStructFieldInt32(ctx context.Context, fieldPath string, value int32) error

Deprecated: Use WriteSymbolValue or WriteInt32 with dot notation

func (*Client) WriteStructFieldUint16 deprecated

func (c *Client) WriteStructFieldUint16(ctx context.Context, fieldPath string, value uint16) error

Deprecated: Use WriteSymbolValue or WriteUint16 with dot notation

func (*Client) WriteStructFieldUint32 deprecated

func (c *Client) WriteStructFieldUint32(ctx context.Context, fieldPath string, value uint32) error

Deprecated: Use WriteSymbolValue or WriteUint32 with dot notation

func (*Client) WriteStructFields added in v0.2.2

func (c *Client) WriteStructFields(ctx context.Context, symbolName string, fieldValues map[string]interface{}) error

WriteStructFields writes multiple fields to a struct by reading the entire struct, modifying the specified fields at their byte offsets, and writing the struct back. This is useful when individual field symbols aren't exported in the PLC.

fieldValues is a map where keys are field names and values are the Go values to write. The function automatically encodes each value based on its type information from the PLC.

Example:

err := client.WriteStructFields(ctx, "MAIN.myStruct", map[string]interface{}{
    "temperature": float32(25.5),
    "enabled": true,
    "counter": int16(42),
})

func (*Client) WriteSymbol

func (c *Client) WriteSymbol(ctx context.Context, symbolName string, data []byte) error

WriteSymbol writes data to a PLC symbol by name. Supports array element access using bracket notation: "MAIN.myArray[5]" Automatically loads symbol table on first call.

func (*Client) WriteSymbolValue added in v0.2.2

func (c *Client) WriteSymbolValue(ctx context.Context, symbolName string, value interface{}) error

WriteSymbolValue automatically encodes and writes a value to a symbol based on its type. Supports basic types (int, float, bool, string), time.Duration, and time.Time. For complex types (structs, arrays), use the specific Write methods or WriteSymbol with raw bytes.

func (*Client) WriteTime

func (c *Client) WriteTime(ctx context.Context, symbolName string, value time.Duration) error

WriteTime writes a time.Duration value to a TIME symbol. TIME is stored as a 32-bit signed integer representing milliseconds.

func (*Client) WriteTimeOfDay

func (c *Client) WriteTimeOfDay(ctx context.Context, symbolName string, value time.Duration) error

WriteTimeOfDay writes a time.Duration value to a TIME_OF_DAY symbol. TIME_OF_DAY is stored as a 32-bit unsigned integer representing milliseconds since midnight.

func (*Client) WriteUint8

func (c *Client) WriteUint8(ctx context.Context, symbolName string, value uint8) error

WriteUint8 writes a UINT8/USINT/BYTE value to a symbol by name.

func (*Client) WriteUint16

func (c *Client) WriteUint16(ctx context.Context, symbolName string, value uint16) error

WriteUint16 writes a UINT16/UINT/WORD value to a symbol by name.

func (*Client) WriteUint32

func (c *Client) WriteUint32(ctx context.Context, symbolName string, value uint32) error

WriteUint32 writes a UINT32/UDINT/DWORD value to a symbol by name.

func (*Client) WriteUint64

func (c *Client) WriteUint64(ctx context.Context, symbolName string, value uint64) error

WriteUint64 writes a UINT64/ULINT/LWORD value to a symbol by name.

func (*Client) WriteWString

func (c *Client) WriteWString(ctx context.Context, symbolName string, value string) error

WriteWString writes a string value to a WSTRING symbol. The string is converted from UTF-8 to UTF-16LE. WSTRING has a fixed buffer size, and the value is null-terminated and padded with zeros.

type ConnectionState

type ConnectionState = transport.ConnectionState

ConnectionState represents the state of the client connection.

type ConnectionStateCallback

type ConnectionStateCallback func(oldState, newState ConnectionState, err error)

ConnectionStateCallback is called when connection state changes.

type DeviceInfo

type DeviceInfo struct {
	Name         string
	MajorVersion uint8
	MinorVersion uint8
	VersionBuild uint16
}

DeviceInfo represents device information returned by ReadDeviceInfo.

type DeviceState

type DeviceState struct {
	ADSState    ads.ADSState
	DeviceState uint16
}

DeviceState represents the state of an ADS device.

type ErrorCategory

type ErrorCategory int

ErrorCategory represents the type of error for better error handling.

const (
	// ErrorCategoryUnknown represents an unclassified error.
	ErrorCategoryUnknown ErrorCategory = iota

	// ErrorCategoryNetwork represents network-level errors (connection, timeout, etc.).
	ErrorCategoryNetwork

	// ErrorCategoryProtocol represents AMS/ADS protocol errors.
	ErrorCategoryProtocol

	// ErrorCategoryADS represents ADS device errors returned by the PLC.
	ErrorCategoryADS

	// ErrorCategoryValidation represents input validation errors.
	ErrorCategoryValidation

	// ErrorCategoryConfiguration represents configuration errors.
	ErrorCategoryConfiguration

	// ErrorCategoryTimeout represents timeout errors.
	ErrorCategoryTimeout

	// ErrorCategoryState represents state-related errors (e.g., client closed).
	ErrorCategoryState
)

func (ErrorCategory) String

func (c ErrorCategory) String() string

type InMemoryMetrics

type InMemoryMetrics struct {

	// Connection metrics
	ConnectionAttemptsCount  atomic.Int64
	ConnectionSuccessesCount atomic.Int64
	ConnectionFailuresCount  atomic.Int64
	ConnectionActiveState    atomic.Bool
	ReconnectionsCount       atomic.Int64

	// Operation metrics
	OperationCounts    map[string]*atomic.Int64
	OperationDurations map[string][]time.Duration
	OperationErrors    map[string]*atomic.Int64

	// Data transfer metrics
	BytesSentCount     atomic.Int64
	BytesReceivedCount atomic.Int64

	// Notification metrics
	NotificationsReceivedCount atomic.Int64
	NotificationsDroppedCount  atomic.Int64
	SubscriptionsActiveCount   atomic.Int64

	// Error metrics
	ErrorsByCategory  map[ErrorCategory]*atomic.Int64
	ErrorsByOperation map[string]*atomic.Int64

	// Health metrics
	HealthChecksStartedCount atomic.Int64
	HealthChecksSuccessCount atomic.Int64
	HealthChecksFailureCount atomic.Int64
	// contains filtered or unexported fields
}

InMemoryMetrics provides a simple in-memory metrics collector for testing and debugging.

func NewInMemoryMetrics

func NewInMemoryMetrics() *InMemoryMetrics

NewInMemoryMetrics creates a new in-memory metrics collector.

func (*InMemoryMetrics) BytesReceived

func (m *InMemoryMetrics) BytesReceived(bytes int64)

func (*InMemoryMetrics) BytesSent

func (m *InMemoryMetrics) BytesSent(bytes int64)

func (*InMemoryMetrics) ConnectionActive

func (m *InMemoryMetrics) ConnectionActive(active bool)

func (*InMemoryMetrics) ConnectionAttempts

func (m *InMemoryMetrics) ConnectionAttempts()

func (*InMemoryMetrics) ConnectionFailures

func (m *InMemoryMetrics) ConnectionFailures()

func (*InMemoryMetrics) ConnectionSuccesses

func (m *InMemoryMetrics) ConnectionSuccesses()

func (*InMemoryMetrics) ErrorOccurred

func (m *InMemoryMetrics) ErrorOccurred(category ErrorCategory, operation string)

func (*InMemoryMetrics) HealthCheckCompleted

func (m *InMemoryMetrics) HealthCheckCompleted(success bool)

func (*InMemoryMetrics) HealthCheckStarted

func (m *InMemoryMetrics) HealthCheckStarted()

func (*InMemoryMetrics) NotificationDropped

func (m *InMemoryMetrics) NotificationDropped()

func (*InMemoryMetrics) NotificationReceived

func (m *InMemoryMetrics) NotificationReceived()

func (*InMemoryMetrics) OperationCompleted

func (m *InMemoryMetrics) OperationCompleted(operation string, duration time.Duration, err error)

func (*InMemoryMetrics) OperationStarted

func (m *InMemoryMetrics) OperationStarted(operation string)

func (*InMemoryMetrics) Reconnections

func (m *InMemoryMetrics) Reconnections()

func (*InMemoryMetrics) Snapshot

func (m *InMemoryMetrics) Snapshot() MetricsSnapshot

Snapshot returns a copy of current metrics for reporting.

func (*InMemoryMetrics) SubscriptionsActive

func (m *InMemoryMetrics) SubscriptionsActive(count int)

type Logger

type Logger interface {
	Debug(msg string, args ...any)
	Info(msg string, args ...any)
	Warn(msg string, args ...any)
	Error(msg string, args ...any)
	With(args ...any) Logger
}

Logger defines the interface for structured logging in goadstc. It follows the standard slog.Logger interface for compatibility.

var (
	// DefaultLogger is a no-op logger to minimize overhead when logging is not configured.
	DefaultLogger Logger = &noopLogger{}
)

func LoggerFromContext

func LoggerFromContext(ctx context.Context, logger Logger) Logger

LoggerFromContext returns a logger with context fields attached.

func NewDefaultLogger

func NewDefaultLogger() Logger

NewDefaultLogger creates a basic JSON logger writing to stderr.

func NewSlogLogger

func NewSlogLogger(logger *slog.Logger) Logger

NewSlogLogger creates a Logger from a slog.Logger.

type Metrics

type Metrics interface {
	// Connection metrics
	ConnectionAttempts()
	ConnectionSuccesses()
	ConnectionFailures()
	ConnectionActive(active bool)
	Reconnections()

	// Operation metrics
	OperationStarted(operation string)
	OperationCompleted(operation string, duration time.Duration, err error)

	// Data transfer metrics
	BytesSent(bytes int64)
	BytesReceived(bytes int64)

	// Notification metrics
	NotificationReceived()
	NotificationDropped()
	SubscriptionsActive(count int)

	// Error metrics
	ErrorOccurred(category ErrorCategory, operation string)

	// Health metrics
	HealthCheckStarted()
	HealthCheckCompleted(success bool)
}

Metrics defines the interface for collecting operational metrics. Implementations can export metrics to various backends (Prometheus, StatsD, etc.).

var (
	// DefaultMetrics is a no-op metrics collector to minimize overhead when metrics are not configured.
	DefaultMetrics Metrics = &noopMetrics{}
)

type MetricsSnapshot

type MetricsSnapshot struct {
	ConnectionAttempts    int64
	ConnectionSuccesses   int64
	ConnectionFailures    int64
	ConnectionActive      bool
	Reconnections         int64
	BytesSent             int64
	BytesReceived         int64
	NotificationsReceived int64
	NotificationsDropped  int64
	SubscriptionsActive   int64
	HealthChecksStarted   int64
	HealthChecksSuccess   int64
	HealthChecksFailure   int64
	OperationCounts       map[string]int64
	OperationErrors       map[string]int64
	ErrorsByCategory      map[ErrorCategory]int64
	ErrorsByOperation     map[string]int64
}

MetricsSnapshot represents a point-in-time snapshot of metrics.

type Notification

type Notification struct {
	Data      []byte
	Timestamp time.Time
}

Notification represents a single notification event from the PLC.

type NotificationOptions

type NotificationOptions struct {
	IndexGroup       uint32
	IndexOffset      uint32
	Length           uint32
	TransmissionMode ads.TransmissionMode
	MaxDelay         time.Duration // Maximum delay before notification is sent
	CycleTime        time.Duration // Cycle time for cyclic notifications
}

NotificationOptions configures a notification subscription.

type Option

type Option func(*clientConfig) error

Option is a functional option for configuring a Client.

func WithAMSNetID

func WithAMSNetID(netID ams.NetID) Option

WithAMSNetID sets the target AMS NetID (required).

func WithAMSPort

func WithAMSPort(port ams.Port) Option

WithAMSPort sets the target AMS port (optional, defaults to 851).

func WithAutoReconnect

func WithAutoReconnect(enabled bool) Option

WithAutoReconnect enables automatic reconnection on connection loss (optional). When enabled, the client will automatically attempt to reconnect with exponential backoff. Subscriptions will be re-established after successful reconnection.

func WithHealthCheck

func WithHealthCheck(period time.Duration) Option

WithHealthCheck enables periodic health checks (optional). The client will periodically send a ReadState request to verify connection. If health check fails and auto-reconnect is enabled, reconnection will be triggered.

func WithLogger

func WithLogger(logger Logger) Option

WithLogger returns a new option that sets the logger for the client.

func WithMaxReconnectDelay

func WithMaxReconnectDelay(delay time.Duration) Option

WithMaxReconnectDelay sets the maximum delay between reconnection attempts (optional). Default is 60 seconds. Only applies when auto-reconnect is enabled.

func WithMetrics

func WithMetrics(metrics Metrics) Option

WithMetrics returns a new option that sets the metrics collector for the client.

func WithSourceNetID

func WithSourceNetID(netID ams.NetID) Option

WithSourceNetID sets the source AMS NetID (optional).

func WithSourcePort

func WithSourcePort(port ams.Port) Option

WithSourcePort sets the source AMS port (optional).

func WithStateCallback

func WithStateCallback(callback ConnectionStateCallback) Option

WithStateCallback sets a callback for connection state changes (optional). The callback is invoked whenever the connection state changes (connected, disconnected, etc.).

func WithTarget

func WithTarget(address string) Option

WithTarget sets the target TCP address (required).

func WithTimeout

func WithTimeout(timeout time.Duration) Option

WithTimeout sets the timeout for requests (optional).

type Subscription

type Subscription struct {
	// contains filtered or unexported fields
}

Subscription represents an active ADS notification subscription.

func (*Subscription) Close

func (s *Subscription) Close() error

Close unsubscribes from the notification and closes the notification channel. It's safe to call Close multiple times.

func (*Subscription) Handle

func (s *Subscription) Handle() uint32

Handle returns the notification handle assigned by the PLC.

func (*Subscription) Notifications

func (s *Subscription) Notifications() <-chan Notification

Notifications returns the channel for receiving notifications. The channel is closed when the subscription is closed.

type SymbolNotificationOptions

type SymbolNotificationOptions struct {
	TransmissionMode ads.TransmissionMode
	MaxDelay         time.Duration // Maximum delay before notification is sent
	CycleTime        time.Duration // Cycle time for cyclic notifications
}

SymbolNotificationOptions configures a symbol-based notification subscription.

Directories

Path Synopsis
Package docs Code generated by swaggo/swag.
Package docs Code generated by swaggo/swag.
examples
arrays command
autoreconnect command
autotype command
comprehensive command
control command
field-symbols command
notifications command
observability command
structs command
symbols command
timedate command
typesafe command
version command
internal
ads
Package ads implements ADS (Automation Device Specification) command handling.
Package ads implements ADS (Automation Device Specification) command handling.
ams
Package ams implements AMS (Automation Message Specification) protocol handling.
Package ams implements AMS (Automation Message Specification) protocol handling.
symbols
Package symbols implements symbol table parsing and caching for TwinCAT 3.
Package symbols implements symbol table parsing and caching for TwinCAT 3.
transport
Package transport implements TCP transport for AMS/ADS communication.
Package transport implements TCP transport for AMS/ADS communication.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL