Auto: s7-d3 — instance-DB / FB parameter resolution

Closes #301
This commit is contained in:
Joseph Doherty
2026-04-26 07:04:40 -04:00
parent c9e28b881e
commit baf1d65875
9 changed files with 797 additions and 14 deletions

View File

@@ -90,6 +90,98 @@ See [`docs/v2/s7.md` "UDT / STRUCT support"](../v2/s7.md#udt--struct-support)
for the full fan-out semantics, the 4-level nesting cap, and the
Optimized-block-access prerequisite.
## Instance DBs / FB parameters
PR-S7-D3 / [#301](https://github.com/dohertj2/lmxopcua/issues/301) — multi-instance
Function-Block (FB) instances are addressed symbolically inside the PLC program
(`MyFB_Instance.MyParam`) but the runtime wire access still needs the absolute
`DBn.DBW_offset`. TIA Portal's "Show all tags" CSV export distinguishes these
rows from regular global DBs via the **`DB type`** column.
### `DB type` column convention
| `DB type` value | Meaning | Path |
|---|---|---|
| (empty) | Legacy export — no column at all (TIA pre-v15 / partial export). Treated as Global. | D1 (existing) |
| `Global DB` / `Global` / `Global Data Block` | Standalone DB declared in the project tree. | D1 (existing) |
| `Globaler Datenbaustein` | Same as above, DE locale. | D1 (existing) |
| `Instance DB` / `Instance` / `Instance Data Block` | Multi-instance FB instance. Member tags are the FB's `IN` / `OUT` / `IN_OUT` / `STAT` parameters. | **D3 (new)** |
| `Instance-DB` / `Instanz-DB` / `Instanz-Datenbaustein` | Same as above (locale + dashing variants). | **D3 (new)** |
The `DB type` column is matched case-insensitively; quoting and surrounding
whitespace are tolerated.
### `MyFB_Instance.MyParam` → `DBn.DBW_offset`
The TIA Portal export ships the **resolved absolute address** in the
`Logical address` column for every instance-DB member — TIA itself walks the FB
interface declaration at export time and writes out the byte-offset-anchored
address verbatim. The importer accepts these rows the same way as a Global-DB
row, with two differences:
1. The row counts under `S7ImportResult.InstanceDbCount` (a sub-counter of
`ParsedCount`) so the operator can see how much of the import depends on the
FB-interface layout.
2. The row is rejected from the UDT placeholder path even if the data type
column happens to match a UDT name pattern — instance-DB members always
import as fully-functional scalar tags.
Example fixture row:
```csv
Name,Path,Data type,Logical address,Comment,Hmi accessible,DB type
MotorFB_1.Speed,FB instances,Int,%DB7.DBW0,Speed setpoint,True,Instance DB
```
The imported `S7TagDefinition` ends up with:
```csharp
new S7TagDefinition(
Name: "MotorFB_1.Speed",
Address: "DB7.DBW0",
DataType: S7DataType.Int16,
Writable: true);
```
### Empty-`Logical address` fallback
When TIA exports an instance-DB row with an empty `Logical address` column
(rare in practice — happens when the export was generated against a
not-yet-compiled project), `InstanceDbResolver` can compute the absolute
address from explicit parent-DB / parent-base-offset / member-offset inputs.
This fallback is exposed at the resolver-class level for advanced bootstrap
scenarios; the CSV path itself does not currently parse interface declarations
out of the file (TIA's CSV doesn't carry them).
For now the operator workflow is: re-export from TIA after compiling the
project so every instance-DB row carries a resolved `Logical address`.
### Re-import on FB-interface edit — caveat
When the FB interface changes — a member is added, removed, or reordered in
TIA — the instance-DB layout shifts on the PLC side. Member byte offsets that
worked yesterday point at the wrong word today; absolute-offset addressing has
no in-band schema check.
**The driver does not auto-detect this.** Operators must:
1. Recompile the FB in TIA Portal.
2. Download the updated program to the PLC.
3. **Re-export "Show all tags" CSV** from the updated project.
4. Re-import the CSV via `AddTiaCsvImport` or the `import-symbols` CLI.
5. Restart the driver instance (Admin UI → Drivers → Reload).
A stale import will silently read / write the wrong byte offsets — the values
will look like valid PLC data but reference whichever member used to live at
that offset before the interface edit. There is no runtime guard; this is the
same caveat that applies to all absolute-offset DB addressing on S7-1200 /
1500 (see [`docs/v2/s7.md` "UDT / STRUCT support"](../v2/s7.md#udt--struct-support)
for the parallel UDT-edit story).
A future enhancement may add a project-fingerprint compare at driver init —
hashing the interface offsets at import time and re-checking against a known
PLC system function. Tracked as a follow-up; not in PR-S7-D3.
## DE locale handling
TIA Portal honours the Windows display locale when writing CSV. A DE-locale
@@ -188,12 +280,14 @@ straight into the driver-instance config under
`--emit summary` writes a single line:
```
Imported 142 tag(s), skipped 3, errors 0, udt-placeholders 5.
Imported 142 tag(s), skipped 3, errors 0, udt-placeholders 5, instance-db 9.
```
`Skipped` covers HMI-accessible-false rows + missing-required-field rows;
`errors` covers rows whose `Address` failed to parse as an S7 address;
`udt-placeholders` covers UDT-typed rows that imported as placeholders.
`udt-placeholders` covers UDT-typed rows that imported as placeholders;
`instance-db` (PR-S7-D3) covers rows whose `DB type` column tagged them as
multi-instance FB-instance members.
## API surface — `IS7SymbolImporter` + `AddTiaCsvImport` / `AddAwlImport`

View File

@@ -1044,6 +1044,30 @@ The fan-out rejects, with clear errors:
- Tag with `UdtName` AND `ElementCount > 1` (array-of-UDT belongs in the UDT
layout, not at the parent-tag level)
### Re-import on UDT / FB-interface edit — caveat
The static-offset model assumes the declared layout matches the runtime
layout exactly. When the underlying UDT or FB interface changes in TIA Portal
— a member added, removed, or reordered — the byte offsets shift on the PLC
side and the cached `S7UdtDefinition` / instance-DB addresses point at the
wrong member.
**The driver does not auto-detect interface drift.** After any UDT edit or
multi-instance-FB interface edit on the PLC side, the operator must:
1. Recompile + download the updated program in TIA Portal.
2. Re-export "Show all tags" CSV from the updated project.
3. Re-import via `AddTiaCsvImport` (or `import-symbols` CLI) and update the
matching `S7UdtDefinition` declarations to mirror the new offsets.
4. Restart the driver instance (Admin UI → Drivers → Reload).
A stale UDT layout will silently read / write the wrong byte offsets — the
values will look like valid PLC data but reference whichever member used to
live at that offset before the edit. The same caveat applies to multi-instance
FB-instance DBs imported via PR-S7-D3 / [#301](https://github.com/dohertj2/lmxopcua/issues/301);
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.
## 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