iec61850

package module
v1.0.7 Latest Latest
Warning

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

Go to latest
Published: Jul 30, 2026 License: MIT Imports: 20 Imported by: 0

README

go-iec61850

Go Go Reference License CI Codecov Release

A pure-Go IEC 61850 MMS client and server library built on top of go-mms.

Logical devices, logical nodes, data objects, data attributes, functional constraints, reports, datasets, controls, quality, timestamps, and SCL are all first-class Go types. You work with IEC 61850 semantics, not raw MMS domain names, item IDs, or alternate access selectors.


Table of contents


Features

  • Browse & discover — list logical devices, nodes, data objects; build model trees; search by glob or regex
  • Read & write — typed single/bulk reads and writes with IEC 61850 semantic values (quality, timestamps, enums, Dbpos, BCR)
  • Datasets — list, inspect, read, create, and delete named variable lists
  • Reports — full BRCB/URCB lifecycle: inspect, configure, subscribe, GI trigger, reserve/release, integrity period, segmented report reassembly, configurable overflow callback, BRCB replay on re-enable
  • Controls — direct normal, SBO normal, and SBOw (enhanced security); server-side connection-scoped ownership enforcement, configurable select timeout, panic containment for application callbacks
  • Files — list, read, download, delete, rename, obtain
  • Journals — read by time range or entry ID, auto-pagination helpers
  • SCL tooling — parse SCD/ICD/CID/IID files (schema editions v1.7 through 2007C5), validate, flatten/export, generate XML, topology lookup helpers
  • CLI toolssclparse (inspect, validate, summarize SCL files) and sclgen (re-generate Go types from XSD)
  • Caching — optional client-side model cache (none / explicit / lazy)
  • Server — SCL-driven MMS server; runtime report engine (URCB/BRCB), control handlers (SBO/SBOw state machine), setting groups, journal services

Installation

go get github.com/otfabric/go-iec61850

Requires Go 1.24 or later.

Install the CLI tools:

go install github.com/otfabric/go-iec61850/scl/cmd/sclparse@latest
go install github.com/otfabric/go-iec61850/scl/cmd/sclgen@latest

Quick start

Client
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/otfabric/go-iec61850"
)

func main() {
    ctx := context.Background()

    client, err := iec61850.Dial(ctx, "10.0.0.1:102", iec61850.DialOptions{})
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close(ctx)

    devices, err := client.ListLogicalDevices(ctx)
    if err != nil {
        log.Fatal(err)
    }
    for _, ld := range devices {
        fmt.Println(ld.Name)
    }

    // Read a data attribute by IEC 61850 reference.
    ref, _ := iec61850.ParseRef("PROT1LD/MMXU1.TotW.mag.f[MX]")
    val, err := client.Read(ctx, ref)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(val)
}
Server
package main

import (
    "context"
    "log"

    "github.com/otfabric/go-iec61850"
    "github.com/otfabric/go-iec61850/scl"
)

func main() {
    s, err := scl.ParseFile("station.icd")
    if err != nil {
        log.Fatal(err)
    }

    model, err := iec61850.NewServerModelFromSCL(s, "IED1", "")
    if err != nil {
        log.Fatal(err)
    }

    srv, err := iec61850.NewServer(model, iec61850.ServerOptions{})
    if err != nil {
        log.Fatal(err)
    }

    re := srv.EnableReports()
    defer re.Stop()

    // Register a direct-control handler for GGIO1.SPCSO1.
    srv.RegisterControl("InteropLD", "GGIO1.SPCSO1", iec61850.CtlModelDirectNormal,
        iec61850.ControlHandler{
            OnOperate: func(ctx context.Context, req iec61850.ControlRequest) error {
                log.Printf("operate: %s ctlVal=%v", req.Ref, req.CtlVal)
                return nil
            },
        })

    log.Fatal(srv.ListenAndServe(":102"))
}
SCL parsing
package main

import (
    "fmt"
    "log"

    "github.com/otfabric/go-iec61850/scl"
)

func main() {
    s, err := scl.ParseFile("station.scd")
    if err != nil {
        log.Fatal(err)
    }
    for _, ied := range s.IEDs {
        fmt.Printf("IED: %s (%s)\n", ied.Name, ied.Manufacturer)
    }

    findings := scl.Validate(s)
    for _, f := range findings {
        fmt.Println(f)
    }
}

API overview

Connection
Function Description
Dial Connect to an IEC 61850 server over MMS/TCP
NewClient Wrap an existing mms.Client
Client.Close Graceful close (MMS Conclude)
Client.Abort Immediate abort
Browse & model discovery
Method Description
ListLogicalDevices List all logical devices
ListLogicalNodes List logical nodes in an LD
ListDataObjects List data objects in an LN
ListChildren List direct children of a DO/DA
Tree / TreeWithOptions Build the full model tree
FindPaths Search by glob or regex pattern
GetVariableType Get MMS type spec for a reference
Read & write
Method Description
Read Read a typed IEC 61850 value
ReadRaw Read the raw MMS value
ReadComponent Read a single structure component
ReadMultiple Bulk read (single MMS PDU)
Write Write a value
WriteMultiple Bulk write (single MMS PDU)
Datasets
Method Description
ListDataSets List all datasets in an LD
GetDataSet Get dataset definition and member list
ReadDataSet Read all dataset member values
CreateDataSet Create a dynamic named variable list (client only; server-side dynamic dataset creation is not yet implemented)
DeleteDataSet Delete a dynamic named variable list (client only; server-side dynamic dataset deletion is not yet implemented)
Reports (URCB / BRCB)
Method Description
ListReports List all RCBs in an LD
GetReportControlBlock Read RCB attributes
SetReportControlBlock Write RCB attributes (mask-based)
SubscribeReport Subscribe and manage the full RCB lifecycle
TriggerGI Send a General Interrogation trigger
ReserveURCB / ReleaseURCB Exclusive URCB ownership
Controls
Method / Type Description
Client.Operate Direct-normal operate
Client.Select SBO normal select (reads SBO attribute)
Client.SelectWithValue SBOw enhanced-security select (writes SBOw)
Client.Cancel Cancel an active SBO reservation
Client.ReadCtlModel Read the ctlModel attribute
Server.RegisterControl Install a server-side control handler
ControlHandler Callbacks for OnSelect, OnOperate, OnCancel
CtlModelDirectNormal / CtlModelSBONormal / CtlModelSBOEnhanced Control model constants
Files
Method Description
ListFiles List files on the server
ReadFile Read file contents into memory
DownloadFile Stream file to an io.Writer
DeleteFile Delete a file
RenameFile Rename a file
ObtainFile Request server to copy a file from source to destination via its FileProvider; MMS segmented role-reversal not implemented
Journals
Method Description
ListJournals List journals in an LD
ReadJournal Read entries by time range
ReadJournalAfter Read entries after a known entry ID
ReadJournalAll Auto-paginating time-range read
ReadJournalAfterAll Auto-paginating after-entry read
Caching
Method Description
RefreshCache Refresh the full model cache
RefreshLDCache Refresh cache for one logical device
InvalidateCache Clear the full cache
InvalidateLDCache Clear cache for one logical device
SCL tooling (scl package)
Function Description
Parse / ParseFile Parse SCL XML (auto-detects schema edition)
Validate Semantic validation (types, dataset refs, topology)
Flatten / WriteCSV Flatten model to tabular rows / CSV
PrintTree Print SCL as a human-readable text tree
ExportDataSets / ExportReports Export summaries
Generate Write the SCL model back to XML
FindIED, FindLDevice, etc. Fast lookup helpers

See the scl package README for full documentation including the sclparse and sclgen command-line tools.

Server
Function / Method Description
NewServer Create an IEC 61850 server from a data model
NewServerModelFromSCL Build the server model from an SCL file
Server.Serve Handle a single accepted connection
Server.ListenAndServe Accept and serve connections on an address
Server.EnableReports Start the runtime report engine (URCB/BRCB)
Server.RegisterControl Install a control object handler
Server.SetValue Write a value and trigger change-detection reports
Server.Close Stop the server and all engines

Command-line tools

sclparse

sclparse inspects, validates, and queries IEC 61850 SCL files (SCD, ICD, CID, IID). It supports schema editions v1.7 through 2007C5 and auto-detects the version.

# Install
go install github.com/otfabric/go-iec61850/scl/cmd/sclparse@latest

# Quick overview of a file
sclparse summary station.scd

# Semantic validation (types, dataset references, topology linkage)
sclparse validate station.scd

# List all IEDs with access-point and LD counts
sclparse list-ieds station.scd

# List all report control blocks
sclparse list-reports station.scd

Available subcommands:

Subcommand Description
summary Compact overview with element counts
validate Semantic validation and diagnostics
detect Identify schema edition and document kind
inspect Show schema version, vendor namespaces, extensions
dump-json Emit normalized model as JSON
list-ieds List all IEDs with access-point and LD counts
list-lns List all logical nodes with IED/LD location
list-datasets List all datasets with member counts
list-reports List all report control blocks
list-goose List all GOOSE (GSE) control blocks
list-smv List all Sampled Values control blocks
list-connected-ap List all connected access points
list-types List all data type templates
version Print build version

See scl/README.md for detailed usage and examples.

sclgen

sclgen regenerates the internal Go type bindings from the official IEC 61850 XSD schemas. It is a developer tool — ordinary users do not need it.

# Install
go install github.com/otfabric/go-iec61850/scl/cmd/sclgen@latest

# Regenerate Go types for all supported schema editions
sclgen generate --spec-root ./scl/specs --out ./scl/internal/raw

# Verify the generated output is up to date (used in CI)
sclgen check --spec-root ./scl/specs --out ./scl/internal/raw

Available subcommands:

Subcommand Description
generate Generate Go types from XSD schemas
check Verify generated output is up to date
version Print build version

See scl/README.md for full developer documentation.


Object references

IEC 61850 object references use the format LD/LN.DO.DA[FC]:

ref, _ := iec61850.ParseRef("IEDLD1/LLN0.Mod.stVal[ST]")
fmt.Println(ref.LD)   // "IEDLD1"
fmt.Println(ref.LN)   // "LLN0"
fmt.Println(ref.Path) // ["Mod", "stVal"]
fmt.Println(ref.FC)   // "ST"

The MMS wire format uses a different convention (domain = LD, item ID = LN$FC$DO$DA). Conversion is handled by Ref.ToMMS() and RefFromMMS().

The DialOptions.IEDName field allows working with full-IED-qualified servers: when set, the client automatically prepends the IED name to outgoing domain names and strips it from returned names, so application code always uses bare LD instance names.


Functional constraints

FC Description
ST Status
MX Measured values
SP Setpoint
SV Substitution
CF Configuration
DC Description
SG Setting group
SE Setting group editable
SR Service response
OR Operate received
BL Blocking
EX Extended definition
CO Control
RP Unbuffered reporting
BR Buffered reporting

Architecture

┌─────────────────────────────────────┐
│  Application / sclparse CLI         │
├─────────────────────────────────────┤
│  go-iec61850 (this package)         │
│  IEC 61850 semantics, SCL, reports, │
│  controls, server model             │
├─────────────────────────────────────┤
│  go-mms                             │
│  Generic MMS protocol (ISO 9506)    │
├─────────────────────────────────────┤
│  go-cotp / go-tpkt                  │
│  ISO transport (COTP over TPKT)     │
└─────────────────────────────────────┘

Repository layout

go-iec61850/
│
├── *.go                        Core library (client, server, browse, read,
│                               write, reports, controls, files, journals,
│                               datasets, caching, values, FC types, errors)
│
├── examples/
│   ├── basic-client/           Connect, list LDs, read a data attribute
│   ├── browse-tree/            Print the full model tree
│   ├── control/                Direct and SBO control operations
│   ├── files/                  File listing and download
│   └── reports/                URCB/BRCB subscription and delivery
│
├── interop/                    Interoperability tests (build tag: interop)
│   │                           Runs against live libiec61850 and iec61850bean
│   │                           adapters from mms-interop
│   ├── harness_test.go         Docker-based test harness
│   ├── libiec61850_*_test.go   Tests against libiec61850 adapters
│   ├── iec61850bean_*_test.go  Tests against iec61850bean adapters
│   ├── brcb_test.go            BRCB: EntryID, replay, purge, overflow
│   ├── cdc_test.go             CDC reads: DPS, BCR
│   ├── control_test.go         Direct, SBO, SBOw interop
│   ├── sbo_state_test.go       SBO/SBOw state machine
│   ├── urcb_*_test.go          URCB integrity, trigger, reservation
│   ├── multi_client_test.go    Concurrent multi-client scenarios
│   └── testdata/               ICD fixture and initial values
│
├── scl/                        SCL parsing, validation, code generation
│   ├── model.go                SCL Go type tree (SCD/ICD/CID/IID)
│   ├── parse.go                XML parser (auto-detects schema edition)
│   ├── validate.go             Semantic validation rules
│   ├── flatten.go              Tabular export and CSV writer
│   ├── generate.go             XML serialisation (round-trip)
│   ├── lookup.go               FindIED, FindLDevice, etc.
│   ├── index/                  Fast cross-reference index
│   ├── validate/               Extended validation rules
│   ├── specs/                  Official XSD schema bundles (v1.7–2007C5)
│   ├── internal/
│   │   ├── genir/              XSD-to-Go code generator (used by sclgen)
│   │   └── raw/                Generated XSD bindings (v17, 2007B, …)
│   └── cmd/
│       ├── sclparse/           CLI: inspect, validate, summarize SCL files
│       └── sclgen/             CLI: regenerate Go types from XSD schemas
│
├── internal/
│   ├── mapping/                IEC 61850 ↔ MMS name mapping utilities
│   ├── sclindex/               Lightweight SCL cross-reference index
│   └── servermodel/            Server-side MMS registration and value store
│
├── INTEROP.md                  IEC 61850 interoperability compatibility matrix
├── API.md                      Complete public API reference
├── ERRORS.md                   Error taxonomy, sentinel values, and usage patterns
├── KNOWN_LIMITATIONS.md        Known constraints and unsupported features
├── OBSERVABILITY.md            Logging and structured-log fields
└── RELEASE.md                  Changelog

Interoperability

Client and server behaviour is tested bidirectionally against pinned libiec61850 and iec61850bean adapters through the independently versioned mms-interop infrastructure.

Tests live in interop/ behind -tags=interop and cover: basic operations, URCB/BRCB reporting, CDC reads (SPS, DPS, MV, BCR), quality and timestamp semantics, datasets, direct/SBO/SBOw controls, multi-client concurrency, and negative/error cases.

Scope of interoperability evidence: two independent software stacks have been tested. Interoperability with physical IEDs (protection relays, meters, bay controllers, RTUs) has not yet been formally established.

See INTEROP.md for the full compatibility matrix and make interop to run the suite locally.


Documentation

Document Description
scl/README.md scl package, sclparse, and sclgen reference
INTEROP.md Interoperability tests and compatibility matrix
API.md Complete public API reference (types, methods, errors)
ERRORS.md Error taxonomy, sentinel values, typed errors, usage patterns
KNOWN_LIMITATIONS.md Known limitations and constraints
OBSERVABILITY.md Logging and structured-log observability

License

This project is licensed under the MIT License. See LICENSE.

Documentation

Overview

Package iec61850 provides a pure-Go IEC 61850 MMS client library built on top of github.com/otfabric/go-mms.

This package exposes IEC 61850 concepts — logical devices, logical nodes, data objects, data attributes, functional constraints, object references, report control blocks, datasets, quality, timestamps — as first-class Go types. Users work with IEC 61850 semantics, not raw MMS domains, item IDs, or alternate access selectors.

Quick start

client, err := iec61850.Dial(ctx, "10.0.0.1:102", iec61850.DialOptions{})
if err != nil {
    log.Fatal(err)
}
defer client.Close(ctx)

// Browse the server model.
devices, _ := client.ListLogicalDevices(ctx)
for _, ld := range devices {
    nodes, _ := client.ListLogicalNodes(ctx, ld.Name)
    fmt.Println(ld.Name, nodes)
}

Layering

This package sits above the protocol stack:

  • go-tpkt / go-cotp: transport
  • go-mms: generic MMS protocol
  • go-iec61850 (this package): IEC 61850 semantics

IEC 61850 semantics (references, functional constraints, typed values, reports, datasets, SCL) live here. The MMS wire protocol lives in go-mms. This separation is intentional and must be maintained.

Object references

IEC 61850 object references follow the format:

LD/LN.DO.DA[FC]

Use ParseRef to parse references and Ref.String to format them. The Ref type provides helpers for parent/child navigation and MMS domain/item-ID translation.

Functional constraints

Functional constraints (FCs) classify data attributes by purpose: ST (status), MX (measured), SP (setpoint), CF (configuration), etc. Use FunctionalConstraint.IsValid or ParseFC to validate FC strings. Note that ParseRef accepts unknown FC values by default; use FunctionalConstraint.IsValid for semantic validation after parsing.

API groups

The package is organised into functional groups:

IEC references vs MMS names

This package uses IEC 61850 object references (LD/LN.DO.DA[FC]) throughout its public API. The underlying MMS names use a different convention:

  • MMS domain = logical device name
  • MMS item ID = LN$FC$DO$DA (components joined by $)
  • MMS dataset/NVL name = LLN0$dsName

Use Ref.ToMMS for conversion when needed.

Errors

