Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
3d3ec5d
P6E: define bounded multi-IED workspace owner
masarray Sep 26, 2026
289dc69
P6E: own independent IED contexts and service associations per workspace
masarray Sep 26, 2026
82a5175
P6E: expose read-only SCL source for per-IED workspace fork
masarray Sep 26, 2026
953c0a6
P6E: render independent persistent IED Browser tabs and active servic…
masarray Sep 26, 2026
662793c
P6E: add per-IED SCL source fork and new Browser workspace flow
masarray Sep 26, 2026
72403e9
P6E: retain trusted SCL provenance for each cloned IED
masarray Sep 26, 2026
57b93ba
P6E: build fleet owner in app and Browser session QA
masarray Sep 26, 2026
709e12d
P6E: behavioral QA for isolated IED slots, switching, SCL fork and bo…
masarray Sep 26, 2026
b5af7ce
P6E: expose event-driven Global Data snapshot per IED
masarray Sep 26, 2026
1a82fff
P6E: expose per-IED Global Data events to fleet view
masarray Sep 26, 2026
af2aa15
P6E: aggregate event-driven Global Data from independent IED slots
masarray Sep 26, 2026
ada2d32
P6E: expose all-IED Global Data without merging device associations
masarray Sep 26, 2026
5f2ea12
P6E: package cross-IED Global Data view
masarray Sep 26, 2026
9de66fb
P6E: route File Home SCL ingress into a fresh isolated IED slot
masarray Sep 26, 2026
35d8c99
P6E: isolate every File/Home SCL and Discover ingress
masarray Sep 26, 2026
f5096a2
P6E: isolate recent SCL/IED ingress even while another slot is online
masarray Sep 26, 2026
10cc053
P6E: support exact SCL provenance adoption per workspace
masarray Sep 26, 2026
ddfab19
P6E: copy exact SCL evidence without changing active IED context
masarray Sep 26, 2026
e7af803
P6E: retain per-IED exact-source Save As capability on SCL fork
masarray Sep 26, 2026
e7aa919
P6E: permanent multi-IED ownership and routing contract
masarray Sep 26, 2026
6f109c8
P6E: gate multi-IED architecture and static reporting protection in CI
masarray Sep 26, 2026
128b0fd
P6E: retire closed IED services after model and QML bindings update
masarray Sep 26, 2026
d3d08a1
P6E: guard post-view lifetime order when closing IED slots
masarray Sep 26, 2026
ca51539
P6E: retain P6B control contract with per-IED service instances
masarray Sep 26, 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
13 changes: 13 additions & 0 deletions .github/workflows/ied-simulator-qt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,19 @@ jobs:
apps/ied_simulator/qml/GooseWorkspace.qml
apps/ied_simulator/qml/CommissioningWorkspace.qml

- name: P6E Multi-IED workspace authority contract
run: >-
python3 apps/ied_simulator/test_multi_ied_workspace.py
apps/ied_simulator/src/IedBrowserFleetController.cpp
apps/ied_simulator/src/IedBrowserFleetController.hpp
apps/ied_simulator/qml/Main.qml
apps/ied_simulator/qml/IedBrowserWorkspace.qml
apps/ied_simulator/qml/FileWorkspace.qml
apps/ied_simulator/qml/FleetGlobalDataPane.qml
apps/ied_simulator/qml/BrowserGlobalDataPane.qml
apps/ied_simulator/src/SclWorkspaceController_part_01.inc
apps/ied_simulator/src/MmsReportController.cpp

