Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
8fd2d6c
Rebase server control and URCB adapters onto portable consolidation
masarray Aug 11, 2026
b5a659a
Use current IoResult transferred field in URCB adapter
masarray Aug 11, 2026
2f4624f
Harden MMS server build against incomplete working trees
masarray Aug 11, 2026
343f106
Sync owner-bound BRCB delivery contract from server base
masarray Aug 11, 2026
2d2412b
Sync two-phase BRCB delivery implementation from server base
masarray Aug 11, 2026
5588407
Sync BRCB owner-bound delivery regression from server base
masarray Aug 11, 2026
1d0a112
fix(mms-server): accept optional InitiateRequest fields
masarray Aug 11, 2026
3c1152e
fix(mms-server): tolerate optional ACSE association fields
masarray Aug 11, 2026
39d2a0b
feat(mms-server): port engineering-client discovery compatibility
masarray Aug 11, 2026
8fa00dd
refactor(mms-server): keep dispatcher strict and move client compatib…
masarray Aug 11, 2026
0600910
feat(mms-server): add engineering-client MMS compatibility primitives
masarray Aug 11, 2026
e36c225
feat(mms-server): encode Identify errors and Conclude response
masarray Aug 11, 2026
0279b0d
feat(mms-server): port engineering-client session compatibility
masarray Aug 11, 2026
8b2b8ef
test(mms-server): prove engineering-client runtime compatibility
masarray Aug 11, 2026
a058384
feat(mms-server): add bounded legacy association compatibility inspector
masarray Aug 11, 2026
ee210eb
feat(mms-server): port tolerant ARIEC61850 AARQ inspection path
masarray Aug 11, 2026
bd88352
feat(mms-server): expose bounded association compatibility decoder
masarray Aug 11, 2026
adb4c8a
feat(mms-server): port tolerant legacy association inspection into AC…
masarray Aug 11, 2026
d458df9
fix(mms-server): use legacy-compatible AARQ inspection for live server
masarray Aug 11, 2026
ccd4be3
chore(mms-server): remove superseded standalone association compat he…
masarray Aug 11, 2026
c32d039
chore(mms-server): remove superseded standalone association compat so…
masarray Aug 11, 2026
113d2a1
test(mms-server): prove strict rejection and legacy-compatible AARQ f…
masarray Aug 11, 2026
048a2ee
chore(mms-server): print terminal session diagnostics for live IEDScout
masarray Aug 11, 2026
b140d9e
feat(mms-server): add bounded COTP reassembly policy and negotiated T…
masarray Aug 11, 2026
6337405
feat(mms-server): port bounded COTP segmentation and reassembly
masarray Aug 11, 2026
c9da1c0
refactor(mms-server): allow workspace-backed COTP reassembly
masarray Aug 11, 2026
791495c
refactor(mms-server): borrow stable workspace for segmented request r…
masarray Aug 11, 2026
13fbf2a
test(mms-server): prove bounded COTP Data reassembly across EOT
masarray Aug 11, 2026
5d3774f
ci: temporarily expose MMS runtime smoke exit code
masarray Aug 11, 2026
6b56049
ci: pinpoint segmented MMS runtime regression
masarray Aug 11, 2026
abd425b
ci: install debugger for one-shot MMS runtime diagnosis
masarray Aug 11, 2026
4ccfa6b
ci: turn MMS diagnostic into one-shot parity finalizer
masarray Aug 11, 2026
9e95a02
ci: stage deterministic MMS server parity patcher
masarray Aug 11, 2026
29770ad
ci: run MMS parity patcher as bounded finalizer
masarray Aug 11, 2026
638acfe
ci: trigger MMS parity finalizer from PR synchronization
masarray Aug 11, 2026
1af117b
ci: qualify MMS parity smoke symbols
masarray Aug 11, 2026
a677982
ci: apply namespace fix in MMS parity finalizer
masarray Aug 11, 2026
2bbe40f
mms-server: finalize engineering-client parity tranche
github-actions[bot] Aug 11, 2026
c17bfaa
ci: remove one-shot MMS parity finalizer
masarray Aug 11, 2026
ffe67e2
ci: remove one-shot MMS parity patcher
masarray Aug 11, 2026
c794abc
ci: remove one-shot MMS parity namespace helper
masarray Aug 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/mms-server-direct-control-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: MMS Direct Control Server CI