The package defines sentinel errors (ErrInvalidReference, ErrNotFound, ErrInvalidArgument, ErrProtocol, etc.) for use with errors.Is, and typed error structs (ReferenceError, DecodeError, DataAccessError, etc.) for use with errors.As. Lower-level go-mms errors are wrapped with fmt.Errorf and %w to preserve the error chain.

Server (experimental)

The Server type provides an experimental server-side model built from SCL. It handles variable registration, datasets, report control block structures, runtime report delivery, control operations, setting groups, and journal services. Use Server.EnableReports to activate the runtime report engine, Server.EnableSettingGroups to activate setting group support, Server.EnableJournals to activate runtime journal generation, and Server.SetValue to inject process values that automatically trigger data-change reports and journal entries. MMS client writes to RCB and SGCB subfields are automatically dispatched to the corresponding runtime engines via a write interceptor.

ServerOptions provides first-class fields for common server configuration: ServerIdentity for MMS Identify, FileProvider for MMS file services, Authenticate for association security, and OnConnect/OnDisconnect for connection lifecycle hooks. The MMS Status service is always registered and returns operational status. Use Server.Capabilities to query which services are active at runtime. Call Server.Close for orderly shutdown of runtime engines.

Concurrency

All server runtime engines (reports, controls, setting groups, journals) are safe for concurrent use. Lock ordering follows engine-level lock → per-element lock. The control runtime uses per-registration mutexes for SBO state; the report engine uses engine-level RWMutex → per-RCB mutex. These have been validated with concurrent stress tests and Go's race detector.

Cross-LN dataset references are not supported. See Server and NewServerModelFromSCL for details and known limitations.

Logging

All logging uses log/slog. Inject a logger via DialOptions.Logger, ClientOptions.Logger, or ServerOptions.Logger. When nil, no logging is emitted. On Dial/NewServer, a nil nested MMS logger inherits the IEC logger; iso.WithLogger is independent. See OBSERVABILITY.md.

Index

Examples

Constants

View Source
const DefaultSelectTimeout = 30 * time.Second

DefaultSelectTimeout is the default SBO select timeout applied when no per-registration timeout is configured.

Uses wall-clock time via time.Since. On systems where the wall clock can jump (NTP corrections, suspend/resume), the effective timeout may differ from the intended duration. For safety-critical applications, consider shorter timeouts and monitoring clock skew.

Variables

View Source
var (
	// ErrInvalidReference indicates a syntactically invalid IEC 61850
	// object reference.
	ErrInvalidReference = errors.New("iec61850: invalid reference")

	// ErrInvalidFunctionalConstraint indicates an unrecognized
	// functional constraint value.
	ErrInvalidFunctionalConstraint = errors.New("iec61850: invalid functional constraint")

	// ErrNotFound indicates that the requested IEC 61850 object does
	// not exist on the server.
	ErrNotFound = errors.New("iec61850: not found")

	// ErrTypeMismatch indicates that a value's type does not match the
	// expected IEC 61850 type.
	ErrTypeMismatch = errors.New("iec61850: type mismatch")

	// ErrUnsupportedService indicates that the requested service is not
	// supported by the server or this library.
	ErrUnsupportedService = errors.New("iec61850: unsupported service")

	// ErrSubscriptionClosed indicates that a report subscription has
	// been closed.
	ErrSubscriptionClosed = errors.New("iec61850: subscription closed")

	// ErrSCLParse indicates a failure to parse an SCL file.
	ErrSCLParse = errors.New("iec61850: SCL parse error")

	// ErrModelMismatch indicates a mismatch between the expected and
	// actual data model.
	ErrModelMismatch = errors.New("iec61850: model mismatch")

	// ErrUnsupportedCDC indicates an unsupported Common Data Class.
	ErrUnsupportedCDC = errors.New("iec61850: unsupported CDC")

	// ErrReportDecode indicates a failure to decode a report payload.
	ErrReportDecode = errors.New("iec61850: report decode error")

	// ErrDatasetDecode indicates a failure to decode dataset contents.
	ErrDatasetDecode = errors.New("iec61850: dataset decode error")

	// ErrClosed indicates that the client connection has been closed.
	ErrClosed = errors.New("iec61850: connection closed")

	// ErrDataAccess indicates a per-variable data access failure
	// returned by the server for an individual read or write.
	ErrDataAccess = errors.New("iec61850: data access error")

	// ErrInvalidArgument indicates that a caller-supplied argument is
	// invalid (empty required field, nil value, etc.). Use [errors.Is]
	// to distinguish argument errors from server-side failures.
	ErrInvalidArgument = errors.New("iec61850: invalid argument")

	// ErrProtocol indicates a protocol-level mismatch between the
	// client and server, such as an unexpected response count or
	// missing mandatory fields in a response.
	ErrProtocol = errors.New("iec61850: protocol error")

	// ErrControlFailed indicates that a control operation (operate,
	// select, cancel) was rejected or failed.
	ErrControlFailed = errors.New("iec61850: control failed")

	// ErrSelectFailed indicates that a select or select-with-value
	// request was denied by the server.
	ErrSelectFailed = errors.New("iec61850: select failed")

	// ErrOperateFailed indicates that an operate request was denied
	// or could not be executed.
	ErrOperateFailed = errors.New("iec61850: operate failed")

	// ErrCancelFailed indicates that a cancel request was denied
	// or could not be executed.
	ErrCancelFailed = errors.New("iec61850: cancel failed")

	// ErrNotControllable indicates that the target data object's
	// ctlModel is status-only and does not support control.
	ErrNotControllable = errors.New("iec61850: not controllable")
)

Sentinel errors for major IEC 61850 failure categories.

Use errors.Is to test against these values.

Functions

func BoolCtlVal

func BoolCtlVal(v bool) *mms.Value

BoolCtlVal creates a boolean control value.

func BspCtlVal

func BspCtlVal(bits []byte, bitLen int) *mms.Value

BspCtlVal creates a bitstring control value for BSC (binary step controllable) CDCs.

func DpCtlVal

func DpCtlVal(on bool) *mms.Value

DpCtlVal creates a Dbpos (double-point) control value using a two-bit bitstring: 01=off, 10=on.

func EncodeQuality

func EncodeQuality(q Quality) *mms.Value

EncodeQuality encodes an IEC 61850 quality as an MMS bit string value.

func EncodeTimestamp

func EncodeTimestamp(ts Timestamp) *mms.Value

EncodeTimestamp encodes an IEC 61850 timestamp as an MMS UTCTime value, including the TimeQuality byte.

The quality byte encodes leap-second awareness, clock failure, clock synchronization, and sub-second accuracy bits.

func EnumCtlVal

func EnumCtlVal(v int32) *mms.Value

EnumCtlVal creates an enumerated control value.

func FloatCtlVal

func FloatCtlVal(v float32) *mms.Value

FloatCtlVal creates a floating-point control value (for APC controllable analogue CDCs).

func HasDuplicateRefs

func HasDuplicateRefs(refs []Ref) bool

HasDuplicateRefs reports whether the given ref slice contains duplicate entries (same LD/LN/Path/FC). Use this before Client.ReadMultiple or Client.WriteMultiple to detect accidental duplicates that the bulk APIs preserve by design.

func IntCtlVal

func IntCtlVal(v int32) *mms.Value

IntCtlVal creates an integer control value (for INC controllable integer CDCs).

func NewServerModelFromSCL

func NewServerModelFromSCL(s *scl.SCL, iedName, apName string) (*servermodel.Model, error)

NewServerModelFromSCL builds a server data model from an SCL configuration. The iedName selects the IED; apName selects the AccessPoint (empty uses the first AccessPoint with a Server).

This is a convenience wrapper around servermodel.FromSCL.

func StringCtlVal

func StringCtlVal(v string) *mms.Value

StringCtlVal creates a visible-string control value.

Types

type AddCause

type AddCause int

AddCause represents the AdditionalCause field in LastApplError, indicating why a control command was refused or failed.

const (
	AddCauseUnknown               AddCause = 0
	AddCauseNotSupported          AddCause = 1
	AddCauseBlocked               AddCause = 2
	AddCauseSelectFailed          AddCause = 3
	AddCauseInvalidPosition       AddCause = 4
	AddCausePositionReached       AddCause = 5
	AddCauseParameterChange       AddCause = 6
	AddCauseStepLimit             AddCause = 7
	AddCauseBlockedBySwitch       AddCause = 8
	AddCauseBlockedByInterlocking AddCause = 9
	AddCauseBlockedBySynchrocheck AddCause = 10
	AddCauseCommandAlreadyExec    AddCause = 11
	AddCauseBlockedByHealth       AddCause = 12
	AddCause1of1                  AddCause = 13
	AddCauseAbort                 AddCause = 14
	AddCauseTimeLimit             AddCause = 15
	AddCauseBlockedByMode         AddCause = 16
	AddCauseBlockedByProcess      AddCause = 17
)

func (AddCause) String

func (c AddCause) String() string

String returns the additional cause name.

type BrowseNode

type BrowseNode struct {
	// Name is the local component name (e.g., "stVal", "mag").
	Name string

	// Reference is the full IEC 61850 object reference.
	Reference Ref
}

BrowseNode represents a generic browse child returned by Client.ListChildren. Unlike DataObject, a BrowseNode does not imply that the node is a data object — it may be a sub-data object, data attribute, or any other child in the FC-merged browse view.

type CacheStrategy

type CacheStrategy int

CacheStrategy controls client-side caching of IEC 61850 model discovery results to reduce server load during repeated browse operations.

const (
	// CacheNone disables caching. Every browse/discovery call hits
	// the server. This is the default.
	CacheNone CacheStrategy = iota

	// CacheExplicit enables a cache that is only populated via
	// explicit calls to [Client.RefreshCache] or
	// [Client.RefreshLDCache]. Browse methods consult the cache
	// if populated, otherwise fetch from the server without
	// storing the result. Use [Client.InvalidateCache] to clear.
	CacheExplicit

	// CacheLazy transparently caches results on first access.
	// Subsequent accesses reuse cached data. Explicit invalidation
	// and refresh are still available via [Client.InvalidateCache]
	// and [Client.RefreshCache].
	CacheLazy
)

type CancelParams

type CancelParams struct {
	// CtlVal is the control value from the original Operate that
	// is being cancelled. Required.
	CtlVal *mms.Value

	// Origin identifies the command originator. When nil, a default
	// Origin with OrCatRemoteControl and empty OrIdent is used.
	Origin *Origin

	// CtlNum is the control sequence number that matches the
	// original Operate.
	CtlNum uint8

	// OperTm is the scheduled operation time from the original
	// Operate. A zero value means the original was immediate.
	OperTm time.Time
}

CancelParams contains parameters for an IEC 61850 Cancel command.

type CheckConditions

type CheckConditions uint8

CheckConditions represents the Check bitstring in a control command. Bit 0 = synchrocheck, Bit 1 = interlockCheck.

const (
	CheckSynchroCheck   CheckConditions = 1 << 0
	CheckInterlockCheck CheckConditions = 1 << 1
)

func (CheckConditions) Has

func (c CheckConditions) Has(flag CheckConditions) bool

Has reports whether the given check bit is set.

type Client

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

func Dial

func Dial(ctx context.Context, addr string, opts DialOptions) (*Client, error)

Dial establishes a new IEC 61850 MMS connection to the specified address (host:port).

The context controls the connection timeout. The caller must call Client.Close when done.

Example

ExampleDial demonstrates connecting to a remote IED and reading a value.

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)

client, err := Dial(ctx, "192.0.2.1:102", DialOptions{
	IEDName: "IED1",
})
if err != nil {
	cancel()
	log.Fatal(err)
}
defer cancel()
defer func() { _ = client.Close(ctx) }()

ref, err := ParseRef("LD1/GGIO1.Ind1.stVal[ST]")
if err != nil {
	log.Fatal(err)
}

val, err := client.Read(ctx, ref)
if err != nil {
	log.Fatal(err)
}

fmt.Println(val)

func NewClient

func NewClient(mmsClient *mms.Client, opts ClientOptions) (*Client, error)

NewClient creates an IEC 61850 client wrapping an already-created mms.Client. The caller retains ownership of the MMS client and is responsible for closing it separately.

Returns an error if mmsClient is nil.

Use this when you need custom MMS connection setup or want to share a single MMS client across layers.

func (*Client) Abort

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

Abort performs a hard, immediate abort of the connection without graceful shutdown. Use this for emergency teardown or protocol desync recovery.

If the client was created via NewClient, Abort only marks the IEC 61850 layer as closed without aborting the MMS client.

Abort is idempotent.

func (*Client) Cancel

func (c *Client) Cancel(ctx context.Context, ref Ref, params CancelParams) error

Cancel sends a cancel command for a previously selected control.

The CancelParams should match the CtlVal, Origin, and CtlNum of the original Operate or SelectWithValue.

func (*Client) Close

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

Close performs a graceful shutdown of the IEC 61850 client.

If the client was created via Dial, Close also closes the underlying MMS connection. If created via NewClient, the caller is responsible for closing the MMS client.

The client transitions through open → closing → closed. During the closing phase, subscription cleanup runs (disabling RCBs, releasing URCBs). Remote cleanup errors during this phase are logged at Debug level because the connection may already be half-closed.

Close is idempotent.

func (*Client) ConfirmEditSG

func (c *Client) ConfirmEditSG(ctx context.Context, ld string) error

ConfirmEditSG confirms the current edit session by writing CnfEdit=true to the SGCB. The server copies the edited SE values into the edit group's storage and clears the edit session.

This must be called after Client.SelectEditSG and any Client.SetEditSGValue calls to commit the changes.

func (*Client) CreateDataSet

func (c *Client) CreateDataSet(ctx context.Context, ld, dsName string, members []DataSetMember) error

CreateDataSet creates a dynamic (deletable) data set on the server.

The ld parameter is the logical device (MMS domain) that owns the data set, dsName is the data set name as an MMS item ID (e.g. "LLN0$dsNew"), and members lists the FCDAs.

Each member must have a valid Ref with LN and FC, or explicit DomainID/ItemID. Members may reference data in different logical devices (cross-LD members); when a member's Ref.LD is empty, the owning ld is used as the default domain. The data set itself is always created under the specified ld.

Member field precedence: if DomainID and ItemID are set explicitly, they are used as-is. Otherwise they are derived from the member's Ref via Ref.ToMMS, defaulting the domain to ld when Ref.LD is empty.

Dynamic data sets can be deleted with Client.DeleteDataSet.

func (*Client) DeleteDataSet

func (c *Client) DeleteDataSet(ctx context.Context, ld, dsName string) error

DeleteDataSet deletes a dynamic data set from the server.

Only dynamically created data sets (Deletable=true) can be deleted. Attempting to delete a static (SCL-configured) data set returns an error from the server.

func (*Client) DeleteFile

func (c *Client) DeleteFile(ctx context.Context, fileName string) error

DeleteFile deletes a file on the server.

func (*Client) DownloadFile

func (c *Client) DownloadFile(ctx context.Context, fileName string, w io.Writer) (*FileEntry, error)

DownloadFile streams a file from the server to the provided writer. This is the preferred method for large files as it does not buffer the entire file in memory.

The returned FileEntry contains the file metadata (size, timestamp). The actual number of bytes written may differ from FileEntry.Size if the server reports an approximate size.

func (*Client) FindPaths

func (c *Client) FindPaths(ctx context.Context, query FindQuery) ([]Ref, error)

FindPaths searches the server model for references matching the query. This performs model discovery and then filters the results.

The Pattern field in FindQuery supports glob matching via path.Match. Matching is applied to the full object reference string (e.g., "LD/LN.DO.DA"):

  • '*' matches any characters within a single path component (does not cross '/')
  • '?' matches a single character
  • '[' brackets match character classes

For patterns that need to cross component boundaries, consider using MatchRegex mode instead.

Pattern matching is performed against the object reference without the [FC] suffix. If the same object path exists under multiple FCs (e.g. ST and MX), it yields one result per FC because the full reference string (including FC) is used as the deduplication key. To get path-level deduplication, set FindQuery.FC to restrict results to a single functional constraint.

The FC field, when non-empty, filters to attributes with that FC. Results are deduplicated by full reference string (path + FC).

func (*Client) GetActiveSGValue

func (c *Client) GetActiveSGValue(ctx context.Context, ref Ref) (*Value, error)

GetActiveSGValue reads a data attribute value from the currently active setting group (FC=SG).

The ref must include LD, LN, and data path — the FC is forced to SG. This returns the active group's value regardless of any ongoing edit session.

func (*Client) GetDataSet

func (c *Client) GetDataSet(ctx context.Context, ld, dsName string) (*DataSet, error)

GetDataSet retrieves the definition (members) of a data set.

The ld parameter is the logical device (MMS domain) and dsName is the data set name as an MMS NVL item ID (e.g. "LLN0$dsName"). The returned DataSet.Reference uses IEC 61850 format (e.g. "LD/LLN0.dsName").

func (*Client) GetEditSGValue

func (c *Client) GetEditSGValue(ctx context.Context, ref Ref) (*Value, error)

GetEditSGValue reads a data attribute value from the current edit setting group (FC=SE). The ref must include LD, LN, and data path — the FC is forced to SE.

An edit session must be active (via Client.SelectEditSG) for the server to return edit-group values.

func (*Client) GetFileAttributes

func (c *Client) GetFileAttributes(ctx context.Context, fileName string) (*FileEntry, error)

GetFileAttributes retrieves the metadata (size, last modified) for a single file without reading its contents.

