moonbit-iec104

Portable IEC 60870-5-104 protocol core for SCADA, gateways, and deterministic simulation.

iec104
scada
telecontrol
protocol
moon add hhxhhx78/moonbit-iec104@0.2.0
Download zip
Author
Version
0.2.0
License
Apache-2.0
Last updated
1 hour ago
Downloads
2
README

#moonbit-iec104

一个面向 SCADA、变电站自动化、配电网关和协议仿真的 IEC 60870-5-104 协议核心。项目使用 MoonBit 编写,库层不绑定 TCP 实现或操作系统 I/O,便于嵌入网关、测试工具和确定性仿真器。

#项目定位

本项目覆盖 IEC 104 链路层与常用应用层数据模型,重点放在可验证的二进制编解码、链路状态、序号窗口、信息对象和边界行为。网络传输由调用方接入,协议核心因此可以在 native、wasm-gc 等目标上复用。

#核心能力

  • APCI I/S/U 帧编解码、15 位发送/接收序号和序号窗口。
  • STARTDT、STOPDT、TESTFR 链路状态机、定时器和流式 APDU 解析。
  • IEC 104 常用 Type ID、VSQ、传送原因、公共地址和信息体地址模型。
  • 单点、双点、步位、归一化值、标度值、短浮点值、累计量及命令对象。
  • CP24Time2a、CP56Time2a、质量描述符、地址序列和带时标 ASDU 编解码。
  • 点表、历史变更、总召唤/计数量召唤、读命令、时钟同步和命令策略。
  • 资源限制、重放保护、CRC、帧统计、健康报告和确定性仿真工作负载。

#快速开始

需要 MoonBit stable 工具链。首次使用时执行:

moon update moon fmt moon check --deny-warn --target all moon build --target wasm-gc moon test --deny-warn --target wasm-gc

运行示例 CLI:

moon run cmd/main moon run cmd/main -- --help moon run cmd/main -- --benchmark

在库代码中构造并编码一个 I 帧:

///|
let payload = @hhxhhx78/moonbit-iec104.normalized_value_asdu(3, 1, 2300, 0)

///|
let apdu = @hhxhhx78/moonbit-iec104.encode_frame(
@hhxhhx78/moonbit-iec104.information_frame(0, 0, payload),
)

#CLI

cmd/main 提供一个不依赖外部服务的可重复示例:默认编码一个归一化测量值 I 帧;--benchmark 执行固定的 10,000 帧编解码工作负载并输出帧数、字节数和校验和;--help 显示用法。宿主机耗时由基准命令外部测量,避免把平台时钟引入协议核心。

#架构

层次主要文件职责
链路与帧frame_types.mbt, codec.mbt, validation.mbt, state_machine.mbtAPCI、ASDU 基础模型、校验和链路状态
应用数据protocol_domain.mbt, quality.mbt, time_tags.mbt, application_objects.mbt, extended_asdu.mbtType ID、地址、质量、时标和信息对象
服务与状态transport_layer.mbt, application_services.mbt, point_store.mbt序号窗口、定时器、召唤事务、点表和历史
工具与可靠性wire_tools.mbt, security_limits.mbt, diagnostics_metrics.mbt, health_report.mbt字节工具、资源保护、指标和诊断
仿真与契约simulation.mbt, conformance_catalog.mbt, protocol_profiles.mbt, benchmark_api.mbt确定性仿真、类型目录、能力协商和基准接口
示例cmd/main可运行的最小 CLI

#基准

基准工作负载由 run_benchmark_workload 定义,输入、输出字节数和 CRC 校验和均是确定的;宿主机实测结果记录在 BENCHMARKS.md,包含执行环境、命令、重复次数和原始输出。重新测量:

1..5 | ForEach-Object { Measure-Command { moon run cmd/main -- --benchmark } }

该数据用于比较同一环境下的回归趋势,不代表所有设备或网络部署的吞吐承诺。

#测试

测试覆盖帧编解码、链路状态、Type ID 和地址边界、CP24/CP56 闰年与无效日期、质量位、签名测量值、ASDU 截断/尾随字节、序号回绕、流式输入、点表历史、服务事务、资源限制、CRC 和确定性基准。推荐在本地分别运行:

moon check --deny-warn --target all moon test --deny-warn --target wasm-gc moon test --deny-warn --target native

#CI

.github/workflows/check.yml 在 Ubuntu、macOS 和 Windows 上安装 MoonBit stable,执行版本检查、依赖更新、格式检查、接口文件一致性、所有目标检查、wasm-gc 构建和测试。CI 使用最小只读仓库权限;本地若缺少某个后端运行时,应以对应平台 CI 结果和明确的本地环境提示为准。

#许可证

本项目采用 Apache License 2.0

#
AdmissionDecision

pub enum AdmissionDecision {
AcceptedAdmission
RejectedAdmission(Diagnostic)
} derive(
Debug
)

#
ApduParseResult

pub enum ApduParseResult {
NeedMore(Int)
Complete(Frame, Int)
Invalid(Diagnostic)
} derive(
Debug
)

Incremental APDU parsing result for TCP or serial gateway adapters.

#
ApduStreamDecoder

pub struct ApduStreamDecoder {
buffer : Array[Byte]
max_apdu : Int
} derive(
Debug
)

A portable byte accumulator for stream transports.

#
ApduStreamDecoder::available_frames

fn ApduStreamDecoder::available_frames(self : ApduStreamDecoder) -> Int

Number of complete frames available in a buffered stream.

#
ApduStreamDecoder::buffered

fn ApduStreamDecoder::buffered(self : ApduStreamDecoder) -> Int

#
ApduStreamDecoder::clear

fn ApduStreamDecoder::clear(self : ApduStreamDecoder) -> Unit

#
ApduStreamDecoder::new

fn ApduStreamDecoder::new(max_apdu? : Int) -> Result[ApduStreamDecoder, String]

#
ApduStreamDecoder::next

Parse and remove the first complete APDU, preserving partial data.

#
ApduStreamDecoder::push

fn ApduStreamDecoder::push(self : ApduStreamDecoder, data : Bytes) -> Result[Int, Diagnostic]

#
ApplicationObject

pub struct ApplicationObject {
address : InformationAddress
type_id : ApplicationType
value : ApplicationValue
time_tag : TimeTag?
} derive(Eq,
Debug
)

An address-qualified application object with an optional time tag.

#
ApplicationObject::address

#
ApplicationObject::is_command

fn ApplicationObject::is_command(self : ApplicationObject) -> Bool

#
ApplicationObject::is_measurement

fn ApplicationObject::is_measurement(self : ApplicationObject) -> Bool

#
ApplicationObject::new

fn ApplicationObject::new(address : InformationAddress, value : ApplicationValue, time_tag? : TimeTag) -> Result[ApplicationObject, String]

Construct an application object and optionally attach its standard time tag.

#
ApplicationObject::summary

fn ApplicationObject::summary(self : ApplicationObject) -> (Int, Int, Int, Bool)

Return a type-tagged object as a stable compact summary tuple.

#
ApplicationObject::time_tag

#
ApplicationObject::type_id

#
ApplicationObject::validate

fn ApplicationObject::validate(self : ApplicationObject) -> Result[Unit, Diagnostic]

Validate an application object before placing it in an ASDU.

#
ApplicationObject::value

#
ApplicationType

pub enum ApplicationType {
MSpNa
MSpTa
MDpNa
MDpTa
MStNa
MStTa
MBoNa
MBoTa
MMeNa
MMeTa
MMeNb
MMeTb
MMeNc
MMeTc
MItNa
MItTa
MEpTa
MEpTb
MEpTc
MPsNa
MMeNd
MSpTb
MDpTb
MStTb
MBoTb
MMeTd
MMeTe
MMeTf
MItTb
MEpTd
MEpTe
MEpTf
MEiNa
CScNa
CDcNa
CRcNa
CSeNa
CSeNb
CSeNc
CBoNa
CIcNa
CCiNa
CRdNa
CCsNa
CTsNa
CRpNa
UnknownType(Int)
} derive(Eq,
Debug
)

Standard IEC 104 application type identifiers.

#
ApplicationType::has_time_tag

fn ApplicationType::has_time_tag(self : ApplicationType) -> Bool

Whether a type carries a CP24 or CP56 time tag.

#
ApplicationType::is_control

fn ApplicationType::is_control(self : ApplicationType) -> Bool

Whether an application type belongs to control direction data.

#
ApplicationType::is_monitoring

fn ApplicationType::is_monitoring(self : ApplicationType) -> Bool

Whether an application type belongs to monitor direction data.

#
ApplicationType::number

fn ApplicationType::number(self : ApplicationType) -> Int

Return an IEC 104 type identifier number.

#
ApplicationType::value_width

fn ApplicationType::value_width(self : ApplicationType) -> Int?

Preferred information-object payload width, excluding IOA and time tag.

#
ApplicationValue

pub enum ApplicationValue {
SinglePointValue(SinglePointValue)
DoublePointValue(DoublePointValue)
StepPositionValue(StepPositionValue)
BitStringValue(UInt)
NormalizedMeasurement(NormalizedValue)
ScaledMeasurement(ScaledValue)
ShortFloatMeasurement(ShortFloatValue)
BinaryCounterMeasurement(BinaryCounterValue)
SingleCommand(Bool, Int)
DoubleCommand(Int, Int)
RegulatingStepCommand(Int, Int)
NormalizedSetPoint(Int, Int)
ScaledSetPoint(Int, Int)
ShortFloatSetPoint(Float, Int)
BitStringCommand(UInt)
InterrogationCommand(Int)
CounterInterrogationCommand(Int)
ReadCommand
ClockSyncCommand(Cp56Time)
TestCommand(Int)
ResetCommand(Int)
DelayCommand(Int)
EndOfInitialization(Int)
RawValue(Bytes)
} derive(Eq,
Debug
)

Values carried by standard IEC 104 information objects.

#
AsduEnvelope

pub struct AsduEnvelope {
type_id : ApplicationType
sequence : Bool
cause : CauseOfTransmission
common_address : CommonAddress
objects : Array[ApplicationObject]
} derive(Eq,
Debug
)

A complete ASDU envelope with address-qualified application objects.

#
AsduEnvelope::cause

#
AsduEnvelope::common_address

fn AsduEnvelope::common_address(self : AsduEnvelope) -> CommonAddress

#
AsduEnvelope::count

fn AsduEnvelope::count(self : AsduEnvelope) -> Int

#
AsduEnvelope::new

fn AsduEnvelope::new(type_id : ApplicationType, sequence : Bool, cause : CauseOfTransmission, common_address : CommonAddress, objects : Array[ApplicationObject]) -> Result[AsduEnvelope, Diagnostic]

Construct an ASDU envelope and check its object/type relationship.

#
AsduEnvelope::objects

#
AsduEnvelope::sequence

fn AsduEnvelope::sequence(self : AsduEnvelope) -> Bool

#
AsduEnvelope::type_id

#
AsduHeader

pub struct AsduHeader {
type_id : TypeId
variable_count : Int
sequence : Bool
cause : Int
common_address : Int
} derive(Eq,
Debug
)

Common information object address and cause of transmission.

#
AsduHeader::cause

fn AsduHeader::cause(self : AsduHeader) -> Int

#
AsduHeader::common_address

fn AsduHeader::common_address(self : AsduHeader) -> Int

#
AsduHeader::count

fn AsduHeader::count(self : AsduHeader) -> Int

#
AsduHeader::is_sequence

fn AsduHeader::is_sequence(self : AsduHeader) -> Bool

#
AsduHeader::type_id

fn AsduHeader::type_id(self : AsduHeader) -> TypeId

#
BenchmarkCase

pub struct BenchmarkCase {
name : String
rounds : Int
payload_size : Int
target : String
} derive(Eq,
Debug
)

A repeatable benchmark case with a deterministic workload definition.

#
BenchmarkCase::name

fn BenchmarkCase::name(self : BenchmarkCase) -> String

#
BenchmarkCase::new

fn BenchmarkCase::new(name : String, rounds : Int, payload_size : Int, target : String) -> Result[BenchmarkCase, String]

#
BenchmarkCase::payload_size

fn BenchmarkCase::payload_size(self : BenchmarkCase) -> Int

#
BenchmarkCase::rounds

fn BenchmarkCase::rounds(self : BenchmarkCase) -> Int

#
BenchmarkCase::target

fn BenchmarkCase::target(self : BenchmarkCase) -> String

#
BenchmarkResult

pub struct BenchmarkResult {
case : BenchmarkCase
encoded_frames : Int
encoded_bytes : Int
checksum : UInt
elapsed_micros : Int
} derive(Eq,
Debug
)

#
BenchmarkResult::case

#
BenchmarkResult::checksum

fn BenchmarkResult::checksum(self : BenchmarkResult) -> UInt

#
BenchmarkResult::elapsed_micros

fn BenchmarkResult::elapsed_micros(self : BenchmarkResult) -> Int

#
BenchmarkResult::encoded_bytes

fn BenchmarkResult::encoded_bytes(self : BenchmarkResult) -> Int

#
BenchmarkResult::encoded_frames

fn BenchmarkResult::encoded_frames(self : BenchmarkResult) -> Int

#
BenchmarkResult::frames_per_second

