diff --git a/architecture.md b/architecture.md index 37694b8..498a8a5 100644 --- a/architecture.md +++ b/architecture.md @@ -125,10 +125,10 @@ Header fields: | Value | Meaning | |---|---| | `0x0001` | Video frame | -| `0x0002` | Control request (JSON) | -| `0x0003` | Control response (JSON) | +| `0x0002` | Control request | +| `0x0003` | Control response | -Video frame payloads are raw compressed frames. Control payloads are JSON — the same request/response structure as the V4L2 RPC protocol, but carried inline on the same connection rather than on a separate port. +Video frame payloads are raw compressed frames. Control payloads are binary-serialized structures — see [Protocol Serialization](#protocol-serialization). ### Unified Control and Video on One Connection @@ -248,6 +248,35 @@ The final deliverable is a single configurable node binary. During development, --- +## Protocol Serialization + +Control message payloads use a compact binary format. The wire encoding is **little-endian** throughout — all target platforms (Raspberry Pi ARM, x86 laptop) are little-endian, and little-endian is the convention of most modern protocols (USB, Bluetooth LE, etc.). + +### Serialization Layer + +A `serial` module provides the primitive read/write operations on byte buffers: + +- `put_u8`, `put_u16`, `put_u32`, `put_i32`, `put_u64` — write a value at a position in a buffer +- `get_u8`, `get_u16`, `get_u32`, `get_i32`, `get_u64` — read a value from a position in a buffer + +These are pure buffer operations with no I/O. Fields are never written by casting a struct to bytes — each field is placed explicitly, which eliminates struct padding and alignment assumptions. + +### Protocol Layer + +A `protocol` module builds on `serial` and the transport to provide typed message functions: + +```c +write_v4l2_set_control(stream, id, value); +write_v4l2_get_control(stream, id); +write_v4l2_enumerate_controls(stream); +``` + +Each `write_*` function knows the exact wire layout of its message, packs the full frame (header + payload) into a stack buffer using `put_*`, then issues a single write to the stream. The corresponding `read_*` functions unpack responses using `get_*`. + +This gives a clean two-layer separation: `serial` handles byte layout, `protocol` handles message semantics and I/O. + +--- + ## Open Questions - What is the graph's representation format — in-memory object graph, serialized config, or both? diff --git a/conventions.md b/conventions.md index 0e837e4..5e9e437 100644 --- a/conventions.md +++ b/conventions.md @@ -4,6 +4,7 @@ - **C11** throughout (`-std=c11`) - **`_GNU_SOURCE`** defined via `-D_GNU_SOURCE` in all Makefiles — enables the full GNU/Linux feature set (POSIX 2008, BSD, GNU and Linux-specific extensions); do not define this in source files +- **LTO enabled** via `-flto` in all Makefiles — the compiler handles inlining across translation units at link time; do not use `static` on functions solely to enable inlining - Target platform: Linux (V4L2, epoll, etc. are Linux-specific) --- diff --git a/dev/cli/Makefile b/dev/cli/Makefile index 48ea0ca..5d74e5e 100644 --- a/dev/cli/Makefile +++ b/dev/cli/Makefile @@ -1,6 +1,6 @@ ROOT := $(abspath ../..) CC = gcc -CFLAGS = -std=c11 -Wall -Wextra -D_GNU_SOURCE -I$(ROOT)/include +CFLAGS = -std=c11 -Wall -Wextra -D_GNU_SOURCE -flto -I$(ROOT)/include BUILD = $(ROOT)/build COMMON_OBJ = $(BUILD)/common/error.o diff --git a/planning.md b/planning.md index c0db72c..ee1e2dc 100644 --- a/planning.md +++ b/planning.md @@ -37,14 +37,16 @@ Modules are listed in intended build order. Each depends only on modules above i | # | Module | Status | Notes | |---|---|---|---| -| 1 | `common` | not started | Error types, base definitions — no dependencies | -| 2 | `media_ctrl` | not started | Media Controller API — device and topology enumeration, pad format config | -| 3 | `v4l2_ctrl` | not started | V4L2 controls — enumerate, get, set camera parameters | -| 4 | `transport` | not started | Encapsulated transport — header encode/decode, framed TCP read/write | -| 5 | `frame_alloc` | not started | Per-frame allocation with bookkeeping (byte budget, ref counting) | -| 6 | `relay` | not started | Input dispatch to output queues (low-latency and completeness modes) | -| 7 | `ingest` | not started | MJPEG frame parser (two-pass EOI state machine, opaque stream → discrete frames) | -| 8 | `archive` | not started | Write frames to disk, control messages to JSON log | +| 1 | `common` | done | Error types, base definitions — no dependencies | +| 2 | `media_ctrl` | done | Media Controller API — device and topology enumeration, pad format config | +| 3 | `v4l2_ctrl` | done | V4L2 controls — enumerate, get, set camera parameters | +| 4 | `serial` | not started | `put`/`get` primitives for little-endian binary serialization into byte buffers | +| 5 | `transport` | not started | Encapsulated transport — frame header, TCP stream abstraction, single-write send | +| 6 | `protocol` | not started | Typed `write_*`/`read_*` functions for all message types; builds on serial + transport | +| 7 | `frame_alloc` | not started | Per-frame allocation with bookkeeping (byte budget, ref counting) | +| 8 | `relay` | not started | Input dispatch to output queues (low-latency and completeness modes) | +| 9 | `ingest` | not started | MJPEG frame parser (two-pass EOI state machine, opaque stream → discrete frames) | +| 10 | `archive` | not started | Write frames to disk, control messages to binary log | --- diff --git a/src/modules/common/Makefile b/src/modules/common/Makefile index dd5fc61..d2c5ab0 100644 --- a/src/modules/common/Makefile +++ b/src/modules/common/Makefile @@ -1,6 +1,6 @@ ROOT := $(abspath ../../..) CC = gcc -CFLAGS = -std=c11 -Wall -Wextra -D_GNU_SOURCE -I$(ROOT)/include +CFLAGS = -std=c11 -Wall -Wextra -D_GNU_SOURCE -flto -I$(ROOT)/include BUILD = $(ROOT)/build/common .PHONY: all clean diff --git a/src/modules/media_ctrl/Makefile b/src/modules/media_ctrl/Makefile index c51ac12..91aca5c 100644 --- a/src/modules/media_ctrl/Makefile +++ b/src/modules/media_ctrl/Makefile @@ -1,6 +1,6 @@ ROOT := $(abspath ../../..) CC = gcc -CFLAGS = -std=c11 -Wall -Wextra -D_GNU_SOURCE -I$(ROOT)/include +CFLAGS = -std=c11 -Wall -Wextra -D_GNU_SOURCE -flto -I$(ROOT)/include BUILD = $(ROOT)/build/media_ctrl .PHONY: all clean diff --git a/src/modules/v4l2_ctrl/Makefile b/src/modules/v4l2_ctrl/Makefile index d321706..07150bb 100644 --- a/src/modules/v4l2_ctrl/Makefile +++ b/src/modules/v4l2_ctrl/Makefile @@ -1,6 +1,6 @@ ROOT := $(abspath ../../..) CC = gcc -CFLAGS = -std=c11 -Wall -Wextra -D_GNU_SOURCE -I$(ROOT)/include +CFLAGS = -std=c11 -Wall -Wextra -D_GNU_SOURCE -flto -I$(ROOT)/include BUILD = $(ROOT)/build/v4l2_ctrl .PHONY: all clean