[s7] S7 — DTL/DT/S5TIME/TIME/TOD/DATE codecs #338

Merged
dohertj2 merged 1 commits from auto/s7/PR-S7-A3 into auto/driver-gaps 2026-04-25 16:40:04 -04:00
Owner

Summary

S7 date/time codec coverage. Adds new static S7DateTimeCodec class mirroring the S7StringCodec pattern, with encode/decode for all six wire formats:

  • DTL (12 bytes): year(2 BE) / month / day / dow / hour / min / sec / ns(4 BE) → DateTime
  • DATE_AND_TIME (8 bytes BCD): yy/mm/dd/hh/mm/ss/ms/dow
  • S5TIME (16 bits BCD): timebase + 3-digit BCD count → TimeSpan
  • TIME (Int32 ms BE, signed): TimeSpan
  • TOD (UInt32 ms BE, 0..86399999): TimeSpan since midnight
  • DATE (UInt16 BE, days since 1990-01-01): DateTime

S7DataType enum gains Dtl, DateAndTime, S5Time, Time, TimeOfDay, Date. S7Driver.ReadOneAsync / WriteOneAsync route via raw ReadBytesAsync / WriteBytesAsync (S7.Net has no string-keyed overload for these widths). MapDataType: DTL/DT/DATE → DateTime; S5TIME/TIME/TOD → Int32 ms (no Duration in DriverDataType yet).

Edge cases: all-zero DTL/DT buffers reject as InvalidDataException (rather than decoding to year-0001 garbage). BCD nibbles validated on every decode.

Test plan

  • dotnet build src/ZB.MOM.WW.OtOpcUa.Driver.S7 + Driver.S7.Cli — clean (0 / 0)
  • dotnet test tests/ZB.MOM.WW.OtOpcUa.Driver.S7.Tests115 / 115 passed (30 new in S7DateTimeCodecTests: golden-byte vectors per type, round-trip, BCD-nibble rejection, all-zero buffer rejection, signed-TIME negatives, TOD upper-bound)
  • Integration tests — Snap7-server fixture supports byte-range reads; not exercised in this PR

🤖 Auto-generated by the Mode-B execution loop. Closes #289.

Closes #289

## Summary S7 date/time codec coverage. Adds new static `S7DateTimeCodec` class mirroring the `S7StringCodec` pattern, with encode/decode for all six wire formats: - **DTL** (12 bytes): year(2 BE) / month / day / dow / hour / min / sec / ns(4 BE) → DateTime - **DATE_AND_TIME** (8 bytes BCD): yy/mm/dd/hh/mm/ss/ms/dow - **S5TIME** (16 bits BCD): timebase + 3-digit BCD count → TimeSpan - **TIME** (Int32 ms BE, signed): TimeSpan - **TOD** (UInt32 ms BE, 0..86399999): TimeSpan since midnight - **DATE** (UInt16 BE, days since 1990-01-01): DateTime `S7DataType` enum gains `Dtl`, `DateAndTime`, `S5Time`, `Time`, `TimeOfDay`, `Date`. `S7Driver.ReadOneAsync` / `WriteOneAsync` route via raw `ReadBytesAsync` / `WriteBytesAsync` (S7.Net has no string-keyed overload for these widths). `MapDataType`: DTL/DT/DATE → `DateTime`; S5TIME/TIME/TOD → `Int32` ms (no Duration in `DriverDataType` yet). **Edge cases**: all-zero DTL/DT buffers reject as `InvalidDataException` (rather than decoding to year-0001 garbage). BCD nibbles validated on every decode. ## Test plan - [x] `dotnet build src/ZB.MOM.WW.OtOpcUa.Driver.S7` + `Driver.S7.Cli` — clean (0 / 0) - [x] `dotnet test tests/ZB.MOM.WW.OtOpcUa.Driver.S7.Tests` — **115 / 115 passed** (30 new in `S7DateTimeCodecTests`: golden-byte vectors per type, round-trip, BCD-nibble rejection, all-zero buffer rejection, signed-TIME negatives, TOD upper-bound) - [ ] Integration tests — Snap7-server fixture supports byte-range reads; not exercised in this PR 🤖 Auto-generated by the Mode-B execution loop. Closes #289. Closes #289
dohertj2 added 1 commit 2026-04-25 16:40:00 -04:00
Adds S7DateTimeCodec static class implementing the six Siemens S7 date/time
wire formats:

  - DTL (12 bytes): UInt16 BE year + month/day/dow/h/m/s + UInt32 BE nanos
  - DATE_AND_TIME (8 bytes BCD): yy/mm/dd/hh/mm/ss + 3-digit BCD ms + dow
  - S5TIME (16 bits): 2-bit timebase + 3-digit BCD count → TimeSpan
  - TIME (Int32 ms BE, signed) → TimeSpan, allows negative durations
  - TOD (UInt32 ms BE, 0..86399999) → TimeSpan since midnight
  - DATE (UInt16 BE days since 1990-01-01) → DateTime

Mirrors the S7StringCodec pattern from PR-S7-A2 — codecs operate on raw byte
spans so each format can be locked with golden-byte unit tests without a
live PLC. New S7DataType members (Dtl, DateAndTime, S5Time, Time, TimeOfDay,
Date) are wired into S7Driver.ReadOneAsync/WriteOneAsync via byte-level
ReadBytesAsync/WriteBytesAsync calls — S7.Net's string-keyed Read/Write
overloads have no syntax for these widths.

Uninitialized PLC buffers (all-zero year+month for DTL/DT) reject as
InvalidDataException → BadOutOfRange to operators, rather than decoding as
year-0001 garbage.

S5TIME / TIME / TOD surface as Int32 ms (DriverDataType has no Duration);
DTL / DT / DATE surface as DriverDataType.DateTime.

Test coverage: 30 new golden-vector + round-trip + rejection tests,
including the all-zero buffer rejection paths and BCD-nibble validation.
Build clean, 115/115 S7 tests pass.

Closes #289

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dohertj2 merged commit 676eebd5e4 into auto/driver-gaps 2026-04-25 16:40:04 -04:00
dohertj2 deleted branch auto/s7/PR-S7-A3 2026-04-25 16:40:05 -04:00
Sign in to join this conversation.