- name: P6D passive MMS capture and decoder contract
run: >-
python3 apps/ied_simulator/test_passive_mms_sniffer.py
Expand Down
7 changes: 7 additions & 0 deletions apps/ied_simulator/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ qt_add_qml_module(arstack_ied_simulator
src/MmsControlController.hpp
src/IedBrowserSessionController.cpp
src/IedBrowserSessionController.hpp
src/IedBrowserFleetController.cpp
src/IedBrowserFleetController.hpp
src/MmsReportController.cpp
src/MmsReportController.hpp
src/MmsSettingGroupPolicy.hpp
Expand Down Expand Up @@ -103,6 +105,7 @@ qt_add_qml_module(arstack_ied_simulator
qml/BrowserDataSetPane.qml
qml/BrowserGoosePane.qml
qml/BrowserGlobalDataPane.qml
qml/FleetGlobalDataPane.qml
qml/BrowserControlDialog.qml
qml/BrowserDataSetAuthoringDialog.qml
qml/BrowserReportAuthoringDialog.qml
Expand Down Expand Up @@ -355,6 +358,10 @@ add_executable(ied_browser_session_qa
src/ied_browser_session_qa.cpp
src/IedBrowserSessionController.cpp
src/IedBrowserSessionController.hpp
src/IedBrowserFleetController.cpp
src/IedBrowserFleetController.hpp
src/SclWorkspaceController.cpp
src/SclWorkspaceController.hpp
src/MmsLiveTreeModel.cpp
src/MmsLiveTreeModel.hpp
src/IedEngineeringContextController.cpp
Expand Down
21 changes: 21 additions & 0 deletions apps/ied_simulator/qml/BrowserGlobalDataPane.qml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,31 @@ Rectangle {

readonly property int maximumEntries: 256
readonly property int watchCount: watchModel.count
signal watchSnapshotChanged()
property int boundContextGeneration: context.contextGeneration
property string statusMessage: "Add DataAttributes, DataSets, Reports, or configured GOOSE from the Browser."

color: theme.background

ListModel { id: watchModel }

function snapshotRows() {
var entries = []
for (var i = 0; i < watchModel.count; ++i) {
var row = watchModel.get(i)
entries.push({
"kind": row.kind,
"reference": row.reference,
"detail": row.detail,
"value": row.value,
"quality": row.quality,
"timestamp": row.timestamp,
"status": row.status
})
}
return entries
}

function indexFor(kind, reference) {
for (var i = 0; i < watchModel.count; ++i) {
var row = watchModel.get(i)
Expand Down Expand Up @@ -102,13 +120,15 @@ Rectangle {
if (row < 0 || row >= watchModel.count)
return
watchModel.remove(row)
root.watchSnapshotChanged()
statusMessage = watchModel.count > 0
? String(watchModel.count) + " monitored object(s)."
: "Global Data is empty."
}

function clearAll() {
watchModel.clear()
root.watchSnapshotChanged()
statusMessage = "Global Data cleared."
}

Expand Down Expand Up @@ -178,6 +198,7 @@ Rectangle {
watchModel.setProperty(i, "status", context.online ? "CONFIGURED" : "OFFLINE")
}
}
root.watchSnapshotChanged()
}

Connections {
Expand Down
20 changes: 8 additions & 12 deletions apps/ied_simulator/qml/FileWorkspace.qml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Item {
property int viewIndex: 0

signal browserRequested()
signal openSourceRequested(url fileUrl)
signal discoverRequested(string host, int port)
signal endpointRequested(string host, int port)
signal simulatorRequested()
Expand All @@ -32,10 +33,7 @@ Item {
title: "Open IEC 61850 engineering model"
fileMode: FileDialog.OpenFile
nameFilters: ["IEC 61850 engineering files (*.scl *.cid *.scd *.iid *.icd)", "All files (*)"]
onAccepted: {
if (workspace.openFile(selectedFile))
root.browserRequested()
}
onAccepted: root.openSourceRequested(selectedFile)
}

Dialog {
Expand Down Expand Up @@ -164,14 +162,14 @@ Item {
theme: root.theme
text: "Open SCL"
primary: true
enabled: !workspace.busy && !browserSession.configurationLocked
enabled: !workspace.busy
onClicked: openDialog.open()
}

ActionButton {
theme: root.theme
text: "Discover IED"
enabled: !browserSession.configurationLocked
enabled: true
onClicked: discoverDialog.open()
}

Expand Down Expand Up @@ -245,7 +243,7 @@ Item {
theme: root.theme
text: "Open SCL"
primary: true
enabled: !workspace.busy && !browserSession.configurationLocked
enabled: !workspace.busy
onClicked: openDialog.open()
}
}
Expand All @@ -271,7 +269,7 @@ Item {
ActionButton {
theme: root.theme
text: "Discover IED"
enabled: !browserSession.configurationLocked
enabled: true
onClicked: discoverDialog.open()
}
}
Expand Down Expand Up @@ -441,10 +439,8 @@ Item {
hoverEnabled: true
enabled: hardening.recentResourceExists(index)
&& !workspace.busy
&& !browserSession.configurationLocked
onClicked: {
if (workspace.openFile(hardening.recentResourceUrl(index)))
root.browserRequested()
root.openSourceRequested(hardening.recentResourceUrl(index))
}
}
}
Expand Down Expand Up @@ -532,7 +528,7 @@ Item {
id: discoveredMouse
anchors.fill: parent
hoverEnabled: true
enabled: !browserSession.configurationLocked
enabled: true
onClicked: root.endpointRequested(
hardening.recentDiscoveredIedHost(index),
hardening.recentDiscoveredIedPort(index))
Expand Down
Loading
Loading