Help us shape the future of Go! Take the 2026 Go Developer Survey

controller

package
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Oct 26, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package controller implements a PROFINET IO-Controller (conformance class A, RT_CLASS_1/2): it finds its devices by station name with DCP, optionally assigns their IP address, establishes an application relationship with each, parameterizes it, exchanges cyclic IO data, acknowledges alarms, reads and writes records and re-establishes the AR after a failure.

Each device runs its own lifecycle on its own goroutine; a failure of one does not affect the others. Process data is exchanged through Device.SetOutput and Device.Input.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CanTransition

func CanTransition(from, to State) bool

CanTransition reports whether the lifecycle allows from → to.

Types

type ARInfo

type ARInfo struct {
	UUID       rpc.UUID     `json:"arUUID"`
	SessionKey uint16       `json:"sessionKey"`
	Type       pnio.ARType  `json:"arType"`
	RTClass    pnio.RTClass `json:"rtClass"`
	// Advanced reports the advanced startup mode.
	Advanced bool `json:"advanced"`
	// DeviceAddr is the device's RPC endpoint.
	DeviceAddr string `json:"deviceAddr"`
	// LocalAlarmRef and RemoteAlarmRef are the alarm references of the
	// controller and of the device.
	LocalAlarmRef  uint16 `json:"localAlarmRef"`
	RemoteAlarmRef uint16 `json:"remoteAlarmRef"`
	// Input and Output are the two IOCRs.
	Input  IOCRInfo `json:"input"`
	Output IOCRInfo `json:"output"`
}

ARInfo describes the established AR of a device: what Connect negotiated.

type AlarmEvent

type AlarmEvent struct {
	Device       string
	Notification pnio.AlarmNotification
	Received     time.Time
}

AlarmEvent is an alarm a device sent; the controller acknowledges it.

type Config

type Config struct {
	// Mux is the Layer 2 port; required.
	Mux *l2.Mux
	// ListenPacket opens the RPC sockets. nil uses the operating system's
	// UDP stack.
	ListenPacket ListenPacketFunc
	// RPCPort is the port of the controller's RPC server, which receives
	// the devices' ApplicationReady. Devices send it to 34964, the
	// default.
	RPCPort int
	// StationName is the controller's name in the AR (CMInitiatorStation
	// Name). Empty means "go-profinet-controller".
	StationName string
	// VendorID, DeviceID and Instance form the controller's object UUID.
	VendorID, DeviceID, Instance uint16
	// DCP configures the DCP requester.
	DCP dcp.ClientOptions
	// Logger receives diagnostics. nil logs nothing.
	Logger profinet.Logger
}

Config configures a Controller.

type Controller

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

Controller is a PROFINET IO-Controller. It is safe for concurrent use.

func New

func New(cfg Config) (*Controller, error)

New starts a controller.

func (*Controller) AddDevice

func (c *Controller) AddDevice(cfg DeviceConfig) (*Device, error)

AddDevice adds a device and starts its lifecycle.

func (*Controller) Close

func (c *Controller) Close() error

Close releases every AR and stops the controller.

func (*Controller) DCP

func (c *Controller) DCP() *dcp.Client

DCP returns the controller's DCP requester, for discovery and explicit configuration of devices.

func (*Controller) Device

func (c *Controller) Device(name string) (*Device, bool)

Device returns the device with a station name.

func (*Controller) Devices

func (c *Controller) Devices() []*Device

Devices returns the devices added to the controller.

func (*Controller) ObjectUUID

func (c *Controller) ObjectUUID() rpc.UUID

ObjectUUID returns the controller's PNIO object UUID.

func (*Controller) RPC

func (c *Controller) RPC() *rpc.Client

RPC returns the controller's RPC client.

type Device

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

Device is a device of the controller.

func (*Device) AR

func (d *Device) AR() (ARInfo, bool)

AR returns the description of the device's current AR; false when none is established.

func (*Device) ARUUID

func (d *Device) ARUUID() rpc.UUID

