|
|
|
|
@@ -1068,6 +1068,94 @@ FB-instance DBs imported via PR-S7-D3 / [#301](https://github.com/dohertj2/lmxop
|
|
|
|
|
see [`docs/drivers/S7-TIA-Import.md` "Re-import on FB-interface edit"](../drivers/S7-TIA-Import.md#re-import-on-fb-interface-edit--caveat)
|
|
|
|
|
for the FB-instance-specific workflow.
|
|
|
|
|
|
|
|
|
|
## CPU diagnostics (SZL)
|
|
|
|
|
|
|
|
|
|
PR-S7-E1 / [#302](https://github.com/dohertj2/lmxopcua/issues/302) — every S7
|
|
|
|
|
CPU answers SZL (System Status List) queries with metadata about itself: CPU
|
|
|
|
|
type, firmware, order number, scan-cycle min/avg/max, and the diagnostic
|
|
|
|
|
buffer ring. The driver surfaces those through a virtual `@System.*` address
|
|
|
|
|
space dispatched against the SZL sub-protocol — no DB / merker tag declarations
|
|
|
|
|
required.
|
|
|
|
|
|
|
|
|
|
### Opt-in: `ExposeSystemTags`
|
|
|
|
|
|
|
|
|
|
Off by default. Set `ExposeSystemTags = true` in `S7DriverOptions` and
|
|
|
|
|
`DiscoverAsync` adds a `Diagnostics/` sub-folder under the driver root with
|
|
|
|
|
the variables listed below. Knobs:
|
|
|
|
|
|
|
|
|
|
| Option | Default | Notes |
|
|
|
|
|
| --- | --- | --- |
|
|
|
|
|
| `ExposeSystemTags` | `false` | Master switch. When `false` the SZL surface is invisible — no extra browse nodes, no extra wire traffic. |
|
|
|
|
|
| `DiagBufferDepth` | `10` | Number of diagnostic-buffer entries to discover under `DiagBuffer/Entry[N]`. Capped at 50. |
|
|
|
|
|
| `SzlCacheTtl` | `5 s` | TTL for the per-driver SZL cache. A burst of `@System.*` reads inside this window reuses one wire response per SZL ID. Set to `TimeSpan.Zero` to disable caching (every read hits the wire). |
|
|
|
|
|
|
|
|
|
|
### `@System.*` address table
|
|
|
|
|
|
|
|
|
|
| Address | OPC UA type | SZL ID | Index | What it is |
|
|
|
|
|
| --- | --- | --- | --- | --- |
|
|
|
|
|
| `@System.CpuType` | `String` | `0x0011` | `0x0000` | CPU friendly name (SZL index 0x0007) or MLFB fallback. |
|
|
|
|
|
| `@System.Firmware` | `String` | `0x0011` | `0x0000` | Firmware version, formatted `Vmaj.min.patch`. |
|
|
|
|
|
| `@System.OrderNo` | `String` | `0x0011` | `0x0000` | MLFB / order number, e.g. `6ES7 516-3AN01-0AB0`. |
|
|
|
|
|
| `@System.CycleMs.Min` | `Float64` | `0x0132` | `0x0005` | Shortest scan cycle observed since last reset, in milliseconds. |
|
|
|
|
|
| `@System.CycleMs.Max` | `Float64` | `0x0132` | `0x0005` | Longest scan cycle observed since last reset, in milliseconds. |
|
|
|
|
|
| `@System.CycleMs.Avg` | `Float64` | `0x0132` | `0x0005` | Rolling average scan-cycle time, in milliseconds. |
|
|
|
|
|
| `@System.DiagBuffer.Entry[N]` | `String` | `0x00A0` | `0x0000` | Diagnostic-buffer entry rendered as `<UTC ISO-8601> \| 0x<event id> \| prio=<N> \| <event text>`. `N` ranges from `0` (most recent) through `DiagBufferDepth-1`. |
|
|
|
|
|
|
|
|
|
|
The diagnostic-buffer entries surface as flat strings rather than a structured
|
|
|
|
|
DataType so dashboards / log scrapers can split / grep them without a custom
|
|
|
|
|
schema.
|
|
|
|
|
|
|
|
|
|
### What's wired today vs not-supported
|
|
|
|
|
|
|
|
|
|
S7netplus 0.20 builds SZL request packages internally
|
|
|
|
|
(`SzlReadRequestPackage` / `WriteSzlReadRequest`) but does **not** expose a
|
|
|
|
|
public `ReadSzlAsync` API. Until S7netplus catches up (or we ship a raw S7comm
|
|
|
|
|
PDU helper that side-steps the library), the production
|
|
|
|
|
[`S7NetSzlReader`](../../src/ZB.MOM.WW.OtOpcUa.Driver.S7/Szl/S7NetSzlReader.cs)
|
|
|
|
|
returns `null` on every call and every `@System.*` read surfaces as
|
|
|
|
|
`BadNotSupported`. The browse tree still lights up — operators can wire
|
|
|
|
|
clients against it — only the values come back not-supported.
|
|
|
|
|
|
|
|
|
|
The parser code (`S7SzlParser`) is fully tested against golden bytes
|
|
|
|
|
regardless. Flipping the wire path on is a one-method change in
|
|
|
|
|
`S7NetSzlReader` once the upstream surface is available; no parser / dispatch
|
|
|
|
|
/ cache changes needed.
|
|
|
|
|
|
|
|
|
|
snap7 (the simulator backing the integration profile) also doesn't implement
|
|
|
|
|
SZL — the integration test
|
|
|
|
|
[`S7_1500SzlTests`](../../tests/ZB.MOM.WW.OtOpcUa.Driver.S7.IntegrationTests/S7_1500/S7_1500SzlTests.cs)
|
|
|
|
|
asserts the not-supported semantics against snap7 + parks the live-firmware
|
|
|
|
|
test behind `[Fact(Skip = ...)]` until the wire path lights up.
|
|
|
|
|
|
|
|
|
|
### Caching
|
|
|
|
|
|
|
|
|
|
Diagnostics shouldn't poll faster than `SzlCacheTtl` — a 100 ms HMI
|
|
|
|
|
subscription on every `@System.*` tag would otherwise hammer the comms
|
|
|
|
|
mailbox for data that doesn't change between scans. The per-driver
|
|
|
|
|
[`S7SzlCache`](../../src/ZB.MOM.WW.OtOpcUa.Driver.S7/Szl/S7SzlCache.cs)
|
|
|
|
|
de-dups concurrent reads by `(SzlId, SzlIndex)`; one SZL 0x0011 round-trip
|
|
|
|
|
backs `CpuType` + `Firmware` + `OrderNo` for the whole TTL window. Negative
|
|
|
|
|
results (SZL not supported) are cached just as aggressively — repeatedly
|
|
|
|
|
hammering a CPU that already said "not supported" wouldn't help.
|
|
|
|
|
|
|
|
|
|
`SzlCacheTtl = TimeSpan.Zero` disables caching entirely; useful for
|
|
|
|
|
diagnostics tests where you want every read to hit the wire.
|
|
|
|
|
|
|
|
|
|
### JSON config example
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
{
|
|
|
|
|
"DriverConfig": {
|
|
|
|
|
"Host": "192.168.10.50",
|
|
|
|
|
"Port": 102,
|
|
|
|
|
"CpuType": "S71500",
|
|
|
|
|
"ExposeSystemTags": true,
|
|
|
|
|
"DiagBufferDepth": 20,
|
|
|
|
|
"SzlCacheTtl": "00:00:05"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## References
|
|
|
|
|
|
|
|
|
|
1. Siemens Industry Online Support, *Modbus/TCP Communication between SIMATIC S7-1500 / S7-1200 and Modbus/TCP Controllers with Instructions `MB_CLIENT` and `MB_SERVER`*, Entry ID 102020340, V6 (Feb 2021). https://cache.industry.siemens.com/dl/files/340/102020340/att_118119/v6/net_modbus_tcp_s7-1500_s7-1200_en.pdf
|
|
|
|
|
|