fn BenchmarkResult::frames_per_second(self : BenchmarkResult) -> Float

#
BenchmarkResult::megabytes_per_second

fn BenchmarkResult::megabytes_per_second(self : BenchmarkResult) -> Float

#
BenchmarkResult::new

fn BenchmarkResult::new(case : BenchmarkCase, workload : BenchmarkWorkload, elapsed_micros : Int) -> Result[BenchmarkResult, String]

#
BenchmarkSuite

pub struct BenchmarkSuite {
cases : Array[BenchmarkCase]
} derive(
Debug
)

#
BenchmarkSuite::add

fn BenchmarkSuite::add(self : BenchmarkSuite, case : BenchmarkCase) -> Result[Unit, String]

#
BenchmarkSuite::cases

#
BenchmarkSuite::len

fn BenchmarkSuite::len(self : BenchmarkSuite) -> Int

#
BenchmarkSuite::new

#
BenchmarkSuite::run

fn BenchmarkSuite::run(self : BenchmarkSuite, elapsed_micros : Array[Int]) -> Result[Array[BenchmarkResult], String]

Run a deterministic benchmark workload; elapsed time is supplied by the host.

#
BenchmarkWorkload

pub struct BenchmarkWorkload {
rounds : Int
payload_size : Int
encoded_frames : Int
encoded_bytes : Int
checksum : UInt
} derive(Eq,
Debug
)

A repeatable workload used by local benchmark runs.

#
BenchmarkWorkload::checksum

fn BenchmarkWorkload::checksum(self : BenchmarkWorkload) -> UInt

#
BenchmarkWorkload::encoded_bytes

fn BenchmarkWorkload::encoded_bytes(self : BenchmarkWorkload) -> Int

#
BenchmarkWorkload::encoded_frames

fn BenchmarkWorkload::encoded_frames(self : BenchmarkWorkload) -> Int

#
BenchmarkWorkload::payload_size

fn BenchmarkWorkload::payload_size(self : BenchmarkWorkload) -> Int

#
BenchmarkWorkload::rounds

fn BenchmarkWorkload::rounds(self : BenchmarkWorkload) -> Int

#
BinaryCounterValue

pub struct BinaryCounterValue {
value : UInt
sequence : Int
carry : Bool
adjusted : Bool
invalid : Bool
} derive(Eq,
Debug
)

32-bit binary counter value with sequence and overflow flags.

#
BinaryCounterValue::flags

fn BinaryCounterValue::flags(self : BinaryCounterValue) -> Int

#
BinaryCounterValue::new

fn BinaryCounterValue::new(value : UInt, sequence? : Int, carry? : Bool, adjusted? : Bool, invalid? : Bool) -> Result[BinaryCounterValue, String]

#
BinaryCounterValue::sequence

fn BinaryCounterValue::sequence(self : BinaryCounterValue) -> Int

#
BinaryCounterValue::value

fn BinaryCounterValue::value(self : BinaryCounterValue) -> UInt

#
ByteCursor

pub struct ByteCursor {
data : Bytes
offset : Int
} derive(
Debug
)

A bounds-checked cursor for binary protocol decoders.

#
ByteCursor::done

fn ByteCursor::done(self : ByteCursor) -> Bool

#
ByteCursor::new

fn ByteCursor::new(data : Bytes) -> ByteCursor

#
ByteCursor::offset

fn ByteCursor::offset(self : ByteCursor) -> Int

#
ByteCursor::read_byte

fn ByteCursor::read_byte(self : ByteCursor) -> Result[Byte, Diagnostic]

#
ByteCursor::read_bytes

fn ByteCursor::read_bytes(self : ByteCursor, length : Int) -> Result[Bytes, Diagnostic]

#
ByteCursor::read_u16

fn ByteCursor::read_u16(self : ByteCursor) -> Result[Int, Diagnostic]

#
ByteCursor::read_u24

fn ByteCursor::read_u24(self : ByteCursor) -> Result[Int, Diagnostic]

#
ByteCursor::read_u32

fn ByteCursor::read_u32(self : ByteCursor) -> Result[UInt, Diagnostic]

#
ByteCursor::remaining

fn ByteCursor::remaining(self : ByteCursor) -> Int

#
ByteCursor::seek

fn ByteCursor::seek(self : ByteCursor, offset : Int) -> Result[Unit, Diagnostic]

#
ByteCursor::skip

fn ByteCursor::skip(self : ByteCursor, length : Int) -> Result[Unit, Diagnostic]

#
ByteStatistics

pub struct ByteStatistics {
length : Int
zeroes : Int
high_bit : Int
checksum : UInt
minimum : Int
maximum : Int
} derive(Eq,
Debug
)

Per-byte statistics useful for fixture and link diagnostics.

#
ByteStatistics::checksum

fn ByteStatistics::checksum(self : ByteStatistics) -> UInt

#
ByteStatistics::high_bit

fn ByteStatistics::high_bit(self : ByteStatistics) -> Int

#
ByteStatistics::length

fn ByteStatistics::length(self : ByteStatistics) -> Int

#
ByteStatistics::maximum

fn ByteStatistics::maximum(self : ByteStatistics) -> Int

#
ByteStatistics::minimum

fn ByteStatistics::minimum(self : ByteStatistics) -> Int

#
ByteStatistics::zeroes

fn ByteStatistics::zeroes(self : ByteStatistics) -> Int

#
ByteWriter

pub struct ByteWriter {
bytes : Array[Byte]
} derive(
Debug
)

A small writer used by application-specific extensions.

#
ByteWriter::len

fn ByteWriter::len(self : ByteWriter) -> Int

#
ByteWriter::new

fn ByteWriter::new() -> ByteWriter

#
ByteWriter::push

fn ByteWriter::push(self : ByteWriter, value : Byte) -> Unit

#
ByteWriter::push_bytes

fn ByteWriter::push_bytes(self : ByteWriter, value : Bytes) -> Unit

#
ByteWriter::push_u16

fn ByteWriter::push_u16(self : ByteWriter, value : Int) -> Result[Unit, String]

#
ByteWriter::push_u24

fn ByteWriter::push_u24(self : ByteWriter, value : Int) -> Result[Unit, String]

#
ByteWriter::push_u32

fn ByteWriter::push_u32(self : ByteWriter, value : UInt) -> Unit

#
ByteWriter::to_bytes

fn ByteWriter::to_bytes(self : ByteWriter) -> Bytes

#
Cause

pub enum Cause {
Periodic
Background
Spontaneous
Initialised
Request
Activation
ActivationConfirmation
ActivationTermination
Unknown(Int)
} derive(Eq,
Debug
)

Standard causes of transmission used by IEC 104 application services.

#
Cause::is_activation

fn Cause::is_activation(self : Cause) -> Bool

#
Cause::is_spontaneous

fn Cause::is_spontaneous(self : Cause) -> Bool

#
Cause::is_termination

fn Cause::is_termination(self : Cause) -> Bool

#
Cause::number

fn Cause::number(self : Cause) -> Int

#
CauseCategory

pub enum CauseCategory {
Periodic
Background
Spontaneous
Initialised
Request
Activation
ActivationConfirmation
ActivationTermination
ReturnInformationRemote
ReturnInformationLocal
UnknownCause
} derive(Eq,
Debug
)

Cause of transmission category. The numeric value is kept separate from the qualifier so applications can preserve vendor extensions.

#
CauseCategory::number

fn CauseCategory::number(self : CauseCategory) -> Int

Return the standard six-bit cause value.

#
CauseOfTransmission

pub struct CauseOfTransmission {
category : CauseCategory
number : Int
positive : Bool
test_flag : Bool
originator : Int
qualifier : Int
} derive(Eq,
Debug
)

Full cause of transmission, including the originator and qualifier bits.

#
CauseOfTransmission::flags

fn CauseOfTransmission::flags(self : CauseOfTransmission) -> Int

Return the four low flag bits in the IEC COT representation.

#
CauseOfTransmission::from_number

fn CauseOfTransmission::from_number(number : Int, positive? : Bool, test_flag? : Bool, originator? : Int, qualifier? : Int) -> Result[CauseOfTransmission, String]

Construct a cause from a raw standard number while preserving extension data.

#
CauseOfTransmission::new

fn CauseOfTransmission::new(category : CauseCategory, positive? : Bool, test_flag? : Bool, originator? : Int, qualifier? : Int) -> Result[CauseOfTransmission, String]

Construct a validated cause of transmission.

#
CauseOfTransmission::originator

fn CauseOfTransmission::originator(self : CauseOfTransmission) -> Int

Return the originator address.

#
CauseOfTransmission::qualifier

fn CauseOfTransmission::qualifier(self : CauseOfTransmission) -> Int

Return the qualifier value.

#
CauseOfTransmission::raw

Return the raw cause number.

#
ClockSyncTransaction

pub struct ClockSyncTransaction {
request : ServiceRequest
status : ServiceStatus
received : Cp56Time?
applied_at : Int?
} derive(
Debug
)

Clock synchronization service with a deterministic skew calculation.

#
ClockSyncTransaction::activate

fn ClockSyncTransaction::activate(self : ClockSyncTransaction) -> Result[Unit, String]

#
ClockSyncTransaction::apply

fn ClockSyncTransaction::apply(self : ClockSyncTransaction, timestamp : Cp56Time, applied_at : Int) -> Result[Int, String]

#
ClockSyncTransaction::new

fn ClockSyncTransaction::new(request : ServiceRequest) -> Result[ClockSyncTransaction, String]

#
ClockSyncTransaction::received

#
ClockSyncTransaction::status

#
CommandOutcome

pub struct CommandOutcome {
accepted : Bool
status : ServiceStatus
object : ApplicationObject?
message : String
} derive(
Debug
)

#
CommandOutcome::accepted

fn CommandOutcome::accepted(self : CommandOutcome) -> Bool

#
CommandOutcome::message

fn CommandOutcome::message(self : CommandOutcome) -> String

#
CommandOutcome::object

#
CommandOutcome::status

#
CommandPolicy

pub struct CommandPolicy {
allowed : Map[Int, Bool]
allow_all : Bool
max_qualifier : Int
} derive(
Debug
)

A command authorization policy for host applications.

#
CommandPolicy::allow

fn CommandPolicy::allow(self : CommandPolicy, address : InformationAddress) -> Unit

#
CommandPolicy::allow_all

fn CommandPolicy::allow_all() -> CommandPolicy

#
CommandPolicy::deny

fn CommandPolicy::deny(self : CommandPolicy, address : InformationAddress) -> Unit

#
CommandPolicy::deny_all

fn CommandPolicy::deny_all() -> CommandPolicy

#
CommandPolicy::permits

fn CommandPolicy::permits(self : CommandPolicy, object : ApplicationObject) -> Bool

#
CommandPolicy::set_max_qualifier

fn CommandPolicy::set_max_qualifier(self : CommandPolicy, value : Int) -> Result[Unit, String]

#
CommandQueue

pub struct CommandQueue {
pending : Array[ApplicationObject]
completed : Array[CommandOutcome]
limit : Int
} derive(
Debug
)

A FIFO command queue with explicit outcomes.

#
CommandQueue::completed_count

fn CommandQueue::completed_count(self : CommandQueue) -> Int

#
CommandQueue::enqueue

fn CommandQueue::enqueue(self : CommandQueue, object : ApplicationObject) -> Result[Unit, String]

#
CommandQueue::new

fn CommandQueue::new(limit? : Int) -> Result[CommandQueue, String]

#
CommandQueue::outcomes

#
CommandQueue::pending_count

fn CommandQueue::pending_count(self : CommandQueue) -> Int

#
CommandQueue::process_one

fn CommandQueue::process_one(self : CommandQueue, policy : CommandPolicy) -> CommandOutcome?

#
CommonAddress

pub struct CommonAddress {
value : Int
} derive(Eq,
Debug
)

Common address of ASDU values. Zero is reserved for an unassigned station.

#
CommonAddress::is_global

fn CommonAddress::is_global(self : CommonAddress) -> Bool

Return whether this common address is the global station address.

#
CommonAddress::new

fn CommonAddress::new(value : Int) -> Result[CommonAddress, String]

Create a two-byte common address.

#
CommonAddress::number

fn CommonAddress::number(self : CommonAddress) -> Int

Return the numeric common address.

#
ConformanceReport

pub struct ConformanceReport {
valid : Bool
type_id : ApplicationType
object_count : Int
expected_width : Int
actual_width : Int
issues : Array[String]
} derive(Eq,
Debug
)

An ASDU consistency report that can be shown in CLI diagnostics.

#
ConformanceReport::actual_width

fn ConformanceReport::actual_width(self : ConformanceReport) -> Int

#
ConformanceReport::add_issue

fn ConformanceReport::add_issue(self : ConformanceReport, message : String) -> Unit

#
ConformanceReport::expected_width

fn ConformanceReport::expected_width(self : ConformanceReport) -> Int

#
ConformanceReport::issues

fn ConformanceReport::issues(self : ConformanceReport) -> Array[String]

#
ConformanceReport::new

#
ConformanceReport::object_count

fn ConformanceReport::object_count(self : ConformanceReport) -> Int

#
ConformanceReport::type_id

#
ConformanceReport::valid

