Stow Types

Overview

Each Stow item has a type that determines how its value is stored, validated, and serialized. The Stow supports a handful of primitive data types, but custom struct types can also be defined.

Each item type has constraints defining the possible values. Constraints are defined in the schema.

Within the firmware, data values are accessed via the data_value_t tagged-union.

Data Types

Type

data_value_t field

Constraints

Description

Enumeration

data.int_value

List of possible values and their names

Named integer values

Integer

data.int_value

Minimum & maximum values

32-bit signed integer

Float

data.float_value

Minimum & maximum values

32-bit float

String

data.string_value

Minimum & maximum length

Variable length string (statically allocated)

Byte Array

data.buffer_value

Minimum & maximum length

Variable length byte buffer (statically allocated)

Buffer

data.buffer_value

Minimum & maximum length

Variable length byte buffer (dynamically allocated)

Struct

data.raw_value

A struct type containing fields and constraints

Composite type with named fields. Fields can be any type, including nested structs

Storage Types

Each item has a storage type that controls persistence:

Storage

Behavior

Ephemeral

Resets to default on reboot.

Persistent

Value persists across reboots.

Trust on first use (TOFU)

Can be changed from the default value after which it cannot be changed.

Enumerations

Enumerations are stored as integers. To convert between the integer value and its name, use enum_get_name_from_value() and enum_get_value_from_name().

Byte Buffers

The Byte Array and Buffer types are both variable length lists of bytes. The core difference is that Byte Arrays are statically allocated while Buffers are dynamically allocated. It is recommended to use Byte Arrays for small or fixed size values. If the maximum value is large, consider using the Buffer type.

Strings are also statically allocated so consider using the Buffer type for large text payloads.

Struct Types

The user can defined arbitrary custom Struct types within the schema. Structs are composite types containing fields. Fields can be any datatype, including other structs. Each field has constraints based on its datatype.

Structs are dynamically allocated. Structs are accessed via the raw_value pointer within data_value_t. When getting and item’s value, the caller should cast this pointer to the correct struct based on the item’s struct type. The C struct types are generated by the schema.

Example

Assume a schema contains a custom struct type with an integer and a buffer. The struct type is called KeyedBuffer. If the Stow contains and item of the KeyedBuffer type, it can be accessed like so:

// Get the struct value
data_value_t value = {0};
STOW_GET(STOW_ROLE_INTERNAL, STOW_ID_KEYED_BUFFER_ITEM, &value);

// Cast the raw value to the C struct type
KeyedBuffer_t* struct_value = (KeyedBuffer_t*)value.data.raw_value;
LOG_INF("Key field: %d", struct_value->key_field);
LOG_INF("Buffer field length: %d", struct_value->buffer->len);

// Release the struct value
STOW_RELEASE(STOW_ID_DEVICE_NAME, &value);

Note

Structs may contain nested items that are dynamically allocated. These values are automatically freed alongside the struct.