🢀 Back to programming guide
Memory objects are binary blobs that AVB devices expose to the network through the AVB ATDECC protocol. They can have many purposes, but commonly the two main uses of them are:
Hive Controller showing an AVB entity with its logo, supplied via memory object
To add a memory object to an AVB device you include a <memory_object>
section in the entity config xml file. Each <memory_object>
must sit within a <memory_objects>
node within a <configuration>
node of the XML. Here is an example of a memory object description:
<memory_object>
<object_name>Entity PNG</object_name>
<memory_object_type>0xA</memory_object_type> <!-- 0xA is PNG_ENTITY -->
<target_descriptor_type>0</target_descriptor_type> <!-- 0 is AEM_DT_ENTITY -->
<target_descriptor_index>0</target_descriptor_index>
<start_address>0x100000</start_address>
<maximum_length>0x100000</maximum_length>
<length>0</length>
<permissions>1</permissions>
</memory_object>
The <memory_object_type>
describes the type of the memory object. Values are from Table 7.19 of 1722.1-2013, and can also be found in stackTypes.h
. They are summarised here:
value | type |
---|---|
0x0000 | AVDECC Entity specific firmware image. |
0x0001 | Vendor specific object. |
0x0002 | AVDECC Entity specific crash information |
0x0003 | AVDECC Entity specific UTF-8 encoded logging information. |
0x0004 | AVDECC Entity specific settings storage used at system startup. |
0x0005 | AVDECC Entity specific settings storage. See 7.2.10.3. |
0x0006 | An image of the manufacturer’s logo in the Scalable Vector Graphic (SVG) format. |
0x0007 | An image representation of the entity in Scalable Vector Graphic (SVG) format. |
0x0008 | A generic image in Scalable Vector Graphic (SVG) format. |
0x0009 | An image of the manufacturer’s logo in the Portable Network Graphic (PNG) format. |
0x000a | An image of the entity in the Portable Network Graphic (PNG) format. |
0x000b | A generic image in the Portable Network Graphic (PNG) format. |
0x000c | COLLADA DAE 3D model of the manufacturer’s logo using the COLLADA Digital Asset |
0x000d | COLLADA DAE 3D model of the entity using the COLLADA Digital Asset Schema. |
0x000e | Generic COLLADA DAE 3D model using the COLLADA Digital Asset Schema. |
0x000f to ffff16 | Reserved for future use. |
<target_descriptor_type>
is usually set to 0
(ENTITY descriptor type) and <target_descriptor_index>
is usually set to 0
as the target of the memory object is usually the entity itself.
Each memory object maps into a global address space, a strange design choice in our opinion, but one we must adhere to. Therefore each memory object requires <start_address>
, <length>
and <maximum_length>
tags. As memory objects can be written as well as read, they require both a <length>
tag (current length) and a <maximum_length>
tag (the maximum size the memory object can ever be). The <length>
tag can be set to zero or omitted if the application returns this at runtime via the callback function appGetMemoryObjectSize()
.
As memory objects can be read, written and even executed, the <permissions>
tag specifies which operations are permitted on the memory object. The value is a bit field taken from the following bit values:
value | permission |
---|---|
0 | NONE (default) |
1 | READ |
2 | WRITE |
4 | EXECUTE |
Typically, vendor and device PNGs would only have the READ permission bit set.
The Sienda Stack requests the actual data contained in a memory object from the application using the following stack callbacks:
bool appGetMemoryObjectSize(uint32_t memoryObjectIndex, uint64_t &size, void *pContext);
bool appReadMemoryObject(uint32_t memoryObjectIndex, uint64_t offset, uint64_t size, uint8_t *pData, void *pContext);
appGetMemoryObjectSize()
is used to retrieve the current size of the memory object at runtime. This way, things such as PNG files can be loaded at runtime and the size is not required to be known when the XML configuration file is created. If the sizes of the memory objects are specified in the configuration XML then the function can be left unimplemented (or return false for a particular memory object index).
appReadMemoryObject()
requests a block of data from the specified memory object memoryObjectIndex
, to be copied into pData
from offset offset
with size size
. Return true if the data was successfully copied, or false otherwise.
!!! info
Although the memory object descriptors require a <start_address>
in the global address space, these global addresses are abstracted by the stack and so the callback function appReadMemoryObject()
requests data at offset offset
from the start of that specific memory object. There is no need for the application to be aware of, or compensate for, the <start_address>
specified in the entity model XML. offset
0
is the first byte of the specified memory object data.
AVB device firmware updates can be performed over the network via an AVB controller. The firmware image is represented as a memory object of type FIRMWARE_IMAGE (value 0x0, 1722.1-2013 Table 7.19). Firmware memory objects must have the <permissions>
tag set to WRITE to allow the memory object to be written. Note that the READ|WRITE permissions are not advertised to the controller but are used internally by the Sienda Stack to ensure that only memory objects with WRITE permission can be written.
A device containing a memory object for firmware updates would have a <memory_object>
section such as this in the configuration XML:
<memory_object>
<object_name>Firmware Update</object_name>
<memory_object_type>0</memory_object_type> <!-- 0 is FIRMWARE_IMAGE -->
<target_descriptor_type>0</target_descriptor_type> <!-- 0 is AEM_DT_ENTITY -->
<target_descriptor_index>0</target_descriptor_index>
<start_address>0x200000</start_address>
<maximum_length>10485760</maximum_length>
<length>0</length>
<maximum_segment_length>10485760</maximum_segment_length>
<permissions>2</permissions>
</memory_object>
Note that there is an extra field <maximum_segment_length>
here (compared to read-only memory objects). The <maximum_segment_length>
tag specifies the maximum amount of data that the device can receive in a single chunk before committing the data to persistent storage. For devices with plenty of RAM, this can be set to the same value as <length>
or <maximum_length>
, and the whole firmware image will be transferred to the device (and stored in RAM) before a command is sent to write the image to persistent storage. Devices with very little available RAM can set this to a sensible buffer size, and the controller should honour this value and only send <maximum_segment_length>
bytes of data before committing the data to persistent storage. The controller will repeat this upload->write cycle several/many times until the whole firmware image is uploaded and written to persistent storage.
!!! info
The Hive AVB Controller, as of September 2022, does NOT honour the <maximum_segment_length>
field and so cannot be used to update the firmware in small memory constrained AVB devices. If you require a controller that can perform such firmware updates, please contact Sienda.
Devices supporting ATDECC firmware updates should also advertise the capability in the <entity_capabilities>
field of the <entity>
descriptor in the configuration XML. The bit field value 0x1 (EFU_MODE) should be present to indicate support of firmware updates.
Firmware update requests are communicated to the application through the following stack callback functions:
bool appStartFirmwareUpload(uint32_t memoryObjectIndex, uint64_t totalSize, void *pContext);
bool appFirmwareUpload(uint32_t memoryObjectIndex, uint64_t offset, uint64_t size, uint8_t *pData, void *pContext);
bool appStartFirmwareWrite(uint32_t memoryObjectIndex, uint64_t offset, uint64_t size, void *pContext);
bool appReboot(void *pContext);
During a firmware update procedure (orchestrated via an AVB controller), the application should expect to receive callbacks in the following order:
appStartFirmwareUpload()
will be called to inform the application that a firmware update process is being started. The parameter totalSize
indicates the total size of the firmware to be delivered. The application may use this function call to do things such as:
totalSize
bytes of RAM in preparation to receive the firmware imageappStartFirmwareUpload
MUST return within 240ms so waiting for FLASH erase completion is not recommended here.)
If the device is not able to prepare for a firmware update at this time, then it may return false which will abort the firmware update and notify the controller of such failure.appFirmwareUpload()
will be called repeatedly to deliver (usually consecutive) parts of the firmware image to the application. The application should store the data provided in pData
(of size size
) into memory object offset offset
, and return true. If the application is unable to complete the request it should return false which will abort the firmware update process and notify the controller.appStartFirmwareWrite()
will be called. The application should instigate a write of the data to persistent storage and return immediately (true on success, false on failure). The write to persistent storage should continue in the background and the application should report progress of the write operation via calls to the stack function firmwareWriteProgress()
. firmwareWriteProgress()
takes a single parameter perMillComplete
to indicate the write progress in ‘mills’, where 1% = 10mills. Thus progress is reported as a value between 0 and 1000. Value 1000 indicates completion of the operation and should only be passed when all data has been successfully written to persistent storage and validated. In case of write error a value between 0xFF00 and 0xFFFE should be sent to notify the stack (and the controller) that an error has occurred and that the firmware update is aborted.!!! info
for IEEE standards eagles: the perMill values and their interpretations are from 1722.1-2021. 1722.1-2013 defines the values to be returned in case of error differently. The stack expects the 1722.1-2021 values, but will attempt to appease 1722.1-2013 controllers by also sending value 0
in case of error, and by rounding value 0
(indicating 0% in 1722.1-2021 but ‘incomplete and stopped’ in 1722.1-2013 to 1
(0.01%))
appReboot()
will be called if the AVB controller requested the device to reboot after a successful firmware update.