fn ConformanceReport::valid(self : ConformanceReport) -> Bool

#
ConnectionParameters

pub struct ConnectionParameters {
k : Int
w : Int
t0_seconds : Int
t1_seconds : Int
t2_seconds : Int
t3_seconds : Int
} derive(Eq,
Debug
)

IEC 104 link-layer timing and window parameters.

#
ConnectionParameters::default

Default parameters from the commonly deployed IEC 104 profile.

#
ConnectionParameters::k

#
ConnectionParameters::new

fn ConnectionParameters::new(k : Int, w : Int, t0_seconds : Int, t1_seconds : Int, t2_seconds : Int, t3_seconds : Int) -> Result[ConnectionParameters, String]

Validate and construct link-layer parameters.

#
ConnectionParameters::t0

#
ConnectionParameters::t1

#
ConnectionParameters::t2

#
ConnectionParameters::t3

#
ConnectionParameters::w

#
CounterInterrogationRequest

pub struct CounterInterrogationRequest {
common_address : CommonAddress
qualifier : Int
created_at : Int
} derive(Eq,
Debug
)

Counter-interrogation request used for historical counter snapshots.

#
CounterInterrogationRequest::common_address

#
CounterInterrogationRequest::created_at

#
CounterInterrogationRequest::new

fn CounterInterrogationRequest::new(common_address : CommonAddress, qualifier : Int, created_at : Int) -> Result[CounterInterrogationRequest, String]

#
CounterInterrogationRequest::qualifier

#
Cp24Time

pub struct Cp24Time {
millisecond : Int
minute : Int
} derive(Eq,
Debug
)

Three-byte CP24Time2a value used by short time-tagged ASDUs.

#
Cp24Time::from_bytes

fn Cp24Time::from_bytes(data : Bytes, offset? : Int) -> Result[Cp24Time, String]

#
Cp24Time::millisecond

fn Cp24Time::millisecond(self : Cp24Time) -> Int

#
Cp24Time::minute

fn Cp24Time::minute(self : Cp24Time) -> Int

#
Cp24Time::new

fn Cp24Time::new(millisecond : Int, minute : Int) -> Result[Cp24Time, String]

#
Cp24Time::remainder_millisecond

fn Cp24Time::remainder_millisecond(self : Cp24Time) -> Int

#
Cp24Time::second

fn Cp24Time::second(self : Cp24Time) -> Int

#
Cp24Time::to_array

fn Cp24Time::to_array(self : Cp24Time) -> Array[Byte]

#
Cp56Time

pub struct Cp56Time {
year : Int
month : Int
day : Int
weekday : Int
hour : Int
minute : Int
millisecond : Int
} derive(Eq,
Debug
)

Seven-byte CP56Time2a timestamp.

#
Cp56Time::calendar_year

fn Cp56Time::calendar_year(self : Cp56Time, century? : Int) -> Int

Return the four-digit calendar year represented by the protocol year.

#
Cp56Time::day

fn Cp56Time::day(self : Cp56Time) -> Int

#
Cp56Time::from_bytes

fn Cp56Time::from_bytes(data : Bytes, offset? : Int) -> Result[Cp56Time, String]

#
Cp56Time::hour

fn Cp56Time::hour(self : Cp56Time) -> Int

#
Cp56Time::millisecond

fn Cp56Time::millisecond(self : Cp56Time) -> Int

#
Cp56Time::minute

fn Cp56Time::minute(self : Cp56Time) -> Int

#
Cp56Time::month

fn Cp56Time::month(self : Cp56Time) -> Int

#
Cp56Time::new

fn Cp56Time::new(year : Int, month : Int, day : Int, hour : Int, minute : Int, millisecond : Int, weekday? : Int) -> Result[Cp56Time, String]

Construct a CP56 timestamp. The year is the two-digit protocol year.

#
Cp56Time::ordering_key

fn Cp56Time::ordering_key(self : Cp56Time) -> Int

A deterministic date-time ordering key.

#
Cp56Time::remainder_millisecond

fn Cp56Time::remainder_millisecond(self : Cp56Time) -> Int

#
Cp56Time::second

fn Cp56Time::second(self : Cp56Time) -> Int

#
Cp56Time::to_array

fn Cp56Time::to_array(self : Cp56Time) -> Array[Byte]

#
Cp56Time::weekday

fn Cp56Time::weekday(self : Cp56Time) -> Int

#
Cp56Time::year

fn Cp56Time::year(self : Cp56Time) -> Int

#
Diagnostic

pub struct Diagnostic {
kind : DiagnosticKind
message : String
offset : Int?
} derive(Eq,
Debug
)

Structured diagnostic returned by validation and service layers.

#
Diagnostic::kind

#
Diagnostic::message

fn Diagnostic::message(self : Diagnostic) -> String

#
Diagnostic::new

fn Diagnostic::new(kind : DiagnosticKind, message : String, offset? : Int) -> Diagnostic

#
Diagnostic::offset

fn Diagnostic::offset(self : Diagnostic) -> Int?

#
Diagnostic::to_line

fn Diagnostic::to_line(self : Diagnostic) -> String

Produce a compact human-readable diagnostic line for CLI and logs.

#
DiagnosticKind

pub enum DiagnosticKind {
MalformedFrame
InvalidSequence
InvalidAddress
InvalidType
InvalidQualifier
UnsupportedFeature
WindowExhausted
TimerExpired
StateViolation
TransportFailure
} derive(Eq,
Debug
)

A stable classification for protocol diagnostics.

#
DoublePointValue

pub struct DoublePointValue {
state : Int
quality : StatusQuality
} derive(Eq,
Debug
)

Double point information value. IEC 104 reserves state value 0 and 3.

#
DoublePointValue::from_byte

fn DoublePointValue::from_byte(value : Int) -> Result[DoublePointValue, String]

#
DoublePointValue::new

fn DoublePointValue::new(state : Int, quality? : StatusQuality) -> Result[DoublePointValue, String]

#
DoublePointValue::quality

#
DoublePointValue::state

fn DoublePointValue::state(self : DoublePointValue) -> Int

#
DoublePointValue::to_byte

fn DoublePointValue::to_byte(self : DoublePointValue) -> Int

#
EventLog

pub struct EventLog {
events : Array[ProtocolEvent]
}

In-memory event log for examples, tests and host applications.

#
EventLog::all

fn EventLog::all(self : EventLog) -> Array[ProtocolEvent]

#
EventLog::len

fn EventLog::len(self : EventLog) -> Int

#
EventLog::new

fn EventLog::new() -> EventLog

#
EventLog::push

fn EventLog::push(self : EventLog, event : ProtocolEvent) -> Unit

#
Frame

pub struct Frame {
kind : FrameKind
send_sequence : Int
receive_sequence : Int
control : UInt16
payload : Bytes
} derive(Eq,
Debug
)

A decoded APCI frame. payload contains the ASDU for I frames.

#
Frame::control

fn Frame::control(self : Frame) -> UInt16

#
Frame::is_information

fn Frame::is_information(self : Frame) -> Bool

#
Frame::is_supervisory

fn Frame::is_supervisory(self : Frame) -> Bool

#
Frame::is_unnumbered

fn Frame::is_unnumbered(self : Frame) -> Bool

#
Frame::kind

fn Frame::kind(self : Frame) -> FrameKind

Stable accessors for frame values used by host integrations.

#
Frame::payload

fn Frame::payload(self : Frame) -> Bytes

#
Frame::receive_sequence

fn Frame::receive_sequence(self : Frame) -> Int

#
Frame::send_sequence

fn Frame::send_sequence(self : Frame) -> Int

#
FrameKind

pub enum FrameKind {
Information
Supervisory
Unnumbered
} derive(Eq,
Debug
)

IEC 60870-5-104 frame kinds.

#
FrameMetrics

pub struct FrameMetrics {
frames_encoded : Int
frames_decoded : Int
information_frames : Int
supervisory_frames : Int
unnumbered_frames : Int
bytes_encoded : Int
bytes_decoded : Int
malformed_frames : Int
sequence_errors : Int
service_failures : Int
} derive(Eq,
Debug
)

Counters for protocol throughput and error monitoring.

#
FrameMetrics::error_count

fn FrameMetrics::error_count(self : FrameMetrics) -> Int

#
FrameMetrics::new

#
FrameMetrics::record_decoded

fn FrameMetrics::record_decoded(self : FrameMetrics, frame : Frame) -> Unit

#
FrameMetrics::record_encoded

fn FrameMetrics::record_encoded(self : FrameMetrics, frame : Frame) -> Unit

#
FrameMetrics::record_malformed

fn FrameMetrics::record_malformed(self : FrameMetrics) -> Unit

#
FrameMetrics::record_sequence_error

fn FrameMetrics::record_sequence_error(self : FrameMetrics) -> Unit

#
FrameMetrics::record_service_failure

fn FrameMetrics::record_service_failure(self : FrameMetrics) -> Unit

#
FrameMetrics::snapshot

fn FrameMetrics::snapshot(self : FrameMetrics) -> MetricsSnapshot

#
FrameMetrics::success_rate

fn FrameMetrics::success_rate(self : FrameMetrics) -> Float

#
FrameMetrics::total_bytes

fn FrameMetrics::total_bytes(self : FrameMetrics) -> Int

#
FrameMetrics::total_frames

fn FrameMetrics::total_frames(self : FrameMetrics) -> Int

#
GatewayAdmissionPolicy

pub struct GatewayAdmissionPolicy {
max_objects : Int
allow_monitoring : Bool
allow_control : Bool
allowed_types : Array[ApplicationType]
denied_types : Array[ApplicationType]
} derive(Eq,
Debug
)

Admission policy applied before a gateway accepts an ASDU.

#
GatewayAdmissionPolicy::allow_type

fn GatewayAdmissionPolicy::allow_type(self : GatewayAdmissionPolicy, type_id : ApplicationType) -> Unit

#
GatewayAdmissionPolicy::default

#
GatewayAdmissionPolicy::deny_type

fn GatewayAdmissionPolicy::deny_type(self : GatewayAdmissionPolicy, type_id : ApplicationType) -> Unit

#
GatewayAdmissionPolicy::evaluate

fn GatewayAdmissionPolicy::evaluate(self : GatewayAdmissionPolicy, envelope : AsduEnvelope) -> Result[Unit, String]

#
GatewayAdmissionPolicy::max_objects

fn GatewayAdmissionPolicy::max_objects(self : GatewayAdmissionPolicy) -> Int

#
GatewayAdmissionPolicy::new

fn GatewayAdmissionPolicy::new(max_objects : Int, allow_monitoring? : Bool, allow_control? : Bool) -> Result[GatewayAdmissionPolicy, String]

#
GatewayCounters

pub struct GatewayCounters {
accepted : Int
forwarded : Int
dropped : Int
rejected : Int
stored : Int
} derive(Eq,
Debug
)

Counters exposed by the gateway for operational dashboards.

#
GatewayCounters::accepted

fn GatewayCounters::accepted(self : GatewayCounters) -> Int

#
GatewayCounters::dropped

fn GatewayCounters::dropped(self : GatewayCounters) -> Int

#
GatewayCounters::empty

#
GatewayCounters::forwarded

fn GatewayCounters::forwarded(self : GatewayCounters) -> Int

#
GatewayCounters::rejected

fn GatewayCounters::rejected(self : GatewayCounters) -> Int

#
GatewayCounters::stored

fn GatewayCounters::stored(self : GatewayCounters) -> Int

#
GatewayCounters::total

fn GatewayCounters::total(self : GatewayCounters) -> Int

#
GatewayDispatch

pub enum GatewayDispatch {
Forwarded(GatewayEnvelope, GatewayRoute)
Dropped(GatewayEnvelope, String)
} derive(
Debug
)

#
GatewayDispatch::envelope

#
GatewayDispatch::is_forwarded

fn GatewayDispatch::is_forwarded(self : GatewayDispatch) -> Bool

#
GatewayDispatch::message

fn GatewayDispatch::message(self : GatewayDispatch) -> String

#
GatewayEnvelope

pub struct GatewayEnvelope {
ingress : Int
egress : Int
common_address : CommonAddress
asdu : AsduEnvelope
received_at : Int
trace_id : String
} derive(
Debug
)

An ASDU together with gateway ingress metadata.

#
GatewayEnvelope::asdu

#
GatewayEnvelope::common_address

fn GatewayEnvelope::common_address(self : GatewayEnvelope) -> CommonAddress

#
GatewayEnvelope::egress

fn GatewayEnvelope::egress(self : GatewayEnvelope) -> Int

#
GatewayEnvelope::ingress

fn GatewayEnvelope::ingress(self : GatewayEnvelope) -> Int

#
GatewayEnvelope::new

fn GatewayEnvelope::new(ingress : Int, egress : Int, asdu : AsduEnvelope, received_at : Int, trace_id? : String) -> Result[GatewayEnvelope, String]

#
GatewayEnvelope::object_count

fn GatewayEnvelope::object_count(self : GatewayEnvelope) -> Int

#
GatewayEnvelope::received_at

fn GatewayEnvelope::received_at(self : GatewayEnvelope) -> Int

#
GatewayEnvelope::trace_id

fn GatewayEnvelope::trace_id(self : GatewayEnvelope) -> String

