Stow Schema

Overview

The Stow schema is defined by a stow.yaml file inside your application’s root directory. The schema includes user-defined enums, structs, item categories, and the Stow items themselves. This stow.yaml can be composed with additional YAML fragments and board-specific overrides, see Fragments & Overrides.

The Stow is automatically generated by the build system based on the stow.yaml. The generated code can be found within the build folder under gantry_generated.

Schema File

The stow.yaml file contains the following sections:

  • enums: Enum types and their possible values

  • structs: Custom struct types and their fields

  • roles: Possible external device roles

  • categories: Categories for organizing items

  • items: The items in the Stow

The description fields do not impact the firmware, they just serve as comments in the schema file and within the generated source code.

Enums

The enums sections lists custom enumerations and their named values. Enum items reference one of these defined enums.

Example:

enums:
   Toggle:
     description: "A toggle to enable or disable"
     values:
       - name: DISABLED
         value: 0
       - name: ENABLED
         value: 1

   SpiChipSelect:
     description: "A SPI chip select index"
     values:
       - name: SPI_CS0
         value: 0
       - name: SPI_CS1
         value: 1

The enum values can be accessed by including generated_stow_enums.h. For example, enum Toggle will have the value Toggle_ENABLED.

Structs

Structs are composite types with named fields. Fields can be any Stow type, including nested structs. The constraints for each field are defined within the struct definition.

Example:

structs:
  - name: SpiBuffer
    description: "A SPI buffer containing a chip select and data"
    fields:
      - name: CS
        type: ENUM
        constraints:
          - enum: SpiChipSelect
      - name: Buffer
        type: BUFFER
        constraints:
          - min_len: 0
          - max_len: 512

The structs can be accessed by including the relevant generated_struct_*.h (e.g. generated_struct_SpiBuffer.h). In this example, the struct is accessible in C code a SpiBuffer_t.

Roles

Items in the Stow have role-based access permissions. The roles section defines possible external client roles. There can be up to 16 roles defined.

Example:

roles:
  - User
  - Clinician
  - Developer

The roles are converted into a bitfield (included via generated_stow_items.h). In this example, an external client may have the roles STOW_ROLE_CLINICIAN | STOW_ROLE_DEVELOPER indicating that the client is both a clinician and a developer.

Categories

Categories are strings used to group related items. Each item may belong to multiple categories. Categories do not serve a functional purpose within the firmware. Instead, external devices reading the Stow will see the categories for each item. This information can be used to organize items (e.g. in a user interface).

categories:
  - System
  - BLE
  - SPI

Items

Items are the individual data entires in the Stow. Each item has:

  • name: The name of the data item.

  • categories: List of categories that the item belongs to.

  • type: The datatype of the item.

  • storage: Storage mode for the item.

  • permissions: read and write access controls. Each is a list of roles able to access the item. The ANY keyword can be used to allow access to all roles. The INTERNAL keyword can be used to restrict access from all roles; only the firmware can access these items.

  • default: The default value of the item.

  • constraints: The item’s value constraints.

  • custom_validate (optional): Name of a C function providing additional validation beyond type-level constraints.

  • custom_get (optional): Name of a C function to override the default get behavior.

  • custom_set (optional): Name of a C function to override the default set behavior.

After generation, items are accessed via the STOW_ID_<NAME> enum (e.g. STOW_ID_DEVICE_NAME). All IDs are defined in generated_stow_items.h.

Built-in Items

The first two items in the Stow built-in and included by default, they are not defined in the stow.yaml. The first is the StowHash, a SHA256 hash string of the current Stow description. The Stow hash allows clients cache the Stow description. The second is the FirmwareVersion, a string derived from the Zephyr VERSION file.

Custom Interface

The custom_get, custom_set, and custom_validate fields each accept a C identifier naming a function that the application provides. For when and how these functions are called, see the API docs.

Each name must be a valid C identifier. Any field that is omitted defaults to the standard interface behavior.

- name: SensorReading
  description: "Live sensor reading (computed on demand)"
  categories: [Sensor]
  type: INT
  storage: EPHEMERAL
  permissions:
    - read: ANY
    - write: INTERNAL
  default: 0
  constraints:
    - min: -1000
    - max: 1000
  custom_get: sensor_reading_get

- name: TargetTemperature
  description: "Target temperature with application-specific validation"
  categories: [System]
  type: FLOAT
  storage: PERSISTENT
  permissions:
    - read: ANY
    - write: [User]
  default: 20.0
  constraints:
    - min: 10.0
    - max: 40.0
  custom_validate: target_temp_validate
  custom_set: target_temp_set

Constraints by Type

Integer / Float

Integer and float constraints define a range of valid values.