Implementation note: MMS does not define a dedicated metadata-only call. This method opens and immediately closes the file to obtain the metadata from the FileOpen response. If go-mms gains a pure metadata accessor (e.g., via FileDirectory with an exact path), this should switch to that to avoid the open/close overhead and potential server-side side effects.

func (*Client) GetReportControlBlock

func (c *Client) GetReportControlBlock(ctx context.Context, ld, rcbItemID string) (*ReportControlBlock, error)

GetReportControlBlock reads all attributes of a report control block from the server.

The ld parameter is the logical device (MMS domain) and rcbItemID is the RCB's MMS item ID (e.g. "LLN0$BR$brcb01" or "LLN0$RP$urcb01").

Example

ExampleClient_GetReportControlBlock demonstrates reading an RCB's current attributes without subscribing.

ctx := context.Background()

client, err := Dial(ctx, "192.0.2.1:102", DialOptions{})
if err != nil {
	log.Fatal(err)
}
defer func() { _ = client.Close(ctx) }()

rcb, err := client.GetReportControlBlock(ctx, "LD1", "LLN0$RP$urcb01")
if err != nil {
	log.Fatal(err)
}

fmt.Printf("RptID=%q DatSet=%q ConfRev=%d RptEna=%v\n",
	rcb.RptID, rcb.DatSet, rcb.ConfRev, rcb.RptEna)

func (*Client) GetSettingGroupInfo

func (c *Client) GetSettingGroupInfo(ctx context.Context, ld string) (*SettingGroupInfo, error)

GetSettingGroupInfo reads the Setting Group Control Block (SGCB) from the given logical device and returns the current state.

The SGCB is located at LLN0$SP$SGCB in every LD that supports setting groups. Returns an error if the SGCB cannot be read or decoded.

func (*Client) GetVariableType

func (c *Client) GetVariableType(ctx context.Context, ref Ref) (*mms.TypeSpec, error)

GetVariableType retrieves the MMS type specification for a variable. The ref must be an object reference (LD/LN with path) and must include a functional constraint.

func (*Client) InvalidateCache

func (c *Client) InvalidateCache()

InvalidateCache clears all cached model data without re-fetching. Subsequent browse calls will fetch fresh data from the server. This is a no-op when caching is disabled (CacheNone).

func (*Client) InvalidateLDCache

func (c *Client) InvalidateLDCache(ld string)

InvalidateLDCache clears cached variable data and dataset definitions for a single logical device. This is a no-op when caching is disabled (CacheNone).

func (*Client) ListChildren

func (c *Client) ListChildren(ctx context.Context, ref Ref) ([]BrowseNode, error)

ListChildren returns the direct browse children (sub-data objects and data attributes) under the specified reference.

The ref must include at least LD and LN. When ref has a path (e.g., LD/LN.DO), this returns the direct children of that path. When ref has only LD/LN, this is equivalent to Client.ListDataObjects but returns BrowseNode instead of DataObject.

Because MMS variable names are FC-qualified, the returned children are a merged view across all functional constraints. A child name like "stVal" may exist under both ST and MX; this method returns it once. Use Client.TreeWithOptions with IncludeFCs to discover which FCs apply, or specify an FC when reading/writing.

Results are sorted alphabetically by name.

func (*Client) ListDataObjects

func (c *Client) ListDataObjects(ctx context.Context, ld, ln string) ([]DataObject, error)

ListDataObjects returns the top-level data objects under the specified logical node.

The data objects are discovered by listing all named variables in the parent MMS domain, filtering for the specified LN, and extracting unique data object names (third $-delimited segment).

Results are sorted alphabetically by name.

func (*Client) ListDataSets

func (c *Client) ListDataSets(ctx context.Context, ld string) ([]string, error)

ListDataSets returns the names of all data sets (MMS Named Variable Lists) defined in the specified logical device (MMS domain).

The returned names are MMS item IDs (e.g., "LLN0$dsName").

Results are sorted alphabetically by name for deterministic output.

func (*Client) ListFiles

func (c *Client) ListFiles(ctx context.Context, pattern string) ([]FileEntry, error)

ListFiles returns the directory listing for the given file path pattern on the server. An empty pattern lists the root directory.

Pagination is handled internally; all matching entries are returned. Results are sorted by name for stable, deterministic output.

func (*Client) ListJournals

func (c *Client) ListJournals(ctx context.Context, ld string) ([]string, error)

ListJournals returns the names of all journals (logs) defined in the specified logical device (MMS domain).

func (*Client) ListLogicalDevices

func (c *Client) ListLogicalDevices(ctx context.Context) ([]LogicalDevice, error)

ListLogicalDevices returns the logical devices (MMS domains) available on the server.

Results are sorted alphabetically by name.

func (*Client) ListLogicalNodes

func (c *Client) ListLogicalNodes(ctx context.Context, ld string) ([]LogicalNode, error)

ListLogicalNodes returns the logical nodes within the specified logical device.

The logical nodes are discovered by listing all named variables in the MMS domain and extracting the unique first $-delimited segment (the LN name in IEC 61850 MMS mapping).

Results are sorted alphabetically by name.

func (*Client) ListReports

func (c *Client) ListReports(ctx context.Context, ld string) ([]string, error)

ListReports returns the names of all report control blocks in the specified logical device.

Discovery is by MMS item-name pattern: an item ID with exactly three '$'-separated segments where the second segment is "BR" or "RP" is treated as a RCB. This is a heuristic — it does not perform semantic verification (e.g., reading RCB attributes) to confirm the variable is actually a report control block.

When StrictnessOptions.VerifyReportCandidates is true, each candidate is read from the server and decoded; items that fail to decode as a valid RCB structure are excluded. This is equivalent to calling Client.ListReportsVerified.

The results include both buffered (BRCB, FC=BR) and unbuffered (URCB, FC=RP) report control blocks. Each returned name is an MMS item ID like "LLN0$BR$brcbName01" or "LLN0$RP$urcbName01".

Results are sorted alphabetically by name for deterministic output.

func (*Client) ListReportsVerified

func (c *Client) ListReportsVerified(ctx context.Context, ld string) ([]string, error)

ListReportsVerified returns verified report control block names by reading each heuristic candidate from the server and confirming it decodes as a valid RCB structure. This is slower than [ListReports] (one MMS read per candidate) but eliminates false positives from naming collisions.

Candidates that fail to read or decode are silently excluded from the result and logged at Debug level.

func (*Client) MMS

func (c *Client) MMS() *mms.Client

MMS returns the underlying mms.Client for advanced operations that are not exposed by the IEC 61850 API.

Warning — unsafe escape hatch

The returned pointer is shared with this Client. Operations performed on it bypass all IEC 61850 state management and can silently corrupt higher-level invariants including:

  • Model cache freshness (raw MMS writes can change server state without invalidating the cached browse results).
  • Report subscription state (disabling or re-enabling an RCB directly may desynchronize the subscription table).
  • Connection lifecycle (calling Close or Abort on the returned client while the IEC 61850 layer owns it leads to double-close or use-after-close).

Rules:

  • Do NOT call Close or Abort on the returned client when the Client was created via Dial (the IEC 61850 layer owns it).
  • After Client.Close or Client.Abort, the returned MMS client follows the underlying go-mms closed semantics (all calls return mms.ErrClosed).
  • Treat this as a read-only escape hatch (e.g. Identify, Status, GetNameList) unless you fully understand the interaction with the IEC 61850 layer's state.

Most users should not need this method.

func (*Client) ObtainFile

func (c *Client) ObtainFile(ctx context.Context, sourceFile, destinationFile string) error

ObtainFile instructs the server to copy a file from sourceFile to destinationFile. This is the standard MMS file transfer mechanism for "uploading" data — the server fetches the source file.

In IEC 61850 deployments, ObtainFile is typically used for configuration file transfer (e.g. SCL/CID files) where the server pulls a file from an engineering workstation or another IED.

Note: MMS does not define a direct client-to-server file write (push) operation. ObtainFile is the closest equivalent, but it requires the server to be able to reach the source file path.

func (*Client) Operate

func (c *Client) Operate(ctx context.Context, ref Ref, params OperateParams) error

Operate performs a direct-operate control command on the specified data object.

The ref identifies the controllable data object (e.g. "LD/LN.SPCSO1"). It must include LD and LN with a data-object path but must NOT include FC — the library writes to CO/Oper automatically.

For SBO control models, use Client.Select or Client.SelectWithValue before calling Operate.

If params.CtlNum is zero, an auto-incrementing sequence number is used. If params.Origin is nil, a default Origin with OrCatRemoteControl is used.

func (*Client) Read

func (c *Client) Read(ctx context.Context, ref Ref) (*Value, error)

Read reads a single IEC 61850 data attribute and returns it as an IEC 61850 Value.

The ref must include LD, LN, and FC.

LN-level reads are supported: when the ref has LD + LN + FC but no path, the server returns the full structured value for all data attributes under that LN and FC combination.

For raw MMS values without the IEC 61850 wrapper, use Client.ReadRaw.

func (*Client) ReadComponent

func (c *Client) ReadComponent(ctx context.Context, ref Ref, component string) (*Value, error)

ReadComponent reads a named component (sub-attribute) of a data object or data attribute.

This is a convenience API equivalent to reading with a ref that has the component appended to the path. For example, reading component "stVal" from ref "LD/LN.Mod[ST]" is equivalent to reading "LD/LN.Mod.stVal[ST]".

The ref must include LD, LN, FC, and at least one path component (the parent structure). The component name must be non-empty and must not contain separator characters.

func (*Client) ReadCtlModel

func (c *Client) ReadCtlModel(ctx context.Context, ref Ref) (CtlModel, error)

ReadCtlModel reads the ctlModel attribute of a controllable data object. This determines which control flow (direct, SBO, enhanced) should be used.

The ref identifies the data object (e.g. "LD/LN.SPCSO1") without FC — the library reads from CF/ctlModel automatically.

func (*Client) ReadDataSet

func (c *Client) ReadDataSet(ctx context.Context, ld, dsName string) ([]DataSetValue, error)

ReadDataSet reads all member values of a data set in a single MMS request.

The ld parameter is the logical device (MMS domain) and dsName is the data set name (MMS item ID, e.g. "LLN0$dsName").

To understand the structure of the returned values, first call Client.GetDataSet to obtain the member definitions.

func (*Client) ReadFile

func (c *Client) ReadFile(ctx context.Context, fileName string) ([]byte, *FileEntry, error)

ReadFile reads an entire file from the server and returns its contents.

For large files, prefer Client.DownloadFile which streams to an io.Writer without buffering the entire file in memory.

func (*Client) ReadJournal

func (c *Client) ReadJournal(ctx context.Context, ld, journal string, start, stop time.Time) (*JournalReadResult, error)

ReadJournal reads journal entries within the given time range [start, stop] from the specified journal in the logical device.

The returned entries are in chronological order. When JournalReadResult.MoreFollows is true, use Client.ReadJournalAfter with the last entry's OccurrenceTime and EntryID to page through remaining entries.

func (*Client) ReadJournalAfter

func (c *Client) ReadJournalAfter(ctx context.Context, ld, journal string, afterTime time.Time, afterID []byte) (*JournalReadResult, error)

ReadJournalAfter reads journal entries starting after the given cursor position. Use the last entry's OccurrenceTime and EntryID from a previous [ReadJournal] or [ReadJournalAfter] call to page through journal data.

func (*Client) ReadJournalAfterAll

func (c *Client) ReadJournalAfterAll(ctx context.Context, ld, journal string, afterTime time.Time, afterID []byte) ([]JournalEntry, error)

ReadJournalAfterAll reads all journal entries starting after the given cursor, automatically following pagination until all entries are retrieved.

This is the paginating equivalent of Client.ReadJournalAfter.

func (*Client) ReadJournalAll

func (c *Client) ReadJournalAll(ctx context.Context, ld, journal string, start, stop time.Time) ([]JournalEntry, error)

ReadJournalAll reads all journal entries within the given time range, automatically following pagination (MoreFollows) until all entries are retrieved.

Entries are returned in chronological order. The stop condition is MoreFollows=false from the server. Same-timestamp cursor semantics are handled correctly via EntryID-based continuation.

For very large journals, consider using the paginated Client.ReadJournal / Client.ReadJournalAfter pair to control memory usage.

func (*Client) ReadLastApplError

func (c *Client) ReadLastApplError(ctx context.Context, ref Ref) (*LastApplError, error)

ReadLastApplError reads and decodes the LastApplError from the logical node containing the given control object.

LastApplError is a structured attribute under the LN at FC=CO that provides the reason for the most recent control failure. Returns nil (no error value) if the attribute is not present or cannot be decoded.

func (*Client) ReadMultiple

func (c *Client) ReadMultiple(ctx context.Context, refs []Ref) ([]ReadResult, error)

ReadMultiple reads multiple IEC 61850 data objects or data attributes in a single MMS request.

Each ref must be an object reference (LD, LN, FC, and at least one path component). LN-level bulk reads are not supported; use Client.Read for those. Results are returned in the same order as the input refs.

Duplicate refs are preserved: if the same ref appears multiple times, each occurrence produces a separate result at the corresponding index. The server may return identical or different values depending on timing.

Per-item errors (e.g., object not found) are reported in ReadResult.Err as a *DataAccessError rather than failing the entire operation.

Mixed-domain and mixed-FC reads are supported: refs may span different logical devices and functional constraints within a single call.

If the MMS request itself fails (e.g., connection error), a non-nil error is returned and the result slice is nil.

func (*Client) ReadRaw

func (c *Client) ReadRaw(ctx context.Context, ref Ref) (*mms.Value, error)

ReadRaw reads a single IEC 61850 data attribute and returns the underlying mms.Value directly, without IEC 61850 wrapping.

This is useful when callers need full control over MMS value interpretation or want to avoid the Value abstraction overhead.

Both object-level (LD/LN.DO.DA[FC]) and LN-level (LD/LN[FC]) reads are supported. LN-level reads return the full structured value for the LN + FC combination as a single MMS structure.

func (*Client) RefreshCache

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

RefreshCache re-fetches all cached model data from the server. This is a no-op when caching is disabled (CacheNone).

Use this after server model changes to ensure the client sees the latest structure. The cache is rebuilt atomically: on failure, the previous cache state is preserved.

func (*Client) RefreshLDCache

func (c *Client) RefreshLDCache(ctx context.Context, ld string) error

RefreshLDCache re-fetches cached variable data for a single logical device. This is a no-op when caching is disabled (CacheNone).

Only the per-LD variable list is refreshed; the global logical device list is not modified. If the LD was added or removed on the server, call Client.RefreshCache instead to refresh both.

Both the raw item list and any derived parsed-ref cache for the LD are replaced atomically. Dataset definitions are preserved — call Client.InvalidateLDCache to clear those as well.

func (*Client) ReleaseURCB

func (c *Client) ReleaseURCB(ctx context.Context, ld, rcbItemID string) error

ReleaseURCB releases a previously reserved unbuffered report control block.

The caller should disable the report (RptEna=false) before releasing to avoid undefined behavior.

func (*Client) RenameFile

func (c *Client) RenameFile(ctx context.Context, currentName, newName string) error

RenameFile renames a file on the server.

func (*Client) ReserveURCB

func (c *Client) ReserveURCB(ctx context.Context, ld, rcbItemID string) error

ReserveURCB reserves an unbuffered report control block for exclusive use by this client.

Reservation is required before configuring or enabling a URCB. The reservation remains until explicitly released via Client.ReleaseURCB or the connection is closed.

func (*Client) Select

func (c *Client) Select(ctx context.Context, ref Ref) (string, error)

Select performs a select-before-operate (SBO) select command.

This is used with CtlModelSBONormal. The server returns the selected object reference on success. The client must then call Client.Operate within the server's select timeout.

For enhanced security SBO (CtlModelSBOEnhanced), use Client.SelectWithValue instead.

Interoperability note

The SBO decode path assumes the server returns a VisibleString from a normal MMS read on the SBO subattribute. An empty string is interpreted as "select denied". This matches IEC 61850-8-1 § 22.2 for normal-security SBO but behaviour may vary across devices. Validate against your target devices before relying on this in production.

func (*Client) SelectActiveSG

func (c *Client) SelectActiveSG(ctx context.Context, ld string, sg uint8) error

SelectActiveSG writes a new active setting group number to the SGCB. The server activates the specified group, making its SE values available via FC=SG reads.

The sg parameter must be in [1, NumOfSGs]. Use Client.GetSettingGroupInfo to discover the valid range.

func (*Client) SelectEditSG

func (c *Client) SelectEditSG(ctx context.Context, ld string, sg uint8) error

SelectEditSG selects a setting group for editing. This reserves the edit session; the server sets EditSG in the SGCB to the requested group number. Only one client may hold an edit session at a time.

After selecting, use Client.GetEditSGValue and Client.SetEditSGValue to read/write SE-constrained values for the edit group. Call Client.ConfirmEditSG to commit changes.

The sg parameter must be in [1, NumOfSGs].

func (*Client) SelectWithValue

func (c *Client) SelectWithValue(ctx context.Context, ref Ref, params OperateParams) error

SelectWithValue performs a select-before-operate with enhanced security (SBOw) by writing the full Oper structure to the SBOw subattribute.

This is used with CtlModelSBOEnhanced. On success the select is held by the server; the client must then call Client.Operate with the same parameters within the server's select timeout.

func (*Client) SetEditSGValue

func (c *Client) SetEditSGValue(ctx context.Context, ref Ref, value *mms.Value) error

SetEditSGValue writes a data attribute value into the current edit setting group (FC=SE). The ref must include LD, LN, and data path — the FC is forced to SE.

An edit session must be active (via Client.SelectEditSG). The change is not committed until Client.ConfirmEditSG is called.

func (*Client) SetReportControlBlock

func (c *Client) SetReportControlBlock(ctx context.Context, ld, rcbItemID string, update RCBUpdate) error

SetReportControlBlock writes selected attributes of a report control block. Only fields specified by RCBUpdate.Fields are sent to the server.

This mask-based approach prevents accidental partial writes that could leave the RCB in an inconsistent state.

func (*Client) SubscribeReport

func (c *Client) SubscribeReport(ctx context.Context, rptID string, opts SubscribeReportOptions) (*ReportSubscription, error)

SubscribeReport creates a subscription that delivers decoded IEC 61850 reports matching the specified RptID pattern.

The caller must read from the ReportSubscription.Reports channel to avoid backpressure. Overflow behavior is controlled by SubscribeReportOptions.OverflowPolicy.

Lifecycle options (AutoEnable, GIOnSubscribe, ReserveURCB) allow the subscription to configure and enable the RCB automatically. These require LD and RCBItemID to be set in options. The caller can still configure RCBs manually via Client.SetReportControlBlock and subscribe passively by not setting any lifecycle options.

Call ReportSubscription.Close when done. The subscription is also closed when the client is closed.

Lifecycle operations are not atomic. If subscription setup fails partway through, some RCB state (e.g., Resv, DatSet) may already have been changed on the server. Rollback is best-effort: the library attempts to undo prior writes, but network or server errors during cleanup are logged and otherwise ignored.

SetReportControlBlock write ordering: configuration fields are written first, RptEna is always written last. This is an IEC 61850 invariant — the library does not promise atomic RCB updates. See Client.SetReportControlBlock for details.

Example

ExampleClient_SubscribeReport demonstrates subscribing to a URCB and receiving data-change reports.

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)

client, err := Dial(ctx, "192.0.2.1:102", DialOptions{})
if err != nil {
	cancel()
	log.Fatal(err)
}
defer cancel()
defer func() { _ = client.Close(ctx) }()

sub, err := client.SubscribeReport(ctx, "urcb01", SubscribeReportOptions{
	LD:             "LD1",
	RCBItemID:      "LLN0$RP$urcb01",
	AutoEnable:     true,
	GIOnSubscribe:  true,
	QueueSize:      64,
	OverflowPolicy: OverflowDropNewest,
})
if err != nil {
	log.Fatal(err)
}
defer func() { _ = sub.Close() }()

for rpt := range sub.Reports() {
	for i, v := range rpt.Values {
		if i < len(rpt.ReasonCodes) {
			fmt.Printf("member[%d]: reason=%v value=%v\n", i, rpt.ReasonCodes[i], v)
		} else {
			fmt.Printf("member[%d]: value=%v\n", i, v)
		}
	}
}

func (*Client) Tree

func (c *Client) Tree(ctx context.Context) (*ModelNode, error)

Tree builds the full IEC 61850 model tree from the server. This performs multiple MMS GetNameList calls to discover the complete hierarchy: logical devices → logical nodes → data objects/attributes.

The returned root ModelNode is a synthetic container (Name="root", empty Reference) whose Children are the logical device nodes. It does not represent a real IEC 61850 object.

The tree merges structure across functional constraints: the same data object path may appear under multiple FCs (e.g., ST and MX), and the tree returns it as a single node. Enable TreeOptions.IncludeFCs to annotate each node with its observed FCs. Without FC annotation, a returned node is a browse view, not a directly readable reference — callers must choose an FC before reading or writing.

The tree includes all data objects and attributes discovered from the MMS variable names. For type information, use Client.GetVariableType on individual nodes.

This operation may be slow on servers with large models.

func (*Client) TreeWithOptions

func (c *Client) TreeWithOptions(ctx context.Context, opts TreeOptions) (*ModelNode, error)

TreeWithOptions builds the IEC 61850 model tree with configurable filtering and annotation.

Like Client.Tree, the returned tree merges structure across functional constraints. Use TreeOptions.IncludeFCs to annotate nodes with their observed FCs so that callers can determine which FCs are valid for each node before performing read/write operations.

See Client.Tree for the simpler zero-options variant.

func (*Client) TriggerGI

func (c *Client) TriggerGI(ctx context.Context, ld, rcbItemID string) error

TriggerGI triggers a General Interrogation on a report control block.

For BRCBs, this writes GI=true to the RCB. The server responds by sending a report containing all data set members with reason=GI.

For URCBs, the same mechanism applies but the RCB must be enabled and reserved (if applicable) first.

func (*Client) Write

func (c *Client) Write(ctx context.Context, ref Ref, value *mms.Value) error

Write writes a single IEC 61850 data attribute.

The ref must include LD, LN, FC, and a path to the target data attribute. The value is written as-is to the MMS layer.

Returns an error if the write is rejected by the server.

Example

ExampleClient_Write demonstrates writing a value to an attribute.

ctx := context.Background()

client, err := Dial(ctx, "192.0.2.1:102", DialOptions{})
if err != nil {
	log.Fatal(err)
}
defer func() { _ = client.Close(ctx) }()

ref, err := ParseRef("LD1/LLN0.Mod.stVal[ST]")
if err != nil {
	log.Fatal(err)
}

if err := client.Write(ctx, ref, mms.NewInteger(1)); err != nil {
	log.Fatal(err)
}

func (*Client) WriteMultiple

func (c *Client) WriteMultiple(ctx context.Context, requests []WriteRequest) ([]WriteResult, error)

WriteMultiple writes multiple IEC 61850 data attributes in a single MMS request.

Each request must include a valid ref (LD, LN, FC, path) and a non-nil value. Results are returned in the same order as the input requests. Per-item errors are reported in WriteResult.Err as a *DataAccessError.

Duplicate refs are preserved: if the same ref appears multiple times, each write is sent in order. The final server-side value is the last successful write.

Mixed-domain and mixed-FC writes are supported: requests may span different logical devices and functional constraints within a single call. Write order is preserved.

If the MMS request itself fails, a non-nil error is returned and the result slice is nil.

type ClientOptions

type ClientOptions struct {
	// Logger, when non-nil, enables structured logging for IEC 61850
	// operations. When nil (the default), no logging is emitted.
	Logger *slog.Logger

	// Strictness controls validation behavior.
	Strictness StrictnessOptions

	// Cache controls the client-side caching strategy for model
	// discovery results (logical devices, logical nodes, data
	// objects, tree). The default ([CacheNone]) disables caching.
	Cache CacheStrategy

	// IEDName, when non-empty, is the IED identifier prefix used by
	// the target server to form MMS domain names. See [DialOptions.IEDName].
	IEDName string
}

ClientOptions configures an IEC 61850 client created via NewClient from an existing mms.Client.

type ConnectionEvent

type ConnectionEvent struct{}

ConnectionEvent is passed to ServerOptions.OnConnect and ServerOptions.OnDisconnect callbacks.

The event currently provides no connection-specific context because the underlying MMS layer does not expose the mms.ServerConn at the transport-accept boundary. Future versions may add a connection identifier or authentication token when the MMS API supports it.

type ControlError

type ControlError struct {
	// Ref is the IEC 61850 object reference of the controlled object.
	Ref string

	// Operation is the control operation that failed (e.g. "operate",
	// "select", "cancel").
	Operation string

	// AddCause is the additional cause reported by the server via
	// LastApplError, if available. Zero means unknown or not read.
	AddCause AddCause

	// Wrapped is the underlying error.
	Wrapped error
}

ControlError is a typed error for control operation failures. It captures the object reference, the operation attempted, and the server-reported additional cause when available.

func (*ControlError) Error

func (e *ControlError) Error() string

func (*ControlError) Unwrap

func (e *ControlError) Unwrap() []error

Unwrap returns a slice of errors so that errors.Is matches both the operation-specific sentinel (e.g. ErrOperateFailed) and the wrapped cause, if any.

type ControlHandler

type ControlHandler struct {
	// SelectTimeout overrides [DefaultSelectTimeout] for this control
	// object. The select reservation expires this long after a
	// successful Select or SelectWithValue. A zero value means use
	// [DefaultSelectTimeout].
	SelectTimeout time.Duration

	// OnSelect is called when a client issues a Select (SBO) or
	// SelectWithValue (SBOw) request. Return nil to accept the
	// select, or an error (preferably wrapping [ErrSelectFailed]
	// with an [AddCause]) to deny it.
	//
	// If nil, selects are accepted unconditionally.
	OnSelect func(ctx context.Context, req ControlRequest) error

	// OnOperate is called when a client issues an Operate request.
	// Return nil to accept the operate, or an error (preferably
	// wrapping [ErrOperateFailed] with an [AddCause]) to deny it.
	//
	// If nil, operates are accepted unconditionally and the value
	// is written to the ValueStore.
	OnOperate func(ctx context.Context, req ControlRequest) error

	// OnCancel is called when a client issues a Cancel request.
	// Return nil to accept the cancellation, or an error to deny.
	//
	// If nil, cancels are accepted unconditionally.
	OnCancel func(ctx context.Context, req ControlRequest) error
}

ControlHandler defines the server-side callbacks for a controllable data object. Implement the methods relevant to the control model; unset (nil) handlers use default accept/reject behavior.

All handler methods receive a context from the MMS layer and a ControlRequest describing the command.

type ControlRequest

type ControlRequest struct {
	// Ref is the IEC 61850 object reference of the controlled object.
	Ref string

	// Operation is "operate", "select", or "cancel".
	Operation string

	// CtlVal is the control value.
	CtlVal *mms.Value

	// Origin is the command originator.
	Origin Origin

	// CtlNum is the control sequence number.
	CtlNum uint8

	// OperTm is the scheduled operation time (zero for immediate).
	OperTm time.Time

	// Test indicates whether this is a test command.
	Test bool

	// Check contains synchrocheck/interlockCheck bits.
	Check CheckConditions
}

ControlRequest contains the decoded parameters from a client control command (Operate, Select, or Cancel).

type CtlModel

type CtlModel int

CtlModel represents the IEC 61850 control model (ctlModel attribute). It determines whether the controllable data object uses direct operation, select-before-operate, or enhanced security variants.

const (
	// CtlModelStatusOnly means the data object is not controllable.
	CtlModelStatusOnly CtlModel = 0

	// CtlModelDirectNormal is direct-operate with normal security.
	// The client writes to Oper without a prior Select.
	CtlModelDirectNormal CtlModel = 1

	// CtlModelSBONormal is select-before-operate with normal security.
	// The client reads SBO (select), then writes to Oper.
	CtlModelSBONormal CtlModel = 2

	// CtlModelDirectEnhanced is direct-operate with enhanced security.
	// Like CtlModelDirectNormal, but the server validates origin,
	// ctlNum, and timestamps for command verification.
	CtlModelDirectEnhanced CtlModel = 3

	// CtlModelSBOEnhanced is select-before-operate with enhanced
	// security. The client writes to SBOw (select-with-value), then
	// writes to Oper, with full origin/ctlNum/timestamp verification.
	CtlModelSBOEnhanced CtlModel = 4
)

func (CtlModel) IsControllable

func (m CtlModel) IsControllable() bool

IsControllable reports whether this control model supports any control operation (i.e., is not status-only).

func (CtlModel) IsEnhanced

func (m CtlModel) IsEnhanced() bool

IsEnhanced reports whether this control model uses enhanced security (origin/ctlNum/timestamp verification).

func (CtlModel) IsSBO

func (m CtlModel) IsSBO() bool

IsSBO reports whether this control model uses select-before-operate.

func (CtlModel) String

func (m CtlModel) String() string

String returns a human-readable control model name.

type DataAccessError

type DataAccessError struct {
	Ref       string
	ErrorCode int
	Operation string
}

DataAccessError is a typed per-item error for bulk read/write operations. It wraps the MMS-level error code into an IEC 61850 error that supports errors.Is with ErrDataAccess.

func (*DataAccessError) Error

func (e *DataAccessError) Error() string

func (*DataAccessError) Unwrap

func (e *DataAccessError) Unwrap() error

type DataObject

type DataObject struct {
	// Name is the component name (e.g., "Mod", "stVal", "mag").
	Name string

	// Reference is the full IEC 61850 object reference.
	Reference Ref

	// FC is the functional constraint, when unambiguous. Empty during
	// browse/tree discovery where the same object may appear under
	// multiple FCs. Populated only when a single FC applies or when
	// explicitly set by the caller.
	FC FunctionalConstraint

	// Children contains sub-objects (nested DOs or DAs).
	// Populated only when the tree is built via [Client.Tree] or
	// explicit recursive browsing.
	Children []DataObject
}

DataObject represents a browsed model component, which may be a data object, sub-data object, or data attribute. It captures name, reference, and optional MMS type information.

type DataSet

type DataSet struct {
	// Reference is a display-friendly data set identifier in
	// IEC 61850 format (e.g., "LD/LLN0.dsName"). This is a
	// convenience string, not a [Ref] and not suitable for
	// programmatic use with [Client.ReadDataSet] or
	// [Client.DeleteDataSet] — those require the raw (ld, dsName)
	// MMS identifiers used when the DataSet was obtained.
	Reference string

	// Deletable indicates whether the data set can be deleted by the
	// client. Static (SCL-configured) data sets are not deletable;
	// dynamically created data sets are.
	Deletable bool

	// Members lists the data set members in definition order.
	Members []DataSetMember
}

DataSet represents an IEC 61850 data set (MMS Named Variable List).

A data set groups related data attributes for efficient bulk reading and for use as the trigger source of report control blocks.

type DataSetMember

type DataSetMember struct {
	// Ref is the IEC 61850 object reference for this member.
	// Includes LD, LN, path, and FC when available.
	Ref Ref

	// DomainID is the MMS domain name.
	DomainID string

	// ItemID is the MMS item ID (LN$FC$DO$DA path).
	ItemID string
}

DataSetMember represents a single member (FCDA) of a data set.

type DataSetValue

type DataSetValue struct {
	// Member is the data set member definition.
	Member DataSetMember

	// Value is the decoded value. Nil when Err is non-nil.
	Value *Value

	// Err is the per-member error, if any.
	Err error
}

DataSetValue holds the result of reading a single data set member.

type DecodeError

type DecodeError struct {
	Ref     string
	Type    string
	Message string
	Wrapped error
}

DecodeError indicates a failure during semantic decoding of an MMS value into an IEC 61850 type.

func (*DecodeError) Error

func (e *DecodeError) Error() string

func (*DecodeError) Unwrap

func (e *DecodeError) Unwrap() error

type DialOptions

type DialOptions struct {
	// MMS holds the underlying MMS dial options. These are passed
	// through to [iso.Dial] via [iso.WithClientDialOptions].
	MMS mms.DialOptions

	// Logger, when non-nil, enables structured logging for IEC 61850
	// operations. When nil (the default), no logging is emitted.
	//
	// When [DialOptions.MMS].Logger is also nil, this logger is passed
	// through to the underlying [mms.Client]. ISO transport logging
	// ([iso.WithLogger]) is independent and is not set from here.
	Logger *slog.Logger

	// Strictness controls validation behavior.
	Strictness StrictnessOptions

	// Cache controls the client-side caching strategy for model
	// discovery results. The default ([CacheNone]) disables caching.
	Cache CacheStrategy

	// IEDName, when non-empty, is the IED identifier prefix used by
	// the target server to form MMS domain names.
	//
	// Compliant IEC 61850-8-1 servers form MMS domain names by
	// concatenating the IED name and the LD instance name (e.g.
	// IEDName="InteropIED" + LDInst="InteropLD" →
	// domain="InteropIEDInteropLD"). When IEDName is set, the
	// client automatically strips the prefix when reporting logical
	// device names and prepends it when making MMS requests, so
	// callers can always use the bare LD instance name.
	IEDName string
}

DialOptions configures an IEC 61850 client connection established via Dial.

type FileEntry

type FileEntry struct {
	// Name is the file path as returned by the server.
	Name string

	// Size is the file size in bytes.
	Size int64

	// LastModified is the file's last modification timestamp.
	LastModified time.Time
}

FileEntry describes a single file on an IEC 61850 / MMS server.

type FindQuery

type FindQuery struct {
	// Pattern is matched against the object reference (without FC
	// suffix). The matching algorithm is determined by [MatchMode].
	//
	// Glob examples (default):
	//   "*/LLN0*"           — all LLN0 nodes across all LDs
	//   "LD1/GGIO1.Ind*"    — all Ind objects under GGIO1
	//
	// Regex examples:
	//   ".*GGIO1\\.Ind[12]" — Ind1 and Ind2 under any GGIO1
	Pattern string

	// MatchMode selects the pattern matching algorithm. The default
	// ([MatchGlob]) preserves backward compatibility.
	MatchMode MatchMode

	// FC optionally filters results to a specific functional
	// constraint. When empty, all FCs are included.
	FC FunctionalConstraint

	// LDFilter, when non-empty, restricts the search to a single
	// logical device. This avoids fetching variable lists from
	// every LD, which can be expensive on servers with many domains.
	LDFilter string

	// MaxDepth limits traversal depth based on [Ref.Depth]. Zero means
	// unlimited. Depth values correspond to:
	//   1 = LD only
	//   2 = LN
	//   3 = first data object level (LD/LN.DO)
	//   4+ = deeper data attributes
	MaxDepth int
}