#
GatewayMode

pub enum GatewayMode {
Stopped
Starting
Running
Draining
Faulted(String)
} derive(Eq,
Debug
)

Lifecycle of an in-memory IEC 104 gateway runtime.

#
GatewayMode::is_accepting

fn GatewayMode::is_accepting(self : GatewayMode) -> Bool

#
GatewayMode::is_quiescent

fn GatewayMode::is_quiescent(self : GatewayMode) -> Bool

#
GatewayMode::name

fn GatewayMode::name(self : GatewayMode) -> String

#
GatewayRoute

pub struct GatewayRoute {
id : Int
source : Int
destination : Int
common_address : CommonAddress?
type_ids : Array[ApplicationType]
enabled : Bool
priority : Int
} derive(Eq,
Debug
)

A route between two logical gateway endpoints.

#
GatewayRoute::common_address

fn GatewayRoute::common_address(self : GatewayRoute) -> CommonAddress?

#
GatewayRoute::describe

fn GatewayRoute::describe(self : GatewayRoute) -> String

#
GatewayRoute::destination

fn GatewayRoute::destination(self : GatewayRoute) -> Int

#
GatewayRoute::enabled

fn GatewayRoute::enabled(self : GatewayRoute) -> Bool

#
GatewayRoute::id

fn GatewayRoute::id(self : GatewayRoute) -> Int

#
GatewayRoute::new

fn GatewayRoute::new(id : Int, source : Int, destination : Int, common_address? : CommonAddress, type_ids? : Array[ApplicationType], priority? : Int) -> Result[GatewayRoute, String]

#
GatewayRoute::priority

fn GatewayRoute::priority(self : GatewayRoute) -> Int

#
GatewayRoute::set_enabled

fn GatewayRoute::set_enabled(self : GatewayRoute, enabled : Bool) -> Unit

#
GatewayRoute::source

fn GatewayRoute::source(self : GatewayRoute) -> Int

#
GatewayRoute::type_ids

#
GatewayRouteTable

pub struct GatewayRouteTable {
routes : Array[GatewayRoute]
capacity : Int
} derive(
Debug
)

Deterministic route table. Higher priority wins; ties use the lower route id.

#
GatewayRouteTable::add

fn GatewayRouteTable::add(self : GatewayRouteTable, route : GatewayRoute) -> Result[Unit, String]

#
GatewayRouteTable::capacity

fn GatewayRouteTable::capacity(self : GatewayRouteTable) -> Int

#
GatewayRouteTable::len

fn GatewayRouteTable::len(self : GatewayRouteTable) -> Int

#
GatewayRouteTable::new

fn GatewayRouteTable::new(capacity? : Int) -> Result[GatewayRouteTable, String]

#
GatewayRouteTable::remove

fn GatewayRouteTable::remove(self : GatewayRouteTable, route_id : Int) -> Bool

#
GatewayRouteTable::routes

#
GatewayRouteTable::select

fn GatewayRouteTable::select(self : GatewayRouteTable, source : Int, common_address : CommonAddress, type_id : ApplicationType) -> GatewayRoute?

#
GatewayRouteTable::set_enabled

fn GatewayRouteTable::set_enabled(self : GatewayRouteTable, route_id : Int, enabled : Bool) -> Bool

#
GatewayRuntime

pub struct GatewayRuntime {
mode : GatewayMode
routes : GatewayRouteTable
policy : GatewayAdmissionPolicy
inbound : Array[GatewayEnvelope]
outbound : Array[GatewayEnvelope]
dead_letters : Array[GatewayEnvelope]
stores : Array[GatewayStoreBinding]
counters : GatewayCounters
max_queue : Int
last_error : String?
} derive(
Debug
)

Deterministic in-memory routing runtime. Network adapters can feed its queue and poll the outbound queue without coupling protocol logic to a socket API.

#
GatewayRuntime::add_route

fn GatewayRuntime::add_route(self : GatewayRuntime, route : GatewayRoute) -> Result[Unit, String]

#
GatewayRuntime::attach_store

fn GatewayRuntime::attach_store(self : GatewayRuntime, binding : GatewayStoreBinding) -> Result[Unit, String]

#
GatewayRuntime::begin_drain

fn GatewayRuntime::begin_drain(self : GatewayRuntime) -> Result[Unit, String]

#
GatewayRuntime::counters

#
GatewayRuntime::dead_letter_len

fn GatewayRuntime::dead_letter_len(self : GatewayRuntime) -> Int

#
GatewayRuntime::diagnostics

fn GatewayRuntime::diagnostics(self : GatewayRuntime) -> String

Return a stable, line-oriented diagnostics report for logs and health probes.

#
GatewayRuntime::drain

fn GatewayRuntime::drain(self : GatewayRuntime, max_dispatches? : Int) -> Array[GatewayDispatch]

#
GatewayRuntime::enqueue

fn GatewayRuntime::enqueue(self : GatewayRuntime, envelope : GatewayEnvelope) -> Result[Unit, String]

#
GatewayRuntime::fail

fn GatewayRuntime::fail(self : GatewayRuntime, message : String) -> Unit

#
GatewayRuntime::ingest_to_store

fn GatewayRuntime::ingest_to_store(self : GatewayRuntime, envelope : GatewayEnvelope) -> Result[Int, String]

#
GatewayRuntime::last_error

fn GatewayRuntime::last_error(self : GatewayRuntime) -> String?

#
GatewayRuntime::mode

#
GatewayRuntime::new

fn GatewayRuntime::new(max_queue : Int, route_capacity? : Int, policy? : GatewayAdmissionPolicy) -> Result[GatewayRuntime, String]

#
GatewayRuntime::outbound_len

fn GatewayRuntime::outbound_len(self : GatewayRuntime) -> Int

#
GatewayRuntime::poll_outbound

fn GatewayRuntime::poll_outbound(self : GatewayRuntime) -> GatewayEnvelope?

#
GatewayRuntime::queue_len

fn GatewayRuntime::queue_len(self : GatewayRuntime) -> Int

#
GatewayRuntime::remove_route

fn GatewayRuntime::remove_route(self : GatewayRuntime, route_id : Int) -> Bool

#
GatewayRuntime::routes

#
GatewayRuntime::set_policy

fn GatewayRuntime::set_policy(self : GatewayRuntime, policy : GatewayAdmissionPolicy) -> Unit

#
GatewayRuntime::snapshot

#
GatewayRuntime::start

fn GatewayRuntime::start(self : GatewayRuntime) -> Result[Unit, String]

#
GatewayRuntime::stop

fn GatewayRuntime::stop(self : GatewayRuntime) -> Result[Unit, String]

#
GatewayRuntime::store_count

fn GatewayRuntime::store_count(self : GatewayRuntime) -> Int

#
GatewayRuntime::take_dead_letter

fn GatewayRuntime::take_dead_letter(self : GatewayRuntime) -> GatewayEnvelope?

#
GatewaySnapshot

pub struct GatewaySnapshot {
mode : GatewayMode
routes : Int
queue : Int
outbound : Int
dead_letters : Int
counters : GatewayCounters
last_error : String?
} derive(Eq,
Debug
)

Snapshot suitable for a health endpoint or a periodic metrics export.

#
GatewaySnapshot::counters

#
GatewaySnapshot::dead_letters

fn GatewaySnapshot::dead_letters(self : GatewaySnapshot) -> Int

#
GatewaySnapshot::last_error

fn GatewaySnapshot::last_error(self : GatewaySnapshot) -> String?

#
GatewaySnapshot::mode

#
GatewaySnapshot::outbound

fn GatewaySnapshot::outbound(self : GatewaySnapshot) -> Int

#
GatewaySnapshot::queue

fn GatewaySnapshot::queue(self : GatewaySnapshot) -> Int

#
GatewaySnapshot::routes

fn GatewaySnapshot::routes(self : GatewaySnapshot) -> Int

#
GatewayStoreBinding

pub struct GatewayStoreBinding {
common_address : CommonAddress
store : PointStore
accepted : Int
rejected : Int
} derive(
Debug
)

A point store attached to one common address in the gateway.

#
GatewayStoreBinding::accepted

fn GatewayStoreBinding::accepted(self : GatewayStoreBinding) -> Int

#
GatewayStoreBinding::common_address

#
GatewayStoreBinding::ingest

fn GatewayStoreBinding::ingest(self : GatewayStoreBinding, envelope : GatewayEnvelope) -> Result[Int, String]

#
GatewayStoreBinding::new

fn GatewayStoreBinding::new(common_address : CommonAddress, history_limit? : Int) -> Result[GatewayStoreBinding, String]

#
GatewayStoreBinding::rejected

fn GatewayStoreBinding::rejected(self : GatewayStoreBinding) -> Int

#
GatewayStoreBinding::store

#
HealthReport

pub struct HealthReport {
state : HealthState
score : Int
checks : Array[String]
warnings : Array[String]
} derive(Eq,
Debug
)

#
HealthReport::checks

fn HealthReport::checks(self : HealthReport) -> Array[String]

#
HealthReport::new

fn HealthReport::new(state : HealthState, score : Int, checks : Array[String], warnings : Array[String]) -> HealthReport

#
HealthReport::score

fn HealthReport::score(self : HealthReport) -> Int

#
HealthReport::state

#
HealthReport::warnings

fn HealthReport::warnings(self : HealthReport) -> Array[String]

#
HealthState

pub enum HealthState {
Healthy
Degraded
Unready
} derive(Eq,
Debug
)

Health state suitable for gateway readiness endpoints.

#
InformationAddress

pub struct InformationAddress {
value : Int
} derive(Eq,
Debug
)

The three-byte information object address used by IEC 104.

#
InformationAddress::from_octets

fn InformationAddress::from_octets(low : Int, middle : Int, high : Int) -> Result[InformationAddress, String]

Construct an information object address from its three octets.

#
InformationAddress::high

fn InformationAddress::high(self : InformationAddress) -> Int

Return the most significant address octet.

#
InformationAddress::is_broadcast

fn InformationAddress::is_broadcast(self : InformationAddress) -> Bool

Return whether the address is the protocol's broadcast address.

#
InformationAddress::low

fn InformationAddress::low(self : InformationAddress) -> Int

Return the least significant address octet.

#
InformationAddress::middle

fn InformationAddress::middle(self : InformationAddress) -> Int

Return the middle address octet.

#
InformationAddress::new

fn InformationAddress::new(value : Int) -> Result[InformationAddress, String]

Create an information object address in the inclusive 0..0xffffff range.

#
InformationAddress::number

fn InformationAddress::number(self : InformationAddress) -> Int

Return the numeric address.

#
InformationObject

pub enum InformationObject {
Single(Bool, Int)
Double(Int, Int)
Normalized(Int, Int)
ShortFloat(Float, Int)
BitString(UInt, Int)
} derive(Eq,
Debug
)

IEC information object values supported by the first stable API.

#
Interrogation

pub struct Interrogation {
request : InterrogationRequest
phase : InterrogationPhase
objects_sent : Int
}

Small deterministic transaction tracker; data transport remains caller-owned.

#
Interrogation::activate

fn Interrogation::activate(self : Interrogation) -> Int

#
Interrogation::finish

fn Interrogation::finish(self : Interrogation) -> Int

#
Interrogation::new

#
Interrogation::record

fn Interrogation::record(self : Interrogation, count : Int) -> Result[Unit, String]

#
InterrogationPhase

pub enum InterrogationPhase {
Idle
Activated
Sending
Terminated
} derive(Eq,
Debug
)

Phases emitted by an interrogation transaction.

#
InterrogationPlan

pub struct InterrogationPlan {
request : InterrogationRequest
objects : Array[ApplicationObject]
batch_size : Int
cursor : Int
status : ServiceStatus
} derive(
Debug
)

A total interrogation plan which can be emitted in deterministic batches.

#
InterrogationPlan::activate

fn InterrogationPlan::activate(self : InterrogationPlan) -> Result[Int, String]

#
InterrogationPlan::new

fn InterrogationPlan::new(request : InterrogationRequest, objects : Array[ApplicationObject], batch_size? : Int) -> Result[InterrogationPlan, String]

#
InterrogationPlan::next_batch

fn InterrogationPlan::next_batch(self : InterrogationPlan) -> Result[Array[ApplicationObject], String]

#
InterrogationPlan::remaining

fn InterrogationPlan::remaining(self : InterrogationPlan) -> Int

#
InterrogationPlan::request

#
InterrogationPlan::status

#
InterrogationPlan::terminate

fn InterrogationPlan::terminate(self : InterrogationPlan) -> Result[Int, String]

#
InterrogationRequest

pub struct InterrogationRequest {
common_address : Int
qualifier : Int
} derive(Eq,
Debug
)

A total interrogation request, suitable for a master command queue.

#
InterrogationRequest::new

fn InterrogationRequest::new(common_address : Int, qualifier? : Int) -> InterrogationRequest

#
LengthHistogram

pub struct LengthHistogram {
buckets : Map[Int, Int]
samples : Int
} derive(
Debug
)

A compact histogram for APDU length distribution.

#
LengthHistogram::all

fn LengthHistogram::all(self : LengthHistogram) -> Array[(Int, Int)]

#
LengthHistogram::bucket

