A C framework for commanding a Pico WH robot over USB, WiFi or BLE with a
small text DSL. No hardware attached yet, so the whole stack runs on the
host against a simulated HAL and is covered by tests.
Two specifications drive the code:
docs/grammar.md the language — one namespace of callables (native,
firmware-resident, and defined over the wire), procedures
with named arguments and defaults, REPEAT, and the rules
that keep it safe on a microcontroller.
docs/flow.md transport, bracket-balance framing, the envelope,
admission, execution, abort and failsafe.
Three properties the design leans on:
- Bodies may only reference callables that already exist, so the call
graph is acyclic by construction, recursion is unrepresentable, and
interpreter depth is checked at definition time rather than discovered
at runtime.
- Nothing blocks. The interpreter is a resumable state machine over an
explicit frame stack, so ABORT is honoured within one tick even in the
middle of a long move, and no program can overflow the MCU stack.
- No queue. One outstanding statement at a time, which keeps abort to a
single unambiguous victim and avoids inventing an answer to "the
running program failed, does the queued one still go?".
Named arguments are resolved to the callee's parameter order at definition
time, so they cost nothing at execution.
rubo_core is target-independent. Porting to the Pico means providing a
non-blocking rubo_transport_t and a rubo_hal_t, and nothing else.
Not built yet: the Pico transport and HAL, the camera DAT/DEND bulk path,
and IF/ELIF, which is reserved in the grammar and lands with the sensors.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hfu1EFVbpee92zvzQunsKb
48 lines
1.6 KiB
CMake
48 lines
1.6 KiB
CMake
cmake_minimum_required(VERSION 3.16)
|
|
project(rubo C)
|
|
|
|
set(CMAKE_C_STANDARD 11)
|
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
|
|
|
# The core is target-independent: everything between the framer and the
|
|
# interpreter is shared by the host and Pico builds (docs/flow.md §2).
|
|
add_library(rubo_core STATIC
|
|
src/sym.c
|
|
src/lexer.c
|
|
src/registry.c
|
|
src/parser.c
|
|
src/exec.c
|
|
src/framer.c
|
|
src/session.c
|
|
src/rubo.c
|
|
src/natives.c
|
|
src/stdlib.c
|
|
)
|
|
target_include_directories(rubo_core PUBLIC include)
|
|
target_compile_options(rubo_core PRIVATE
|
|
-Wall -Wextra -Wpedantic -Wshadow -Wstrict-prototypes
|
|
)
|
|
|
|
# ----------------------------------------------------------------- host build
|
|
# Simulated HAL + stdio transport: the whole stack, no hardware.
|
|
add_library(rubo_sim STATIC src/hal_sim.c)
|
|
target_link_libraries(rubo_sim PUBLIC rubo_core)
|
|
|
|
add_executable(rubo_host host/main.c host/transport_stdio.c)
|
|
target_link_libraries(rubo_host PRIVATE rubo_core rubo_sim)
|
|
|
|
# ---------------------------------------------------------------------- tests
|
|
enable_testing()
|
|
add_executable(test_rubo tests/test_rubo.c)
|
|
target_link_libraries(test_rubo PRIVATE rubo_core rubo_sim)
|
|
target_include_directories(test_rubo PRIVATE src)
|
|
add_test(NAME rubo COMMAND test_rubo)
|
|
|
|
# ----------------------------------------------------------------- pico build
|
|
# Swapping in the real hardware means providing exactly two things: a
|
|
# rubo_transport_t over USB CDC / lwIP / BLE NUS, and a rubo_hal_t driving
|
|
# the motors. Nothing in rubo_core changes.
|
|
if(DEFINED ENV{PICO_SDK_PATH} OR DEFINED PICO_SDK_PATH)
|
|
message(STATUS "rubo: PICO_SDK_PATH set, but pico/ is not implemented yet")
|
|
endif()
|