FindQuery specifies search criteria for Client.FindPaths.

type FunctionalConstraint

type FunctionalConstraint string

FunctionalConstraint identifies the purpose of a data attribute within the IEC 61850 data model. Each FC classifies what kind of information the attribute carries (status, measured value, setpoint, configuration, etc.).

const (
	// FCST is Status information.
	FCST FunctionalConstraint = "ST"
	// FCMX is Measurands (analog values).
	FCMX FunctionalConstraint = "MX"
	// FCSP is Setpoint.
	FCSP FunctionalConstraint = "SP"
	// FCSV is Substitution.
	FCSV FunctionalConstraint = "SV"
	// FCCF is Configuration.
	FCCF FunctionalConstraint = "CF"
	// FCDC is Description.
	FCDC FunctionalConstraint = "DC"
	// FCSG is Setting group.
	FCSG FunctionalConstraint = "SG"
	// FCSE is Setting group editable.
	FCSE FunctionalConstraint = "SE"
	// FCSR is Service response / service tracking.
	FCSR FunctionalConstraint = "SR"
	// FCOR is Operate received.
	FCOR FunctionalConstraint = "OR"
	// FCBL is Blocking.
	FCBL FunctionalConstraint = "BL"
	// FCEX is Extended definition.
	FCEX FunctionalConstraint = "EX"
	// FCCO is Control.
	FCCO FunctionalConstraint = "CO"
	// FCUS is Unicast SV.
	FCUS FunctionalConstraint = "US"
	// FCMS is Multicast SV.
	FCMS FunctionalConstraint = "MS"
	// FCRP is Unbuffered report.
	FCRP FunctionalConstraint = "RP"
	// FCBR is Buffered report.
	FCBR FunctionalConstraint = "BR"
	// FCLG is Log control blocks.
	FCLG FunctionalConstraint = "LG"
	// FCGO is GOOSE control blocks.
	FCGO FunctionalConstraint = "GO"
)

func AllFunctionalConstraints

func AllFunctionalConstraints() []FunctionalConstraint

AllFunctionalConstraints returns all valid functional constraint values in a stable, specification-defined order. The returned slice is a copy — callers may modify it freely.

func ParseFC

func ParseFC(s string) (FunctionalConstraint, error)

ParseFC parses a string as a functional constraint. Returns ErrInvalidFunctionalConstraint if the string is not a recognized FC value.

func (FunctionalConstraint) Description

func (fc FunctionalConstraint) Description() string

Description returns a human-readable description of the functional constraint (e.g., "Status" for ST). Returns "Unknown" for unrecognized values.

func (FunctionalConstraint) IsValid

func (fc FunctionalConstraint) IsValid() bool

IsValid reports whether fc is a recognized functional constraint.

func (FunctionalConstraint) String

func (fc FunctionalConstraint) String() string

String returns the two-letter FC code.

type JournalEngine

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

JournalEngine is the server-side runtime journal engine. It generates journal (log) entries in response to value changes and application events, storing them in a MemoryJournalProvider that backs the MMS journal services.

The engine is created by Server.EnableJournals and attached to the server's MMS layer as the mms.JournalProvider.

func (*JournalEngine) LogEvent

func (e *JournalEngine) LogEvent(domain, journal string, occTime time.Time, vars []mms.JournalVariable) []byte

LogEvent records a custom application event in the specified journal. The domain is the logical device name and journal is the MMS journal name (typically "LLN0$logName"). Variables contain the data to record.

func (*JournalEngine) LogValueWrite

func (e *JournalEngine) LogValueWrite(ctx context.Context, storeKey string, occTime time.Time)

LogValueWrite records a value-write entry in all journals defined for the logical device that contains the given store key. Every write is logged regardless of whether the value actually changed; this provides an audit trail rather than semantic change detection. The store key format is "ldName/itemID".

func (*JournalEngine) Provider

func (e *JournalEngine) Provider() *MemoryJournalProvider

Provider returns the underlying MemoryJournalProvider used by this engine, allowing direct inspection of stored entries.

type JournalEngineOption

type JournalEngineOption func(*JournalEngine)

JournalEngineOption configures the JournalEngine.

func WithJournalMaxEntries

func WithJournalMaxEntries(n int) JournalEngineOption

WithJournalMaxEntries sets the maximum entries per journal in the underlying MemoryJournalProvider. Default is 10000.

func WithJournalProvider

func WithJournalProvider(p *MemoryJournalProvider) JournalEngineOption

WithJournalProvider replaces the default MemoryJournalProvider with a pre-configured one. This is useful when the caller needs direct access to the provider for inspection or pre-population.

type JournalEntry

type JournalEntry struct {
	// EntryID is the opaque entry identifier assigned by the server.
	// It is used as a cursor for pagination via [Client.ReadJournalAfter].
	EntryID []byte

	// OccurrenceTime is the timestamp when the event occurred.
	OccurrenceTime time.Time

	// Variables contains the data values recorded in this entry.
	Variables []JournalVariable
}

JournalEntry represents a single entry in an IEC 61850 journal (log).

type JournalReadResult

type JournalReadResult struct {
	// Entries contains the journal entries in chronological order.
	Entries []JournalEntry

	// MoreFollows indicates that additional entries are available
	// beyond those returned. Use [Client.ReadJournalAfter] with the
	// last entry's OccurrenceTime and EntryID to retrieve the next page.
	MoreFollows bool
}

JournalReadResult holds the result of a journal read operation, including pagination state.

type JournalVariable

type JournalVariable struct {
	// Tag identifies the variable (typically an MMS variable name).
	Tag string

	// Value is the recorded value. Wraps the underlying [mms.Value].
	Value *Value
}

JournalVariable represents a single variable recorded in a journal entry.

type LastApplError

type LastApplError struct {
	// CntrlObj is the object reference of the control that failed.
	CntrlObj string

	// Error is the IEC 61850 service error class.
	Error int

	// Origin is the originator that issued the failed command.
	Origin Origin

	// AddCause provides the specific additional cause.
	AddCause AddCause
}

LastApplError contains the decoded result of a LastApplError read, providing server-side failure reason for a control command.

type LogicalDevice

type LogicalDevice struct {
	// Name is the logical device name (MMS domain ID).
	Name string
}

LogicalDevice represents a logical device discovered on the server. A logical device maps to an MMS domain.

type LogicalNode

type LogicalNode struct {
	// Name is the logical node name (e.g., "LLN0", "GGIO1").
	Name string

	// LD is the parent logical device name.
	LD string
}

LogicalNode represents a logical node within a logical device. In the MMS mapping, logical nodes appear as the first $-delimited segment of named variables within a domain.

func (LogicalNode) Ref

func (ln LogicalNode) Ref() Ref

Ref returns the IEC 61850 object reference for this logical node.

type MatchMode

type MatchMode int

MatchMode selects the pattern matching algorithm for FindQuery.

const (
	// MatchGlob uses [path.Match] glob semantics (default). '*'
	// matches any characters within a single component, '?' matches
	// a single character.
	MatchGlob MatchMode = iota

	// MatchRegex uses Go [regexp] semantics. The pattern is compiled
	// with [regexp.Compile] and matched against the full object
	// reference string.
	MatchRegex
)

type MemoryJournalOption

type MemoryJournalOption func(*MemoryJournalProvider)

MemoryJournalOption configures a MemoryJournalProvider.

func WithMaxEntries

func WithMaxEntries(n int) MemoryJournalOption

WithMaxEntries sets the maximum number of entries per journal. When exceeded, the oldest entries are dropped. Default is 10000.

type MemoryJournalProvider

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

MemoryJournalProvider is a thread-safe, in-memory implementation of mms.JournalProvider. It stores entries per (domain, journal) pair with configurable maximum capacity. When the capacity is exceeded, the oldest entries are discarded (ring-buffer semantics).

Entry IDs are auto-assigned as monotonically increasing 8-byte big-endian integers, guaranteeing strict ordering even when multiple entries share the same OccurrenceTime. This makes cursor pagination deterministic and skip-free.

This provider is intended for testing, development, and lightweight server deployments. For production use with large journal volumes, a persistent provider backed by a database or file storage should be used instead.

func NewMemoryJournalProvider

func NewMemoryJournalProvider(opts ...MemoryJournalOption) *MemoryJournalProvider

NewMemoryJournalProvider creates a new in-memory journal provider.

func (*MemoryJournalProvider) AddEntry

func (p *MemoryJournalProvider) AddEntry(domain, journal string, occTime time.Time, vars []mms.JournalVariable) []byte

AddEntry appends a journal entry with the given timestamp and variable data. The EntryID is assigned automatically. Returns the assigned EntryID.

The provided variables are defensively copied so that later mutation of the caller's slice or the values within it does not corrupt the journal history.

If the journal does not exist, it is created implicitly.

func (*MemoryJournalProvider) EntryCount

func (p *MemoryJournalProvider) EntryCount(domain, journal string) int

EntryCount returns the number of entries in the specified journal.

func (*MemoryJournalProvider) ListJournals

func (p *MemoryJournalProvider) ListJournals(_ context.Context, domain string) ([]string, error)

ListJournals implements mms.JournalProvider. Results are sorted for deterministic output.

func (*MemoryJournalProvider) ReadStartAfter

func (p *MemoryJournalProvider) ReadStartAfter(_ context.Context, domain, journal string, afterID []byte, afterTime time.Time, maxEntries int) (*mms.JournalResult, error)

ReadStartAfter implements mms.JournalProvider.

func (*MemoryJournalProvider) ReadTimeRange

func (p *MemoryJournalProvider) ReadTimeRange(_ context.Context, domain, journal string, start, stop time.Time, maxEntries int) (*mms.JournalResult, error)

ReadTimeRange implements mms.JournalProvider.

func (*MemoryJournalProvider) RegisterJournal

func (p *MemoryJournalProvider) RegisterJournal(domain, journal string)

RegisterJournal creates an empty journal. This must be called before [AddEntry] to establish the journal's existence. Calling RegisterJournal for an already-registered journal is a no-op.

type ModelError

type ModelError struct {
	Ref     string
	Message string
	Wrapped error
}

ModelError indicates a mismatch or inconsistency in the IEC 61850 data model.

func (*ModelError) Error

func (e *ModelError) Error() string

func (*ModelError) Unwrap

func (e *ModelError) Unwrap() error

type ModelNode

type ModelNode struct {
	// Name is the local name of this node (LD name, LN name, or
	// path component name).
	Name string

	// Reference is the object reference for this node. During browse/
	// tree discovery the FC field is typically empty because the same
	// path may appear under multiple FCs. Use [Ref.WithFC],
	// [ModelNode.FC], or [ModelNode.FCs] to obtain an FC-qualified
	// reference suitable for read/write operations.
	Reference Ref

	// FC is the functional constraint when a single unambiguous FC
	// applies. Set only when exactly one FC is observed for this
	// node (e.g., via [TreeOptions.IncludeFCs] or caller-assigned).
	FC FunctionalConstraint

	// FCs contains all functional constraints observed for this
	// node. Populated when [TreeOptions.IncludeFCs] is true.
	// Multiple entries indicate the node appears under several FCs
	// (common for DOs containing attributes in ST, MX, CF, etc.).
	// Empty when FC annotation is not requested.
	FCs []FunctionalConstraint

	// Type contains MMS type information when available (from
	// GetVariableAccessAttributes). Nil when type info has not
	// been retrieved.
	Type *mms.TypeSpec

	// Children contains the child nodes in the hierarchy.
	Children []*ModelNode
}

ModelNode represents a node in the IEC 61850 data model tree. Used by Client.Tree to represent the full model hierarchy.

type OperateParams

type OperateParams struct {
	// CtlVal is the control value to write. Required.
	// Use [BoolCtlVal], [IntCtlVal], [FloatCtlVal], [EnumCtlVal],
	// or [StringCtlVal] to construct it.
	CtlVal *mms.Value

	// Origin identifies the command originator. When nil, a default
	// Origin with OrCatRemoteControl and empty OrIdent is used.
	Origin *Origin

	// CtlNum is the control sequence number. For enhanced security
	// models, this must be unique per select/operate cycle. When
	// zero, the library auto-increments an internal counter.
	CtlNum uint8

	// OperTm is the scheduled operation time. A zero value means
	// "operate now" (no timed command).
	OperTm time.Time

	// Test, when true, sets the Test bit to indicate a test command
	// that should not cause physical action.
	Test bool

	// Check specifies synchrocheck/interlockCheck conditions.
	Check CheckConditions
}

OperateParams contains all parameters for an IEC 61850 control Operate or SelectWithValue command.

At minimum, CtlVal must be set. For enhanced security models, Origin, CtlNum, and timestamps are also required. The library fills in sensible defaults for unset fields when possible.

type OptFlds

type OptFlds uint16

OptFlds represents the optional fields bit mask of a report control block. Each bit controls whether the corresponding field is included in generated reports.

const (
	OptFldSeqNum       OptFlds = 1 << 0 // Sequence number
	OptFldTimeStamp    OptFlds = 1 << 1 // Report timestamp
	OptFldReasonCode   OptFlds = 1 << 2 // Inclusion reason per member
	OptFldDataSet      OptFlds = 1 << 3 // Dataset reference
	OptFldDataRef      OptFlds = 1 << 4 // Data references
	OptFldBufOvfl      OptFlds = 1 << 5 // Buffer overflow flag
	OptFldEntryID      OptFlds = 1 << 6 // Entry ID (BRCB)
	OptFldConfRev      OptFlds = 1 << 7 // Configuration revision
	OptFldSegmentation OptFlds = 1 << 8 // Segmentation info
)

Optional field flags for OptFlds.

func (OptFlds) Has

func (o OptFlds) Has(flag OptFlds) bool

Has reports whether the specified optional field flag is set.

func (OptFlds) String

func (o OptFlds) String() string

String returns a comma-separated list of set optional field names.

type OrCat

type OrCat int

OrCat represents the originator category (orCat) in the Origin structure of IEC 61850 control commands.

const (
	OrCatNotSupported     OrCat = 0
	OrCatBayControl       OrCat = 1
	OrCatStationControl   OrCat = 2
	OrCatRemoteControl    OrCat = 3
	OrCatAutomaticBay     OrCat = 4
	OrCatAutomaticStation OrCat = 5
	OrCatAutomaticRemote  OrCat = 6
	OrCatMaintenance      OrCat = 7
	OrCatProcess          OrCat = 8
)

func (OrCat) String

func (c OrCat) String() string

String returns the originator category name.

type Origin

type Origin struct {
	// OrCat is the originator category.
	OrCat OrCat

	// OrIdent is the originator identifier (application-specific,
	// typically an IP address or operator ID).
	OrIdent []byte
}

Origin identifies the originator of a control command.

type OverflowPolicy

type OverflowPolicy int

OverflowPolicy controls what happens when a subscription's report channel is full.

URCB vs BRCB loss semantics

For URCB (unbuffered) reports, report loss at the application queue level is expected and accepted — the server makes no durability promise. When OverflowDropNewest or OverflowDropOldest is used, lost reports are silently discarded and the client will not observe a gap indicator. This matches the standard URCB contract: reports are best-effort.

For BRCB (buffered) reports, application queue overflow is a different concern from the server-side BRCB buffer overflow:

  • Server-side BRCB buffer overflow occurs when the in-memory buffer (default: 1000 entries) fills up before any client enables the BRCB. The server drops the oldest entry and sets BufOvfl=true in the next delivered report so the client knows a gap exists.

  • Client-side application queue overflow (this type) occurs when the client's in-process channel (QueueSize) fills up while reports are being delivered. The chosen OverflowPolicy applies here; the server is unaware of this loss. For BRCB use cases that require no loss, set QueueSize large enough and consume reports promptly, or use OverflowBlock.

Choosing a policy

  • OverflowDropNewest: default. Safe for all uses. Report loss is visible in SeqNum gaps.
  • OverflowDropOldest: prefer fresher data; older values are discarded.
  • OverflowBlock: zero-loss delivery. Blocks report dispatch for all subscriptions on this connection if the channel is full.
  • OverflowCallback: custom handling (e.g., metrics, reconnect trigger).
const (
	// OverflowDropNewest drops the incoming report when the channel
	// is full (default). A warning is logged.
	OverflowDropNewest OverflowPolicy = iota

	// OverflowDropOldest discards the oldest buffered report to
	// make room for the new one.
	OverflowDropOldest

	// OverflowBlock blocks the dispatcher until space is available.
	// Use with caution: this can block all report delivery.
	OverflowBlock

	// OverflowCallback invokes the OnOverflow callback (if set)
	// and drops the report. If no callback is set, behaves like
	// [OverflowDropNewest].
	OverflowCallback
)

type Quality

type Quality uint16

Quality represents an IEC 61850 quality bit string (13 bits).

Quality is stored as a uint16 where bit positions match the IEC 61850 standard and the C libiec61850 convention:

  • bits 0–1: Validity
  • bit 2: Overflow
  • bit 3: OutOfRange
  • bit 4: BadReference
  • bit 5: Oscillatory
  • bit 6: Failure
  • bit 7: OldData
  • bit 8: Inconsistent
  • bit 9: Inaccurate
  • bit 10: Source (substituted)
  • bit 11: Test
  • bit 12: OperatorBlocked