fn LengthHistogram::bucket(self : LengthHistogram, maximum : Int) -> Int

#
LengthHistogram::new

#
LengthHistogram::observe

fn LengthHistogram::observe(self : LengthHistogram, length : Int) -> Unit

#
LengthHistogram::samples

fn LengthHistogram::samples(self : LengthHistogram) -> Int

#
LinkState

pub enum LinkState {
Disconnected
Connecting
Started
Stopped
TestPending
} derive(Eq,
Debug
)

Link-layer state used by a master or outstation session.

#
LinkState::is_connected

fn LinkState::is_connected(self : LinkState) -> Bool

#
LinkState::is_terminal

fn LinkState::is_terminal(self : LinkState) -> Bool

#
MeasurementState

pub enum MeasurementState {
Good
Blocked
Substituted
NotTopical
Invalid
} derive(Eq,
Debug
)

Quality-preserving measurement classification used by point stores.

#
MetricsSnapshot

pub struct MetricsSnapshot {
frames : Int
bytes : Int
errors : Int
success_rate : Float
} derive(Eq,
Debug
)

Snapshot an evolving metrics object for export or health endpoints.

#
MetricsSnapshot::bytes

fn MetricsSnapshot::bytes(self : MetricsSnapshot) -> Int

#
MetricsSnapshot::errors

fn MetricsSnapshot::errors(self : MetricsSnapshot) -> Int

#
MetricsSnapshot::frames

fn MetricsSnapshot::frames(self : MetricsSnapshot) -> Int

#
MetricsSnapshot::success_rate

fn MetricsSnapshot::success_rate(self : MetricsSnapshot) -> Float

#
NegotiationDecision

pub enum NegotiationDecision {
CompatibleProfile
IncompatibleProfile(Array[String])
} derive(
Debug
)

#
NormalizedValue

pub struct NormalizedValue {
value : Int
quality : QualityDescriptor
} derive(Eq,
Debug
)

Normalized signed 16-bit measurement.

#
NormalizedValue::new

fn NormalizedValue::new(value : Int, quality? : QualityDescriptor) -> Result[NormalizedValue, String]

#
NormalizedValue::quality

#
NormalizedValue::raw_unsigned

fn NormalizedValue::raw_unsigned(self : NormalizedValue) -> Int

#
NormalizedValue::to_array

fn NormalizedValue::to_array(self : NormalizedValue) -> Array[Byte]

#
NormalizedValue::value

fn NormalizedValue::value(self : NormalizedValue) -> Int

#
Outstation

pub struct Outstation {
common_address : Int
single_points : Map[Int, Bool]
normalized_values : Map[Int, Int]
}

A compact in-memory outstation used in tests, demos and protocol simulations.

#
Outstation::new

fn Outstation::new(common_address : Int) -> Outstation

#
Outstation::normalized

fn Outstation::normalized(self : Outstation, ioa : Int) -> Int?

#
Outstation::set_normalized

fn Outstation::set_normalized(self : Outstation, ioa : Int, value : Int) -> Unit

#
Outstation::set_single

fn Outstation::set_single(self : Outstation, ioa : Int, value : Bool) -> Unit

#
Outstation::single

fn Outstation::single(self : Outstation, ioa : Int) -> Bool?

#
Outstation::snapshot_normalized

fn Outstation::snapshot_normalized(self : Outstation) -> Array[PointSnapshot]

#
Outstation::snapshot_single

fn Outstation::snapshot_single(self : Outstation) -> Array[PointSnapshot]

#
PointChange

pub struct PointChange {
kind : PointChangeKind
address : InformationAddress
revision : Int
timestamp : Int
message : String
} derive(Eq,
Debug
)

#
PointChange::address

#
PointChange::kind

#
PointChange::message

fn PointChange::message(self : PointChange) -> String

#
PointChange::new

fn PointChange::new(kind : PointChangeKind, address : InformationAddress, revision : Int, timestamp : Int, message : String) -> PointChange

#
PointChange::revision

fn PointChange::revision(self : PointChange) -> Int

#
PointChange::timestamp

fn PointChange::timestamp(self : PointChange) -> Int

#
PointChangeKind

pub enum PointChangeKind {
Inserted
Updated
Removed
Rejected
} derive(Eq,
Debug
)

A change recorded by the point store.

#
PointDirection

pub enum PointDirection {
MonitorDirection
ControlDirection
} derive(Eq,
Debug
)

Point direction used by a station data model.

#
PointFilter

pub struct PointFilter {
direction : PointDirection?
type_id : ApplicationType?
first_address : InformationAddress?
last_address : InformationAddress?
only_valid : Bool
source : String?
} derive(Eq,
Debug
)

Query constraints for a point-store snapshot.

#
PointFilter::all

#
PointFilter::control

fn PointFilter::control() -> PointFilter

#
PointFilter::from_source

fn PointFilter::from_source(self : PointFilter, source : String) -> PointFilter

#
PointFilter::monitoring

fn PointFilter::monitoring() -> PointFilter

#
PointFilter::valid_only

fn PointFilter::valid_only(self : PointFilter) -> PointFilter

#
PointFilter::with_range

fn PointFilter::with_range(self : PointFilter, first : InformationAddress, last : InformationAddress) -> PointFilter

#
PointFilter::with_type

fn PointFilter::with_type(self : PointFilter, type_id : ApplicationType) -> PointFilter

#
PointRecord

pub struct PointRecord {
address : InformationAddress
type_id : ApplicationType
value : ApplicationValue
time_tag : TimeTag?
revision : Int
updated_at : Int
source : String
} derive(Eq,
Debug
)

A stored value with its protocol identity and update metadata.

#
PointRecord::address

#
PointRecord::direction

fn PointRecord::direction(self : PointRecord) -> PointDirection

#
PointRecord::is_valid

fn PointRecord::is_valid(self : PointRecord) -> Bool

#
PointRecord::new

fn PointRecord::new(object : ApplicationObject, updated_at : Int, revision? : Int, source? : String) -> PointRecord

#
PointRecord::revision

fn PointRecord::revision(self : PointRecord) -> Int

#
PointRecord::source

fn PointRecord::source(self : PointRecord) -> String

#
PointRecord::time_tag

fn PointRecord::time_tag(self : PointRecord) -> TimeTag?

#
PointRecord::type_id

fn PointRecord::type_id(self : PointRecord) -> ApplicationType

#
PointRecord::updated_at

fn PointRecord::updated_at(self : PointRecord) -> Int

#
PointRecord::value

#
PointSnapshot

pub struct PointSnapshot {
ioa : Int
value : InformationObject
}

An immutable snapshot of values that can be used to build a response ASDU.

#
PointStore

pub struct PointStore {
common_address : CommonAddress
points : Map[Int, PointRecord]
history : Array[PointChange]
history_limit : Int
} derive(
Debug
)

Deterministic point store for outstations, simulators and gateways.

#
PointStore::addresses

fn PointStore::addresses(self : PointStore) -> Array[InformationAddress]

#
PointStore::common_address

fn PointStore::common_address(self : PointStore) -> CommonAddress

#
PointStore::get

fn PointStore::get(self : PointStore, address : InformationAddress) -> PointRecord?

#
PointStore::history

fn PointStore::history(self : PointStore) -> Array[PointChange]

#
PointStore::history_len

fn PointStore::history_len(self : PointStore) -> Int

#
PointStore::len

fn PointStore::len(self : PointStore) -> Int

#
PointStore::new

fn PointStore::new(common_address : CommonAddress, history_limit? : Int) -> Result[PointStore, String]

#
PointStore::objects

fn PointStore::objects(self : PointStore, filter : PointFilter) -> Array[ApplicationObject]

Convert a store snapshot into application objects for interrogation.

#
PointStore::query

fn PointStore::query(self : PointStore, filter : PointFilter) -> Array[PointRecord]

#
PointStore::remove

fn PointStore::remove(self : PointStore, address : InformationAddress, timestamp : Int) -> Result[PointChange, Diagnostic]

#
PointStore::statistics

fn PointStore::statistics(self : PointStore) -> StoreStatistics

#
PointStore::upsert

fn PointStore::upsert(self : PointStore, object : ApplicationObject, timestamp : Int, source? : String) -> Result[PointChange, Diagnostic]

#
ProfileRegistry

pub struct ProfileRegistry {
profiles : Map[String, StationProfile]
} derive(
Debug
)

#
ProfileRegistry::get

fn ProfileRegistry::get(self : ProfileRegistry, name : String) -> StationProfile?

#
ProfileRegistry::len

fn ProfileRegistry::len(self : ProfileRegistry) -> Int

#
ProfileRegistry::names

fn ProfileRegistry::names(self : ProfileRegistry) -> Array[String]

#
ProfileRegistry::new

#
ProfileRegistry::put

fn ProfileRegistry::put(self : ProfileRegistry, profile : StationProfile) -> Result[Unit, String]

#
ProfileRegistry::remove

fn ProfileRegistry::remove(self : ProfileRegistry, name : String) -> Bool

#
ProfileRegistry::replace

fn ProfileRegistry::replace(self : ProfileRegistry, profile : StationProfile) -> Unit

#
ProtocolEvent

pub enum ProtocolEvent {
Connected
Started
Stopped
Sent(Int)
Received(Int)
Acknowledged(Int)
Fault(String)
} derive(Eq,
Debug
)

A protocol event useful for deterministic simulation and diagnostics.

#
ProtocolTimers

pub struct ProtocolTimers {
t0 : TimerState
t1 : TimerState
t2 : TimerState
t3 : TimerState
} derive(Eq,
Debug
)

#
ProtocolTimers::expired

fn ProtocolTimers::expired(self : ProtocolTimers, now : Int) -> Array[String]

#
ProtocolTimers::new

#
ProtocolTimers::start_t0

fn ProtocolTimers::start_t0(self : ProtocolTimers, deadline : Int) -> Unit

#
ProtocolTimers::start_t1

fn ProtocolTimers::start_t1(self : ProtocolTimers, deadline : Int) -> Unit

#
ProtocolTimers::start_t2

fn ProtocolTimers::start_t2(self : ProtocolTimers, deadline : Int) -> Unit

#
ProtocolTimers::start_t3

fn ProtocolTimers::start_t3(self : ProtocolTimers, deadline : Int) -> Unit

#
ProtocolTimers::stop_t0

fn ProtocolTimers::stop_t0(self : ProtocolTimers) -> Unit

#
ProtocolTimers::stop_t1

fn ProtocolTimers::stop_t1(self : ProtocolTimers) -> Unit

#
ProtocolTimers::stop_t2

fn ProtocolTimers::stop_t2(self : ProtocolTimers) -> Unit

#
ProtocolTimers::stop_t3

fn ProtocolTimers::stop_t3(self : ProtocolTimers) -> Unit

#
QualityDescriptor

pub struct QualityDescriptor {
overflow : Bool
blocked : Bool
substituted : Bool
not_topical : Bool
invalid : Bool
} derive(Eq,
Debug
)

Quality descriptor shared by status and measurement objects.

#
QualityDescriptor::clear

#
QualityDescriptor::flags

fn QualityDescriptor::flags(self : QualityDescriptor) -> Array[String]

#
QualityDescriptor::from_byte

fn QualityDescriptor::from_byte(value : Int) -> Result[QualityDescriptor, String]

Decode the low byte of a QDS value.

#
QualityDescriptor::has_status_change

fn QualityDescriptor::has_status_change(self : QualityDescriptor) -> Bool

#
QualityDescriptor::is_usable

fn QualityDescriptor::is_usable(self : QualityDescriptor) -> Bool

#
QualityDescriptor::to_byte

fn QualityDescriptor::to_byte(self : QualityDescriptor) -> Int

#
QualityDescriptor::with_blocked

fn QualityDescriptor::with_blocked(self : QualityDescriptor, value : Bool) -> QualityDescriptor

#
QualityDescriptor::with_invalid

fn QualityDescriptor::with_invalid(self : QualityDescriptor, value : Bool) -> QualityDescriptor

#
QualityDescriptor::with_not_topical

fn QualityDescriptor::with_not_topical(self : QualityDescriptor, value : Bool) -> QualityDescriptor

#
QualityDescriptor::with_overflow

fn QualityDescriptor::with_overflow(self : QualityDescriptor, value : Bool) -> QualityDescriptor

#
QualityDescriptor::with_substituted

fn QualityDescriptor::with_substituted(self : QualityDescriptor, value : Bool) -> QualityDescriptor

#
RateLimiter

pub struct RateLimiter {
window_start : Int
window_size : Int
limit : Int
used : Int
} derive(Eq,
Debug
)

A fixed-window rate limiter for commands and diagnostics.

#
RateLimiter::allow

fn RateLimiter::allow(self : RateLimiter, now : Int) -> Bool

#
RateLimiter::new

fn RateLimiter::new(window_size : Int, limit : Int) -> Result[RateLimiter, String]

#
RateLimiter::remaining

fn RateLimiter::remaining(self : RateLimiter) -> Int

#
RateLimiter::used

fn RateLimiter::used(self : RateLimiter) -> Int

#
ReadTransaction

pub struct ReadTransaction {
request : ServiceRequest
status : ServiceStatus
} derive(
Debug
)

