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 |
|
Constraints |
Description |
|---|---|---|---|
Enumeration |
|
List of possible values and their names |
Named integer values |
Integer |
|
Minimum & maximum values |
32-bit signed integer |
Float |
|
Minimum & maximum values |
32-bit float |
String |
|
Minimum & maximum length |
Variable length string (statically allocated) |
Byte Array |
|
Minimum & maximum length |
Variable length byte buffer (statically allocated) |
Buffer |
|
Minimum & maximum length |
Variable length byte buffer (dynamically allocated) |
Struct |
|
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.