architecture.md: replace JSON control payloads with binary serialization; add Protocol Serialization section describing little-endian wire format, put/get buffer layer, and write_*/read_* protocol layer. planning.md: mark common/media_ctrl/v4l2_ctrl done; insert serial (#4) and protocol (#6) modules with descriptions. conventions.md: document -flto and its implication (no manual static for inlining — compiler handles it at link time). Makefiles: add -flto to CFLAGS in all four Makefiles. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
179 lines
5.2 KiB
Markdown
179 lines
5.2 KiB
Markdown
# Conventions and Preferences
|
|
|
|
## Language
|
|
|
|
- **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)
|
|
|
|
---
|
|
|
|
## Naming
|
|
|
|
| Kind | Convention | Example |
|
|
|---|---|---|
|
|
| Structs | `Title_Snek_Case` | `struct App_Error`, `struct Frame_Header` |
|
|
| Enums (type) | `Title_Snek_Case` | `enum Error_Code` |
|
|
| Enum values | `CAPITAL_SNEK_CASE` | `ERR_NONE`, `ERR_SYSCALL` |
|
|
| Functions | `lower_snek_case` | `v4l2_ctrl_open()`, `app_error_print()` |
|
|
| Local variables | `lower_snek_case` | `frame_count`, `device_fd` |
|
|
| Constants (`#define`, `const`) | `CAPITAL_SNEK_CASE` | `MAX_FRAME_SIZE` |
|
|
| Module-level singletons | `lower_snek_case` | (treated as functions) |
|
|
|
|
Identifiers are prefixed with their module name where disambiguation is needed (e.g. `v4l2_ctrl_`, `media_ctrl_`, `transport_`).
|
|
|
|
---
|
|
|
|
## Types
|
|
|
|
### No typedefs for structs
|
|
|
|
Always use the `struct` keyword at the call site. This makes composite types unambiguous without inspecting declarations.
|
|
|
|
```c
|
|
/* correct */
|
|
struct App_Error err = app_error_ok();
|
|
void process(struct Frame_Header *header);
|
|
|
|
/* wrong */
|
|
typedef struct { ... } App_Error;
|
|
```
|
|
|
|
### typedefs are acceptable for
|
|
|
|
- Enums: `typedef enum Error_Code { ... } Error_Code;` — allows using the name without `enum` keyword
|
|
- Scalar aliases where the underlying type is genuinely irrelevant to the caller (e.g. `typedef uint32_t Frame_Id;`)
|
|
|
|
---
|
|
|
|
## Formatting
|
|
|
|
- **Indentation**: tabs (display width 4)
|
|
- **Braces**: always use block braces, including single-statement bodies
|
|
|
|
```c
|
|
/* correct */
|
|
if (err.code != ERR_NONE) {
|
|
return err;
|
|
}
|
|
|
|
/* wrong */
|
|
if (err.code != ERR_NONE)
|
|
return err;
|
|
```
|
|
|
|
- **Quotes**: double quotes for string literals (C standard)
|
|
|
|
---
|
|
|
|
## Error Handling
|
|
|
|
Errors are returned as `struct App_Error` values. Functions that can fail return `struct App_Error` directly, or take an out-parameter for the result alongside it.
|
|
|
|
### Structure
|
|
|
|
```c
|
|
/* modules/common/error.h */
|
|
|
|
typedef enum Error_Code {
|
|
ERR_NONE = 0,
|
|
ERR_SYSCALL = 1, /* errno is meaningful */
|
|
ERR_INVALID = 2,
|
|
} Error_Code;
|
|
|
|
struct Syscall_Error_Detail {
|
|
int err_no;
|
|
};
|
|
|
|
struct Invalid_Error_Detail {
|
|
/* fields added as concrete cases arise */
|
|
};
|
|
|
|
struct App_Error {
|
|
Error_Code code;
|
|
const char *file; /* __FILE__ — future: replaced by generated location code */
|
|
int line; /* __LINE__ — future: replaced by generated location code */
|
|
union {
|
|
struct Syscall_Error_Detail syscall;
|
|
struct Invalid_Error_Detail invalid;
|
|
} detail;
|
|
};
|
|
```
|
|
|
|
### Macros
|
|
|
|
```c
|
|
#define APP_OK \
|
|
((struct App_Error){ .code = ERR_NONE })
|
|
|
|
#define APP_IS_OK(e) \
|
|
((e).code == ERR_NONE)
|
|
|
|
#define APP_ERROR(error_code, detail_field, ...) \
|
|
((struct App_Error){ \
|
|
.code = (error_code), \
|
|
.file = __FILE__, \
|
|
.line = __LINE__, \
|
|
.detail = { .detail_field = { __VA_ARGS__ } } \
|
|
})
|
|
|
|
#define APP_SYSCALL_ERROR() \
|
|
APP_ERROR(ERR_SYSCALL, syscall, .err_no = errno)
|
|
```
|
|
|
|
### Presentation
|
|
|
|
Each error kind is handled in `app_error_print()`, which writes a human-readable description to stderr. A JSON writer (`app_error_write_json()`) will be added later and will use the same structured fields.
|
|
|
|
### Future upgrade
|
|
|
|
When the custom preprocessor is available, `__FILE__` and `__LINE__` will be replaced by a generated numeric location code that uniquely identifies the error site in the project. JSON consumers will see the same struct shape either way.
|
|
|
|
---
|
|
|
|
## Directory Structure
|
|
|
|
```
|
|
video-setup/
|
|
src/ - all C source files
|
|
modules/ - translation units; each has a .c and a Makefile
|
|
common/ - shared types (error, base definitions); no external dependencies
|
|
<module>/
|
|
node/ - video node entry point and integration (later)
|
|
include/ - public headers (.h files)
|
|
dev/ - development aids; not part of the final deliverable
|
|
cli/ - exploratory CLI drivers, one per module
|
|
experiments/ - freeform experiments
|
|
tests/ - automated tests (later)
|
|
Makefile - top-level build
|
|
```
|
|
|
|
Source files live in `src/`. Public headers live in `include/`. CLI drivers and experiments live in `dev/`. Nothing in `dev/` is a dependency of anything in `src/`.
|
|
|
|
---
|
|
|
|
## Module Structure
|
|
|
|
Each module has its source under `src/modules/<name>/` and its public header under `include/`:
|
|
|
|
```
|
|
src/modules/<name>/
|
|
<name>.c - implementation
|
|
Makefile - builds a static object
|
|
|
|
include/
|
|
<name>.h - public API; minimal includes, no implementation details
|
|
```
|
|
|
|
The corresponding CLI driver lives at `dev/cli/<name>_cli.c`.
|
|
|
|
---
|
|
|
|
## Build
|
|
|
|
- **GNU make** with tabs for recipe indentation
|
|
- Each module builds to a static object (`.o`)
|
|
- CLI drivers link the module object(s) they need
|
|
- No CDN or vendored sources; dependencies are system libraries (libc, Linux kernel headers)
|