Read service state for a single information object.

#
ReadTransaction::activate

fn ReadTransaction::activate(self : ReadTransaction) -> Result[Unit, String]

#
ReadTransaction::complete

fn ReadTransaction::complete(self : ReadTransaction, object : ApplicationObject) -> Result[ServiceResponse, String]

#
ReadTransaction::new

fn ReadTransaction::new(request : ServiceRequest) -> Result[ReadTransaction, String]

#
ReadTransaction::reject

fn ReadTransaction::reject(self : ReadTransaction, message : String) -> ServiceResponse

#
ReadTransaction::status

#
ReplayGuard

pub struct ReplayGuard {
seen : Map[UInt, Int]
ttl : Int
limit : Int
} derive(
Debug
)

Replay guard keyed by APDU checksum and a bounded time interval.

#
ReplayGuard::is_replay

fn ReplayGuard::is_replay(self : ReplayGuard, frame : Bytes, now : Int) -> Bool

#
ReplayGuard::len

fn ReplayGuard::len(self : ReplayGuard) -> Int

#
ReplayGuard::new

fn ReplayGuard::new(ttl : Int, limit : Int) -> Result[ReplayGuard, String]

#
ReplayGuard::purge

fn ReplayGuard::purge(self : ReplayGuard, now : Int) -> Int

#
ReplayGuard::remember

fn ReplayGuard::remember(self : ReplayGuard, frame : Bytes, now : Int) -> Result[Unit, String]

#
ResourceLimits

pub struct ResourceLimits {
max_apdu : Int
max_asdu : Int
max_objects : Int
max_history : Int
max_commands : Int
max_trace_events : Int
} derive(Eq,
Debug
)

Resource limits prevent malformed peers from exhausting a gateway.

#
ResourceLimits::default

#
ResourceLimits::max_apdu

fn ResourceLimits::max_apdu(self : ResourceLimits) -> Int

#
ResourceLimits::max_asdu

fn ResourceLimits::max_asdu(self : ResourceLimits) -> Int

#
ResourceLimits::max_commands

fn ResourceLimits::max_commands(self : ResourceLimits) -> Int

#
ResourceLimits::max_history

fn ResourceLimits::max_history(self : ResourceLimits) -> Int

#
ResourceLimits::max_objects

fn ResourceLimits::max_objects(self : ResourceLimits) -> Int

#
ResourceLimits::max_trace_events

fn ResourceLimits::max_trace_events(self : ResourceLimits) -> Int

#
ResourceLimits::new

fn ResourceLimits::new(max_apdu : Int, max_asdu : Int, max_objects : Int, max_history : Int, max_commands : Int, max_trace_events : Int) -> Result[ResourceLimits, String]

#
ScaledValue

pub struct ScaledValue {
value : Int
quality : QualityDescriptor
} derive(Eq,
Debug
)

Signed 16-bit scaled measurement.

#
ScaledValue::new

fn ScaledValue::new(value : Int, quality? : QualityDescriptor) -> Result[ScaledValue, String]

#
ScaledValue::quality

#
ScaledValue::to_array

fn ScaledValue::to_array(self : ScaledValue) -> Array[Byte]

#
ScaledValue::value

fn ScaledValue::value(self : ScaledValue) -> Int

#
ScheduledAction

pub struct ScheduledAction {
at : Int
ordinal : Int
action : SimulationAction
} derive(
Debug
)

#
ScheduledAction::action

#
ScheduledAction::at

fn ScheduledAction::at(self : ScheduledAction) -> Int

#
ScheduledAction::new

fn ScheduledAction::new(at : Int, ordinal : Int, action : SimulationAction) -> ScheduledAction

#
ScheduledAction::ordinal

fn ScheduledAction::ordinal(self : ScheduledAction) -> Int

#
SequenceWindow

pub struct SequenceWindow {
first_unacknowledged : Int
next_send : Int
next_receive : Int
capacity : Int
} derive(Eq,
Debug
)

A validated receive/send sequence window.

#
SequenceWindow::acknowledge

fn SequenceWindow::acknowledge(self : SequenceWindow, sequence : Int) -> Result[Int, String]

#
SequenceWindow::available

fn SequenceWindow::available(self : SequenceWindow) -> Int

#
SequenceWindow::can_send

fn SequenceWindow::can_send(self : SequenceWindow) -> Bool

#
SequenceWindow::new

fn SequenceWindow::new(capacity : Int) -> Result[SequenceWindow, String]

#
SequenceWindow::next_receive

fn SequenceWindow::next_receive(self : SequenceWindow) -> Int

#
SequenceWindow::next_send

fn SequenceWindow::next_send(self : SequenceWindow) -> Int

#
SequenceWindow::pending

fn SequenceWindow::pending(self : SequenceWindow) -> Int

#
SequenceWindow::receive

fn SequenceWindow::receive(self : SequenceWindow, sequence : Int) -> Result[Unit, String]

#
SequenceWindow::reserve_send

fn SequenceWindow::reserve_send(self : SequenceWindow) -> Result[Int, String]

#
ServiceKind

pub enum ServiceKind {
InterrogationService
CounterInterrogationService
ReadService
ClockSyncService
CommandService
ResetService
DelayAcquisitionService
} derive(Eq,
Debug
)

Application service classes supported by the portable core.

#
ServiceRequest

pub struct ServiceRequest {
service : ServiceKind
address : InformationAddress
common_address : CommonAddress
qualifier : Int
created_at : Int
originator : Int
} derive(Eq,
Debug
)

An application service request independent of a transport.

#
ServiceRequest::address

#
ServiceRequest::common_address

fn ServiceRequest::common_address(self : ServiceRequest) -> CommonAddress

#
ServiceRequest::created_at

fn ServiceRequest::created_at(self : ServiceRequest) -> Int

#
ServiceRequest::new

fn ServiceRequest::new(service : ServiceKind, address : InformationAddress, common_address : CommonAddress, qualifier : Int, created_at : Int, originator? : Int) -> Result[ServiceRequest, Diagnostic]

#
ServiceRequest::originator

fn ServiceRequest::originator(self : ServiceRequest) -> Int

#
ServiceRequest::qualifier

fn ServiceRequest::qualifier(self : ServiceRequest) -> Int

#
ServiceRequest::service

#
ServiceResponse

pub struct ServiceResponse {
request : ServiceRequest
status : ServiceStatus
cause : CauseOfTransmission
objects : Array[ApplicationObject]
message : String
} derive(
Debug
)

A service response with optional application data.

#
ServiceResponse::cause

#
ServiceResponse::message

fn ServiceResponse::message(self : ServiceResponse) -> String

#
ServiceResponse::new

fn ServiceResponse::new(request : ServiceRequest, status : ServiceStatus, cause : CauseOfTransmission, objects : Array[ApplicationObject], message? : String) -> ServiceResponse

#
ServiceResponse::objects

#
ServiceResponse::request

#
ServiceResponse::status

#
ServiceStatus

pub enum ServiceStatus {
IdleService
ActiveService
ConfirmedService
TerminatedService
RejectedService
FailedService
} derive(Eq,
Debug
)

Result state used by application transactions.

#
Session

pub struct Session {
state : LinkState
send_sequence : Int
receive_sequence : Int
window_size : Int
pending : Int
} derive(
Debug
)

A deterministic session state machine. Transport I/O is intentionally injected by callers.

#
Session::new

fn Session::new(window_size? : Int) -> Session

#
Session::receive

fn Session::receive(self : Session, frame : Frame) -> Result[Unit, String]

#
Session::send

fn Session::send(self : Session, payload : Bytes) -> Result[Frame, String]

#
Session::snapshot

fn Session::snapshot(self : Session) -> SessionSnapshot

#
Session::start

fn Session::start(self : Session) -> Frame

#
Session::stop

fn Session::stop(self : Session) -> Frame

fn Session::test_link(self : Session) -> Frame

#
SessionAction

pub enum SessionAction {
SendStart
SendStop
SendTest
SendSupervisory(Int)
SendInformation(Int)
DeliverInformation(Bytes)
Acknowledge(Int)
Report(Diagnostic)
NoAction
} derive(
Debug
)

A deterministic action emitted by a session driver.

#
SessionSnapshot

pub struct SessionSnapshot {
state : LinkState
send_sequence : Int
receive_sequence : Int
pending : Int
window_size : Int
} derive(Eq,
Debug
)

Host-visible session observation.

#
SessionSnapshot::available

fn SessionSnapshot::available(self : SessionSnapshot) -> Int

#
SessionSnapshot::is_started

fn SessionSnapshot::is_started(self : SessionSnapshot) -> Bool

#
SessionSnapshot::pending

fn SessionSnapshot::pending(self : SessionSnapshot) -> Int

#
SessionSnapshot::receive_sequence

fn SessionSnapshot::receive_sequence(self : SessionSnapshot) -> Int

#
SessionSnapshot::send_sequence

fn SessionSnapshot::send_sequence(self : SessionSnapshot) -> Int

#
ShortFloatValue

pub struct ShortFloatValue {
value : Float
quality : QualityDescriptor
} derive(Eq,
Debug
)

IEEE-754 short floating point measurement.

#
ShortFloatValue::new

fn ShortFloatValue::new(value : Float, quality? : QualityDescriptor) -> ShortFloatValue

#
ShortFloatValue::quality

#
ShortFloatValue::value

fn ShortFloatValue::value(self : ShortFloatValue) -> Float

#
Simulation

pub struct Simulation {
clock : VirtualClock
actions : Array[ScheduledAction]
events : Array[SimulationEvent]
next_ordinal : Int
max_events : Int
} derive(
Debug
)

#
Simulation::clear_events

fn Simulation::clear_events(self : Simulation) -> Unit

#
Simulation::events

#
Simulation::new

fn Simulation::new(start? : Int, max_events? : Int) -> Result[Simulation, String]

#
Simulation::now

fn Simulation::now(self : Simulation) -> Int

#
Simulation::pending

fn Simulation::pending(self : Simulation) -> Int

#
Simulation::run_until

fn Simulation::run_until(self : Simulation, timestamp : Int) -> Result[Int, String]

Run all scheduled actions up to an inclusive timestamp.

#
Simulation::schedule

fn Simulation::schedule(self : Simulation, at : Int, action : SimulationAction) -> Result[Unit, String]

#
Simulation::step

fn Simulation::step(self : Simulation) -> Result[Bool, String]

Run the next scheduled action, if any.

#
SimulationAction

pub enum SimulationAction {
Receive(Frame)
Publish(ApplicationObject)
AdvanceTimer(String)
Record(String)
} derive(
Debug
)

Work scheduled for a deterministic simulation tick.

#
SimulationEvent

pub enum SimulationEvent {
FrameProduced(Int, Frame)
ObjectPublished(Int, ApplicationObject)
TimerAdvanced(Int, String)
Note(Int, String)
SimulationFault(Int, Diagnostic)
} derive(
Debug
)

Results emitted by one simulation step.

#
SinglePointValue

pub struct SinglePointValue {
state : Bool
quality : StatusQuality
} derive(Eq,
Debug
)

Single point information value, including its QDS.

#
SinglePointValue::from_byte

fn SinglePointValue::from_byte(value : Int) -> Result[SinglePointValue, String]

#
SinglePointValue::new

fn SinglePointValue::new(state : Bool, quality? : StatusQuality) -> SinglePointValue

#
SinglePointValue::quality

#
SinglePointValue::state

fn SinglePointValue::state(self : SinglePointValue) -> Bool

#
SinglePointValue::to_byte

fn SinglePointValue::to_byte(self : SinglePointValue) -> Int

#
StationProfile

pub struct StationProfile {
name : String
common_address : CommonAddress
parameters : ConnectionParameters
supported_types : Array[ApplicationType]
max_objects : Int
tls_required : Bool
} derive(
Debug
)

A station profile exchanged by deployment configuration and test tools.

#
StationProfile::common_address

fn StationProfile::common_address(self : StationProfile) -> CommonAddress

#
StationProfile::max_objects

fn StationProfile::max_objects(self : StationProfile) -> Int

#
StationProfile::name

fn StationProfile::name(self : StationProfile) -> String

#
StationProfile::new

fn StationProfile::new(name : String, common_address : CommonAddress, parameters : ConnectionParameters, supported_types : Array[ApplicationType], max_objects? : Int, tls_required? : Bool) -> Result[StationProfile, String]

#
StationProfile::parameters

#
StationProfile::supported_types

fn StationProfile::supported_types(self : StationProfile) -> Array[ApplicationType]

#
StationProfile::supports

fn StationProfile::supports(self : StationProfile, type_id : ApplicationType) -> Bool

#
StationProfile::tls_required

fn StationProfile::tls_required(self : StationProfile) -> Bool

#
StationSimulation

pub struct StationSimulation {
store : PointStore
session : Session
simulation : Simulation
metrics : FrameMetrics
trace : TraceLog
} derive(
Debug
)

A deterministic station simulation composed from a point store and session.

#
StationSimulation::events

#
StationSimulation::ingest

fn StationSimulation::ingest(self : StationSimulation, object : ApplicationObject, timestamp : Int) -> Result[PointChange, Diagnostic]

#
StationSimulation::metrics

#
StationSimulation::new

