
Adaptive Physical Communication System — Documentation
This folder is the complete documentation set for the Adaptive Physical Communication System (APCS). APCS is a Flutter app that moves text, links, photos and short videos from one phone to another using only light (animated QR codes) or sound (multi-tone chords). A third channel, vibration (motor pulses), is experimental and doesn’t work reliably on real phones yet. No Internet, Wi-Fi, Bluetooth, NFC or mobile data is involved.
The root README.md is a one-file technical manual. The documents here split that material by topic and go deeper. They add byte-level examples generated from the real code, step-by-step derivations, design rationale, developer references and operational guides.
Start here
Documentation by type
The documents follow the Diátaxis framework: each one is mainly a tutorial, a how-to guide, a reference or an explanation. Knowing which kind you need helps you pick the right page.
Tutorials: learn by doing
| Document |
What you’ll do |
| Installation |
Go from a clean machine to the app running on a phone, in Chrome and in the test suite |
| User Guide |
Make your first transfer, then learn every screen and button |
How-to guides: get a specific job done
Reference: look up exact facts
| Document |
What it lists |
| API Reference |
Every public class, function and constant in lib/core, lib/application and lib/main.dart |
| Data Formats |
Every byte layout, with real hex dumps |
| Calculations |
Every formula and worked number |
| UI Guide |
Screens, widgets, navigation and state management |
| Testing |
Every test file, the simulators and the device checklist |
| Simulation Lab |
The medium model, scenarios, orchestrator and comparison |
| Performance |
Throughput, timing tables, CPU and memory |
| Permissions and Privacy |
Every permission, why it’s needed, and how data is handled |
| Known Issues |
Limitations and code-review findings |
| Changelog |
What changed in each milestone |
| Glossary |
Terms and abbreviations |
| References |
Papers, standards and libraries |
Explanation: understand why
| Document |
The question it answers |
| System Architecture |
How are the layers and modules put together? |
| Design Decisions |
Why was each major choice made, and what else was considered? |
| Light Channel |
How does the animated fountain QR link work? |
| Sound Channel |
How do MT-FSK, Reed-Solomon and fountain coding work over audio? |
| Vibration Channel |
How is pulse-width keying between motor and accelerometer designed? (Experimental, not reliable yet.) |
| Legacy Modems |
What came before, and why was it replaced? |
| Fountain Code |
How does the LT code let the receiver finish with any K frames? |
| Reed-Solomon |
How are corrupted bytes repaired? |
| Signal Processing |
How are tones detected, synchronised and shown live? |
| Adaptive Engine |
How are channels scored and switched? |
| Security |
What is protected, what isn’t, and why? |
| FAQ |
Short answers to the questions people ask most |
| Roadmap |
Where could the project go next? |
Documentation map
docs/
├── README.md ← you are here
├── getting-started/
│ ├── INSTALLATION.md Toolchain, clone, run on phone / web
│ ├── USER_GUIDE.md Every screen and button, for end users
│ ├── SHOWCASE_GUIDE.md Demo script, checklist, talking points, recovery plan
│ └── FAQ.md Short answers to common questions
├── architecture/
│ ├── ARCHITECTURE.md Layers, modules, send/receive flows, threading
│ ├── DATA_FORMATS.md Every byte layout with real hex dumps
│ └── DESIGN_DECISIONS.md Why each major choice was made (decision records)
├── channels/
│ ├── LIGHT_CHANNEL.md Fountain QR: framing, density, camera, HUD
│ ├── SOUND_CHANNEL.md MT-FSK + Reed-Solomon + fountain over audio
│ ├── VIBRATION_CHANNEL.md Pulse-width keying with motor and accelerometer (experimental)
│ └── LEGACY_MODEMS.md CSK light, APCS1 text QR, two-tone FSK
├── algorithms/
│ ├── FOUNTAIN_CODE.md LT code: encoding, proofs, GF(2) decoder, worked example
│ ├── REED_SOLOMON.md GF(256), Berlekamp–Massey, Forney, erasures, GMD
│ ├── SIGNAL_PROCESSING.md Goertzel, tone orthogonality, sync, QR imaging, live-readout FFT
│ ├── ADAPTIVE_ENGINE.md Transport, state machine, scoring, switching
│ └── CALCULATIONS.md Every formula and worked number in one place
├── development/
│ ├── API_REFERENCE.md Public classes, functions and constants in lib/core
│ ├── UI_GUIDE.md Screens, widgets, navigation, state management
│ ├── TESTING.md Test suite, simulators, device test checklist
│ ├── SIMULATION_LAB.md Medium model, scenarios, orchestrator, comparison
│ ├── MEDIA_PIPELINE.md Compression, demo samples, explainer tooling, Gallery
│ └── CONTRIBUTING.md Workflow, code style, adding features safely
├── operations/
│ ├── BUILD_AND_RELEASE.md APK / iOS / web builds, signing, versioning
│ ├── PERMISSIONS_AND_PRIVACY.md Every permission and why; data handling
│ ├── SECURITY.md Threat model and what is (not) protected
│ ├── PERFORMANCE.md Throughput, timing tables, CPU and memory
│ └── TROUBLESHOOTING.md Symptoms → causes → fixes
├── project/
│ ├── CHANGELOG.md Version history
│ ├── ROADMAP.md Planned and possible future work
│ ├── KNOWN_ISSUES.md Limitations and code-review findings
│ ├── GLOSSARY.md Terms and abbreviations
│ └── REFERENCES.md Papers, standards, libraries
└── images/ Screenshots used by the guides and the root README
The system in one page
SENDER PHONE RECEIVER PHONE(S)
┌──────────────────────────────┐ ┌──────────────────────────────┐
│ Text / link / photo / video │ │ Message card, video player, │
│ │ │ │ auto-save to Gallery │
│ APCM envelope (7 B + name │ │ ▲ │
│ + MIME + raw bytes) │ │ APCM envelope validated │
│ │ │ │ ▲ │
│ LT fountain encoder │ │ LT decoder (GF(2) exact) │
│ (endless fresh symbols) │ │ done at rank = K │
│ │ │ │ │ ▲ ▲ │
│ APCF frame Acoustic frame │ │ APCF+CRC32 RS+CRC16 │
│ + CRC-32 + CRC-16 + RS │ │ ▲ ▲ │
│ │ │ │ │ │ │ │
│ QR code on MT-FSK chords │ ~~~ light ~~~► │ camera + microphone + │
│ full-bright from speaker │ ~~~ sound ~~~► │ zxing2 Goertzel │
│ screen │ │ │
│ │ │ │
│ Vibration: packets + CRC-32 │ ~~ contact ~~► │ accelerometer pulse timing │
└──────────────────────────────┘ └──────────────────────────────┘
The four ideas that make it work:
- Rateless fountain coding. The sender never repeats itself and never waits for replies. The receiver completes as soon as it has caught about K good frames, whichever frames those are. See Fountain Code.
- Camera-realistic QR density. QR codes are kept sparse (version 8–12) because, in the camera simulator and in an early field test, a hand-held camera read a dense (version 20) code only about 11–13% of the time. See Light Channel.
- Soft-decision acoustic decoding. The demodulator reports which bytes it is unsure of, and Reed-Solomon spends half the parity on those. See Sound Channel and Reed-Solomon.
- Honest simulation before hardware. Headless models of a phone camera and of a room drove every design number. See Testing.
Key numbers
Most of these values are exact, because they’re set in the code: frame sizes, frequencies, tone spacing and the scoring weights. The rates are nominal, calculated from each profile’s timing; real transfers take longer when frames are lost, and results vary between phones. See Performance for how each figure is derived.
| Quantity |
Value |
Where explained |
| Light frame overhead |
26 bytes (22 header + 4 CRC-32) |
Data Formats |
| Light bytes per QR (Auto) |
160 / 240 / 330 → QR v8 / v10 / v12 |
Light Channel |
| Light display rate |
12 frames/s (Safe: 8) |
Light Channel |
| Sound rates (nominal) |
10.8 / 18.1 / 27.0 / 35.8 B/s audible; 3.4 / 5.0 B/s Silent (18–20 kHz) |
Sound Channel |
| Sound tone spacing |
44 100 / 1024 = 43.066 Hz |
Signal Processing |
| Sound time per bit |
Standard 2.9 ms raw / 4.6 ms net; Silent 11.6 ms raw / 25 ms net (16-ary FSK, 4 bits per tone) |
FAQ |
| Reed-Solomon repair |
up to 12 errors or 24 erasures per 99-byte frame |
Reed-Solomon |
| Fountain overhead |
mean 0–2.2 extra symbols (measured in tests) |
Fountain Code |
| Adaptive score |
0.35T + 0.25R + 0.15L + 0.15C + 0.10S |
Adaptive Engine |
| Vibration (nominal; experimental, unreliable) |
≈0.5 B/s |
Vibration Channel |
Conventions used in these documents
- Byte order. Light and Sound frames are big-endian. Protocol packets are little-endian. Every table says which.
- Hex dumps are real output of the project’s own codecs (generated on 27 Sep 2026; envelope and Sound dumps regenerated on 28 Sep 2026 for the compact envelopes and the Silent band), not hand-written.
- “K” always means the number of source blocks in a fountain transfer.
- File paths are relative to the project root, e.g.
lib/core/physical/fountain/lt_codec.dart.
- Numbers are copied from the code. If the code and a document ever disagree, the code wins. Please fix the document (see Contributing).
- Style. British English in prose, “you” for the reader, bold for buttons and labels in the app,
code font for files, classes and commands. The full style rules are in Contributing §9.
Getting help
- Search these documents; the FAQ and Troubleshooting answer most questions.
- Check Known Issues to see whether the problem is already known.
- Open an issue on GitHub using the Bug report, Device test report or Feature request form.
- For a security problem, don’t open an issue; follow the security policy.