ARUUID returns the UUID of the current AR, nil when there is none.

func (*Device) Close

func (d *Device) Close() error

Close releases the AR (when established) and stops the lifecycle. The device is removed from the controller.

func (*Device) ConsumerStatus

func (d *Device) ConsumerStatus(slot, subslot uint16) (uint8, bool)

ConsumerStatus returns the device's consumer status (IOCS) of a submodule's outputs.

func (*Device) IP

func (d *Device) IP() dcp.IPSuite

IP returns the device's IP suite once it was resolved.

func (*Device) Input

func (d *Device) Input(slot, subslot uint16) (data []byte, iops uint8, ok bool)

Input returns a copy of the input data of a submodule and its provider status from the last cyclic frame.

func (*Device) MAC

func (d *Device) MAC() ethernet.MAC

MAC returns the device's MAC address once it was resolved.

func (*Device) ModuleDiff

func (d *Device) ModuleDiff() *pnio.ModuleDiffBlock

ModuleDiff returns the ModuleDiffBlock of the last Connect, nil when the real configuration matched.

func (*Device) Name

func (d *Device) Name() string

Name returns the device's station name.

func (*Device) ReadDiagnosis

func (d *Device) ReadDiagnosis(ctx context.Context) ([]pnio.DiagnosisData, error)

ReadDiagnosis reads the diagnosis of the whole device.

func (*Device) ReadIM0

func (d *Device) ReadIM0(ctx context.Context) (pnio.IM0, error)

ReadIM0 reads the device's I&M0.

func (*Device) ReadRecord

func (d *Device) ReadRecord(ctx context.Context, rec Record, maxLen uint32) ([]byte, error)

ReadRecord reads a record within the AR.

func (*Device) SetOutput

func (d *Device) SetOutput(slot, subslot uint16, data []byte, iops uint8) error

SetOutput sets the output data and provider status of a submodule for the next cyclic frames.

func (*Device) State

func (d *Device) State() (State, error)

State returns the lifecycle state and the error of the last failure.

func (*Device) Stats

func (d *Device) Stats() DeviceStats

Stats returns the counters of the device and of its current AR.

func (*Device) WaitState

func (d *Device) WaitState(ctx context.Context, s State) error

WaitState waits until the device is in state s.

func (*Device) WriteMultiple

func (d *Device) WriteMultiple(ctx context.Context, items []WriteItem) ([]pnio.Status, error)

WriteMultiple writes several records in one call.

func (*Device) WriteRecord

func (d *Device) WriteRecord(ctx context.Context, rec Record, data []byte) error

WriteRecord writes a record within the AR.

type DeviceConfig

type DeviceConfig struct {
	// StationName is the device's NameOfStation; required.
	StationName string
	// Model is the expected configuration; required. Its identity's vendor
	// and device ID must match what the device reports in DCP.
	Model *model.Device
	// IP is the IP suite the device should have. When AssignIP is true
	// and the device reports a different one, it is set with DCP
	// (temporarily, or permanently with PermanentIP). Without AssignIP the
	// device's own address is used.
	IP          dcp.IPSuite
	AssignIP    bool
	PermanentIP bool
	// SendClockFactor (units of 31.25 µs) and ReductionRatio define the
	// cycle; zero means 32 (1 ms) and 4: a cycle of 4 ms.
	SendClockFactor, ReductionRatio uint16
	// DataHoldFactor and WatchdogFactor are in cycles; zero means 10.
	// PLCs commonly use 3, which a general-purpose operating system does
	// not hold: its scheduling stalls of 10 to 20 ms expire a hold of 3
	// cycles of 4 ms (see docs/CYCLIC.md).
	DataHoldFactor, WatchdogFactor uint16
	// Advanced selects the advanced startup mode with RTClass 2;
	// otherwise the legacy startup with RTClass 1 is used.
	Advanced bool
	// ActivityTimeout is the CM initiator activity timeout; zero means
	// 10 s.
	ActivityTimeout time.Duration
	// RTATimeoutFactor (units of 100 ms) and RTARetries configure the
	// alarm transport; zero means 5 and 3.
	RTATimeoutFactor, RTARetries uint16
	// Parameters are written after Connect and before PrmEnd.
	Parameters []Parameter
	// RPCTimeout bounds each RPC call; zero means 5 s.
	RPCTimeout time.Duration
	// ReconnectMin and ReconnectMax bound the backoff between attempts;
	// zero means 200 ms and 10 s.
	ReconnectMin, ReconnectMax time.Duration
	// OnAlarm receives every alarm, on the alarm goroutine of the AR; it
	// must not block.
	OnAlarm func(AlarmEvent)
	// OnState receives every state change, before WaitState returns for it.
	OnState func(from, to State, err error)
}