fn StationSimulation::new(common_address : CommonAddress, window_size? : Int) -> Result[StationSimulation, String]

#
StationSimulation::receive

fn StationSimulation::receive(self : StationSimulation, frame : Frame) -> Result[Unit, String]

#
StationSimulation::run_until

fn StationSimulation::run_until(self : StationSimulation, timestamp : Int) -> Result[Int, String]

#
StationSimulation::schedule

fn StationSimulation::schedule(self : StationSimulation, at : Int, action : SimulationAction) -> Result[Unit, String]

#
StationSimulation::send

fn StationSimulation::send(self : StationSimulation, payload : Bytes) -> Result[Frame, String]

#
StationSimulation::session

#
StationSimulation::start

#
StationSimulation::stop

#
StationSimulation::store

#
StationSimulation::trace

#
StatusQuality

pub struct StatusQuality {
blocked : Bool
substituted : Bool
not_topical : Bool
invalid : Bool
} derive(Eq,
Debug
)

Quality descriptor for single and double point status values.

#
StatusQuality::as_measurement

fn StatusQuality::as_measurement(self : StatusQuality) -> QualityDescriptor

#
StatusQuality::clear

#
StatusQuality::from_byte

fn StatusQuality::from_byte(value : Int) -> Result[StatusQuality, String]

#
StatusQuality::is_usable

fn StatusQuality::is_usable(self : StatusQuality) -> Bool

#
StatusQuality::to_byte

fn StatusQuality::to_byte(self : StatusQuality) -> Int

#
StepPositionValue

pub struct StepPositionValue {
position : Int
transient : Bool
quality : StatusQuality
} derive(Eq,
Debug
)

Step position value with a signed seven-bit position and transient flag.

#
StepPositionValue::new

fn StepPositionValue::new(position : Int, transient? : Bool, quality? : StatusQuality) -> Result[StepPositionValue, String]

#
StepPositionValue::position

fn StepPositionValue::position(self : StepPositionValue) -> Int

#
StepPositionValue::quality

#
StepPositionValue::to_array

fn StepPositionValue::to_array(self : StepPositionValue) -> Array[Byte]

#
StoreStatistics

pub struct StoreStatistics {
total : Int
monitoring : Int
control : Int
valid : Int
invalid : Int
revisions : Int
changes : Int
} derive(Eq,
Debug
)

Aggregate counts for an in-memory point store.

#
StoreStatistics::changes

fn StoreStatistics::changes(self : StoreStatistics) -> Int

#
StoreStatistics::control

fn StoreStatistics::control(self : StoreStatistics) -> Int

#
StoreStatistics::empty

#
StoreStatistics::invalid

fn StoreStatistics::invalid(self : StoreStatistics) -> Int

#
StoreStatistics::monitoring

fn StoreStatistics::monitoring(self : StoreStatistics) -> Int

#
StoreStatistics::revisions

fn StoreStatistics::revisions(self : StoreStatistics) -> Int

#
StoreStatistics::total

fn StoreStatistics::total(self : StoreStatistics) -> Int

#
StoreStatistics::valid

fn StoreStatistics::valid(self : StoreStatistics) -> Int

#
StoreTransaction

pub struct StoreTransaction {
pending : Array[(ApplicationObject, Int, String)]
removed : Array[(InformationAddress, Int)]
committed : Bool
} derive(
Debug
)

A transaction that stages changes before committing them to a store.

#
StoreTransaction::commit

fn StoreTransaction::commit(self : StoreTransaction, store : PointStore) -> Result[Array[PointChange], Diagnostic]

#
StoreTransaction::new

#
StoreTransaction::pending_count

fn StoreTransaction::pending_count(self : StoreTransaction) -> Int

#
StoreTransaction::rollback

fn StoreTransaction::rollback(self : StoreTransaction) -> Unit

#
StoreTransaction::stage

fn StoreTransaction::stage(self : StoreTransaction, object : ApplicationObject, timestamp : Int, source? : String) -> Result[Unit, Diagnostic]

#
StoreTransaction::stage_remove

fn StoreTransaction::stage_remove(self : StoreTransaction, address : InformationAddress, timestamp : Int) -> Result[Unit, Diagnostic]

#
TimeTag

pub enum TimeTag {
Short(Cp24Time)
Long(Cp56Time)
} derive(Eq,
Debug
)

A tagged union used by event stores and application services.

#
TimeTag::kind

fn TimeTag::kind(self : TimeTag) -> TimeTagKind

#
TimeTag::to_array

fn TimeTag::to_array(self : TimeTag) -> Array[Byte]

#
TimeTag::width

fn TimeTag::width(self : TimeTag) -> Int

#
TimeTagKind

pub enum TimeTagKind {
NoTimeTag
Cp24TimeTag
Cp56TimeTag
} derive(Eq,
Debug
)

Tag precision carried by a time-tagged application object.

#
TimeTagKind::width

fn TimeTagKind::width(self : TimeTagKind) -> Int

#
TimerState

pub enum TimerState {
Inactive
Running(Int)
Expired
} derive(Eq,
Debug
)

State of a timer that is driven by a host monotonic clock.

#
TraceEvent

pub struct TraceEvent {
timestamp : Int
kind : TraceKind
detail : String
correlation : Int
} derive(Eq,
Debug
)

#
TraceEvent::correlation

fn TraceEvent::correlation(self : TraceEvent) -> Int

#
TraceEvent::detail

fn TraceEvent::detail(self : TraceEvent) -> String

#
TraceEvent::kind

fn TraceEvent::kind(self : TraceEvent) -> TraceKind

#
TraceEvent::new

fn TraceEvent::new(timestamp : Int, kind : TraceKind, detail : String, correlation? : Int) -> TraceEvent

#
TraceEvent::timestamp

fn TraceEvent::timestamp(self : TraceEvent) -> Int

#
TraceKind

pub enum TraceKind {
FrameSent
FrameReceived
StateChanged
PointUpdated
ServiceStarted
ServiceCompleted
DiagnosticRaised
} derive(Eq,
Debug
)

A trace event with a monotonic timestamp.

#
TraceLog

pub struct TraceLog {
events : Array[TraceEvent]
limit : Int
} derive(
Debug
)

#
TraceLog::all

fn TraceLog::all(self : TraceLog) -> Array[TraceEvent]

#
TraceLog::len

fn TraceLog::len(self : TraceLog) -> Int

#
TraceLog::new

fn TraceLog::new(limit? : Int) -> Result[TraceLog, String]

#
TraceLog::push

fn TraceLog::push(self : TraceLog, event : TraceEvent) -> Unit

#
TraceLog::since

fn TraceLog::since(self : TraceLog, timestamp : Int) -> Array[TraceEvent]

#
TransportMode

pub enum TransportMode {
Tcp
SerialGateway
ReplayFile
InMemory
} derive(Eq,
Debug
)

#
TypeDescriptor

pub struct TypeDescriptor {
type_id : ApplicationType
name : String
direction : PointDirection
time_tag : TimeTagKind
value_width : Int
supported : Bool
command : Bool
} derive(Eq,
Debug
)

Machine-readable description of an IEC 104 application type.

#
TypeDescriptor::direction

#
TypeDescriptor::is_command

fn TypeDescriptor::is_command(self : TypeDescriptor) -> Bool

#
TypeDescriptor::name

fn TypeDescriptor::name(self : TypeDescriptor) -> String

#
TypeDescriptor::supported

fn TypeDescriptor::supported(self : TypeDescriptor) -> Bool

#
TypeDescriptor::time_tag

fn TypeDescriptor::time_tag(self : TypeDescriptor) -> TimeTagKind

#
TypeDescriptor::type_id

#
TypeDescriptor::value_width

fn TypeDescriptor::value_width(self : TypeDescriptor) -> Int

#
TypeId

pub enum TypeId {
SinglePoint
DoublePoint
NormalizedValue
ShortFloat
BitString32
Unknown(Int)
} derive(Eq,
Debug
)

Application type identifiers used by this library.

#
TypeId::is_known

fn TypeId::is_known(self : TypeId) -> Bool

#
TypeId::name

fn TypeId::name(self : TypeId) -> String

#
TypeId::number

fn TypeId::number(self : TypeId) -> Int

#
UCommand

pub enum UCommand {
StartDataTransfer
StopDataTransfer
TestFrame
Unknown(UInt16)
} derive(Eq,
Debug
)

IEC 104 U-frame commands.

#
UCommand::control

fn UCommand::control(self : UCommand) -> UInt16

#
VirtualClock

pub struct VirtualClock {
now : Int
} derive(Eq,
Debug
)

A deterministic monotonic clock for protocol simulations and tests.

#
VirtualClock::advance

fn VirtualClock::advance(self : VirtualClock, delta : Int) -> Result[Int, String]

#
VirtualClock::new

fn VirtualClock::new(start? : Int) -> Result[VirtualClock, String]

#
VirtualClock::now

fn VirtualClock::now(self : VirtualClock) -> Int

#
VirtualClock::set

fn VirtualClock::set(self : VirtualClock, timestamp : Int) -> Result[Unit, String]

#
admit_envelope

fn admit_envelope(envelope : AsduEnvelope, limits : ResourceLimits) -> AdmissionDecision

#
admit_frame

fn admit_frame(frame : Frame, limits : ResourceLimits) -> AdmissionDecision

#
admit_inbound

fn admit_inbound(data : Bytes, limits : ResourceLimits, replay : ReplayGuard, now : Int) -> Result[Frame, Diagnostic]

Admission pipeline for an inbound APDU.

#
append_u24

fn append_u24(out : Array[Byte], value : Int) -> Result[Unit, String]

#
application_service_examples

fn application_service_examples() -> Array[ServiceStatus]

#
application_type

fn application_type(value : Int) -> ApplicationType

Decode all currently assigned standard IEC 104 type identifiers.

#
application_type_catalog

fn application_type_catalog() -> Array[TypeDescriptor]

Return the standard catalog used to negotiate object capabilities.

#
application_value_examples

fn application_value_examples() -> Array[ApplicationValue]

#
application_value_is_command

fn application_value_is_command(value : ApplicationValue) -> Bool

#
application_value_is_measurement

fn application_value_is_measurement(value : ApplicationValue) -> Bool

#
application_value_type

fn application_value_type(value : ApplicationValue) -> ApplicationType

#
application_value_width

fn application_value_width(value : ApplicationValue) -> Int

#
assess_metrics

fn assess_metrics(metrics : MetricsSnapshot) -> HealthReport

#
assess_session

fn assess_session(snapshot : SessionSnapshot) -> HealthReport

#
assess_store

fn assess_store(store : PointStore) -> HealthReport

#
benchmark_fixture_checksums

fn benchmark_fixture_checksums() -> Array[UInt]

#
benchmark_result_table

fn benchmark_result_table(results : Array[BenchmarkResult]) -> String

#
binary_counter_object

fn binary_counter_object(address : InformationAddress, value : UInt, sequence? : Int, time_tag? : TimeTag) -> Result[ApplicationObject, String]

#
bit_is_set

fn bit_is_set(value : Int, bit : Int) -> Bool

#
bit_string_object

fn bit_string_object(address : InformationAddress, value : UInt, time_tag? : TimeTag) -> Result[ApplicationObject, String]

#
byte_statistics

fn byte_statistics(data : Bytes) -> ByteStatistics

#
bytes_equal_left

fn bytes_equal_left(a : Bytes, b : Bytes) -> Bool

#
calendar_weekday

fn calendar_weekday(year : Int, month : Int, day : Int) -> Result[Int, String]

Calculate ISO-like weekday for a Gregorian date: Monday is 1, Sunday is 7.

#
cause

fn cause(value : Int) -> Cause

#
cause_category

fn cause_category(value : Int) -> CauseCategory

Decode a standard cause category without rejecting extension values.

#
clock_sync_object

fn clock_sync_object(address : InformationAddress, value : Cp56Time) -> Result[ApplicationObject, String]

#
compatibility_examples

fn compatibility_examples() -> Array[String]

#
conformance_examples

fn conformance_examples() -> Array[TypeDescriptor]

#
control_type_catalog

fn control_type_catalog() -> Array[TypeDescriptor]

#
counter_interrogation_object

fn counter_interrogation_object(address : InformationAddress, qualifier : Int) -> Result[ApplicationObject, String]

#
crc16_ibm

fn crc16_ibm(data : Bytes) -> UInt

CRC-16/IBM helper for gateways that wrap IEC APDUs in a framed channel.

#
crc32_ieee

fn crc32_ieee(data : Bytes) -> UInt

CRC-32 used by fixture manifests and deterministic transport tests.

#
create_interrogation_plan

fn create_interrogation_plan(store : PointStore, request : InterrogationRequest, filter : PointFilter, batch_size? : Int) -> Result[InterrogationPlan, String]

Build plans from a point store while retaining type and address boundaries.

#
days_in_month

fn days_in_month(year : Int, month : Int) -> Int?

Return the number of days in a Gregorian month.

#
days_in_year

fn days_in_year(year : Int) -> Int

Return the number of days in a year.

#
decode_asdu

fn decode_asdu(data : Bytes) -> Result[(AsduHeader, Array[InformationObject]), String]

Decode an ASDU header and its information objects.

#
decode_extended_asdu

