BLOB Transfer Model
The Binary Large OBject (BLOB) transfer model implements the Bluetooth Mesh Binary Large Object Transfer Model specification version 1.0, providing the capability to send large binary objects from a single source to multiple destination nodes over a Bluetooth Mesh network. It serves as the underlying transfer method for Device Firmware Updates (DFU) but can also be utilized for other object transfer purposes. This implementation is considered experimental.
The BLOB transfer model supports the transmission of continuous binary objects up to 4 GB (2^32 bytes) in size. The BLOB transfer protocol includes a built-in packet loss recovery process and checkpoints to ensure all destinations receive all data before proceeding. The order of data transmission is not guaranteed.
BLOB transfers are constrained by the transmission speed and reliability of the underlying Mesh network. Under ideal conditions, BLOBs can be transferred at rates up to 1 kbps, allowing for the transfer of a 100 kB BLOB within 10-15 minutes. However, network conditions, transmission capabilities, and other limiting factors can easily reduce the data rate by several orders of magnitude. Adjusting the transmission parameters according to the application and network configuration, and scheduling them during periods of low network traffic, can significantly improve the speed and reliability of the protocol. Nevertheless, achieving transfer rates close to the ideal in real-world deployments is impractical.
There are two BLOB Transfer models:
The BLOB Transfer Client is instantiated on the sender node, and the BLOB Transfer Server is instantiated on the receiver nodes.
Concepts
The BLOB transfer protocol introduces several new concepts to implement the BLOB transfer.
BLOBs
A BLOB is a binary object up to 4 GB in size, which can contain any data that an application wishes to transmit over the Mesh network. A BLOB is a continuous data object divided into blocks and segments for reliable and manageable transmission. There are no restrictions on the content or structure of a BLOB, and applications are free to define any encoding or compression they desire for the data itself.
The BLOB transfer protocol does not provide any built-in integrity checks, encryption or authentication of the BLOB data. However, the underlying encryption of the Bluetooth Mesh protocol provides data integrity checks and protects the contents of the BLOB from third parties using network and application-level encryption.
Segmentation
Binary objects are divided into blocks, typically ranging in size from a few hundred to a few thousand bytes.
Each block is transmitted separately, and the BLOB Transfer Client ensures that all BLOB Transfer Servers have received a complete block before moving to the next one.
The block size is determined by the transmitted block_size_log
parameter and is the same for all blocks in a transfer, except for the last block, which may be smaller.
For BLOBs stored in flash memory, the block size is usually a multiple of the target device’s flash page size.
Block Structure
Each block is divided into segments. A segment is the smallest unit of data in BLOB transfer and must fit within a single Bluetooth Mesh Access Message (excluding opcodes) (379 bytes or less). The mechanism for transmitting segments depends on the transfer mode.
When operating in Push BLOB transfer mode, segments are sent as unacknowledged packets from the BLOB Transfer Client to all target BLOB Transfer Servers. Once all segments in a block have been sent, the BLOB Transfer Client queries each BLOB Transfer Server for any missing segments and resends them. This process repeats until all BLOB Transfer Servers have received all segments, or the BLOB Transfer Client abandons the transfer.
When operating in Pull BLOB transfer mode, the BLOB Transfer Server requests a small number of segments from the BLOB Transfer Client at a time and waits for the BLOB Transfer Client to send them before requesting more segments. This process repeats until all segments have been transferred or the BLOB Transfer Server abandons the transfer.
Read more about the transfer modes in Transfer Modes section.
BLOB Streams
In the API of the BLOB transfer model, BLOB data processing is separated from high-level transfer handling. This separation allows for the reuse of different BLOB storage and transfer strategies for different applications. While high-level transfers are directly controlled by the application, BLOB data itself is accessed through a BLOB stream.
The BLOB stream is comparable to a standard library file stream. Through opening, closing, reading and writing, the BLOB Transfer model gets full access to the BLOB data, whether it’s kept in flash, RAM, or on a peripheral. The BLOB stream is opened with an access mode (read or write) before it’s used, and the BLOB Transfer models will move around inside the BLOB’s data in blocks and chunks, using the BLOB stream as an interface.
Interactions
Before reading or writing a BLOB, the stream is opened by calling its
open
callback. When used with a BLOB Transfer Server, the BLOB
stream is always opened in write mode, and when used with a BLOB Transfer Client, it’s always opened
in read mode.
For each block in the BLOB, the BLOB Transfer model starts by calling
block_start
. Then, depending on the access mode, the BLOB
stream’s wr
or rd
callback is
called repeatedly to move data to or from the BLOB. When the model is done processing the block, it
calls block_end
. When the transfer is complete, the BLOB
stream is closed by calling close
.
Starting Position
Applications can implement their own BLOB streams or use implementations provided by the WM IoT SDK:
Transfer Capabilities
Each BLOB Transfer Server may have different transfer capabilities. The transmission capabilities of each device are controlled through the following configuration options:
CONFIG_BT_MESH_BLOB_SIZE_MAX
CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MIN
CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MAX
CONFIG_BT_MESH_BLOB_CHUNK_COUNT_MAX
The CONFIG_BT_MESH_BLOB_CHUNK_COUNT_MAX
option is also used by the BLOB Transfer
Client and affects memory consumption by the BLOB Transfer Client model structure.
To ensure that the transfer can be received by as many servers as possible, the BLOB Transfer Client can retrieve the capabilities of each BLOB Transfer Server before starting the transfer. The client will transfer the BLOB with the highest possible block and segment size.
Transfer Modes
BLOBs can be transferred using two transfer modes: Push BLOB Transfer Mode and Pull BLOB Transfer Mode. In most cases, the transfer should be conducted in Push BLOB Transfer Mode.
In Push BLOB Transfer Mode, the sending rate is controlled by the BLOB Transfer Client, which will push all the chunks of each block without any high level flow control. Push BLOB Transfer Mode supports any number of Target nodes, and should be the default transfer mode.
In Pull BLOB Transfer Mode, the BLOB Transfer Server will “pull” the chunks from the BLOB Transfer Client at its own rate. Pull BLOB Transfer Mode can be conducted with multiple Target nodes, and is intended for transferring BLOBs to Target nodes acting as Low-Power Node. When operating in Pull BLOB Transfer Mode, the BLOB Transfer Server will request chunks from the BLOB Transfer Client in small batches, and wait for them all to arrive before requesting more chunks. This process is repeated until the BLOB Transfer Server has received all chunks in a block. Then, the BLOB Transfer Client starts the next block, and the BLOB Transfer Server requests all chunks of that block.
Transfer Timeout
The timeout of the BLOB transfer is based on a Timeout Base value. Both client and server use the same Timeout Base value, but they calculate timeout differently.
The BLOB Transfer Server uses the following formula to calculate the BLOB transfer timeout:
10 * (Timeout Base + 1) seconds
For the BLOB Transfer Client, the following formula is used:
(10000 * (Timeout Base + 2)) + (100 * TTL) milliseconds
where TTL is time to live value set in the transfer.
API Reference
This section contains types and defines common to the BLOB Transfer models.
- group bt_mesh_blob
Defines
-
CONFIG_BT_MESH_BLOB_CHUNK_COUNT_MAX
Enums
-
enum bt_mesh_blob_xfer_mode
BLOB transfer mode.
Values:
-
enumerator BT_MESH_BLOB_XFER_MODE_NONE
No valid transfer mode.
-
enumerator BT_MESH_BLOB_XFER_MODE_PUSH
Push mode (Push BLOB Transfer Mode).
-
enumerator BT_MESH_BLOB_XFER_MODE_PULL
Pull mode (Pull BLOB Transfer Mode).
-
enumerator BT_MESH_BLOB_XFER_MODE_ALL
Both modes are valid.
-
enumerator BT_MESH_BLOB_XFER_MODE_NONE
-
enum bt_mesh_blob_xfer_phase
Transfer phase.
Values:
-
enumerator BT_MESH_BLOB_XFER_PHASE_INACTIVE
The BLOB Transfer Server is awaiting configuration.
-
enumerator BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START
The BLOB Transfer Server is ready to receive a BLOB transfer.
-
enumerator BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK
The BLOB Transfer Server is waiting for the next block of data.
-
enumerator BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK
The BLOB Transfer Server is waiting for the next chunk of data.
-
enumerator BT_MESH_BLOB_XFER_PHASE_COMPLETE
The BLOB was transferred successfully.
-
enumerator BT_MESH_BLOB_XFER_PHASE_SUSPENDED
The BLOB transfer is paused.
-
enumerator BT_MESH_BLOB_XFER_PHASE_INACTIVE
-
enum bt_mesh_blob_status
BLOB model status codes.
Values:
-
enumerator BT_MESH_BLOB_SUCCESS
The message was processed successfully.
-
enumerator BT_MESH_BLOB_ERR_INVALID_BLOCK_NUM
The Block Number field value is not within the range of blocks being transferred.
-
enumerator BT_MESH_BLOB_ERR_INVALID_BLOCK_SIZE
The block size is smaller than the size indicated by the Min Block Size Log state or is larger than the size indicated by the Max Block Size Log state.
-
enumerator BT_MESH_BLOB_ERR_INVALID_CHUNK_SIZE
The chunk size exceeds the size indicated by the Max Chunk Size state, or the number of chunks exceeds the number specified by the Max Total Chunks state.
-
enumerator BT_MESH_BLOB_ERR_WRONG_PHASE
The operation cannot be performed while the server is in the current phase.
-
enumerator BT_MESH_BLOB_ERR_INVALID_PARAM
A parameter value in the message cannot be accepted.
-
enumerator BT_MESH_BLOB_ERR_WRONG_BLOB_ID
The message contains a BLOB ID value that is not expected.
-
enumerator BT_MESH_BLOB_ERR_BLOB_TOO_LARGE
There is not enough space available in memory to receive the BLOB.
-
enumerator BT_MESH_BLOB_ERR_UNSUPPORTED_MODE
The transfer mode is not supported by the BLOB Transfer Server model.
-
enumerator BT_MESH_BLOB_ERR_INTERNAL
An internal error occurred on the node.
-
enumerator BT_MESH_BLOB_ERR_INFO_UNAVAILABLE
The requested information cannot be provided while the server is in the current phase.
-
enumerator BT_MESH_BLOB_SUCCESS
-
struct bt_mesh_blob_block
BLOB transfer data block.
-
struct bt_mesh_blob_chunk
BLOB data chunk.
-
struct bt_mesh_blob_xfer
BLOB transfer.
Public Members
-
uint64_t id
BLOB ID.
-
size_t size
Total BLOB size in bytes.
-
enum bt_mesh_blob_xfer_mode mode
BLOB transfer mode.
-
uint16_t chunk_size
Base chunk size. May be smaller for the last chunk.
-
uint64_t id
-
struct bt_mesh_blob_io
BLOB stream.
Public Members
-
int (*open)(const struct bt_mesh_blob_io *io, const struct bt_mesh_blob_xfer *xfer, enum bt_mesh_blob_io_mode mode)
Open callback.
Called when the reader is opened for reading.
- Param io:
BLOB stream.
- Param xfer:
BLOB transfer.
- Param mode:
Direction of the stream (read/write).
- Return:
0 on success, or (negative) error code otherwise.
-
void (*close)(const struct bt_mesh_blob_io *io, const struct bt_mesh_blob_xfer *xfer)
Close callback.
Called when the reader is closed.
- Param io:
BLOB stream.
- Param xfer:
BLOB transfer.
-
int (*block_start)(const struct bt_mesh_blob_io *io, const struct bt_mesh_blob_xfer *xfer, const struct bt_mesh_blob_block *block)
Block start callback.
Called when a new block is opened for sending. Each block is only sent once, and are always sent in increasing order. The data chunks inside a single block may be requested out of order and multiple times.
- Param io:
BLOB stream.
- Param xfer:
BLOB transfer.
- Param block:
Block that was started.
-
void (*block_end)(const struct bt_mesh_blob_io *io, const struct bt_mesh_blob_xfer *xfer, const struct bt_mesh_blob_block *block)
Block end callback.
Called when the current block has been transmitted in full. No data from this block will be requested again, and the application data associated with this block may be discarded.
- Param io:
BLOB stream.
- Param xfer:
BLOB transfer.
- Param block:
Block that finished sending.
-
int (*wr)(const struct bt_mesh_blob_io *io, const struct bt_mesh_blob_xfer *xfer, const struct bt_mesh_blob_block *block, const struct bt_mesh_blob_chunk *chunk)
Chunk data write callback.
Used by the BLOB Transfer Server on incoming data.
Each block is divided into chunks of data. This callback is called when a new chunk of data is received. Chunks may be received in any order within their block.
If the callback returns successfully, this chunk will be marked as received, and will not be received again unless the block is restarted due to a transfer suspension. If the callback returns a non-zero value, the chunk remains unreceived, and the BLOB Transfer Client will attempt to resend it later.
Note that the Client will only perform a limited number of attempts at delivering a chunk before dropping a Target node from the transfer. The number of retries performed by the Client is implementation specific.
- Param io:
BLOB stream.
- Param xfer:
BLOB transfer.
- Param block:
Block the chunk is part of.
- Param chunk:
Received chunk.
- Return:
0 on success, or (negative) error code otherwise.
-
int (*rd)(const struct bt_mesh_blob_io *io, const struct bt_mesh_blob_xfer *xfer, const struct bt_mesh_blob_block *block, const struct bt_mesh_blob_chunk *chunk)
Chunk data read callback.
Used by the BLOB Transfer Client to fetch outgoing data.
The Client calls the chunk data request callback to populate a chunk message going out to the Target nodes. The data request callback may be called out of order and multiple times for each offset, and cannot be used as an indication of progress.
Returning a non-zero status code on the chunk data request callback results in termination of the transfer.
- Param io:
BLOB stream.
- Param xfer:
BLOB transfer.
- Param block:
Block the chunk is part of.
- Param chunk:
Chunk to get the data of. The buffer pointer to by the
data
member should be filled by the callback.- Return:
0 on success, or (negative) error code otherwise.
-
int (*open)(const struct bt_mesh_blob_io *io, const struct bt_mesh_blob_xfer *xfer, enum bt_mesh_blob_io_mode mode)
-
CONFIG_BT_MESH_BLOB_CHUNK_COUNT_MAX