DeviceConfig configures a device of the controller.

type DeviceStats

type DeviceStats struct {
	Connects, Aborts uint64
	Provider         rt.ProviderStats
	Consumer         rt.ConsumerStats
	Cycle            rt.TaskStats
	Alarms           uint64
}

DeviceStats are the counters of a device.

type IOCRInfo

type IOCRInfo struct {
	Type    pnio.IOCRType `json:"type"`
	FrameID uint16        `json:"frameId"`
	// DataLength is the length of the C_SDU.
	DataLength      uint16 `json:"dataLength"`
	SendClockFactor uint16 `json:"sendClockFactor"`
	ReductionRatio  uint16 `json:"reductionRatio"`
	WatchdogFactor  uint16 `json:"watchdogFactor"`
	DataHoldFactor  uint16 `json:"dataHoldFactor"`
	// Cycle is SendClockFactor × 31.25 µs × ReductionRatio.
	Cycle time.Duration `json:"cycle"`
	// Objects are the data objects of the C_SDU and IOCS the consumer
	// statuses it carries, at their offsets.
	Objects []rt.Object `json:"objects"`
	IOCS    []rt.Status `json:"iocs"`
}

IOCRInfo describes one IOCR of an AR.

type ListenPacketFunc

type ListenPacketFunc func(ctx context.Context, network, address string) (net.PacketConn, error)

ListenPacketFunc opens a UDP socket; net.ListenConfig.ListenPacket and netstack.Stack.ListenPacket have this signature.

type Parameter

type Parameter struct {
	Slot, Subslot uint16
	Index         pnio.Index
	Data          []byte
}

Parameter is a record written to a device before the end of parameterization.

type Record

type Record struct {
	API     uint32
	Slot    uint16
	Subslot uint16
	Index   pnio.Index
}

Record addresses one record.

func (Record) String

func (rec Record) String() string

type RecordClient

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

RecordClient performs the acyclic PNIO services of one device: Read, Write, ReadImplicit, Control and Release. It is safe for concurrent use.

func NewRecordClient

func NewRecordClient(c *rpc.Client, addr net.Addr, object rpc.UUID) *RecordClient

NewRecordClient returns a client for the device at addr (its RPC endpoint, port 34964) with PNIO object UUID object (see pnio.ObjectUUID). Its calls share one RPC activity, as the calls of one AR must; they run one at a time.

func (*RecordClient) Addr

func (r *RecordClient) Addr() net.Addr

Addr returns the device's RPC address.

func (*RecordClient) Connect

Connect sends a Connect request and returns the decoded response.

func (*RecordClient) Control

func (r *RecordClient) Control(ctx context.Context, c pnio.ControlBlock) error

Control sends a control block (PrmEnd, PrmBegin) and checks the Done acknowledgement.

func (*RecordClient) OpenSupervisor

func (r *RecordClient) OpenSupervisor(ctx context.Context, cfg SupervisorConfig) (*SupervisorAR, error)

OpenSupervisor establishes a device access AR with the device of r.

func (*RecordClient) Read

func (r *RecordClient) Read(ctx context.Context, ar rpc.UUID, rec Record, maxLen uint32) ([]byte, error)

