BERGSONNE

@studio annotations

A small set of @studio directives inside a header’s Doxygen comments turns an SDK module or a tile driver into Studio palette blocks, DSL imports, reference pages, and coverage tables. You write the header; the generators derive everything else — nobody hand-edits palette JSON or coverage tables.

Overview

Studio and these docs are built from the C headers in the SDK. The bridge is a handful of @studio tags placed inside /** … */ blocks. Two discovery rules govern everything:

  • A file opts in with a file-level tag — @studio category (SDK modules) or @studio tile (tile drivers). Without it, the file is skipped.
  • A function becomes a palette block / DSL call only if its Doxygen block carries @studio expose. Functions without it still appear on the SDK reference page (so init/lifecycle helpers are documented) — they just aren’t palette blocks.

Standard Doxygen feeds the same output: @brief becomes the summary + palette tooltip, and @param names are the DSL parameter names (there’s no rename — pick C names that read well).

Two pipelines

The directive set is split across two independent generators. A tag parsed by one is ignored by the other, so it helps to know which drives what:

  • Palette / DSL / manifests gen_studio_manifest.py parses category, tile, expose, event, param, and the buffer tags into manifests/*.json.
  • Docs / coverage tables — the driver-docs parser reads expose section= and unsupported into the per-driver JSON that powers Tile Drivers.
  • Simulator / SDK coveragetwin and the coverage block feed the SDK’s coverage + simulator-status views.

File-level directives

@studio category <name> [label=] [icon=]

Required on every SDK core_*.h that exposes anything. The name becomes the category id (and the manifests/sdk-docs/<name>.json filename); label/icon are display.

/**
 * core_pwm.h — PWM output and periodic timers
 * @studio category pwm label=Core.PWM icon=◲
 */

@studio tile [label=] [icon=]

The tile-driver equivalent — exactly one per tile_*.h. Opts the driver into the palette and flips its Studio-ready state.

/**
 * @studio tile label=Sense.BP icon=◇
 */

@studio event name=<id> [payload=] [mask= read= read_type=]

Declares an event the module/tile can raise (becomes on Core.Pad.rising(pad: int) { … } in the DSL). payload is comma-separated name:type pairs. Tile events add mask (a bit in the tile’s interrupt status), read (a fn that fills the payload), and read_type (its struct):

/**
 * @studio tile label=Sense.I.6P6 icon=▦
 * @studio event name=tap mask=ICM42686P_INT_STATUS3_TAP_DET \
 *   payload=count:int,axis:int,direction:int \
 *   read=tile_sense_i_6p6_get_tap_result read_type=sense_i_6p6_tap_result_t
 */

Function-level directives

@studio expose category=<name> name=<dsl_name> [section=] [returns=] [availability=]

The core directive — marks a function palette-exposed and DSL-callable. category must match the file’s category/tile; name is the DSL-facing name. returns gives the DSL return type (int, bool, float, string, or a fixed array like int[3]); availability limits it to certain Cores.

/**
 * Set PWM duty cycle on a pad.
 *
 * @studio expose category=pwm name=duty
 * @param pad        [1..64] Pad configured as TIMx.<ch> in config.json.
 * @param duty_permil [0..1000] 0 = off, 500 = 50%, 1000 = full.
 */
static inline void core_pwm_duty(uint8_t pad, uint16_t duty_permil);

section=<bucket> (read by the docs parser) groups the function into a named row group on the driver page — e.g. @studio expose section=fifo.

Shaping parameters & outputs

  • @studio param <c> enum {KEY=label, …} — friendly labels for an int-valued parameter (codegen still emits the C identifier).
  • @studio param <c> type=int[16] — override a pointer parameter’s DSL type (fixed-length array input).
  • @studio out_buffer <c> type=<ctype> (length=N | cap_param=<c>) — promote a pointer-out to a typed array: fixed-length collapses into the return value; cap_param mode surfaces a writable array with a separate count.
  • @studio out_scalar <c> type=<ctype> — a scalar pointer the function writes into; the DSL caller passes an lvalue, back-filled on return. Multiple are allowed (multi-out functions).
  • @studio in_buffer <c> type=<elem> (length=N | length_param=<c>) — a caller-passed array (and its length param), collapsed to one DSL array argument.
  • @studio twin <full|regs|noop> — the simulator-twin fidelity for this function, feeding the SDK coverage view.
/**
 * Read raw accelerometer [X, Y, Z].
 *
 * @studio expose category=tile name=get_raw_accels returns=int[3]
 * @studio out_buffer buffer type=int16_t length=3
 */
void tile_sense_i_6p6_get_raw_accels(tile_t *tile, int16_t *buffer);

Coverage & gaps

@studio unsupported severity=<common|advanced|niche> category="…"

Declares a chip capability the driver doesn’t cover, with the rationale on the following lines. These become the driver page’s coverage-gap rows — the canonical, derived way to record a gap. An optional section= groups it.

/**
 * @studio unsupported severity=advanced category="Alternate bus modes (SPI / I3C)"
 *   I²C-only today. The ILPS22QS supports 3/4-wire SPI and I3C SDR; adding
 *   them needs the driver framework to plumb a second bus abstraction.
 */
Declare gaps in the header, never in the UI
The Coverage Table is a derived view. Walk the datasheet’s capability list and annotate every feature you defer — honest, generated coverage beats a hand-curated table that drifts.

@studio coverage

A file-level block on SDK modules (id, name, page, blurb) describing the module for the SDK coverage table.

How the docs & palette derive

The manifest generator runs from the SDK and writes the checked-in manifests; a --check mode in CI fails the build if a header changes without its manifest being regenerated, so the palette and docs can never silently fall behind the code:

tools/gen_studio_manifest.py          # write manifests
tools/gen_studio_manifest.py --check  # CI: verify manifests match headers

Tile-driver pages flow through the driver-docs parser into the per-tile JSON the site renders. To see the annotations in the context of writing a driver, see Writing a tile driver.