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.
This commit is contained in:
Bilal
2026-02-22 05:50:08 +00:00
committed by GitHub
parent 88537769f6
commit f62529ad91
8 changed files with 407 additions and 8 deletions

1
.gitignore vendored
View File

@@ -10,3 +10,4 @@ build
**/__pycache__/ **/__pycache__/
/compile_commands.json /compile_commands.json
/.cache /.cache
/.venv

View File

@@ -154,6 +154,8 @@ For more details on the internal file structures, see the [file formats document
Contributions are very welcome! Contributions are very welcome!
If you are new to the codebase, start with the [contributing docs](./docs/contributing/README.md).
If you're looking for a way to help out, take a look at the [ideas discussion board](https://github.com/crosspoint-reader/crosspoint-reader/discussions/categories/ideas). If you're looking for a way to help out, take a look at the [ideas discussion board](https://github.com/crosspoint-reader/crosspoint-reader/discussions/categories/ideas).
If there's something there you'd like to work on, leave a comment so that we can avoid duplicated effort. If there's something there you'd like to work on, leave a comment so that we can avoid duplicated effort.

View File

@@ -1,17 +1,32 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Check if clang-format is availible # Check if clang-format is available and pick the preferred binary.
command -v clang-format >/dev/null 2>&1 || { if command -v clang-format-21 >/dev/null 2>&1; then
printf "'clang-format' not found in current environment\n" CLANG_FORMAT_BIN="clang-format-21"
printf "install 'clang', 'clang-tools', or 'clang-format' depending on your distro/os and tooling requirements\n" elif command -v clang-format >/dev/null 2>&1; then
exit 1 CLANG_FORMAT_BIN="clang-format"
} else
printf "'clang-format' not found in current environment\n"
printf "Install clang-format-21 (recommended), clang, clang-tools, or clang-format depending on your distro/os and tooling requirements\n"
exit 1
fi
set -euo pipefail
GIT_LS_FILES_FLAGS="" GIT_LS_FILES_FLAGS=""
if [[ "$1" == "-g" ]]; then if [[ "${1:-}" == "-g" ]]; then
GIT_LS_FILES_FLAGS="--modified" GIT_LS_FILES_FLAGS="--modified"
fi fi
CLANG_FORMAT_VERSION_RAW="$(${CLANG_FORMAT_BIN} --version)"
CLANG_FORMAT_MAJOR="$(printf '%s\n' "${CLANG_FORMAT_VERSION_RAW}" | grep -oE '[0-9]+' | head -n1)"
if [[ -z "${CLANG_FORMAT_MAJOR}" || "${CLANG_FORMAT_MAJOR}" -lt 21 ]]; then
echo "Error: ${CLANG_FORMAT_BIN} is too old: ${CLANG_FORMAT_VERSION_RAW}"
echo "This repository's .clang-format requires clang-format 21 or newer."
echo "Install clang-format-21 and rerun ./bin/clang-format-fix"
exit 1
fi
# --- Main Logic --- # --- Main Logic ---
@@ -27,4 +42,4 @@ git ls-files --exclude-standard ${GIT_LS_FILES_FLAGS} \
| grep -v -E '^lib/EpdFont/builtinFonts/' \ | grep -v -E '^lib/EpdFont/builtinFonts/' \
| grep -v -E '^lib/Epub/Epub/hyphenation/generated/' \ | grep -v -E '^lib/Epub/Epub/hyphenation/generated/' \
| grep -v -E '^lib/uzlib/' \ | grep -v -E '^lib/uzlib/' \
| xargs -r clang-format -style=file -i | xargs -r "${CLANG_FORMAT_BIN}" -style=file -i

View File

@@ -0,0 +1,11 @@
# Contributing Docs
This section is a lightweight contributor guide for CrossPoint Reader.
It is written for software developers who may be new to embedded development.
- [Getting Started](./getting-started.md)
- [Architecture Overview](./architecture.md)
- [Development Workflow](./development-workflow.md)
- [Testing and Debugging](./testing-debugging.md)
If you are new, start with [Getting Started](./getting-started.md).

View File

@@ -0,0 +1,199 @@
# 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
```mermaid
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`.
```mermaid
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/`.
```mermaid
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.
```mermaid
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:
```text
/.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:
- [SCOPE.md](../../SCOPE.md)
- [GOVERNANCE.md](../../GOVERNANCE.md)

View File

@@ -0,0 +1,43 @@
# Development Workflow
This page defines the expected local workflow before opening a pull request.
## 1) Fork and create a focused branch
- Fork the repository to your own GitHub account
- Clone your fork locally and add the upstream repository if needed
- Branch from `master`
- Keep each PR focused on one fix or feature area
## 2) Implement with scope in mind
- Confirm your idea is in project scope: [SCOPE.md](../../SCOPE.md)
- Prefer incremental changes over broad refactors
## 3) Run local checks
```sh
./bin/clang-format-fix
pio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high
pio run
```
CI enforces formatting, static analysis, and build checks.
Use clang-format 21+ locally to match CI.
If `clang-format` is missing or too old locally, see [Getting Started](./getting-started.md).
## 4) Open the PR
- Use a semantic title (example: `fix: avoid crash when opening malformed epub`)
- Fill out `.github/PULL_REQUEST_TEMPLATE.md`
- Describe the problem, approach, and any tradeoffs
- Include reproduction and verification steps for bug fixes
## 5) Review etiquette
- Be explicit and concise in responses
- Keep discussions technical and respectful
- Assume good intent and focus on code-level feedback
For community expectations, see [GOVERNANCE.md](../../GOVERNANCE.md).

View File

@@ -0,0 +1,80 @@
# Getting Started
This guide helps you build and run CrossPoint locally.
## Prerequisites
- PlatformIO Core (`pio`) or VS Code + PlatformIO IDE
- Python 3.8+
- `clang-format` 21+ in your `PATH` (CI uses clang-format 21)
- USB-C cable
- Xteink X4 device for hardware testing
If `./bin/clang-format-fix` fails with either of these errors, install clang-format 21:
- `clang-format: No such file or directory`
- `.clang-format: error: unknown key 'AlignFunctionDeclarations'`
Examples:
```sh
# Debian/Ubuntu (try this first)
sudo apt-get update && sudo apt-get install -y clang-format-21
# If the package is unavailable, add LLVM apt repo and retry
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 21
sudo apt-get update
sudo apt-get install -y clang-format-21
# macOS (Homebrew)
brew install clang-format
```
Then verify:
```sh
clang-format-21 --version
```
The reported major version must be 21 or newer.
## Clone and initialize
```sh
git clone --recursive https://github.com/crosspoint-reader/crosspoint-reader
cd crosspoint-reader
```
If you already cloned without submodules:
```sh
git submodule update --init --recursive
```
## Build
```sh
pio run
```
## Flash
```sh
pio run --target upload
```
## First checks before opening a PR
```sh
./bin/clang-format-fix
pio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high
pio run
```
## What to read next
- [Architecture Overview](./architecture.md)
- [Development Workflow](./development-workflow.md)
- [Testing and Debugging](./testing-debugging.md)

View File

@@ -0,0 +1,48 @@
# Testing and Debugging
CrossPoint runs on real hardware, so debugging usually combines local build checks and on-device logs.
## Local checks
Make sure `clang-format` 21+ is installed and available in `PATH` before running the formatting step.
If needed, see [Getting Started](./getting-started.md).
```sh
./bin/clang-format-fix
pio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high
pio run
```
## Flash and monitor
Flash firmware:
```sh
pio run --target upload
```
Open serial monitor:
```sh
pio device monitor
```
Optional enhanced monitor:
```sh
python3 -m pip install pyserial colorama matplotlib
python3 scripts/debugging_monitor.py
```
## Useful bug report contents
- Firmware version and build environment
- Exact steps to reproduce
- Expected vs actual behavior
- Serial logs from boot through failure
- Whether issue reproduces after clearing `.crosspoint/` cache on SD card
## Common troubleshooting references
- [User Guide troubleshooting section](../../USER_GUIDE.md#7-troubleshooting-issues--escaping-bootloop)
- [Webserver troubleshooting](../troubleshooting.md)