/* * Copyright (c) 2020 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #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; }