Files
crosspoint-reader-mod/docs/contributing/architecture.md
Bilal f62529ad91 docs: Add lightweight contributor onboarding documentation (#894)
### Summary

This PR introduces a lightweight contributor onboarding docs section
under `docs/contributing/` and improves local formatting ergonomics for
first-time contributors.

The goal is to make CrossPoint easier to contribute to for software
developers who are new to embedded systems (like me), while keeping
onboarding modular and aligned with existing project docs.

### What changed

- Added contributor docs hub: `docs/contributing/README.md`
- Added focused onboarding pages:
  - `docs/contributing/getting-started.md`
  - `docs/contributing/architecture.md`
  - `docs/contributing/development-workflow.md`
  - `docs/contributing/testing-debugging.md`
- Linked contributor docs from `README.md` for discoverability
- Expanded architecture documentation with Mermaid diagrams
- Improved `bin/clang-format-fix`:
  - prefers `clang-format-21` when available
- validates formatter version and fails fast with a clear message if too
old
  - handles missing positional arg safely
- Updated docs to explain common `clang-format` setup/version issues and
install paths (including fallback steps when `clang-format-21` is
unavailable in default apt sources)

### Why

- There was no dedicated contributor onboarding path; first-time
contributors had to infer workflow from multiple files.
- New contributors (especially from non-embedded backgrounds) need a
clear mental model of architecture, runtime flow, and debugging process.
- Local formatting setup caused avoidable friction due to clang-format
version mismatch (`.clang-format` expects newer keys used in CI).
- The updates make contribution setup more predictable, reduce
onboarding confusion, and align local checks with CI expectations.

### Additional context

- No firmware behavior/runtime logic was changed; this PR focuses on
contributor experience and tooling clarity.

---

### AI Usage

> Did you use AI tools to help write this code?

Yes, I used AI tools to assist with generating the documentation. I then
manually reviewed, tested, and refined the code to ensure it works
correctly. please feel free to point out any discrepancies or areas for
improvement.
2026-02-22 16:50:08 +11:00

6.5 KiB

Architecture Overview

CrossPoint is firmware for the Xteink X4 (unaffiliated with Xteink), built with PlatformIO targeting the ESP32-C3 microcontroller.

At a high level, it is firmware that uses an activity-driven application architecture loop with persistent settings/state, SD-card-first caching, and a rendering pipeline optimized for e-ink constraints.

System at a glance

graph TD
    A[Hardware: ESP32-C3 + SD + E-ink + Buttons] --> B[open-x4-sdk HAL]
    B --> C[src/main.cpp runtime loop]
    C --> D[Activities layer]
    C --> E[State and settings]
    D --> F[Reader flows]
    D --> G[Home/Library/Settings flows]
    D --> H[Network/Web server flows]
    F --> I[lib/Epub parsing + layout + hyphenation]
    I --> J[SD cache in .crosspoint]
    D --> K[GfxRenderer]
    K --> L[E-ink display buffer]

Runtime lifecycle

Primary entry point is src/main.cpp.

flowchart TD
    A[Boot] --> B[Init GPIO and optional serial]
    B --> C[Init SD storage]
    C --> D[Load settings and app state]
    D --> E[Init display and fonts]
    E --> F{Resume reader?}
    F -->|No| G[Enter Home activity]
    F -->|Yes| H[Enter Reader activity]
    G --> I[Main loop]
    H --> I
    I --> J[Poll input and run current activity]
    J --> K{Sleep condition met?}
    K -->|No| I
    K -->|Yes| L[Persist state and enter deep sleep]

In each loop iteration, the firmware updates input, runs the active activity, handles auto-sleep/power behavior, and applies a short delay policy to balance responsiveness and power.

Activity model

Activities are screen-level controllers deriving from src/activities/Activity.h. Some flows use src/activities/ActivityWithSubactivity.h to host nested activities.

  • onEnter() and onExit() manage setup/teardown
  • loop() handles per-frame behavior
  • skipLoopDelay() and preventAutoSleep() are used by long-running flows (for example web server mode)

Top-level activity groups:

  • src/activities/home/: home and library navigation
  • src/activities/reader/: EPUB/XTC/TXT reading flows
  • src/activities/settings/: settings menus and configuration
  • src/activities/network/: WiFi selection, AP/STA mode, file transfer server
  • src/activities/boot_sleep/: boot and sleep transitions

Reader and content pipeline

Reader orchestration starts in src/activities/reader/ReaderActivity.h and dispatches to format-specific readers. EPUB processing is implemented in lib/Epub/.

flowchart LR
    A[Select book] --> B[ReaderActivity]
    B --> C{Format}
    C -->|EPUB| D[lib/Epub/Epub]
    C -->|XTC| E[lib/Xtc reader]
    C -->|TXT| F[lib/Txt reader]
    D --> G[Parse OPF/TOC/CSS]
    G --> H[Layout pages/sections]
    H --> I[Write section and metadata caches]
    I --> J[Render current page via GfxRenderer]

Why caching matters:

  • RAM is limited on ESP32-C3, so expensive parsed/layout data is persisted to SD
  • repeat opens/page navigation can reuse cached data instead of full reparsing

Reader internals call graph

This diagram zooms into the EPUB path to show the main control and data flow from activity entry to on-screen draw.

flowchart TD
    A[ReaderActivity onEnter] --> B{File type}
    B -->|EPUB| C[Create Epub object]
    B -->|XTC/TXT| Z[Use format-specific reader]

    C --> D[Epub load]
    D --> E[Locate container and OPF]
    E --> F[Build or load BookMetadataCache]
    F --> G[Load TOC and spine]
    G --> H[Load or parse CSS rules]

    H --> I[EpubReaderActivity]
    I --> J{Section cache exists for current settings?}
    J -->|Yes| K[Read section bin from SD cache]
    J -->|No| L[Parse chapter HTML and layout text]
    L --> M[Apply typography settings and hyphenation]
    M --> N[Write section cache bin]

    K --> O[Build page model]
    N --> O
    O --> P[GfxRenderer draw calls]
    P --> Q[HAL display framebuffer update]
    Q --> R[E-ink refresh policy]

    S[SETTINGS singleton] -. influences .-> J
    S -. influences .-> M
    T[APP_STATE singleton] -. persists .-> U[Reading progress and resume context]
    U -. used by .-> I

Notes:

  • "section cache exists" depends on cache-busting parameters such as font and layout-related settings
  • rendering favors reusing precomputed layout data to keep page turns responsive on constrained hardware
  • progress/session state is persisted so the reader can reopen at the last position after reboot/sleep

State and persistence

Two singletons are central:

  • src/CrossPointSettings.h (SETTINGS): user preferences and behavior flags
  • src/CrossPointState.h (APP_STATE): runtime/session state such as current book and sleep context

Typical persisted areas on SD:

/.crosspoint/
  epub_<hash>/
    book.bin
    progress.bin
    cover.bmp
    sections/*.bin
  settings.bin
  state.bin

For binary cache formats, see docs/file-formats.md.

Networking architecture

Network file transfer is controlled by src/activities/network/CrossPointWebServerActivity.h and served by src/network/CrossPointWebServer.h.

Modes:

  • STA: join existing WiFi network
  • AP: create hotspot

Server behavior:

  • HTTP server on port 80
  • WebSocket upload server on port 81
  • file operations backed by SD storage
  • activity requests faster loop responsiveness while server is running

Endpoint reference: docs/webserver-endpoints.md.

Build-time generated assets

Some sources are generated and should not be edited manually.

  • scripts/build_html.py generates src/network/html/*.generated.h from HTML files
  • scripts/generate_hyphenation_trie.py generates hyphenation headers under lib/Epub/Epub/hyphenation/generated/

When editing related source assets, regenerate via normal build steps/scripts.

Key directories

  • src/: app orchestration, settings/state, and activity implementations
  • src/network/: web server and OTA/update networking
  • src/components/: theming and shared UI components
  • lib/Epub/: EPUB parser, layout, CSS handling, and hyphenation
  • lib/: supporting libraries (fonts, text, filesystem helpers, etc.)
  • open-x4-sdk/: hardware SDK submodule (display, input, storage, battery)
  • docs/: user and technical documentation

Embedded constraints that shape design

  • constrained RAM drives SD-first caching and careful allocations
  • e-ink refresh cost drives render/update batching choices
  • main loop responsiveness matters for input, power handling, and watchdog safety
  • background/network flows must cooperate with sleep and loop timing logic

Scope guardrails

Before implementing larger ideas, check: