Files
aquacom-gateway-suite/docs/protocol/test-vectors.md
T
2026-10-06 07:08:03 +02:00

114 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AquaCom approved test vectors
**Fixture source policy:** all vectors below are derived from *Technical description – AquaCom – RTU level*, Rev 1.6, ITT Flygt AB, July 2004 (`AquaCom_RTU_1_6_eng.pdf`) — evidence class **SPECIFICATION** (examples printed in the authoritative document). Vectors marked *(synthetic)* are constructed by the project to exercise edge cases the document's examples do not cover; they are labeled **SYNTHETIC_FROM_SPECIFICATION** and are subordinate to the source examples in authority. Each fixture becomes an automated test on implementation; fixtures are immutable once approved (implementation specification §64).
**Notation.** `<SOH>`=01H, `<STX>`=02H, `<CR>`=0DH, `_`=space (20H), `!W` = Wait byte (DC3, 13H). Checksums are per §2.4: sum of all bytes after SOH/STX up to (excluding) `#`, excluding Wait bytes, in a 16-bit signed integer; the transmitted value is the absolute value. The separator space between `#` and the checksum, and the trailing space before `CR`, **are included** in the summed range.
**Checksum convention reminder (verified by the examples below):** the summed range starts *after* SOH/STX — i.e. at the space that follows the start byte — and ends at the space immediately before the checksum digits. `32+83+67+79+32=293` for `SCO` (§2.4) confirms this: leading space 32, `SCO` 83+67+79, trailing space 32.
---
## 1. Checksum algorithm vectors
| ID | Telegram | Documented checksum | Verified | Source |
|---|---|---|---|---|
| AQ-CK-001 | `<STX> SCO _ # _ 293 <CR>` | 293 | yes | §2.4 |
| AQ-CK-002 | `<SOH> 9 BRK _ # _ 376 <CR>` | 376 | yes | §3.4.1.2 |
| AQ-CK-003 | `<SOH> 0 ALO _ # _ 364 <CR>` | 364 | yes | §2.2.3.3 |
| AQ-CK-004 | `<STX> NDA _ # _ 275 <CR>` | 275 | yes | §3.4.12.2 |
| AQ-CK-005 | `<STX> SCO _ # _ 293 <CR>` (RTU→CS OK answer) | 293 | yes | §3.4.2.3 |
| AQ-CK-006 | `<STX> SCE 48 _ # _ 423 <CR>` | 423 | yes | §3.4.2.3 |
| AQ-CK-007 | `<SOH> 9 WCA 0 3 6 17 13 59 _ # _ 1031 <CR>` | 1031 | yes | §2.2.3.3 |
| AQ-CK-008 | `<SOH> 9 WCA 0 3 6 17 14 0 _ # _ 970 <CR>` | 970 | yes | §2.2.3.3 |
| AQ-CK-009 | `<STX> ALN T 0 0 0 0 _ # _ 719 <CR>` | 719 | yes | §2.2.3.3 |
| AQ-CK-010 | `<STX> OK _ # _ 218 <CR>` | 218 | yes | §2.2.3.1, §3.4.1.2 |
| AQ-CK-011 | `<SOH> 5 WCA 0 1 4 27 10 13 _ # _ 1011 <CR>` | 1011 | yes | §3.4.1.3 |
| AQ-CK-012 | `<STX> ALR 111 11 1 4 27 10 13 A T 0 0 0 0 B 31 _ # _ 1922 <CR>` | 1922 | yes | §3.4.1.3 |
| AQ-CK-013 | `<SOH> 5 ALO _ # _ 369 <CR>` | 369 | yes | §3.4.1.3 |
| AQ-CK-014 | `<SOH> 9 MCC 0 1 _ # _ 525 <CR>` | 525 | yes | §3.4.3.2 |
| AQ-CK-015 | `<SOH> 9 SLT 0 1 _ # _ 557 <CR>` | 557 | yes | §3.4.9.2 |
| AQ-CK-016 | `<SOH> 2 MAS 0 1 _ # _ 532 <CR>` | 532 | yes | §3.4.5.3 |
| AQ-CK-017 | `<SOH> 2 MAT 7 7 81 81 82 9003 _ # _ 1194 <CR>` | 1194 | yes | §3.4.6.1 |
| AQ-CK-018 | `<SOH> 9 MAT 7 9001 _ # _ 700 <CR>` | 700 | yes | §3.4.6.2 |
| AQ-CK-019 | `<SOH> 9 WGD 01 05 02 13 38 01 05 01 _ # _ 1433 <CR>` | 1433 | yes | §3.4.11.3 |
| AQ-CK-020 | `<SOH> 5 WGD 01 05 02 13 10 01 05 01 _ # _ 1419 <CR>` | 1419 | yes | §3.4.11.2 |
| AQ-CK-021 | `<SOH> 9 WGH 01 04 30 23 30 _ # _ 1039 <CR>` | 1039 | yes | §3.4.12.2 |
| AQ-CK-022 | `<SOH> 9 WGH 01 05 01 03 50 _ # _ 1038 <CR>` | 1038 | yes | §3.4.12.2 |
| AQ-CK-023 | `<SOH> 9 WGH 01 05 01 08 10 _ # _ 1039 <CR>` | 1039 | yes | §3.4.12.2 |
| AQ-CK-024 | `<SOH> 9 WGH 01 05 01 08 20 _ # _ 1040 <CR>` | 1040 | yes | §3.4.12.2 |
| AQ-CK-025 | `<SOH> 500 WGH 99 12 31 21 40 _ # _ 1147 <CR>` | 1147 | yes | §3.7 |
| AQ-CK-026 | `<STX> 9_ACT_#_369_<CR>` (caller-ID, literal ACT) | 369 | yes | §2.2.3.3 |
| AQ-CK-027 | `<STX> ALR 9 12 3 6 17 13 58 P T 0 0 0 0 A 27 _ # _ 1867 <CR>` | 1867 | yes | §2.2.3.3 |
| AQ-CK-028 | `<STX> ALR 9 12 1 4 27 10 26 P T 0 0 0 0 A 27 _ # _ 1856 <CR>` | 1856 | yes | §3.4.1.2 |
| AQ-CK-029 | `<SOH> 9 WCA 0 1 4 27 10 27 _ # _ 1020 <CR>` | 1020 | yes | §3.4.1.2 |
| AQ-CK-030 | `<SOH> 86 WGS P 0 ! 1 _ # _ 785 <CR>` | 785 | yes | §2.2.3.1 — confirms the `0 !` two-field form |
| AQ-CK-031 | `<SOH> 901 WGS P 0 ! 11 _ # _ 878 <CR>` | 878 | yes | §3.4.10.2 |
| AQ-CK-032 | `<SOH> 9 WGS P 2 F 1 _ # _ 771 <CR>` | 771 | yes | §3.4.10.3 |
| AQ-CK-033 | `<STX> 32000 654321 03 11 0 0 0 0 0 1 2 3 4 5 6 7 8 9 10 8050 8531 8532 _ # _ 2925 <CR>` | 2925 | yes | §3.6.4 (Wait-free form of the WGS-answer pair) |
| AQ-CK-034 | `<STX> 32000 65!W4321 03 11!W 0 0 0 0 0!W 1 2 3 4 5!W 6 7 8 9 1!W0 8050 853!W1 8532 _ # _ 2925 <CR>` | 2925 | yes | §3.6.4 (Wait-laden form; identical checksum — proves Wait exclusion) |
| AQ-CK-035 | `<STX> 7 9001 _ # _ 353 <CR>` | 353 | yes | §3.4.7.2 (MAT fetch answer) |
**Discrepant vector (documented checksum fails recomputation; see `protocol-gaps.md` AQ-GAP-006):**
| ID | Telegram | Documented | Recomputed | Source | Note |
|---|---|---|---|---|---|
| AQ-CK-E1 | `<SOH> 9 MAT 0 1 _ # _ 557 <CR>` | 557 | 540 | §3.4.7.2 | fetch **request**; 557 is exactly the SLT fetch checksum (copy-paste error); not approved until PDF-confirmed |
The long multi-line examples (WGS answers 7679 / 3633 / 6967 / 6968; WGH answers 6922 / 6479 / 4220; WGD answers 4984 / 5632; MCC 24268 / 28910; SLT 14331 / 15425 / 15061) are candidates for wraparound coverage (sums > 65535) but **cannot be recomputed from the markdown conversion** — blockquote markers, `\#` escapes and line-wrap artifacts survive in the conversion and alter byte sums (AQ-GAP-005). They must be transcribed from the authoritative PDF before approval; until then they are **not approved fixtures**, and the synthetic vectors below cover the wraparound branches.
**Synthetic algorithm-branch vectors (values computed and verified against the §2.4 algorithm):**
| ID | Constructed telegram | Raw sum | Expected checksum | Why |
|---|---|---|---|---|
| AQ-CK-S1 | `<STX>` + 200 × `A` + ` _ # _` | 13064 | 13064 | no wraparound — round-trip baseline *(synthetic)* |
| AQ-CK-S2 | `<STX>` + 806 × `z` + ` _ # _` | 98396 | 32676 | sum > 65535 (16-bit wraparound **and** the ≥32768 absolute-value branch: 98396 mod 65536 = 32860 → 65536−32860 = 32676) *(synthetic)* |
| AQ-CK-S3 | `<STX>` + 550 × `z` + ` _ # _` | 67164 | 1628 | wraparound **without** the absolute-value branch (67164 mod 65536 = 1628 < 32768) — isolates the mod-65536 step *(synthetic)* |
| AQ-CK-S4 | `<STX> SCO !W !W _ # _ 293 <CR>` | — | 293 | Wait bytes excluded from the sum *(synthetic; superseded by source vector AQ-CK-033/034, retained as an algorithm-level unit test)* |
---
## 2. Framing / session vectors
| ID | Scenario | Expectation | Source |
|---|---|---|---|
| AQ-FR-001 | CS dialled, RTU answers 6×OK 2.5 s apart; CS transmits request after first OK detected | conversation proceeds; the OK sequence is aborted by the incoming request | §2.2.3 |
| AQ-FR-002 | Answer arrives with Wait bytes embedded mid-token (`…65!!4321…`) | strip `!W` before tokenization; checksum unchanged; parser output equals the Wait-free form | §3.6.4 |
| AQ-FR-003 | BRK sent 3×, then hang-up | no answer expected; transport closes cleanly | §3.4.13 |
| AQ-FR-004 | Inter-character gap of 1 s inside a telegram | accepted (RTU-side limit is exactly 1 s; the gateway as CS uses 4–20 s whole-telegram timeout — §2.5) | §2.5 |
| AQ-FR-005 | Telegram data length > 4000 chars | rejected by framer; diagnostic generated (protocol max) | §2.3.2 |
## 3. Live data vectors (WGS)
| ID | Scenario | Expected decode | Source |
|---|---|---|---|
| AQ-WGS-001 | Fixed, request `901 WGS P 0 ! 11` → answer `23400 13885 01 22 0 0 0 0 0 3 0 3 3 4800 … 7 8111` | `ver=23400`, `prod=13885`, `Nal=1`, `alp=22`, `rem=0`, 21 measuring points (alp−1, hypothesis — AQ-GAP-002), then 1 alarm code (8111). Decode via `Nal`; cross-check `alp−1` diagnostically only | §3.4.10.2 (checksum not yet approvable — AQ-GAP-005 long example) |
| AQ-WGS-002 | Request with control command then BRK | command suppressed by gateway (control OUT-OF-SCOPE); BRK still required after command-bearing WGS per §3.4.13 | §3.4.10, §3.4.13 |
| AQ-WGS-003 | Request with `dir`=`!` (ignore) | no command dispatched; normal status answer | §3.4.10 |
## 4. Historical vectors (WGH)
| ID | Scenario | Expected decode | Source |
|---|---|---|---|
| AQ-WGH-001 | Request `9 WGH 01 04 30 23 30` → first answer of §3.4.12.2 (36 blocks, checksum 6922) | 36 blocks; first `1 4 30 23 35`, last `1 5 1 3 50`; 7 values per block; `!` separators; **requires AQ-GAP-003 hypothesis wiring** | §3.4.12.2 |
| AQ-WGH-002 | Continuation: request with last received block timestamp `9 WGH 01 05 01 03 50` → next answer | stream resumes at `1 5 1 3 55`; proves the watermark-resume protocol | §3.4.12.2 |
| AQ-WGH-003 | Final continuation `9 WGH 01 05 01 08 20` → `NDA` | `NDA` = normal end-of-stream, not an error; synchronization interval complete | §3.4.12.2 |
| AQ-WGH-004 | Day rollover: block `1 4 30 0 0` follows block `1 4 30 23 55` | the `00:00` block belongs to the *next* day (comment: "the last block for a day is the one with time stamp 00:00") — **no date-field jump; the date increments**; single-digit year/month/day accepted (1–2 byte fields) | §3.4.12.2 |
| AQ-WGH-005 | Answer with embedded Wait bytes (§3.7 form) | parse identical to Wait-free form; checksum identical (§3.6.4 pair) | §3.7, §3.6.4 |
| AQ-WGH-006 | Request whose span exceeds 6 hours or 4000 chars | RTU truncates per §3.4.12.1 limits; gateway detects truncated stream by receiving fewer blocks than the requested interval and re-requests from the last block timestamp (at-least-once; dedup by §13/§23 rules) | §3.4.12.1 *(synthetic scenario, specification-derived limit)* |
| AQ-WGH-007 | Scaling: CFG point `Max=0.01, Min=0, Max_input=10`, raw 64786 | `Scaled = Raw×(Max−Min)/Max_input + Min` → 64.786 — every vector decode must apply wagon scaling per station CFG, not raw values | §3.4.12.3 *(synthetic combination of documented formula + example raw value)* |
## 5. Report vectors (WGD)
| ID | Scenario | Expected decode | Source |
|---|---|---|---|
| AQ-WGD-001 | Request `5 WGD 01 05 02 13 10 01 05 01` → answer `0 0 0 501 501 0 0 0 1506 1506 …` | per point: seg1..seg4 + sum; 10 reporting points per §3.4.11.4 CFG; scaling formula per point | §3.4.11.2, §3.4.11.4 |
| AQ-WGD-002 | Empty report day → all-zero answer (§3.4.11.3) | 64 zero values decoded as valid (not NDA); zero is a legitimate report value | §3.4.11.3 |
| AQ-WGD-003 | `NDA` answer | report data for that day does not exist; mark interval missing, do not treat as failure | §3.4.11 |
## 6. Simulator scenario requirements (traceability targets)
The simulator (implementation specification §49) shall be able to replay every vector above plus inject: bad checksum (failing AQ-CK verification), truncated telegram (no `#`/`CR`), over-long telegram, inter-character stall of 1.5 s (RTU-side timeout breach), mid-telegram Wait flooding, duplicate WGH blocks across two answers (dedup regression per `ARCHITECTURE.md` §23), conflicting block re-transmission (REJECT_CONFLICT path per §13), and station clock set to a future date (timestamp-validation diagnostics per `software-specification.md` §26). The simulator must not share parsing code with the production decoder (§49).
---
**Approval state:** section 1 verified rows (AQ-CK-001–035) and section 2 approved as fixtures; AQ-CK-E1 pending AQ-GAP-006 (PDF confirmation); long examples pending AQ-GAP-005 (PDF transcription); sections 3–4 blocked by AQ-GAP-002/003 for full decode assertions (framing-level assertions may proceed; `Nal`-based decoding is documented and unblocked). Synthetic vectors subordinate to source vectors. Update this file's approval state when gaps close — never delete vectors.