test(s7): live-pin the Timer/Counter multi-var exclusion against a TM/CT-seeded s7_1500 fixture
This commit is contained in:
@@ -76,7 +76,8 @@ without Docker running.
|
||||
|
||||
## What's encoded in `profiles/s7_1500.json`
|
||||
|
||||
DB1 (1024 bytes) + MB (256 bytes) with typed seeds at known offsets:
|
||||
DB1 (1024 bytes) + MB (256 bytes) + TM0/CT0 (64 bytes each) with typed seeds at
|
||||
known offsets:
|
||||
|
||||
| Address | Type | Seed | Purpose |
|
||||
|---|---|---|---|
|
||||
@@ -116,6 +117,58 @@ inside the holes cluster A's span reads through. No tag maps to them; they are
|
||||
there so a mis-computed slice offset returns garbage instead of a zero that could
|
||||
match by luck. Every seed above is distinct and non-zero for the same reason.
|
||||
|
||||
### Timer / Counter (TM / CT) areas
|
||||
|
||||
`TM0` and `CT0` are 64 bytes each — **32 device cells**, since a timer is a 2-byte
|
||||
S5TIME word and a counter a 2-byte count word, with device number `N` at byte
|
||||
offset `2 × N`. They exist so `S7_1500SpanReadTests` can pin, against real wire,
|
||||
that `S7ReadSpanPlanner` excludes Timer/Counter from every span and the multi-var
|
||||
pass excludes them again on `IsBufferType` — each takes its own area-typed
|
||||
`ReadBytes` round-trip instead.
|
||||
|
||||
| Address | Byte offset | Seed | Decodes to |
|
||||
|---|---|---|---|
|
||||
| `T0` | 0 | `0x2456` | `456.0` s (S5TIME base 2 = ×1 s, BCD 456) |
|
||||
| `T5` | 10 | `0x1123` | `12.3` s (base 1 = ×0.1 s, BCD 123) |
|
||||
| `T9` | 18 | `0x0250` | `2.5` s (base 0 = ×0.01 s, BCD 250) |
|
||||
| `C0` | 0 | `4711` | `4711` (raw big-endian count word) |
|
||||
| `C7` | 14 | `31337` | `31337` |
|
||||
| `C11` | 22 | `1234` | `1234` |
|
||||
|
||||
A timer decodes to seconds as a `double` (S7.Net `Timer.FromByteArray`) and a
|
||||
counter to an `int` count (`Counter.FromByteArray`, raw word — **not** BCD).
|
||||
|
||||
#### ⚠️ Only device **0** is addressable on this fixture
|
||||
|
||||
Live-probed 2026-08-17: snap7's server resolves the TM/CT request address as a
|
||||
**bit address** — it serves byte `addr >> 3` of the area — whereas S7.Net, and a
|
||||
real S7 CPU, put the device **number** in that field. Measured directly against
|
||||
`10.100.0.35:1102`:
|
||||
|
||||
```
|
||||
ReadBytes(Timer,db=0,start=0,count=8) => [00 00 00 00 24 56 00 00] # bytes 0..7 (T2 seeded at byte 4)
|
||||
ReadBytes(Timer,db=0,start=2,count=2) => [00 00] # 2>>3 = byte 0, NOT timer 2 at byte 4
|
||||
ReadBytes(Timer,db=0,start=4,count=2) => [00 00] # 4>>3 = byte 0
|
||||
ReadBytes(Timer,db=0,start=32,count=2) => [24 56] # 32>>3 = byte 4 ← the timer-2 cell
|
||||
ReadBytes(Counter,db=0,start=48,count=2) => [12 67] # 48>>3 = byte 6 ← the counter-3 cell
|
||||
```
|
||||
|
||||
No error is raised — the reads succeed, they just land on the wrong cell. Device
|
||||
**0** is the single fixed point of the two conventions (`0 >> 3 == 2 × 0 == 0`),
|
||||
so `T0` / `C0` are the only cells whose *value* the fixture can pin; that is what
|
||||
`Timer_and_counter_tags_never_enter_a_multi_var_request` asserts, and the
|
||||
wire-shape half of that test is unaffected by the quirk. The `2 × N` cells above
|
||||
are seeded for a real CPU: run
|
||||
`Timer_and_counter_decode_the_seeded_values_at_their_device_numbers` against one
|
||||
with
|
||||
|
||||
```bash
|
||||
S7_SIM_ENDPOINT=<cpu>:102 S7_TIMER_NUMBER_ADDRESSING=1 \
|
||||
dotnet test tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.IntegrationTests
|
||||
```
|
||||
|
||||
It skips (naming this limitation) whenever that variable is unset.
|
||||
|
||||
## Known limitations
|
||||
|
||||
From the `snap7.server.Server` docstring upstream:
|
||||
@@ -130,6 +183,9 @@ Not exercised here — needs a lab rig:
|
||||
- S7-1500 Optimized-DB symbolic access
|
||||
- PG / OP / S7-Basic session-type differentiation
|
||||
- PUT/GET-disabled-by-default enforcement
|
||||
- Device-number addressing of the TM / CT areas (see the ⚠️ above — the reads are
|
||||
served, but resolved as bit addresses, so only device 0 lands where a CPU
|
||||
would put it)
|
||||
|
||||
See [`docs/drivers/S7-Test-Fixture.md`](../../../docs/drivers/S7-Test-Fixture.md)
|
||||
for the full coverage map.
|
||||
|
||||
Reference in New Issue
Block a user