/* * Copyright (c) 2022-2024 Libre Solar Technologies GmbH * Copyright (c) 2022-2024 tado GmbH * * SPDX-License-Identifier: Apache-2.0 */ #include "frag_flash.h" #include #include #include #include #include LOG_MODULE_REGISTER(lorawan_frag_flash, CONFIG_LORAWAN_SERVICES_LOG_LEVEL); #define TARGET_IMAGE_AREA FIXED_PARTITION_ID(slot1_partition) struct frag_cache_entry { uint32_t addr; uint8_t data[FRAG_MAX_SIZE]; }; static struct frag_cache_entry frag_cache[FRAG_MAX_REDUNDANCY]; static uint32_t frag_size; static int cached_frags; static bool use_cache; static const struct flash_area *fa; int frag_flash_init(uint32_t fragment_size) { int err; if (fragment_size > FRAG_MAX_SIZE) { return -ENOSPC; } frag_size = fragment_size; cached_frags = 0; use_cache = false; err = flash_area_open(TARGET_IMAGE_AREA, &fa); if (err) { return err; } LOG_DBG("Starting to erase flash area"); err = flash_area_erase(fa, 0, fa->fa_size); LOG_DBG("Finished erasing flash area"); return err; } int8_t frag_flash_write(uint32_t addr, uint8_t *data, uint32_t size) { int8_t err = 0; if (!use_cache) { LOG_DBG("Writing %u bytes to addr 0x%X", size, addr); err = flash_area_write(fa, addr, data, size); } else { LOG_DBG("Caching %u bytes for addr 0x%X", size, addr); if (size != frag_size) { LOG_ERR("Invalid fragment size %d", size); return -EINVAL; } /* overwrite fragment in cache if existing */ for (int i = 0; i < cached_frags; i++) { if (frag_cache[i].addr == addr) { memcpy(frag_cache[i].data, data, size); return 0; } } /* otherwise create new cache entry */ if (cached_frags < ARRAY_SIZE(frag_cache)) { frag_cache[cached_frags].addr = addr; memcpy(frag_cache[cached_frags].data, data, size); cached_frags++; } else { LOG_ERR("Fragment cache too small"); err = -ENOSPC; } } return err == 0 ? 0 : -1; } int8_t frag_flash_read(uint32_t addr, uint8_t *data, uint32_t size) { for (int i = 0; i < cached_frags; i++) { if (frag_cache[i].addr == addr) { memcpy(data, frag_cache[i].data, size); return 0; } } return flash_area_read(fa, addr, data, size) == 0 ? 0 : -1; } void frag_flash_use_cache(void) { use_cache = true; } void frag_flash_finish(void) { int err; for (int i = 0; i < cached_frags; i++) { LOG_DBG("Writing %u bytes to addr 0x%x", frag_size, frag_cache[i].addr); flash_area_write(fa, frag_cache[i].addr, frag_cache[i].data, frag_size); } flash_area_close(fa); err = boot_request_upgrade(BOOT_UPGRADE_TEST); if (err) { LOG_ERR("Failed to request upgrade (err %d)", err); } }