on:
push:
branches: ["agent/mms-server-direct-normal-control"]
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
cc: gcc
cxx: g++
- os: ubuntu-latest
cc: clang
cxx: clang++
- os: windows-latest
cc: ""
cxx: ""
runs-on: ${{ matrix.os }}
env:
CC: ${{ matrix.cc }}
CXX: ${{ matrix.cxx }}
steps:
- uses: actions/checkout@v4
- name: Configure
run: cmake -S tools/mms_direct_control_server -B build-mms-direct-control -DCMAKE_BUILD_TYPE=Release
- name: Build
run: cmake --build build-mms-direct-control --config Release --parallel
- name: Unit and help contract
run: ctest --test-dir build-mms-direct-control -C Release --output-on-failure
63 changes: 63 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ add_library(ariec61850_mms_server_core
src/mms/static_dispatcher.cpp
src/mms/connection_runtime.cpp
src/mms/static_server_session.cpp
src/mms/static_direct_control.cpp
src/mms/static_information_report.cpp
src/mms/static_report_connection.cpp
src/mms/static_urcb_objects.cpp
src/mms/static_urcb_runtime.cpp
src/mms/static_brcb_runtime.cpp
src/mms/static_brcb_control.cpp
src/mms/static_brcb_objects.cpp
Expand Down Expand Up @@ -195,6 +200,32 @@ if(ARIEC61850_BUILD_TOOLS)
target_compile_features(ariec61850_static_ied_server PRIVATE cxx_std_20)
ariec61850_apply_warnings(ariec61850_static_ied_server)
ariec61850_apply_sanitizers(ariec61850_static_ied_server)

add_executable(
ariec61850_mms_direct_control_server
tools/mms_direct_control_server.cpp)
target_link_libraries(
ariec61850_mms_direct_control_server
PRIVATE ARIEC61850::mms_server_core ARIEC61850::core)
if(WIN32)
target_link_libraries(ariec61850_mms_direct_control_server PRIVATE ws2_32)
endif()
target_compile_features(ariec61850_mms_direct_control_server PRIVATE cxx_std_20)
ariec61850_apply_warnings(ariec61850_mms_direct_control_server)
ariec61850_apply_sanitizers(ariec61850_mms_direct_control_server)

add_executable(
ariec61850_mms_urcb_server
tools/mms_urcb_server.cpp)
target_link_libraries(
ariec61850_mms_urcb_server
PRIVATE ARIEC61850::mms_server_core ARIEC61850::core)
if(WIN32)
target_link_libraries(ariec61850_mms_urcb_server PRIVATE ws2_32)
endif()
target_compile_features(ariec61850_mms_urcb_server PRIVATE cxx_std_20)
ariec61850_apply_warnings(ariec61850_mms_urcb_server)
ariec61850_apply_sanitizers(ariec61850_mms_urcb_server)
endif()

if(ARIEC61850_BUILD_TESTS)
Expand Down Expand Up @@ -397,6 +428,32 @@ if(ARIEC61850_BUILD_TESTS)
NAME ariec61850_mms_connection_runtime_tests
COMMAND ariec61850_mms_connection_runtime_tests)

add_executable(
ariec61850_mms_direct_control_tests
tests/test_mms_static_direct_control.cpp)
target_link_libraries(
ariec61850_mms_direct_control_tests
PRIVATE ARIEC61850::mms_server_core ARIEC61850::core)
target_compile_features(ariec61850_mms_direct_control_tests PRIVATE cxx_std_20)
ariec61850_apply_warnings(ariec61850_mms_direct_control_tests)
ariec61850_apply_sanitizers(ariec61850_mms_direct_control_tests)
add_test(
NAME ariec61850_mms_direct_control_tests
COMMAND ariec61850_mms_direct_control_tests)

add_executable(
ariec61850_mms_server_urcb_tests
tests/test_mms_server_urcb_report.cpp)
target_link_libraries(
ariec61850_mms_server_urcb_tests
PRIVATE ARIEC61850::mms_server_core ARIEC61850::core)
target_compile_features(ariec61850_mms_server_urcb_tests PRIVATE cxx_std_20)
ariec61850_apply_warnings(ariec61850_mms_server_urcb_tests)
ariec61850_apply_sanitizers(ariec61850_mms_server_urcb_tests)
add_test(
NAME ariec61850_mms_server_urcb_tests
COMMAND ariec61850_mms_server_urcb_tests)