const (
	QualityOverflow     Quality = 1 << 2
	QualityOutOfRange   Quality = 1 << 3
	QualityBadReference Quality = 1 << 4
	QualityOscillatory  Quality = 1 << 5
	QualityFailure      Quality = 1 << 6
	QualityOldData      Quality = 1 << 7
	QualityInconsistent Quality = 1 << 8
	QualityInaccurate   Quality = 1 << 9
)

Detail quality flags (bits 2–9).

const (
	QualitySourceSubstituted Quality = 1 << 10
	QualityTest              Quality = 1 << 11
	QualityOperatorBlocked   Quality = 1 << 12
)

Source, test, and operator flags (bits 10–12).

func DecodeQuality

func DecodeQuality(v *mms.Value) (Quality, error)

DecodeQuality decodes an IEC 61850 quality from an MMS bit string value. Returns a DecodeError if the value is not a bit string or has fewer than 13 bits.

func (Quality) Has

func (q Quality) Has(flag Quality) bool

Has returns true if the specified quality flag is set.

func (Quality) IsGood

func (q Quality) IsGood() bool

IsGood returns true when validity is ValidityGood and no detail quality flags are set.

func (Quality) String

func (q Quality) String() string

String returns a human-readable representation of the quality.

func (Quality) Validity

func (q Quality) Validity() Validity

Validity returns the validity component of the quality.

func (Quality) WithValidity

func (q Quality) WithValidity(v Validity) Quality

WithValidity returns a copy of the quality with the given validity.

type RCBFieldMask

type RCBFieldMask uint32

RCBFieldMask specifies which RCB fields to write in a Client.SetReportControlBlock call. Only fields with the corresponding mask bit set are written to the server.

const (
	RCBFieldRptID    RCBFieldMask = 1 << 0  // Write RptID
	RCBFieldRptEna   RCBFieldMask = 1 << 1  // Write RptEna
	RCBFieldDatSet   RCBFieldMask = 1 << 2  // Write DatSet
	RCBFieldOptFlds  RCBFieldMask = 1 << 3  // Write OptFlds
	RCBFieldBufTm    RCBFieldMask = 1 << 4  // Write BufTm
	RCBFieldTrgOps   RCBFieldMask = 1 << 5  // Write TrgOps
	RCBFieldIntgPd   RCBFieldMask = 1 << 6  // Write IntgPd
	RCBFieldGI       RCBFieldMask = 1 << 7  // Write GI
	RCBFieldResv     RCBFieldMask = 1 << 8  // Write Resv (URCB)
	RCBFieldPurgeBuf RCBFieldMask = 1 << 9  // Write PurgeBuf (BRCB)
	RCBFieldEntryID  RCBFieldMask = 1 << 10 // Write EntryID (BRCB)
	RCBFieldResvTms  RCBFieldMask = 1 << 11 // Write ResvTms (URCB)
)

RCB field mask constants for RCBUpdate.

type RCBType

type RCBType int

RCBType distinguishes buffered from unbuffered report control blocks.

const (
	// RCBBuffered is a buffered report control block (BRCB, FC=BR).
	RCBBuffered RCBType = iota
	// RCBUnbuffered is an unbuffered report control block (URCB, FC=RP).
	RCBUnbuffered
)

func (RCBType) FC

FC returns the functional constraint for this RCB type.

func (RCBType) String

func (t RCBType) String() string

String returns "BRCB" or "URCB".

type RCBUpdate

type RCBUpdate struct {
	// Fields selects which attributes to write.
	Fields RCBFieldMask

	RptID    string
	RptEna   bool
	DatSet   string
	OptFlds  OptFlds
	BufTm    uint32
	TrgOps   TrgOps
	IntgPd   uint32
	GI       bool
	Resv     bool
	PurgeBuf bool
	EntryID  []byte
	ResvTms  int32
}

RCBUpdate specifies the RCB fields to write and their new values.

type ReadResult

type ReadResult struct {
	// Ref is the reference that was read.
	Ref Ref

	// Value is the decoded value. Nil when Err is non-nil.
	Value *Value

	// Err is the per-item error, if any. When the MMS server
	// returns a per-variable DataAccessError, Err is set and
	// Value is nil.
	Err error
}

ReadResult holds the outcome of reading a single variable as part of a bulk read operation.

type ReasonCode

type ReasonCode uint8

ReasonCode represents the reason for inclusion of a data set member in a report.

const (
	ReasonDataChanged    ReasonCode = 1 << 0 // Included due to data change
	ReasonQualityChanged ReasonCode = 1 << 1 // Included due to quality change
	ReasonDataUpdate     ReasonCode = 1 << 2 // Included due to data update
	ReasonIntegrity      ReasonCode = 1 << 3 // Included due to integrity scan
	ReasonGI             ReasonCode = 1 << 4 // Included due to GI
)

Reason code values for report member inclusion.

func (ReasonCode) String

func (r ReasonCode) String() string

String returns a comma-separated list of set reason flags, matching the multi-bit style used by OptFlds.String and TrgOps.String.

type Ref

type Ref struct {
	// LD is the logical device name.
	LD string
	// LN is the logical node name (e.g., "LLN0", "GGIO1").
	LN string
	// Path contains the data object / data attribute path components.
	// Empty when the reference points to a logical node.
	Path []string
	// FC is the functional constraint. Empty when not specified.
	FC FunctionalConstraint
}

Ref is a parsed IEC 61850 object reference.

An IEC 61850 object reference identifies a node in the data model hierarchy: LogicalDevice / LogicalNode . DataObject . DataAttribute. An optional functional constraint can be appended in brackets.

Format: LD/LN.DO.DA[FC]

A Ref may represent different levels of the hierarchy:

  • LD-only (LN empty, no path) — identifies a logical device for browsing and GetNameList operations. Not all operations accept LD-only refs; read/write require at least LN + FC.
  • LN-level (LN set, no path) — identifies a logical node.
  • Object-level (LN set, path present) — identifies a data object or data attribute.

Examples:

simpleIOGenericIO/GGIO1.Ind1.stVal[ST]
simpleIOGenericIO/GGIO1.Ind1.stVal
simpleIOGenericIO/LLN0

func ParseRef

func ParseRef(s string) (Ref, error)

ParseRef parses an IEC 61850 object reference string.

Accepted formats:

LD/LN.DO.DA[FC]   — full reference with functional constraint
LD/LN.DO.DA        — reference without FC
LD/LN              — logical node reference
LD                 — logical device reference (LN will be empty)

Returns a *ReferenceError wrapping ErrInvalidReference on malformed input.

The parser accepts references of any reasonable length. Use ParseRefStrict to enforce the conservative 129-character limit inspired by IEC 61850-7-2 VisibleString129.

Unknown FC values (not in the standard set) are accepted. Use StrictnessOptions.RejectUnknownFC at call sites or FunctionalConstraint.IsValid for semantic FC validation.

Example

ExampleParseRef demonstrates parsing an IEC 61850 object reference string.

ref, err := ParseRef("LD1/GGIO1.Ind1.stVal[ST]")
if err != nil {
	log.Fatal(err)
}

fmt.Println(ref.LD)      // "LD1"
fmt.Println(ref.LN)      // "GGIO1"
fmt.Println(ref.Path[0]) // "Ind1"
fmt.Println(ref.Path[1]) // "stVal"
fmt.Println(ref.FC)      // "ST"

func ParseRefStrict

func ParseRefStrict(s string) (Ref, error)

ParseRefStrict is like ParseRef but enforces a maximum reference length of 129 characters, inspired by the IEC 61850-7-2 MMS VisibleString129 type for ObjectReference attributes.

func RefFromMMS

func RefFromMMS(domain mms.DomainID, itemID mms.ItemID) (Ref, error)

RefFromMMS constructs a Ref from an MMS domain ID and item ID.

The item ID is expected to follow the IEC 61850 MMS mapping convention: LN$FC$path$components. The FC is extracted from the second $-delimited segment.

Unknown FCs are accepted and stored as-is. This matches the library's "accept by default, reject via strictness" philosophy. Use StrictnessOptions.RejectUnknownFC at call sites to enforce stricter validation.

Returns an error for empty domain or empty segments within the item ID.

func (Ref) Child

func (r Ref) Child(name string) (Ref, error)

Child returns a new reference with name appended to the path. Returns an error if r has no logical node (LD-only), if name is empty, or if name contains separator characters (/, ., $, [, ]).

func (Ref) Depth

func (r Ref) Depth() int

Depth returns the depth of the reference in the hierarchy.

  • 0: zero-value ref (empty LD)
  • 1: LD only
  • 2: LD/LN
  • 3+: LD/LN + path components (depth = 2 + len(Path))

func (Ref) HasPath

func (r Ref) HasPath() bool

HasPath reports whether the reference includes a data object or data attribute path.

func (Ref) IsLD

func (r Ref) IsLD() bool

IsLD reports whether the reference points to a logical device only.

func (Ref) IsLN

func (r Ref) IsLN() bool

IsLN reports whether the reference points to a logical node (no path).

func (Ref) IsObject

func (r Ref) IsObject() bool

IsObject reports whether the reference points to a data object or data attribute (LN set with at least one path component).

func (Ref) ObjectReference

func (r Ref) ObjectReference() string

ObjectReference returns the reference formatted without the FC bracket suffix.

func (Ref) Parent

func (r Ref) Parent() (Ref, bool)

Parent returns the parent reference. For a DA reference, this returns the parent DO or LN. Returns false if r is already at the top level (LD-only).

The functional constraint is preserved when the returned parent still refers to a logical node or object path. When the parent is LD-only, the FC is dropped because LD[FC] is not a meaningful IEC 61850 reference shape.

func (Ref) String

func (r Ref) String() string

String returns the canonical IEC 61850 object reference string.

func (Ref) ToMMS

func (r Ref) ToMMS() (domain mms.DomainID, itemID mms.ItemID, err error)

ToMMS converts the reference to MMS domain and item ID.

Calls Ref.Validate before conversion. Requires a valid FC when the reference includes a path.

LN-level refs without FC (e.g., Ref{LD:"LD1", LN:"LLN0"}) produce a bare item ID of "LLN0". This is used for GetNameList and other browse-oriented MMS operations. It is not the normal read/write mapping — MMS read/write at the LN level is a special IEC 61850 convention that returns the complete named-variable subtree. Normal attribute access requires FC-qualified refs.

Examples:

Ref{LD:"LD1", LN:"LLN0"}                                     → domain="LD1", itemID="LLN0"
Ref{LD:"LD1", LN:"LLN0", Path:[]string{"Mod","stVal"}, FC:FCST} → domain="LD1", itemID="LLN0$ST$Mod$stVal"

func (Ref) Validate

func (r Ref) Validate() error

Validate checks the structural invariants of the Ref.

Rules:

  • LD must be non-empty
  • if LN is empty, Path must also be empty
  • if LN is empty, FC must also be empty (FC requires at least LN)
  • no empty path components
  • if FC is non-empty, it must be exactly 2 characters (length check only — unknown FC values are accepted; use FunctionalConstraint.IsValid for semantic validation)
  • components must not contain separators (/, ., $, [, ])

func (Ref) WithFC

func (r Ref) WithFC(fc FunctionalConstraint) Ref

WithFC returns a copy of r with the functional constraint set to fc.

type ReferenceError

type ReferenceError struct {
	Input   string
	Reason  string
	Wrapped error
}

ReferenceError is a typed error for malformed or invalid IEC 61850 object references.

func (*ReferenceError) Error

func (e *ReferenceError) Error() string

func (*ReferenceError) Unwrap

func (e *ReferenceError) Unwrap() error

type ReportControlBlock

type ReportControlBlock struct {
	// Reference is a display-only pseudo-reference derived from the
	// MMS item ID by replacing '$' with '.' (e.g. "LD/LLN0.BR.brcb01").
	// This is not a proper IEC 61850 object reference because BR/RP
	// is a functional constraint, not a path component. Use the LD
	// and MMS item ID from the original [Client.GetReportControlBlock]
	// call for programmatic access.
	Reference string

	// Type is BRCB or URCB.
	Type RCBType

	// RptID is the report identifier.
	RptID string

	// RptEna indicates whether the report is enabled.
	RptEna bool

	// DatSet is the data set reference.
	DatSet string

	// ConfRev is the configuration revision number.
	ConfRev uint32

	// OptFlds is the optional fields bit mask.
	OptFlds OptFlds

	// BufTm is the buffer time in milliseconds.
	BufTm uint32

	// SqNum is the current sequence number.
	SqNum uint32

	// TrgOps is the trigger options bit mask.
	TrgOps TrgOps

	// IntgPd is the integrity period in milliseconds.
	IntgPd uint32

	// GI indicates a general interrogation request.
	GI bool

	// Resv is the reservation flag (URCB only).
	Resv bool

	// ResvTms is the reservation time in ms (BRCB only, optional).
	ResvTms int32

	// EntryID is the entry identifier (BRCB only).
	EntryID []byte

	// PurgeBuf indicates a purge buffer request (BRCB only).
	PurgeBuf bool

	// Owner is the client owner identifier (optional, edition 2+).
	Owner []byte
}

ReportControlBlock holds the decoded attributes of a report control block read from a server.

type ReportEngine

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

ReportEngine is the server-side runtime report engine. It monitors value changes in the servermodel.ValueStore and generates IEC 61850 InformationReports to connected clients based on RCB configuration (trigger options, optional fields, dataset bindings).

The engine is created by Server.EnableReports and runs until the server is shut down or ReportEngine.Stop is called.

Interoperability note

The report encoding follows IEC 61850-8-1 field ordering (RptID, OptFlds, optional fields by flag order, SubSeqNum, MoreSegments, inclusion bitmap, values, reason codes). However, IEC 61850 report encoding is unforgiving — small ordering or type mismatches can cause decode failures on the receiving side. The encoding has been validated in loopback tests with the go-iec61850 client decoder but should be verified against real devices or libiec61850 before being considered production-ready.

func (*ReportEngine) HandleRCBWrite

func (re *ReportEngine) HandleRCBWrite(ctx context.Context, ldName, rcbItemID, subfield string, val *mms.Value, conn ...*mms.ServerConn) error

HandleRCBWrite is called when a client writes to an RCB subfield. It intercepts RptEna, GI, Resv, and PurgeBuf writes to trigger the appropriate runtime behavior. The optional conn parameter identifies the MMS connection that issued the write, used for URCB connection-scoped delivery.

func (*ReportEngine) NotifyValueChanged

func (re *ReportEngine) NotifyValueChanged(ctx context.Context, storeKey string)

NotifyValueChanged is called when a data attribute value is changed in the ValueStore. It checks all enabled RCBs for relevant triggers and generates reports as needed.

func (*ReportEngine) SetRCBBufMax added in v1.0.2

func (re *ReportEngine) SetRCBBufMax(ldName, rcbItemID string, max int) bool

SetRCBBufMax sets the maximum buffer capacity for the named BRCB. Returns false if the RCB is not found. Intended for testing; use with caution in production code.

func (*ReportEngine) Stop

func (re *ReportEngine) Stop()

Stop shuts down the report engine, stopping all integrity timers and disabling all RCBs.

type ReportError

type ReportError struct {
	RCBRef  string
	Message string
	Wrapped error
}

ReportError indicates a failure related to report control block operations or report decoding.

func (*ReportError) Error

func (e *ReportError) Error() string

func (*ReportError) Unwrap

func (e *ReportError) Unwrap() error

type ReportIndication

type ReportIndication struct {
	// RptID is the report identifier.
	RptID string

	// OptFlds is the optional fields mask from this report.
	OptFlds OptFlds

	// SeqNum is the sequence number (present when OptFldSeqNum is set).
	SeqNum uint32

	// SubSeqNum is the sub-sequence number for segmented reports.
	SubSeqNum uint32

	// MoreSegments indicates additional report segments follow.
	MoreSegments bool

	// DatSet is the data set reference (present when OptFldDataSet is set).
	DatSet string

	// BufOvfl indicates buffer overflow (present when OptFldBufOvfl is set).
	BufOvfl bool

	// EntryID is the entry identifier (present when OptFldEntryID is set).
	EntryID []byte

	// ConfRev is the configuration revision (present when OptFldConfRev is set).
	ConfRev uint32

	// Timestamp is the report timestamp (present when OptFldTimeStamp
	// is set). Decoded from UTCTime or BinaryTime depending on the
	// server's encoding.
	Timestamp time.Time

	// Inclusion is a bitmask indicating which data set members are
	// included in this report.
	Inclusion []bool

	// DataReferences contains data references for included members
	// (present when OptFldDataRef is set).
	DataReferences []string

	// Values contains the values for included members, in order of
	// inclusion. Only entries where Inclusion[i] is true have values.
	Values []*Value

	// ReasonCodes contains the reason for inclusion for each included
	// member (present when OptFldReasonCode is set).
	ReasonCodes []ReasonCode
}

ReportIndication represents a decoded IEC 61850 report received from the server via an InformationReport.

type ReportSubscription

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

ReportSubscription represents an active subscription to IEC 61850 reports. Reports are delivered to the channel returned by [Reports].

Call ReportSubscription.Close to unsubscribe and release resources. Close is idempotent and safe to call from any goroutine.

func (*ReportSubscription) Close

func (s *ReportSubscription) Close() error

Close terminates the report subscription. It is idempotent and safe to call from any goroutine.

If the subscription was created with lifecycle options (AutoEnable, ReserveURCB), Close performs best-effort remote cleanup: disable the RCB (RptEna=false), then release the URCB reservation. Remote cleanup errors are logged but never prevent local shutdown.

