========== 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 :doc:`schema `. Within the firmware, data values are accessed via the :any:`data_value_t` tagged-union. Data Types ========== .. list-table:: :header-rows: 1 :widths: 20 20 30 60 * - 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: .. list-table:: :header-rows: 1 :widths: 25 75 * - 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 :any:`enum_get_name_from_value` and :any:`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 :doc:`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 :any:`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: .. code-block:: c // 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.