fn decode_extended_asdu(data : Bytes) -> Result[AsduEnvelope, Diagnostic]

Decode a complete address-qualified ASDU.

#
decode_frame

fn decode_frame(data : Bytes) -> Result[Frame, String]

Decode one complete APDU. Extra bytes after the declared APDU are rejected.

#
decode_signed16

fn decode_signed16(low : Int, high : Int) -> Result[Int, String]

Return the signed value represented by a two-byte little-endian field.

#
decode_time_tag

fn decode_time_tag(kind : TimeTagKind, data : Bytes, offset? : Int) -> Result[TimeTag, String]

Decode the selected tag precision from a byte sequence.

#
default_benchmark_suite

fn default_benchmark_suite() -> BenchmarkSuite

Produce the standard local suite used by README benchmark commands.

#
diagnostic_kind_examples

fn diagnostic_kind_examples() -> Array[DiagnosticKind]

Keep all diagnostic categories available to host-side telemetry adapters.

#
diagnostic_kind_name

fn diagnostic_kind_name(kind : DiagnosticKind) -> String

#
diagnostics_examples

fn diagnostics_examples() -> Array[DiagnosticKind]

#
double_command_object

fn double_command_object(address : InformationAddress, state : Int, qualifier : Int) -> Result[ApplicationObject, String]

#
double_point_object

fn double_point_object(address : InformationAddress, state : Int, quality? : StatusQuality, time_tag? : TimeTag) -> Result[ApplicationObject, String]

#
encode_application_object

fn encode_application_object(object : ApplicationObject) -> Bytes

Encode an IOA-qualified object without the ASDU header.

#
encode_asdu

fn encode_asdu(header : AsduHeader, objects : Array[InformationObject]) -> Bytes

Encode an ASDU header followed by information objects.

#
encode_extended_asdu

fn encode_extended_asdu(envelope : AsduEnvelope) -> Result[Bytes, Diagnostic]

Encode an address-qualified ASDU into its IEC 104 application payload.

#
encode_frame

fn encode_frame(frame : Frame) -> Bytes

Encode one APCI frame, including the 0x68 start byte and length byte.

#
encode_signed16

fn encode_signed16(value : Int) -> Result[Array[Byte], String]

Encode a signed value into a little-endian two-byte field.

#
encode_time_tag

fn encode_time_tag(tag : TimeTag) -> Bytes

#
encoded_frame_size

fn encoded_frame_size(frame : Frame) -> Int

Return the number of octets that an encoded frame will occupy.

#
end_of_initialization_object

fn end_of_initialization_object(address : InformationAddress, value : Int) -> Result[ApplicationObject, String]

#
evaluate_command

fn evaluate_command(policy : CommandPolicy, object : ApplicationObject) -> CommandOutcome

#
extended_asdu_examples

fn extended_asdu_examples() -> Array[AsduEnvelope]

#
frame_fits_apdu

fn frame_fits_apdu(frame : Frame, maximum : Int) -> Bool

Return a conservative APDU limit check for gateways.

#
frame_kind_name

fn frame_kind_name(kind : FrameKind) -> String

#
health_state_examples

fn health_state_examples() -> Array[HealthState]

#
health_state_name

fn health_state_name(state : HealthState) -> String

#
hex_decode

fn hex_decode(text : String) -> Result[Bytes, String]

#
hex_digit

fn hex_digit(value : Int) -> Char

Convert a hexadecimal nibble to a display character.

#
hex_encode

fn hex_encode(data : Bytes) -> String

#
hex_value

fn hex_value(value : Char) -> Int?

#
implementation_version

fn implementation_version() -> String

#
information_frame

fn information_frame(send_sequence : Int, receive_sequence : Int, payload : Bytes) -> Frame

Create an I frame from a sequence pair and an ASDU payload.

#
interrogation_object

fn interrogation_object(address : InformationAddress, qualifier : Int) -> Result[ApplicationObject, String]

#
is_leap_year

fn is_leap_year(year : Int) -> Bool

Whether a year is a Gregorian leap year.

#
mask_bits

fn mask_bits(value : Int, mask : Int) -> Int

#
measurement_state

fn measurement_state(quality : QualityDescriptor) -> MeasurementState

#
measurement_state_examples

fn measurement_state_examples() -> Array[MeasurementState]

#
milliseconds_since_midnight

fn milliseconds_since_midnight(hour : Int, minute : Int, second : Int, millisecond : Int) -> Result[Int, String]

Sum milliseconds since midnight, used by deterministic simulations.

#
monitoring_type_catalog

fn monitoring_type_catalog() -> Array[TypeDescriptor]

#
negotiate_profiles

fn negotiate_profiles(local_profile : StationProfile, remote : StationProfile) -> NegotiationDecision

#
normalize_quality

fn normalize_quality(value : Int) -> Int

Clamp a quality byte to the protocol's low eight bits.

#
normalized_object

fn normalized_object(address : InformationAddress, value : Int, quality? : QualityDescriptor, time_tag? : TimeTag) -> Result[ApplicationObject, String]

#
normalized_set_point_object

fn normalized_set_point_object(address : InformationAddress, value : Int, qualifier : Int) -> Result[ApplicationObject, String]

#
normalized_value_asdu

fn normalized_value_asdu(cause : Int, common_address : Int, value : Int, quality : Int) -> Bytes

Build a normalized telemetry value.

#
observe_frame_length

fn observe_frame_length(histogram : LengthHistogram, frame : Frame) -> Unit

Record an APDU length observation.

#
ordinal_day

fn ordinal_day(year : Int, month : Int, day : Int) -> Result[Int, String]

Convert a month/day pair to a one-based ordinal day.

#
pad_bytes

fn pad_bytes(data : Bytes, length : Int, fill : Byte) -> Result[Bytes, String]

#
parse_apdu_prefix

fn parse_apdu_prefix(data : Bytes) -> ApduParseResult

Parse one APDU from a byte view without requiring a socket implementation.

#
parse_vsq

fn parse_vsq(value : Int) -> Result[(Int, Bool), String]

Validate a VSQ byte and return its count/sequence pair.

#
point_change_kind_examples

fn point_change_kind_examples() -> Array[PointChangeKind]

#
point_direction

fn point_direction(type_id : ApplicationType) -> PointDirection

#
point_store_examples

fn point_store_examples() -> Array[PointDirection]

#
profile_examples

fn profile_examples() -> Array[StationProfile]

#
protocol_event_examples

fn protocol_event_examples() -> Array[ProtocolEvent]

Standard event constructors for host integrations.

#
protocol_name

fn protocol_name() -> String

#
quality_for_state

fn quality_for_state(state : MeasurementState) -> QualityDescriptor

Build a quality descriptor from a measurement state.

#
read_object

fn read_object(address : InformationAddress) -> Result[ApplicationObject, String]

#
read_u24

fn read_u24(data : Bytes, offset : Int) -> Result[Int, String]

#
regulating_step_command_object

fn regulating_step_command_object(address : InformationAddress, step : Int, qualifier : Int) -> Result[ApplicationObject, String]

#
reset_command_object

fn reset_command_object(address : InformationAddress, value : Int) -> Result[ApplicationObject, String]

#
run_benchmark_workload

fn run_benchmark_workload(rounds : Int, payload_size : Int) -> Result[BenchmarkWorkload, String]

#
safe_apdu_payload

fn safe_apdu_payload(data : Bytes) -> Result[Bytes, Diagnostic]

#
scaled_object

fn scaled_object(address : InformationAddress, value : Int, quality? : QualityDescriptor, time_tag? : TimeTag) -> Result[ApplicationObject, String]

#
scaled_set_point_object

fn scaled_set_point_object(address : InformationAddress, value : Int, qualifier : Int) -> Result[ApplicationObject, String]

#
security_examples

fn security_examples() -> Array[AdmissionDecision]

#
sequence_acknowledges

fn sequence_acknowledges(send_cursor : Int, acknowledgement : Int) -> Bool

Whether a sequence acknowledgement is valid for a send cursor.

#
sequence_before

fn sequence_before(start : Int, candidate : Int, limit : Int) -> Bool

Whether candidate is strictly before limit from start.

#
sequence_distance

fn sequence_distance(start : Int, end : Int) -> Int

Distance from start to end on the 15-bit sequence ring.

#
sequence_next

fn sequence_next(value : Int) -> Int

Return the next sequence number on the IEC ring.

#
sequence_normalize

fn sequence_normalize(value : Int) -> Int

Sequence numbers are modulo 32768 in IEC 104.

#
sequence_previous

fn sequence_previous(value : Int) -> Int

Return the previous sequence number on the IEC ring.

#
service_kind_examples

fn service_kind_examples() -> Array[ServiceKind]

#
service_status_examples

fn service_status_examples() -> Array[ServiceStatus]

#
service_status_name

fn service_status_name(status : ServiceStatus) -> String

#
session_action_examples

fn session_action_examples() -> Array[SessionAction]

#
set_bit

fn set_bit(value : Int, bit : Int, enabled : Bool) -> Int

#
short_float_object

fn short_float_object(address : InformationAddress, value : Float, quality? : QualityDescriptor, time_tag? : TimeTag) -> Result[ApplicationObject, String]

#
short_float_set_point_object

fn short_float_set_point_object(address : InformationAddress, value : Float, qualifier : Int) -> Result[ApplicationObject, String]

#
simulation_action_examples

fn simulation_action_examples() -> Array[SimulationAction]

#
simulation_event_examples

fn simulation_event_examples() -> Array[SimulationEvent]

#
single_command_object

fn single_command_object(address : InformationAddress, state : Bool, qualifier : Int) -> Result[ApplicationObject, String]

#
single_object_asdu

fn single_object_asdu(object : ApplicationObject, cause : CauseOfTransmission, common_address : CommonAddress) -> Result[AsduEnvelope, Diagnostic]

Build an ASDU containing one object.

#
single_point_asdu

fn single_point_asdu(cause : Int, common_address : Int, ioa : Int, status : Bool, quality : Int) -> Bytes

Build a single-point status ASDU.

#
single_point_object

fn single_point_object(address : InformationAddress, state : Bool, quality? : StatusQuality, time_tag? : TimeTag) -> Result[ApplicationObject, String]

#
split_apdus

fn split_apdus(data : Bytes) -> Result[(Array[Frame], Bytes), Diagnostic]

Split a byte stream into complete APDUs and retain incomplete tails.

#
split_milliseconds_since_midnight

fn split_milliseconds_since_midnight(value : Int) -> Result[(Int, Int, Int, Int), String]

Split milliseconds since midnight into hour, minute, second and remainder.

#
step_position_object

fn step_position_object(address : InformationAddress, position : Int, transient? : Bool, quality? : StatusQuality, time_tag? : TimeTag) -> Result[ApplicationObject, String]

#
supervisory_frame

fn supervisory_frame(receive_sequence : Int) -> Frame

Create an S frame acknowledging received I frames.

#
supported_type_catalog

fn supported_type_catalog() -> Array[TypeDescriptor]

#
test_command_object

fn test_command_object(address : InformationAddress, value : Int) -> Result[ApplicationObject, String]

#
time_tag_examples

fn time_tag_examples() -> Array[TimeTag]

#
time_tag_kind_for_type

fn time_tag_kind_for_type(type_id : ApplicationType) -> TimeTagKind

#
timer_state_examples

fn timer_state_examples() -> Array[TimerState]

#
trace_kind_examples

fn trace_kind_examples() -> Array[TraceKind]

#
transport_examples

fn transport_examples() -> Array[ApduParseResult]

#
transport_mode_examples

fn transport_mode_examples() -> Array[TransportMode]

#
transport_mode_name

fn transport_mode_name(mode : TransportMode) -> String

#
trim_trailing_bytes

fn trim_trailing_bytes(data : Bytes, value : Byte) -> Bytes

#
type_descriptor

fn type_descriptor(type_id : ApplicationType) -> TypeDescriptor

#
type_id

fn type_id(value : Int) -> TypeId

#
type_id_examples

fn type_id_examples() -> Array[TypeId]

#
type_is_supported

fn type_is_supported(type_id : ApplicationType) -> Bool

#
type_name

fn type_name(type_id : ApplicationType) -> String

#
type_wire_width

fn type_wire_width(type_id : ApplicationType) -> Int

#
u_command

fn u_command(control : UInt16) -> UCommand

#
unnumbered_frame

fn unnumbered_frame(control : UInt16) -> Frame

Create a U frame. The low six control bits are retained by the encoder.

#
validate_common_address

fn validate_common_address(value : Int) -> Result[CommonAddress, Diagnostic]

#
validate_envelope

fn validate_envelope(envelope : AsduEnvelope) -> ConformanceReport

#
validate_frame

fn validate_frame(frame : Frame) -> Result[Unit, String]

Validate invariants that are independent of a concrete transport.

#
validate_information_address

fn validate_information_address(value : Int) -> Result[InformationAddress, Diagnostic]

#
validate_transport_frame

fn validate_transport_frame(frame : Frame) -> Result[Unit, Diagnostic]

Validate a frame against transport-level limits before sending it.

#
wire_tool_examples

fn wire_tool_examples() -> Array[Bytes]

#
xor_checksum

fn xor_checksum(data : Bytes) -> Byte