Auto: s7-f — Optimized DB / S7Plus decision (Track 1+3 docs-only)
Closes #304
This commit is contained in:
@@ -88,6 +88,18 @@ real PLC latency is not exercised.
|
|||||||
S7-1200 vs S7-1500 vs S7-300/400 connection semantics (PG vs OP vs S7-Basic)
|
S7-1200 vs S7-1500 vs S7-300/400 connection semantics (PG vs OP vs S7-Basic)
|
||||||
not differentiated at test time.
|
not differentiated at test time.
|
||||||
|
|
||||||
|
**Optimized DB / S7Plus** is the variant-shaped gap with the biggest field
|
||||||
|
impact. snap7 happens to behave like a classic-S7comm-only PLC, so the
|
||||||
|
integration suite cannot reproduce the shape that an S7-1500 with default
|
||||||
|
"Optimized block access" checked would return (`BadDeviceFailure` on every
|
||||||
|
absolute-offset read). The decision is documented at
|
||||||
|
[`docs/v2/s7.md` § Optimized DB constraint (S7Plus)](../v2/s7.md#optimized-db-constraint-s7plus)
|
||||||
|
and tracked in [`docs/featuregaps.md`](../featuregaps.md) row #1; the
|
||||||
|
project ships **Track 1** (operator unchecks Optimized block access in TIA
|
||||||
|
Portal) and **Track 3** (bridge via the `OpcUaClient` driver against the
|
||||||
|
CPU's onboard OPC UA server). A custom S7Plus implementation is out of
|
||||||
|
scope.
|
||||||
|
|
||||||
### 5. Data types beyond the scalars
|
### 5. Data types beyond the scalars
|
||||||
|
|
||||||
`STRING` with length-prefix quirks, `DTL` / `DATE_AND_TIME`, arrays of
|
`STRING` with length-prefix quirks, `DTL` / `DATE_AND_TIME`, arrays of
|
||||||
@@ -162,7 +174,36 @@ configured, which is parked as a follow-up.
|
|||||||
runner with the lab rig executes. The classifier branch
|
runner with the lab rig executes. The classifier branch
|
||||||
(`S7PreflightClassifier.IsPutGetDisabled`) is unit-tested without a
|
(`S7PreflightClassifier.IsPutGetDisabled`) is unit-tested without a
|
||||||
network in `S7PreflightTests.Classifier_matches_only_PUT_GET_disabled_error_codes`.
|
network in `S7PreflightTests.Classifier_matches_only_PUT_GET_disabled_error_codes`.
|
||||||
5. **PR-S7-E1 — live SZL test against a real S7-1500.** snap7 doesn't
|
5. **Live-firmware Optimized-block-access toggle (PR-S7-F / [#304](https://github.com/dohertj2/lmxopcua/issues/304)).**
|
||||||
|
snap7 happens to behave like a classic-S7comm CPU, so the integration
|
||||||
|
profile cannot reproduce the failure that a default new TIA Portal V14+
|
||||||
|
project produces (`BadDeviceFailure` on `DB1.DBW0` against an Optimized
|
||||||
|
DB). A manual smoke test on the lab rig, gated behind `--with-real-plc`,
|
||||||
|
would close that loop. Suggested checklist on a real S7-1500 V2.5+:
|
||||||
|
1. Create `DB1` in TIA Portal with three INT members at offsets 0, 2, 4.
|
||||||
|
Leave **Optimized block access checked** (the default).
|
||||||
|
2. Compile + download to the PLC.
|
||||||
|
3. Drive the OtOpcUa S7 driver against `DB1.DBW0` — assert that the read
|
||||||
|
returns `BadDeviceFailure` (the Track-1-not-applied symptom). This is
|
||||||
|
the failure shape the docs warn about.
|
||||||
|
4. Open `DB1`'s properties → **uncheck Optimized block access** →
|
||||||
|
compile → download. Re-run the read; assert it returns the seeded
|
||||||
|
INT value at offset 0. (Track 1 verified end-to-end.)
|
||||||
|
5. **Track 3 verification (separate run on the same rig):** with
|
||||||
|
Optimized access re-enabled on `DB1`, activate the CPU's onboard
|
||||||
|
OPC UA server in TIA Portal, expose `DB1.<MemberName>` through a
|
||||||
|
Server interface, register an `OpcUaClient` driver against
|
||||||
|
`opc.tcp://<plc-ip>:4840`, and assert the symbolic read returns the
|
||||||
|
same seeded value. This proves the bridge path against a real
|
||||||
|
Optimized DB without the operator having to disable Optimized
|
||||||
|
access.
|
||||||
|
|
||||||
|
The test must stay manual: TIA Portal compile + download cannot be
|
||||||
|
automated from CI without a Siemens engineering toolchain license, and
|
||||||
|
download-with-CPU-stop is destructive on a shared lab rig. Document
|
||||||
|
results inline in PR descriptions when the rig is available.
|
||||||
|
|
||||||
|
6. **PR-S7-E1 — live SZL test against a real S7-1500.** snap7 doesn't
|
||||||
implement SZL at all, and S7netplus 0.20 doesn't expose a public
|
implement SZL at all, and S7netplus 0.20 doesn't expose a public
|
||||||
`ReadSzlAsync`, so the `@System.*` virtual address surface currently
|
`ReadSzlAsync`, so the `@System.*` virtual address surface currently
|
||||||
answers `BadNotSupported` against every backend. The parser
|
answers `BadNotSupported` against every backend. The parser
|
||||||
|
|||||||
20
docs/featuregaps.md
Normal file
20
docs/featuregaps.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Feature gaps — driver-side limitations and decisions
|
||||||
|
|
||||||
|
Cross-driver registry of known capability gaps, the workaround we ship, and
|
||||||
|
whether the gap is on the roadmap. Each row links to the driver-specific
|
||||||
|
deep-dive document. Closed entries stay in the table for traceability — they
|
||||||
|
are not deleted, only marked.
|
||||||
|
|
||||||
|
| # | Driver | Gap | Status | Workaround / decision | Roadmap | Reference |
|
||||||
|
|---|--------|-----|--------|-----------------------|---------|-----------|
|
||||||
|
| 1 | S7 | **Optimized DB / S7Plus** — S7netplus speaks classic S7comm only and cannot read S7-1200 / S7-1500 DBs that have "Optimized block access" checked (the TIA Portal V14+ default). Absolute-offset reads against an Optimized DB return `BadDeviceFailure`. | **Decided — Track 1 + Track 3 (closed by [#304](https://github.com/dohertj2/lmxopcua/issues/304))** | **Track 1 (docs):** operators uncheck "Optimized block access" in TIA Portal on every DB the driver reads, recompile, and download. **Track 3 (bridge):** for shops that won't or can't disable Optimized access, run an `OpcUaClient` driver instance against the S7-1500 V2.5+ CPU's onboard OPC UA server (Siemens runtime OPC UA license required). | **Track 2 (custom S7Plus library) is out of scope** unless a customer funds the ≥4-week initial implementation plus ongoing protocol-revision maintenance. Sharp7 / Snap7Net don't help — they are also classic-S7comm-only. | [`docs/v2/s7.md` § Optimized DB constraint](v2/s7.md#optimized-db-constraint-s7plus) · [`docs/drivers/OpcUaClient.md`](drivers/OpcUaClient.md) |
|
||||||
|
|
||||||
|
## How to read this table
|
||||||
|
|
||||||
|
- **Status** is one of `Open` (work pending), `Decided` (architectural
|
||||||
|
decision made; docs reflect it; no code change planned), or
|
||||||
|
`Closed` (delivered).
|
||||||
|
- **Roadmap** captures whether the gap is funded for the next phase. A blank
|
||||||
|
cell means "no roadmap; doc-only outcome."
|
||||||
|
- The numeric **#** is stable — new rows append at the bottom and keep their
|
||||||
|
number across deletions/edits so cross-references survive.
|
||||||
191
docs/v2/s7.md
191
docs/v2/s7.md
@@ -1,5 +1,190 @@
|
|||||||
# Siemens SIMATIC S7 (S7-1200 / S7-1500 / S7-300 / S7-400 / ET 200SP) — Modbus TCP quirks
|
# Siemens SIMATIC S7 (S7-1200 / S7-1500 / S7-300 / S7-400 / ET 200SP) — Modbus TCP quirks
|
||||||
|
|
||||||
|
> **Read first: [Optimized DB constraint (S7Plus)](#optimized-db-constraint-s7plus).**
|
||||||
|
> S7netplus, the wire library this driver is built on, speaks classic S7comm
|
||||||
|
> only — it cannot read Optimized-block-access DBs on S7-1200 / S7-1500. That
|
||||||
|
> is the default in TIA Portal V14+ for new projects. If you skip the section
|
||||||
|
> below, every absolute-offset read against a freshly-created S7-1500 project
|
||||||
|
> will return `BadDeviceFailure`.
|
||||||
|
|
||||||
|
## Optimized DB constraint (S7Plus)
|
||||||
|
|
||||||
|
### Symptom
|
||||||
|
|
||||||
|
Against a default new S7-1500 TIA Portal project, an absolute-offset read like
|
||||||
|
`DB1.DBW0` issued by the OtOpcUa S7 driver returns `BadDeviceFailure` (the
|
||||||
|
S7netplus `PlcException` surfaces as `ErrorCode.WrongVarFormat` /
|
||||||
|
`ErrorCode.ReadData` depending on firmware revision). No bytes are returned;
|
||||||
|
the read never reaches the user data; the failure is identical whether
|
||||||
|
PUT/GET is enabled or not.
|
||||||
|
|
||||||
|
### Why
|
||||||
|
|
||||||
|
The OtOpcUa S7 driver is built on
|
||||||
|
[**S7netplus**](https://github.com/S7NetPlus/s7netplus), which implements
|
||||||
|
**classic S7comm** only — the protocol historically used by S7-300 / S7-400
|
||||||
|
and the legacy "compatibility" path on S7-1200 / S7-1500. Classic S7comm
|
||||||
|
addresses DB contents by **absolute byte offset**: `DB1.DBW0` literally means
|
||||||
|
"give me 2 bytes starting at byte 0 of DB number 1". This works as long as
|
||||||
|
the byte offsets in the program match the byte offsets on the wire.
|
||||||
|
|
||||||
|
S7-1200 V4 and S7-1500 introduced **Optimized block access**. When checked,
|
||||||
|
the TIA Portal compiler is free to **reorder DB members**, insert padding for
|
||||||
|
alignment, and store members in CPU-internal memory that the absolute-offset
|
||||||
|
read protocol cannot reach. There are no fixed byte offsets to address — the
|
||||||
|
only way to read an Optimized DB is by **symbolic name**, which requires
|
||||||
|
**S7Plus** (the post-2014 protocol Siemens uses for TIA-Portal-aware tooling
|
||||||
|
and OPC UA gateways).
|
||||||
|
|
||||||
|
S7Plus is undocumented by Siemens. A community Wireshark dissector exists
|
||||||
|
(`s7comm-plus`), but no production-ready open-source library implements the
|
||||||
|
write/subscribe surface end-to-end. **S7netplus does not, and is not on a
|
||||||
|
roadmap to, support S7Plus.** Snap7 v2 / Snap7Net and the various Sharp7
|
||||||
|
forks are also classic-S7comm-only.
|
||||||
|
|
||||||
|
### Default to know about
|
||||||
|
|
||||||
|
In **TIA Portal V14 and newer, "Optimized block access" is checked by default
|
||||||
|
on every newly-created DB**. A customer who clicks "Add new block → Data
|
||||||
|
block → OK" on a fresh S7-1500 project gets an Optimized DB. The driver
|
||||||
|
cannot read it.
|
||||||
|
|
||||||
|
### Supported workarounds
|
||||||
|
|
||||||
|
The OtOpcUa project supports two workarounds. Pick one per deployment.
|
||||||
|
|
||||||
|
#### Track 1 — Disable Optimized block access in TIA Portal
|
||||||
|
|
||||||
|
Per DB the driver reads:
|
||||||
|
|
||||||
|
1. In TIA Portal, open the project tree → `<PLC>` → **Program blocks** →
|
||||||
|
right-click the DB → **Properties**.
|
||||||
|
2. In the **Attributes** tab, **uncheck "Optimized block access"**.
|
||||||
|
3. **Compile** the program.
|
||||||
|
4. **Download** to the PLC (download the changed block; the CPU will go into
|
||||||
|
STOP if the DB layout changed and download-without-reinitialize is
|
||||||
|
refused — schedule a maintenance window).
|
||||||
|
|
||||||
|
After this, `DB1.DBW0` and friends address absolute byte offsets again and
|
||||||
|
the OtOpcUa S7 driver reads through unmodified.
|
||||||
|
|
||||||
|
**Trade-off:** Optimized DBs are slightly faster for *the PLC program
|
||||||
|
itself* to access (better alignment, sometimes better cache behaviour) and
|
||||||
|
let the compiler add/remove DB members without renumbering offsets in user
|
||||||
|
code. Disabling Optimized access trades a tiny amount of CPU-side
|
||||||
|
performance and a layout-stability guarantee for absolute-offset wire
|
||||||
|
addressability. For DBs that exist only as a Modbus / S7comm gateway buffer
|
||||||
|
(common pattern), there is no real downside.
|
||||||
|
|
||||||
|
This is the same prerequisite called out in
|
||||||
|
["Optimized block access — must be off"](#optimized-block-access--must-be-off)
|
||||||
|
and ["Address / DB Mapping → MB_HOLD_REG"](#address--db-mapping) for the
|
||||||
|
Modbus-TCP path; the constraint is the same and stems from the same
|
||||||
|
absolute-offset-only assumption.
|
||||||
|
|
||||||
|
#### Track 3 — Bridge via the OpcUaClient driver against the CPU's onboard OPC UA server
|
||||||
|
|
||||||
|
S7-1500 firmware **V2.5 and later** ship with an **integrated OPC UA
|
||||||
|
server** running on the CPU's PROFINET port (default port 4840). Once
|
||||||
|
enabled in TIA Portal it exposes the entire symbol table — including
|
||||||
|
Optimized DBs — through standard OPC UA, by symbolic name. There is no S7
|
||||||
|
protocol involved at all from the OtOpcUa side.
|
||||||
|
|
||||||
|
Configure the bridge once:
|
||||||
|
|
||||||
|
1. **TIA Portal side**:
|
||||||
|
- Open the CPU's properties → **OPC UA** → **General** → check
|
||||||
|
**Activate OPC UA server**.
|
||||||
|
- Set the server port (default 4840) and security policy. For a quick
|
||||||
|
bring-up, allow `None` + `UserName` and create a server certificate;
|
||||||
|
for production, use Basic256Sha256 with a CA-issued cert.
|
||||||
|
- Under **OPC UA** → **Server interfaces**, expose the symbols/tags the
|
||||||
|
OtOpcUa side should see. (Whole-symbol-table exposure works; a
|
||||||
|
curated server interface is more secure and faster.)
|
||||||
|
- Compile and download.
|
||||||
|
- Note: this requires a **runtime OPC UA license on the CPU**
|
||||||
|
(Siemens SIMATIC NET OPC UA server license, typically activated via
|
||||||
|
SIMATIC SUM). The license is per CPU, not per client.
|
||||||
|
|
||||||
|
2. **OtOpcUa side** — register an `OpcUaClient` driver instance pointing
|
||||||
|
at the CPU. Minimal `DriverConfig` JSON:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Driver": "OpcUaClient",
|
||||||
|
"Name": "PLC1500_Onboard",
|
||||||
|
"Options": {
|
||||||
|
"EndpointUrl": "opc.tcp://10.0.0.42:4840",
|
||||||
|
"SecurityMode": "SignAndEncrypt",
|
||||||
|
"SecurityPolicy": "Basic256Sha256",
|
||||||
|
"UserName": "OtOpcUa",
|
||||||
|
"Password": "<from secret store>",
|
||||||
|
"WatchModelChanges": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The driver handles browse, read, write, and subscriptions through the
|
||||||
|
CPU's symbolic name space. Optimized DBs Just Work — the CPU resolves
|
||||||
|
names internally, so the wire never sees a byte offset.
|
||||||
|
|
||||||
|
See [`docs/drivers/OpcUaClient.md`](../drivers/OpcUaClient.md) for the full
|
||||||
|
configuration surface (reverse connect, model-change re-import, failover,
|
||||||
|
aggregate functions, redundancy via `ServerUriArray`, etc.).
|
||||||
|
|
||||||
|
**When to use Track 3 over Track 1**:
|
||||||
|
|
||||||
|
- The DB layout is owned by an upstream Siemens engineering team that won't
|
||||||
|
disable Optimized access (legitimate concern: shared-DB constraints,
|
||||||
|
compile-time member-renumbering, application notes that mandate optimized
|
||||||
|
blocks).
|
||||||
|
- The customer already licenses OPC UA on the CPU.
|
||||||
|
- Symbolic addressing is preferred end-to-end (no byte-offset bookkeeping
|
||||||
|
in the OtOpcUa tag list; tags survive DB-member additions).
|
||||||
|
- S7-300 / S7-400 are out of scope on this CPU (the onboard OPC UA server
|
||||||
|
is S7-1500 V2.5+ only — see V2.5 firmware change list).
|
||||||
|
|
||||||
|
**When to use Track 1 over Track 3**:
|
||||||
|
|
||||||
|
- The CPU is S7-1200 (no onboard OPC UA server even on the V4 firmware
|
||||||
|
line) or older S7-1500 firmware (< V2.5).
|
||||||
|
- The customer won't pay for the SIMATIC NET OPC UA server license on the
|
||||||
|
CPU.
|
||||||
|
- The DBs in question exist purely as gateway buffers and have no
|
||||||
|
significant CPU-program access pattern that would benefit from
|
||||||
|
Optimized access.
|
||||||
|
|
||||||
|
### Track 2 — out of scope
|
||||||
|
|
||||||
|
For completeness, the **Track 2** option that was evaluated and rejected:
|
||||||
|
migrate the OtOpcUa S7 driver off S7netplus to a library that speaks
|
||||||
|
S7Plus. The candidates were:
|
||||||
|
|
||||||
|
- **Snap7 v2 / Snap7Net** — classic S7comm only. Same Optimized-DB
|
||||||
|
limitation. Not a step forward.
|
||||||
|
- **Sharp7 community forks** — partial S7-1200 / S7-1500 PUT/GET semantics
|
||||||
|
but still classic-S7comm wire format. Not a step forward.
|
||||||
|
- **Custom S7Plus implementation** — possible in principle (the Wireshark
|
||||||
|
`s7comm-plus` dissector covers the wire format), but estimated **≥4
|
||||||
|
weeks** of engineering for a minimal read/write/subscribe surface, plus
|
||||||
|
ongoing maintenance every time Siemens revs the protocol version
|
||||||
|
(which they do silently with each TIA Portal release).
|
||||||
|
|
||||||
|
**Track 2 is not on the OtOpcUa roadmap** unless a specific customer funds
|
||||||
|
the engineering and ongoing maintenance. Track 1 + Track 3 together cover
|
||||||
|
every shipping S7 deployment we have visibility into.
|
||||||
|
|
||||||
|
### Pre-flight diagnostics
|
||||||
|
|
||||||
|
The driver does not currently auto-detect Optimized DBs from the
|
||||||
|
`BadDeviceFailure` shape (the same error code is returned for "DB doesn't
|
||||||
|
exist", "DB exists but is too short", etc.). On first encounter of a
|
||||||
|
device-failure error, check the suspect DB's properties in TIA Portal
|
||||||
|
**before** chasing wire-level theories. The auto-detect would require an
|
||||||
|
SZL probe or a symbolic round-trip; tracked but not a v2 deliverable.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
Siemens S7 PLCs do *not* speak Modbus TCP natively at the OS/firmware level. Every
|
Siemens S7 PLCs do *not* speak Modbus TCP natively at the OS/firmware level. Every
|
||||||
S7 Modbus-TCP-server deployment is either (a) the **`MB_SERVER`** library block
|
S7 Modbus-TCP-server deployment is either (a) the **`MB_SERVER`** library block
|
||||||
running on the CPU's PROFINET port (S7-1200 / S7-1500 / CPU 1510SP-series
|
running on the CPU's PROFINET port (S7-1200 / S7-1500 / CPU 1510SP-series
|
||||||
@@ -1030,7 +1215,11 @@ addresses by absolute offset, including UDT-typed DBs.
|
|||||||
|
|
||||||
If a customer can't disable Optimized access (e.g., shared-DB constraints),
|
If a customer can't disable Optimized access (e.g., shared-DB constraints),
|
||||||
the workaround is to expose the UDT through the symbolic-tag path once that
|
the workaround is to expose the UDT through the symbolic-tag path once that
|
||||||
ships — not in PR-S7-D2.
|
ships — not in PR-S7-D2. See
|
||||||
|
[Optimized DB constraint (S7Plus)](#optimized-db-constraint-s7plus) at the
|
||||||
|
top of this document for the project-wide decision (Track 1 disable in TIA
|
||||||
|
Portal, or Track 3 bridge via the OpcUaClient driver against the CPU's
|
||||||
|
onboard OPC UA server).
|
||||||
|
|
||||||
### Validation
|
### Validation
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user