After Close, the [Reports] channel is closed and no further reports are delivered.

func (*ReportSubscription) Reports

func (s *ReportSubscription) Reports() <-chan *ReportIndication

Reports returns a read-only channel that delivers decoded report indications. The channel is closed when the subscription is closed or the client connection is terminated.

type RptMatchMode

type RptMatchMode int

RptMatchMode selects how incoming report IDs are matched against the subscription's RptID pattern.

const (
	// RptMatchExact matches the RptID exactly (default).
	RptMatchExact RptMatchMode = iota

	// RptMatchGlob uses [path.Match] glob semantics. '*' matches
	// any characters within a segment, '?' matches one character.
	RptMatchGlob
)

type SCLParseError

type SCLParseError struct {
	File    string
	Line    int
	Message string
	Wrapped error
}

SCLParseError indicates a failure during SCL file parsing.

func (*SCLParseError) Error

func (e *SCLParseError) Error() string

func (*SCLParseError) Unwrap

func (e *SCLParseError) Unwrap() error

type Server

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

Server is an IEC 61850 MMS server built from an SCL data model.

Stability

The server API is stable as of v1.0.0. It supports variable registration, control operations (direct normal, SBO normal, and SBOw enhanced security with connection-scoped ownership enforcement), runtime report delivery (data-change, quality-change, integrity-period, GI triggers, BRCB replay on re-enable), setting groups (active/edit selection, confirmation, handler callbacks), and journal services (runtime log entry generation with in-memory storage).

Known limitations

  • SCL array/count attributes are parsed but not expanded during server model registration. DA elements with count > 1 are registered as scalar variables.
  • Enum BTypes are mapped to generic integers (INT8) without stronger enum-type semantics.
  • Dataset and report cross-references are validated only within the same logical node. Cross-LN dataset references are not supported.
  • Runtime report engine sends URCBs to the enabling connection and broadcasts BRCBs to all connections. Multi-client URCB arbitration and segmented report generation are not yet implemented.
  • BRCB buffering is in-memory with configurable depth. There is no persistent buffer storage or replay-on-reconnect.
  • Control handlers support SBO ownership enforcement and enhanced-security ctlNum verification, but interlocking, synchrocheck, and command termination are application responsibility via callbacks.

Architecture

The Server wraps a mms.Server and populates its variable registry from an IEC 61850 data model derived from an SCL file. Data attribute values are stored in a thread-safe [ValueStore] that backs the MMS read/write callbacks. Call Server.Close for orderly shutdown of runtime engines when the server is no longer needed.

func NewServer

func NewServer(model *servermodel.Model, opts ServerOptions) (*Server, error)

NewServer creates an IEC 61850 server from the given data model.

The model is typically built via NewServerModelFromSCL. After construction, call Server.Serve or Server.ListenAndServe to accept client connections.

Example

ExampleNewServer demonstrates creating and serving a minimal IEC 61850 server built from an in-process SCL model.

// Build the server model from SCL.
model, err := NewServerModelFromSCL(testServerSCLWithURCB(), "IED1", "")
if err != nil {
	log.Fatal(err)
}

// Create the server.
srv, err := NewServer(model, ServerOptions{})
if err != nil {
	log.Fatal(err)
}

// Optionally start the report engine.
re := srv.EnableReports()
defer re.Stop()

// Register a custom control handler.
_ = srv.RegisterControl("LD1", "GGIO1.SPCSO1", CtlModelDirectNormal, ControlHandler{
	OnOperate: func(ctx context.Context, req ControlRequest) error {
		val, _ := req.CtlVal.Bool()
		log.Printf("operate: ctlVal=%v", val)
		return nil
	},
})
// Serve connections (typically via iso.Listen for production use).
ctx := context.Background()
_ = ctx
// In a real program:
// ln, _ := iso.Listen(":102")
// log.Fatal(srv.ListenAndServe(ctx, ln))

func (*Server) Capabilities

func (s *Server) Capabilities() ServiceCapabilities

Capabilities returns a snapshot of which IEC 61850 services are currently active on this server. This is useful for diagnostics and for verifying that all expected services have been enabled before starting to accept connections.

func (*Server) ChangeActiveSettingGroup

func (s *Server) ChangeActiveSettingGroup(ctx context.Context, ld string, sg uint8) error

ChangeActiveSettingGroup programmatically changes the active setting group for the given LD. This is for server-side use (e.g., operator override). The handler's OnActiveSGChanged callback is invoked.

func (*Server) Close

func (s *Server) Close()

Close performs an orderly shutdown of the server's runtime engines. It stops the report engine (integrity timers, delivery goroutines) and clears references to the journal and setting group engines. Close is idempotent and safe to call multiple times.

Note: Close does not close the underlying MMS server or any active connections. Use context cancellation to stop Server.Serve or Server.ListenAndServe. The journal and setting group engines are stateless (no background goroutines), so they only need reference clearing for garbage collection.

func (*Server) EnableJournals

func (s *Server) EnableJournals(opts ...JournalEngineOption) *JournalEngine

EnableJournals creates and starts the JournalEngine for this server. It scans the model for log definitions, registers journals, and makes the provider available as mms.JournalProvider.

If the MMS server was constructed with a MemoryJournalProvider in [ServerOptions.MMS.JournalProvider], EnableJournals automatically adopts it so that client MMS ReadJournal requests are served from the same data the engine writes to. If no provider was configured, the engine creates one internally. In that case, the engine records entries for programmatic access via JournalEngine.Provider, but client MMS journal reads will not be served (they require the provider to be set at server construction time).

To ensure full client↔server journal support:

jp := iec61850.NewMemoryJournalProvider()
srv, _ := iec61850.NewServer(model, iec61850.ServerOptions{
    MMS: mms.ServerOptions{JournalProvider: jp},
})
engine := srv.EnableJournals(iec61850.WithJournalProvider(jp))

func (*Server) EnableReports

func (s *Server) EnableReports() *ReportEngine

EnableReports creates and starts the ReportEngine for this server. It scans all RCBs in the model, creates runtime state for each, and begins monitoring for GI/integrity triggers.

Call this after NewServer and before Server.Serve or Server.ListenAndServe.

func (*Server) EnableSettingGroups

func (s *Server) EnableSettingGroups(handler SettingGroupHandler)

EnableSettingGroups initialises the setting group engine for the server. It scans the server model for SGCB definitions and registers them with the provided handler.

This should be called after NewServer and before accepting connections.

func (*Server) HandleIdentify

func (s *Server) HandleIdentify(id ServerIdentity)

HandleIdentify registers the MMS Identify handler using the given identity. This is called automatically by NewServer when ServerOptions.Identity is set.

func (*Server) HandleStatus

func (s *Server) HandleStatus()

HandleStatus registers a static MMS Status response. The server always reports operational status.

func (*Server) JournalEngine

func (s *Server) JournalEngine() *JournalEngine

JournalEngine returns the journal engine, or nil if journals have not been enabled via Server.EnableJournals.

func (*Server) ListenAndServe

func (s *Server) ListenAndServe(ctx context.Context, ln mms.TransportListener) error

ListenAndServe accepts connections on the given listener and serves each in a new goroutine. This blocks until the context is cancelled or the listener is closed.

Each accepted connection is handled by Server.Serve in its own goroutine, which ensures that connection lifecycle hooks are invoked.

func (*Server) MMS

func (s *Server) MMS() *mms.Server

MMS returns the underlying MMS server for advanced configuration (e.g., registering Identify/Status handlers or a FileProvider).

func (*Server) Model

func (s *Server) Model() *servermodel.Model

Model returns the server's data model. The returned pointer is shared with the server internals. The caller must not modify the model after server creation — doing so may corrupt the MMS variable registry and cause undefined runtime behaviour.

func (*Server) RegisterControl

func (s *Server) RegisterControl(ldName, doRef string, ctlModel CtlModel, handler ControlHandler) error

RegisterControl registers a ControlHandler for the controllable data object identified by ldName and doRef (e.g. "GGIO1.SPCSO1"). The ctlModel determines the expected control flow.

The handler callbacks are invoked from within the MMS write path when a client writes to the Oper, SBO, SBOw, or Cancel subattributes.

Example

ExampleServer_RegisterControl demonstrates registering a direct control.

model, err := NewServerModelFromSCL(testServerSCLWithURCB(), "IED1", "")
if err != nil {
	log.Fatal(err)
}

srv, err := NewServer(model, ServerOptions{})
if err != nil {
	log.Fatal(err)
}
defer srv.Close()

_ = srv.RegisterControl("LD1", "GGIO1.SPCSO1", CtlModelDirectNormal, ControlHandler{
	OnOperate: func(ctx context.Context, req ControlRequest) error {
		val, _ := req.CtlVal.Bool()
		log.Printf("operate SPCSO1: %v", val)
		return nil
	},
	OnCancel: func(ctx context.Context, req ControlRequest) error {
		log.Println("SPCSO1 cancelled")
		return nil
	},
})

func (*Server) ReportEngine

func (s *Server) ReportEngine() *ReportEngine

ReportEngine returns the report engine, or nil if reports have not been enabled via Server.EnableReports.

func (*Server) Serve

func (s *Server) Serve(ctx context.Context, conn mms.Transport) error

Serve handles a single MMS transport connection. This blocks until the connection is closed or the context is cancelled.

If ServerOptions.OnConnect or ServerOptions.OnDisconnect are configured, OnConnect is called when the transport is accepted (before the MMS association handshake completes), and OnDisconnect is called when the Serve call returns (after the connection is fully closed). This means OnConnect fires even if the association subsequently fails during authentication or handshake.

func (*Server) SetValue

func (s *Server) SetValue(ctx context.Context, storeKey string, val *mms.Value)

SetValue updates a data attribute value in the store and notifies the report engine (if enabled) of the change. The storeKey follows the format "ldName/itemID" (see servermodel.StoreKey).

This is the primary way to inject process values into a running server and have them trigger reports automatically.

Example

ExampleServer_SetValue demonstrates pushing a data value into the server model, which triggers data-change reports to subscribed clients.

model, err := NewServerModelFromSCL(testServerSCLWithURCB(), "IED1", "")
if err != nil {
	log.Fatal(err)
}

srv, err := NewServer(model, ServerOptions{})
if err != nil {
	log.Fatal(err)
}
re := srv.EnableReports()
defer re.Stop()
defer srv.Close()

// Push a new value — this triggers a dchg report to subscribed clients.
srv.SetValue(context.Background(), "LD1/LLN0$ST$Mod$stVal", mms.NewInteger(1))

func (*Server) SettingGroupEngine

func (s *Server) SettingGroupEngine() *SettingGroupEngine

SettingGroupEngine returns the setting group engine, or nil if setting groups have not been enabled via Server.EnableSettingGroups.

func (*Server) ValueStore

func (s *Server) ValueStore() *servermodel.ValueStore

ValueStore returns the server's value store for direct value manipulation (e.g., updating data attribute values from process inputs).

When reports are enabled, prefer Server.SetValue which automatically triggers change-detection and report generation.

type ServerIdentity

type ServerIdentity struct {
	// Vendor is the vendor/manufacturer name (e.g. "OTFabric").
	Vendor string

	// Model is the device model or product name.
	Model string

	// Revision is the firmware or software revision string.
	Revision string
}

ServerIdentity describes the IEC 61850 server identity returned by the MMS Identify service. Setting this on ServerOptions automatically registers an Identify handler on the MMS server.

type ServerOptions

type ServerOptions struct {
	// Logger, when non-nil, enables structured logging. When
	// [ServerOptions.MMS].Logger is also nil, this logger is passed
	// through to the underlying [mms.Server]. ISO transport logging
	// ([iso.WithLogger]) is independent and is not set from here.
	Logger *slog.Logger

	// Identity, when non-nil, registers the MMS Identify handler so
	// that clients can query vendor/model/revision. Without this,
	// Identify requests are rejected with service-unsupported.
	Identity *ServerIdentity

	// FileProvider, when non-nil, enables MMS file services
	// (FileOpen, FileRead, FileClose, FileDelete, FileDirectory).
	// This is a convenience field; it is equivalent to setting
	// MMS.FileProvider.
	FileProvider mms.FileProvider

	// Authenticate, when non-nil, is called during association
	// establishment to accept or reject peers. This is a convenience
	// field; it is equivalent to setting MMS.Authenticate.
	Authenticate mms.Authenticator

	// OnConnect, when non-nil, is called when a new transport
	// connection is accepted, before the MMS association handshake.
	// This fires even if the association subsequently fails.
	OnConnect func(ConnectionEvent)

	// OnDisconnect, when non-nil, is called when a transport
	// connection's [Server.Serve] call returns (the connection is
	// fully closed regardless of how it ended).
	OnDisconnect func(ConnectionEvent)

	// MMS holds the underlying MMS server options. Fields set here
	// take precedence over convenience fields above (FileProvider,
	// Authenticate) when both are set.
	MMS mms.ServerOptions
}

ServerOptions configures the IEC 61850 server.

type ServiceCapabilities

type ServiceCapabilities struct {
	// Variables is always true (the server always registers variables).
	Variables bool

	// DataSets is true when the model contains dataset definitions.
	// This is a model-level property, not a runtime toggle.
	DataSets bool

	// Reports is true when [Server.EnableReports] has been called
	// (runtime-enabled, not just configured in the model).
	Reports bool

	// Controls is true when at least one control has been registered
	// via [Server.RegisterControl] (runtime-enabled).
	Controls bool

	// SettingGroups is true when [Server.EnableSettingGroups] has been
	// called (runtime-enabled, not just present in the model).
	SettingGroups bool

	// Journals is true when [Server.EnableJournals] has been called
	// (runtime-enabled, not just present in the model).
	Journals bool

	// Files is true when a [mms.FileProvider] was configured.
	Files bool

	// Identify is true when server identity was configured.
	Identify bool
}

ServiceCapabilities reports which IEC 61850 server-side services are active on this server instance.

There is a distinction between "configured" (the model contains the necessary definitions) and "runtime-enabled" (the application called the Enable method). For reports, setting groups, and journals the boolean reflects runtime enablement, not merely model presence. Use this to verify that all expected services have been enabled before accepting connections.

func (ServiceCapabilities) String

func (c ServiceCapabilities) String() string

String returns a human-readable summary of enabled services, useful for diagnostics and startup logging.

type SettingGroupEngine

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

SettingGroupEngine manages server-side setting group control blocks. It intercepts SGCB writes (ActSG, EditSG, CnfEdit) and enforces the setting group lifecycle.

Interoperability note

This implementation covers the core setting group workflow (active selection, edit reservation, confirm/commit). Reservation timeouts, multi-connection ownership tracking, and persistent setting group storage are not yet implemented. These are documented in KNOWN_LIMITATIONS.md.

func (*SettingGroupEngine) GetActiveSettingGroup

func (e *SettingGroupEngine) GetActiveSettingGroup(ldName string) uint8

GetActiveSettingGroup returns the currently active setting group for the given LD. Returns 0 if no SGCB is registered.

func (*SettingGroupEngine) GetEditSettingGroup

func (e *SettingGroupEngine) GetEditSettingGroup(ldName string) uint8

GetEditSettingGroup returns the setting group currently under edit for the given LD. Returns 0 if no edit session is active.

func (*SettingGroupEngine) HandleSGCBWrite

func (e *SettingGroupEngine) HandleSGCBWrite(ctx context.Context, ldName, subfield string, val *mms.Value) error

HandleSGCBWrite intercepts writes to SGCB subfields and enforces setting group semantics. Returns nil if the write is handled (accepted or rejected with an MMS error); returns an error to propagate to the MMS layer as a write failure.

Supported subfields: ActSG, EditSG, CnfEdit.

type SettingGroupHandler

type SettingGroupHandler struct {
	// OnActiveSGChanged is called when a client selects a new active
	// setting group. Return a non-nil error to reject the activation.
	// The newSG is 1-based.
	OnActiveSGChanged func(ctx context.Context, ld string, newSG uint8) error

	// OnEditSGSelected is called when a client selects a group for
	// editing. Return a non-nil error to reject the selection (e.g.,
	// if another edit session is in progress from a different source).
	OnEditSGSelected func(ctx context.Context, ld string, editSG uint8) error

	// OnConfirmEdit is called when a client confirms an edit session.
	// The application should persist or apply the edited values.
	// Return a non-nil error to reject the confirmation.
	OnConfirmEdit func(ctx context.Context, ld string, editSG uint8) error
}

SettingGroupHandler provides application callbacks for setting group operations. All callbacks are optional; nil callbacks accept the operation unconditionally.

type SettingGroupInfo

type SettingGroupInfo struct {
	// NumOfSGs is the total number of setting groups (1-based).
	NumOfSGs uint8

	// ActSG is the currently active setting group number (1-based).
	ActSG uint8

	// EditSG is the group currently selected for editing (0 = none).
	EditSG uint8

	// CnfEdit is true when the server has confirmed the edit.
	CnfEdit bool

	// ResvTms is the reservation timeout in seconds (0 = no timeout).
	// This field is optional; not all servers expose it.
	ResvTms uint16
}

SettingGroupInfo holds the state of a Setting Group Control Block (SGCB) as defined in IEC 61850-7-2 §16.

The SGCB is a special control block under LLN0 at FC=SP that governs multiple setting groups. Each setting group provides a complete set of SE-constrained data attribute values; one group is "active" (read by clients via FC=SG) and one may be under edit (written via FC=SE).

MMS mapping

