Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f1237e8
feat(hle): add Phase 1 build system, shims, and Phase 2 SPI bridge ch…
racerxdl Jun 4, 2026
620f0b9
feat(hle): add Phase 2 SPI bridge integration
racerxdl Jun 4, 2026
bd5bb07
feat(hle): add Phase 3 P4 core, LVGL, display shims
racerxdl Jun 4, 2026
d6bc086
feat(hle): add VFS/storage stub, esp_vfs_fat, fix LVGL integration
racerxdl Jun 4, 2026
71f7d8a
feat(hle): add Phase 4 interactive mode with SDL2 + LVGL
racerxdl Jun 4, 2026
7ad93d8
feat(hle): add Phase 5 CC1101 emulator, E2E bridge tests
racerxdl Jun 4, 2026
4a2f22d
ci(hle): add HLE tests job to CI pipeline
racerxdl Jun 4, 2026
93343c4
feat(hle): HLE kernel boot sequence with boot screen and home menu
racerxdl Jun 4, 2026
6a5ae39
feat(hle): compile real firmware UI, use styled boot and home screens
racerxdl Jun 4, 2026
1c2497a
feat(hle): real firmware kernel_init() boots completely
racerxdl Jun 4, 2026
4f0208e
feat(hle): full firmware compiles and boots — real kernel_init → ui_init
racerxdl Jun 4, 2026
6a58809
fix(hle): remove duplicate lv_timer_handler() call from main loop
racerxdl Jun 4, 2026
eaa983b
fix(hle): upgrade LVGL to v9.4.0, remove duplicate lv_timer_handler
racerxdl Jun 4, 2026
34321a6
fix(hle): fix task stack size — was 8KB, now respects firmware request
racerxdl Jun 4, 2026
99063f4
fix(hle): restore host assets and button input
racerxdl Jun 4, 2026
75d2187
fix(hle): render splash assets and menu fonts
racerxdl Jun 4, 2026
883c5fa
refactor(hle): compile P4 SPI proxy services for real (#24)
racerxdl Jun 8, 2026
0c0ffbb
refactor(hle): compile P4 BLE applications for real (#25)
racerxdl Jun 8, 2026
c5ad5f7
refactor(hle): compile P4 system services for real (#26)
racerxdl Jun 8, 2026
0410e12
refactor(hle): compile hardware drivers, UI screens, and transports f…
racerxdl Jun 8, 2026
8bbb50b
feat(hle): wire SPI bridge PHY to in-memory channel with protocol fixes
racerxdl Jun 8, 2026
448e429
fix(hle): harden SPI bridge channel lifecycle and concurrency
racerxdl Jun 8, 2026
ad1a357
feat(hle): harden native simulator workflow
racerxdl Jul 30, 2026
73b3f1c
docs(hle): expand emulator run instructions
racerxdl Jul 31, 2026
558e9b9
docs(hle): add emulator screenshot and test example
racerxdl Jul 31, 2026
9e1c8d6
fix(hle): support current dev firmware interfaces
racerxdl Jul 31, 2026
a10ed4e
ci(format): check only pull request changes
racerxdl Jul 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Install clang-format
run: pip install clang-format==22.1.3

- name: Run format check
run: bash tools/format.sh --check
run: bash tools/format.sh --check-changed "${{ github.event.pull_request.base.sha }}"

commitlint:
name: Validate Commits
Expand Down Expand Up @@ -50,3 +52,25 @@ jobs:
- name: Build
run: bash tools/build.sh
shell: bash

hle-tests:
name: HLE Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libsdl2-dev

- name: Configure
run: cmake -B build -S tools/hle
env:
SDL_VIDEODRIVER: dummy

- name: Build tests
run: cmake --build build --target hle_tests -j$(nproc)

- name: Run tests
run: ./build/hle_tests
120 changes: 120 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# TentacleOS — Agent Instructions

## Project Overview

Embedded firmware for the High Boy platform (ESP32-S3/P4/C5). Dual-firmware architecture: ESP32-C5 is the co-processor, ESP32-P4 is the master that embeds the C5 binary at build time.

## Build & Flash

ESP-IDF v5.5.3 is the pinned version. Source the environment before any build command:

```bash
. $HOME/esp/v5.5.3/esp-idf/export.sh # or rely on $IDF_PATH
```

Full build (C5 then P4, in order — P4 embeds the C5 binary):

```bash
./tools/build.sh
```

Build a single target:

```bash
cd firmware_c5 && idf.py -DIDF_TARGET=esp32c5 build
cd firmware_p4 && idf.py -DIDF_TARGET=esp32p4 build
```

Flash (P4 only, which also programs C5):

```bash
./tools/flash.sh
```

## Formatting

Formatting is enforced by CI and the pre-commit hook. Run manually before committing:

```bash
./tools/format.sh # fix all firmware sources
./tools/format.sh --check # verify all firmware sources
./tools/format.sh --changed <base-ref> # fix files changed from a base
./tools/format.sh --check-changed <base-ref> # verify changed files (CI uses this)
```

Config: `.clang-format` — LLVM base, 2-space indent, 100-column limit, pointers right-aligned, no sorted includes. Only `.c` and `.h` files under `firmware_*/` are formatted.

## Commit Messages

Conventional Commits enforced by git hook and CI. Format: `<type>(<scope>): <description>`

Types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `chore`, `ci`, `build`, `revert`, `delete`, `deleted`, `remove`, `removed`

Breaking changes use `!` before the colon. Header max length: 200 chars.

## Repo Structure

```
firmware_c5/ # ESP32-C5 co-processor firmware
firmware_p4/ # ESP32-P4 master firmware (embeds C5 binary)
components/
Drivers/ # Hardware drivers (SPI, buttons, display, radio, USB)
Service/ # Support services (OTA, WiFi, console, storage, SPI bridge)
Core/ # System core and main managers
Applications/ # User-facing apps (UI, bad_usb, SubGhz)
Drivers/spi_bridge_phy/ # SPI bridge physical layer (P4 side)
main/main.c # Entry point
common/metadata/ # Shared metadata
tools/ # Build, flash, format, setup scripts
```

Each target is a standalone ESP-IDF project with its own `CMakeLists.txt`, `partitions.csv`, and `sdkconfig.defaults`.

## Coding Standards

All rules are in `CODING_STANDARDS.md`. Key points an agent must not miss:

- **Public functions** are prefixed with module name (`cc1101_set_frequency()`). **Static functions** drop the prefix (`process_pulse()`).
- **Variables**: local `snake_case`, static `s_` prefix, global `g_` prefix, bools `is_`/`has_`/`can_`, output params `out_`.
- **Types**: `module_name_t` with `_cb_t` for callbacks.
- **Constants**: `UPPER_SNAKE_CASE`. Every literal with domain meaning must be a named `#define` (except `0`, `1`, `NULL`, `true`, `false`).
- **Enums**: `UPPER_SNAKE_CASE` with module prefix, include `_COUNT` sentinel when iterable.
- **Fixed-width types** from `<stdint.h>` for all hardware code. Never rely on implicit `int`.
- **Error handling**: public functions return `esp_err_t`. Every `malloc` must be checked for `NULL`, logged with `ESP_LOGE`, and handled via `goto cleanup`.
- **Logging**: every `.c` file defines `static const char *TAG = "MODULE_NAME";`. Use `ESP_LOGx` macros, never `printf`.
- **File layout order**: license, own header, C stdlib, ESP-IDF/FreeRTOS, project headers, defines, static types, static vars, forward decls, public funcs, static funcs.
- **Headers**: `#ifndef` guards, `extern "C"` blocks, include order separated by blank lines.
- **Source file layout**: `^[0-9a-z_]+\.[ch]$`, filename is a prefix for its content.

## Hook Setup

Run once after cloning:

```bash
./tools/setup.sh
```

This sets `core.hooksPath` to `.githooks/` (pre-commit: clang-format, commit-msg: conventional commits).

## CI

GitHub Actions runs on PRs to `main`/`dev`:
1. **Format check** — `./tools/format.sh --check`
2. **Commitlint** — validates all commits in PR
3. **Build** — both targets inside `espressif/idf:v5.5.3` container via `./tools/build.sh`

All must pass before merge.

## Generated Files (do not edit)

- `managed_components/` — ESP-IDF component manager (gitignored)
- `sdkconfig` / `sdkconfig.old` — ESP-IDF build config (gitignored); use `sdkconfig.defaults` instead
- `dependencies.lock` — ESP-IDF component manager lockfile (gitignored)
- Build outputs in `build/` directories (gitignored)

## Versioning

Automated via semantic-release on `main`. Do not manage versions manually — commit messages determine bumps. Version is written to:
- `firmware_p4/assets/config/OTA/firmware.json`
- `firmware_c5/assets/config/OTA/firmware.json`
- `firmware_p4/components/Service/ota/include/ota_version.h`
134 changes: 134 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,140 @@ Example layout:
```


## Native HLE simulator

The host-level emulation (HLE) target runs the P4 UI, LVGL, host-backed storage,
and a simulated C5 SPI bridge on Linux. It is intended for UI and firmware-flow
development without a connected High Boy.

<p align="center">
<img src="pics/hle-emulator.png" alt="TentacleOS HLE emulator boot screen" width="240"/>
<br/>
<em>Boot screen rendered by the native SDL simulator.</em>
</p>

### Requirements

- Linux
- CMake 3.16 or newer
- A C11/C++17 toolchain
- Git and the SDL2 development headers
- Internet access during the first configure, which downloads LVGL, cJSON, and
GoogleTest

On Ubuntu or Debian:

```bash
sudo apt update
sudo apt install build-essential cmake git libsdl2-dev
```

ESP-IDF, an ESP32 toolchain, and connected High Boy hardware are not required
for the native simulator.

### Build and run

Run these commands from the repository root:

```bash
cmake -S tools/hle -B build
cmake --build build --target hle_interactive -j
./build/hle_interactive
```

The first build also converts the assets under `firmware_p4/assets`. After UI
or firmware changes, rerun the `cmake --build` command and restart the
simulator; reconfiguration is only needed after CMake or source-layout changes.

### Controls

| High Boy input | Keyboard |
| :--- | :--- |
| Directional buttons | Arrow keys or W/A/S/D |
| OK | Enter, keypad Enter, or Space |
| Back | Backspace or Escape |
| Exit simulator | Ctrl+Q or close the window |

### Storage

The simulator stores `/sdcard` data under `/tmp/hle_storage` by default.
Override the location with `HLE_STORAGE_PATH`:

```bash
HLE_STORAGE_PATH="$HOME/.local/state/tentacleos-hle" ./build/hle_interactive
```

Point `HLE_STORAGE_PATH` at a new empty directory to exercise the firmware's
first-boot flow again.

### Headless snapshots

For deterministic, headless UI snapshots:

```bash
SDL_VIDEODRIVER=dummy \
HLE_SNAPSHOT_PATH=/tmp/high-boy.ppm \
HLE_SNAPSHOT_MS=6500 \
./build/hle_interactive
```

The snapshot example renders for 6500 ms, writes a PPM image, and exits. It is
also suitable for CI or SSH sessions without a display server.

### Tests

Run the native regression suite with:

```bash
cmake --build build --target hle_tests -j
ctest --test-dir build --output-on-failure
```

#### Example: testing display output

Every `*.cpp` file under `tools/hle/tests` is compiled into `hle_tests` and
automatically registered with GoogleTest. For example, create
`tools/hle/tests/test_my_ui.cpp`:

```cpp
#include <array>
#include <cstdint>

#include <gtest/gtest.h>

#include "hle/hle_display.h"

TEST(MyUIScreen, DrawsExpectedPixel) {
auto &display = hle::Display::instance();
display.fill_screen(0);

constexpr uint16_t expected_color = 0xF81F;
display.draw_bitmap(12, 20, 13, 21, &expected_color);

std::array<uint16_t, hle::LCD_H_RES * hle::LCD_V_RES> framebuffer{};
ASSERT_TRUE(display.copy_pixels_if_dirty(
framebuffer.data(), hle::LCD_H_RES * sizeof(uint16_t)));
EXPECT_EQ(framebuffer[(20 * hle::LCD_H_RES) + 12], expected_color);
}
```

Build and run only that test:

```bash
cmake --build build --target hle_tests -j
./build/hle_tests --gtest_filter=MyUIScreen.DrawsExpectedPixel
```

Use the same pattern for NVS, SPI bridge, input, and other host-emulated
contracts. Tests that include C firmware headers should place those includes
inside an `extern "C"` block.

### Scope and limitations

The HLE covers UI and host-emulated firmware flows. Wi-Fi, Bluetooth, radio,
and other physical-hardware behavior still require target testing.


## How to Contribute

Contributions are what make the open-source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
Expand Down
Loading
Loading