@@ -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`
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user