zephyr/subsys/bluetooth/mesh/blob_io_flash.c
Kyra Lengfeld 0a7908588c Bluetooth: Mesh: add Kconfig options for BLOB chunk size
The MBT server, as the MBT client currently sets the maximum chunk size
according to maximum supported segments in the accesss layer. This might
be suboptimal for some use cases.
The added Kconfig options give customers the option to fine tune it
themselves.

Future work will include addition of an API for the customer to modify
it also during runtime.

Signed-off-by: Kyra Lengfeld <kyra.lengfeld@nordicsemi.no>
2024-08-20 14:45:57 +02:00

160 lines
3.7 KiB
C

/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/bluetooth/mesh.h>
#include <zephyr/storage/flash_map.h>
#include <zephyr/drivers/flash.h>
#include <assert.h>
#include "blob.h"
#include "net.h"
#include "transport.h"
#define WRITE_BLOCK_SIZE DT_PROP(DT_INST(0, soc_nv_flash), write_block_size)
#define FLASH_IO(_io) CONTAINER_OF(_io, struct bt_mesh_blob_io_flash, io)
static int test_flash_area(uint8_t area_id)
{
const struct flash_area *area;
uint8_t align;
int err;
err = flash_area_open(area_id, &area);
if (err) {
return err;
}
align = flash_area_align(area);
flash_area_close(area);
if (align > WRITE_BLOCK_SIZE) {
return -EINVAL;
}
return 0;
}
static int io_open(const struct bt_mesh_blob_io *io,
const struct bt_mesh_blob_xfer *xfer,
enum bt_mesh_blob_io_mode mode)
{
struct bt_mesh_blob_io_flash *flash = FLASH_IO(io);
flash->mode = mode;
return flash_area_open(flash->area_id, &flash->area);
}
static void io_close(const struct bt_mesh_blob_io *io,
const struct bt_mesh_blob_xfer *xfer)
{
struct bt_mesh_blob_io_flash *flash = FLASH_IO(io);
flash_area_close(flash->area);
}
static int block_start(const struct bt_mesh_blob_io *io,
const struct bt_mesh_blob_xfer *xfer,
const struct bt_mesh_blob_block *block)
{
struct bt_mesh_blob_io_flash *flash = FLASH_IO(io);
size_t erase_size;
if (flash->mode == BT_MESH_BLOB_READ) {
return 0;
}
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
struct flash_pages_info page;
const struct device *flash_dev;
int err;
flash_dev = flash_area_get_device(flash->area);
if (!flash_dev) {
return -ENODEV;
}
err = flash_get_page_info_by_offs(flash_dev,
flash->offset + block->offset, &page);
if (err) {
return err;
}
erase_size = page.size * DIV_ROUND_UP(block->size, page.size);
#else
erase_size = block->size;
#endif
return flash_area_flatten(flash->area, flash->offset + block->offset,
erase_size);
}
static int rd_chunk(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)
{
struct bt_mesh_blob_io_flash *flash = FLASH_IO(io);
return flash_area_read(flash->area,
flash->offset + block->offset + chunk->offset,
chunk->data, chunk->size);
}
static int wr_chunk(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)
{
struct bt_mesh_blob_io_flash *flash = FLASH_IO(io);
if (IS_ENABLED(CONFIG_SOC_FLASH_NRF_RRAM)) {
return flash_area_write(flash->area,
flash->offset + block->offset + chunk->offset,
chunk->data, chunk->size);
}
uint8_t buf[ROUND_UP(BLOB_RX_CHUNK_SIZE, WRITE_BLOCK_SIZE)];
off_t area_offset = flash->offset + block->offset + chunk->offset;
int i = 0;
/* Write block align the chunk data */
memset(&buf[i], 0xff, area_offset % WRITE_BLOCK_SIZE);
i += area_offset % WRITE_BLOCK_SIZE;
memcpy(&buf[i], chunk->data, chunk->size);
i += chunk->size;
memset(&buf[i], 0xff, ROUND_UP(i, WRITE_BLOCK_SIZE) - i);
i = ROUND_UP(i, WRITE_BLOCK_SIZE);
return flash_area_write(flash->area,
ROUND_DOWN(area_offset, WRITE_BLOCK_SIZE),
buf, i);
}
int bt_mesh_blob_io_flash_init(struct bt_mesh_blob_io_flash *flash,
uint8_t area_id, off_t offset)
{
int err;
err = test_flash_area(area_id);
if (err) {
return err;
}
flash->area_id = area_id;
flash->offset = offset;
flash->io.open = io_open;
flash->io.close = io_close;
flash->io.block_start = block_start;
flash->io.block_end = NULL;
flash->io.rd = rd_chunk;
flash->io.wr = wr_chunk;
return 0;
}