Skip to content

zeyadhost/engelbart

Repository files navigation

Engelbart

Engelbart is a compile-time USB device compiler for embedded C++.

Users describe a USB device with a high-level, strongly typed C++ API. Engelbart generates USB descriptors, HID report descriptors, endpoint layouts, interface numbering, composite device configuration, TinyUSB-facing glue, validation results, and human-readable inspection output.

The first target is RP2040 / Raspberry Pi Pico WH with Pico SDK, TinyUSB, CMake, GCC ARM Embedded, and C++20 where the toolchain supports it. The current implementation is intentionally narrow: HID mouse, boot keyboard, and composite mouse + keyboard with separate HID interfaces.

Engelbart is not a USB attack framework, BadUSB toolkit, anti-cheat tool, GUI product, build-system replacement, runtime descriptor interpreter, or general embedded ecosystem. The core project is the typed descriptor compiler and the generated bytes must remain inspectable.

Status

Engelbart is pre-1.0. Public APIs, generated artifact formats, and diagnostic IDs may still change.

Implemented now:

  • header-only C++20 core library
  • typed device identities and minimal HID device models
  • byte-exact device, configuration, string, and HID report descriptors
  • deterministic endpoint and interface allocation for the supported devices
  • validation with diagnostic IDs
  • inspection text for generated descriptors and allocation state
  • TinyUSB descriptor callback helpers
  • host-side tests and golden descriptor fixtures
  • Pico WH / TinyUSB smoke firmware with UF2 output and picotool reset support

Deferred until a later RFC or ADR:

  • CDC, MIDI, gamepad, vendor class, and richer HID models
  • runtime descriptor reconfiguration
  • runtime descriptor interpretation
  • CLI, GUI, dashboard, Studio, or host-side Inspector
  • broad board support beyond RP2040 / Pico WH

Technology Stack

  • C++20
  • CMake 3.20 or newer
  • Pico SDK for the hardware smoke target
  • TinyUSB as the year-one USB device stack
  • GCC ARM Embedded / arm-none-eabi-g++ for Pico builds
  • picotool for the verified USB-only smoke workflow

Architecture

The project is organized around a static transformation:

typed device description
    -> validation
    -> descriptor bytes
    -> endpoint and interface allocation
    -> inspection output
    -> TinyUSB-facing callback glue

The public model describes USB devices, HID capabilities, descriptors, endpoints, and interfaces. TinyUSB is the implementation layer used by the Pico target, not the primary authoring model.

Generated descriptors are emitted as bytes rather than host-packed C++ structs. Tests verify byte output, length fields, string descriptor encoding, endpoint allocation, interface numbering, HID report descriptors, and TinyUSB callback routing.

Getting Started

Host Build

Build the host examples and tests:

cmake -S . -B build
cmake --build build
ctest --test-dir build --output-on-failure

The host build produces:

  • engelbart_tests
  • engelbart_mouse_example
  • engelbart_keyboard_example
  • engelbart_composite_example

Pico Smoke Build

Build the Pico WH / TinyUSB smoke firmware when PICO_SDK_PATH and the ARM embedded toolchain are available:

cmake -S examples/pico_tinyusb_smoke -B build-pico-smoke -DPICO_BOARD=pico_w
cmake --build build-pico-smoke

The smoke build emits ELF, UF2, BIN, and HEX outputs through the Pico SDK. The UF2 path is:

build-pico-smoke/engelbart_pico_tinyusb_smoke.uf2

Hardware Smoke Workflow

The Pico smoke firmware uses the pid.codes-style test VID/PID 1209:0003. RP2040 BOOTSEL mode uses Raspberry Pi VID/PID 2e8a:0003.

To ask the running smoke firmware to reboot into BOOTSEL:

sudo picotool reboot -u -f --vid 0x1209 --pid 0x0003 || true

Once the board is in BOOTSEL, use plain picotool commands without the smoke firmware VID/PID filter:

sudo picotool info -a
sudo picotool load -x build-pico-smoke/engelbart_pico_tinyusb_smoke.uf2

See hardware testing for Linux permission notes, picotool's serial-tracking behavior, and the SWD/OpenOCD automation path. The reset support in the smoke firmware is development harness infrastructure; it does not make CDC or vendor class a supported Engelbart-generated USB class.

Minimal API Example

The current API is small and may change before 1.0:

#include <iostream>

#include "engelbart/engelbart.hpp"

using example_identity = engelbart::identity<
    0x1209,
    0x0001,
    engelbart::fixed_string{"Engelbart Example"},
    engelbart::fixed_string{"Example HID Mouse"}>;

using example_device = engelbart::hid_mouse<example_identity>;

int main() {
    static_assert(engelbart::validate_device<example_device>().ok());
    std::cout << engelbart::inspect_device<example_device>();
}

Examples use non-impersonating test identities. Do not use real vendor IDs, product IDs, manufacturer strings, or product strings in examples unless they belong to the project using them.

Project Structure

include/engelbart/              Header-only core library
examples/                       Host examples
examples/pico_tinyusb_smoke/    Pico WH / TinyUSB smoke firmware
tests/                          Host tests and golden descriptor fixtures
docs/adr/                       Accepted architecture decisions
docs/rfc/                       API and descriptor layout RFCs
docs/design-history/            Public design-history summaries
docs/hardware-testing.md        Hardware smoke workflow

The local internal/ directory is ignored by git and is not part of the public project.

Development Workflow

Keep changes inside the project identity: a compile-time USB device compiler for embedded C++.

For descriptor changes:

  • update or add byte-exact golden tests
  • verify descriptor length fields and little-endian encoding
  • update inspection expectations when visible output changes
  • document compatibility-relevant descriptor byte changes
  • avoid runtime descriptor synthesis unless an ADR explicitly allows it

For Pico/TinyUSB changes:

  • keep the Engelbart core separate from smoke-test harness conveniences
  • do not treat development-only reset support as a generated USB class
  • verify the Pico smoke build still emits a UF2
  • update hardware testing when the real workflow changes

For scope changes:

  • start with an RFC or ADR
  • check non-goals
  • keep examples free of real-product impersonation

Coding Standards

  • Prefer compile-time generation and validation where practical.
  • Emit descriptor bytes explicitly; do not rely on host struct packing or host endianness.
  • Keep generated output deterministic and inspectable.
  • Avoid hidden global registration, static constructor side effects, and runtime descriptor trees.
  • Keep abstractions zero-cost for generated descriptors.
  • Treat TinyUSB as an integration boundary, not the user's main device description language.
  • Keep diagnostics actionable and test diagnostic IDs plus key message fragments.

Testing

Run the standard host test loop:

cmake -S . -B build
cmake --build build
ctest --test-dir build --output-on-failure

The test strategy covers:

  • pure descriptor generation
  • byte-exact golden descriptors
  • HID report descriptor bytes
  • USB string descriptor encoding and indexes
  • endpoint and interface allocation
  • validation failures and diagnostic IDs
  • TinyUSB callback routing
  • inspection output

Pico hardware enumeration remains manual or CI-hardware-dependent. The repository provides a smoke firmware, not a complete hardware lab automation system.

Documentation

Start with these documents:

Contributing

Contributions should make the supported descriptor compiler clearer, smaller, better tested, or more correct. Avoid adding product surfaces or USB classes before the core model needs them. See CONTRIBUTING.md.

Before changing generated bytes, explain why the byte output changes and update the golden tests deliberately. Before adding a new device class or target board, write the design down first.

License

Engelbart is distributed under the MIT License.

About

A compile-time USB device compiler for embedded C++

Topics

Resources

License

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors