Portable IEC 60870-5-104 protocol core for SCADA, gateways, and deterministic simulation.
moon update
moon fmt
moon check --deny-warn --target all
moon build --target wasm-gc
moon test --deny-warn --target wasm-gcmoon run cmd/main
moon run cmd/main -- --help
moon run cmd/main -- --benchmark
moon run cmd/main -- --application-benchmark///|
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),
)| 层次 | 主要文件 | 职责 |
|---|---|---|
| 链路与帧 | frame_types.mbt, codec.mbt, validation.mbt, state_machine.mbt | APCI、ASDU 基础模型、校验和链路状态 |
| 应用数据 | protocol_domain.mbt, quality.mbt, time_tags.mbt, application_objects.mbt, extended_asdu.mbt | Type ID、地址、质量、时标和信息对象 |
| 服务与状态 | transport_layer.mbt, station_database.mbt, telemetry_pipeline.mbt, command_scheduler.mbt, point_store.mbt | 传输会话、站点数据库、遥测、命令和点表 |
| 运行时能力 | file_transfer.mbt, historical_archive.mbt, redundancy_manager.mbt, service_registry.mbt, runtime_facade.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 |
1..5 | ForEach-Object { Measure-Command { moon run cmd/main -- --benchmark } }moon check --deny-warn --target all
moon test --deny-warn --target wasm-gc
moon test --deny-warn --target nativepub struct AlarmEvent {
station : CommonAddress
address : InformationAddress
name : String
severity : AlarmSeverity
active : Bool
value : Float
timestamp : Int
message : String
} derive(Eq, Debug)pub struct AlarmJournal {
active : Map[String, AlarmRecord]
events : Array[AlarmJournalEvent]
event_limit : Int
next_sequence : Int
metrics : AlarmJournalMetrics
} derive(Debug)fn AlarmJournal::acknowledge(self : AlarmJournal, key : String, operator : String, timestamp : Int) -> Result[AlarmRecord, String]fn AlarmJournal::escalate(self : AlarmJournal, key : String, operator : String, timestamp : Int) -> Result[AlarmRecord, String]fn AlarmJournal::shelve(self : AlarmJournal, key : String, operator : String, until : Int, timestamp : Int) -> Result[AlarmRecord, String]pub struct AlarmJournalEvent {
sequence : Int
timestamp : Int
key : String
action : AlarmJournalAction
operator : String
detail : String
} derive(Eq, Debug)pub struct AlarmRecord {
key : String
station : CommonAddress
address : InformationAddress
name : String
severity : AlarmSeverity
lifecycle : AlarmLifecycle
first_seen : Int
last_seen : Int
occurrences : Int
acknowledged_by : String?
acknowledged_at : Int?
shelf_until : Int?
last_value : Float
message : String
} derive(Debug)pub struct AlarmRule {
low : Float?
high : Float?
severity : AlarmSeverity
hysteresis : Float
name : String
} derive(Eq, Debug)fn AlarmRule::new(name : String, severity : AlarmSeverity, low? : Float, high? : Float, hysteresis? : Float) -> Result[AlarmRule, String]pub struct ApplicationObject {
address : InformationAddress
type_id : ApplicationType
value : ApplicationValue
time_tag : TimeTag?
} derive(Eq, Debug)fn ApplicationObject::new(address : InformationAddress, value : ApplicationValue, time_tag? : TimeTag) -> Result[ApplicationObject, String]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)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)pub struct ArchiveBucket {
station : CommonAddress
address : InformationAddress
start : Int
end : Int
count : Int
minimum : Float
maximum : Float
sum : Float
invalid : Int
} derive(Eq, Debug)fn ArchivePolicy::new(maximum_samples? : Int, maximum_age? : Int, bucket_width? : Int, reject_invalid? : Bool) -> Result[ArchivePolicy, String]pub struct ArchiveQuery {
station : CommonAddress?
first_address : InformationAddress?
last_address : InformationAddress?
start : Int?
end : Int?
source : String?
include_invalid : Bool
} derive(Eq, Debug)fn ArchiveQuery::address_range(self : ArchiveQuery, first : InformationAddress, last : InformationAddress) -> ArchiveQuerypub struct ArchiveStore {
samples : Array[ArchivedSample]
policy : ArchivePolicy
next_sequence : Int
evicted : Int
} derive(Debug)fn ArchiveStore::latest(self : ArchiveStore, station : CommonAddress, address : InformationAddress) -> ArchivedSample?pub struct ArchivedSample {
station : CommonAddress
address : InformationAddress
type_id : ApplicationType
value : Float
quality : QualityDescriptor
timestamp : Int
sequence : Int
source : String
} derive(Debug)pub struct AsduEnvelope {
type_id : ApplicationType
sequence : Bool
cause : CauseOfTransmission
common_address : CommonAddress
objects : Array[ApplicationObject]
} derive(Eq, Debug)fn AsduEnvelope::new(type_id : ApplicationType, sequence : Bool, cause : CauseOfTransmission, common_address : CommonAddress, objects : Array[ApplicationObject]) -> Result[AsduEnvelope, Diagnostic]fn BenchmarkCase::new(name : String, rounds : Int, payload_size : Int, target : String) -> Result[BenchmarkCase, String]pub struct BenchmarkResult {
case : BenchmarkCase
encoded_frames : Int
encoded_bytes : Int
checksum : UInt
elapsed_micros : Int
} derive(Eq, Debug)fn BenchmarkResult::new(case : BenchmarkCase, workload : BenchmarkWorkload, elapsed_micros : Int) -> Result[BenchmarkResult, String]fn BenchmarkSuite::run(self : BenchmarkSuite, elapsed_micros : Array[Int]) -> Result[Array[BenchmarkResult], String]fn BinaryCounterValue::new(value : UInt, sequence? : Int, carry? : Bool, adjusted? : Bool, invalid? : Bool) -> Result[BinaryCounterValue, String]pub struct CauseOfTransmission {
category : CauseCategory
number : Int
positive : Bool
test_flag : Bool
originator : Int
qualifier : Int
} derive(Eq, Debug)fn CauseOfTransmission::from_number(number : Int, positive? : Bool, test_flag? : Bool, originator? : Int, qualifier? : Int) -> Result[CauseOfTransmission, String]fn CauseOfTransmission::new(category : CauseCategory, positive? : Bool, test_flag? : Bool, originator? : Int, qualifier? : Int) -> Result[CauseOfTransmission, String]pub struct ClockSyncTransaction {
request : ServiceRequest
status : ServiceStatus
received : Cp56Time?
applied_at : Int?
} derive(Debug)fn ClockSyncTransaction::apply(self : ClockSyncTransaction, timestamp : Cp56Time, applied_at : Int) -> Result[Int, String]pub struct CommandAudit {
ticket : Int
timestamp : Int
from : CommandLifecycle
to : CommandLifecycle
attempt : Int
message : String
} derive(Eq, Debug)fn CommandAudit::new(ticket : Int, timestamp : Int, from : CommandLifecycle, to : CommandLifecycle, attempt : Int, message : String) -> CommandAuditpub struct CommandDispatch {
ticket : Int
station : CommonAddress
object : ApplicationObject
attempt : Int
expires_at : Int
} derive(Debug)pub struct CommandOutcome {
accepted : Bool
status : ServiceStatus
object : ApplicationObject?
message : String
} derive(Debug)pub struct CommandQueue {
pending : Array[ApplicationObject]
completed : Array[CommandOutcome]
limit : Int
} derive(Debug)pub struct CommandRequest {
ticket : Int
station : CommonAddress
object : ApplicationObject
priority : CommandPriority
submitted_at : Int
deadline : Int
idempotency_key : String
source : String
policy : RetryPolicy
attempts : Int
lifecycle : CommandLifecycle
next_attempt_at : Int
last_error : String
} derive(Debug)fn CommandRequest::new(ticket : Int, station : CommonAddress, object : ApplicationObject, priority : CommandPriority, submitted_at : Int, deadline : Int, idempotency_key : String, source : String, policy : RetryPolicy) -> Result[CommandRequest, Diagnostic]pub struct CommandScheduler {
pending : Array[CommandRequest]
audits : Array[CommandAudit]
audit_limit : Int
idempotency : Map[String, Int]
next_ticket : Int
metrics : SchedulerMetrics
} derive(Debug)fn CommandScheduler::cancel(self : CommandScheduler, ticket : Int, now : Int, reason? : String) -> Result[CommandRequest, Diagnostic]fn CommandScheduler::confirm(self : CommandScheduler, ticket : Int, now : Int, accepted : Bool, message? : String) -> Result[CommandRequest, Diagnostic]fn CommandScheduler::dispatch(self : CommandScheduler, policy : CommandPolicy, now : Int) -> Result[CommandDispatch?, Diagnostic]fn CommandScheduler::submit(self : CommandScheduler, station : CommonAddress, object : ApplicationObject, priority : CommandPriority, now : Int, deadline : Int, idempotency_key : String, source? : String, policy? : RetryPolicy) -> Result[CommandRequest, Diagnostic]pub struct ConfigChange {
key : String
kind : ConfigChangeKind
from : ConfigValue?
to : ConfigValue?
revision : Int
timestamp : Int
operator : String
message : String
} derive(Eq, Debug)pub struct ConfigDefinition {
key : String
description : String
default_value : ConfigValue
required : Bool
minimum : Int?
maximum : Int?
secret : Bool
restart_required : Bool
} derive(Eq, Debug)fn ConfigDefinition::new(key : String, description : String, default_value : ConfigValue, required? : Bool, minimum? : Int, maximum? : Int, secret? : Bool, restart_required? : Bool) -> Result[ConfigDefinition, String]pub struct ConfigEntry {
definition : ConfigDefinition
value : ConfigValue
revision : Int
updated_at : Int
updated_by : String
} derive(Eq, Debug)pub struct ConfigTransaction {
base_revision : Int
operator : String
timestamp : Int
updates : Array[(String, ConfigValue)]
resets : Array[String]
closed : Bool
} derive(Debug)fn ConfigTransaction::new(base_revision : Int, operator : String, timestamp : Int) -> ConfigTransactionfn ConfigTransaction::set(self : ConfigTransaction, key : String, value : ConfigValue) -> Result[Unit, String]pub enum ConfigValue {
ConfigInt(Int)
ConfigBool(Bool)
ConfigText(String)
ConfigDuration(Int)
ConfigAddress(CommonAddress)
ConfigAddressList(Array[CommonAddress])
} derive(Eq, Debug)pub struct ConfigurationRegistry {
definitions : Map[String, ConfigDefinition]
values : Map[String, ConfigEntry]
history : Array[ConfigChange]
history_limit : Int
revision : Int
} derive(Debug)fn ConfigurationRegistry::commit(self : ConfigurationRegistry, transaction : ConfigTransaction) -> Result[Array[ConfigChange], String]fn ConfigurationRegistry::definition(self : ConfigurationRegistry, key : String) -> ConfigDefinition?fn ConfigurationRegistry::register_definition(self : ConfigurationRegistry, definition : ConfigDefinition, timestamp : Int, operator : String) -> Result[Unit, String]fn ConfigurationRegistry::reset(self : ConfigurationRegistry, key : String, timestamp : Int, operator : String) -> Result[ConfigEntry, String]fn ConfigurationRegistry::set(self : ConfigurationRegistry, key : String, value : ConfigValue, timestamp : Int, operator : String) -> Result[ConfigEntry, String]pub struct ConformanceReport {
valid : Bool
type_id : ApplicationType
object_count : Int
expected_width : Int
actual_width : Int
issues : Array[String]
} derive(Eq, Debug)pub struct ConformanceVector {
name : String
category : VectorCategory
input : Bytes
expectation : VectorExpectation
expected_kind : FrameKind?
expected_send : Int?
expected_receive : Int?
expected_payload : Bytes?
} derive(Debug)fn ConformanceVector::new(name : String, category : VectorCategory, input : Bytes, expectation : VectorExpectation, expected_kind? : FrameKind, expected_send? : Int, expected_receive? : Int, expected_payload? : Bytes) -> Result[ConformanceVector, String]fn ConnectionParameters::new(k : Int, w : Int, t0_seconds : Int, t1_seconds : Int, t2_seconds : Int, t3_seconds : Int) -> Result[ConnectionParameters, String]pub struct CounterInterrogationRequest {
common_address : CommonAddress
qualifier : Int
created_at : Int
} derive(Eq, Debug)fn CounterInterrogationRequest::new(common_address : CommonAddress, qualifier : Int, created_at : Int) -> Result[CounterInterrogationRequest, String]pub struct DatabaseEvent {
sequence : Int
timestamp : Int
kind : DatabaseEventKind
common_address : CommonAddress?
point_address : InformationAddress?
message : String
} derive(Eq, Debug)fn DatabaseEvent::new(sequence : Int, timestamp : Int, kind : DatabaseEventKind, common_address? : CommonAddress, point_address? : InformationAddress, message? : String) -> DatabaseEventpub struct DatabaseSnapshot {
revision : Int
timestamp : Int
stations : Array[StationSummary]
events : Array[DatabaseEvent]
} derive(Debug)pub struct DatabaseTransaction {
base_revision : Int
timestamp : Int
additions : Array[StationConfig]
removals : Array[CommonAddress]
states : Array[(CommonAddress, StationStatus, StationStateReason, String)]
points : Array[(CommonAddress, ApplicationObject, String)]
closed : Bool
} derive(Debug)fn DatabaseTransaction::add_station(self : DatabaseTransaction, config : StationConfig) -> Result[Unit, String]fn DatabaseTransaction::remove_station(self : DatabaseTransaction, common_address : CommonAddress) -> Result[Unit, String]fn DatabaseTransaction::set_state(self : DatabaseTransaction, common_address : CommonAddress, status : StationStatus, reason : StationStateReason, message? : String) -> Result[Unit, String]fn DatabaseTransaction::write_point(self : DatabaseTransaction, common_address : CommonAddress, object : ApplicationObject, source? : String) -> Result[Unit, Diagnostic]fn DeadbandRule::changed(self : DeadbandRule, previous : TelemetrySample, current : TelemetrySample) -> Boolfn DeadbandRule::new(absolute? : Float, relative_percent? : Float, minimum_interval? : Int) -> Result[DeadbandRule, String]pub struct DiagnosticCatalog {
records : Map[String, DiagnosticRecord]
history : Array[DiagnosticRecord]
history_limit : Int
metrics : DiagnosticCatalogMetrics
} derive(Debug)fn DiagnosticCatalog::acknowledge(self : DiagnosticCatalog, key : String, operator : String) -> Result[DiagnosticRecord, String]fn DiagnosticCatalog::record_diagnostic(self : DiagnosticCatalog, diagnostic : Diagnostic, severity : DiagnosticSeverity, station : CommonAddress?, timestamp : Int) -> DiagnosticRecordfn DiagnosticCatalog::resolve(self : DiagnosticCatalog, key : String, timestamp : Int) -> Result[DiagnosticRecord, String]pub struct DiagnosticRecord {
key : String
kind : DiagnosticKind
severity : DiagnosticSeverity
message : String
station : CommonAddress?
first_seen : Int
last_seen : Int
occurrences : Int
active : Bool
acknowledged : Bool
acknowledged_by : String?
} derive(Eq, Debug)pub struct FailoverEvent {
station : CommonAddress
from_peer : Int?
to_peer : Int?
reason : FailoverReason
timestamp : Int
fencing_token : Int
message : String
} derive(Eq, Debug)fn FileIdentity::new(station : CommonAddress, name : String, file_id : Int) -> Result[FileIdentity, String]pub struct FileInventoryEntry {
identity : FileIdentity
size : Int
revision : Int
checksum : UInt
updated_at : Int
} derive(Eq, Debug)fn FileSegment::new(file_id : Int, section : Int, offset : Int, data : Bytes, last : Bool) -> Result[FileSegment, String]pub struct FileStore {
files : Map[String, StoredFile]
capacity : Int
maximum_size : Int
} derive(Debug)fn FileStore::put(self : FileStore, identity : FileIdentity, data : Bytes, timestamp : Int) -> Result[StoredFile, String]pub struct FileTransferManager {
store : FileStore
sessions : Map[Int, FileTransferSession]
history : Array[FileTransferSession]
history_limit : Int
next_ticket : Int
metrics : FileTransferMetrics
} derive(Debug)fn FileTransferManager::ack(self : FileTransferManager, ticket : Int, timestamp : Int) -> Result[Unit, String]fn FileTransferManager::activate(self : FileTransferManager, ticket : Int, timestamp : Int) -> Result[Unit, String]fn FileTransferManager::append(self : FileTransferManager, ticket : Int, segment : FileSegment, timestamp : Int) -> Result[FileTransferState, String]fn FileTransferManager::begin_download(self : FileTransferManager, identity : FileIdentity, segment_size? : Int, timestamp? : Int) -> Result[Array[FileSegment], String]fn FileTransferManager::begin_upload(self : FileTransferManager, identity : FileIdentity, expected_size : Int, expected_checksum? : UInt, segment_size? : Int, timestamp? : Int) -> Result[FileTransferSession, String]fn FileTransferManager::cancel(self : FileTransferManager, ticket : Int, timestamp : Int) -> Result[Unit, String]fn FileTransferManager::finish(self : FileTransferManager, ticket : Int, timestamp : Int) -> Result[StoredFile, String]fn FileTransferManager::new(store : FileStore, history_limit? : Int) -> Result[FileTransferManager, String]pub struct FileTransferSession {
ticket : Int
identity : FileIdentity
direction : FileTransferDirection
expected_size : Int
segment_size : Int
expected_checksum : UInt?
buffer : Array[Byte]
next_offset : Int
next_section : Int
state : FileTransferState
attempts : Int
last_activity : Int
error : String
} derive(Debug)fn FileTransferSession::activate(self : FileTransferSession, timestamp : Int) -> Result[Unit, String]fn FileTransferSession::append(self : FileTransferSession, segment : FileSegment, timestamp : Int) -> Result[Unit, String]fn FileTransferSession::new(ticket : Int, identity : FileIdentity, direction : FileTransferDirection, expected_size : Int, segment_size : Int, expected_checksum : UInt?, timestamp : Int) -> Result[FileTransferSession, String]pub struct GatewayAdmissionPolicy {
max_objects : Int
allow_monitoring : Bool
allow_control : Bool
allowed_types : Array[ApplicationType]
denied_types : Array[ApplicationType]
} derive(Eq, Debug)fn GatewayAdmissionPolicy::allow_type(self : GatewayAdmissionPolicy, type_id : ApplicationType) -> Unitfn GatewayAdmissionPolicy::deny_type(self : GatewayAdmissionPolicy, type_id : ApplicationType) -> Unitfn GatewayAdmissionPolicy::evaluate(self : GatewayAdmissionPolicy, envelope : AsduEnvelope) -> Result[Unit, String]fn GatewayAdmissionPolicy::new(max_objects : Int, allow_monitoring? : Bool, allow_control? : Bool) -> Result[GatewayAdmissionPolicy, String]pub enum GatewayDispatch {
Forwarded(GatewayEnvelope, GatewayRoute)
Dropped(GatewayEnvelope, String)
} derive(Debug)pub struct GatewayEnvelope {
ingress : Int
egress : Int
common_address : CommonAddress
asdu : AsduEnvelope
received_at : Int
trace_id : String
} derive(Debug)fn GatewayEnvelope::new(ingress : Int, egress : Int, asdu : AsduEnvelope, received_at : Int, trace_id? : String) -> Result[GatewayEnvelope, String]pub struct GatewayRoute {
id : Int
source : Int
destination : Int
common_address : CommonAddress?
type_ids : Array[ApplicationType]
enabled : Bool
priority : Int
} derive(Eq, Debug)fn GatewayRoute::new(id : Int, source : Int, destination : Int, common_address? : CommonAddress, type_ids? : Array[ApplicationType], priority? : Int) -> Result[GatewayRoute, String]fn GatewayRouteTable::select(self : GatewayRouteTable, source : Int, common_address : CommonAddress, type_id : ApplicationType) -> GatewayRoute?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)fn GatewayRuntime::attach_store(self : GatewayRuntime, binding : GatewayStoreBinding) -> Result[Unit, String]fn GatewayRuntime::enqueue(self : GatewayRuntime, envelope : GatewayEnvelope) -> Result[Unit, String]fn GatewayRuntime::ingest_to_store(self : GatewayRuntime, envelope : GatewayEnvelope) -> Result[Int, String]fn GatewayRuntime::new(max_queue : Int, route_capacity? : Int, policy? : GatewayAdmissionPolicy) -> Result[GatewayRuntime, String]pub struct GatewaySnapshot {
mode : GatewayMode
routes : Int
queue : Int
outbound : Int
dead_letters : Int
counters : GatewayCounters
last_error : String?
} derive(Eq, Debug)pub struct GatewayStoreBinding {
common_address : CommonAddress
store : PointStore
accepted : Int
rejected : Int
} derive(Debug)fn GatewayStoreBinding::ingest(self : GatewayStoreBinding, envelope : GatewayEnvelope) -> Result[Int, String]fn GatewayStoreBinding::new(common_address : CommonAddress, history_limit? : Int) -> Result[GatewayStoreBinding, String]pub struct HealthReport {
state : HealthState
score : Int
checks : Array[String]
warnings : Array[String]
} derive(Eq, Debug)fn HealthReport::new(state : HealthState, score : Int, checks : Array[String], warnings : Array[String]) -> HealthReportpub struct Iec104Runtime {
database : StationDatabase
telemetry : TelemetryPipeline
schedulers : Map[Int, CommandScheduler]
redundancy : Map[Int, RedundancyManager]
policy : OperationalPolicy
redundancy_policy : RedundancyPolicy
files : FileTransferManager
clock : VirtualClock
events : Array[RuntimeEvent]
event_limit : Int
next_event : Int
metrics : RuntimeMetrics
} derive(Debug)fn Iec104Runtime::confirm_command(self : Iec104Runtime, station : CommonAddress, ticket : Int, accepted : Bool, message? : String) -> Result[CommandRequest, Diagnostic]fn Iec104Runtime::dispatch_command(self : Iec104Runtime, station : CommonAddress, policy : CommandPolicy) -> Result[CommandDispatch?, Diagnostic]fn Iec104Runtime::heartbeat(self : Iec104Runtime, station : CommonAddress, peer_id : Int) -> Result[Unit, String]fn Iec104Runtime::ingest(self : Iec104Runtime, station : CommonAddress, object : ApplicationObject, source? : String) -> Result[PipelineResult, Diagnostic]fn Iec104Runtime::register_station(self : Iec104Runtime, config : StationConfig) -> Result[StationSummary, String]fn Iec104Runtime::submit_command(self : Iec104Runtime, operator_id : String, station : CommonAddress, object : ApplicationObject, priority : CommandPriority, deadline : Int, idempotency_key : String) -> Result[CommandRequest, Diagnostic]fn InformationAddress::from_octets(low : Int, middle : Int, high : Int) -> Result[InformationAddress, String]pub struct Interrogation {
request : InterrogationRequest
phase : InterrogationPhase
objects_sent : Int
}pub struct InterrogationPlan {
request : InterrogationRequest
objects : Array[ApplicationObject]
batch_size : Int
cursor : Int
status : ServiceStatus
} derive(Debug)fn InterrogationPlan::new(request : InterrogationRequest, objects : Array[ApplicationObject], batch_size? : Int) -> Result[InterrogationPlan, String]fn InterrogationPlan::next_batch(self : InterrogationPlan) -> Result[Array[ApplicationObject], String]pub struct MaintenanceWindow {
id : Int
station : CommonAddress?
start : Int
end : Int
reason : String
blocks_commands : Bool
blocks_file_writes : Bool
enabled : Bool
} derive(Eq, Debug)fn MaintenanceWindow::contains(self : MaintenanceWindow, station : CommonAddress, timestamp : Int) -> Boolfn MaintenanceWindow::new(id : Int, start : Int, end : Int, reason : String, station? : CommonAddress, blocks_commands? : Bool, blocks_file_writes? : Bool) -> Result[MaintenanceWindow, String]fn NormalizedValue::new(value : Int, quality? : QualityDescriptor) -> Result[NormalizedValue, String]pub struct OperationalPolicy {
rules : Array[PolicyRule]
windows : Array[MaintenanceWindow]
identities : Map[String, OperatorIdentity]
journal : PolicyAuditJournal
revision : Int
} derive(Debug)fn OperationalPolicy::add_identity(self : OperationalPolicy, identity : OperatorIdentity) -> Result[Unit, String]fn OperationalPolicy::add_window(self : OperationalPolicy, window : MaintenanceWindow) -> Result[Unit, String]fn OperationalPolicy::authorize(self : OperationalPolicy, operator_id : String, permission : OperationalPermission, station : CommonAddress, type_id : ApplicationType?, timestamp : Int) -> PolicyDecisionfn OperationalPolicy::remove_identity(self : OperationalPolicy, id : String) -> Result[Unit, String]pub struct OperatorIdentity {
id : String
display_name : String
role : OperatorRole
stations : Array[CommonAddress]
active : Bool
} derive(Eq, Debug)fn OperatorIdentity::new(id : String, display_name : String, role : OperatorRole, stations? : Array[CommonAddress], active? : Bool) -> Result[OperatorIdentity, String]pub struct PipelineResult {
sample : TelemetrySample
accepted : Bool
changed : Bool
rate_valid : Bool
alarms : Array[AlarmEvent]
subscribers : Array[Int]
message : String
} derive(Debug)pub struct PointChange {
kind : PointChangeKind
address : InformationAddress
revision : Int
timestamp : Int
message : String
} derive(Eq, Debug)fn PointChange::new(kind : PointChangeKind, address : InformationAddress, revision : Int, timestamp : Int, message : String) -> PointChangepub struct PointFilter {
direction : PointDirection?
type_id : ApplicationType?
first_address : InformationAddress?
last_address : InformationAddress?
only_valid : Bool
source : String?
} derive(Eq, Debug)fn PointFilter::with_range(self : PointFilter, first : InformationAddress, last : InformationAddress) -> PointFilterpub struct PointRecord {
address : InformationAddress
type_id : ApplicationType
value : ApplicationValue
time_tag : TimeTag?
revision : Int
updated_at : Int
source : String
} derive(Eq, Debug)fn PointRecord::new(object : ApplicationObject, updated_at : Int, revision? : Int, source? : String) -> PointRecordpub struct PointStore {
common_address : CommonAddress
points : Map[Int, PointRecord]
history : Array[PointChange]
history_limit : Int
} derive(Debug)fn PointStore::new(common_address : CommonAddress, history_limit? : Int) -> Result[PointStore, String]fn PointStore::remove(self : PointStore, address : InformationAddress, timestamp : Int) -> Result[PointChange, Diagnostic]fn PointStore::upsert(self : PointStore, object : ApplicationObject, timestamp : Int, source? : String) -> Result[PointChange, Diagnostic]pub struct PolicyAudit {
sequence : Int
timestamp : Int
action : AuditAction
operator : String
station : CommonAddress?
object : InformationAddress?
allowed : Bool
detail : String
} derive(Eq, Debug)pub struct PolicyAuditJournal {
entries : Array[PolicyAudit]
limit : Int
next_sequence : Int
} derive(Debug)fn PolicyAuditJournal::append(self : PolicyAuditJournal, timestamp : Int, action : AuditAction, operator : String, station : CommonAddress?, object : InformationAddress?, allowed : Bool, detail : String) -> PolicyAuditpub struct PolicyDecision {
allowed : Bool
permission : OperationalPermission
operator : String
station : CommonAddress
rule_id : Int?
reason : String
} derive(Eq, Debug)pub struct PolicyRule {
id : Int
permission : OperationalPermission
station : CommonAddress?
type_ids : Array[ApplicationType]
roles : Array[OperatorRole]
enabled : Bool
reason : String
} derive(Eq, Debug)fn PolicyRule::new(id : Int, permission : OperationalPermission, reason : String, station? : CommonAddress, type_ids? : Array[ApplicationType], roles? : Array[OperatorRole]) -> Result[PolicyRule, String]pub struct ProtocolRouter {
rules : Array[RoutingRule]
queues : Map[Int, Array[RoutedObject]]
queue_capacity : Int
metrics : RouterMetrics
sequence : Int
} derive(Debug)fn ProtocolRouter::drain(self : ProtocolRouter, destination : Int, limit : Int) -> Array[RoutedObject]fn ProtocolRouter::evaluate(self : ProtocolRouter, source : Int, destination : Int, object : ApplicationObject) -> RouteDecisionfn ProtocolRouter::route(self : ProtocolRouter, source : Int, destination : Int, object : ApplicationObject, timestamp : Int) -> Result[RouteDecision, Diagnostic]pub struct ProtocolTimers {
t0 : TimerState
t1 : TimerState
t2 : TimerState
t3 : TimerState
} derive(Eq, Debug)pub struct QualityEvaluation {
station : CommonAddress?
address : InformationAddress?
disposition : QualityDisposition
score : Int
age : Int
evaluated_at : Int
rule_id : Int
findings : Array[QualityFinding]
message : String
} derive(Eq, Debug)pub struct QualityGateRule {
id : Int
name : String
max_age : Int
future_skew : Int
require_source : Bool
reject_invalid : Bool
reject_stale : Bool
reject_future : Bool
reject_control : Bool
invalid_penalty : Int
stale_penalty : Int
future_penalty : Int
missing_source_penalty : Int
enabled : Bool
} derive(Eq, Debug)fn QualityGateRule::new(id : Int, name : String, max_age? : Int, future_skew? : Int, require_source? : Bool, reject_invalid? : Bool, reject_stale? : Bool, reject_future? : Bool, reject_control? : Bool, invalid_penalty? : Int, stale_penalty? : Int, future_penalty? : Int, missing_source_penalty? : Int, enabled? : Bool) -> Result[QualityGateRule, String]pub struct QualityPolicyEngine {
rules : Map[Int, QualityGateRule]
station_rules : Map[Int, Int]
history : Array[QualityEvaluation]
history_limit : Int
metrics : QualityPolicyMetrics
} derive(Debug)fn QualityPolicyEngine::accepts_point(self : QualityPolicyEngine, station : CommonAddress, record : PointRecord, now : Int) -> Boolfn QualityPolicyEngine::accepts_sample(self : QualityPolicyEngine, sample : TelemetrySample, now : Int) -> Boolfn QualityPolicyEngine::assign(self : QualityPolicyEngine, station : CommonAddress, rule_id : Int) -> Result[Unit, String]fn QualityPolicyEngine::evaluate_object(self : QualityPolicyEngine, station : CommonAddress, object : ApplicationObject, source : String, timestamp : Int, now : Int) -> QualityEvaluationfn QualityPolicyEngine::evaluate_point(self : QualityPolicyEngine, station : CommonAddress, record : PointRecord, now : Int) -> QualityEvaluationfn QualityPolicyEngine::evaluate_records(self : QualityPolicyEngine, station : CommonAddress, records : Array[PointRecord], now : Int) -> QualityPolicyReportfn QualityPolicyEngine::evaluate_sample(self : QualityPolicyEngine, sample : TelemetrySample, now : Int) -> QualityEvaluationfn QualityPolicyEngine::evaluate_store(self : QualityPolicyEngine, store : PointStore, now : Int) -> QualityPolicyReportfn QualityPolicyEngine::filter_accepted(_self : QualityPolicyEngine, evaluations : Array[QualityEvaluation]) -> Array[QualityEvaluation]fn QualityPolicyEngine::filter_rejected(_self : QualityPolicyEngine, evaluations : Array[QualityEvaluation]) -> Array[QualityEvaluation]fn QualityPolicyEngine::finding_counts(_self : QualityPolicyEngine, evaluations : Array[QualityEvaluation]) -> Map[String, Int]fn QualityPolicyEngine::history_since(self : QualityPolicyEngine, evaluated_at : Int) -> Array[QualityEvaluation]fn QualityPolicyEngine::register_rule(self : QualityPolicyEngine, rule : QualityGateRule) -> Result[Unit, String]fn QualityPolicyEngine::remove_assignment(self : QualityPolicyEngine, station : CommonAddress) -> Boolfn QualityPolicyEngine::replace_rule(self : QualityPolicyEngine, rule : QualityGateRule) -> Result[Unit, String]fn QualityPolicyEngine::station_rule(self : QualityPolicyEngine, station : CommonAddress) -> QualityGateRulefn QualityPolicyEngine::stations_for_rule(self : QualityPolicyEngine, rule_id : Int) -> Array[CommonAddress]pub struct QualityPolicyReport {
total : Int
accepted : Int
degraded : Int
rejected : Int
evaluations : Array[QualityEvaluation]
} derive(Debug)pub struct QualityPolicySnapshot {
rule_count : Int
assignment_count : Int
history_count : Int
metrics : QualityPolicyMetrics
configuration_issues : Array[String]
} derive(Debug)fn ReadTransaction::complete(self : ReadTransaction, object : ApplicationObject) -> Result[ServiceResponse, String]pub struct RedundancyManager {
station : CommonAddress
peers : Map[Int, RedundantPeer]
events : Array[FailoverEvent]
event_limit : Int
policy : RedundancyPolicy
owner : Int?
last_takeover : Int
fencing_token : Int
metrics : RedundancyMetrics
} derive(Debug)fn RedundancyManager::add_peer(self : RedundancyManager, peer : RedundantPeer) -> Result[Unit, String]fn RedundancyManager::heartbeat(self : RedundancyManager, id : Int, now : Int) -> Result[LinkHealth, String]fn RedundancyManager::manual_takeover(self : RedundancyManager, id : Int, now : Int) -> Result[FailoverEvent, String]fn RedundancyManager::new(station : CommonAddress, policy? : RedundancyPolicy, event_limit? : Int) -> Result[RedundancyManager, String]fn RedundancyPolicy::new(heartbeat_interval? : Int, failure_threshold? : Int, recovery_threshold? : Int, takeover_cooldown? : Int, require_fencing? : Bool) -> Result[RedundancyPolicy, String]pub struct RedundantPeer {
id : Int
station : CommonAddress
priority : Int
role : RedundantRole
health : LinkHealth
missed_heartbeats : Int
recovered_heartbeats : Int
last_heartbeat : Int
fencing_token : Int
endpoint : String
} derive(Eq, Debug)fn RedundantPeer::new(id : Int, station : CommonAddress, priority : Int, endpoint : String) -> Result[RedundantPeer, String]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]fn RetryPolicy::new(max_attempts? : Int, timeout? : Int, backoff? : Int, retry_rejected? : Bool) -> Result[RetryPolicy, String]pub struct RouteDecision {
accepted : Bool
rule_id : Int?
action : RoutingAction
source : Int
destination : Int
object : ApplicationObject
reason : String
} derive(Debug)pub struct RoutingRule {
id : Int
source : Int
destination : Int
common_address : CommonAddress?
type_ids : Array[ApplicationType]
action : RoutingAction
priority : Int
enabled : Bool
} derive(Eq, Debug)fn RoutingRule::new(id : Int, source : Int, destination : Int, action : RoutingAction, common_address? : CommonAddress, type_ids? : Array[ApplicationType], priority? : Int) -> Result[RoutingRule, String]pub struct RuntimeConfig {
event_limit : Int
audit_limit : Int
scheduler_audit_limit : Int
file_history_limit : Int
file_capacity : Int
file_maximum_size : Int
telemetry_alarm_limit : Int
redundancy_policy : RedundancyPolicy
} derive(Debug)fn RuntimeConfig::new(event_limit? : Int, audit_limit? : Int, scheduler_audit_limit? : Int, file_history_limit? : Int, file_capacity? : Int, file_maximum_size? : Int, telemetry_alarm_limit? : Int, redundancy_policy? : RedundancyPolicy) -> Result[RuntimeConfig, String]pub struct RuntimeEvent {
sequence : Int
timestamp : Int
kind : RuntimeEventKind
station : CommonAddress?
object : InformationAddress?
correlation : Int
message : String
} derive(Eq, Debug)pub struct Scenario {
name : String
duration : Int
steps : Array[ScenarioStep]
fail_fast : Bool
} derive(Debug)fn Scenario::add(self : Scenario, action : ScenarioAction, at : Int, label : String) -> Result[Unit, String]pub enum ScenarioAction {
WaitScenario(Int)
HeartbeatScenario(Int)
ReceiveApduScenario(Bytes)
SendApduScenario(Bytes)
SetPointScenario(InformationAddress, Int)
RaiseDiagnosticScenario(String)
ClearDiagnosticScenario
CheckpointScenario(String)
} derive(Debug)pub struct ScenarioResult {
name : String
completed : Bool
elapsed : Int
observations : Array[ScenarioObservation]
checkpoints : Array[String]
failures : Array[String]
} derive(Debug)pub struct ScenarioRunner {
context : ScenarioContext
results : Array[ScenarioResult]
run_count : Int
} derive(Debug)pub struct ScenarioStep {
index : Int
at : Int
action : ScenarioAction
label : String
} derive(Debug)fn ScenarioStep::new(index : Int, at : Int, action : ScenarioAction, label : String) -> Result[ScenarioStep, String]pub struct ServiceDefinition {
name : String
kind : SupervisorServiceKind
dependencies : Array[ServiceDependency]
startup_timeout : Int
shutdown_timeout : Int
heartbeat_interval : Int
restart_limit : Int
restart_backoff : Int
enabled : Bool
critical : Bool
tags : Array[String]
} derive(Eq, Debug)fn ServiceDefinition::new(name : String, kind : SupervisorServiceKind, dependencies? : Array[ServiceDependency], startup_timeout? : Int, shutdown_timeout? : Int, heartbeat_interval? : Int, restart_limit? : Int, restart_backoff? : Int, enabled? : Bool, critical? : Bool, tags? : Array[String]) -> Result[ServiceDefinition, String]fn ServiceDependency::new(name : String, required? : Bool, allow_degraded? : Bool) -> Result[ServiceDependency, String]pub struct ServiceEvent {
sequence : Int
timestamp : Int
service : String
kind : ServiceEventKind
detail : String
lifecycle : ServiceLifecycle
health : ServiceHealth
} derive(Eq, Debug)fn ServiceLease::new(owner : String, acquired_at : Int, expires_at : Int, generation : Int) -> Result[ServiceLease, String]pub struct ServiceRecord {
definition : ServiceDefinition
lifecycle : ServiceLifecycle
health : ServiceHealth
restart_count : Int
last_transition : Int
last_heartbeat : Int
last_error : String
generation : Int
lease : ServiceLease?
} derive(Debug)pub struct ServiceRegistry {
records : Map[String, ServiceRecord]
events : Array[ServiceEvent]
event_limit : Int
next_sequence : Int
topology_revision : Int
} derive(Debug)fn ServiceRegistry::acquire_lease(self : ServiceRegistry, name : String, owner : String, timestamp : Int, ttl : Int) -> Result[ServiceLease, String]fn ServiceRegistry::dependencies_ready(self : ServiceRegistry, name : String) -> Result[Bool, String]fn ServiceRegistry::fail(self : ServiceRegistry, name : String, timestamp : Int, message : String) -> Result[ServiceRecord, String]fn ServiceRegistry::heartbeat(self : ServiceRegistry, name : String, timestamp : Int) -> Result[ServiceRecord, String]fn ServiceRegistry::register(self : ServiceRegistry, definition : ServiceDefinition, timestamp : Int) -> Result[ServiceRecord, String]fn ServiceRegistry::release_lease(self : ServiceRegistry, name : String, owner : String, timestamp : Int) -> Result[Unit, String]fn ServiceRegistry::renew_lease(self : ServiceRegistry, name : String, owner : String, timestamp : Int, ttl : Int) -> Result[ServiceLease, String]fn ServiceRegistry::restart(self : ServiceRegistry, name : String, timestamp : Int, reason? : String) -> Result[ServiceRecord, String]fn ServiceRegistry::set_health(self : ServiceRegistry, name : String, health : ServiceHealth, timestamp : Int, detail? : String) -> Result[ServiceRecord, String]fn ServiceRegistry::start(self : ServiceRegistry, name : String, timestamp : Int) -> Result[ServiceRecord, String]fn ServiceRegistry::stop(self : ServiceRegistry, name : String, timestamp : Int, force? : Bool) -> Result[ServiceRecord, String]fn ServiceRegistry::unregister(self : ServiceRegistry, name : String, _timestamp : Int) -> Result[Unit, String]pub struct ServiceRequest {
service : ServiceKind
address : InformationAddress
common_address : CommonAddress
qualifier : Int
created_at : Int
originator : Int
} derive(Eq, Debug)fn ServiceRequest::new(service : ServiceKind, address : InformationAddress, common_address : CommonAddress, qualifier : Int, created_at : Int, originator? : Int) -> Result[ServiceRequest, Diagnostic]pub struct ServiceResponse {
request : ServiceRequest
status : ServiceStatus
cause : CauseOfTransmission
objects : Array[ApplicationObject]
message : String
} derive(Debug)fn ServiceResponse::new(request : ServiceRequest, status : ServiceStatus, cause : CauseOfTransmission, objects : Array[ApplicationObject], message? : String) -> ServiceResponsepub enum SessionAction {
SendStart
SendStop
SendTest
SendSupervisory(Int)
SendInformation(Int)
DeliverInformation(Bytes)
Acknowledge(Int)
Report(Diagnostic)
NoAction
} derive(Debug)pub struct Simulation {
clock : VirtualClock
actions : Array[ScheduledAction]
events : Array[SimulationEvent]
next_ordinal : Int
max_events : Int
} derive(Debug)fn Simulation::schedule(self : Simulation, at : Int, action : SimulationAction) -> Result[Unit, String]pub enum SimulationAction {
Receive(Frame)
Publish(ApplicationObject)
AdvanceTimer(String)
Record(String)
} derive(Debug)pub enum SimulationEvent {
FrameProduced(Int, Frame)
ObjectPublished(Int, ApplicationObject)
TimerAdvanced(Int, String)
Note(Int, String)
SimulationFault(Int, Diagnostic)
} derive(Debug)pub struct StationConfig {
common_address : CommonAddress
name : String
location : String
owner : String
point_capacity : Int
history_limit : Int
heartbeat_interval : Int
tags : Array[String]
enabled : Bool
} derive(Eq, Debug)fn StationConfig::new(common_address : CommonAddress, name : String, location? : String, owner? : String, point_capacity? : Int, history_limit? : Int, heartbeat_interval? : Int, tags? : Array[String], enabled? : Bool) -> Result[StationConfig, String]pub struct StationDatabase {
stations : Map[Int, StationRecord]
events : Array[DatabaseEvent]
event_limit : Int
revision : Int
next_sequence : Int
} derive(Debug)fn StationDatabase::commit(self : StationDatabase, transaction : DatabaseTransaction) -> Result[Array[DatabaseEvent], Diagnostic]fn StationDatabase::compact_events(self : StationDatabase, keep : Int, timestamp : Int) -> Result[Unit, String]fn StationDatabase::heartbeat(self : StationDatabase, common_address : CommonAddress, timestamp : Int) -> Result[StationStateChange?, String]fn StationDatabase::miss_heartbeat(self : StationDatabase, common_address : CommonAddress, timestamp : Int) -> Result[StationStateChange?, String]fn StationDatabase::point_snapshot(self : StationDatabase, common_address : CommonAddress, filter : PointFilter) -> Result[StationPointSnapshot, String]fn StationDatabase::query(self : StationDatabase, query : StationQuery, now : Int) -> Array[StationSummary]fn StationDatabase::read(self : StationDatabase, common_address : CommonAddress, filter : PointFilter) -> Result[Array[PointRecord], String]fn StationDatabase::register(self : StationDatabase, config : StationConfig, timestamp : Int) -> Result[StationSummary, String]fn StationDatabase::set_state(self : StationDatabase, common_address : CommonAddress, status : StationStatus, reason : StationStateReason, timestamp : Int, message? : String) -> Result[StationStateChange, String]fn StationDatabase::summary(self : StationDatabase, common_address : CommonAddress, now : Int) -> Result[StationSummary, String]fn StationDatabase::unregister(self : StationDatabase, common_address : CommonAddress, timestamp : Int) -> Result[Unit, String]fn StationDatabase::write(self : StationDatabase, common_address : CommonAddress, object : ApplicationObject, timestamp : Int, source? : String) -> Result[PointChange, Diagnostic]pub struct StationPointSnapshot {
common_address : CommonAddress
database_revision : Int
station_revision : Int
points : Array[PointRecord]
} derive(Debug)pub struct StationProfile {
name : String
common_address : CommonAddress
parameters : ConnectionParameters
supported_types : Array[ApplicationType]
max_objects : Int
tls_required : Bool
} derive(Debug)fn StationProfile::new(name : String, common_address : CommonAddress, parameters : ConnectionParameters, supported_types : Array[ApplicationType], max_objects? : Int, tls_required? : Bool) -> Result[StationProfile, String]pub struct StationQuery {
status : StationStatus?
tag : String?
name_prefix : String?
include_disabled : Bool
min_points : Int?
max_heartbeat_age : Int?
} derive(Eq, Debug)pub struct StationRecord {
config : StationConfig
store : PointStore
status : StationStatus
last_seen : Int
revision : Int
counters : StationCounters
transitions : Array[StationStateChange]
} derive(Debug)pub struct StationSimulation {
store : PointStore
session : Session
simulation : Simulation
metrics : FrameMetrics
trace : TraceLog
} derive(Debug)fn StationSimulation::ingest(self : StationSimulation, object : ApplicationObject, timestamp : Int) -> Result[PointChange, Diagnostic]fn StationSimulation::new(common_address : CommonAddress, window_size? : Int) -> Result[StationSimulation, String]fn StationSimulation::schedule(self : StationSimulation, at : Int, action : SimulationAction) -> Result[Unit, String]pub struct StationStateChange {
common_address : CommonAddress
from : StationStatus
to : StationStatus
reason : StationStateReason
timestamp : Int
revision : Int
message : String
} derive(Eq, Debug)fn StationStateChange::new(common_address : CommonAddress, from : StationStatus, to : StationStatus, reason : StationStateReason, timestamp : Int, revision : Int, message? : String) -> StationStateChangepub struct StationSummary {
common_address : CommonAddress
name : String
status : StationStatus
point_count : Int
last_seen : Int
revision : Int
valid_points : Int
invalid_points : Int
heartbeat_age : Int
} derive(Eq, Debug)pub struct StepPositionValue {
position : Int
transient : Bool
quality : StatusQuality
} derive(Eq, Debug)fn StepPositionValue::new(position : Int, transient? : Bool, quality? : StatusQuality) -> Result[StepPositionValue, String]pub struct StoreTransaction {
pending : Array[(ApplicationObject, Int, String)]
removed : Array[(InformationAddress, Int)]
committed : Bool
} derive(Debug)fn StoreTransaction::commit(self : StoreTransaction, store : PointStore) -> Result[Array[PointChange], Diagnostic]fn StoreTransaction::stage(self : StoreTransaction, object : ApplicationObject, timestamp : Int, source? : String) -> Result[Unit, Diagnostic]fn StoreTransaction::stage_remove(self : StoreTransaction, address : InformationAddress, timestamp : Int) -> Result[Unit, Diagnostic]pub struct StoredFile {
identity : FileIdentity
data : Bytes
created_at : Int
updated_at : Int
revision : Int
checksum : UInt
} derive(Eq, Debug)pub struct TelemetryPipeline {
samples : Map[Int, TelemetrySample]
aggregates : Map[Int, TelemetryAggregate]
deadbands : Map[Int, DeadbandRule]
rates : Map[Int, RateRule]
alarms : Map[Int, Array[AlarmRule]]
active_alarms : Map[String, Bool]
subscriptions : Array[TelemetrySubscription]
alarm_history : Array[AlarmEvent]
alarm_limit : Int
sequence : Int
metrics : TelemetryMetrics
} derive(Debug)fn TelemetryPipeline::aggregate(self : TelemetryPipeline, address : InformationAddress) -> TelemetryAggregatefn TelemetryPipeline::ingest(self : TelemetryPipeline, station : CommonAddress, object : ApplicationObject, timestamp : Int, source? : String) -> Result[PipelineResult, Diagnostic]fn TelemetryPipeline::latest(self : TelemetryPipeline, address : InformationAddress) -> TelemetrySample?fn TelemetryPipeline::set_alarm_rules(self : TelemetryPipeline, address : InformationAddress, rules : Array[AlarmRule]) -> Unitfn TelemetryPipeline::set_deadband(self : TelemetryPipeline, address : InformationAddress, rule : DeadbandRule) -> Unitfn TelemetryPipeline::set_rate_rule(self : TelemetryPipeline, address : InformationAddress, rule : RateRule) -> Unitfn TelemetryPipeline::subscribe(self : TelemetryPipeline, subscription : TelemetrySubscription) -> Result[Unit, String]pub struct TelemetrySample {
station : CommonAddress
address : InformationAddress
type_id : ApplicationType
value : Float
quality : QualityDescriptor
state : TelemetryState
timestamp : Int
source : String
sequence : Int
} derive(Debug)pub struct TelemetrySubscription {
id : Int
station : CommonAddress?
first_address : InformationAddress?
last_address : InformationAddress?
minimum_state : TelemetryState
include_unchanged : Bool
} derive(Eq, Debug)fn TelemetrySubscription::new(id : Int, station? : CommonAddress, first_address? : InformationAddress, last_address? : InformationAddress, minimum_state? : TelemetryState, include_unchanged? : Bool) -> Result[TelemetrySubscription, String]fn TraceEvent::new(timestamp : Int, kind : TraceKind, detail : String, correlation? : Int) -> TraceEventpub struct TransportEndpoint {
id : Int
station : CommonAddress
parameters : ConnectionParameters
window : SequenceWindow
decoder : ApduStreamDecoder
state : ManagedTransportState
last_activity : Int
last_send : Int
last_receive : Int
sent_frames : Int
received_frames : Int
malformed_frames : Int
} derive(Debug)fn TransportEndpoint::new(id : Int, station : CommonAddress, parameters : ConnectionParameters, window_capacity : Int, max_apdu? : Int) -> Result[TransportEndpoint, String]fn TransportEndpoint::receive(self : TransportEndpoint, data : Bytes, timestamp : Int) -> Result[Array[Frame], Diagnostic]fn TransportEndpoint::send(self : TransportEndpoint, payload : Bytes, timestamp : Int) -> Result[Bytes, Diagnostic]pub struct TransportEvent {
sequence : Int
timestamp : Int
kind : TransportEventKind
endpoint : Int
frame_size : Int
detail : String
} derive(Eq, Debug)pub struct TransportManager {
endpoints : Map[Int, TransportEndpoint]
events : Array[TransportEvent]
event_limit : Int
next_event : Int
metrics : TransportManagerMetrics
} derive(Debug)fn TransportManager::add(self : TransportManager, endpoint : TransportEndpoint) -> Result[Unit, String]fn TransportManager::close(self : TransportManager, id : Int, timestamp : Int) -> Result[Unit, String]fn TransportManager::open(self : TransportManager, id : Int, timestamp : Int) -> Result[Bytes, String]fn TransportManager::receive(self : TransportManager, id : Int, data : Bytes, timestamp : Int) -> Result[Array[Frame], Diagnostic]fn TransportManager::send(self : TransportManager, id : Int, payload : Bytes, timestamp : Int) -> Result[Bytes, Diagnostic]pub struct TypeDescriptor {
type_id : ApplicationType
name : String
direction : PointDirection
time_tag : TimeTagKind
value_width : Int
supported : Bool
command : Bool
} derive(Eq, Debug)pub struct ValidationIssue {
kind : ValidationIssueKind
path : String
message : String
address : InformationAddress?
fatal : Bool
} derive(Eq, Debug)fn ValidationProfile::new(max_points? : Int, max_history? : Int, require_time_tag_for_events? : Bool, reject_unknown_types? : Bool, require_non_global_station? : Bool) -> Result[ValidationProfile, String]pub struct ValidationReport {
subject : String
valid : Bool
issues : Array[ValidationIssue]
checked : Int
} derive(Debug)pub struct VectorCatalog {
vectors : Array[ConformanceVector]
names : Map[String, Bool]
} derive(Debug)fn VectorCatalog::add_all(self : VectorCatalog, vectors : Array[ConformanceVector]) -> Result[Unit, String]pub struct VectorReport {
total : Int
passed : Int
failed : Int
rejected : Int
bytes : Int
results : Array[VectorResult]
} derive(Debug)pub struct VectorResult {
name : String
passed : Bool
decoded : Bool
encoded_size : Int
mismatches : Array[VectorMismatch]
message : String
} derive(Debug)pub struct WorkloadResult {
workload : ApplicationBenchmarkWorkload
iterations : Int
accepted : Int
rejected : Int
bytes : Int
checksum : UInt
detail : String
} derive(Eq, Debug)fn admit_inbound(data : Bytes, limits : ResourceLimits, replay : ReplayGuard, now : Int) -> Result[Frame, Diagnostic]fn binary_counter_object(address : InformationAddress, value : UInt, sequence? : Int, time_tag? : TimeTag) -> Result[ApplicationObject, String]fn bit_string_object(address : InformationAddress, value : UInt, time_tag? : TimeTag) -> Result[ApplicationObject, String]fn calendar_weekday(year : Int, month : Int, day : Int) -> Result[Int, String]fn clock_sync_object(address : InformationAddress, value : Cp56Time) -> Result[ApplicationObject, String]fn counter_interrogation_object(address : InformationAddress, qualifier : Int) -> Result[ApplicationObject, String]fn crc16_ibm(data : Bytes) -> UIntfn crc32_ieee(data : Bytes) -> UIntfn create_interrogation_plan(store : PointStore, request : InterrogationRequest, filter : PointFilter, batch_size? : Int) -> Result[InterrogationPlan, String]fn days_in_month(year : Int, month : Int) -> Int?fn decode_signed16(low : Int, high : Int) -> Result[Int, String]fn double_command_object(address : InformationAddress, state : Int, qualifier : Int) -> Result[ApplicationObject, String]fn double_point_object(address : InformationAddress, state : Int, quality? : StatusQuality, time_tag? : TimeTag) -> Result[ApplicationObject, String]fn end_of_initialization_object(address : InformationAddress, value : Int) -> Result[ApplicationObject, String]fn hex_digit(value : Int) -> Charfn interrogation_object(address : InformationAddress, qualifier : Int) -> Result[ApplicationObject, String]fn milliseconds_since_midnight(hour : Int, minute : Int, second : Int, millisecond : Int) -> Result[Int, String]fn negotiate_profiles(local_profile : StationProfile, remote : StationProfile) -> NegotiationDecisionfn normalize_quality(value : Int) -> Intfn normalized_object(address : InformationAddress, value : Int, quality? : QualityDescriptor, time_tag? : TimeTag) -> Result[ApplicationObject, String]fn normalized_set_point_object(address : InformationAddress, value : Int, qualifier : Int) -> Result[ApplicationObject, String]fn normalized_value_asdu(cause : Int, common_address : Int, value : Int, quality : Int) -> Bytesfn ordinal_day(year : Int, month : Int, day : Int) -> Result[Int, String]fn parse_vsq(value : Int) -> Result[(Int, Bool), String]fn regulating_step_command_object(address : InformationAddress, step : Int, qualifier : Int) -> Result[ApplicationObject, String]fn reset_command_object(address : InformationAddress, value : Int) -> Result[ApplicationObject, String]fn scaled_object(address : InformationAddress, value : Int, quality? : QualityDescriptor, time_tag? : TimeTag) -> Result[ApplicationObject, String]fn scaled_set_point_object(address : InformationAddress, value : Int, qualifier : Int) -> Result[ApplicationObject, String]fn sequence_acknowledges(send_cursor : Int, acknowledgement : Int) -> Boolfn sequence_before(start : Int, candidate : Int, limit : Int) -> Boolfn sequence_distance(start : Int, end : Int) -> Intfn sequence_next(value : Int) -> Intfn sequence_normalize(value : Int) -> Intfn sequence_previous(value : Int) -> Intfn short_float_object(address : InformationAddress, value : Float, quality? : QualityDescriptor, time_tag? : TimeTag) -> Result[ApplicationObject, String]fn short_float_set_point_object(address : InformationAddress, value : Float, qualifier : Int) -> Result[ApplicationObject, String]fn single_command_object(address : InformationAddress, state : Bool, qualifier : Int) -> Result[ApplicationObject, String]fn single_object_asdu(object : ApplicationObject, cause : CauseOfTransmission, common_address : CommonAddress) -> Result[AsduEnvelope, Diagnostic]fn single_point_asdu(cause : Int, common_address : Int, ioa : Int, status : Bool, quality : Int) -> Bytesfn single_point_object(address : InformationAddress, state : Bool, quality? : StatusQuality, time_tag? : TimeTag) -> Result[ApplicationObject, String]fn split_milliseconds_since_midnight(value : Int) -> Result[(Int, Int, Int, Int), String]fn step_position_object(address : InformationAddress, position : Int, transient? : Bool, quality? : StatusQuality, time_tag? : TimeTag) -> Result[ApplicationObject, String]fn test_command_object(address : InformationAddress, value : Int) -> Result[ApplicationObject, String]fn validate_application_object(object : ApplicationObject, profile : ValidationProfile) -> ValidationReportInstall
Download zipPortable IEC 60870-5-104 protocol core for SCADA, gateways, and deterministic simulation.