constraints:
  - min: -100
  - max: 100

String / Byte Array / Buffer

String, Byte Array, and Buffer constraints define the minimum and maximum lengths for the buffer.

constraints:
  - min_len: 0
  - max_len: 64

Enum

Enum constraints reference one of the defined enums. The referenced enum definition contains a list of possible values.

constraints:
  - enum: MyEnumName

Struct

Struct constraints reference one of the defined structs. The referenced struct contains the constraints for each field in its definition.

constraints:
  - struct: MyStructName

Example:

items:
  - name: DeviceName
    description: "The name of the device"
    categories: [System]
    type: STRING
    storage: PERSISTENT
    permissions:
      - read: ANY
      - write: [User]
    default: "Gantry"
    constraints:
      - min_len: 3
      - max_len: 25

  - name: SerialNumber
    description: "The device serial number"
    categories: [System]
    type: STRING
    storage: TOFU
    permissions:
      - read: ANY
      - write: [Developer]
    default: "0000000000000000"
    constraints:
      - min_len: 16
      - max_len: 16

  - name: BleConnectionState
    description: "The current BLE connection state"
    categories: [System, BLE]
    type: ENUM
    storage: EPHEMERAL
    permissions:
      - read: ANY
      - write: INTERNAL
    default: DISCONNECTED
    constraints:
      - enum: BleConnectionState

  - name: TestInt
    description: "Test int value"
    categories: [System, Test]
    type: INT
    storage: EPHEMERAL
    permissions:
      - read: [User, Clinician]
      - write: [Clinician]
    default: 0
    constraints:
      - min: -100
      - max: 100
    custom_validate: test_custom_validator

  - name: TestFloat
    description: "Test float value"
    categories: [System, Test]
    type: FLOAT
    storage: EPHEMERAL
    permissions:
      - read: ANY
      - write: ANY
    default: 21.5
    constraints:
      - min: 15.0
      - max: 30.0

  - name: TestBytes
    description: "Test bytes"
    categories: [Test]
    type: BYTE_ARRAY
    storage: EPHEMERAL
    permissions:
      - read: ANY
      - write: ANY
    default:
      [0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]
    constraints:
      - min_len: 12
      - max_len: 12

  - name: TestBuffer
    description: "Test buffer"
    categories: [Test]
    type: BUFFER
    storage: EPHEMERAL
    permissions:
      - read: ANY
      - write: ANY
    default: []
    constraints:
      - min_len: 0
      - max_len: 20

  - name: SpiTxBuffer
    description: "SPI TX buffer"
    categories: [SPI]
    type: STRUCT
    storage: EPHEMERAL
    permissions:
      - read: ANY
      - write: ANY
    default:
      - field: CS
        value: SPI_CS0
      - field: Buffer
        value: []
    constraints:
      - struct: SpiBuffer

Fragments & Overrides

A Stow definition can be assembled from multiple YAML fragments instead of a single stow.yaml. This allows a module’s items live in their own file, be reused across apps, and be overridden per app or per board.

By convention, fragment files are named *.stow.yaml. The fully composed definition is written to merged.stow.yaml.

Note

CONFIG_GANTRY_STOW requires CMake >= 3.29 to defer fragment composition such that an app (or other modules) can define additional stow fragments.

Registering a fragment

Call gantry_stow_add_fragment(<path>) from your app’s CMakeLists.txt:

gantry_stow_add_fragment(${CMAKE_CURRENT_SOURCE_DIR}/ble.stow.yaml)

A fragment has the same shape as stow.yaml (enums, structs, roles, categories, items), but need not be complete.

Merge order

Fragments are composed lowest to highest precedence:

  1. Fragments registered via gantry_stow_add_fragment(), in registration order.

  2. The app’s own stow.yaml content. This is applied on top of all registered fragments, so it’s the natural place to override values for a specific app.

  3. An auto-discovered board fragment, boards/<BOARD>.stow.yaml. Always highest precedence, if present.

Overrides

Enums, structs, and items are matched by name across fragments:

  • Duplicate definitions are merged.

  • If a later fragment redefines something differently, only the fields it specifies are patched onto the earlier definition and unspecified fields are inherited.

This means a fragment can define an item in full, and a later layer can override just what it needs to change:

# ble.stow.yaml
items:
  - name: DeviceName
    description: "The name of the device"
    categories: [General]
    type: STRING
    storage: PERSISTENT
    permissions:
      - read: ANY
      - write: [Session]
    default: "BleDevice"
    constraints:
      - min_len: 3
      - max_len: 25
# stow.yaml
items:
  - name: DeviceName
    default: "Gantry"

roles and categories are merged as an ordered union of unique strings.