Generators¶
Every spec file starts with a kind: that selects one of seven generators. All of them are
scaffolded by pinfit create and produced by the same
pinfit generate run, and all of them write their output next to the YAML that describes them.
Choosing one¶
-
A contract several modules can implement: a context plus function-pointer table, with guarded
static inlinedispatch. Header only.Use when callers should not know which driver they are talking to.
-
A concrete unit: private state, variables, standalone functions, and an implementation of any number of interfaces. Header and source.
The workhorse. Most files in a project are modules.
-
States, events, transitions and guards, with entry/exit/tick hooks and a
_tick()for your main loop.engine: statesmithadds hierarchical (composite) states via StateSmith.Use when behaviour depends on what happened before.
-
Fan one call out to every subscriber implementing a
void-returning interface. Fixed capacity, no allocation.Use for event notification with an unknown number of listeners.
-
An opcode dispatcher for UART, CLI or wire protocols, with one handler region per command.
Use when bytes arrive and something has to decide what they mean.
-
A shared status enum plus
SUCCEEDED/FAILED/CHECKmacros. Header only, no source.Use for one error vocabulary across a whole project.
-
Glue between two incompatible interfaces — typically your own contract and a vendor HAL. Matching signatures become direct call-throughs.
Use when you cannot change either side.
At a glance¶
| Kind | create command |
Output | Cross-references | User regions |
|---|---|---|---|---|
interface |
pinfit create interface <name> [dir] |
header | — | 3 |
module |
pinfit create module <name> [dir] --implements <i> |
header + source | interfaces | one per function, plus file-level |
state-machine |
pinfit create state-machine <name> [dir] [--engine statesmith] |
header + source (+ _hooks.h/.c and _sm/ with engine: statesmith) |
— | per state, transition and event |
observer |
pinfit create observer <name> --interface <i> [dir] |
header + source | one interface | none |
command-table |
pinfit create command-table <name> [dir] |
header + source | — | one per command, plus command.unknown |
status-codes |
pinfit create status-codes <name> [dir] |
header | — | none |
adapter |
pinfit create adapter <name> --from <i> --to <i> [dir] |
header + source | two interfaces | one per unmapped function |
Shared conventions¶
These apply to every kind.
Common top-level keys¶
kind: module # selects the generator
name: ra_iic # C identifier prefix for everything generated
description: ... # becomes the file's @brief
header: ra_iic.h # generated header name
source: ra_iic.c # generated source name (kinds that emit one)
includes: ['"vendor_i2c.h"', <stdint.h>]
includes entries are copied verbatim into the generated header. Quote a local include in single
quotes so YAML keeps the double quotes.
Compact "type name" shorthand¶
Struct fields, function and event parameters, and context entries all accept a plain string
instead of a map:
Use the map form when you need a description:
Where files land¶
The spec and its generated files always share a directory. To sort generators into folders, move
the YAML — the output follows it on the next generate.
Naming¶
Generated function names are <name>_<something> by default. The project-wide
format.functionNaming switch renders them in
camelCase instead if you prefer.