Read reads a record within an AR (ar is the AR UUID) or, with a nil ar, implicitly (ReadImplicit, no AR needed). maxLen bounds the data; zero means 4096. A PNIO error is returned as a *pnio.StatusError.

func (*RecordClient) ReadDiagnosis

func (r *RecordClient) ReadDiagnosis(ctx context.Context, ar rpc.UUID, slot, subslot uint16, sub bool) ([]pnio.DiagnosisData, error)

ReadDiagnosis reads the diagnosis of the device (index 0xF80C), or of one submodule when slot and subslot are given with sub true (0x800C).

func (*RecordClient) ReadIM0

func (r *RecordClient) ReadIM0(ctx context.Context, ar rpc.UUID, slot, subslot uint16) (pnio.IM0, error)

ReadIM0 reads I&M0 of a submodule (the DAP: slot 0, subslot 1).

func (*RecordClient) Write

func (r *RecordClient) Write(ctx context.Context, ar rpc.UUID, rec Record, data []byte) error

Write writes a record within an AR.

func (*RecordClient) WriteMultiple

func (r *RecordClient) WriteMultiple(ctx context.Context, ar rpc.UUID, items []WriteItem) ([]pnio.Status, error)

WriteMultiple writes several records in one call (index 0xE040). It returns the status of each item; err reports a transport failure or a failed call without per-item results.

type State

type State uint8

State is the state of a device's lifecycle on the controller.

const (
	StateOffline State = iota
	StateResolving
	StateConnecting
	StateParameterizing
	StateWaitAppReady
	StateRunning
	StateStopped
)

States. A device goes Offline → Resolving → Connecting → Parameterizing → WaitApplicationReady → Running; a failure in any of them goes back to Offline (and after the backoff to Resolving); Close goes to Stopped.

func (State) String

func (s State) String() string

type SupervisorAR

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

SupervisorAR is a device access AR: an IOSAR with the DeviceAccess property, through which an engineering tool reads and writes records of a device without IO data, alarms or parameterization, and without the expected configuration of an IOCAR. Devices that do not support it reject the Connect.

func (*SupervisorAR) Read

func (s *SupervisorAR) Read(ctx context.Context, rec Record, maxLen uint32) ([]byte, error)

Read reads a record within the AR.

func (*SupervisorAR) Release

func (s *SupervisorAR) Release(ctx context.Context) error

Release releases the AR. Releasing it again does nothing.

func (*SupervisorAR) SessionKey

func (s *SupervisorAR) SessionKey() uint16

SessionKey returns the session key of the AR.

func (*SupervisorAR) UUID

func (s *SupervisorAR) UUID() rpc.UUID

UUID returns the AR UUID.

func (*SupervisorAR) Write

func (s *SupervisorAR) Write(ctx context.Context, rec Record, data []byte) error

Write writes a record within the AR.

Write changes the configuration of an industrial device. Only call it on an explicit request of the user.

func (*SupervisorAR) WriteMultiple

func (s *SupervisorAR) WriteMultiple(ctx context.Context, items []WriteItem) ([]pnio.Status, error)

WriteMultiple writes several records in one call.

type SupervisorConfig

type SupervisorConfig struct {
	// InitiatorMAC is the tool's MAC address; required.
	InitiatorMAC ethernet.MAC
	// InitiatorObject is the tool's PNIO object UUID (pnio.ObjectUUID);
	// required. Nothing calls it: a device access AR has no
	// ApplicationReady.
	InitiatorObject rpc.UUID
	// StationName is the tool's name in the AR. Empty means
	// "go-profinet-supervisor".
	StationName string
	// ActivityTimeout is the CM initiator activity timeout after which
	// the device closes an AR the tool left behind; zero means 10 s.
	ActivityTimeout time.Duration
}

SupervisorConfig configures a device access AR.

type WriteItem

type WriteItem struct {
	Record Record
	Data   []byte
}

WriteItem is one record of a WriteMultiple.

Jump to

Keyboard shortcuts

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