foreach(brcb_smoke IN ITEMS
mms_brcb
mms_brcb_control
Expand Down Expand Up @@ -436,6 +493,12 @@ if(ARIEC61850_BUILD_TESTS)
add_test(
NAME ariec61850_static_ied_server_help
COMMAND ariec61850_static_ied_server --help)
add_test(
NAME ariec61850_mms_direct_control_server_help
COMMAND ariec61850_mms_direct_control_server --help)
add_test(
NAME ariec61850_mms_urcb_server_help
COMMAND ariec61850_mms_urcb_server --help)
endif()
endif()

Expand Down
113 changes: 113 additions & 0 deletions docs/MMS_SERVER_DIRECT_CONTROL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# MMS Server Direct-Normal Control Trial

This slice advances the clean MMS server prototype from read-only browse/read to a bounded, explicitly writable IEC 61850 control target.

## Implemented server model

Domain: `ESP32S3IOLD0`

Logical Nodes:

- `LLN0`
- `LPHD1`
- `GGIO1`

Read-only digital inputs:

- `GGIO1.Ind1` .. `GGIO1.Ind8`

Direct-with-normal-security Boolean controls:

- `ESP32S3IOLD0/GGIO1.SPCSO1`
- `ESP32S3IOLD0/GGIO1.SPCSO2`
- ...
- `ESP32S3IOLD0/GGIO1.SPCSO8`

Each control exposes:

- `ST$SPCSO<n>$stVal`
- `CF$SPCSO<n>$ctlModel` = `1` (Direct-with-normal-security)
- `CO$SPCSO<n>$Oper`

The live `Oper` TypeSpecification is the bounded SPC shape:

1. `ctlVal` Boolean
2. `origin` structure (`orCat` Unsigned, `orIdent` OctetString)
3. `ctlNum` Unsigned
4. `T` UTC time
5. `Test` Boolean
6. `Check` 2-bit BitString

A static non-deletable DataSet is also exposed:

`ESP32S3IOLD0/LLN0.Outputs`

It contains the eight `SPCSO<n>.stVal` status leaves and is intended to become the first static reporting DataSet in the next server-side RCB tranche.

## Safety semantics

The `Oper` decoder is allocation-free and rejects malformed or unexpected structures.

- `ctlNum=0` is rejected.
- origin category outside the bounded IEC range is rejected.
- synchro/interlock Check requests are fail-closed by default because this prototype does not yet implement those plant checks.
- `Test=true` is accepted but does not change the live output state.
- an application/hardware apply callback can reject the command before the published status changes.
- there is no command retry.

This tranche implements only Direct-with-normal-security. SBO and enhanced-security CommandTermination belong to later server slices.

## Windows build

```powershell
powershell.exe -ExecutionPolicy Bypass -File .\scripts\build_mms_direct_control_server.ps1
```

The script configures, builds, and runs the direct-control unit/help contract.

## Run

Use a non-privileged lab port first:

```powershell
.\build-mms-direct-control\Release\ariec61850_mms_direct_control_server.exe `
--bind 0.0.0.0 `
--port 8102 `
--di-mask 0x55 `
--do-mask 0x00
```

Expected startup marker:

```text
MMS_DIRECT_CONTROL_SERVER_READY ... controls=8 ctlModel=1 dataset=ESP32S3IOLD0/LLN0.Outputs
```

For a standards-port laboratory run, use TCP 102 only when the host privileges/firewall configuration allow it.

## IEDScout trial

Connect IEDScout as an MMS/IEC 61850 client to the host running this executable.

Browse `ESP32S3IOLD0/GGIO1` and verify that `SPCSO1..8` expose `ctlModel=1`, `Oper`, and `stVal`. Operate one Boolean output and then read its `stVal`.

After the client disconnects, the server prints a summary such as:

```text
MMS_DIRECT_CONTROL_STATE doMask=1 acceptedOps=1 rejectedOps=0
```

Retain terminal output and a PCAP/PCAPNG for interoperability evidence. This is simulator/server interoperability evidence, not IEC 61850 conformance certification.

## Current boundary / next server tranche

Still pending after this slice:

1. server-side URCB/BRCB objects and InformationReport transmission;
2. static DataSet report binding and GI/event triggers;
3. SBO normal and enhanced control plus CommandTermination/LastApplError;
4. concurrent-client ownership/contention;
5. server-side FileDirectory/FileOpen/FileRead/FileClose;
6. GPIO/lwIP adapter on the target ESP board;
7. runtime SCL/CID-driven model generation;
8. TLS/security profiles and broader multi-vendor evidence.
107 changes: 107 additions & 0 deletions docs/MMS_SERVER_URCB_REPORT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# MMS Server Static URCB / InformationReport Trial

This tranche adds a runnable server-side unbuffered report path on top of the bounded MMS server core.

## Model

Domain: `ESP32S3IOLD0`

Static DataSet:

`ESP32S3IOLD0/LLN0.Outputs`

Members, in fixed order:

- `GGIO1$ST$SPCSO1$stVal`
- `GGIO1$ST$SPCSO2$stVal`
- `GGIO1$ST$SPCSO3$stVal`
- `GGIO1$ST$SPCSO4$stVal`
- `GGIO1$ST$SPCSO5$stVal`
- `GGIO1$ST$SPCSO6$stVal`
- `GGIO1$ST$SPCSO7$stVal`
- `GGIO1$ST$SPCSO8$stVal`

URCB:

`ESP32S3IOLD0/LLN0$RP$Outputs01`

Default `RptID`: `ARSTACK-Outputs01`.

The object bank exposes `RptID`, `RptEna`, `Resv`, `DatSet`, `ConfRev`, `OptFlds`, `BufTm`, `TrgOps`, `IntgPd`, `GI`, and `SqNum` as MMS variables.

## First acceptance profile

The first live gate is deliberately deterministic and GI-driven:

1. associate;
2. inspect the static DataSet and URCB;
3. reserve the URCB if the client uses `Resv`;
4. set `RptEna=true`;
5. set `GI=true`;
6. receive one MMS `InformationReport` carrying all eight ordered DataSet values;
7. verify `SqNum` advances only after a complete report frame is encoded;
8. disable/release and disconnect.

The initial `OptFlds` enable sequence number, reason, DataSet name, data references, and configuration revision. Report time is intentionally omitted in this first profile so timestamp semantics do not obscure the basic interoperability gate.

## Safety and ownership boundary

This executable currently serves one client at a time.

`RptEna` and `Resv` are explicitly reset to false at connection boundaries so one disconnected client cannot leave a live reservation/enable state for the next client.

No dynamic DataSet mutation is available on this server. `LLN0.Outputs` is static and non-deletable.

No automatic report-control takeover or retry is performed.

## Build

```powershell
powershell.exe -ExecutionPolicy Bypass -File .\scripts\build_mms_direct_control_server.ps1
```

The helper builds/tests both server trial executables.

## Run

```powershell
.\build-mms-direct-control\Release\ariec61850_mms_urcb_server.exe `
--bind 0.0.0.0 `
--port 8102 `
--mask 0x55
```

Expected startup marker:

```text
MMS_URCB_SERVER_READY ... dataset=ESP32S3IOLD0/LLN0.Outputs urcb=ESP32S3IOLD0/LLN0$RP$Outputs01 members=8 ...
```

On each emitted report the server prints:

```text
MMS_URCB_REPORT_SENT index=0 sqNum=<n> reason=8 bytes=<n>
```

Reason `8` is General Interrogation.

For TCP 102, use a laboratory host configuration that permits binding the standard MMS port.

## IEDScout trial

Connect IEDScout to the server host and browse `ESP32S3IOLD0`.

Verify the `LLN0.Outputs` DataSet and `LLN0$RP$Outputs01` URCB are visible. Enable the report and issue GI. The expected evidence is one report with eight Boolean values matching the configured `--mask` bit order.

Retain console output and PCAP/PCAPNG. Until this live run is performed, this tranche is classified as software/offline-tested rather than live-proven server interoperability.

## Still pending

- event-on-change/data-change triggering;
- multiple URCBs and concurrent-client ownership;
- BRCB retention/replay/EntryID/PurgeBuf on the runnable server adapter;
- Direct/SBO enhanced server control and CommandTermination;
- server-side MMS file services;
- GPIO/lwIP hardware adapter;
- runtime SCL/CID model generation;
- TLS/security profiles and broader multi-vendor evidence.
Loading
Loading