b::application
Application code starts at fall_main(). The function receives
b::application&, which is the target-specific application
object for the selected build.
#include "b.hpp"
[[noreturn]] void fall_main(b::application& app) noexcept {
app.debug().write("boot\n");
b::run_forever([&app]() noexcept {
app.time().delay_for(b::seconds(1));
app.debug().write("tick\n");
});
}
The application does not call _start(), configure UART
registers, or choose a Linux syscall number. src/start.cpp
provides the platform entry point, constructs b::application,
and then calls fall_main().
Today b::application exposes two services:
app.debug()- the target debug sink;app.time()- the target monotonic clock and delay provider.
Makefile Commands
The root Makefile is the normal entry point for this repository.
make build Linux + RP2350 + optional ESP32 targets
make all same as make build
make strict-all require Linux, RP2350, ESP32, and ESP32 display
make firmware firmware targets only
make linux Linux applications, tests, and host tools
make ttir host font asset compiler only
make noto generate assets/noto.hpp
make noto-regular generate assets/noto-regular.hpp
make rp2350 build Pico 2 / RP2350 firmware
make esp32 build generic ESP32 firmware
make esp32-display build the T-Display firmware
make run run the Linux smoke sequence
make smoke run Linux smoke sequence and clangd checks
make clangd-check check source files with clangd
make size print artifact sizes
make tools show detected tools
make clean clean configured build trees
make distclean remove build trees
make distclean-tools remove FALL-managed ESP32 tools
Useful variables:
make linux BUILD_TYPE=RelBareSafe
make rp2350 APP=fall_hello
make esp32 ESP32_AUTO_INSTALL=0
make flash-esp32 PORT=/dev/ttyUSB1
Build For Linux
Linux x86-64 is the host target with working debug, time, sockets, and filesystem backends.
make linux
make run
Direct CMake form:
cmake -S . -B build-relbare -G Ninja \
-DCMAKE_BUILD_TYPE=RelBare \
-DFALL_EXAMPLE_TARGET=linux_x86_64 \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
cmake --build build-relbare
make run runs the current Linux smoke sequence. fall_hello
is an endless embedded-style application, so the Makefile runs
it with a timeout.
Build For Embedded ESP32
The supported embedded build path is classic ESP32 / Xtensa LX6.
The generic target id is esp32_xtensa; the T-Display board
target id is esp32_t_display.
make esp32
make flash-esp32 PORT=/dev/ttyUSB0
Build and flash the Tenstar/TTGO T-Display example:
make esp32-display
make flash-esp32-display PORT=/dev/ttyUSB0
By default ESP32_AUTO_INSTALL=1, so the Makefile may prepare
local ESP32 tools under .fall-tools/esp32. Disable that when
the Xtensa compiler and esptool.py are already managed by your
environment.
make esp32 ESP32_AUTO_INSTALL=0
RP2350 has a firmware build target in this repository, but it is currently a bring-up scaffold. This documentation only teaches Linux and embedded ESP32 as supported workflows.
Sockets
b::net::socket is a move-only RAII capability. When the object
is destroyed, an open native socket is closed. Errors are
reported as b::net::error.
The current public socket API supports IPv4 TCP and UDP on Linux. Embedded targets currently expose an unavailable network provider.
b::net::socket server{};
b::net::error status = server
.open(b::net::tcp)
.bind(b::net::loopback_ipv4(b::net::service(43191)))
.listen(b::net::backlog(1));
if (b::net::failed(status)) {
return;
}
Common operations:
open(b::net::tcp)andopen(b::net::datagram);bind(endpoint)andconnect(endpoint);listen(backlog)andaccept();send_some(),send_all(),recv_some(), andrecv_exact();set_nonblocking()andshutdown().
Socket Chains
socket_chain lets several socket operations read like one
operation. Each step runs only while the previous status is
success. The final chain value converts to b::net::error.
b::net::socket client{};
b::net::error status = client
.open(b::net::tcp)
.connect(b::net::loopback_ipv4(b::net::service(43191)))
.send_all("hello");
A chain preserves the first failure. If open() fails,
connect() and send_all() are not executed.
For fixed-capacity resumable socket work, use
socket.flow<Capacity>(). The flow stores its operation list
inside the flow object and can report that it is waiting for
readable or writable readiness.
b::net::socket client{};
a::u8 response[8]{};
auto flow = client.flow<4>();
flow.open(b::net::tcp, b::net::blocking_mode::nonblocking)
.connect(b::net::loopback_ipv4(b::net::service(43191)))
.send_all("fall-net")
.recv_exact(a::view<a::u8>{response});
b::net::operation_poll poll = flow.poll();
if (poll.state == b::net::operation_state::pending) {
auto events = b::net::events(poll.wait_for);
poll = flow.resume({events.readable, events.writable});
}
The flow state machine exists, but FALL does not yet provide a portable poller or reactor.
Filesystem
b::fs::file and b::fs::dir are move-only RAII handles.
Errors are reported as b::fs::error. The current working
backend is Linux.
Directory-relative operations use b::fs::entry_name.
entry_name rejects empty names, ., .., names containing
/, and names with embedded zeroes.
b::fs::dir root{};
b::fs::dir tmp{};
b::fs::error status = root
.open("/")
.open_dir(tmp, "tmp")
.close();
if (b::fs::failed(status)) {
return;
}
After this chain, root is closed by the cleanup step and
tmp remains open as the child directory capability.
Filesystem Chains
file_chain and dir_chain use the same sticky status idea as
socket chains. They skip later normal steps after a failure, but
close() is cleanup and still runs.
static constexpr const char name[] = "settings.bin";
static constexpr const char payload[] = "fall-fs";
b::fs::file file{};
status = tmp
.open_file(file, name, b::fs::open_mode::create_or_replace)
.write_all(payload)
.commit(b::fs::durability::data_and_metadata)
.close();
Read the file back:
a::u8 buffer[32]{};
a::usize count = 0;
status = tmp
.open_file(file, name, b::fs::open_mode::read_only)
.read_to_end(a::view<a::u8>{buffer}, &count)
.close();
Remove the file and commit the containing directory:
status = tmp.remove(name);
if (b::fs::ok(status)) {
status = tmp.commit();
}
Durability levels describe intent:
b::fs::durability::none- no synchronization request;b::fs::durability::data- persist file data;b::fs::durability::data_and_metadata- persist data and metadata;b::fs::durability::filesystem- persist the filesystem containing the handle.