summaryrefslogtreecommitdiff
path: root/README.md
diff options
context:
space:
mode:
authorcirakg <cirakg@cirakg.xyz>2026-10-20 11:24:58 +0200
committercirakg <cirakg@cirakg.xyz>2026-10-20 11:24:58 +0200
commitd360f8ed78adf08e2a99df0be141b0a823cf8be9 (patch)
tree79073507ca89b88479b961fa7f17ec25c83c6dd9 /README.md
parent1251aab9f8f9f38aa5bdefd4fed1f58236166cf8 (diff)
docs: record M6c (Data Matrix, PDF417) results
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'README.md')
-rw-r--r--README.md10
1 files changed, 9 insertions, 1 deletions
diff --git a/README.md b/README.md
index 9655d4f..b9a119b 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,13 @@
A Garmin Connect IQ watch app that shows one-time passwords (TOTP, HOTP, and optional Steam Guard codes) and stores barcodes and QR codes (loyalty cards, tickets) to show at a scanner. Everything lives encrypted on the watch. There is no cloud, no backend and no analytics, and the app requests no permissions, so it cannot use the network.
-> **Status: M6a (linear barcodes) and M6b (QR) done; M6c-M6d (Data Matrix, PDF417, Aztec) next; M1 (settings spike) ready for your phone test.** The plan below was approved on 2026-10-18. M0 built the Docker toolchain and pipeline, M2 the crypto and OTP core, M3 the encrypted vault ([docs/SECURITY.md](docs/SECURITY.md)), M4 the screens and M5 import (`otpauth://` and Aegis JSON via the phone settings). M6a added the code screen and the eight linear symbologies. M6b added QR Code: versions 1 to 40, levels L to H, optimal mode segmentation and all eight masks, encoded on the watch as a resumable job and cached encrypted. QR is checked against segno module for module and decoded with zxing-cpp, and screenshots of both kinds of code decode on seven simulated watches. The settings spike (`make spike`, [docs/SETTINGS_SPIKE.md](docs/SETTINGS_SPIKE.md)) waits for your test. The Phase 0 research, with sources, is in [docs/FEASIBILITY.md](docs/FEASIBILITY.md); the daily workflow is in [docs/DEVELOPER_GUIDE.md](docs/DEVELOPER_GUIDE.md).
+> **Status: M6a-M6c (linear barcodes, QR, Data Matrix, PDF417) done; M6d (Aztec) next; M1 (settings spike) ready for your phone test.** The plan below was approved on 2026-10-18. M0 built the Docker toolchain and pipeline, M2 the crypto and OTP core, M3 the encrypted vault ([docs/SECURITY.md](docs/SECURITY.md)), M4 the screens and M5 import (`otpauth://` and Aegis JSON via the phone settings). M6 added the code screen and, so far, 11 of the 12 symbologies, encoded on the watch:
+>
+> - **Linear codes** are encoded directly.
+> - **2D codes** are encoded as resumable jobs and cached encrypted.
+> - **Checks:** each is compared with a reference encoder (zxing-cpp, segno, ppf.datamatrix, pdf417gen) and decoded with zxing-cpp, and screenshots of four kinds of code decode on seven simulated watches.
+>
+> The settings spike (`make spike`, [docs/SETTINGS_SPIKE.md](docs/SETTINGS_SPIKE.md)) waits for your test. The Phase 0 research, with sources, is in [docs/FEASIBILITY.md](docs/FEASIBILITY.md); the daily workflow is in [docs/DEVELOPER_GUIDE.md](docs/DEVELOPER_GUIDE.md).
"OTP Wallet" is a working title.
@@ -590,6 +596,8 @@ Linear: EAN-13 needs 113 modules, which means 1 px per module on a 218 px screen
1. **Reference comparison**: Python reference encoders in Docker (zxing-cpp's writer, segno for QR with forced version and mask, and others) generate expected bar patterns and matrices for fixed parameters. The watch encoder must match them exactly wherever the output is deterministic: the EAN/UPC family, Code 39, ITF, Codabar, QR with forced version and mask, and Data Matrix in ASCII mode. Code 128 is the exception, because it has several equally short encodings. zxing-cpp 3 writes through zint, which breaks those ties differently from the zxing rules the watch uses. For Code 128 the module count must match (it did for 5,000 random strings), and the code must decode (check 2). For QR there are two deliberate differences from segno:
- **Padding.** segno adds a whole zero byte when the bit stream already ends on a codeword boundary (always the case in byte mode). ISO/IEC 18004 7.4.10 adds no padding there, and the watch follows the standard. The exact references therefore use payloads that segno pads correctly.
- **Segmentation.** segno encodes one mode per symbol, while the watch segments optimally. The exact references use single-mode payloads, and mixed content is covered by decoding.
+
+ Data Matrix is compared with ppf.datamatrix in ASCII mode. ppf turns a pad codeword of exactly 254 into 0 (`(R + 130) % 254`), while ISO/IEC 16022 5.2.3 keeps 254, so the references avoid payloads whose padding hits that value. PDF417 is compared with pdf417gen at fixed columns and level. The watch mirrors pdf417gen's compaction rules, so its rows match exactly.
2. **Decoding**: the simulator tests dump every encoder output. It's rendered at each device's module size and decoded with zxing-cpp, which reads all 12 symbologies. The decoded text must equal the input, for hundreds of seeded random payloads per symbology.
3. **Screenshots**: simulator screenshots of the code screen on Forerunner 255S, Venu Sq 2 and Forerunner 965 must decode with zxing-cpp.
4. **Real world** (manual checklist): your phone's camera, plus any real shop scanner you can try, indoors and outdoors, on MIP and AMOLED.