docs(s7): wide-type/Timer-Counter support — CLI help + driver-specs + S7 driver doc

Drop the "not yet implemented / BadNotSupported" stale note from all three
S7 CLI --type option descriptions (ReadCommand, WriteCommand, SubscribeCommand)
and replace with accurate help listing the full supported type set, byte-anchored
addressing for wide types, and Timer/Counter read-only status.

docs/v2/driver-specs.md §5: add Supported Data Types table, Byte-Anchored
Addressing table (DBB/MB/IB/QB + examples), Timer/Counter read section with
the Counter-BCD known-limitation, and Deferrals list.

docs/drivers/S7.md: expand Data types to a full table, add "Wide types &
Timer/Counter" section (byte-anchored addressing, Timer/Counter read-only,
Counter BCD known-limitation, deferrals), update Address forms table and
1-D array Deferrals note.
This commit is contained in:
Joseph Doherty
2026-06-17 06:22:36 -04:00
parent 11e8e4302d
commit b7dfb5aff2
5 changed files with 160 additions and 33 deletions
+64 -4
View File
@@ -395,13 +395,73 @@ Pure managed .NET, MIT license. No native dependencies.
| Area | Address Syntax | Area Code | Examples |
|------|---------------|-----------|----------|
| Data Block | `DB{n}.DB{X\|B\|W\|D}{offset}[.bit]` | 0x84 | `DB1.DBX0.0`, `DB1.DBW0`, `DB1.DBD4` |
| Merkers | `M{B\|W\|D}{offset}` or `M{offset}.{bit}` | 0x83 | `M0.0`, `MW0`, `MD4` |
| Inputs | `I{B\|W\|D}{offset}` or `I{offset}.{bit}` | 0x81 | `I0.0`, `IW0`, `ID0` |
| Outputs | `Q{B\|W\|D}{offset}` or `Q{offset}.{bit}` | 0x82 | `Q0.0`, `QW0`, `QD0` |
| Data Block | `DB{n}.DB{X\|B\|W\|D}{offset}[.bit]` | 0x84 | `DB1.DBX0.0`, `DB1.DBW0`, `DB1.DBD4`, `DB1.DBB8` |
| Merkers | `M{B\|W\|D}{offset}` or `M{offset}.{bit}` | 0x83 | `M0.0`, `MW0`, `MD4`, `MB4` |
| Inputs | `I{B\|W\|D}{offset}` or `I{offset}.{bit}` | 0x81 | `I0.0`, `IW0`, `ID0`, `IB0` |
| Outputs | `Q{B\|W\|D}{offset}` or `Q{offset}.{bit}` | 0x82 | `Q0.0`, `QW0`, `QD0`, `QB0` |
| Timers | `T{n}` | 0x1D | `T0`, `T15` |
| Counters | `C{n}` | 0x1C | `C0`, `C10` |
### Supported Data Types
| DataType | S7 Type | Width | Read | Write | Notes |
|----------|---------|-------|------|-------|-------|
| `Bool` | BOOL | 1 bit | yes | yes | |
| `Byte` | BYTE | 1 byte | yes | yes | |
| `Int16` | INT | 2 bytes | yes | yes | |
| `UInt16` | WORD | 2 bytes | yes | yes | |
| `Int32` | DINT | 4 bytes | yes | yes | |
| `UInt32` | DWORD | 4 bytes | yes | yes | |
| `Float32` | REAL | 4 bytes | yes | yes | |
| `Int64` | LINT | 8 bytes | yes | yes | Byte-anchored — see below |
| `UInt64` | ULINT/LWORD | 8 bytes | yes | yes | Byte-anchored — see below |
| `Float64` | LREAL | 8 bytes | yes | yes | Byte-anchored — see below |
| `String` | STRING | `StringLength + 2` bytes | yes | yes | Byte-anchored; default `StringLength`=254 |
| `DateTime` | DATE_AND_TIME | 8 bytes | yes | yes | Byte-anchored — see below |
| Timer | TIME | — | yes | **no** | `T{n}` address only; DataType must be `Float64`; value = seconds |
| Counter | COUNTER | — | yes | **no** | `C{n}` address only; DataType must be `Int32`; value = raw word |
### Wide / Structured Types — Byte-Anchored Addressing
Wide types (`Int64`, `UInt64`, `Float64`/LReal, `String`, `DateTime`) are **byte-anchored**: the
address must use the `B` suffix to specify the start byte; the driver reads the
correct number of bytes based on the DataType.
| DataType | Required address form | Example |
|----------|-----------------------|---------|
| `Int64` | `DB{n}.DBB{offset}` / `MB{offset}` / `IB{offset}` / `QB{offset}` | `DB1.DBB8` → LINT at bytes 815 |
| `UInt64` | same | `DB2.DBB16` → ULINT at bytes 1623 |
| `Float64` | same | `DB1.DBB8` → LREAL at bytes 815 |
| `DateTime` | same | `DB3.DBB0` → DATE_AND_TIME at bytes 07 |
| `String` | same | `DB4.DBB0` DataType=String, StringLength=40 → reads 42 bytes |
Using a `W` (word) or `D` (dword) suffix with a wide DataType produces an address parse
error at `InitializeAsync`.
### Timer / Counter Read
**Timer (`T{n}`)** — reads the timer's current value as elapsed **seconds** (double). The OPC UA
node DataType is `Float64`. Timers are **read-only** this phase; writes return `BadNotWritable`.
**Counter (`C{n}`)** — reads the counter current value as a raw count (`int`). The OPC UA node
DataType is `Int32`. Counters are **read-only** this phase; writes return `BadNotWritable`.
> **Counter known-limitation**: `S7.Net`'s `Counter.FromByteArray` returns the raw big-endian
> word without BCD decode. On **classic S7-300/400** the C-area word is BCD-encoded (0999),
> so the surfaced value can differ from the actual count on that hardware. S7-1200/1500 use
> IEC/DB counters (plain integers) where the raw word is correct. BCD reinterpretation for
> legacy C-area is a live-hardware-gated follow-up.
### Deferrals (not yet implemented)
The following are explicitly deferred and will return `BadNotSupported` or a config error if attempted:
- **Wide-type arrays** — array tags (`isArray: true`) with element types `Int64`, `UInt64`,
`Float64`, `String`, or `DateTime`.
- **`S7WString`** (2-byte characters; distinct from `STRING`).
- **`DTL` / `DateTimeLong`** (12-byte Siemens date-and-time-long).
- **Timer / Counter writes** — surfaced as `BadNotWritable` until full write support lands.
### PDU Size & Optimization
| PLC | PDU Size | Max Data per Read |