📝 Documenation

This commit is contained in:
Jonas Bengtsson
2026-10-06 07:08:03 +02:00
parent 08d44babbb
commit e1f51772da
12 changed files with 17511 additions and 9 deletions
+114
View File
@@ -0,0 +1,114 @@
# 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.