diff options
| author | cirakg <cirakg@cirakg.xyz> | 2026-10-20 06:56:58 +0200 |
|---|---|---|
| committer | cirakg <cirakg@cirakg.xyz> | 2026-10-20 06:56:58 +0200 |
| commit | 93d0becabf76aaa568989f295ca9b8a2c387f0cc (patch) | |
| tree | 14adc56b77d791ebe387c411f7de65063119df0e /README.md | |
| parent | f455246fde086dda0cb61b92c84a5146a831a2bf (diff) | |
docs: record M6b (QR) results
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'README.md')
| -rw-r--r-- | README.md | 6 |
1 files changed, 4 insertions, 2 deletions
@@ -6,7 +6,7 @@ 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) done; M6b-M6d (QR, 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 EAN-13, EAN-8, UPC-A, UPC-E, Code 128, Code 39, ITF and Codabar encoders. They're checked against zxing-cpp reference rows and decoded at 1 to 3 px per module, and a screenshot of the code screen decodes 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 (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). "OTP Wallet" is a working title. @@ -587,7 +587,9 @@ Linear: EAN-13 needs 113 modules, which means 1 px per module on a 218 px screen ### 12.4 How each symbology is proven scannable -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). +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. 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. |