The SGCB is mapped to MMS as "LLN0$SP$SGCB" with the following structure members in order:

[0] NumOfSGs   (Unsigned8)  — total number of setting groups
[1] ActSG      (Unsigned8)  — currently active setting group
[2] EditSG     (Unsigned8)  — currently selected edit group (0 = none)
[3] CnfEdit    (BOOLEAN)    — confirm-edit flag
[4] LActTm     (UTCTime)    — last activation timestamp
[5] ResvTms    (Unsigned16) — reservation timeout in seconds (optional)

type StrictnessOptions

type StrictnessOptions struct {
	// RejectUnknownFC, when true, causes browse and tree operations
	// to return an error when an item ID contains a functional
	// constraint that is not in the IEC 61850 standard set. When
	// false (the default), unknown FCs are silently accepted and
	// stored as-is.
	RejectUnknownFC bool

	// VerifyReportCandidates, when true, causes [Client.ListReports]
	// to read and decode each heuristic RCB candidate, excluding
	// items that fail to decode as valid RCB structures. When false
	// (the default), discovery uses the fast naming-heuristic only.
	VerifyReportCandidates bool
}

StrictnessOptions controls how strictly the client validates server responses and reference formats. The zero value uses pragmatic defaults suitable for interop with real-world IEC 61850 servers.

type SubscribeReportOptions

type SubscribeReportOptions struct {
	// QueueSize is the buffer size for the report channel. Defaults
	// to 64 if zero.
	QueueSize int

	// OverflowPolicy controls behavior when the channel is full.
	// Default is [OverflowDropNewest].
	OverflowPolicy OverflowPolicy

	// OnOverflow is called when a report is dropped due to overflow
	// (only used with [OverflowCallback]). Called from the dispatch
	// goroutine — must not block.
	OnOverflow func(*ReportIndication)

	// MatchMode selects how the RptID is matched. Default is exact.
	MatchMode RptMatchMode

	// CloneReports, when true, delivers a shallow copy of each
	// [ReportIndication] to this subscription instead of sharing
	// a pointer with other subscriptions. This allows safe mutation
	// of Values, DataReferences, and ReasonCodes slices without
	// affecting other subscribers.
	CloneReports bool

	// AutoEnable, when true, enables the RCB (RptEna=true) as part
	// of subscribing. Requires LD and RCBItemID to be set.
	AutoEnable bool

	// GIOnSubscribe, when true, triggers a General Interrogation
	// after enabling. Requires AutoEnable or that the RCB is
	// already enabled.
	GIOnSubscribe bool

	// ReserveURCB, when true, reserves the URCB before enabling.
	// Only meaningful for unbuffered RCBs.
	ReserveURCB bool

	// LD is the logical device for lifecycle operations
	// (AutoEnable, GIOnSubscribe, ReserveURCB). Required when
	// any lifecycle option is set.
	LD string

	// RCBItemID is the RCB MMS item ID for lifecycle operations.
	// Required when any lifecycle option is set.
	RCBItemID string
}

SubscribeReportOptions configures a report subscription.

type TimeQuality

type TimeQuality struct {
	// LeapSecondKnown indicates whether leap second information
	// is known (bit 7 of quality byte).
	LeapSecondKnown bool

	// ClockFailure indicates a clock hardware failure
	// (bit 6 of quality byte).
	ClockFailure bool

	// ClockNotSynchronized indicates the clock is not synchronized
	// to an external time source (bit 5 of quality byte).
	ClockNotSynchronized bool

	// TimeAccuracy is the number of significant bits in the
	// fraction-of-second field (bits 0–4, range 0–31). Higher
	// values indicate better precision. Zero means unspecified.
	TimeAccuracy int
}

TimeQuality represents the time quality byte of an IEC 61850 timestamp.

type Timestamp

type Timestamp struct {
	// Time is the timestamp value.
	Time time.Time

	// Quality contains time quality flags. Zero-valued when
	// decoded from go-mms (time quality not yet exposed by
	// the MMS layer).
	Quality TimeQuality
}

Timestamp represents an IEC 61850 timestamp (UTCTime) with optional time quality information.

The IEC 61850 timestamp is an 8-byte structure:

  • bytes 0–3: seconds since Unix epoch
  • bytes 4–6: fraction of second (24-bit binary fraction)
  • byte 7: time quality

EncodeTimestamp preserves the full TimeQuality in the UTCTimeQuality byte. DecodeTimestamp quality fidelity depends on go-mms exposing UTCTimeQuality(); if the MMS layer does not populate the quality byte, decoded quality will be zero-valued.

func DecodeTimestamp

func DecodeTimestamp(v *mms.Value) (Timestamp, error)

DecodeTimestamp decodes an IEC 61850 timestamp from an MMS UTCTime value. Returns a DecodeError if the value is not a UTCTime.

Time quality flags (leap second awareness, clock failure, clock synchronization, sub-second accuracy) are decoded from the go-mms UTCTimeQuality byte.

func (Timestamp) IsZero

func (ts Timestamp) IsZero() bool

IsZero returns true if the timestamp has a zero time value.

func (Timestamp) String

func (ts Timestamp) String() string

String returns the timestamp formatted as RFC 3339 with nanosecond precision.

type TreeOptions

type TreeOptions struct {
	// LDFilter, when non-empty, restricts the tree to a single
	// logical device matching this name.
	LDFilter string

	// MaxDepth limits how deep the tree is built. Zero means
	// unlimited. Depth counts model-hierarchy levels starting at
	// the logical device level (consistent with [Ref.Depth]):
	//   1 = LD nodes only
	//   2 = LD + LN nodes
	//   3 = LD + LN + first DO level
	//   4+ = deeper data attributes
	//
	// Note: the returned root node is a synthetic container that
	// sits outside the depth model. Its children are the LD nodes
	// (depth 1). MaxDepth=1 therefore returns a root whose
	// children are bare LD nodes with no further expansion.
	MaxDepth int

	// IncludeFCs annotates tree nodes with functional constraint
	// information. When true, each leaf/intermediate node will
	// have its FCs field populated with all FCs observed for that
	// node in the MMS item IDs. The single FC field is set when
	// only one FC applies.
	IncludeFCs bool
}

TreeOptions configures the tree-building behavior for Client.TreeWithOptions.

type TrgOps

type TrgOps uint8

TrgOps represents the trigger options bit mask of a report control block.

const (
	TrgOpDataChanged    TrgOps = 1 << 0 // Data change
	TrgOpQualityChanged TrgOps = 1 << 1 // Quality change
	TrgOpDataUpdate     TrgOps = 1 << 2 // Data update
	TrgOpIntegrity      TrgOps = 1 << 3 // Integrity period
	TrgOpGI             TrgOps = 1 << 4 // General interrogation
)

Trigger option flags for TrgOps.

func (TrgOps) Has

func (t TrgOps) Has(flag TrgOps) bool

Has reports whether the specified trigger option is set.

func (TrgOps) String

func (t TrgOps) String() string

String returns a comma-separated list of set trigger option names.

type Validity

type Validity int

Validity represents the validity portion of an IEC 61850 quality.

const (
	// ValidityGood indicates the value is valid.
	ValidityGood Validity = 0
	// ValidityReserved is reserved for future use.
	ValidityReserved Validity = 1
	// ValidityInvalid indicates the value is not valid.
	ValidityInvalid Validity = 2
	// ValidityQuestionable indicates the value may not be valid.
	ValidityQuestionable Validity = 3
)

type Value

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

Value wraps an mms.Value with IEC 61850 semantic accessors.

Value provides typed accessor methods that return errors instead of ok booleans, and IEC 61850-specific decoders for Quality and Timestamp. Use Value.MMS to access the underlying MMS value when needed.

Values are created by NewValue, the constructor functions (BoolValue, IntValue, etc.), or returned from read operations.

func ArrayValue

func ArrayValue(elements []*Value) (*Value, error)

ArrayValue creates a Value from a slice of element Values with validation. Returns an error if any element is nil.

Use UnsafeArrayValue for the unchecked fast path when all elements are guaranteed non-nil.

func BoolValue

func BoolValue(b bool) *Value

BoolValue creates a Value from a bool.

func FloatValue

func FloatValue(f float64) *Value

FloatValue creates a Value from a float64.

func IntValue

func IntValue(i int64) *Value

IntValue creates a Value from an int64.

func NewValue

func NewValue(v *mms.Value) *Value

NewValue wraps an mms.Value. Returns nil if v is nil.

func OctetStringValue

func OctetStringValue(data []byte) *Value

OctetStringValue creates a Value from a byte slice.

func QualityValue

func QualityValue(q Quality) *Value

QualityValue creates a Value from a Quality.

func StringValue

func StringValue(s string) *Value

StringValue creates a Value from a string (MMS VisibleString).

func StructureValue

func StructureValue(elements []*Value) (*Value, error)

StructureValue creates a Value from a slice of element Values with validation. Returns an error if any element is nil.

Use UnsafeStructureValue for the unchecked fast path when all elements are guaranteed non-nil.

func TimestampValue

func TimestampValue(ts Timestamp) *Value

TimestampValue creates a Value from a Timestamp.

func UintValue

func UintValue(u uint64) *Value

UintValue creates a Value from a uint64.

func UnsafeArrayValue

func UnsafeArrayValue(elements []*Value) *Value

UnsafeArrayValue creates a Value from a slice of element Values without nil-checking. Nil elements produce a malformed MMS array that will fail encoding. Prefer ArrayValue unless performance requires skipping validation.

func UnsafeStructureValue

func UnsafeStructureValue(elements []*Value) *Value

UnsafeStructureValue creates a Value from a slice of element Values without nil-checking. Nil elements produce a malformed MMS structure that will fail encoding. Prefer StructureValue unless performance requires skipping validation.

func (*Value) BitString

func (v *Value) BitString() ([]byte, error)

BitString returns the raw bit string bytes. The returned slice may alias the underlying MMS value memory. Copy it if ownership or later mutation is required. Returns a DecodeError if the value is nil or not a bit string.

func (*Value) Bool

func (v *Value) Bool() (bool, error)

Bool returns the value as a bool. Returns a DecodeError if the value is nil or not a boolean.

func (*Value) Elements

func (v *Value) Elements() ([]*Value, error)

Elements returns the structure or array elements as Values. Use Value.IsStructure and Value.IsArray to determine which container kind the value holds before calling this method. Returns a DecodeError if the value is nil or not a structure or array.

func (*Value) Float32

func (v *Value) Float32() (float32, error)

Float32 returns the value as a float32. Returns a DecodeError if the value is nil or not a float.

func (*Value) Float64

func (v *Value) Float64() (float64, error)

Float64 returns the value as a float64. Returns a DecodeError if the value is nil or not a float.

func (*Value) Int32

func (v *Value) Int32() (int32, error)

Int32 returns the value as an int32. Returns a DecodeError if the value is nil or not an integer.

func (*Value) Int64

func (v *Value) Int64() (int64, error)

Int64 returns the value as an int64. Returns a DecodeError if the value is nil or not an integer.

func (*Value) IsArray

func (v *Value) IsArray() bool

IsArray reports whether the value is an MMS array.

func (*Value) IsStructure

func (v *Value) IsStructure() bool

IsStructure reports whether the value is an MMS structure.

func (*Value) MMS

func (v *Value) MMS() *mms.Value

MMS returns the underlying mms.Value. This is the escape hatch for operations not covered by the IEC 61850 typed accessors.

func (*Value) MmsString

func (v *Value) MmsString() (string, error)

MmsString returns the value as a string (MMS MmsString / UTF-8). Returns a DecodeError if the value is nil or not an MMS string.

func (*Value) OctetString

func (v *Value) OctetString() ([]byte, error)

OctetString returns the value as a byte slice. The returned slice may alias the underlying MMS value memory. Copy it if ownership or later mutation is required. Returns a DecodeError if the value is nil or not an octet string.

func (*Value) Quality

func (v *Value) Quality() (Quality, error)

Quality decodes the value as an IEC 61850 quality bit string. Returns a DecodeError if the value is nil or not a 13-bit bit string.

func (*Value) String

func (v *Value) String() string

String returns a debug-friendly string representation of the value.

func (*Value) Timestamp

func (v *Value) Timestamp() (Timestamp, error)

Timestamp decodes the value as an IEC 61850 timestamp. Returns a DecodeError if the value is nil or not a UTCTime.

func (*Value) Type

func (v *Value) Type() mms.ValueType

Type returns the MMS value type. Returns mms.ValueTypeDataAccessError when the Value or its underlying MMS value is nil.

func (*Value) Uint32

func (v *Value) Uint32() (uint32, error)

Uint32 returns the value as a uint32. Returns a DecodeError if the value is nil or not an unsigned integer.

func (*Value) Uint64

func (v *Value) Uint64() (uint64, error)

Uint64 returns the value as a uint64. Returns a DecodeError if the value is nil or not an unsigned integer.

func (*Value) VisibleString

func (v *Value) VisibleString() (string, error)

VisibleString returns the value as a string (MMS VisibleString). Returns a DecodeError if the value is nil or not a visible string.

type WriteRequest

type WriteRequest struct {
	// Ref is the target reference. Must include LD, LN, FC,
	// and at least one path component.
	Ref Ref

	// Value is the MMS value to write.
	Value *mms.Value
}

WriteRequest specifies a single variable to write as part of a bulk write operation.

type WriteResult

type WriteResult struct {
	// Ref is the reference that was written.
	Ref Ref

	// Success is true if the write was accepted by the server.
	Success bool

	// Err is the per-item error, if any.
	Err error
}

WriteResult holds the outcome of writing a single variable as part of a bulk write operation.

Directories

Path Synopsis
examples
basic-client command
Command basic-client demonstrates connecting to an IEC 61850 server, listing logical devices and nodes, and reading the first browsed data attribute.
Command basic-client demonstrates connecting to an IEC 61850 server, listing logical devices and nodes, and reading the first browsed data attribute.
browse-tree command
Command browse-tree demonstrates building and printing the IEC 61850 model tree from a server, optionally with FC annotations.
Command browse-tree demonstrates building and printing the IEC 61850 model tree from a server, optionally with FC annotations.
control command
Command control demonstrates IEC 61850 control operations: reading the control model, performing direct-operate, and select-before-operate workflows.
Command control demonstrates IEC 61850 control operations: reading the control model, performing direct-operate, and select-before-operate workflows.
files command
Command files demonstrates listing and reading files from an IEC 61850 server.
Command files demonstrates listing and reading files from an IEC 61850 server.
ied-client command
Command ied-client is an end-to-end example of how a production IEC 61850 client application is structured using go-iec61850.
Command ied-client is an end-to-end example of how a production IEC 61850 client application is structured using go-iec61850.
ied-server command
Command ied-server is an end-to-end example of how a production IEC 61850 server application is structured using go-iec61850.
Command ied-server is an end-to-end example of how a production IEC 61850 server application is structured using go-iec61850.
reports command
Command reports demonstrates subscribing to an IEC 61850 buffered report and printing incoming indications.
Command reports demonstrates subscribing to an IEC 61850 buffered report and printing incoming indications.
internal
mapping
Package mapping provides internal helpers for translating between MMS named variables and IEC 61850 model structure.
Package mapping provides internal helpers for translating between MMS named variables and IEC 61850 model structure.
sclindex
Package sclindex is reserved for centralizing SCL DataTypeTemplates lookup and cycle-detection logic that is currently duplicated across the servermodel and (future) client-side model expansion packages.
Package sclindex is reserved for centralizing SCL DataTypeTemplates lookup and cycle-detection logic that is currently duplicated across the servermodel and (future) client-side model expansion packages.
servermodel
Package servermodel defines the IEC 61850 server-side data model.
Package servermodel defines the IEC 61850 server-side data model.
scl
Package scl provides parsing and inspection of IEC 61850 SCL (Substation Configuration Language) files.
Package scl provides parsing and inspection of IEC 61850 SCL (Substation Configuration Language) files.
cmd/sclgen command
Command sclgen generates internal Go types from IEC 61850 SCL XSD schemas.
Command sclgen generates internal Go types from IEC 61850 SCL XSD schemas.
cmd/sclparse command
Command sclparse inspects, validates, and summarizes IEC 61850 SCL files.
Command sclparse inspects, validates, and summarizes IEC 61850 SCL files.
index
Package index provides a shared, indexed view of a parsed SCL model.
Package index provides a shared, indexed view of a parsed SCL model.
internal/genir
Package genir provides the intermediate representation for the SCL code generator.
Package genir provides the intermediate representation for the SCL code generator.
internal/raw/v17
Package v17 contains generated raw XML types for IEC 61850 SCL schema version v17.
Package v17 contains generated raw XML types for IEC 61850 SCL schema version v17.
internal/raw/v2007b
Package v2007b contains generated raw XML types for IEC 61850 SCL schema version v2007b.
Package v2007b contains generated raw XML types for IEC 61850 SCL schema version v2007b.
internal/raw/v2007b4
Package v2007b4 contains generated raw XML types for IEC 61850 SCL schema version v2007b4.
Package v2007b4 contains generated raw XML types for IEC 61850 SCL schema version v2007b4.
internal/raw/v2007c5
Package v2007c5 contains generated raw XML types for IEC 61850 SCL schema version v2007c5.
Package v2007c5 contains generated raw XML types for IEC 61850 SCL schema version v2007c5.
validate
Package validate provides semantic validation of a parsed SCL model.
Package validate provides semantic validation of a parsed SCL model.

Jump to

Keyboard shortcuts

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