mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			Merge pull request #2701 from simonqhughes/master
CFSTORE Integration with Storage-Volume-Manager and Flash-Journal API update to the latest versionspull/2709/merge
						commit
						2866e21bea
					
				| 
						 | 
				
			
			@ -32,8 +32,8 @@
 | 
			
		|||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0);
 | 
			
		||||
ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_(0);
 | 
			
		||||
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_MTD_K64F;
 | 
			
		||||
ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_MTD_K64F;
 | 
			
		||||
 | 
			
		||||
/* temporary buffer to hold data for testing. */
 | 
			
		||||
static const unsigned BUFFER_SIZE = 16384;
 | 
			
		||||
| 
						 | 
				
			
			@ -112,6 +112,7 @@ void test_getInfo()
 | 
			
		|||
 | 
			
		||||
    TEST_ASSERT_EQUAL(0, info.security.reserved1);
 | 
			
		||||
    TEST_ASSERT_EQUAL(0, info.security.reserved2);
 | 
			
		||||
    TEST_ASSERT((info.program_cycles == ARM_STORAGE_PROGRAM_CYCLES_INFINITE) || (info.program_cycles > 0));
 | 
			
		||||
    TEST_ASSERT(info.total_storage > 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -373,7 +374,7 @@ control_t test_programDataUsingProgramUnit(const size_t call_count)
 | 
			
		|||
        return (call_count < REPEAT_INSTANCES) ? CaseTimeout(200) + CaseRepeatAll: CaseTimeout(200);
 | 
			
		||||
    } else {
 | 
			
		||||
        TEST_ASSERT_EQUAL(firstBlock.attributes.erase_unit, rc);
 | 
			
		||||
        verifyBytePattern(addr, firstBlock.attributes.erase_unit, (uint8_t)0xFF);
 | 
			
		||||
        verifyBytePattern(addr, firstBlock.attributes.erase_unit, info.erased_value ? (uint8_t)0xFF : (uint8_t)0);
 | 
			
		||||
 | 
			
		||||
        static const uint32_t BYTE_PATTERN = 0xAA551122;
 | 
			
		||||
        size_t sizeofData = info.program_unit;
 | 
			
		||||
| 
						 | 
				
			
			@ -495,7 +496,7 @@ control_t test_programDataUsingOptimalProgramUnit(const size_t call_count)
 | 
			
		|||
        return (call_count < REPEAT_INSTANCES) ? CaseTimeout(200) + CaseRepeatAll: CaseTimeout(200);
 | 
			
		||||
    } else {
 | 
			
		||||
        TEST_ASSERT_EQUAL(firstBlock.attributes.erase_unit, rc);
 | 
			
		||||
        verifyBytePattern(addr, firstBlock.attributes.erase_unit, (uint8_t)0xFF);
 | 
			
		||||
        verifyBytePattern(addr, firstBlock.attributes.erase_unit, info.erased_value ? (uint8_t)0xFF : (uint8_t)0);
 | 
			
		||||
 | 
			
		||||
        static const uint8_t BYTE_PATTERN = 0xAA;
 | 
			
		||||
        size_t sizeofData = info.optimal_program_unit;
 | 
			
		||||
| 
						 | 
				
			
			@ -579,10 +580,12 @@ void eraseCompleteCallback(int32_t status, ARM_STORAGE_OPERATION operation)
 | 
			
		|||
    const uint64_t addr = firstBlock.addr + eraseIteration * ERASE_UNITS_PER_ITERATION * firstBlock.attributes.erase_unit;
 | 
			
		||||
    ++eraseIteration;
 | 
			
		||||
 | 
			
		||||
#ifndef __CC_ARM
 | 
			
		||||
    printf("testing erased sector at addr %lu\n", (uint32_t)addr);
 | 
			
		||||
#endif
 | 
			
		||||
    verifyBytePattern(addr, ERASE_UNITS_PER_ITERATION * firstBlock.attributes.erase_unit, (uint8_t)0xFF);
 | 
			
		||||
    ARM_STORAGE_INFO info;
 | 
			
		||||
    int32_t rc = drv->GetInfo(&info);
 | 
			
		||||
    TEST_ASSERT_EQUAL(ARM_DRIVER_OK, rc);
 | 
			
		||||
 | 
			
		||||
    //printf("testing erased sector at addr %lu", (uint32_t)addr);
 | 
			
		||||
    verifyBytePattern(addr, ERASE_UNITS_PER_ITERATION * firstBlock.attributes.erase_unit, info.erased_value ? (uint8_t)0xFF : (uint8_t)0);
 | 
			
		||||
 | 
			
		||||
    Harness::validate_callback();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -628,6 +631,10 @@ control_t test_erase(const size_t call_count)
 | 
			
		|||
    } else {
 | 
			
		||||
        TEST_ASSERT_EQUAL(ERASE_UNITS_PER_ITERATION * firstBlock.attributes.erase_unit, rc);
 | 
			
		||||
 | 
			
		||||
        ARM_STORAGE_INFO info;
 | 
			
		||||
        rc = drv->GetInfo(&info);
 | 
			
		||||
        TEST_ASSERT_EQUAL(ARM_DRIVER_OK, rc);
 | 
			
		||||
 | 
			
		||||
        /* test that the actual sector has been erased */
 | 
			
		||||
        printf("testing erased sector at addr %lu\n", (uint32_t)addr);
 | 
			
		||||
        verifyBytePattern(addr, ERASE_UNITS_PER_ITERATION * firstBlock.attributes.erase_unit, (uint8_t)0xFF);
 | 
			
		||||
| 
						 | 
				
			
			@ -708,8 +715,12 @@ control_t test_eraseAll(const size_t call_count)
 | 
			
		|||
        unsigned index = 0;
 | 
			
		||||
        static const unsigned MAX_VERIFY_ITERATIONS = 5;
 | 
			
		||||
        while ((index < MAX_VERIFY_ITERATIONS) && (addr < (firstBlock.addr + firstBlock.size))) {
 | 
			
		||||
            printf("testing erased chip at addr %lu\n", (uint32_t)addr);
 | 
			
		||||
            verifyBytePattern(addr, firstBlock.attributes.erase_unit, (uint8_t)0xFF);
 | 
			
		||||
            //printf("testing erased chip at addr %lu", (uint32_t)addr);
 | 
			
		||||
            ARM_STORAGE_INFO info;
 | 
			
		||||
            rc = drv->GetInfo(&info);
 | 
			
		||||
            TEST_ASSERT_EQUAL(ARM_DRIVER_OK, rc);
 | 
			
		||||
 | 
			
		||||
            verifyBytePattern(addr, firstBlock.attributes.erase_unit, info.erased_value ? (uint8_t)0xFF : (uint8_t)0);
 | 
			
		||||
 | 
			
		||||
            index++;
 | 
			
		||||
            addr += firstBlock.attributes.erase_unit;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -279,7 +279,7 @@ control_t cfstore_add_del_test_04(const size_t call_count)
 | 
			
		|||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @brief  Delete and attribute after an internal realloc of the cfstore memory area
 | 
			
		||||
/** @brief  Delete an attribute after an internal realloc of the cfstore memory area
 | 
			
		||||
 *
 | 
			
		||||
 * This test case goes through the following steps:
 | 
			
		||||
 * 1. Creates attribute att_1 of size x, and write some data. This causes an internal
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -234,7 +234,6 @@ typedef enum cfstore_ex_state_t {
 | 
			
		|||
    CFSTORE_EX_STATE_UNINIT_DONE
 | 
			
		||||
} cfstore_ex_state_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef struct cfstore_example1_ctx_t
 | 
			
		||||
{
 | 
			
		||||
    ARM_CFSTORE_CAPABILITIES caps;
 | 
			
		||||
| 
						 | 
				
			
			@ -263,7 +262,87 @@ static void cfstore_ex_fms_update(cfstore_example1_ctx_t* ctx);
 | 
			
		|||
/// @endcond
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   test startup code to reset flash
 | 
			
		||||
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_FLASH_START_FORMAT (FLASH_JOURNAL_OPCODE_RESET + 0x00010000)
 | 
			
		||||
 | 
			
		||||
typedef enum cfstore_ex_flash_state_t {
 | 
			
		||||
    CFSTORE_EX_FLASH_STATE_STARTING = 1,
 | 
			
		||||
    CFSTORE_EX_FLASH_STATE_FORMATTING,
 | 
			
		||||
    CFSTORE_EX_FLASH_STATE_INITIALIZING,
 | 
			
		||||
    CFSTORE_EX_FLASH_STATE_RESETTING,
 | 
			
		||||
    CFSTORE_EX_FLASH_STATE_READY,
 | 
			
		||||
} cfstore_ex_flash_state_t;
 | 
			
		||||
 | 
			
		||||
typedef struct cfstore_example1_flash_ctx_t
 | 
			
		||||
{
 | 
			
		||||
    volatile cfstore_ex_flash_state_t state;
 | 
			
		||||
} cfstore_example1_flash_ctx_t;
 | 
			
		||||
 | 
			
		||||
static cfstore_example1_flash_ctx_t cfstore_example1_flash_ctx_g;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void cfstore_ex_flash_journal_callback(int32_t status, FlashJournal_OpCode_t cmd_code)
 | 
			
		||||
{
 | 
			
		||||
    static FlashJournal_t jrnl;
 | 
			
		||||
    extern ARM_DRIVER_STORAGE ARM_Driver_Storage_MTD_K64F;
 | 
			
		||||
    const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_MTD_K64F;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if(cmd_code == (FlashJournal_OpCode_t) CFSTORE_FLASH_START_FORMAT) {
 | 
			
		||||
        CFSTORE_EX1_LOG("FORMATTING%s", "\n");
 | 
			
		||||
        status = flashJournalStrategySequential_format(drv, 4, cfstore_ex_flash_journal_callback);
 | 
			
		||||
        CFSTORE_EX1_TEST_ASSERT_MSG(status >= JOURNAL_STATUS_OK, "%s:Error: FlashJournal_format() failed (status=%d)\r\n", __func__, (int) status);
 | 
			
		||||
        if(status == 0) {
 | 
			
		||||
            /* async completion pending */
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        /* status > 0 implies  operation completed synchronously
 | 
			
		||||
         * intentional fall through */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch(cmd_code)
 | 
			
		||||
    {
 | 
			
		||||
    case FLASH_JOURNAL_OPCODE_FORMAT:
 | 
			
		||||
        /* format done */
 | 
			
		||||
        CFSTORE_EX1_TEST_ASSERT_MSG(status > JOURNAL_STATUS_OK, "%s:Error: FlashJournal_format() failed (status=%d)\r\n", __func__, (int) status);
 | 
			
		||||
        cfstore_example1_flash_ctx_g.state = CFSTORE_EX_FLASH_STATE_INITIALIZING;
 | 
			
		||||
 | 
			
		||||
        CFSTORE_EX1_LOG("FLASH INITIALIZING%s", "\n");
 | 
			
		||||
        status = FlashJournal_initialize(&jrnl, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, NULL);
 | 
			
		||||
        CFSTORE_EX1_TEST_ASSERT_MSG(status >= JOURNAL_STATUS_OK, "%s:Error: FlashJournal_initialize() failed (status=%d)\r\n", __func__, (int) status);
 | 
			
		||||
        if(status == 0) {
 | 
			
		||||
            /* async completion pending */
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        /* status > 0 implies  operation completed synchronously
 | 
			
		||||
         * intentional fall through */
 | 
			
		||||
    case FLASH_JOURNAL_OPCODE_INITIALIZE:
 | 
			
		||||
        /* initialize done */
 | 
			
		||||
        CFSTORE_EX1_TEST_ASSERT_MSG(status > JOURNAL_STATUS_OK, "%s:Error: FlashJournal_initialize() failed (status=%d)\r\n", __func__, (int) status);
 | 
			
		||||
        cfstore_example1_flash_ctx_g.state = CFSTORE_EX_FLASH_STATE_RESETTING;
 | 
			
		||||
 | 
			
		||||
        CFSTORE_EX1_LOG("FLASH RESETTING%s", "\n");
 | 
			
		||||
        status = FlashJournal_reset(&jrnl);
 | 
			
		||||
        CFSTORE_EX1_TEST_ASSERT_MSG(status >= JOURNAL_STATUS_OK, "%s:Error: FlashJournal_reset() failed (status=%d)\r\n", __func__, (int) status);
 | 
			
		||||
        /* intentional fall through */
 | 
			
		||||
    case FLASH_JOURNAL_OPCODE_RESET:
 | 
			
		||||
        /* reset done */
 | 
			
		||||
        CFSTORE_EX1_LOG("FLASH RESET DONE%s", "\n");
 | 
			
		||||
        cfstore_example1_flash_ctx_g.state = CFSTORE_EX_FLASH_STATE_READY;
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
        CFSTORE_EX1_LOG("%s:Error: notification of unsupported cmd_code event (status=%d, cmd_code=%d)\n", __func__, (int) status, (int) cmd_code);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
#endif  /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   test startup code to reset flash for testing purposes.
 | 
			
		||||
 */
 | 
			
		||||
static int32_t cfstore_test_startup(void)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -272,16 +351,13 @@ static int32_t cfstore_test_startup(void)
 | 
			
		|||
 | 
			
		||||
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    static FlashJournal_t jrnl;
 | 
			
		||||
    extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0);
 | 
			
		||||
    const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_(0);
 | 
			
		||||
    memset(&cfstore_example1_flash_ctx_g, 0, sizeof(cfstore_example1_flash_ctx_g));
 | 
			
		||||
    cfstore_example1_flash_ctx_g.state = CFSTORE_EX_FLASH_STATE_STARTING;
 | 
			
		||||
    cfstore_ex_flash_journal_callback(JOURNAL_STATUS_OK, (FlashJournal_OpCode_t) CFSTORE_FLASH_START_FORMAT);
 | 
			
		||||
    while(cfstore_example1_flash_ctx_g.state != CFSTORE_EX_FLASH_STATE_READY) {
 | 
			
		||||
        /* spin */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = FlashJournal_initialize(&jrnl, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, NULL);
 | 
			
		||||
    CFSTORE_EX1_TEST_ASSERT_MSG(ret >= JOURNAL_STATUS_OK, "%s:Error: FlashJournal_initialize() failed (ret=%d)\r\n", __func__, (int) ret);
 | 
			
		||||
 | 
			
		||||
    ret = FlashJournal_reset(&jrnl);
 | 
			
		||||
    CFSTORE_EX1_TEST_ASSERT_MSG(ret >= JOURNAL_STATUS_OK, "%s:Error: FlashJournal_reset() failed (ret=%d)\r\n", __func__, (int) ret);
 | 
			
		||||
#endif /*  CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
 | 
			
		||||
 | 
			
		||||
    return ARM_DRIVER_OK;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -268,7 +268,7 @@ static control_t cfstore_example3_app_start(const size_t call_count)
 | 
			
		|||
    ctx->hkey_prev = ctx->hkey_prev_buf;
 | 
			
		||||
    ctx->caps = cfstore_drv->GetCapabilities();
 | 
			
		||||
    CFSTORE_EX1_LOG("%s:INITIALIZING: caps.asynchronous_ops=%lu\n", __func__, ctx->caps.asynchronous_ops);
 | 
			
		||||
    if(ctx->caps.asynchronous_ops == true){
 | 
			
		||||
    if(ctx->caps.asynchronous_ops == 1){
 | 
			
		||||
    	/* This is a sync mode only test. If this test is not built for sync mode, then skip testing return true
 | 
			
		||||
    	 * This means the test will conveniently pass when run in CI as part of async mode testing */
 | 
			
		||||
        CFSTORE_EX1_LOG("*** Skipping test as binary built for flash journal async mode, and this test is sync-only%s", "\n");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -74,7 +74,7 @@ static control_t cfstore_example4_test_00(const size_t call_count)
 | 
			
		|||
    /* initialise the context */
 | 
			
		||||
    caps = gCfStoreDriver->GetCapabilities();
 | 
			
		||||
    CFSTORE_LOG("%s:INITIALIZING: caps.asynchronous_ops=%lu\n", __func__, caps.asynchronous_ops);
 | 
			
		||||
    if(caps.asynchronous_ops == true){
 | 
			
		||||
    if(caps.asynchronous_ops == 1){
 | 
			
		||||
    	/* This is a sync mode only test. If this test is not built for sync mode, then skip testing return true
 | 
			
		||||
    	 * This means the test will conveniently pass when run in CI as part of async mode testing */
 | 
			
		||||
        CFSTORE_LOG("*** Skipping test as binary built for flash journal async mode, and this test is sync-only%s", "\n");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -167,8 +167,8 @@ int32_t cfstore_test_startup(void)
 | 
			
		|||
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    static FlashJournal_t jrnl;
 | 
			
		||||
    extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0);
 | 
			
		||||
    const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_(0);
 | 
			
		||||
    extern ARM_DRIVER_STORAGE ARM_Driver_Storage_MTD_K64F;
 | 
			
		||||
    const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_MTD_K64F;
 | 
			
		||||
 | 
			
		||||
    ret = FlashJournal_initialize(&jrnl, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, NULL);
 | 
			
		||||
    CFSTORE_EX5_TEST_ASSERT_MSG(ret >= JOURNAL_STATUS_OK, "%s:Error: FlashJournal_initialize() failed (ret=%d)\r\n", __func__, (int) ret);
 | 
			
		||||
| 
						 | 
				
			
			@ -278,7 +278,7 @@ static control_t cfstore_EXAMPLE5_app_start(const size_t call_count)
 | 
			
		|||
    ctx->hkey_prev = ctx->hkey_prev_buf;
 | 
			
		||||
    ctx->caps = cfstore_drv->GetCapabilities();
 | 
			
		||||
    CFSTORE_EX5_LOG("%s:INITIALIZING: caps.asynchronous_ops=%lu\n", __func__, ctx->caps.asynchronous_ops);
 | 
			
		||||
    if(ctx->caps.asynchronous_ops == true){
 | 
			
		||||
    if(ctx->caps.asynchronous_ops){
 | 
			
		||||
    	/* This is a sync mode only test. If this test is not built for sync mode, then skip testing return true
 | 
			
		||||
    	 * This means the test will conveniently pass when run in CI as part of async mode testing */
 | 
			
		||||
        CFSTORE_EX5_LOG("*** Skipping test as binary built for flash journal async mode, and this test is sync-only%s", "\n");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -88,7 +88,8 @@ char cfstore_flash_utest_msg_g[CFSTORE_FLASH_UTEST_MSG_BUF_SIZE];
 | 
			
		|||
 | 
			
		||||
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
uint16_t cfstore_flash_mtd_async_ops_g = 0;
 | 
			
		||||
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0);
 | 
			
		||||
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_MTD_K64F;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* KV data for test_01 */
 | 
			
		||||
static cfstore_kv_data_t cfstore_flush_test_01_kv_data[] = {
 | 
			
		||||
| 
						 | 
				
			
			@ -279,7 +280,7 @@ void cfstore_flash_test_01_callback(int32_t status, FlashJournal_OpCode_t cmd_co
 | 
			
		|||
static void cfstore_flash_fsm_init_on_entry(void* context)
 | 
			
		||||
{
 | 
			
		||||
    /* round up cfstore_flash_data_blob_t to nearest k64f program unit size */
 | 
			
		||||
    const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_(0);
 | 
			
		||||
    const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_MTD_K64F;
 | 
			
		||||
    FlashJournal_Info_t info;
 | 
			
		||||
    FlashJournal_Status_t status = JOURNAL_STATUS_ERROR;
 | 
			
		||||
    cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -844,7 +844,7 @@ static control_t cfstore_flush3_test_00(const size_t call_count)
 | 
			
		|||
    /* initialise the context */
 | 
			
		||||
    caps = drv->GetCapabilities();
 | 
			
		||||
    CFSTORE_LOG("%s:INITIALIZING: caps.asynchronous_ops=%lu\n", __func__, caps.asynchronous_ops);
 | 
			
		||||
    if(caps.asynchronous_ops == true){
 | 
			
		||||
    if(caps.asynchronous_ops == 1){
 | 
			
		||||
        /* This is a sync mode only test. If this test is not built for sync mode, then skip testing return true
 | 
			
		||||
         * This means the test will conveniently pass when run in CI as part of async mode testing */
 | 
			
		||||
        CFSTORE_LOG("*** Skipping test as binary built for flash journal async mode, and this test is sync-only%s", "\n");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -103,7 +103,7 @@ static control_t cfstore_init_app_start(const size_t call_count)
 | 
			
		|||
    memset(ctx, 0, sizeof(cfstore_init_ctx_t));
 | 
			
		||||
    ctx->caps = cfstore_drv->GetCapabilities();
 | 
			
		||||
    CFSTORE_LOG("%s:INITIALIZING: caps.asynchronous_ops=%lu\n", __func__, ctx->caps.asynchronous_ops);
 | 
			
		||||
    if(ctx->caps.asynchronous_ops == true){
 | 
			
		||||
    if(ctx->caps.asynchronous_ops == 1){
 | 
			
		||||
    	/* This is a sync mode only test. If this test is not built for sync mode, then skip testing return true
 | 
			
		||||
    	 * This means the test will conveniently pass when run in CI as part of async mode testing */
 | 
			
		||||
        CFSTORE_LOG("*** Skipping test as binary built for flash journal async mode, and this test is sync-only%s", "\n");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -272,7 +272,7 @@ control_t cfstore_misc_test_04_start(const size_t call_count)
 | 
			
		|||
 | 
			
		||||
    status = drv->GetStatus();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: GetStatus() before initialisation should have reported error, but reported no error.\r\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(status.error == true, cfstore_misc_utest_msg_g);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(status.error == 1, cfstore_misc_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    ret = drv->Initialize(cfstore_utest_default_callback, NULL);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to initialize CFSTORE (ret=%d)\n", __func__, (int) ret);
 | 
			
		||||
| 
						 | 
				
			
			@ -295,10 +295,10 @@ control_t cfstore_misc_test_04_end(const size_t call_count)
 | 
			
		|||
 | 
			
		||||
    status = drv->GetStatus();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: GetStatus() but reported error.\r\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(status.error == false, cfstore_misc_utest_msg_g);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(status.error == 0, cfstore_misc_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: GetStatus() reported operation in progress.\r\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(status.in_progress == false, cfstore_misc_utest_msg_g);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(status.in_progress == 0, cfstore_misc_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,10 +15,6 @@
 | 
			
		|||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#if !DEVICE_STORAGE
 | 
			
		||||
    #error [NOT_SUPPORTED] Storage not supported for this target
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef TARGET_LIKE_POSIX
 | 
			
		||||
#define AVOID_GREENTEA
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -29,6 +25,7 @@
 | 
			
		|||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
 | 
			
		||||
#include "flash-journal-strategy-sequential/flash_journal_crc.h"
 | 
			
		||||
#include "flash-journal-strategy-sequential/flash_journal_strategy_sequential.h"
 | 
			
		||||
#include "flash-journal-strategy-sequential/flash_journal_private.h"
 | 
			
		||||
#include <string.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -36,8 +33,8 @@
 | 
			
		|||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0);
 | 
			
		||||
ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_(0);
 | 
			
		||||
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_MTD_K64F;
 | 
			
		||||
const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_MTD_K64F;
 | 
			
		||||
 | 
			
		||||
FlashJournal_t      journal;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -54,32 +51,64 @@ void callbackHandler(int32_t status, FlashJournal_OpCode_t cmd_code)
 | 
			
		|||
 | 
			
		||||
    switch (cmd_code) {
 | 
			
		||||
        case FLASH_JOURNAL_OPCODE_INITIALIZE:
 | 
			
		||||
            // printf("journal_callbackHandler: callback for init with status %" PRId32 "\n", status);
 | 
			
		||||
            //printf("journal_callbackHandler: callback for init with status %" PRId32 "\n", status);
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case FLASH_JOURNAL_OPCODE_READ_BLOB:
 | 
			
		||||
            // printf("journal_callbackHandler: callback for read with status %" PRId32 "\n", status);
 | 
			
		||||
            //printf("journal_callbackHandler: callback for read with status %" PRId32 "\n", status);
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case FLASH_JOURNAL_OPCODE_LOG_BLOB:
 | 
			
		||||
            // printf("journal_callbackHandler: callback for log with status %" PRId32 "\n", status);
 | 
			
		||||
            //printf("journal_callbackHandler: callback for log with status %" PRId32 "\n", status);
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case FLASH_JOURNAL_OPCODE_COMMIT:
 | 
			
		||||
            // printf("journal_callbackHandler: callback for commit with status %" PRId32 "\n", status);
 | 
			
		||||
            //printf("journal_callbackHandler: callback for commit with status %" PRId32 "\n", status);
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case FLASH_JOURNAL_OPCODE_RESET:
 | 
			
		||||
            // printf("journal_callbackHandler: callback for reset with status %" PRId32 "\n", status);
 | 
			
		||||
            //printf("journal_callbackHandler: callback for reset with status %" PRId32 "\n", status);
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case FLASH_JOURNAL_OPCODE_FORMAT:
 | 
			
		||||
            //printf("journal_callbackHandler: callback for format with status %" PRId32 "\n", status);
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            // printf("journal_callbackHandler: callback for opcode %u with status %" PRId32 "\n", cmd_code, status);
 | 
			
		||||
            //printf("journal_callbackHandler: callback for opcode %u with status %" PRId32 "\n", cmd_code, status);
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
    Harness::validate_callback(); // Validate the callback
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
control_t test_format(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
    //printf("test_format: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
 | 
			
		||||
 | 
			
		||||
    ARM_STORAGE_INFO mtdInfo;
 | 
			
		||||
    rc = drv->GetInfo(&mtdInfo);
 | 
			
		||||
    TEST_ASSERT_EQUAL(ARM_DRIVER_OK, rc);
 | 
			
		||||
    TEST_ASSERT(mtdInfo.total_storage > 0);
 | 
			
		||||
 | 
			
		||||
    if (call_count == 1) {
 | 
			
		||||
        rc = flashJournalStrategySequential_format(drv, 4 /* numSlots */, callbackHandler);
 | 
			
		||||
        TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
 | 
			
		||||
        if (rc == JOURNAL_STATUS_OK) {
 | 
			
		||||
            return CaseTimeout(200) + CaseRepeatAll;
 | 
			
		||||
        }
 | 
			
		||||
        TEST_ASSERT_EQUAL(1, rc); /* synchronous completion is expected to return 1. */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test_initializeBeforeCreate()
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc = FlashJournal_initialize(&journal, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, callbackHandler);
 | 
			
		||||
    TEST_ASSERT((rc == 1) || (rc == JOURNAL_STATUS_NOT_FORMATTED));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
control_t test_initialize()
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc = FlashJournal_initialize(&journal, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, callbackHandler);
 | 
			
		||||
| 
						 | 
				
			
			@ -115,7 +144,7 @@ control_t test_resetAndInitialize(const size_t call_count)
 | 
			
		|||
        NEEDS_VERIFICATION_FOLLOWING_INITIALIZE,
 | 
			
		||||
    } state;
 | 
			
		||||
 | 
			
		||||
    printf("test_resetAndInitialize: entered with call_count %u\n", call_count);
 | 
			
		||||
    //printf("test_resetAndInitialize: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
 | 
			
		||||
    if (call_count == 1) {
 | 
			
		||||
        state = NEEDS_INITIAL_RESET;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -127,7 +156,7 @@ control_t test_resetAndInitialize(const size_t call_count)
 | 
			
		|||
            TEST_ASSERT(info.capacity > 0);
 | 
			
		||||
            previousCapacity = info.capacity;
 | 
			
		||||
 | 
			
		||||
            printf("test_resetAndInitialize: calling reset()\n");
 | 
			
		||||
            //printf("test_resetAndInitialize: calling reset()\n");
 | 
			
		||||
            rc = FlashJournal_reset(&journal);
 | 
			
		||||
            TEST_ASSERT_NOT_EQUAL(JOURNAL_STATUS_UNSUPPORTED, rc);
 | 
			
		||||
            TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
 | 
			
		||||
| 
						 | 
				
			
			@ -152,7 +181,7 @@ control_t test_resetAndInitialize(const size_t call_count)
 | 
			
		|||
            TEST_ASSERT_EQUAL(0, info.sizeofJournaledBlob);
 | 
			
		||||
 | 
			
		||||
            /* attempt an initialize following reset() */
 | 
			
		||||
            printf("test_resetAndInitialize: calling initialize() after reset\n");
 | 
			
		||||
            //printf("test_resetAndInitialize: calling initialize() after reset\n");
 | 
			
		||||
            rc = FlashJournal_initialize(&journal, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, callbackHandler);
 | 
			
		||||
            TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
 | 
			
		||||
            state = NEEDS_VERIFICATION_FOLLOWING_INITIALIZE;
 | 
			
		||||
| 
						 | 
				
			
			@ -164,7 +193,7 @@ control_t test_resetAndInitialize(const size_t call_count)
 | 
			
		|||
            /* fall through */
 | 
			
		||||
        case NEEDS_VERIFICATION_FOLLOWING_INITIALIZE:
 | 
			
		||||
        default:
 | 
			
		||||
            printf("test_resetAndInitialize: verification\n");
 | 
			
		||||
            //printf("test_resetAndInitialize: verification\n");
 | 
			
		||||
            TEST_ASSERT_EQUAL(0, sequentialJournal->nextSequenceNumber);
 | 
			
		||||
            TEST_ASSERT_EQUAL((uint32_t)-1, sequentialJournal->currentBlobIndex);
 | 
			
		||||
            TEST_ASSERT_EQUAL(SEQUENTIAL_JOURNAL_STATE_INITIALIZED, sequentialJournal->state);
 | 
			
		||||
| 
						 | 
				
			
			@ -184,7 +213,7 @@ control_t test_commitWithoutLogs(const size_t call_count)
 | 
			
		|||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    printf("test_commitWithoutLogs: entered with call_count %u\n", call_count);
 | 
			
		||||
    //printf("test_commitWithoutLogs: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
 | 
			
		||||
 | 
			
		||||
    switch (call_count) {
 | 
			
		||||
        case 1:
 | 
			
		||||
| 
						 | 
				
			
			@ -199,7 +228,7 @@ control_t test_commitWithoutLogs(const size_t call_count)
 | 
			
		|||
 | 
			
		||||
        case 2:
 | 
			
		||||
            rc = FlashJournal_commit(&journal);
 | 
			
		||||
            // printf("commit returned %" PRId32 "\r\n", rc);
 | 
			
		||||
            //printf("commit returned %" PRId32 "\r\n", rc);
 | 
			
		||||
            TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
 | 
			
		||||
            if (rc == JOURNAL_STATUS_OK) {
 | 
			
		||||
                TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
 | 
			
		||||
| 
						 | 
				
			
			@ -221,7 +250,7 @@ control_t test_logSmallWithoutCommit(const size_t call_count)
 | 
			
		|||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    printf("test_logSmallWithoutCommit: entered with call_count %u\n", call_count);
 | 
			
		||||
    //printf("test_logSmallWithoutCommit: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
 | 
			
		||||
 | 
			
		||||
    switch (call_count) {
 | 
			
		||||
        case 1:
 | 
			
		||||
| 
						 | 
				
			
			@ -257,7 +286,7 @@ control_t test_logSmallAndCommit(const size_t call_count)
 | 
			
		|||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    printf("test_logSmallAndCommit: entered with call_count %u\n", call_count);
 | 
			
		||||
    //printf("test_logSmallAndCommit: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
 | 
			
		||||
 | 
			
		||||
    switch (call_count) {
 | 
			
		||||
        case 1:
 | 
			
		||||
| 
						 | 
				
			
			@ -311,13 +340,13 @@ control_t test_initializeAfterLogSmallAndCommit(const size_t call_count)
 | 
			
		|||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    printf("test_initializeAfterLogSmallAndCommit: entered with call_count %u\n", call_count);
 | 
			
		||||
    //printf("test_initializeAfterLogSmallAndCommit: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
 | 
			
		||||
 | 
			
		||||
    if (call_count == 1) {
 | 
			
		||||
        rc = FlashJournal_initialize(&journal, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, callbackHandler);
 | 
			
		||||
        TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
 | 
			
		||||
        if (rc == JOURNAL_STATUS_OK) {
 | 
			
		||||
            printf("asynchronous_ops for init\n");
 | 
			
		||||
            //printf("asynchronous_ops for init\n");
 | 
			
		||||
            return CaseTimeout(200) + CaseRepeatAll;
 | 
			
		||||
        }
 | 
			
		||||
        TEST_ASSERT_EQUAL(1, rc); /* synchronous completion of initialize() is expected to return 1 */
 | 
			
		||||
| 
						 | 
				
			
			@ -335,7 +364,7 @@ control_t test_logLargeWithoutCommit(const size_t call_count)
 | 
			
		|||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    printf("test_logLargeWithoutCommit: entered with call_count %u\n", call_count);
 | 
			
		||||
    //printf("test_logLargeWithoutCommit: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
 | 
			
		||||
 | 
			
		||||
    switch (call_count) {
 | 
			
		||||
        case 1:
 | 
			
		||||
| 
						 | 
				
			
			@ -370,7 +399,7 @@ control_t test_logLargeAndCommit(const size_t call_count)
 | 
			
		|||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    printf("test_logLargeAndCommit: entered with call_count %u\n", call_count);
 | 
			
		||||
    //printf("test_logLargeAndCommit: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
 | 
			
		||||
 | 
			
		||||
    switch (call_count) {
 | 
			
		||||
        case 1:
 | 
			
		||||
| 
						 | 
				
			
			@ -424,13 +453,13 @@ control_t test_initializeAfterLogLargeAndCommit(const size_t call_count)
 | 
			
		|||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    printf("test_initializeAfterLogLargeAndCommit: entered with call_count %u\n", call_count);
 | 
			
		||||
    //printf("test_initializeAfterLogLargeAndCommit: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
 | 
			
		||||
 | 
			
		||||
    if (call_count == 1) {
 | 
			
		||||
        rc = FlashJournal_initialize(&journal, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, callbackHandler);
 | 
			
		||||
        TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
 | 
			
		||||
        if (rc == JOURNAL_STATUS_OK) {
 | 
			
		||||
            printf("test_initializeAfterLogLargeAndCommit: asynchronous_ops for init\n");
 | 
			
		||||
            //printf("test_initializeAfterLogLargeAndCommit: asynchronous_ops for init\n");
 | 
			
		||||
            return CaseTimeout(200) + CaseRepeatAll;
 | 
			
		||||
        }
 | 
			
		||||
        TEST_ASSERT_EQUAL(1, rc); /* synchronous completion of initialize() is expected to return 1 */
 | 
			
		||||
| 
						 | 
				
			
			@ -449,7 +478,7 @@ control_t test_logLargeAndReadSmallChunks(const size_t call_count)
 | 
			
		|||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    printf("test_logLargeAndReadSmallChunks: entered with call_count %u\n", call_count);
 | 
			
		||||
    //printf("test_logLargeAndReadSmallChunks: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
 | 
			
		||||
 | 
			
		||||
    static const size_t SMALL_CHUNK_COUNT = 4;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -501,7 +530,7 @@ control_t test_logLargeAndReadSmallChunks(const size_t call_count)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    while ((rc = FlashJournal_read(&journal, buffer, SIZEOF_LARGE_WRITE / SMALL_CHUNK_COUNT)) != JOURNAL_STATUS_EMPTY) {
 | 
			
		||||
        // printf("read returned %ld\n", rc);
 | 
			
		||||
        // printf("read returned %" PRId32 "\n", rc);
 | 
			
		||||
        TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
 | 
			
		||||
        if (rc == JOURNAL_STATUS_OK) {
 | 
			
		||||
            TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
 | 
			
		||||
| 
						 | 
				
			
			@ -523,7 +552,7 @@ control_t test_readLargeInSmallOddChunks(const size_t call_count)
 | 
			
		|||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    printf("test_readLargeInSmallOddChunks<0x%02x, %u>: entered with call_count %u\n", PATTERN, SIZEOF_READS, call_count);
 | 
			
		||||
    //printf("test_readLargeInSmallOddChunks<0x%02x, %" PRIu32 ">: entered with call_count %" PRIu32 "\n", PATTERN, (uint32_t)SIZEOF_READS, (uint32_t)call_count);
 | 
			
		||||
 | 
			
		||||
    if (call_count == 1) {
 | 
			
		||||
        FlashJournal_Info_t info;
 | 
			
		||||
| 
						 | 
				
			
			@ -546,7 +575,7 @@ control_t test_readLargeInSmallOddChunks(const size_t call_count)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    while ((rc = FlashJournal_read(&journal, buffer, SIZEOF_READS)) != JOURNAL_STATUS_EMPTY) {
 | 
			
		||||
        // printf("read returned %ld\n", rc);
 | 
			
		||||
        // printf("read returned %" PRId32 "\n", rc);
 | 
			
		||||
        TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
 | 
			
		||||
        if (rc == JOURNAL_STATUS_OK) {
 | 
			
		||||
            TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
 | 
			
		||||
| 
						 | 
				
			
			@ -563,6 +592,205 @@ control_t test_readLargeInSmallOddChunks(const size_t call_count)
 | 
			
		|||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<uint8_t PATTERN>
 | 
			
		||||
control_t test_logPattern(size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc = JOURNAL_STATUS_OK;
 | 
			
		||||
 | 
			
		||||
    //printf("test_logpattern: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
 | 
			
		||||
 | 
			
		||||
    switch (call_count) {
 | 
			
		||||
        case 1:
 | 
			
		||||
            for (unsigned index = 0; index < SIZEOF_LARGE_WRITE; index++) {
 | 
			
		||||
                buffer[index] = (uint8_t)(PATTERN ^ index);
 | 
			
		||||
            }
 | 
			
		||||
            rc = FlashJournal_log(&journal, buffer, SIZEOF_LARGE_WRITE);
 | 
			
		||||
            TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
 | 
			
		||||
            if (rc == JOURNAL_STATUS_OK) {
 | 
			
		||||
                TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
 | 
			
		||||
                return CaseTimeout(500) + CaseRepeatAll;
 | 
			
		||||
            }
 | 
			
		||||
            /* intentional fall-through */
 | 
			
		||||
            call_count = 2;
 | 
			
		||||
 | 
			
		||||
        case 2:
 | 
			
		||||
            rc = FlashJournal_commit(&journal);
 | 
			
		||||
            TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
 | 
			
		||||
            if (rc == JOURNAL_STATUS_OK) {
 | 
			
		||||
                TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
 | 
			
		||||
                return CaseTimeout(500) + CaseRepeatAll;
 | 
			
		||||
            }
 | 
			
		||||
            callbackStatus = rc;
 | 
			
		||||
            /* intentional fall-through */
 | 
			
		||||
            call_count = 3;
 | 
			
		||||
 | 
			
		||||
        case 3:
 | 
			
		||||
            {
 | 
			
		||||
                FlashJournal_Info_t info;
 | 
			
		||||
                rc = FlashJournal_getInfo(&journal, &info);
 | 
			
		||||
                TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
 | 
			
		||||
                TEST_ASSERT_EQUAL(SIZEOF_LARGE_WRITE, info.sizeofJournaledBlob);
 | 
			
		||||
            }
 | 
			
		||||
            /* intentional fall-through */
 | 
			
		||||
            call_count = 4;
 | 
			
		||||
 | 
			
		||||
        case 4:
 | 
			
		||||
            TEST_ASSERT_EQUAL(1, callbackStatus);
 | 
			
		||||
 | 
			
		||||
            rc = FlashJournal_read(&journal, buffer, SIZEOF_LARGE_WRITE);
 | 
			
		||||
            TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
 | 
			
		||||
            if (rc == JOURNAL_STATUS_OK) {
 | 
			
		||||
                TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
 | 
			
		||||
                return CaseTimeout(500) + CaseRepeatAll;
 | 
			
		||||
            }
 | 
			
		||||
            callbackStatus = rc;
 | 
			
		||||
            /* intentional fall-through */
 | 
			
		||||
            call_count = 4;
 | 
			
		||||
 | 
			
		||||
        case 5:
 | 
			
		||||
            TEST_ASSERT_EQUAL(SIZEOF_LARGE_WRITE, rc);
 | 
			
		||||
            for (unsigned i = 0; i < SIZEOF_LARGE_WRITE; i++) {
 | 
			
		||||
                // printf("index %u value %x\n", i, buffer[i]);
 | 
			
		||||
                TEST_ASSERT_EQUAL((uint8_t)(PATTERN ^ i), buffer[i]);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            TEST_ASSERT(false);
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<uint8_t PATTERN, size_t SIZEOF_READS>
 | 
			
		||||
control_t test_readFromInReverse(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
    static size_t offset = SIZEOF_LARGE_WRITE;
 | 
			
		||||
 | 
			
		||||
    //printf("test_readFrom<0x%02x, %" PRIu32 ">: entered with call_count %" PRIu32 "\n", PATTERN, (uint32_t)SIZEOF_READS, (uint32_t)call_count);
 | 
			
		||||
 | 
			
		||||
    if (call_count == 1) {
 | 
			
		||||
        FlashJournal_Info_t info;
 | 
			
		||||
        rc = FlashJournal_getInfo(&journal, &info);
 | 
			
		||||
        TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
 | 
			
		||||
        TEST_ASSERT_EQUAL(SIZEOF_LARGE_WRITE, info.sizeofJournaledBlob);
 | 
			
		||||
        TEST_ASSERT(SIZEOF_READS <= info.sizeofJournaledBlob);
 | 
			
		||||
 | 
			
		||||
        rc = FlashJournal_readFrom(&journal, offset + 1, buffer, SIZEOF_READS);
 | 
			
		||||
        TEST_ASSERT_EQUAL(JOURNAL_STATUS_EMPTY, rc);
 | 
			
		||||
        rc = FlashJournal_readFrom(&journal, offset, buffer, SIZEOF_READS);
 | 
			
		||||
        TEST_ASSERT_EQUAL(JOURNAL_STATUS_EMPTY, rc);
 | 
			
		||||
        offset -= SIZEOF_READS;
 | 
			
		||||
    } else {
 | 
			
		||||
        if (drv->GetCapabilities().asynchronous_ops) {
 | 
			
		||||
            if (callbackStatus == 0) {
 | 
			
		||||
                return CaseNext; /* termination condition */
 | 
			
		||||
            }
 | 
			
		||||
            TEST_ASSERT_EQUAL(SIZEOF_READS, callbackStatus);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (unsigned i = 0; i < SIZEOF_READS; i++) {
 | 
			
		||||
            // printf("index %u value %x\n", i, buffer[i]);
 | 
			
		||||
            TEST_ASSERT_EQUAL((uint8_t)(PATTERN ^ (offset + i)), buffer[i]);
 | 
			
		||||
        }
 | 
			
		||||
        if (offset == 0) {
 | 
			
		||||
            return CaseNext;
 | 
			
		||||
        }
 | 
			
		||||
        if (offset >= SIZEOF_READS) {
 | 
			
		||||
            offset -= SIZEOF_READS;
 | 
			
		||||
        } else {
 | 
			
		||||
            offset = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // printf("test_readFrom: issuing read at offset %lu\n", offset);
 | 
			
		||||
    while ((rc = FlashJournal_readFrom(&journal, offset, buffer, SIZEOF_READS)) != JOURNAL_STATUS_EMPTY) {
 | 
			
		||||
        // printf("read returned %" PRId32 "\n", rc);
 | 
			
		||||
        TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
 | 
			
		||||
        if (rc == JOURNAL_STATUS_OK) {
 | 
			
		||||
            TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
 | 
			
		||||
            return CaseTimeout(500) + CaseRepeatAll;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        TEST_ASSERT(rc <= (int32_t)SIZEOF_READS);
 | 
			
		||||
        for (unsigned i = 0; i < (unsigned)rc; i++) {
 | 
			
		||||
            // printf("index %u value %x\n", i, buffer[i]);
 | 
			
		||||
            TEST_ASSERT_EQUAL((uint8_t)(PATTERN ^ (offset + i)), buffer[i]);
 | 
			
		||||
        }
 | 
			
		||||
        if (offset == 0) {
 | 
			
		||||
            return CaseNext;
 | 
			
		||||
        }
 | 
			
		||||
        if (offset >= SIZEOF_READS) {
 | 
			
		||||
            offset -= SIZEOF_READS;
 | 
			
		||||
        } else {
 | 
			
		||||
            offset = 0;
 | 
			
		||||
        }
 | 
			
		||||
        // printf("test_readFrom: issuing read at offset %lu\n", offset);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<uint8_t PATTERN, size_t SIZEOF_READS>
 | 
			
		||||
control_t test_readFromFollowedByReads(size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    //printf("test_readFrom<0x%02x, %" PRIu32 ">: entered with call_count %" PRIu32 "\n", PATTERN, (uint32_t)SIZEOF_READS, (uint32_t)call_count);
 | 
			
		||||
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
    static size_t offset = SIZEOF_LARGE_WRITE / 2;
 | 
			
		||||
 | 
			
		||||
    FlashJournal_Info_t info;
 | 
			
		||||
    switch (call_count) {
 | 
			
		||||
        case 1:
 | 
			
		||||
            rc = FlashJournal_getInfo(&journal, &info);
 | 
			
		||||
            TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
 | 
			
		||||
            TEST_ASSERT_EQUAL(SIZEOF_LARGE_WRITE, info.sizeofJournaledBlob);
 | 
			
		||||
            TEST_ASSERT(SIZEOF_READS <= (info.sizeofJournaledBlob - offset));
 | 
			
		||||
 | 
			
		||||
            rc = FlashJournal_readFrom(&journal, offset, buffer, SIZEOF_READS);
 | 
			
		||||
            TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
 | 
			
		||||
            if (rc == JOURNAL_STATUS_OK) {
 | 
			
		||||
                TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
 | 
			
		||||
                return CaseTimeout(500) + CaseRepeatAll;
 | 
			
		||||
            }
 | 
			
		||||
            callbackStatus = rc;
 | 
			
		||||
            /* intentional fall-through */
 | 
			
		||||
            call_count = 2;
 | 
			
		||||
 | 
			
		||||
        case 2:
 | 
			
		||||
            /* verify the previous readFrom */
 | 
			
		||||
            TEST_ASSERT_EQUAL(SIZEOF_READS, callbackStatus);
 | 
			
		||||
            for (unsigned i = 0; i < (unsigned)callbackStatus; i++) {
 | 
			
		||||
                // printf("index %u value %x\n", i, buffer[i]);
 | 
			
		||||
                TEST_ASSERT_EQUAL((uint8_t)(PATTERN ^ (offset + i)), buffer[i]);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* issue a sequential read to follow the previous readFrom */
 | 
			
		||||
            rc = FlashJournal_read(&journal, buffer, SIZEOF_READS);
 | 
			
		||||
            TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
 | 
			
		||||
            if (rc == JOURNAL_STATUS_OK) {
 | 
			
		||||
                TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
 | 
			
		||||
                return CaseTimeout(500) + CaseRepeatAll;
 | 
			
		||||
            }
 | 
			
		||||
            callbackStatus = rc;
 | 
			
		||||
            /* intentional fall-through */
 | 
			
		||||
            call_count = 3;
 | 
			
		||||
 | 
			
		||||
        case 3:
 | 
			
		||||
            TEST_ASSERT_EQUAL(SIZEOF_READS, callbackStatus);
 | 
			
		||||
 | 
			
		||||
            for (unsigned i = 0; i < (unsigned)callbackStatus; i++) {
 | 
			
		||||
                // printf("index %u value %x\n", i, buffer[i]);
 | 
			
		||||
                TEST_ASSERT_EQUAL((uint8_t)(PATTERN ^ (offset + SIZEOF_READS + i)), buffer[i]);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t SIZEOF_ODD_CHUNK, size_t N_WRITES>
 | 
			
		||||
control_t test_logSeveralOddSizedChunks(size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -573,7 +801,7 @@ control_t test_logSeveralOddSizedChunks(size_t call_count)
 | 
			
		|||
    static const uint8_t PATTERN = 0xAA;
 | 
			
		||||
    static size_t totalDataLogged = 0;
 | 
			
		||||
 | 
			
		||||
    printf("test_logSeveralOddSizedChunks<%u, %u>: entered with call_count %u\n", SIZEOF_ODD_CHUNK, N_WRITES, call_count);
 | 
			
		||||
    //printf("test_logSeveralOddSizedChunks<%" PRIu32 ", %" PRIu32 ">: entered with call_count %" PRIu32 "\n", (uint32_t)SIZEOF_ODD_CHUNK, (uint32_t)N_WRITES, (uint32_t)call_count);
 | 
			
		||||
    TEST_ASSERT(SIZEOF_ODD_CHUNK <= BUFFER_SIZE);
 | 
			
		||||
 | 
			
		||||
    /* check the status of the previous asynchronous operation */
 | 
			
		||||
| 
						 | 
				
			
			@ -584,7 +812,7 @@ control_t test_logSeveralOddSizedChunks(size_t call_count)
 | 
			
		|||
            rc = FlashJournal_getInfo(&journal, &info);
 | 
			
		||||
            TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
 | 
			
		||||
            TEST_ASSERT(SIZEOF_ODD_CHUNK < info.program_unit);
 | 
			
		||||
            printf("test_logSeveralOddSizedChunks: RETURNING CaseNext\n");
 | 
			
		||||
            //printf("test_logSeveralOddSizedChunks: RETURNING CaseNext\n");
 | 
			
		||||
            return CaseNext;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -600,7 +828,7 @@ control_t test_logSeveralOddSizedChunks(size_t call_count)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    while (call_count <= N_WRITES) {
 | 
			
		||||
        printf("test_logSeveralOddSizedChunks: iteration with call_count %u\n", call_count);
 | 
			
		||||
        //printf("test_logSeveralOddSizedChunks: iteration with call_count %" PRIu32 "\n", (uint32_t)call_count);
 | 
			
		||||
        memset(buffer, PATTERN, SIZEOF_ODD_CHUNK);
 | 
			
		||||
        rc = FlashJournal_log(&journal, buffer, SIZEOF_ODD_CHUNK);
 | 
			
		||||
        // printf("test_logSeveralOddSizedChunks: called FlashJournal_log(): rc = %" PRId32 "\n", rc);
 | 
			
		||||
| 
						 | 
				
			
			@ -663,13 +891,13 @@ control_t test_multipleWritesFollowedByCommitFollowedByMultipleReads(const size_
 | 
			
		|||
    static const size_t  SIZEOF_WRITE = BUFFER_SIZE / N_WRITES;
 | 
			
		||||
    static const size_t  SIZEOF_READ  = BUFFER_SIZE / N_READS;
 | 
			
		||||
 | 
			
		||||
    printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: entered with call_count %u\n", call_count);
 | 
			
		||||
    //printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
 | 
			
		||||
 | 
			
		||||
    if (call_count <= N_WRITES) {
 | 
			
		||||
        printf("writing pattern %02x\n", PATTERN ^ call_count);
 | 
			
		||||
        //printf("writing pattern %02" PRIx8 "\n", (uint8_t)(PATTERN ^ call_count));
 | 
			
		||||
        memset(buffer, (PATTERN ^ call_count), SIZEOF_WRITE);
 | 
			
		||||
        rc = FlashJournal_log(&journal, buffer, SIZEOF_WRITE);
 | 
			
		||||
        // printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: log returned %" PRId32 "\n", rc);
 | 
			
		||||
        //printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: log returned %" PRId32 "\n", rc);
 | 
			
		||||
        TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
 | 
			
		||||
        if (rc == JOURNAL_STATUS_OK) {
 | 
			
		||||
            TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
 | 
			
		||||
| 
						 | 
				
			
			@ -684,12 +912,12 @@ control_t test_multipleWritesFollowedByCommitFollowedByMultipleReads(const size_
 | 
			
		|||
            TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
 | 
			
		||||
            return CaseTimeout(500) + CaseRepeatAll;
 | 
			
		||||
        }
 | 
			
		||||
        // printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: commit returned %" PRId32 "\n", rc);
 | 
			
		||||
        //printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: commit returned %" PRId32 "\n", rc);
 | 
			
		||||
        callbackStatus = rc; /* pass forward the return value so that the next iteration can check callbackStatus */
 | 
			
		||||
        return CaseRepeatAll;
 | 
			
		||||
    } else if (call_count < (N_WRITES + 1 + N_READS + 1)) {
 | 
			
		||||
        unsigned readIteration = call_count - (N_WRITES + 1);
 | 
			
		||||
        printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: read iteration %u\n", readIteration);
 | 
			
		||||
        //printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: read iteration %u\n", readIteration);
 | 
			
		||||
        if (call_count == (N_WRITES + 1 /* commit */ + 1 /* first iteration after commit */)) {
 | 
			
		||||
            TEST_ASSERT_EQUAL(1, callbackStatus);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -706,7 +934,7 @@ control_t test_multipleWritesFollowedByCommitFollowedByMultipleReads(const size_
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        while ((rc = FlashJournal_read(&journal, buffer, SIZEOF_READ)) != JOURNAL_STATUS_EMPTY) {
 | 
			
		||||
            // printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: read returned %ld\n", rc);
 | 
			
		||||
            // printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: read returned %" PRId32 "\n", rc);
 | 
			
		||||
            TEST_ASSERT((rc == JOURNAL_STATUS_OK) || (rc == SIZEOF_READ));
 | 
			
		||||
            if (rc == JOURNAL_STATUS_OK) {
 | 
			
		||||
                TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
 | 
			
		||||
| 
						 | 
				
			
			@ -714,7 +942,7 @@ control_t test_multipleWritesFollowedByCommitFollowedByMultipleReads(const size_
 | 
			
		|||
            }
 | 
			
		||||
 | 
			
		||||
            TEST_ASSERT_EQUAL(SIZEOF_READ, rc);
 | 
			
		||||
            printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: checking for pattern %02x\n", PATTERN ^ readIteration);
 | 
			
		||||
            //printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: checking for pattern %02x\n", PATTERN ^ readIteration);
 | 
			
		||||
            for (unsigned i = 0; i < SIZEOF_READ; i++) {
 | 
			
		||||
                // printf("index %u value %x\n", i, buffer[i]);
 | 
			
		||||
                TEST_ASSERT_EQUAL(PATTERN ^ readIteration, buffer[i]);
 | 
			
		||||
| 
						 | 
				
			
			@ -733,7 +961,7 @@ control_t test_failedSmallWriteFollowedByPaddedWrite(const size_t call_count)
 | 
			
		|||
 | 
			
		||||
    static const uint8_t PATTERN = 0xAA;
 | 
			
		||||
 | 
			
		||||
    printf("test_failedSmallWriteFollowedByPaddedWrite: entered with call_count %u\n", call_count);
 | 
			
		||||
    //printf("test_failedSmallWriteFollowedByPaddedWrite: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
 | 
			
		||||
 | 
			
		||||
    FlashJournal_Info_t info;
 | 
			
		||||
    rc = FlashJournal_getInfo(&journal, &info);
 | 
			
		||||
| 
						 | 
				
			
			@ -799,9 +1027,35 @@ control_t test_failedSmallWriteFollowedByPaddedWrite(const size_t call_count)
 | 
			
		|||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test_crc32()
 | 
			
		||||
{
 | 
			
		||||
    const unsigned char dummyMsg[] = "ahello world";
 | 
			
		||||
    flashJournalCrcReset(); TEST_ASSERT_EQUAL(0xe8b7be43, flashJournalCrcCummulative(dummyMsg, 1));
 | 
			
		||||
    flashJournalCrcReset(); TEST_ASSERT_EQUAL(0x7e56a173, flashJournalCrcCummulative(dummyMsg, 2));
 | 
			
		||||
    flashJournalCrcReset(); TEST_ASSERT_EQUAL(0x26a80c7d, flashJournalCrcCummulative(dummyMsg, 3));
 | 
			
		||||
    flashJournalCrcReset(); TEST_ASSERT_EQUAL(0xb8946773, flashJournalCrcCummulative(dummyMsg, 4));
 | 
			
		||||
    flashJournalCrcReset(); TEST_ASSERT_EQUAL(0x5fb2761f, flashJournalCrcCummulative(dummyMsg, 5));
 | 
			
		||||
    flashJournalCrcReset(); TEST_ASSERT_EQUAL(0x82582cc7, flashJournalCrcCummulative(dummyMsg, 6));
 | 
			
		||||
    flashJournalCrcReset(); TEST_ASSERT_EQUAL(0xeceec07a, flashJournalCrcCummulative(dummyMsg, 7));
 | 
			
		||||
    flashJournalCrcReset(); TEST_ASSERT_EQUAL(0xac5f7df0, flashJournalCrcCummulative(dummyMsg, 8));
 | 
			
		||||
    flashJournalCrcReset(); TEST_ASSERT_EQUAL(0xb21e3e25, flashJournalCrcCummulative(dummyMsg, 9));
 | 
			
		||||
    flashJournalCrcReset(); TEST_ASSERT_EQUAL(0x27bf35e4, flashJournalCrcCummulative(dummyMsg, 10));
 | 
			
		||||
    flashJournalCrcReset(); TEST_ASSERT_EQUAL(0x31465baa, flashJournalCrcCummulative(dummyMsg, 11));
 | 
			
		||||
    flashJournalCrcReset(); TEST_ASSERT_EQUAL(0xaeef4661, flashJournalCrcCummulative(dummyMsg, 12));
 | 
			
		||||
 | 
			
		||||
    /* check for composability */
 | 
			
		||||
    uint32_t crc;
 | 
			
		||||
    for (unsigned msgLen = 1; msgLen < strlen((const char *)dummyMsg); msgLen++) {
 | 
			
		||||
        for (unsigned partitionIndex = 1; partitionIndex < msgLen; partitionIndex++) {
 | 
			
		||||
            flashJournalCrcReset(); crc = flashJournalCrcCummulative(dummyMsg, partitionIndex); crc = flashJournalCrcCummulative(dummyMsg + partitionIndex, msgLen - partitionIndex);
 | 
			
		||||
            flashJournalCrcReset(); TEST_ASSERT_EQUAL(flashJournalCrcCummulative(dummyMsg, msgLen), crc);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifndef AVOID_GREENTEA
 | 
			
		||||
// Custom setup handler required for proper Greentea support
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(60, "default_auto");
 | 
			
		||||
    // Call the default reporting function
 | 
			
		||||
| 
						 | 
				
			
			@ -816,6 +1070,9 @@ status_t default_setup(const size_t)
 | 
			
		|||
 | 
			
		||||
// Specify all your test cases here
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
 | 
			
		||||
    Case("initializeBeforeCreate",                      test_initializeBeforeCreate),
 | 
			
		||||
    Case("format",                                      test_format),
 | 
			
		||||
    Case("initialize",                                  test_initialize),
 | 
			
		||||
    Case("reset and initialize1",                       test_resetAndInitialize),
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -861,6 +1118,17 @@ Case cases[] = {
 | 
			
		|||
    Case("read large item in small, odd-sized chunks3", test_readLargeInSmallOddChunks<0xAA, 1021>),
 | 
			
		||||
    Case("read large item in small, odd-sized chunks4", test_readLargeInSmallOddChunks<0xAA, 2401>),
 | 
			
		||||
 | 
			
		||||
    Case("log pattern",                                 test_logPattern<0x55>),
 | 
			
		||||
    Case("readFrom",                                    test_readFromInReverse<0x55, 255>),
 | 
			
		||||
    Case("readFrom",                                    test_readFromInReverse<0x55, 512>),
 | 
			
		||||
    Case("readFrom",                                    test_readFromInReverse<0x55, ((BUFFER_SIZE / 2) - 1)>),
 | 
			
		||||
    Case("readFrom",                                    test_readFromInReverse<0x55, BUFFER_SIZE>),
 | 
			
		||||
    Case("readFrom followed by sequential reads",       test_readFromFollowedByReads<0x55, 255>),
 | 
			
		||||
    Case("readFrom followed by sequential reads",       test_readFromFollowedByReads<0x55, 511>),
 | 
			
		||||
    Case("readFrom followed by sequential reads",       test_readFromFollowedByReads<0x55, 512>),
 | 
			
		||||
    Case("readFrom followed by sequential reads",       test_readFromFollowedByReads<0x55, 513>),
 | 
			
		||||
    Case("readFrom followed by sequential reads",       test_readFromFollowedByReads<0x55, 1024>),
 | 
			
		||||
 | 
			
		||||
    /* log odd-sized blocks which wouldn't align with program_unit at the tail */
 | 
			
		||||
    Case("initialize3",                                 test_initialize),
 | 
			
		||||
    Case("log odd-sized chunk",                         test_logSeveralOddSizedChunks<1, 1>),
 | 
			
		||||
| 
						 | 
				
			
			@ -876,6 +1144,7 @@ Case cases[] = {
 | 
			
		|||
    Case("failed small write followed by padded write", test_failedSmallWriteFollowedByPaddedWrite),
 | 
			
		||||
 | 
			
		||||
    Case("reset and initialize6",                       test_resetAndInitialize),
 | 
			
		||||
    Case("crc32",                                       test_crc32),
 | 
			
		||||
    // Case("uninitialize", test_uninitialize),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -56,9 +56,8 @@
 | 
			
		|||
#define CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// todo: fixup for storage driver using more than the STORAGE_xxx namespace:
 | 
			
		||||
#if defined DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS
 | 
			
		||||
#define CFSTORE_STORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS
 | 
			
		||||
#if defined STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS
 | 
			
		||||
#define CFSTORE_STORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,6 +27,7 @@
 | 
			
		|||
        printf(_fmt, __VA_ARGS__);                      \
 | 
			
		||||
  }while(0);
 | 
			
		||||
 | 
			
		||||
//todo: restore #define noCFSTORE_DEBUG
 | 
			
		||||
#define noCFSTORE_DEBUG
 | 
			
		||||
//#define CFSTORE_DEBUG
 | 
			
		||||
#ifdef CFSTORE_DEBUG
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,76 @@
 | 
			
		|||
/*
 | 
			
		||||
 * mbed Microcontroller Library
 | 
			
		||||
 * Copyright (c) 2006-2016 ARM Limited
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <Driver_Common.h>
 | 
			
		||||
#include "storage_volume_manager.h"
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "cfstore_svm.h"
 | 
			
		||||
 | 
			
		||||
/** @file   cfstore_svm.cpp
 | 
			
		||||
 *
 | 
			
		||||
 * This module is provides a C wrapper to the C++ storage-volume-manager.h API,
 | 
			
		||||
 * so it can be called by the C-HAL implementation configuration_store.c
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_SVM_VOL_01_START_OFFSET       0x80000UL
 | 
			
		||||
#define CFSTORE_SVM_VOL_01_SIZE               0x80000UL
 | 
			
		||||
 | 
			
		||||
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_MTD_K64F;
 | 
			
		||||
static ARM_DRIVER_STORAGE *cfstore_svm_storage_drv = &ARM_Driver_Storage_MTD_K64F;
 | 
			
		||||
 | 
			
		||||
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
 | 
			
		||||
 | 
			
		||||
/* the storage volume manager instance used to generate virtual mtd descriptors */
 | 
			
		||||
static StorageVolumeManager volumeManager;
 | 
			
		||||
 | 
			
		||||
/* used only for the initialization of the volume-manager. */
 | 
			
		||||
static void cfstore_svm_volume_manager_initialize_callback(int32_t status)
 | 
			
		||||
{
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s: operation %d with status %d" , __func__, (int) operation, (int) status);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cfstore_svm_journal_mtc_callback(int32_t status, ARM_STORAGE_OPERATION operation)
 | 
			
		||||
{
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s: operation %d with status %d" , __func__, (int) operation, (int) status);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t cfstore_svm_init(struct _ARM_DRIVER_STORAGE *storage_mtd)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_OK;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    ret = volumeManager.initialize(cfstore_svm_storage_drv, cfstore_svm_volume_manager_initialize_callback);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK) {
 | 
			
		||||
        CFSTORE_ERRLOG("%s:debug: volume-manager::initialize() failed for storage_mtd=%p (ret=%d)", __func__, storage_mtd, (int) ret);
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    ret = volumeManager.addVolume_C(CFSTORE_SVM_VOL_01_START_OFFSET, CFSTORE_SVM_VOL_01_SIZE, storage_mtd);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK) {
 | 
			
		||||
        CFSTORE_ERRLOG("%s:debug: volume-manager::addVolume_C() failed for storage_mtd=%p (ret=%d)", __func__, storage_mtd, (int) ret);
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    ret = storage_mtd->Initialize(cfstore_svm_journal_mtc_callback);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK) {
 | 
			
		||||
        CFSTORE_ERRLOG("%s:debug: storage_mtd->initialize() failed for storage_mtd=%p (ret=%d)", __func__, storage_mtd, (int) ret);
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,41 @@
 | 
			
		|||
/*
 | 
			
		||||
 * mbed Microcontroller Library
 | 
			
		||||
 * Copyright (c) 2006-2016 ARM Limited
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/** @file  cfstore_svm.h
 | 
			
		||||
 *
 | 
			
		||||
 * This is the interface file to configuration store storage volume manager.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __CFSTORE_SVM_H_
 | 
			
		||||
#define __CFSTORE_SVM_H_
 | 
			
		||||
 | 
			
		||||
#include <Driver_Storage.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int32_t cfstore_svm_init(struct _ARM_DRIVER_STORAGE *mtd);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /*__CFSTORE_SVM_H_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -257,8 +257,8 @@ int32_t cfstore_test_startup(void)
 | 
			
		|||
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
 | 
			
		||||
    static FlashJournal_t jrnl;
 | 
			
		||||
    extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0);
 | 
			
		||||
    const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_(0);
 | 
			
		||||
    extern ARM_DRIVER_STORAGE ARM_Driver_Storage_MTD_K64F;
 | 
			
		||||
    const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_MTD_K64F;
 | 
			
		||||
 | 
			
		||||
    ret = FlashJournal_initialize(&jrnl, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, NULL);
 | 
			
		||||
    if(ret < JOURNAL_STATUS_OK){
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,6 +31,7 @@
 | 
			
		|||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
#include "cfstore_svm.h"
 | 
			
		||||
#include "flash_journal_strategy_sequential.h"
 | 
			
		||||
#include "flash_journal.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -45,8 +46,10 @@
 | 
			
		|||
 | 
			
		||||
#ifdef CFSTORE_DEBUG
 | 
			
		||||
uint32_t cfstore_optDebug_g = 1;
 | 
			
		||||
uint32_t cfstore_optLogLevel_g = CFSTORE_LOG_NONE; /*CFSTORE_LOG_NONE|CFSTORE_LOG_ERR|CFSTORE_LOG_DEBUG|CFSTORE_LOG_FENTRY */
 | 
			
		||||
uint32_t cfstore_optLogTracepoint_g = CFSTORE_TP_NONE; /*CFSTORE_TP_NONE|CFSTORE_TP_CLOSE|CFSTORE_TP_CREATE|CFSTORE_TP_DELETE|CFSTORE_TP_FILE|CFSTORE_TP_FIND|CFSTORE_TP_FLUSH|CFSTORE_TP_INIT|CFSTORE_TP_OPEN|CFSTORE_TP_READ|CFSTORE_TP_WRITE|CFSTORE_TP_VERBOSE1|CFSTORE_TP_VERBOSE2|CFSTORE_TP_VERBOSE3|CFSTORE_TP_FENTRY; */
 | 
			
		||||
//todo: restore uint32_t cfstore_optLogLevel_g = CFSTORE_LOG_NONE; /*CFSTORE_LOG_NONE|CFSTORE_LOG_ERR|CFSTORE_LOG_DEBUG|CFSTORE_LOG_FENTRY */
 | 
			
		||||
//uint32_t cfstore_optLogTracepoint_g = CFSTORE_TP_NONE; /*CFSTORE_TP_NONE|CFSTORE_TP_CLOSE|CFSTORE_TP_CREATE|CFSTORE_TP_DELETE|CFSTORE_TP_FILE|CFSTORE_TP_FIND|CFSTORE_TP_FLUSH|CFSTORE_TP_INIT|CFSTORE_TP_OPEN|CFSTORE_TP_READ|CFSTORE_TP_WRITE|CFSTORE_TP_VERBOSE1|CFSTORE_TP_VERBOSE2|CFSTORE_TP_VERBOSE3|CFSTORE_TP_FENTRY; */
 | 
			
		||||
uint32_t cfstore_optLogLevel_g = CFSTORE_LOG_NONE|CFSTORE_LOG_ERR|CFSTORE_LOG_DEBUG|CFSTORE_LOG_FENTRY;
 | 
			
		||||
uint32_t cfstore_optLogTracepoint_g = CFSTORE_TP_NONE|CFSTORE_TP_CLOSE|CFSTORE_TP_CREATE|CFSTORE_TP_DELETE|CFSTORE_TP_FILE|CFSTORE_TP_FIND|CFSTORE_TP_FLUSH|CFSTORE_TP_INIT|CFSTORE_TP_OPEN|CFSTORE_TP_READ|CFSTORE_TP_WRITE|CFSTORE_TP_VERBOSE1|CFSTORE_TP_VERBOSE2|CFSTORE_TP_VERBOSE3|CFSTORE_TP_FENTRY;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -54,10 +57,12 @@ uint32_t cfstore_optLogTracepoint_g = CFSTORE_TP_NONE; /*CFSTORE_TP_NONE|CFSTORE
 | 
			
		|||
 * Externs
 | 
			
		||||
 */
 | 
			
		||||
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0);
 | 
			
		||||
ARM_DRIVER_STORAGE *cfstore_storage_drv = &ARM_Driver_Storage_(0);
 | 
			
		||||
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_MTD_K64F;
 | 
			
		||||
ARM_DRIVER_STORAGE *cfstore_storage_drv = &ARM_Driver_Storage_MTD_K64F;
 | 
			
		||||
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
 | 
			
		||||
 | 
			
		||||
struct _ARM_DRIVER_STORAGE cfstore_journal_mtd;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Defines
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -69,7 +74,10 @@ ARM_DRIVER_STORAGE *cfstore_storage_drv = &ARM_Driver_Storage_(0);
 | 
			
		|||
 *  valid sizes of areas should always be greater than the size of the header, and therefore
 | 
			
		||||
 *  greater than this value, which is defined as smaller than the header size
 | 
			
		||||
 *
 | 
			
		||||
 *  ARM_DRIVER_OK_DONE
 | 
			
		||||
 * CFSTORE_FLASH_NUMSLOTS
 | 
			
		||||
 *  number of flash journal slots
 | 
			
		||||
 *
 | 
			
		||||
 * ARM_DRIVER_OK_DONE
 | 
			
		||||
 *   value that indicates an operation has been done i.e. a value > 0
 | 
			
		||||
 */
 | 
			
		||||
#define CFSTORE_KEY_NAME_CHARS_ACCEPTABLE           "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}.-_@"
 | 
			
		||||
| 
						 | 
				
			
			@ -79,6 +87,7 @@ ARM_DRIVER_STORAGE *cfstore_storage_drv = &ARM_Driver_Storage_(0);
 | 
			
		|||
#define CFSTORE_FILE_CREATE_MODE_DEFAULT            (ARM_CFSTORE_FMODE)0
 | 
			
		||||
#define CFSTORE_FLASH_STACK_BUF_SIZE 	            64
 | 
			
		||||
#define CFSTORE_FLASH_AREA_SIZE_MIN                 (sizeof(cfstore_area_header_t) - 1)
 | 
			
		||||
#define CFSTORE_FLASH_NUMSLOTS                      4
 | 
			
		||||
#define cfstore_fsm_null                            NULL
 | 
			
		||||
#define CFSTORE_SENTINEL                            0x7fffffff
 | 
			
		||||
#define CFSTORE_CALLBACK_RET_CODE_DEFAULT           0x1
 | 
			
		||||
| 
						 | 
				
			
			@ -169,6 +178,7 @@ typedef enum cfstore_fsm_state_t {
 | 
			
		|||
    cfstore_fsm_state_committing,
 | 
			
		||||
    cfstore_fsm_state_resetting,
 | 
			
		||||
    cfstore_fsm_state_ready,        /* ready for next flash journal command to arise */
 | 
			
		||||
    cfstore_fsm_state_formatting,   /* flash formatting in progress */
 | 
			
		||||
    cfstore_fsm_state_max
 | 
			
		||||
} cfstore_fsm_state_t;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -180,6 +190,7 @@ typedef enum cfstore_fsm_event_t {
 | 
			
		|||
    cfstore_fsm_event_commit_req,
 | 
			
		||||
    cfstore_fsm_event_commit_done,
 | 
			
		||||
    cfstore_fsm_event_reset_done,
 | 
			
		||||
    cfstore_fsm_event_format_done,
 | 
			
		||||
    cfstore_fsm_event_max,
 | 
			
		||||
} cfstore_fsm_event_t;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -198,6 +209,7 @@ typedef struct cfstore_fsm_t
 | 
			
		|||
/* strings used for debug trace */
 | 
			
		||||
static const char* cfstore_flash_opcode_str[] =
 | 
			
		||||
{
 | 
			
		||||
    "FLASH_JOURNAL_OPCODE_FORMAT",
 | 
			
		||||
    "FLASH_JOURNAL_OPCODE_INITIALIZE",
 | 
			
		||||
    "FLASH_JOURNAL_OPCODE_GET_INFO",
 | 
			
		||||
    "FLASH_JOURNAL_OPCODE_READ_BLOB",
 | 
			
		||||
| 
						 | 
				
			
			@ -215,6 +227,7 @@ static const char* cfstore_flash_state_str[] =
 | 
			
		|||
    "committing",
 | 
			
		||||
    "resetting",
 | 
			
		||||
    "ready",
 | 
			
		||||
    "formatting",
 | 
			
		||||
    "unknown"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -226,6 +239,7 @@ static const char* cfstore_flash_event_str[] =
 | 
			
		|||
    "commit_req",
 | 
			
		||||
    "commit_done",
 | 
			
		||||
    "reset_done",
 | 
			
		||||
    "format_done",
 | 
			
		||||
    "unknown"
 | 
			
		||||
};
 | 
			
		||||
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
 | 
			
		||||
| 
						 | 
				
			
			@ -727,7 +741,6 @@ void *cfstore_realloc(void *ptr, ARM_CFSTORE_SIZE size)
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
#ifdef CFSTORE_TARGET_LIKE_X86_LINUX_NATIVE
 | 
			
		||||
static inline void cfstore_critical_section_init(CFSTORE_LOCK* lock){ *lock = 0; }
 | 
			
		||||
static inline void cfstore_critical_section_lock(CFSTORE_LOCK* lock, const char* tag){ (void) tag; __sync_fetch_and_add(lock, 1); }
 | 
			
		||||
static inline void cfstore_critical_section_unlock(CFSTORE_LOCK* lock, const char* tag){(void) tag;  __sync_fetch_and_sub(lock, 1); }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -764,7 +777,6 @@ static CFSTORE_INLINE int32_t cfstore_hkvt_refcount_inc(cfstore_area_hkvt_t* hkv
 | 
			
		|||
 * Platform Specific Function Implementations
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static inline void cfstore_critical_section_init(CFSTORE_LOCK* lock){ *lock = 0; }
 | 
			
		||||
static inline void cfstore_critical_section_unlock(CFSTORE_LOCK* lock, const char* tag)
 | 
			
		||||
{
 | 
			
		||||
    (void) lock;
 | 
			
		||||
| 
						 | 
				
			
			@ -1540,6 +1552,9 @@ static void cfstore_flash_journal_callback(int32_t status, FlashJournal_OpCode_t
 | 
			
		|||
    CFSTORE_FENTRYLOG("%s:entered: status=%d, cmd_code=%d (%s)\n", __func__, (int) status, (int) cmd_code, cfstore_flash_opcode_str[cmd_code]);
 | 
			
		||||
    switch(cmd_code)
 | 
			
		||||
    {
 | 
			
		||||
    case FLASH_JOURNAL_OPCODE_FORMAT:
 | 
			
		||||
        ctx->fsm.event = cfstore_fsm_event_format_done;
 | 
			
		||||
        break;
 | 
			
		||||
    case FLASH_JOURNAL_OPCODE_INITIALIZE:
 | 
			
		||||
        ctx->fsm.event = cfstore_fsm_event_init_done;
 | 
			
		||||
        break;
 | 
			
		||||
| 
						 | 
				
			
			@ -1595,14 +1610,30 @@ static int32_t cfstore_fsm_stop_on_entry(void* context)
 | 
			
		|||
static int32_t cfstore_fsm_init_on_entry(void* context)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_(0);
 | 
			
		||||
    cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
 | 
			
		||||
    ret = FlashJournal_initialize(&ctx->jrnl, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, cfstore_flash_journal_callback);
 | 
			
		||||
    ret = cfstore_svm_init(&cfstore_journal_mtd);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_DBGLOG("%s:Error: Unable to initialize storage volume manager\n", __func__);
 | 
			
		||||
        cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_formatting, ctx);
 | 
			
		||||
        return ARM_DRIVER_OK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = FlashJournal_initialize(&ctx->jrnl, (ARM_DRIVER_STORAGE *) &cfstore_journal_mtd, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, cfstore_flash_journal_callback);
 | 
			
		||||
    CFSTORE_TP(CFSTORE_TP_FSM, "%s:FlashJournal_initialize ret=%d\n", __func__, (int) ret);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        if(ret == JOURNAL_STATUS_NOT_FORMATTED) {
 | 
			
		||||
            CFSTORE_DBGLOG("%s:Error: flash not formatted\n", __func__);
 | 
			
		||||
            cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_formatting, ctx);
 | 
			
		||||
            return ARM_DRIVER_OK;
 | 
			
		||||
        }
 | 
			
		||||
        if(ret == JOURNAL_STATUS_METADATA_ERROR) {
 | 
			
		||||
            CFSTORE_ERRLOG("%s:Error: flash meta-data (CRC) error detected when initializing flash. Reformatting flash.\n", __func__);
 | 
			
		||||
            cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_formatting, ctx);
 | 
			
		||||
            return ARM_DRIVER_OK;
 | 
			
		||||
        }
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: failed to initialize flash journaling layer (ret=%d)\n", __func__, (int) ret);
 | 
			
		||||
        cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_stopped, ctx);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1993,18 +2024,64 @@ static int32_t cfstore_fsm_ready_on_commit_req(void* context)
 | 
			
		|||
/* int32_t cfstore_fsm_ready_on_exit(void* context){ (void) context;} */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @brief  fsm handler when entering the formatting state
 | 
			
		||||
 */
 | 
			
		||||
static int32_t cfstore_fsm_format_on_entry(void* context)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
 | 
			
		||||
    ret = flashJournalStrategySequential_format((ARM_DRIVER_STORAGE *) &cfstore_journal_mtd, CFSTORE_FLASH_NUMSLOTS, cfstore_flash_journal_callback);
 | 
			
		||||
    CFSTORE_TP(CFSTORE_TP_FSM, "%s:flashJournalStrategySequential_format ret=%d\n", __func__, (int) ret);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: failed to format flash (ret=%d)\n", __func__, (int) ret);
 | 
			
		||||
        cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_stopped, ctx);
 | 
			
		||||
    }
 | 
			
		||||
    else if(ret > 0){
 | 
			
		||||
        /* operation completed synchronously*/
 | 
			
		||||
        cfstore_flash_journal_callback(ret, FLASH_JOURNAL_OPCODE_FORMAT);
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @brief  fsm handler when in formatting state
 | 
			
		||||
 */
 | 
			
		||||
int32_t cfstore_fsm_formatting(void* context)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_OK;
 | 
			
		||||
    cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    CFSTORE_ASSERT(ctx->fsm.state == cfstore_fsm_state_formatting);
 | 
			
		||||
    CFSTORE_ASSERT(ctx->cmd_code == FLASH_JOURNAL_OPCODE_FORMAT);
 | 
			
		||||
 | 
			
		||||
    /* only change state if status > 0*/
 | 
			
		||||
    if(ctx->status > 0){
 | 
			
		||||
        ret = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_initing, ctx);
 | 
			
		||||
    } else if(ctx->status < 0) {
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: failed to format flash (ret=%d)\n", __func__, (int) ctx->status);
 | 
			
		||||
        cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_stopped, ctx);
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* int32_t cfstore_fsm_format_on_exit(void* context){ (void) context;} */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* handler functions while in state */
 | 
			
		||||
static cfstore_fsm_handler cfstore_flash_fsm[cfstore_fsm_state_max][cfstore_fsm_event_max] =
 | 
			
		||||
{
 | 
			
		||||
/* state\event:   init_done               read_done             log_done              commit_req                            commit_done               reset_done */
 | 
			
		||||
/* stopped    */  {cfstore_fsm_null,      cfstore_fsm_null,     cfstore_fsm_null,     cfstore_fsm_null,                     cfstore_fsm_null,         cfstore_fsm_null          },
 | 
			
		||||
/* init       */  {cfstore_fsm_initing,   cfstore_fsm_null,     cfstore_fsm_null,     cfstore_fsm_null,                     cfstore_fsm_null,         cfstore_fsm_null          },
 | 
			
		||||
/* reading    */  {cfstore_fsm_null,      cfstore_fsm_reading,  cfstore_fsm_null,     cfstore_fsm_null,                     cfstore_fsm_null,         cfstore_fsm_null          },
 | 
			
		||||
/* logging    */  {cfstore_fsm_null,      cfstore_fsm_null,     cfstore_fsm_logging,  cfstore_fsm_null,                     cfstore_fsm_null,         cfstore_fsm_null          },
 | 
			
		||||
/* committing */  {cfstore_fsm_null,      cfstore_fsm_null,     cfstore_fsm_null,     cfstore_fsm_null,                     cfstore_fsm_committing,   cfstore_fsm_null          },
 | 
			
		||||
/* resetting  */  {cfstore_fsm_null,      cfstore_fsm_null,     cfstore_fsm_null,     cfstore_fsm_null,                     cfstore_fsm_null,         cfstore_fsm_null          },
 | 
			
		||||
/* ready      */  {cfstore_fsm_null,      cfstore_fsm_null,     cfstore_fsm_null,     cfstore_fsm_ready_on_commit_req,      cfstore_fsm_null,         cfstore_fsm_null          },
 | 
			
		||||
/* state\event:   init_done               read_done             log_done              commit_req                            commit_done               reset_done                format_done, */
 | 
			
		||||
/* stopped    */  {cfstore_fsm_null,      cfstore_fsm_null,     cfstore_fsm_null,     cfstore_fsm_null,                     cfstore_fsm_null,         cfstore_fsm_null,     cfstore_fsm_null        },
 | 
			
		||||
/* init       */  {cfstore_fsm_initing,   cfstore_fsm_null,     cfstore_fsm_null,     cfstore_fsm_null,                     cfstore_fsm_null,         cfstore_fsm_null,     cfstore_fsm_null        },
 | 
			
		||||
/* reading    */  {cfstore_fsm_null,      cfstore_fsm_reading,  cfstore_fsm_null,     cfstore_fsm_null,                     cfstore_fsm_null,         cfstore_fsm_null,     cfstore_fsm_null        },
 | 
			
		||||
/* logging    */  {cfstore_fsm_null,      cfstore_fsm_null,     cfstore_fsm_logging,  cfstore_fsm_null,                     cfstore_fsm_null,         cfstore_fsm_null,     cfstore_fsm_null        },
 | 
			
		||||
/* committing */  {cfstore_fsm_null,      cfstore_fsm_null,     cfstore_fsm_null,     cfstore_fsm_null,                     cfstore_fsm_committing,   cfstore_fsm_null,     cfstore_fsm_null        },
 | 
			
		||||
/* resetting  */  {cfstore_fsm_null,      cfstore_fsm_null,     cfstore_fsm_null,     cfstore_fsm_null,                     cfstore_fsm_null,         cfstore_fsm_null,     cfstore_fsm_null        },
 | 
			
		||||
/* ready      */  {cfstore_fsm_null,      cfstore_fsm_null,     cfstore_fsm_null,     cfstore_fsm_ready_on_commit_req,      cfstore_fsm_null,         cfstore_fsm_null,     cfstore_fsm_null        },
 | 
			
		||||
/* formatting */  {cfstore_fsm_null,      cfstore_fsm_null,     cfstore_fsm_null,     cfstore_fsm_null,                     cfstore_fsm_null,         cfstore_fsm_null,     cfstore_fsm_formatting  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* handler functions for entering the state*/
 | 
			
		||||
| 
						 | 
				
			
			@ -2016,7 +2093,8 @@ cfstore_fsm_handler cfstore_fsm_on_entry[cfstore_fsm_state_max] =
 | 
			
		|||
    cfstore_fsm_log_on_entry,
 | 
			
		||||
    cfstore_fsm_commit_on_entry,
 | 
			
		||||
    cfstore_fsm_null,               /* cfstore_fsm_reset_on_entry */
 | 
			
		||||
    cfstore_fsm_null                /* cfstore_fsm_ready_on_entry */
 | 
			
		||||
    cfstore_fsm_null,               /* cfstore_fsm_ready_on_entry */
 | 
			
		||||
    cfstore_fsm_format_on_entry     /* cfstore_fsm_format_on_entry */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* handler functions for exiting state, currently none used */
 | 
			
		||||
| 
						 | 
				
			
			@ -2028,7 +2106,8 @@ cfstore_fsm_handler cfstore_fsm_on_exit[cfstore_fsm_state_max] =
 | 
			
		|||
    cfstore_fsm_log_on_exit,
 | 
			
		||||
    cfstore_fsm_commit_on_exit,
 | 
			
		||||
    cfstore_fsm_null,             /* cfstore_fsm_reset_on_exit */
 | 
			
		||||
    cfstore_fsm_null              /* cfstore_fsm_ready_on_exit */
 | 
			
		||||
    cfstore_fsm_null,             /* cfstore_fsm_ready_on_exit */
 | 
			
		||||
    cfstore_fsm_null              /* cfstore_fsm_format_on_exit */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2425,8 +2504,8 @@ static bool cfstore_file_is_empty(ARM_CFSTORE_HANDLE hkey)
 | 
			
		|||
/* @brief  See definition in configuration_store.h for description. */
 | 
			
		||||
ARM_CFSTORE_CAPABILITIES cfstore_get_capabilities(void)
 | 
			
		||||
{
 | 
			
		||||
    /* getting capabilities doesnt change the sram area so this can happen independently of
 | 
			
		||||
     * an oustanding async operation. its unnecessary to check the fsm state */
 | 
			
		||||
    /* getting capabilities doesn't change the sram area so this can happen independently of
 | 
			
		||||
     * an outstanding async operation. its unnecessary to check the fsm state */
 | 
			
		||||
    return cfstore_caps_g;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3866,9 +3945,7 @@ static int32_t cfstore_initialise(ARM_CFSTORE_CALLBACK callback, void* client_co
 | 
			
		|||
        ctx->init_ref_count++;
 | 
			
		||||
        /* initially there is no memory allocated for the area */
 | 
			
		||||
        CFSTORE_INIT_LIST_HEAD(&ctx->file_list);
 | 
			
		||||
        /* This is not required here are the lock is statically initialised to 0
 | 
			
		||||
         *  cfstore_critical_section_init(&ctx->rw_area0_lock);
 | 
			
		||||
         */
 | 
			
		||||
        /* ctx->rw_area0_lock initialisation is not required here as the lock is statically initialised to 0 */
 | 
			
		||||
        ctx->area_0_head = NULL;
 | 
			
		||||
        ctx->area_0_tail = NULL;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,25 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2006-2016, ARM Limited, All Rights Reserved
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
			
		||||
 * not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __FLASH_JOURNAL_CONFIG_H__
 | 
			
		||||
#define __FLASH_JOURNAL_CONFIG_H__
 | 
			
		||||
 | 
			
		||||
#ifndef SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS
 | 
			
		||||
#define SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS 4
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __FLASH_JOURNAL_CONFIG_H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,220 @@
 | 
			
		|||
/**********************************************************************
 | 
			
		||||
 *
 | 
			
		||||
 * Filename:    flash_journal_crc.c
 | 
			
		||||
 *
 | 
			
		||||
 * Description: Slow and fast implementations of the CRC standards.
 | 
			
		||||
 *
 | 
			
		||||
 * Notes:       The parameters for each supported CRC standard are
 | 
			
		||||
 *              defined in the header file crc.h.  The implementations
 | 
			
		||||
 *              here should stand up to further additions to that list.
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2000 by Michael Barr.  This software is placed into
 | 
			
		||||
 * the public domain and may be used for any purpose.  However, this
 | 
			
		||||
 * notice must not be changed or removed and no warranty is either
 | 
			
		||||
 * expressed or implied by its publication or distribution.
 | 
			
		||||
 **********************************************************************/
 | 
			
		||||
 | 
			
		||||
#include "flash-journal-strategy-sequential/flash_journal_crc.h"
 | 
			
		||||
 | 
			
		||||
#define FALSE   0
 | 
			
		||||
#define TRUE    !FALSE
 | 
			
		||||
 | 
			
		||||
#define CRC_NAME            "CRC-32"
 | 
			
		||||
#define POLYNOMIAL          0x04C11DB7
 | 
			
		||||
#define INITIAL_REMAINDER   0xFFFFFFFF
 | 
			
		||||
#define FINAL_XOR_VALUE     0xFFFFFFFF
 | 
			
		||||
#define REFLECT_DATA        TRUE
 | 
			
		||||
#define REFLECT_REMAINDER   TRUE
 | 
			
		||||
#define CHECK_VALUE         0xCBF43926
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Derive parameters from the standard-specific parameters in crc.h.
 | 
			
		||||
 */
 | 
			
		||||
#define WIDTH    (8 * sizeof(flash_journal_crc32_t))
 | 
			
		||||
/* U postfix required to suppress the following warning with TOOLCHAIN_ARM:
 | 
			
		||||
 * #61-D: integer operation result is out of range
 | 
			
		||||
 */
 | 
			
		||||
#define TOPBIT   0x80000000U
 | 
			
		||||
 | 
			
		||||
#if (REFLECT_DATA == TRUE)
 | 
			
		||||
#undef  REFLECT_DATA
 | 
			
		||||
#define REFLECT_DATA(X)         ((unsigned char) reflect((X), 8))
 | 
			
		||||
#else
 | 
			
		||||
#undef  REFLECT_DATA
 | 
			
		||||
#define REFLECT_DATA(X)         (X)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if (REFLECT_REMAINDER == TRUE)
 | 
			
		||||
#undef  REFLECT_REMAINDER
 | 
			
		||||
#define REFLECT_REMAINDER(X)    ((flash_journal_crc32_t) reflect((X), WIDTH))
 | 
			
		||||
#else
 | 
			
		||||
#undef  REFLECT_REMAINDER
 | 
			
		||||
#define REFLECT_REMAINDER(X)    (X)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*********************************************************************
 | 
			
		||||
 *
 | 
			
		||||
 * Function:    reflect()
 | 
			
		||||
 *
 | 
			
		||||
 * Description: Reorder the bits of a binary sequence, by reflecting
 | 
			
		||||
 *              them about the middle position.
 | 
			
		||||
 *
 | 
			
		||||
 * Notes:       No checking is done that nBits <= 32.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns:     The reflection of the original data.
 | 
			
		||||
 *
 | 
			
		||||
 *********************************************************************/
 | 
			
		||||
static uint32_t
 | 
			
		||||
reflect(uint32_t data, unsigned char nBits)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t  reflection = 0x00000000;
 | 
			
		||||
    unsigned char  bit;
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Reflect the data about the center bit.
 | 
			
		||||
     */
 | 
			
		||||
    for (bit = 0; bit < nBits; ++bit)
 | 
			
		||||
    {
 | 
			
		||||
        /*
 | 
			
		||||
         * If the LSB bit is set, set the reflection of it.
 | 
			
		||||
         */
 | 
			
		||||
        if (data & 0x01)
 | 
			
		||||
        {
 | 
			
		||||
            reflection |= (1 << ((nBits - 1) - bit));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        data = (data >> 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (reflection);
 | 
			
		||||
 | 
			
		||||
}   /* reflect() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static flash_journal_crc32_t  crcTable[256];
 | 
			
		||||
static flash_journal_crc32_t  crcEngineRemainder = INITIAL_REMAINDER;
 | 
			
		||||
 | 
			
		||||
/*********************************************************************
 | 
			
		||||
 *
 | 
			
		||||
 * Function:    flashJournalCrcInit()
 | 
			
		||||
 *
 | 
			
		||||
 * Description: Populate the partial CRC lookup table.
 | 
			
		||||
 *
 | 
			
		||||
 * Notes:       This function must be rerun any time the CRC standard
 | 
			
		||||
 *              is changed.  If desired, it can be run "offline" and
 | 
			
		||||
 *              the table results stored in an embedded system's ROM.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns:     None defined.
 | 
			
		||||
 *
 | 
			
		||||
 *********************************************************************/
 | 
			
		||||
void
 | 
			
		||||
flashJournalCrcInit(void)
 | 
			
		||||
{
 | 
			
		||||
    flash_journal_crc32_t            remainder;
 | 
			
		||||
    int            dividend;
 | 
			
		||||
    unsigned char  bit;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Compute the remainder of each possible dividend.
 | 
			
		||||
     */
 | 
			
		||||
    for (dividend = 0; dividend < 256; ++dividend)
 | 
			
		||||
    {
 | 
			
		||||
        /*
 | 
			
		||||
         * Start with the dividend followed by zeros.
 | 
			
		||||
         */
 | 
			
		||||
        remainder = dividend << (WIDTH - 8);
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
         * Perform modulo-2 division, a bit at a time.
 | 
			
		||||
         */
 | 
			
		||||
        for (bit = 8; bit > 0; --bit)
 | 
			
		||||
        {
 | 
			
		||||
            /*
 | 
			
		||||
             * Try to divide the current data bit.
 | 
			
		||||
             */
 | 
			
		||||
            if (remainder & TOPBIT)
 | 
			
		||||
            {
 | 
			
		||||
                remainder = (remainder << 1) ^ POLYNOMIAL;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                remainder = (remainder << 1);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
         * Store the result into the table.
 | 
			
		||||
         */
 | 
			
		||||
        crcTable[dividend] = remainder;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}   /* flashJournalCrcInit() */
 | 
			
		||||
 | 
			
		||||
/*********************************************************************
 | 
			
		||||
 *
 | 
			
		||||
 * Function:    flashJournalCrcReset()
 | 
			
		||||
 *
 | 
			
		||||
 * Description: Resets internal state before calling crcCummulative().
 | 
			
		||||
 *
 | 
			
		||||
 * Notes: See the notes to crcCummulative().
 | 
			
		||||
 *
 | 
			
		||||
 * Returns:     None defined.
 | 
			
		||||
 *
 | 
			
		||||
 *********************************************************************/
 | 
			
		||||
void
 | 
			
		||||
flashJournalCrcReset(void)
 | 
			
		||||
{
 | 
			
		||||
    static unsigned initCalled = 0;
 | 
			
		||||
    if (!initCalled) {
 | 
			
		||||
        flashJournalCrcInit();
 | 
			
		||||
        initCalled = 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    crcEngineRemainder = INITIAL_REMAINDER;
 | 
			
		||||
 | 
			
		||||
}   /* flashJournalCrcReset() */
 | 
			
		||||
 | 
			
		||||
/*********************************************************************
 | 
			
		||||
 *
 | 
			
		||||
 * Function:    crcCummulative()
 | 
			
		||||
 *
 | 
			
		||||
 * Description: Compute the CRC of a group of messages.
 | 
			
		||||
 *
 | 
			
		||||
 * Notes:
 | 
			
		||||
 * This function is intended to be used in the following way:
 | 
			
		||||
 *  - crcReset() is called first to reset internal state before the first
 | 
			
		||||
 *    fragment of a new message is processed with crcCummulative().
 | 
			
		||||
 *  - crcCummulative() called successfully appending additional message
 | 
			
		||||
 *    fragments to those previously supplied (in order), and returning
 | 
			
		||||
 *    the current crc for the message payload so far.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns:     The CRC of the message.
 | 
			
		||||
 *
 | 
			
		||||
 *********************************************************************/
 | 
			
		||||
flash_journal_crc32_t
 | 
			
		||||
flashJournalCrcCummulative(unsigned char const message[], int nBytes)
 | 
			
		||||
{
 | 
			
		||||
    unsigned char  data;
 | 
			
		||||
    int            byte;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Divide the message by the polynomial, a byte at a time.
 | 
			
		||||
     */
 | 
			
		||||
    for (byte = 0; byte < nBytes; ++byte)
 | 
			
		||||
    {
 | 
			
		||||
        data = REFLECT_DATA(message[byte]) ^ (crcEngineRemainder >> (WIDTH - 8));
 | 
			
		||||
        crcEngineRemainder = crcTable[data] ^ (crcEngineRemainder << 8);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * The final remainder is the CRC.
 | 
			
		||||
     */
 | 
			
		||||
    return (REFLECT_REMAINDER(crcEngineRemainder) ^ FINAL_XOR_VALUE);
 | 
			
		||||
 | 
			
		||||
}   /* crcCummulative() */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
/**********************************************************************
 | 
			
		||||
 *
 | 
			
		||||
 * Filename:    flash_journal_crc.h.h
 | 
			
		||||
 *
 | 
			
		||||
 * Description: A header file describing the various CRC standards.
 | 
			
		||||
 *
 | 
			
		||||
 * Notes:
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2000 by Michael Barr.  This software is placed into
 | 
			
		||||
 * the public domain and may be used for any purpose.  However, this
 | 
			
		||||
 * notice must not be changed or removed and no warranty is either
 | 
			
		||||
 * expressed or implied by its publication or distribution.
 | 
			
		||||
 **********************************************************************/
 | 
			
		||||
 | 
			
		||||
#ifndef _flash_journal_crc_h
 | 
			
		||||
#define _flash_journal_crc_h
 | 
			
		||||
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef uint32_t  flash_journal_crc32_t;
 | 
			
		||||
 | 
			
		||||
void flashJournalCrcReset(void);
 | 
			
		||||
flash_journal_crc32_t flashJournalCrcCummulative(unsigned char const message[], int nBytes);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* _flash_journal_crc_h */
 | 
			
		||||
| 
						 | 
				
			
			@ -23,11 +23,22 @@ extern "C" {
 | 
			
		|||
#endif // __cplusplus
 | 
			
		||||
 | 
			
		||||
#include "flash-journal/flash_journal.h"
 | 
			
		||||
#include "flash-journal-strategy-sequential/config.h"
 | 
			
		||||
 | 
			
		||||
static inline uint32_t roundUp_uint32(uint32_t N, uint32_t BOUNDARY) {
 | 
			
		||||
    return ((((N) + (BOUNDARY) - 1) / (BOUNDARY)) * (BOUNDARY));
 | 
			
		||||
}
 | 
			
		||||
static inline uint32_t roundDown_uint32(uint32_t N, uint32_t BOUNDARY) {
 | 
			
		||||
    return (((N) / (BOUNDARY)) * (BOUNDARY));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define LCM_OF_ALL_ERASE_UNITS 4096 /* Assume an LCM of erase_units for now. This will be generalized later. */
 | 
			
		||||
 | 
			
		||||
static const uint32_t SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER = 0xFFFFFFFFUL;
 | 
			
		||||
static const uint32_t SEQUENTIAL_FLASH_JOURNAL_VERSION = 1;
 | 
			
		||||
static const uint32_t SEQUENTIAL_FLASH_JOURNAL_MAGIC   = 0xCE02102AUL;
 | 
			
		||||
static const uint32_t SEQUENTIAL_FLASH_JOURNAL_MAGIC                       = 0xCE02102AUL;
 | 
			
		||||
static const uint32_t SEQUENTIAL_FLASH_JOURNAL_VERSION                     = 1;
 | 
			
		||||
static const uint32_t SEQUENTIAL_FLASH_JOURNAL_HEADER_MAGIC                = 0xCEA00AEEUL;
 | 
			
		||||
static const uint32_t SEQUENTIAL_FLASH_JOURNAL_HEADER_VERSION              = 1;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED,
 | 
			
		||||
| 
						 | 
				
			
			@ -41,6 +52,20 @@ typedef enum {
 | 
			
		|||
    SEQUENTIAL_JOURNAL_STATE_READING,
 | 
			
		||||
} SequentialFlashJournalState_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Meta-data placed at the head of a Journal. The actual header would be an
 | 
			
		||||
 * extension of this generic header, and would depend on the implementation
 | 
			
		||||
 * strategy. Initialization algorithms can expect to find this generic header at
 | 
			
		||||
 * the start of every Journal.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct _SequentialFlashJournalHeader {
 | 
			
		||||
    FlashJournalHeader_t genericHeader; /** Generic meta-data placed at the head of a Journal; common to all journal types. */
 | 
			
		||||
    uint32_t             magic;         /** Sequential journal header specific magic code. */
 | 
			
		||||
    uint32_t             version;       /** Revision number for this sequential journal header. */
 | 
			
		||||
    uint32_t             numSlots;      /** Maximum number of logged blobs; i.e. maximum number of versions of the journaled payload. */
 | 
			
		||||
    uint32_t             sizeofSlot;    /** Slot size. Each slot holds a header, blob-payload, and a tail. */
 | 
			
		||||
} SequentialFlashJournalHeader_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Meta-data placed at the head of a sequential-log entry.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -62,9 +87,12 @@ typedef struct _SequentialFlashJournalLogHead {
 | 
			
		|||
 *     a partially written log-entry-tail won't be accepted as valid.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct _SequentialFlashJournalLogTail {
 | 
			
		||||
    uint64_t sizeofBlob; /**< the size of the payload in this blob. */
 | 
			
		||||
    uint32_t sizeofBlob; /**< the size of the payload in this blob. */
 | 
			
		||||
    uint32_t magic;
 | 
			
		||||
    uint32_t sequenceNumber;
 | 
			
		||||
    uint32_t crc32;      /**< This field contains the CRC of the header, body (only including logged data),
 | 
			
		||||
                          *   and the tail. The 'CRC32' field is assumed to hold 0x0 for the purpose of
 | 
			
		||||
                          *   computing the CRC */
 | 
			
		||||
} SequentialFlashJournalLogTail_t;
 | 
			
		||||
 | 
			
		||||
#define SEQUENTIAL_JOURNAL_VALID_TAIL(TAIL_PTR) ((TAIL_PTR)->magic == SEQUENTIAL_FLASH_JOURNAL_MAGIC)
 | 
			
		||||
| 
						 | 
				
			
			@ -76,7 +104,9 @@ typedef struct _SequentialFlashJournal_t {
 | 
			
		|||
    ARM_DRIVER_STORAGE            *mtd;                /**< The underlying Memory-Technology-Device. */
 | 
			
		||||
    ARM_STORAGE_CAPABILITIES       mtdCapabilities;    /**< the return from mtd->GetCapabilities(); held for quick reference. */
 | 
			
		||||
    uint64_t                       mtdStartOffset;     /**< the start of the address range maintained by the underlying MTD. */
 | 
			
		||||
    uint32_t                       sequentialSkip;     /**< size of the log stride. */
 | 
			
		||||
    uint32_t                       firstSlotOffset;  /** Offset from the start of the journal header to the actual logged journal. */
 | 
			
		||||
    uint32_t                       numSlots;           /** Maximum number of logged blobs; i.e. maximum number of versions of the journaled payload. */
 | 
			
		||||
    uint32_t                       sizeofSlot;         /**< size of the log stride. */
 | 
			
		||||
    uint32_t                       nextSequenceNumber; /**< the next valid sequence number to be used when logging the next blob. */
 | 
			
		||||
    uint32_t                       currentBlobIndex;   /**< index of the most recently written blob. */
 | 
			
		||||
    SequentialFlashJournalState_t  state;              /**< state of the journal. SEQUENTIAL_JOURNAL_STATE_INITIALIZED being the default. */
 | 
			
		||||
| 
						 | 
				
			
			@ -90,12 +120,9 @@ typedef struct _SequentialFlashJournal_t {
 | 
			
		|||
        /** state relevant to initialization. */
 | 
			
		||||
        struct {
 | 
			
		||||
            uint64_t currentOffset;
 | 
			
		||||
            union {
 | 
			
		||||
                SequentialFlashJournalLogHead_t head;
 | 
			
		||||
                struct {
 | 
			
		||||
                    uint32_t                        headSequenceNumber;
 | 
			
		||||
                    SequentialFlashJournalLogTail_t tail;
 | 
			
		||||
                };
 | 
			
		||||
            struct {
 | 
			
		||||
                uint32_t                        headSequenceNumber;
 | 
			
		||||
                SequentialFlashJournalLogTail_t tail;
 | 
			
		||||
            };
 | 
			
		||||
        } initScan;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -105,11 +132,11 @@ typedef struct _SequentialFlashJournal_t {
 | 
			
		|||
            size_t         sizeofBlob;
 | 
			
		||||
            union {
 | 
			
		||||
                struct {
 | 
			
		||||
                    uint64_t eraseOffset;
 | 
			
		||||
                    uint64_t mtdEraseOffset;
 | 
			
		||||
                };
 | 
			
		||||
                struct {
 | 
			
		||||
                    uint64_t       offset;          /**< the current offset at which data is being written. */
 | 
			
		||||
                    uint64_t       tailOffset;      /**< offset at which the SequentialFlashJournalLogTail_t will be logged for this log-entry. */
 | 
			
		||||
                    uint64_t       mtdOffset;       /**< the current Storage offset at which data will be written. */
 | 
			
		||||
                    uint64_t       mtdTailOffset;   /**< Storage offset at which the SequentialFlashJournalLogTail_t will be logged for this log-entry. */
 | 
			
		||||
                    const uint8_t *dataBeingLogged; /**< temporary pointer aimed at the next data to be logged. */
 | 
			
		||||
                    size_t         amountLeftToLog;
 | 
			
		||||
                    union {
 | 
			
		||||
| 
						 | 
				
			
			@ -124,10 +151,10 @@ typedef struct _SequentialFlashJournal_t {
 | 
			
		|||
        struct {
 | 
			
		||||
            const uint8_t *blob;               /**< the original buffer holding source data. */
 | 
			
		||||
            size_t         sizeofBlob;
 | 
			
		||||
            uint64_t       offset;             /**< the current offset at which data is being written. */
 | 
			
		||||
            uint64_t       mtdOffset;          /**< the current Storage offset from which data is being read. */
 | 
			
		||||
            uint8_t       *dataBeingRead;      /**< temporary pointer aimed at the next data to be read-into. */
 | 
			
		||||
            size_t         amountLeftToRead;
 | 
			
		||||
            size_t         totalDataRead;      /**< the total data that has been read off the blob so far. */
 | 
			
		||||
            size_t         logicalOffset;      /**< the logical offset within the blob at which the next read will occur. */
 | 
			
		||||
        } read;
 | 
			
		||||
    };
 | 
			
		||||
} SequentialFlashJournal_t;
 | 
			
		||||
| 
						 | 
				
			
			@ -139,6 +166,8 @@ typedef struct _SequentialFlashJournal_t {
 | 
			
		|||
 */
 | 
			
		||||
typedef char AssertSequentialJournalSizeLessThanOrEqualToGenericJournal[sizeof(SequentialFlashJournal_t)<=sizeof(FlashJournal_t)?1:-1];
 | 
			
		||||
 | 
			
		||||
#define SLOT_ADDRESS(JOURNAL, INDEX) ((JOURNAL)->mtdStartOffset + (JOURNAL)->firstSlotOffset + ((INDEX) * (JOURNAL)->sizeofSlot))
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif // __cplusplus
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,12 +24,118 @@ extern "C" {
 | 
			
		|||
 | 
			
		||||
#include "flash-journal/flash_journal.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Create/format a sequential flash journal at a given offset within a storage
 | 
			
		||||
 * device and with a given slot-cardinality.
 | 
			
		||||
 *
 | 
			
		||||
 * This function must be called *once* for each incarnation of a sequential
 | 
			
		||||
 * journal.
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in] mtd
 | 
			
		||||
 *              The underlying Storage driver.
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in] numSlots
 | 
			
		||||
 *              Number of slots in the sequential journal. Each slot holds a header, blob-payload, and a tail.
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in] callback
 | 
			
		||||
 *                Caller-defined callback to be invoked upon command completion
 | 
			
		||||
 *                in case the storage device executes operations asynchronously.
 | 
			
		||||
 *                Use a NULL pointer when no callback signals are required.
 | 
			
		||||
 *
 | 
			
		||||
 * @note: this is an asynchronous operation, but it can finish
 | 
			
		||||
 * synchronously if the underlying MTD supports that.
 | 
			
		||||
 *
 | 
			
		||||
 * @return
 | 
			
		||||
 *   The function executes in the following ways:
 | 
			
		||||
 *   - When the operation is asynchronous, the function only starts the
 | 
			
		||||
 *     initialization and control returns to the caller with an
 | 
			
		||||
 *     JOURNAL_STATUS_OK before the actual completion of the operation (or with
 | 
			
		||||
 *     an appropriate error code in case of failure). When the operation is
 | 
			
		||||
 *     completed the command callback is invoked with 1 passed in as the
 | 
			
		||||
 *     'status' parameter of the callback. In case of errors, the completion
 | 
			
		||||
 *     callback is invoked with an error status.
 | 
			
		||||
 *   - When the operation is executed by the journal in a blocking (i.e.
 | 
			
		||||
 *     synchronous) manner, control returns to the caller only upon the actual
 | 
			
		||||
 *     completion of the operation or the discovery of a failure condition. In
 | 
			
		||||
 *     this case, the function returns 1 to signal successful synchronous
 | 
			
		||||
 *     completion or an appropriate error code, and no further
 | 
			
		||||
 *     invocation of the completion callback should be expected at a later time.
 | 
			
		||||
 *
 | 
			
		||||
 * Here's a code snippet to suggest how this API might be used by callers:
 | 
			
		||||
 * \code
 | 
			
		||||
 *     ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code
 | 
			
		||||
 *     int32_t returnValue = flashJournalStrategySequential_format(MTD, numSlots, callbackHandler);
 | 
			
		||||
 *     if (returnValue < JOURNAL_STATUS_OK) {
 | 
			
		||||
 *         // handle error
 | 
			
		||||
 *     } else if (returnValue == JOURNAL_STATUS_OK) {
 | 
			
		||||
 *         ASSERT(MTD->GetCapabilities().asynchronous_ops == 1);
 | 
			
		||||
 *         // handle early return from asynchronous execution
 | 
			
		||||
 *     } else {
 | 
			
		||||
 *         ASSERT(returnValue == 1);
 | 
			
		||||
 *         // handle synchronous completion
 | 
			
		||||
 *     }
 | 
			
		||||
 * \endcode
 | 
			
		||||
 *
 | 
			
		||||
 *     +-------------------------------+    ^
 | 
			
		||||
 *     |                               |    |
 | 
			
		||||
 *     |  Journal Header               |    |
 | 
			
		||||
 *     |  starts with generic header   |    |
 | 
			
		||||
 *     |  followed by specific header  |    |
 | 
			
		||||
 *     |                               |    |   multiple of program_unit
 | 
			
		||||
 *     +-------------------------------+    |   and erase-boundary
 | 
			
		||||
 *     +-------------------------------+    |
 | 
			
		||||
 *     |                               |    |
 | 
			
		||||
 *     |   padding to allow alignment  |    |
 | 
			
		||||
 *     |                               |    |
 | 
			
		||||
 *     +-------------------------------+    v
 | 
			
		||||
 *     +-------------------------------+
 | 
			
		||||
 *     | +---------------------------+ |    ^
 | 
			
		||||
 *     | |  slot header              | |    |
 | 
			
		||||
 *     | |  aligned with program_unit| |    |
 | 
			
		||||
 *     | +---------------------------+ |    |     slot 0
 | 
			
		||||
 *     |                               |    |     aligned with LCM of all erase boundaries
 | 
			
		||||
 *     |                               |    |
 | 
			
		||||
 *     |                               |    |
 | 
			
		||||
 *     |                               |    |
 | 
			
		||||
 *     |          BLOB0                |    |
 | 
			
		||||
 *     |                               |    |
 | 
			
		||||
 *     |                               |    |
 | 
			
		||||
 *     | +---------------------------+ |    |
 | 
			
		||||
 *     | |  slot tail                | |    |
 | 
			
		||||
 *     | |  aligned with program_unit| |    |
 | 
			
		||||
 *     | +---------------------------+ |    |
 | 
			
		||||
 *     +-------------------------------+    v
 | 
			
		||||
 *     +-------------------------------+
 | 
			
		||||
 *     | +---------------------------+ |    ^
 | 
			
		||||
 *     | |  slot header              | |    |
 | 
			
		||||
 *     | |  aligned with program_unit| |    |
 | 
			
		||||
 *     | +---------------------------+ |    |     slot 1
 | 
			
		||||
 *     |                               |    |     aligned with LCM of all erase boundaries
 | 
			
		||||
 *     |          BLOB1                |    |
 | 
			
		||||
 *     |                               |    |
 | 
			
		||||
 *     .                               .    .
 | 
			
		||||
 *     .                               .    .
 | 
			
		||||
 *
 | 
			
		||||
 *     .                               .    .
 | 
			
		||||
 *     .          BLOB(N-1)            .    .
 | 
			
		||||
 *     |                               |    |
 | 
			
		||||
 *     | +---------------------------+ |    |     slot 'N - 1'
 | 
			
		||||
 *     | |  slot tail                | |    |     aligned with LCM of all erase boundaries
 | 
			
		||||
 *     | |  aligned with program_unit| |    |
 | 
			
		||||
 *     | +---------------------------+ |    |
 | 
			
		||||
 *     +-------------------------------+    v
 | 
			
		||||
 */
 | 
			
		||||
int32_t               flashJournalStrategySequential_format(ARM_DRIVER_STORAGE      *mtd,
 | 
			
		||||
                                                            uint32_t                 numSlots,
 | 
			
		||||
                                                            FlashJournal_Callback_t  callback);
 | 
			
		||||
 | 
			
		||||
int32_t               flashJournalStrategySequential_initialize(FlashJournal_t           *journal,
 | 
			
		||||
                                                                ARM_DRIVER_STORAGE       *mtd,
 | 
			
		||||
                                                                const FlashJournal_Ops_t *ops,
 | 
			
		||||
                                                                FlashJournal_Callback_t   callback);
 | 
			
		||||
FlashJournal_Status_t flashJournalStrategySequential_getInfo(FlashJournal_t *journal, FlashJournal_Info_t *info);
 | 
			
		||||
int32_t               flashJournalStrategySequential_read(FlashJournal_t *journal, void *blob, size_t n);
 | 
			
		||||
int32_t               flashJournalStrategySequential_readFrom(FlashJournal_t *journal, size_t offset, void *blob, size_t n);
 | 
			
		||||
int32_t               flashJournalStrategySequential_log(FlashJournal_t *journal, const void *blob, size_t n);
 | 
			
		||||
int32_t               flashJournalStrategySequential_commit(FlashJournal_t *journal);
 | 
			
		||||
int32_t               flashJournalStrategySequential_reset(FlashJournal_t *journal);
 | 
			
		||||
| 
						 | 
				
			
			@ -38,6 +144,7 @@ static const FlashJournal_Ops_t FLASH_JOURNAL_STRATEGY_SEQUENTIAL = {
 | 
			
		|||
    flashJournalStrategySequential_initialize,
 | 
			
		||||
    flashJournalStrategySequential_getInfo,
 | 
			
		||||
    flashJournalStrategySequential_read,
 | 
			
		||||
    flashJournalStrategySequential_readFrom,
 | 
			
		||||
    flashJournalStrategySequential_log,
 | 
			
		||||
    flashJournalStrategySequential_commit,
 | 
			
		||||
    flashJournalStrategySequential_reset
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,7 @@
 | 
			
		|||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "flash-journal-strategy-sequential/flash_journal_crc.h"
 | 
			
		||||
#include "flash-journal-strategy-sequential/flash_journal_private.h"
 | 
			
		||||
#include "flash-journal-strategy-sequential/flash_journal_strategy_sequential.h"
 | 
			
		||||
#include "support_funcs.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -23,82 +24,101 @@
 | 
			
		|||
 | 
			
		||||
SequentialFlashJournal_t *activeJournal;
 | 
			
		||||
 | 
			
		||||
/* forward declarations */
 | 
			
		||||
void mtdHandler(int32_t status, ARM_STORAGE_OPERATION operation);
 | 
			
		||||
/*
 | 
			
		||||
 * forward declarations of static-inline helper functions.
 | 
			
		||||
 */
 | 
			
		||||
static inline int32_t mtdGetTotalCapacity(ARM_DRIVER_STORAGE *mtd, uint64_t *capacityP);
 | 
			
		||||
static inline int32_t flashJournalStrategySequential_format_sanityChecks(ARM_DRIVER_STORAGE *mtd, uint32_t numSlots);
 | 
			
		||||
static inline int32_t flashJournalStrategySequential_read_sanityChecks(SequentialFlashJournal_t *journal, const void *blob, size_t sizeofBlob);
 | 
			
		||||
static inline int32_t flashJournalStrategySequential_log_sanityChecks(SequentialFlashJournal_t *journal, const void *blob, size_t sizeofBlob);
 | 
			
		||||
static inline int32_t flashJournalStrategySequential_commit_sanityChecks(SequentialFlashJournal_t *journal);
 | 
			
		||||
 | 
			
		||||
static inline int32_t mtdGetTotalCapacity(ARM_DRIVER_STORAGE *mtd, uint64_t *capacityP)
 | 
			
		||||
 | 
			
		||||
int32_t flashJournalStrategySequential_format(ARM_DRIVER_STORAGE      *mtd,
 | 
			
		||||
                                              uint32_t                 numSlots,
 | 
			
		||||
                                              FlashJournal_Callback_t  callback)
 | 
			
		||||
{
 | 
			
		||||
    /* fetch MTD's INFO */
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
    if ((rc = flashJournalStrategySequential_format_sanityChecks(mtd, numSlots)) != JOURNAL_STATUS_OK) {
 | 
			
		||||
        return rc;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ARM_STORAGE_INFO mtdInfo;
 | 
			
		||||
    int32_t rc = mtd->GetInfo(&mtdInfo);
 | 
			
		||||
    if (rc != ARM_DRIVER_OK) {
 | 
			
		||||
    if (mtd->GetInfo(&mtdInfo) < ARM_DRIVER_OK) {
 | 
			
		||||
        return JOURNAL_STATUS_STORAGE_API_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    uint64_t mtdAddr;
 | 
			
		||||
    if (mtdGetStartAddr(mtd, &mtdAddr) < JOURNAL_STATUS_OK) {
 | 
			
		||||
        return JOURNAL_STATUS_STORAGE_API_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    *capacityP = mtdInfo.total_storage;
 | 
			
		||||
 | 
			
		||||
    return JOURNAL_STATUS_OK;
 | 
			
		||||
    formatInfoSingleton.mtd            = mtd;
 | 
			
		||||
    formatInfoSingleton.mtdAddr        = mtdAddr;
 | 
			
		||||
    formatInfoSingleton.callback       = callback;
 | 
			
		||||
    formatInfoSingleton.mtdProgramUnit = mtdInfo.program_unit;
 | 
			
		||||
 | 
			
		||||
    if ((rc = setupSequentialJournalHeader(&formatInfoSingleton.header, mtd, mtdInfo.total_storage, numSlots)) != JOURNAL_STATUS_OK) {
 | 
			
		||||
        return rc;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* initialize MTD */
 | 
			
		||||
    rc = mtd->Initialize(formatHandler);
 | 
			
		||||
    if (rc < ARM_DRIVER_OK) {
 | 
			
		||||
        return JOURNAL_STATUS_STORAGE_API_ERROR;
 | 
			
		||||
    } else if (rc == ARM_DRIVER_OK) {
 | 
			
		||||
        return JOURNAL_STATUS_OK; /* An asynchronous operation is pending; it will result in a completion callback
 | 
			
		||||
                                   * where the rest of processing will take place. */
 | 
			
		||||
    }
 | 
			
		||||
    if (rc != 1) {
 | 
			
		||||
        return JOURNAL_STATUS_STORAGE_API_ERROR; /* synchronous completion is expected to return 1 */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* progress the rest of the create state-machine */
 | 
			
		||||
    return flashJournalStrategySequential_format_progress(ARM_DRIVER_OK, ARM_STORAGE_OPERATION_INITIALIZE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int32_t flashJournalStrategySequential_read_sanityChecks(SequentialFlashJournal_t *journal, const void *blob, size_t sizeofBlob)
 | 
			
		||||
/**
 | 
			
		||||
 * Validate a header at the start of the MTD.
 | 
			
		||||
 *
 | 
			
		||||
 * @param [in/out] headerP
 | 
			
		||||
 *                     Caller-allocated header which gets filled in during validation.
 | 
			
		||||
 | 
			
		||||
 * @return JOURNAL_STATUS_OK if the header is sane. As a side-effect, the memory
 | 
			
		||||
 *         pointed to by 'headerP' is initialized with the header.
 | 
			
		||||
 */
 | 
			
		||||
int32_t readAndVerifyJournalHeader(SequentialFlashJournal_t *journal, SequentialFlashJournalHeader_t *headerP)
 | 
			
		||||
{
 | 
			
		||||
    if ((journal == NULL) || (blob == NULL) || (sizeofBlob == 0)) {
 | 
			
		||||
    if (headerP == NULL) {
 | 
			
		||||
        return JOURNAL_STATUS_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
    if ((journal->state == SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED) || (journal->state == SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS)) {
 | 
			
		||||
        return JOURNAL_STATUS_NOT_INITIALIZED;
 | 
			
		||||
    }
 | 
			
		||||
    if (journal->state != SEQUENTIAL_JOURNAL_STATE_INITIALIZED) {
 | 
			
		||||
        return JOURNAL_STATUS_ERROR; /* journal is in an un-expected state. */
 | 
			
		||||
    }
 | 
			
		||||
    // printf("read sanity checks: totalDataRead = %lu, sizeofJournaledBlob = %lu\n", (uint32_t)journal->read.totalDataRead, (uint32_t)journal->info.sizeofJournaledBlob);
 | 
			
		||||
    if ((journal->info.sizeofJournaledBlob == 0) || (journal->read.totalDataRead == journal->info.sizeofJournaledBlob)) {
 | 
			
		||||
        journal->read.totalDataRead = 0;
 | 
			
		||||
        return JOURNAL_STATUS_EMPTY;
 | 
			
		||||
 | 
			
		||||
    int32_t rc = journal->mtd->ReadData(journal->mtdStartOffset, headerP, sizeof(SequentialFlashJournalHeader_t));
 | 
			
		||||
    if (rc < ARM_DRIVER_OK) {
 | 
			
		||||
        return JOURNAL_STATUS_STORAGE_IO_ERROR;
 | 
			
		||||
    } else if (rc == ARM_DRIVER_OK) {
 | 
			
		||||
        ARM_STORAGE_CAPABILITIES mtdCaps = journal->mtd->GetCapabilities();
 | 
			
		||||
        if (!mtdCaps.asynchronous_ops) {
 | 
			
		||||
            return JOURNAL_STATUS_ERROR; /* asynchronous_ops must be set if MTD returns ARM_DRIVER_OK. */
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return JOURNAL_STATUS_ERROR; /* TODO: handle init with pending asynchronous activity. */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return JOURNAL_STATUS_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int32_t flashJournalStrategySequential_log_sanityChecks(SequentialFlashJournal_t *journal, const void *blob, size_t sizeofBlob)
 | 
			
		||||
{
 | 
			
		||||
    if ((journal == NULL) || (blob == NULL) || (sizeofBlob == 0)) {
 | 
			
		||||
        return JOURNAL_STATUS_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
    if ((journal->state == SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED) || (journal->state == SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS)) {
 | 
			
		||||
        return JOURNAL_STATUS_NOT_INITIALIZED;
 | 
			
		||||
    }
 | 
			
		||||
    if ((journal->state != SEQUENTIAL_JOURNAL_STATE_INITIALIZED) && (journal->state != SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY)) {
 | 
			
		||||
        return JOURNAL_STATUS_ERROR; /* journal is in an un-expected state. */
 | 
			
		||||
    }
 | 
			
		||||
    if (journal->state == SEQUENTIAL_JOURNAL_STATE_INITIALIZED) {
 | 
			
		||||
        if (sizeofBlob > journal->info.capacity) {
 | 
			
		||||
            return JOURNAL_STATUS_BOUNDED_CAPACITY; /* adding this log chunk would cause us to exceed capacity (write past the tail). */
 | 
			
		||||
        }
 | 
			
		||||
    } else if (journal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY) {
 | 
			
		||||
        if (journal->log.offset + sizeofBlob > journal->log.tailOffset) {
 | 
			
		||||
            return JOURNAL_STATUS_BOUNDED_CAPACITY; /* adding this log chunk would cause us to exceed capacity (write past the tail). */
 | 
			
		||||
        }
 | 
			
		||||
    if ((headerP->genericHeader.magic        != FLASH_JOURNAL_HEADER_MAGIC)             ||
 | 
			
		||||
        (headerP->genericHeader.version      != FLASH_JOURNAL_HEADER_VERSION)           ||
 | 
			
		||||
        (headerP->genericHeader.sizeofHeader != sizeof(SequentialFlashJournalHeader_t)) ||
 | 
			
		||||
        (headerP->magic                      != SEQUENTIAL_FLASH_JOURNAL_HEADER_MAGIC)  ||
 | 
			
		||||
        (headerP->version                    != SEQUENTIAL_FLASH_JOURNAL_HEADER_VERSION)) {
 | 
			
		||||
        return JOURNAL_STATUS_NOT_FORMATTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return JOURNAL_STATUS_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int32_t flashJournalStrategySequential_commit_sanityChecks(SequentialFlashJournal_t *journal)
 | 
			
		||||
{
 | 
			
		||||
    if (journal == NULL) {
 | 
			
		||||
        return JOURNAL_STATUS_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
    if (journal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY) {
 | 
			
		||||
        if (journal->prevCommand != FLASH_JOURNAL_OPCODE_LOG_BLOB) {
 | 
			
		||||
            return JOURNAL_STATUS_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
        if ((journal->log.offset          == ARM_STORAGE_INVALID_OFFSET) ||
 | 
			
		||||
            (journal->log.tailOffset      == ARM_STORAGE_INVALID_OFFSET) ||
 | 
			
		||||
            (journal->log.tailOffset       < journal->log.offset)        ||
 | 
			
		||||
            (journal->log.tail.sizeofBlob == 0)                          ||
 | 
			
		||||
            (journal->log.tail.sizeofBlob  > journal->info.capacity)) {
 | 
			
		||||
            return JOURNAL_STATUS_ERROR; /* journal is in an un-expected state. */
 | 
			
		||||
        }
 | 
			
		||||
    uint32_t expectedCRC = headerP->genericHeader.checksum;
 | 
			
		||||
    headerP->genericHeader.checksum = 0;
 | 
			
		||||
    flashJournalCrcReset();
 | 
			
		||||
    uint32_t computedCRC = flashJournalCrcCummulative((const unsigned char *)&headerP->genericHeader, sizeof(SequentialFlashJournalLogHead_t));
 | 
			
		||||
    if (computedCRC != expectedCRC) {
 | 
			
		||||
        //printf("readAndVerifyJournalHeader: checksum mismatch during header verification: expected = %u, computed = %u\n", (unsigned int) expectedCRC, (unsigned int) computedCRC);
 | 
			
		||||
        return JOURNAL_STATUS_METADATA_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return JOURNAL_STATUS_OK;
 | 
			
		||||
| 
						 | 
				
			
			@ -111,9 +131,30 @@ int32_t flashJournalStrategySequential_initialize(FlashJournal_t           *_jou
 | 
			
		|||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    /* initialize MTD */
 | 
			
		||||
    rc = mtd->Initialize(mtdHandler);
 | 
			
		||||
    if (rc < ARM_DRIVER_OK) {
 | 
			
		||||
        memset(_journal, 0, sizeof(FlashJournal_t));
 | 
			
		||||
        return JOURNAL_STATUS_STORAGE_API_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    if (rc == ARM_DRIVER_OK) {
 | 
			
		||||
        ARM_STORAGE_CAPABILITIES mtdCaps = mtd->GetCapabilities();
 | 
			
		||||
        if (!mtdCaps.asynchronous_ops) {
 | 
			
		||||
            return JOURNAL_STATUS_ERROR; /* asynchronous_ops must be set if MTD returns ARM_DRIVER_OK. */
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return JOURNAL_STATUS_ERROR; /* TODO: handle init with pending asynchronous activity. */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SequentialFlashJournal_t *journal;
 | 
			
		||||
    activeJournal = journal = (SequentialFlashJournal_t *)_journal;
 | 
			
		||||
    journal->state          = SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED;
 | 
			
		||||
    activeJournal = journal    = (SequentialFlashJournal_t *)_journal;
 | 
			
		||||
    journal->state             = SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED;
 | 
			
		||||
    journal->mtd               = mtd;
 | 
			
		||||
 | 
			
		||||
    /* Setup start address within MTD. */
 | 
			
		||||
    if ((rc = mtdGetStartAddr(journal->mtd, &journal->mtdStartOffset)) != JOURNAL_STATUS_OK) {
 | 
			
		||||
        return rc;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* fetch MTD's total capacity */
 | 
			
		||||
    uint64_t mtdCapacity;
 | 
			
		||||
| 
						 | 
				
			
			@ -125,27 +166,27 @@ int32_t flashJournalStrategySequential_initialize(FlashJournal_t           *_jou
 | 
			
		|||
        return JOURNAL_STATUS_STORAGE_API_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SequentialFlashJournalHeader_t journalHeader;
 | 
			
		||||
    if ((rc = readAndVerifyJournalHeader(journal, &journalHeader)) != JOURNAL_STATUS_OK) {
 | 
			
		||||
        return rc;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* initialize the journal structure */
 | 
			
		||||
    memcpy(&journal->ops, ops, sizeof(FlashJournal_Ops_t));
 | 
			
		||||
    journal->mtd               = mtd;
 | 
			
		||||
    journal->mtdCapabilities   = mtd->GetCapabilities(); /* fetch MTD's capabilities */
 | 
			
		||||
    journal->sequentialSkip    = mtdCapacity / SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS;
 | 
			
		||||
    journal->info.capacity     = journal->sequentialSkip - (sizeof(SequentialFlashJournalLogHead_t) + sizeof(SequentialFlashJournalLogTail_t)); /* effective capacity */
 | 
			
		||||
 | 
			
		||||
    journal->firstSlotOffset   = journalHeader.genericHeader.journalOffset;
 | 
			
		||||
    journal->numSlots          = journalHeader.numSlots;
 | 
			
		||||
    journal->sizeofSlot        = journalHeader.sizeofSlot;
 | 
			
		||||
 | 
			
		||||
    /* effective capacity */
 | 
			
		||||
    journal->info.capacity     = journal->sizeofSlot
 | 
			
		||||
                                 - roundUp_uint32(sizeof(SequentialFlashJournalLogHead_t), mtdInfo.program_unit)
 | 
			
		||||
                                 - roundUp_uint32(sizeof(SequentialFlashJournalLogTail_t), mtdInfo.program_unit);
 | 
			
		||||
    journal->info.program_unit = mtdInfo.program_unit;
 | 
			
		||||
    journal->callback          = callback;
 | 
			
		||||
    journal->prevCommand       = FLASH_JOURNAL_OPCODE_INITIALIZE;
 | 
			
		||||
 | 
			
		||||
    /* initialize MTD */
 | 
			
		||||
    ARM_STORAGE_CAPABILITIES mtdCaps = mtd->GetCapabilities();
 | 
			
		||||
    rc = mtd->Initialize(mtdHandler);
 | 
			
		||||
    if (rc < ARM_DRIVER_OK) {
 | 
			
		||||
        memset(journal, 0, sizeof(FlashJournal_t));
 | 
			
		||||
        return JOURNAL_STATUS_STORAGE_API_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    if ((mtdCaps.asynchronous_ops) && (rc == ARM_DRIVER_OK)) {
 | 
			
		||||
        return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((rc = discoverLatestLoggedBlob(journal)) != JOURNAL_STATUS_OK) {
 | 
			
		||||
        return rc;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -167,6 +208,10 @@ int32_t flashJournalStrategySequential_read(FlashJournal_t *_journal, void *blob
 | 
			
		|||
    SequentialFlashJournal_t *journal;
 | 
			
		||||
    activeJournal = journal = (SequentialFlashJournal_t *)_journal;
 | 
			
		||||
 | 
			
		||||
    if (journal->prevCommand != FLASH_JOURNAL_OPCODE_READ_BLOB) {
 | 
			
		||||
        journal->read.logicalOffset = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
    if ((rc = flashJournalStrategySequential_read_sanityChecks(journal, blob, sizeofBlob)) != JOURNAL_STATUS_OK) {
 | 
			
		||||
        return rc;
 | 
			
		||||
| 
						 | 
				
			
			@ -175,18 +220,53 @@ int32_t flashJournalStrategySequential_read(FlashJournal_t *_journal, void *blob
 | 
			
		|||
    journal->read.blob       = blob;
 | 
			
		||||
    journal->read.sizeofBlob = sizeofBlob;
 | 
			
		||||
 | 
			
		||||
    if ((journal->prevCommand != FLASH_JOURNAL_OPCODE_READ_BLOB) || (journal->read.totalDataRead == 0)) {
 | 
			
		||||
        journal->read.offset        = journal->mtdStartOffset
 | 
			
		||||
                                      + (journal->currentBlobIndex * journal->sequentialSkip)
 | 
			
		||||
                                      + sizeof(SequentialFlashJournalLogHead_t);
 | 
			
		||||
        journal->read.totalDataRead = 0;
 | 
			
		||||
    if (journal->read.logicalOffset == 0) {
 | 
			
		||||
        { /* Establish the sanity of this slot before proceeding with the read. */
 | 
			
		||||
            uint32_t headSequenceNumber;
 | 
			
		||||
            SequentialFlashJournalLogTail_t tail;
 | 
			
		||||
            if (slotIsSane(journal,
 | 
			
		||||
                           SLOT_ADDRESS(journal, journal->currentBlobIndex),
 | 
			
		||||
                           &headSequenceNumber,
 | 
			
		||||
                           &tail) != 1) {
 | 
			
		||||
                /* TODO: rollback to an older slot. */
 | 
			
		||||
                return JOURNAL_STATUS_STORAGE_IO_ERROR;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        journal->read.mtdOffset = SLOT_ADDRESS(journal, journal->currentBlobIndex) + sizeof(SequentialFlashJournalLogHead_t);
 | 
			
		||||
    } else {
 | 
			
		||||
        /* journal->read.offset is already set from the previous read execution */
 | 
			
		||||
        // printf("flashJournalStrategySequential_read: continuing read of %lu from offset %lu\n", sizeofBlob, (uint32_t)journal->read.offset);
 | 
			
		||||
    }
 | 
			
		||||
    journal->read.dataBeingRead    = blob;
 | 
			
		||||
    journal->read.amountLeftToRead = ((journal->info.sizeofJournaledBlob - journal->read.totalDataRead) < sizeofBlob) ?
 | 
			
		||||
                                        (journal->info.sizeofJournaledBlob - journal->read.totalDataRead) : sizeofBlob;
 | 
			
		||||
    journal->read.amountLeftToRead = ((journal->info.sizeofJournaledBlob - journal->read.logicalOffset) < sizeofBlob) ?
 | 
			
		||||
                                        (journal->info.sizeofJournaledBlob - journal->read.logicalOffset) : sizeofBlob;
 | 
			
		||||
    // printf("amount left to read %u\n", journal->read.amountLeftToRead);
 | 
			
		||||
 | 
			
		||||
    journal->state       = SEQUENTIAL_JOURNAL_STATE_READING;
 | 
			
		||||
    journal->prevCommand = FLASH_JOURNAL_OPCODE_READ_BLOB;
 | 
			
		||||
    return flashJournalStrategySequential_read_progress();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t flashJournalStrategySequential_readFrom(FlashJournal_t *_journal, size_t offset, void *blob, size_t sizeofBlob)
 | 
			
		||||
{
 | 
			
		||||
    SequentialFlashJournal_t *journal;
 | 
			
		||||
    activeJournal = journal = (SequentialFlashJournal_t *)_journal;
 | 
			
		||||
 | 
			
		||||
    journal->read.logicalOffset = offset;
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
    if ((rc = flashJournalStrategySequential_read_sanityChecks(journal, blob, sizeofBlob)) != JOURNAL_STATUS_OK) {
 | 
			
		||||
        return rc;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    journal->read.blob             = blob;
 | 
			
		||||
    journal->read.sizeofBlob       = sizeofBlob;
 | 
			
		||||
 | 
			
		||||
    journal->read.mtdOffset        = SLOT_ADDRESS(journal, journal->currentBlobIndex) + sizeof(SequentialFlashJournalLogHead_t) + offset;
 | 
			
		||||
 | 
			
		||||
    journal->read.dataBeingRead    = blob;
 | 
			
		||||
    journal->read.amountLeftToRead = ((journal->info.sizeofJournaledBlob - journal->read.logicalOffset) < sizeofBlob) ?
 | 
			
		||||
                                        (journal->info.sizeofJournaledBlob - journal->read.logicalOffset) : sizeofBlob;
 | 
			
		||||
    // printf("amount left to read %u\n", journal->read.amountLeftToRead);
 | 
			
		||||
 | 
			
		||||
    journal->state       = SEQUENTIAL_JOURNAL_STATE_READING;
 | 
			
		||||
| 
						 | 
				
			
			@ -208,24 +288,27 @@ int32_t flashJournalStrategySequential_log(FlashJournal_t *_journal, const void
 | 
			
		|||
    journal->log.sizeofBlob = size;
 | 
			
		||||
 | 
			
		||||
    if (journal->prevCommand != FLASH_JOURNAL_OPCODE_LOG_BLOB) {
 | 
			
		||||
        /*
 | 
			
		||||
         * This is the first log in the sequence. We have to begin by identifying a new slot and erasing it.
 | 
			
		||||
         */
 | 
			
		||||
 | 
			
		||||
         /* choose the next slot */
 | 
			
		||||
        uint32_t logBlobIndex = journal->currentBlobIndex + 1;
 | 
			
		||||
        if (logBlobIndex == SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS) {
 | 
			
		||||
        if (logBlobIndex == journal->numSlots) {
 | 
			
		||||
            logBlobIndex = 0;
 | 
			
		||||
        }
 | 
			
		||||
        journal->log.eraseOffset = journal->mtdStartOffset + (logBlobIndex * journal->sequentialSkip);
 | 
			
		||||
 | 
			
		||||
        /* ensure that the request is at least as large as the minimum program unit */
 | 
			
		||||
        if (size < journal->info.program_unit) {
 | 
			
		||||
            return JOURNAL_STATUS_SMALL_LOG_REQUEST;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        journal->state       = SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE; /* start with erasing the log region */
 | 
			
		||||
        journal->prevCommand = FLASH_JOURNAL_OPCODE_LOG_BLOB;
 | 
			
		||||
        /* setup an erase for the slot */
 | 
			
		||||
        journal->log.mtdEraseOffset = SLOT_ADDRESS(journal, logBlobIndex);
 | 
			
		||||
        journal->state              = SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE; /* start with erasing the log region */
 | 
			
		||||
        journal->prevCommand        = FLASH_JOURNAL_OPCODE_LOG_BLOB;
 | 
			
		||||
    } else {
 | 
			
		||||
        /* This is a continuation of an ongoing logging sequence. */
 | 
			
		||||
        journal->log.dataBeingLogged = blob;
 | 
			
		||||
        journal->log.amountLeftToLog = size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* progress the state machine for log() */
 | 
			
		||||
    return flashJournalStrategySequential_log_progress();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -240,17 +323,21 @@ int32_t flashJournalStrategySequential_commit(FlashJournal_t *_journal)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    if (journal->prevCommand == FLASH_JOURNAL_OPCODE_LOG_BLOB) {
 | 
			
		||||
        journal->log.offset          = journal->log.tailOffset;
 | 
			
		||||
        /* the tail has already been setup during previous calls to log(); we can now include it in the crc32. */
 | 
			
		||||
        journal->log.tail.crc32 = flashJournalCrcCummulative((const unsigned char *)&journal->log.tail, sizeof(SequentialFlashJournalLogTail_t));
 | 
			
		||||
        flashJournalCrcReset();
 | 
			
		||||
 | 
			
		||||
        journal->log.mtdOffset       = journal->log.mtdTailOffset;
 | 
			
		||||
        journal->log.dataBeingLogged = (const uint8_t *)&journal->log.tail;
 | 
			
		||||
        journal->log.amountLeftToLog = sizeof(SequentialFlashJournalLogTail_t);
 | 
			
		||||
        journal->state               = SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL;
 | 
			
		||||
    } else {
 | 
			
		||||
        uint32_t logBlobIndex = journal->currentBlobIndex + 1;
 | 
			
		||||
        if (logBlobIndex == SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS) {
 | 
			
		||||
        if (logBlobIndex == journal->numSlots) {
 | 
			
		||||
            logBlobIndex = 0;
 | 
			
		||||
        }
 | 
			
		||||
        journal->log.eraseOffset = journal->mtdStartOffset + (logBlobIndex * journal->sequentialSkip);
 | 
			
		||||
        journal->state           = SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE;
 | 
			
		||||
        journal->log.mtdEraseOffset = SLOT_ADDRESS(journal, logBlobIndex);
 | 
			
		||||
        journal->state              = SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    journal->prevCommand = FLASH_JOURNAL_OPCODE_COMMIT;
 | 
			
		||||
| 
						 | 
				
			
			@ -267,3 +354,124 @@ int32_t flashJournalStrategySequential_reset(FlashJournal_t *_journal)
 | 
			
		|||
    journal->prevCommand = FLASH_JOURNAL_OPCODE_RESET;
 | 
			
		||||
    return flashJournalStrategySequential_reset_progress();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t mtdGetTotalCapacity(ARM_DRIVER_STORAGE *mtd, uint64_t *capacityP)
 | 
			
		||||
{
 | 
			
		||||
    /* fetch MTD's INFO */
 | 
			
		||||
    ARM_STORAGE_INFO mtdInfo;
 | 
			
		||||
    int32_t rc = mtd->GetInfo(&mtdInfo);
 | 
			
		||||
    if (rc != ARM_DRIVER_OK) {
 | 
			
		||||
        return JOURNAL_STATUS_STORAGE_API_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    *capacityP = mtdInfo.total_storage;
 | 
			
		||||
 | 
			
		||||
    return JOURNAL_STATUS_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t flashJournalStrategySequential_format_sanityChecks(ARM_DRIVER_STORAGE *mtd, uint32_t numSlots)
 | 
			
		||||
{
 | 
			
		||||
    /*
 | 
			
		||||
     * basic parameter checking
 | 
			
		||||
     */
 | 
			
		||||
    if ((mtd == NULL) || (numSlots == 0)) {
 | 
			
		||||
        return JOURNAL_STATUS_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ARM_STORAGE_INFO mtdInfo;
 | 
			
		||||
    if (mtd->GetInfo(&mtdInfo) < ARM_DRIVER_OK) {
 | 
			
		||||
        return JOURNAL_STATUS_STORAGE_API_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    if (mtdInfo.total_storage == 0) {
 | 
			
		||||
        return JOURNAL_STATUS_STORAGE_API_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint64_t mtdAddr;
 | 
			
		||||
    if (mtdGetStartAddr(mtd, &mtdAddr) < JOURNAL_STATUS_OK) {
 | 
			
		||||
        return JOURNAL_STATUS_STORAGE_API_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    if (mtd->GetBlock(mtdAddr, NULL) < ARM_DRIVER_OK) { /* check validity of journal's start address */
 | 
			
		||||
        return JOURNAL_STATUS_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
    if (mtd->GetBlock(mtdAddr + mtdInfo.total_storage - 1, NULL) < ARM_DRIVER_OK) { /* check validity of the journal's end address */
 | 
			
		||||
        return JOURNAL_STATUS_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((mtdAddr % mtdInfo.program_unit) != 0) { /* ensure that the journal starts at a programmable unit */
 | 
			
		||||
        return JOURNAL_STATUS_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
    if ((mtdAddr % LCM_OF_ALL_ERASE_UNITS) != 0) { /* ensure that the journal starts and ends at an erase-boundary */
 | 
			
		||||
        return JOURNAL_STATUS_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return JOURNAL_STATUS_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t flashJournalStrategySequential_read_sanityChecks(SequentialFlashJournal_t *journal, const void *blob, size_t sizeofBlob)
 | 
			
		||||
{
 | 
			
		||||
    if ((journal == NULL) || (blob == NULL) || (sizeofBlob == 0)) {
 | 
			
		||||
        return JOURNAL_STATUS_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
    if ((journal->state == SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED) || (journal->state == SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS)) {
 | 
			
		||||
        return JOURNAL_STATUS_NOT_INITIALIZED;
 | 
			
		||||
    }
 | 
			
		||||
    if (journal->state != SEQUENTIAL_JOURNAL_STATE_INITIALIZED) {
 | 
			
		||||
        return JOURNAL_STATUS_ERROR; /* journal is in an un-expected state. */
 | 
			
		||||
    }
 | 
			
		||||
    // printf("read sanity checks: logicalOffset = %lu, sizeofJournaledBlob = %lu\n", (uint32_t)journal->read.logicalOffset, (uint32_t)journal->info.sizeofJournaledBlob);
 | 
			
		||||
    if ((journal->info.sizeofJournaledBlob == 0) || (journal->read.logicalOffset >= journal->info.sizeofJournaledBlob)) {
 | 
			
		||||
        journal->read.logicalOffset = 0;
 | 
			
		||||
        return JOURNAL_STATUS_EMPTY;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return JOURNAL_STATUS_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t flashJournalStrategySequential_log_sanityChecks(SequentialFlashJournal_t *journal, const void *blob, size_t sizeofBlob)
 | 
			
		||||
{
 | 
			
		||||
    if ((journal == NULL) || (blob == NULL) || (sizeofBlob == 0)) {
 | 
			
		||||
        return JOURNAL_STATUS_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
    if ((journal->state == SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED) || (journal->state == SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS)) {
 | 
			
		||||
        return JOURNAL_STATUS_NOT_INITIALIZED;
 | 
			
		||||
    }
 | 
			
		||||
    if ((journal->state != SEQUENTIAL_JOURNAL_STATE_INITIALIZED) && (journal->state != SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY)) {
 | 
			
		||||
        return JOURNAL_STATUS_ERROR; /* journal is in an un-expected state. */
 | 
			
		||||
    }
 | 
			
		||||
    if (journal->state == SEQUENTIAL_JOURNAL_STATE_INITIALIZED) {
 | 
			
		||||
        if (sizeofBlob > journal->info.capacity) {
 | 
			
		||||
            return JOURNAL_STATUS_BOUNDED_CAPACITY; /* adding this log chunk would cause us to exceed capacity (write past the tail). */
 | 
			
		||||
        }
 | 
			
		||||
    } else if (journal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY) {
 | 
			
		||||
        if (journal->log.mtdOffset + sizeofBlob > journal->log.mtdTailOffset) {
 | 
			
		||||
            return JOURNAL_STATUS_BOUNDED_CAPACITY; /* adding this log chunk would cause us to exceed capacity (write past the tail). */
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* ensure that the request is at least as large as the minimum program unit */
 | 
			
		||||
    if (sizeofBlob < journal->info.program_unit) {
 | 
			
		||||
        return JOURNAL_STATUS_SMALL_LOG_REQUEST;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return JOURNAL_STATUS_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t flashJournalStrategySequential_commit_sanityChecks(SequentialFlashJournal_t *journal)
 | 
			
		||||
{
 | 
			
		||||
    if (journal == NULL) {
 | 
			
		||||
        return JOURNAL_STATUS_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
    if (journal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY) {
 | 
			
		||||
        if (journal->prevCommand != FLASH_JOURNAL_OPCODE_LOG_BLOB) {
 | 
			
		||||
            return JOURNAL_STATUS_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
        if ((journal->log.mtdOffset       == ARM_STORAGE_INVALID_OFFSET) ||
 | 
			
		||||
            (journal->log.mtdTailOffset   == ARM_STORAGE_INVALID_OFFSET) ||
 | 
			
		||||
            (journal->log.mtdTailOffset    < journal->log.mtdOffset)     ||
 | 
			
		||||
            (journal->log.tail.sizeofBlob == 0)                          ||
 | 
			
		||||
            (journal->log.tail.sizeofBlob  > journal->info.capacity)) {
 | 
			
		||||
            return JOURNAL_STATUS_ERROR; /* journal is in an un-expected state. */
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return JOURNAL_STATUS_OK;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,12 +15,15 @@
 | 
			
		|||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "flash-journal-strategy-sequential/flash_journal_crc.h"
 | 
			
		||||
#include "support_funcs.h"
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
static inline int32_t mtdGetStartAddr(ARM_DRIVER_STORAGE *mtd, uint64_t *startAddrP)
 | 
			
		||||
struct FormatInfo_t formatInfoSingleton;
 | 
			
		||||
 | 
			
		||||
int32_t mtdGetStartAddr(ARM_DRIVER_STORAGE *mtd, uint64_t *startAddrP)
 | 
			
		||||
{
 | 
			
		||||
    ARM_STORAGE_BLOCK mtdBlock;
 | 
			
		||||
    if ((mtd->GetNextBlock(NULL, &mtdBlock)) != ARM_DRIVER_OK) {
 | 
			
		||||
| 
						 | 
				
			
			@ -34,130 +37,295 @@ static inline int32_t mtdGetStartAddr(ARM_DRIVER_STORAGE *mtd, uint64_t *startAd
 | 
			
		|||
    return JOURNAL_STATUS_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t discoverLatestLoggedBlob(SequentialFlashJournal_t *journal)
 | 
			
		||||
/**
 | 
			
		||||
 * Check the sanity of a given slot
 | 
			
		||||
 * @param       journal
 | 
			
		||||
 * @param       slotOffset
 | 
			
		||||
 * @param [out] headSequenceNumberP
 | 
			
		||||
 *                  sequence number of the slot as read from the header.
 | 
			
		||||
 * @param [out] tailP
 | 
			
		||||
 *                  the tail of the slot
 | 
			
		||||
 * @return 1 if the slot is valid; i.e. if head and tail match, and if CRC32 agrees.
 | 
			
		||||
 */
 | 
			
		||||
int32_t slotIsSane(SequentialFlashJournal_t        *journal,
 | 
			
		||||
                   uint64_t                         slotOffset,
 | 
			
		||||
                   uint32_t                        *headSequenceNumberP,
 | 
			
		||||
                   SequentialFlashJournalLogTail_t *tailP)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
    ARM_DRIVER_STORAGE *mtd = journal->mtd;
 | 
			
		||||
 | 
			
		||||
    SequentialFlashJournalLogHead_t head;
 | 
			
		||||
    /* TODO: add support for asynchronous read */
 | 
			
		||||
    if (((rc = mtd->ReadData(slotOffset, &head, sizeof(SequentialFlashJournalLogHead_t))) < ARM_DRIVER_OK) ||
 | 
			
		||||
        (rc != sizeof(SequentialFlashJournalLogHead_t))) {
 | 
			
		||||
        if ((rc == ARM_DRIVER_OK) && (journal->mtdCapabilities.asynchronous_ops)) {
 | 
			
		||||
            return JOURNAL_STATUS_UNSUPPORTED;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return JOURNAL_STATUS_STORAGE_IO_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* compute the CRC32 of the header */
 | 
			
		||||
    flashJournalCrcReset();
 | 
			
		||||
    flashJournalCrcCummulative((const unsigned char *)&head, sizeof(SequentialFlashJournalLogHead_t));
 | 
			
		||||
 | 
			
		||||
    // printf("head->version: %lu\n", journal->initScan.head.version);
 | 
			
		||||
    // printf("head->magic: %lx\n", journal->initScan.head.magic);
 | 
			
		||||
    // printf("head->sequenceNumber: %lu\n", journal->initScan.head.sequenceNumber);
 | 
			
		||||
    // printf("head->reserved: %lu\n", journal->initScan.head.reserved);
 | 
			
		||||
 | 
			
		||||
    if (SEQUENTIAL_JOURNAL_VALID_HEAD(&head)) {
 | 
			
		||||
        *headSequenceNumberP = head.sequenceNumber;
 | 
			
		||||
        // printf("found valid header with sequenceNumber %" PRIu32 "\n", *headSequenceNumberP);
 | 
			
		||||
 | 
			
		||||
        uint64_t tailoffset = slotOffset
 | 
			
		||||
                              - ((slotOffset - SLOT_ADDRESS(journal, 0)) % journal->sizeofSlot)
 | 
			
		||||
                              + journal->sizeofSlot
 | 
			
		||||
                              - sizeof(SequentialFlashJournalLogTail_t);
 | 
			
		||||
        // printf("hoping to read a tail at offset %lu\n", (uint32_t)tailoffset);
 | 
			
		||||
 | 
			
		||||
        /* TODO: add support for asynchronous read */
 | 
			
		||||
        if (((rc = mtd->ReadData(tailoffset, tailP, sizeof(SequentialFlashJournalLogTail_t))) < ARM_DRIVER_OK) ||
 | 
			
		||||
            (rc != sizeof(SequentialFlashJournalLogTail_t))) {
 | 
			
		||||
            return JOURNAL_STATUS_STORAGE_IO_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (SEQUENTIAL_JOURNAL_VALID_TAIL(tailP) && (tailP->sequenceNumber == *headSequenceNumberP)) {
 | 
			
		||||
            // printf("found valid tail\n");
 | 
			
		||||
 | 
			
		||||
            /* iterate over the body of the slot computing CRC */
 | 
			
		||||
            #define CRC_CHUNK_SIZE 64
 | 
			
		||||
            uint8_t crcBuffer[CRC_CHUNK_SIZE];
 | 
			
		||||
            uint64_t bodyIndex = 0;
 | 
			
		||||
            uint64_t bodyOffset = slotOffset + sizeof(SequentialFlashJournalLogHead_t);
 | 
			
		||||
            while (bodyIndex < tailP->sizeofBlob) {
 | 
			
		||||
                size_t sizeofReadOperation;
 | 
			
		||||
                if ((tailP->sizeofBlob - bodyIndex) > CRC_CHUNK_SIZE) {
 | 
			
		||||
                    sizeofReadOperation = CRC_CHUNK_SIZE;
 | 
			
		||||
                } else {
 | 
			
		||||
                    sizeofReadOperation = (tailP->sizeofBlob - bodyIndex);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                /* TODO: add support for asynchronous read */
 | 
			
		||||
                rc = mtd->ReadData(bodyOffset + bodyIndex, crcBuffer, sizeofReadOperation);
 | 
			
		||||
                if (rc != (int32_t)sizeofReadOperation) {
 | 
			
		||||
                    return JOURNAL_STATUS_STORAGE_IO_ERROR;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                bodyIndex += sizeofReadOperation;
 | 
			
		||||
                flashJournalCrcCummulative(crcBuffer, sizeofReadOperation);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* compute CRC32 over the tail */
 | 
			
		||||
            /* extract existing CRC32 from the tail. The CRC32 field in the tail needs to contain 0 before CRC32 can be computed over it. */
 | 
			
		||||
            uint32_t expectedCRC32 = tailP->crc32;
 | 
			
		||||
            tailP->crc32 = 0;
 | 
			
		||||
 | 
			
		||||
            uint32_t crc32 = flashJournalCrcCummulative((const unsigned char *)tailP, sizeof(SequentialFlashJournalLogTail_t));
 | 
			
		||||
            flashJournalCrcReset();
 | 
			
		||||
            // printf("expectedCRC32: 0x%x, computedCRC32: 0x%x\n", expectedCRC32, crc32);
 | 
			
		||||
            if (crc32 == expectedCRC32) {
 | 
			
		||||
                return 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return JOURNAL_STATUS_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t setupSequentialJournalHeader(SequentialFlashJournalHeader_t *headerP, ARM_DRIVER_STORAGE *mtd, uint64_t totalSize, uint32_t numSlots)
 | 
			
		||||
{
 | 
			
		||||
    ARM_STORAGE_INFO mtdInfo;
 | 
			
		||||
    if (mtd->GetInfo(&mtdInfo) < ARM_DRIVER_OK) {
 | 
			
		||||
        return JOURNAL_STATUS_STORAGE_API_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    headerP->genericHeader.magic        = FLASH_JOURNAL_HEADER_MAGIC;
 | 
			
		||||
    headerP->genericHeader.version      = FLASH_JOURNAL_HEADER_VERSION;
 | 
			
		||||
    headerP->genericHeader.sizeofHeader = sizeof(SequentialFlashJournalHeader_t);
 | 
			
		||||
 | 
			
		||||
    /* Determine 'journalOffset'.
 | 
			
		||||
     * Constraint: journal header should start and terminate at an erase-boundary
 | 
			
		||||
     * (so that slot-0 can be erased independently), and also a program-unit boundary.
 | 
			
		||||
     */
 | 
			
		||||
    headerP->genericHeader.journalOffset = roundUp_uint32(headerP->genericHeader.sizeofHeader, LCM_OF_ALL_ERASE_UNITS);
 | 
			
		||||
    if ((headerP->genericHeader.journalOffset % mtdInfo.program_unit) != 0) {
 | 
			
		||||
        //printf("setupSequentialJournalHeader: journalOffset is not a multiple of MTD's program_unit\r\n");
 | 
			
		||||
        return JOURNAL_STATUS_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    headerP->magic    = SEQUENTIAL_FLASH_JOURNAL_HEADER_MAGIC;
 | 
			
		||||
    headerP->version  = SEQUENTIAL_FLASH_JOURNAL_HEADER_VERSION;
 | 
			
		||||
    headerP->numSlots = numSlots;
 | 
			
		||||
 | 
			
		||||
    /* Determine 'sizeofSlot'.
 | 
			
		||||
     * Constraint: slot-size should be a multiple of the erase-units of all involved storage blocks.
 | 
			
		||||
     */
 | 
			
		||||
    uint64_t spaceAvailableForSlots = totalSize - headerP->genericHeader.journalOffset;
 | 
			
		||||
    headerP->sizeofSlot = roundDown_uint32(spaceAvailableForSlots / numSlots, LCM_OF_ALL_ERASE_UNITS);
 | 
			
		||||
    if (headerP->sizeofSlot == 0) {
 | 
			
		||||
        //printf("setupSequentialJournalHeader: not enough space to create %" PRIu32 " slots\r\n", numSlots);
 | 
			
		||||
        return JOURNAL_STATUS_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    headerP->genericHeader.totalSize = headerP->genericHeader.journalOffset + (headerP->sizeofSlot * numSlots);
 | 
			
		||||
    //printf("setupSequentialJournalHeader: header size = %" PRIu32 ", journalOffset = %" PRIu32 ", sizeofSlot = %" PRIu32 ", totalSize = %lu\n", headerP->genericHeader.sizeofHeader, headerP->genericHeader.journalOffset, headerP->sizeofSlot, (uint32_t)headerP->genericHeader.totalSize);
 | 
			
		||||
 | 
			
		||||
    /* compute checksum over the entire header */
 | 
			
		||||
    headerP->genericHeader.checksum = 0;
 | 
			
		||||
    flashJournalCrcReset();
 | 
			
		||||
    headerP->genericHeader.checksum = flashJournalCrcCummulative((const unsigned char *)&headerP->genericHeader, sizeof(SequentialFlashJournalLogHead_t));
 | 
			
		||||
 | 
			
		||||
    return JOURNAL_STATUS_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t discoverLatestLoggedBlob(SequentialFlashJournal_t *journal)
 | 
			
		||||
{
 | 
			
		||||
    /* reset top level journal metadata prior to scanning headers. */
 | 
			
		||||
    journal->nextSequenceNumber       = SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER; /* we are currently unaware of previously written blobs */
 | 
			
		||||
    journal->currentBlobIndex         = SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS;
 | 
			
		||||
    journal->currentBlobIndex         = journal->numSlots;
 | 
			
		||||
    journal->info.sizeofJournaledBlob = 0;
 | 
			
		||||
 | 
			
		||||
    /* begin header-scan from the first block of the MTD */
 | 
			
		||||
    ARM_DRIVER_STORAGE *mtd = journal->mtd;
 | 
			
		||||
    if ((rc = mtdGetStartAddr(journal->mtd, &journal->mtdStartOffset)) != JOURNAL_STATUS_OK) {
 | 
			
		||||
        return rc;
 | 
			
		||||
    }
 | 
			
		||||
    journal->initScan.currentOffset = journal->mtdStartOffset;
 | 
			
		||||
    journal->state                  = SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS;
 | 
			
		||||
    journal->initScan.currentOffset   = SLOT_ADDRESS(journal, 0);
 | 
			
		||||
    journal->state                    = SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS;
 | 
			
		||||
 | 
			
		||||
    // printf("start of init scan\n");
 | 
			
		||||
    // printf("discoverLatestLoggedBlob: start of init scan\n");
 | 
			
		||||
    for (unsigned blobIndex = 0;
 | 
			
		||||
         blobIndex < SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS;
 | 
			
		||||
         blobIndex++, journal->initScan.currentOffset += journal->sequentialSkip) {
 | 
			
		||||
        // printf("blob index %u\n", blobIndex);
 | 
			
		||||
         blobIndex < journal->numSlots;
 | 
			
		||||
         blobIndex++, journal->initScan.currentOffset += journal->sizeofSlot) {
 | 
			
		||||
        // printf("discoverLatestLoggedBlob: blob index %u\n", blobIndex);
 | 
			
		||||
        /* TODO: it is possible that the header structure spans multiple blocks, needing multiple reads. */
 | 
			
		||||
 | 
			
		||||
        if (((rc = mtd->ReadData(journal->initScan.currentOffset, &journal->initScan.head, sizeof(SequentialFlashJournalLogHead_t))) < ARM_DRIVER_OK) ||
 | 
			
		||||
            (rc != sizeof(SequentialFlashJournalLogHead_t))) {
 | 
			
		||||
            /* TODO: add support for asynchronous scan */
 | 
			
		||||
            if ((rc == ARM_DRIVER_OK) && (journal->mtdCapabilities.asynchronous_ops)) {
 | 
			
		||||
                return JOURNAL_STATUS_UNSUPPORTED;
 | 
			
		||||
        if (slotIsSane(journal,
 | 
			
		||||
                       journal->initScan.currentOffset,
 | 
			
		||||
                       &journal->initScan.headSequenceNumber,
 | 
			
		||||
                       &journal->initScan.tail) == 1) {
 | 
			
		||||
            // printf("found valid blob with sequence number %lu\n", journal->initScan.headSequenceNumber);
 | 
			
		||||
            uint32_t nextSequenceNumber = journal->initScan.headSequenceNumber + 1;
 | 
			
		||||
            if (nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) {
 | 
			
		||||
                nextSequenceNumber = 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return JOURNAL_STATUS_STORAGE_IO_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
        // printf("head->version: %lu\n", journal->initScan.head.version);
 | 
			
		||||
        // printf("head->magic: %lx\n", journal->initScan.head.magic);
 | 
			
		||||
        // printf("head->sequenceNumber: %lu\n", journal->initScan.head.sequenceNumber);
 | 
			
		||||
        // printf("head->reserved: %lu\n", journal->initScan.head.reserved);
 | 
			
		||||
 | 
			
		||||
        if (SEQUENTIAL_JOURNAL_VALID_HEAD(&journal->initScan.head)) {
 | 
			
		||||
            journal->initScan.headSequenceNumber = journal->initScan.head.sequenceNumber;
 | 
			
		||||
            // printf("found valid header with sequenceNumber %lu\n", journal->initScan.headSequenceNumber);
 | 
			
		||||
 | 
			
		||||
            uint64_t tailoffset = journal->initScan.currentOffset
 | 
			
		||||
                                  - ((journal->initScan.currentOffset - journal->mtdStartOffset) % journal->sequentialSkip)
 | 
			
		||||
                                  + journal->sequentialSkip
 | 
			
		||||
                                  - sizeof(SequentialFlashJournalLogTail_t);
 | 
			
		||||
 | 
			
		||||
            // printf("hoping to read a tail at offset %lu\n", (uint32_t)tailoffset);
 | 
			
		||||
            if (((rc = mtd->ReadData(tailoffset, &journal->initScan.tail, sizeof(SequentialFlashJournalLogTail_t))) < ARM_DRIVER_OK) ||
 | 
			
		||||
                (rc != sizeof(SequentialFlashJournalLogTail_t))) {
 | 
			
		||||
                return JOURNAL_STATUS_STORAGE_IO_ERROR;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (SEQUENTIAL_JOURNAL_VALID_TAIL(&journal->initScan.tail) &&
 | 
			
		||||
                (journal->initScan.tail.sequenceNumber == journal->initScan.headSequenceNumber)) {
 | 
			
		||||
                // printf("found valid blob with sequence number %lu\n", journal->initScan.headSequenceNumber);
 | 
			
		||||
                uint32_t nextSequenceNumber = journal->initScan.headSequenceNumber + 1;
 | 
			
		||||
                if (nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) {
 | 
			
		||||
                    nextSequenceNumber = 0;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if ((journal->nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) ||
 | 
			
		||||
                    /* We take advantage of properties of unsigned arithmetic in the following
 | 
			
		||||
                     * expression.
 | 
			
		||||
                     *
 | 
			
		||||
                     * We want to calculate if (nextSequenceNumber > journal->nextSequenceNumber),
 | 
			
		||||
                     * instead we use the expression ((nextSequenceNumber - journal->nextSequenceNumber) > 0)
 | 
			
		||||
                     * to take wraparounds into account.
 | 
			
		||||
                     */
 | 
			
		||||
                    ((int32_t)(nextSequenceNumber - journal->nextSequenceNumber) > 0)) {
 | 
			
		||||
                    journal->currentBlobIndex         = blobIndex;
 | 
			
		||||
                    journal->nextSequenceNumber       = nextSequenceNumber;
 | 
			
		||||
                    journal->info.sizeofJournaledBlob = journal->initScan.tail.sizeofBlob;
 | 
			
		||||
                    // printf("discoverLatestLoggedBlob: index %lu, sizeofBlob: %lu, nextSequenceNumber: %lu\n",
 | 
			
		||||
                    //        journal->currentBlobIndex, (uint32_t)journal->info.sizeofJournaledBlob, journal->nextSequenceNumber);
 | 
			
		||||
                }
 | 
			
		||||
            /* Have we found the best of the slots seen so far? */
 | 
			
		||||
            if ((journal->nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) ||
 | 
			
		||||
                /* We take advantage of properties of unsigned arithmetic in the following
 | 
			
		||||
                 * expression.
 | 
			
		||||
                 *
 | 
			
		||||
                 * We want to calculate if (nextSequenceNumber > journal->nextSequenceNumber),
 | 
			
		||||
                 * instead we use the expression ((nextSequenceNumber - journal->nextSequenceNumber) > 0)
 | 
			
		||||
                 * to take wraparounds into account.
 | 
			
		||||
                 */
 | 
			
		||||
                ((int32_t)(nextSequenceNumber - journal->nextSequenceNumber) > 0)) {
 | 
			
		||||
                journal->currentBlobIndex         = blobIndex;
 | 
			
		||||
                journal->nextSequenceNumber       = nextSequenceNumber;
 | 
			
		||||
                journal->info.sizeofJournaledBlob = journal->initScan.tail.sizeofBlob;
 | 
			
		||||
                // printf("discoverLatestLoggedBlob: index %lu, sizeofBlob: %lu, nextSequenceNumber: %lu\n",
 | 
			
		||||
                //        journal->currentBlobIndex, (uint32_t)journal->info.sizeofJournaledBlob, journal->nextSequenceNumber);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // printf("finished init scan\n");
 | 
			
		||||
    // printf("discoverLatestLoggedBlob: finished init scan\n");
 | 
			
		||||
 | 
			
		||||
    /* Handle the case where our scan hasn't yielded any results. */
 | 
			
		||||
    if (journal->nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) {
 | 
			
		||||
        // printf("discoverLatestLoggedBlob: initializing to defaults\n");
 | 
			
		||||
        journal->currentBlobIndex   = (uint32_t)-1; /* to be incremented to 0 during the first attempt to log(). */
 | 
			
		||||
        journal->nextSequenceNumber = 0;
 | 
			
		||||
 | 
			
		||||
        /* setup info.current_program_unit */
 | 
			
		||||
        ARM_STORAGE_BLOCK storageBlock;
 | 
			
		||||
        if ((rc = journal->mtd->GetBlock(journal->mtdStartOffset, &storageBlock)) != ARM_DRIVER_OK) {
 | 
			
		||||
            return JOURNAL_STATUS_STORAGE_API_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
 | 
			
		||||
 | 
			
		||||
    return JOURNAL_STATUS_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Progress the state machine for the 'format' operation. This method can also be called from an interrupt handler.
 | 
			
		||||
 * @return  < JOURNAL_STATUS_OK for error
 | 
			
		||||
 *          = JOURNAL_STATUS_OK to signal pending asynchronous activity
 | 
			
		||||
 *          > JOURNAL_STATUS_OK for completion
 | 
			
		||||
 */
 | 
			
		||||
int32_t flashJournalStrategySequential_format_progress(int32_t status, ARM_STORAGE_OPERATION operationWhichJustFinshed)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
    size_t sizeofWrite = roundUp_uint32(formatInfoSingleton.header.genericHeader.sizeofHeader, formatInfoSingleton.mtdProgramUnit);
 | 
			
		||||
    size_t sizeofErase = roundUp_uint32(formatInfoSingleton.header.genericHeader.sizeofHeader, LCM_OF_ALL_ERASE_UNITS);
 | 
			
		||||
    switch (operationWhichJustFinshed) {
 | 
			
		||||
        case ARM_STORAGE_OPERATION_INITIALIZE:
 | 
			
		||||
            if (status != ARM_DRIVER_OK) {
 | 
			
		||||
                return JOURNAL_STATUS_STORAGE_API_ERROR;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // printf("erasing %u bytes from offset %u\n", roundUp_uint32(header.genericHeader.sizeofHeader, mtdInfo.program_unit), mtdAddr);
 | 
			
		||||
            rc = (formatInfoSingleton.mtd)->Erase(formatInfoSingleton.mtdAddr, sizeofErase);
 | 
			
		||||
            if (rc < ARM_DRIVER_OK) {
 | 
			
		||||
                if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
 | 
			
		||||
                    return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
 | 
			
		||||
                } else {
 | 
			
		||||
                    return JOURNAL_STATUS_STORAGE_IO_ERROR;
 | 
			
		||||
                }
 | 
			
		||||
            } else if (rc == ARM_DRIVER_OK) {
 | 
			
		||||
                return JOURNAL_STATUS_OK; /* An asynchronous operation is pending; it will result in a completion callback
 | 
			
		||||
                                           * where the rest of processing will take place. */
 | 
			
		||||
            }
 | 
			
		||||
            /* handle synchronous completion of programData */
 | 
			
		||||
            status = rc;
 | 
			
		||||
 | 
			
		||||
            /* intentional fall-through */
 | 
			
		||||
 | 
			
		||||
        case ARM_STORAGE_OPERATION_ERASE:
 | 
			
		||||
            if (status != (int32_t)sizeofErase) {
 | 
			
		||||
                return JOURNAL_STATUS_STORAGE_IO_ERROR;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // printf("calling ProgramData at address %u for %u bytes\n",
 | 
			
		||||
            //        formatInfoSingleton.mtdAddr, roundUp_uint32(formatInfoSingleton.header.genericHeader.sizeofHeader, formatInfoSingleton.mtdProgramUnit));
 | 
			
		||||
            rc = (formatInfoSingleton.mtd)->ProgramData(formatInfoSingleton.mtdAddr, &(formatInfoSingleton.header), sizeofWrite);
 | 
			
		||||
            if (rc < ARM_DRIVER_OK) {
 | 
			
		||||
                if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
 | 
			
		||||
                    return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
 | 
			
		||||
                } else {
 | 
			
		||||
                    return JOURNAL_STATUS_STORAGE_IO_ERROR;
 | 
			
		||||
                }
 | 
			
		||||
            } else if (rc == ARM_DRIVER_OK) {
 | 
			
		||||
                return JOURNAL_STATUS_OK; /* An asynchronous operation is pending; it will result in a completion callback
 | 
			
		||||
                                           * where the rest of processing will take place. */
 | 
			
		||||
            }
 | 
			
		||||
            /* handle synchronous completion of programData */
 | 
			
		||||
            status = rc;
 | 
			
		||||
 | 
			
		||||
            /* intentional fall-through */
 | 
			
		||||
 | 
			
		||||
        case ARM_STORAGE_OPERATION_PROGRAM_DATA:
 | 
			
		||||
            if (status != (int32_t)sizeofWrite) {
 | 
			
		||||
                return JOURNAL_STATUS_STORAGE_IO_ERROR;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return 1; /* acknowledge the completion of create */
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            return JOURNAL_STATUS_STORAGE_API_ERROR; /* we don't expect to be here */
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t flashJournalStrategySequential_reset_progress(void)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
    SequentialFlashJournal_t *journal = activeJournal;
 | 
			
		||||
 | 
			
		||||
    if (journal->mtdCapabilities.erase_all) {
 | 
			
		||||
        if ((rc = journal->mtd->EraseAll()) < ARM_DRIVER_OK) {
 | 
			
		||||
            journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
 | 
			
		||||
    if ((rc = journal->mtd->Erase(SLOT_ADDRESS(journal, 0), journal->numSlots * journal->sizeofSlot)) < ARM_DRIVER_OK) {
 | 
			
		||||
        journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
 | 
			
		||||
        if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
 | 
			
		||||
            return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
 | 
			
		||||
        } else {
 | 
			
		||||
            return JOURNAL_STATUS_STORAGE_IO_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
        if ((journal->mtdCapabilities.asynchronous_ops) && (rc == ARM_DRIVER_OK)) {
 | 
			
		||||
            return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */
 | 
			
		||||
        }
 | 
			
		||||
        /* else we fall through to handle synchronous completion */
 | 
			
		||||
    } else {
 | 
			
		||||
        if ((rc = journal->mtd->Erase(journal->mtdStartOffset, SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS * journal->sequentialSkip)) < ARM_DRIVER_OK) {
 | 
			
		||||
            journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
 | 
			
		||||
            return JOURNAL_STATUS_STORAGE_IO_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
        if ((journal->mtdCapabilities.asynchronous_ops) && (rc == ARM_DRIVER_OK)) {
 | 
			
		||||
            printf("eturning JOURNAL_STATUS_OK\n");
 | 
			
		||||
            return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */
 | 
			
		||||
        }
 | 
			
		||||
        /* else we fall through to handle synchronous completion */
 | 
			
		||||
    }
 | 
			
		||||
    if ((journal->mtdCapabilities.asynchronous_ops) && (rc == ARM_DRIVER_OK)) {
 | 
			
		||||
        //printf("eturning JOURNAL_STATUS_OK\n");
 | 
			
		||||
        return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */
 | 
			
		||||
    }
 | 
			
		||||
    /* else we fall through to handle synchronous completion */
 | 
			
		||||
 | 
			
		||||
    journal->nextSequenceNumber       = 0;
 | 
			
		||||
    journal->currentBlobIndex         = (uint32_t)-1;
 | 
			
		||||
| 
						 | 
				
			
			@ -179,11 +347,11 @@ int32_t flashJournalStrategySequential_read_progress(void)
 | 
			
		|||
    ARM_STORAGE_BLOCK storageBlock;
 | 
			
		||||
 | 
			
		||||
    if ((journal->read.amountLeftToRead) &&
 | 
			
		||||
        ((rc = journal->mtd->GetBlock(journal->read.offset, &storageBlock)) != ARM_DRIVER_OK)) {
 | 
			
		||||
        ((rc = journal->mtd->GetBlock(journal->read.mtdOffset, &storageBlock)) != ARM_DRIVER_OK)) {
 | 
			
		||||
        journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
 | 
			
		||||
        return JOURNAL_STATUS_STORAGE_API_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    uint64_t storageBlockAvailableCapacity = storageBlock.size - (journal->read.offset - storageBlock.addr);
 | 
			
		||||
    uint64_t storageBlockAvailableCapacity = storageBlock.size - (journal->read.mtdOffset - storageBlock.addr);
 | 
			
		||||
 | 
			
		||||
    while (journal->read.amountLeftToRead) {
 | 
			
		||||
        while (!storageBlockAvailableCapacity) {
 | 
			
		||||
| 
						 | 
				
			
			@ -191,7 +359,7 @@ int32_t flashJournalStrategySequential_read_progress(void)
 | 
			
		|||
                journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
 | 
			
		||||
                return JOURNAL_STATUS_ERROR; /* We ran out of storage blocks. Journal is in an un-expected state. */
 | 
			
		||||
            }
 | 
			
		||||
            journal->read.offset          =  storageBlock.addr; /* This should not be necessary since we assume
 | 
			
		||||
            journal->read.mtdOffset       =  storageBlock.addr; /* This should not be necessary since we assume
 | 
			
		||||
                                                                 * storage map manages a contiguous address space. */
 | 
			
		||||
            storageBlockAvailableCapacity = storageBlock.size;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -201,8 +369,8 @@ int32_t flashJournalStrategySequential_read_progress(void)
 | 
			
		|||
                            journal->read.amountLeftToRead : storageBlockAvailableCapacity;
 | 
			
		||||
 | 
			
		||||
        /* perform the IO */
 | 
			
		||||
        //printf("reading %lu bytes at offset %lu\n", xfer, (uint32_t)journal->read.offset);
 | 
			
		||||
        rc = journal->mtd->ReadData(journal->read.offset, journal->read.dataBeingRead, xfer);
 | 
			
		||||
        //printf("reading %lu bytes at offset %lu\n", xfer, (uint32_t)journal->read.mtdOffset);
 | 
			
		||||
        rc = journal->mtd->ReadData(journal->read.mtdOffset, journal->read.dataBeingRead, xfer);
 | 
			
		||||
        if (rc < ARM_DRIVER_OK) {
 | 
			
		||||
            journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
 | 
			
		||||
            return JOURNAL_STATUS_STORAGE_IO_ERROR;
 | 
			
		||||
| 
						 | 
				
			
			@ -211,10 +379,10 @@ int32_t flashJournalStrategySequential_read_progress(void)
 | 
			
		|||
            return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */
 | 
			
		||||
        } else {
 | 
			
		||||
            /* synchronous completion. 'rc' contains the actual number of bytes transferred. */
 | 
			
		||||
            journal->read.offset           += rc;
 | 
			
		||||
            journal->read.mtdOffset        += rc;
 | 
			
		||||
            journal->read.amountLeftToRead -= rc;
 | 
			
		||||
            journal->read.dataBeingRead    += rc;
 | 
			
		||||
            journal->read.totalDataRead    += rc;
 | 
			
		||||
            journal->read.logicalOffset    += rc;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -222,6 +390,12 @@ int32_t flashJournalStrategySequential_read_progress(void)
 | 
			
		|||
    return (journal->read.dataBeingRead - journal->read.blob);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Progress the state machine for the 'log' operation. This method can also be called from an interrupt handler.
 | 
			
		||||
 * @return  < JOURNAL_STATUS_OK for error
 | 
			
		||||
 *          = JOURNAL_STATUS_OK to signal pending asynchronous activity
 | 
			
		||||
 *          > JOURNAL_STATUS_OK for completion
 | 
			
		||||
 */
 | 
			
		||||
int32_t flashJournalStrategySequential_log_progress(void)
 | 
			
		||||
{
 | 
			
		||||
    SequentialFlashJournal_t *journal = activeJournal;
 | 
			
		||||
| 
						 | 
				
			
			@ -234,7 +408,7 @@ int32_t flashJournalStrategySequential_log_progress(void)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    uint32_t blobIndexBeingLogged = journal->currentBlobIndex + 1;
 | 
			
		||||
    if (blobIndexBeingLogged == SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS) {
 | 
			
		||||
    if (blobIndexBeingLogged == journal->numSlots) {
 | 
			
		||||
        blobIndexBeingLogged = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -242,22 +416,24 @@ int32_t flashJournalStrategySequential_log_progress(void)
 | 
			
		|||
        int32_t rc;
 | 
			
		||||
 | 
			
		||||
        if (journal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE) {
 | 
			
		||||
            uint64_t amountLeftToErase = journal->mtdStartOffset
 | 
			
		||||
                                         + (blobIndexBeingLogged + 1) * journal->sequentialSkip
 | 
			
		||||
                                         - journal->log.eraseOffset;
 | 
			
		||||
            uint64_t amountLeftToErase = SLOT_ADDRESS(journal, blobIndexBeingLogged + 1) - journal->log.mtdEraseOffset;
 | 
			
		||||
            // printf("journal state: erasing; offset %lu [size %lu]\n",
 | 
			
		||||
            //        (uint32_t)journal->log.eraseOffset, (uint32_t)amountLeftToErase);
 | 
			
		||||
            while (amountLeftToErase) {
 | 
			
		||||
                if ((rc = journal->mtd->Erase(journal->log.eraseOffset, amountLeftToErase)) < ARM_DRIVER_OK) {
 | 
			
		||||
                if ((rc = journal->mtd->Erase(journal->log.mtdEraseOffset, amountLeftToErase)) < ARM_DRIVER_OK) {
 | 
			
		||||
                    journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
 | 
			
		||||
                    return JOURNAL_STATUS_ERROR; /* We ran out of storage blocks. Journal is in an un-expected state. */
 | 
			
		||||
                    if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
 | 
			
		||||
                        return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        return JOURNAL_STATUS_ERROR;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                if ((journal->mtdCapabilities.asynchronous_ops) && (rc == ARM_DRIVER_OK)) {
 | 
			
		||||
                    return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */
 | 
			
		||||
                } else {
 | 
			
		||||
                    /* synchronous completion. */
 | 
			
		||||
                    journal->log.eraseOffset += rc;
 | 
			
		||||
                    amountLeftToErase        -= rc;
 | 
			
		||||
                    journal->log.mtdEraseOffset += rc;
 | 
			
		||||
                    amountLeftToErase           -= rc;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -273,11 +449,11 @@ int32_t flashJournalStrategySequential_log_progress(void)
 | 
			
		|||
                }
 | 
			
		||||
 | 
			
		||||
                /* check for alignment of next log offset with program_unit */
 | 
			
		||||
                if ((rc = journal->mtd->GetBlock(journal->log.offset, &storageBlock)) != ARM_DRIVER_OK) {
 | 
			
		||||
                if ((rc = journal->mtd->GetBlock(journal->log.mtdOffset, &storageBlock)) != ARM_DRIVER_OK) {
 | 
			
		||||
                    journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
 | 
			
		||||
                    return JOURNAL_STATUS_STORAGE_API_ERROR;
 | 
			
		||||
                }
 | 
			
		||||
                if ((journal->log.offset - storageBlock.addr) % journal->info.program_unit) {
 | 
			
		||||
                if ((journal->log.mtdOffset - storageBlock.addr) % journal->info.program_unit) {
 | 
			
		||||
                    journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
 | 
			
		||||
                    return JOURNAL_STATUS_ERROR; /* Program offset doesn't align with info.program_unit. This would result in an IO error if attempted. */
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -286,17 +462,21 @@ int32_t flashJournalStrategySequential_log_progress(void)
 | 
			
		|||
                xfer -= xfer % journal->info.program_unit; /* align transfer-size with program_unit. */
 | 
			
		||||
 | 
			
		||||
                /* perform the IO */
 | 
			
		||||
                // printf("programming %lu bytes at offset %lu\n", xfer, (uint32_t)journal->log.offset);
 | 
			
		||||
                rc = journal->mtd->ProgramData(journal->log.offset, journal->log.dataBeingLogged, xfer);
 | 
			
		||||
                // printf("programming %lu bytes at offset %lu\n", xfer, (uint32_t)journal->log.mtdOffset);
 | 
			
		||||
                rc = journal->mtd->ProgramData(journal->log.mtdOffset, journal->log.dataBeingLogged, xfer);
 | 
			
		||||
                if (rc < ARM_DRIVER_OK) {
 | 
			
		||||
                    journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
 | 
			
		||||
                    return JOURNAL_STATUS_STORAGE_IO_ERROR;
 | 
			
		||||
                    if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
 | 
			
		||||
                        return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        return JOURNAL_STATUS_STORAGE_IO_ERROR;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                if ((journal->mtdCapabilities.asynchronous_ops) && (rc == ARM_DRIVER_OK)) {
 | 
			
		||||
                    return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */
 | 
			
		||||
                } else {
 | 
			
		||||
                    /* synchronous completion. 'rc' contains the actual number of bytes transferred. */
 | 
			
		||||
                    journal->log.offset          += rc;
 | 
			
		||||
                    journal->log.mtdOffset       += rc;
 | 
			
		||||
                    journal->log.amountLeftToLog -= rc;
 | 
			
		||||
                    journal->log.dataBeingLogged += rc;
 | 
			
		||||
                    if (journal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY) {
 | 
			
		||||
| 
						 | 
				
			
			@ -312,7 +492,7 @@ int32_t flashJournalStrategySequential_log_progress(void)
 | 
			
		|||
        switch (journal->state) {
 | 
			
		||||
            case SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE:
 | 
			
		||||
                journal->state                   = SEQUENTIAL_JOURNAL_STATE_LOGGING_HEAD;
 | 
			
		||||
                journal->log.offset              = journal->mtdStartOffset + blobIndexBeingLogged * journal->sequentialSkip;
 | 
			
		||||
                journal->log.mtdOffset           = SLOT_ADDRESS(journal, blobIndexBeingLogged);
 | 
			
		||||
                journal->log.head.version        = SEQUENTIAL_FLASH_JOURNAL_VERSION;
 | 
			
		||||
                journal->log.head.magic          = SEQUENTIAL_FLASH_JOURNAL_MAGIC;
 | 
			
		||||
                journal->log.head.sequenceNumber = journal->nextSequenceNumber;
 | 
			
		||||
| 
						 | 
				
			
			@ -322,23 +502,32 @@ int32_t flashJournalStrategySequential_log_progress(void)
 | 
			
		|||
                // printf("newstate: program HEAD; amount to log %u\n", journal->log.amountLeftToLog);
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case SEQUENTIAL_JOURNAL_STATE_LOGGING_HEAD: /* switch to writing the body */
 | 
			
		||||
            case SEQUENTIAL_JOURNAL_STATE_LOGGING_HEAD: /* we've finished writing the head */
 | 
			
		||||
                /* compute CRC32 on the header */
 | 
			
		||||
                flashJournalCrcReset();
 | 
			
		||||
                flashJournalCrcCummulative((const unsigned char *)&journal->log.head, sizeof(SequentialFlashJournalLogHead_t));
 | 
			
		||||
 | 
			
		||||
                /* switch to writing the body */
 | 
			
		||||
 | 
			
		||||
                /* Prepare for the tail to be written out at a later time.
 | 
			
		||||
                 * This will only be done once Commit() is called. */
 | 
			
		||||
                journal->log.tailOffset          = journal->mtdStartOffset
 | 
			
		||||
                                                   + (blobIndexBeingLogged + 1) * journal->sequentialSkip
 | 
			
		||||
                                                   - sizeof(SequentialFlashJournalLogTail_t);
 | 
			
		||||
                journal->log.mtdTailOffset       = SLOT_ADDRESS(journal, blobIndexBeingLogged + 1) - sizeof(SequentialFlashJournalLogTail_t);
 | 
			
		||||
 | 
			
		||||
                journal->log.tail.magic          = SEQUENTIAL_FLASH_JOURNAL_MAGIC;
 | 
			
		||||
                journal->log.tail.sequenceNumber = journal->nextSequenceNumber;
 | 
			
		||||
                journal->log.tail.sizeofBlob     = 0; /* we'll update this as we complete our writes. */
 | 
			
		||||
                journal->log.tail.crc32          = 0;
 | 
			
		||||
 | 
			
		||||
                if (journal->prevCommand == FLASH_JOURNAL_OPCODE_COMMIT) {
 | 
			
		||||
                    /* This branch is taken only when commit() is called without any preceding log() operations. */
 | 
			
		||||
                    journal->log.tail.crc32      = flashJournalCrcCummulative((const unsigned char *)&journal->log.tail, sizeof(SequentialFlashJournalLogTail_t));
 | 
			
		||||
                    flashJournalCrcReset();
 | 
			
		||||
 | 
			
		||||
                    journal->state               = SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL;
 | 
			
		||||
                    journal->log.dataBeingLogged = (const uint8_t *)&journal->log.tail;
 | 
			
		||||
                    journal->log.amountLeftToLog = sizeof(SequentialFlashJournalLogTail_t);
 | 
			
		||||
                    journal->log.offset          = journal->log.tailOffset;
 | 
			
		||||
                    // printf("newstate: program TAIL at offset %lu\r\n", (uint32_t)journal->log.offset);
 | 
			
		||||
                    journal->log.mtdOffset       = journal->log.mtdTailOffset;
 | 
			
		||||
                    // printf("newstate: program TAIL at offset %lu\r\n", (uint32_t)journal->log.mtdOffset);
 | 
			
		||||
                } else {
 | 
			
		||||
                    journal->state                   = SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY;
 | 
			
		||||
                    journal->log.dataBeingLogged     = journal->log.blob;
 | 
			
		||||
| 
						 | 
				
			
			@ -352,15 +541,19 @@ int32_t flashJournalStrategySequential_log_progress(void)
 | 
			
		|||
                if (journal->log.dataBeingLogged == journal->log.blob) {
 | 
			
		||||
                    return JOURNAL_STATUS_SMALL_LOG_REQUEST;
 | 
			
		||||
                } else {
 | 
			
		||||
                    return (journal->log.dataBeingLogged - journal->log.blob);
 | 
			
		||||
                    uint32_t amountOfDataLogged = (journal->log.dataBeingLogged - journal->log.blob);
 | 
			
		||||
                    flashJournalCrcCummulative(journal->log.blob, amountOfDataLogged); /* compute CRC32 on logged data */
 | 
			
		||||
                    return amountOfDataLogged;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            case SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL:
 | 
			
		||||
                // printf("crc32 of slot: 0x%x\n", journal->log.tail.crc32);
 | 
			
		||||
 | 
			
		||||
                journal->info.sizeofJournaledBlob = journal->log.tail.sizeofBlob;
 | 
			
		||||
                journal->state                    = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state to allow further operations */
 | 
			
		||||
 | 
			
		||||
                ++journal->currentBlobIndex;
 | 
			
		||||
                if (journal->currentBlobIndex == SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS) {
 | 
			
		||||
                if (journal->currentBlobIndex == journal->numSlots) {
 | 
			
		||||
                    journal->currentBlobIndex = 0;
 | 
			
		||||
                }
 | 
			
		||||
                // printf("currentBlobIndex: %lu\n", journal->currentBlobIndex);
 | 
			
		||||
| 
						 | 
				
			
			@ -381,24 +574,48 @@ int32_t flashJournalStrategySequential_log_progress(void)
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void formatHandler(int32_t status, ARM_STORAGE_OPERATION operation)
 | 
			
		||||
{
 | 
			
		||||
    if (status < ARM_DRIVER_OK) {
 | 
			
		||||
        if (formatInfoSingleton.callback) {
 | 
			
		||||
            formatInfoSingleton.callback(status, FLASH_JOURNAL_OPCODE_FORMAT);
 | 
			
		||||
        }
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int32_t rc = flashJournalStrategySequential_format_progress(status, operation);
 | 
			
		||||
    if (rc != JOURNAL_STATUS_OK) {
 | 
			
		||||
        if (formatInfoSingleton.callback) {
 | 
			
		||||
            formatInfoSingleton.callback(rc, FLASH_JOURNAL_OPCODE_FORMAT);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mtdHandler(int32_t status, ARM_STORAGE_OPERATION operation)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    if (status < ARM_DRIVER_OK) {
 | 
			
		||||
        printf("mtdHandler: received error status %" PRId32 "\n", status);
 | 
			
		||||
        /* Map integrity failures reported by the Storage driver appropriately. */
 | 
			
		||||
        if (status == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
 | 
			
		||||
            status = JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
 | 
			
		||||
        } else {
 | 
			
		||||
            status = JOURNAL_STATUS_STORAGE_IO_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // printf("journal mtdHandler: received error status %ld\n", status);
 | 
			
		||||
        switch (activeJournal->state) {
 | 
			
		||||
            case SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED:
 | 
			
		||||
            case SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS:
 | 
			
		||||
                if (activeJournal->callback) {
 | 
			
		||||
                    activeJournal->callback(JOURNAL_STATUS_STORAGE_IO_ERROR, FLASH_JOURNAL_OPCODE_INITIALIZE);
 | 
			
		||||
                    activeJournal->callback(status, FLASH_JOURNAL_OPCODE_INITIALIZE);
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case SEQUENTIAL_JOURNAL_STATE_RESETING:
 | 
			
		||||
                activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
 | 
			
		||||
                if (activeJournal->callback) {
 | 
			
		||||
                    activeJournal->callback(JOURNAL_STATUS_STORAGE_IO_ERROR, FLASH_JOURNAL_OPCODE_RESET);
 | 
			
		||||
                    activeJournal->callback(status, FLASH_JOURNAL_OPCODE_RESET);
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -411,7 +628,7 @@ void mtdHandler(int32_t status, ARM_STORAGE_OPERATION operation)
 | 
			
		|||
                activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
 | 
			
		||||
 | 
			
		||||
                if (activeJournal->callback) {
 | 
			
		||||
                    activeJournal->callback(JOURNAL_STATUS_STORAGE_IO_ERROR, FLASH_JOURNAL_OPCODE_LOG_BLOB);
 | 
			
		||||
                    activeJournal->callback(status, FLASH_JOURNAL_OPCODE_LOG_BLOB);
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            case SEQUENTIAL_JOURNAL_STATE_READING:
 | 
			
		||||
| 
						 | 
				
			
			@ -419,7 +636,7 @@ void mtdHandler(int32_t status, ARM_STORAGE_OPERATION operation)
 | 
			
		|||
                activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
 | 
			
		||||
 | 
			
		||||
                if (activeJournal->callback) {
 | 
			
		||||
                    activeJournal->callback(JOURNAL_STATUS_STORAGE_IO_ERROR, FLASH_JOURNAL_OPCODE_READ_BLOB);
 | 
			
		||||
                    activeJournal->callback(status, FLASH_JOURNAL_OPCODE_READ_BLOB);
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -455,7 +672,7 @@ void mtdHandler(int32_t status, ARM_STORAGE_OPERATION operation)
 | 
			
		|||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                activeJournal->log.eraseOffset += status;
 | 
			
		||||
                activeJournal->log.mtdEraseOffset += status;
 | 
			
		||||
 | 
			
		||||
                if ((rc = flashJournalStrategySequential_log_progress()) != JOURNAL_STATUS_OK) {
 | 
			
		||||
                    activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
 | 
			
		||||
| 
						 | 
				
			
			@ -476,9 +693,9 @@ void mtdHandler(int32_t status, ARM_STORAGE_OPERATION operation)
 | 
			
		|||
            break;
 | 
			
		||||
 | 
			
		||||
        case ARM_STORAGE_OPERATION_PROGRAM_DATA:
 | 
			
		||||
            // printf("PROGRAM_DATA: received status of %ld\n", status);
 | 
			
		||||
            // printf("journal mtdHandler: PROGRAM_DATA: received status of %ld\n", status);
 | 
			
		||||
            rc = status;
 | 
			
		||||
            activeJournal->log.offset          += rc;
 | 
			
		||||
            activeJournal->log.mtdOffset       += rc;
 | 
			
		||||
            activeJournal->log.amountLeftToLog -= rc;
 | 
			
		||||
            activeJournal->log.dataBeingLogged += rc;
 | 
			
		||||
            if (activeJournal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY) {
 | 
			
		||||
| 
						 | 
				
			
			@ -504,7 +721,7 @@ void mtdHandler(int32_t status, ARM_STORAGE_OPERATION operation)
 | 
			
		|||
            break;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            printf("mtdHandler: unknown operation %u\n", operation);
 | 
			
		||||
            //printf("mtdHandler: unknown operation %u\n", operation);
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,12 +21,58 @@
 | 
			
		|||
#include "flash-journal-strategy-sequential/flash_journal_private.h"
 | 
			
		||||
#include "flash-journal-strategy-sequential/flash_journal_strategy_sequential.h"
 | 
			
		||||
 | 
			
		||||
/* The following singleton captures the state of the format machine. Format is
 | 
			
		||||
 * handled differently because it executes even before a journal exists (or a
 | 
			
		||||
 * Journal_t can be initialized. */
 | 
			
		||||
extern struct FormatInfo_t {
 | 
			
		||||
    ARM_DRIVER_STORAGE             *mtd;
 | 
			
		||||
    SequentialFlashJournalHeader_t  header;
 | 
			
		||||
    FlashJournal_Callback_t         callback;
 | 
			
		||||
    uint64_t                        mtdAddr;
 | 
			
		||||
    uint32_t                        mtdProgramUnit;
 | 
			
		||||
} formatInfoSingleton;
 | 
			
		||||
 | 
			
		||||
extern SequentialFlashJournal_t *activeJournal;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Check the sanity of a given slot
 | 
			
		||||
 * @param       journal
 | 
			
		||||
 * @param       slotOffset
 | 
			
		||||
 * @param [out] headSequenceNumberP
 | 
			
		||||
 *                  sequence number of the slot as read from the header.
 | 
			
		||||
 * @param [out] tailP
 | 
			
		||||
 *                  the tail of the slot
 | 
			
		||||
 * @return 1 if the slot is valid; i.e. if head and tail match, and if CRC32 agrees.
 | 
			
		||||
 */
 | 
			
		||||
int32_t slotIsSane(SequentialFlashJournal_t        *journal,
 | 
			
		||||
                   uint64_t                         slotOffset,
 | 
			
		||||
                   uint32_t                        *headSequenceNumberP,
 | 
			
		||||
                   SequentialFlashJournalLogTail_t *tailP);
 | 
			
		||||
 | 
			
		||||
int32_t mtdGetStartAddr(ARM_DRIVER_STORAGE *mtd, uint64_t *startAddrP);
 | 
			
		||||
int32_t setupSequentialJournalHeader(SequentialFlashJournalHeader_t *headerP, ARM_DRIVER_STORAGE *mtd, uint64_t totalSize, uint32_t numSlots);
 | 
			
		||||
int32_t discoverLatestLoggedBlob(SequentialFlashJournal_t *journal);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Progress the state machine for the 'format' operation. This method can also be called from an interrupt handler.
 | 
			
		||||
 * @return  < JOURNAL_STATUS_OK for error
 | 
			
		||||
 *          = JOURNAL_STATUS_OK to signal pending asynchronous activity
 | 
			
		||||
 *          > JOURNAL_STATUS_OK for completion
 | 
			
		||||
 */
 | 
			
		||||
int32_t flashJournalStrategySequential_format_progress(int32_t status, ARM_STORAGE_OPERATION operationWhichJustFinshed);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Progress the state machine for the 'log' operation. This method can also be called from an interrupt handler.
 | 
			
		||||
 * @return  < JOURNAL_STATUS_OK for error
 | 
			
		||||
 *          = JOURNAL_STATUS_OK to signal pending asynchronous activity
 | 
			
		||||
 *          > JOURNAL_STATUS_OK for completion
 | 
			
		||||
 */
 | 
			
		||||
int32_t flashJournalStrategySequential_log_progress(void);
 | 
			
		||||
 | 
			
		||||
int32_t flashJournalStrategySequential_reset_progress(void);
 | 
			
		||||
int32_t flashJournalStrategySequential_read_progress(void);
 | 
			
		||||
int32_t flashJournalStrategySequential_log_progress(void);
 | 
			
		||||
 | 
			
		||||
void    mtdHandler(int32_t status, ARM_STORAGE_OPERATION operation);
 | 
			
		||||
void    formatHandler(int32_t status, ARM_STORAGE_OPERATION operation);
 | 
			
		||||
 | 
			
		||||
#endif /*__FLASH_JOURNAL_SEQUENTIAL_STRATEGY_SUPPORT_FUNCTIONS_H__*/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,6 @@ extern "C" {
 | 
			
		|||
#endif // __cplusplus
 | 
			
		||||
 | 
			
		||||
#include "storage_abstraction/Driver_Storage.h"
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * General return codes. All Flash-Journal APIs return an int32_t to allow for
 | 
			
		||||
| 
						 | 
				
			
			@ -44,6 +43,9 @@ typedef enum _FlashJournal_Status
 | 
			
		|||
    JOURNAL_STATUS_NOT_INITIALIZED   =  -9, ///< journal not initialized
 | 
			
		||||
    JOURNAL_STATUS_EMPTY             = -10, ///< There is no further data to read
 | 
			
		||||
    JOURNAL_STATUS_SMALL_LOG_REQUEST = -11, ///< log request is smaller than the program_unit of the underlying MTD block.
 | 
			
		||||
    JOURNAL_STATUS_NOT_FORMATTED     = -12, ///< need to call xxx_format() before using the journal.
 | 
			
		||||
    JOURNAL_STATUS_METADATA_ERROR    = -13, ///< sanity checks for the journal metadata failed.
 | 
			
		||||
    JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE = -14, ///< validation or run-time errors arising from the badkend media.
 | 
			
		||||
} FlashJournal_Status_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -51,6 +53,7 @@ typedef enum _FlashJournal_Status
 | 
			
		|||
 * completing commands. Refer to \ref ARM_Flash_Callback_t.
 | 
			
		||||
 */
 | 
			
		||||
typedef enum _FlashJournal_OpCode {
 | 
			
		||||
    FLASH_JOURNAL_OPCODE_FORMAT,
 | 
			
		||||
    FLASH_JOURNAL_OPCODE_INITIALIZE,
 | 
			
		||||
    FLASH_JOURNAL_OPCODE_GET_INFO,
 | 
			
		||||
    FLASH_JOURNAL_OPCODE_READ_BLOB,
 | 
			
		||||
| 
						 | 
				
			
			@ -76,6 +79,29 @@ typedef struct _FlashJournal_Info {
 | 
			
		|||
                                   ///<   the requested amount).
 | 
			
		||||
} FlashJournal_Info_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const uint32_t FLASH_JOURNAL_HEADER_MAGIC   = 0xA00AEE1DUL;
 | 
			
		||||
static const uint32_t FLASH_JOURNAL_HEADER_VERSION = 1;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Meta-data placed at the head of a Journal. The actual header would be an
 | 
			
		||||
 * extension of this generic header, and would depend on the implementation
 | 
			
		||||
 * strategy. Initialization algorithms can expect to find this generic header at
 | 
			
		||||
 * the start of every Journal.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct _FlashJournalHeader {
 | 
			
		||||
    uint32_t magic;         /** Journal-header specific magic code */
 | 
			
		||||
    uint32_t version;       /** Revision number for this generic journal header. */
 | 
			
		||||
    uint64_t totalSize;     /** Total space (in bytes) occupied by the journal, including the header.
 | 
			
		||||
                             *    Both 'mtdOffset' and 'mtdOffset + totalSize' should
 | 
			
		||||
                             *    lie on erase boundaries. */
 | 
			
		||||
    uint32_t sizeofHeader;  /** The size of the journal header; this is expected to be larger than this generic header. */
 | 
			
		||||
    uint32_t journalOffset; /** Offset from the start of the journal header to the actual logged journal. */
 | 
			
		||||
    uint32_t checksum;      /** CRC32 over the entire flash-journal-header, including the implementation
 | 
			
		||||
                             *    specific extension (i.e. over 'sizeofHeader' bytes). The value of the
 | 
			
		||||
                             *    field is taken to be 0 for the purpose of computing the checksum. */
 | 
			
		||||
} FlashJournalHeader_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This is the type of the command completion callback handler for the
 | 
			
		||||
 * asynchronous flash-journal APIs: initialize(), read(), log(), commit() and
 | 
			
		||||
| 
						 | 
				
			
			@ -95,8 +121,7 @@ typedef struct _FlashJournal_Info {
 | 
			
		|||
typedef void (*FlashJournal_Callback_t)(int32_t status, FlashJournal_OpCode_t cmd_code);
 | 
			
		||||
 | 
			
		||||
/* forward declarations. */
 | 
			
		||||
typedef struct _FlashJournal_t FlashJournal_t;
 | 
			
		||||
typedef struct _FlashJournal_Ops_t FlashJournal_Ops_t;
 | 
			
		||||
struct FlashJournal_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @ref FlashJournal_t is an abstraction implemented by a table of generic
 | 
			
		||||
| 
						 | 
				
			
			@ -111,44 +136,53 @@ typedef struct _FlashJournal_Ops_t FlashJournal_Ops_t;
 | 
			
		|||
 * strategy-specific metadata. The value of this MAX_SIZE may need to be
 | 
			
		||||
 * increased if some future journal-strategy needs more metadata.
 | 
			
		||||
 */
 | 
			
		||||
#define FLASH_JOURNAL_HANDLE_MAX_SIZE 140
 | 
			
		||||
#define FLASH_JOURNAL_HANDLE_MAX_SIZE 160
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This is the set of operations offered by the flash-journal abstraction. A set
 | 
			
		||||
 * of implementations for these operations defines a logging strategy.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct _FlashJournal_Ops_t {
 | 
			
		||||
 | 
			
		||||
typedef struct FlashJournal_Ops_t {
 | 
			
		||||
    /**
 | 
			
		||||
     * \brief Initialize the flash journal. Refer to @ref FlashJournal_initialize.
 | 
			
		||||
     */
 | 
			
		||||
    int32_t               (*initialize)(FlashJournal_t *journal, ARM_DRIVER_STORAGE *mtd, const FlashJournal_Ops_t *ops, FlashJournal_Callback_t callback);
 | 
			
		||||
    int32_t               (*initialize)(struct FlashJournal_t           *journal,
 | 
			
		||||
                                        ARM_DRIVER_STORAGE       *mtd,
 | 
			
		||||
                                        const struct FlashJournal_Ops_t *ops,
 | 
			
		||||
                                        FlashJournal_Callback_t   callback);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * \brief fetch journal metadata. Refer to @ref FlashJournal_getInfo.
 | 
			
		||||
     */
 | 
			
		||||
    FlashJournal_Status_t (*getInfo)   (FlashJournal_t *journal, FlashJournal_Info_t *info);
 | 
			
		||||
    FlashJournal_Status_t (*getInfo)   (struct FlashJournal_t *journal, FlashJournal_Info_t *info);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief Read from the most recently logged blob. Refer to @ref FlashJournal_read.
 | 
			
		||||
     */
 | 
			
		||||
    int32_t               (*read)      (FlashJournal_t *journal, void *buffer, size_t size);
 | 
			
		||||
    int32_t               (*read)      (struct FlashJournal_t *journal, void *buffer, size_t size);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief Read from the most recently logged blob from a particular offset. Refer to @ref FlashJournal_readFrom.
 | 
			
		||||
     */
 | 
			
		||||
    int32_t               (*readFrom)  (struct FlashJournal_t *journal, size_t offset, void *buffer, size_t size);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief Start logging a new blob or append to the one currently being logged. Refer to @ref FlashJournal_log.
 | 
			
		||||
     */
 | 
			
		||||
    int32_t               (*log)       (FlashJournal_t *journal, const void *blob, size_t size);
 | 
			
		||||
    int32_t               (*log)       (struct FlashJournal_t *journal, const void *blob, size_t size);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief commit a blob accumulated through a non-empty sequence of
 | 
			
		||||
     *     previously successful log() operations. Refer to @ref FlashJournal_commit.
 | 
			
		||||
     */
 | 
			
		||||
    int32_t               (*commit)    (FlashJournal_t *journal);
 | 
			
		||||
    int32_t               (*commit)    (struct FlashJournal_t *journal);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief Reset the journal. This has the effect of erasing all valid blobs.
 | 
			
		||||
     *     Refer to @ref FlashJournal_reset.
 | 
			
		||||
     */
 | 
			
		||||
    int32_t               (*reset)     (FlashJournal_t *journal);
 | 
			
		||||
    int32_t               (*reset)     (struct FlashJournal_t *journal);
 | 
			
		||||
} FlashJournal_Ops_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -167,7 +201,7 @@ typedef struct _FlashJournal_Ops_t {
 | 
			
		|||
 * @note: there is a risk of overallocation in case an implementation doesn't
 | 
			
		||||
 * need FLASH_JOURNAL_HANDLE_MAX_SIZE bytes, but the impact should be small.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct _FlashJournal_t {
 | 
			
		||||
typedef struct FlashJournal_t {
 | 
			
		||||
    FlashJournal_Ops_t       ops;
 | 
			
		||||
 | 
			
		||||
    union {
 | 
			
		||||
| 
						 | 
				
			
			@ -224,7 +258,7 @@ typedef struct _FlashJournal_t {
 | 
			
		|||
 *     JOURNAL_STATUS_OK before the actual completion of the operation (or
 | 
			
		||||
 *     with an appropriate error code in case of failure). When the
 | 
			
		||||
 *     operation is completed the command callback is invoked with
 | 
			
		||||
 *     JOURNAL_STATUS_OK passed in as the 'status' parameter of the
 | 
			
		||||
 *     1 passed in as the 'status' parameter of the
 | 
			
		||||
 *     callback. In case of errors, the completion callback is invoked with
 | 
			
		||||
 *     an error status.
 | 
			
		||||
 *   - When the operation is executed by the journal in a blocking (i.e.
 | 
			
		||||
| 
						 | 
				
			
			@ -234,6 +268,11 @@ typedef struct _FlashJournal_t {
 | 
			
		|||
 *     completion or an appropriate error code, and no further
 | 
			
		||||
 *     invocation of the completion callback should be expected at a later time.
 | 
			
		||||
 *
 | 
			
		||||
 * @note The user must call an appropriate xxx_format() to format underlying
 | 
			
		||||
 *     storage before initializing it for use. If Initialize() is called on
 | 
			
		||||
 *     unformatted storage, an error value of JOURNAL_STATUS_NOT_FORMATTED will be
 | 
			
		||||
 *     returned.
 | 
			
		||||
 *
 | 
			
		||||
 * Here's a code snippet to suggest how this API might be used by callers:
 | 
			
		||||
 * \code
 | 
			
		||||
 *     ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code
 | 
			
		||||
| 
						 | 
				
			
			@ -377,6 +416,88 @@ static inline int32_t FlashJournal_read(FlashJournal_t *journal, void *blob, siz
 | 
			
		|||
    return journal->ops.read(journal, blob, n);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Read from the most recently logged blob at a given offset. A front-end
 | 
			
		||||
 *     for @ref FlashJournal_Ops_t::readFrom().
 | 
			
		||||
 *
 | 
			
		||||
 * @details Read off a chunk of the logged blob from a given offset. The journal
 | 
			
		||||
 *     maintains a read-pointer internally to allow reads to continue where the
 | 
			
		||||
 *     previous one left off. This call effectively sets the read-counter before
 | 
			
		||||
 *     fetching data. Subsequent reads continue sequentially from where the
 | 
			
		||||
 *     readFrom() left off.
 | 
			
		||||
 *
 | 
			
		||||
 * @note: If the given offset stands at (or is beyond) the end of the previously
 | 
			
		||||
 *     logged blob, readFrom() returns the error JOURNAL_STATUS_EMPTY (or passes
 | 
			
		||||
 *     that value as the status of a completion callback) and resets the read-
 | 
			
		||||
 *     pointer to allow re-reading the blob from the start.
 | 
			
		||||
 *
 | 
			
		||||
 * @param  [in] journal
 | 
			
		||||
 *                A previously initialized journal.
 | 
			
		||||
 *
 | 
			
		||||
 * @param  [in] offset
 | 
			
		||||
 *                The logical offset (within the blob) at which to read data from.
 | 
			
		||||
 *
 | 
			
		||||
 * @param [out] buffer
 | 
			
		||||
 *                The destination of the read operation. The memory is owned
 | 
			
		||||
 *                by the caller and should remain valid for the lifetime
 | 
			
		||||
 *                of this operation.
 | 
			
		||||
 *
 | 
			
		||||
 * @param  [in] size
 | 
			
		||||
 *                The maximum amount of data which can be read in this
 | 
			
		||||
 *                operation. The memory pointed to by 'buffer' should be as
 | 
			
		||||
 *                large as this amount.
 | 
			
		||||
 *
 | 
			
		||||
 * @return
 | 
			
		||||
 *    The function executes in the following ways:
 | 
			
		||||
 *   - When the operation is asynchronous--i.e. when the underlying MTD's
 | 
			
		||||
 *     ARM_STOR_CAPABILITIES::asynchronous_ops is set to 1--and the operation
 | 
			
		||||
 *     executed by the journal in a non-blocking (i.e. asynchronous) manner,
 | 
			
		||||
 *     control returns to the caller with JOURNAL_STATUS_OK before the actual
 | 
			
		||||
 *     completion of the operation (or with an appropriate error code in case of
 | 
			
		||||
 *     failure). When the operation completes, the command callback is
 | 
			
		||||
 *     invoked with the number of successfully transferred bytes passed in as
 | 
			
		||||
 *     the 'status' parameter of the callback. If any error is encountered
 | 
			
		||||
 *     after the launch of an asynchronous operation, the completion callback
 | 
			
		||||
 *     is invoked with an error status.
 | 
			
		||||
 *   - When the operation is executed by the journal in a blocking (i.e.
 | 
			
		||||
 *     synchronous) manner, control returns to the caller only upon the
 | 
			
		||||
 *     actual completion of the operation, or the discovery of a failure
 | 
			
		||||
 *     condition. In synchronous mode, the function returns the number
 | 
			
		||||
 *     of data items read or an appropriate error code.
 | 
			
		||||
 *
 | 
			
		||||
 * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops
 | 
			
		||||
 *     is set then this operation may execute asynchronously. In the case of
 | 
			
		||||
 *     asynchronous operation, the invocation returns early (with
 | 
			
		||||
 *     JOURNAL_STATUS_OK) and results in a completion callback later.
 | 
			
		||||
 *
 | 
			
		||||
 * @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops
 | 
			
		||||
 *     is set, the journal is not required to operate asynchronously. A Read
 | 
			
		||||
 *     operation can be finished synchronously in spite of
 | 
			
		||||
 *     ARM_STORAGE_CAPABILITIES::asynchronous_ops being set, returning the
 | 
			
		||||
 *     number of data items read to indicate successful completion, or an
 | 
			
		||||
 *     appropriate error code. In this case no further invocation of a
 | 
			
		||||
 *     completion callback should be expected at a later time.
 | 
			
		||||
 *
 | 
			
		||||
 * Here's a code snippet to suggest how this API might be used by callers:
 | 
			
		||||
 * \code
 | 
			
		||||
 *     ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code
 | 
			
		||||
 *     int32_t returnValue = FlashJournal_readFrom(&journal, offset, buffer, size);
 | 
			
		||||
 *     if (returnValue < JOURNAL_STATUS_OK) {
 | 
			
		||||
 *         // handle error
 | 
			
		||||
 *     } else if (returnValue == JOURNAL_STATUS_OK) {
 | 
			
		||||
 *         ASSERT(MTD->GetCapabilities().asynchronous_ops == 1);
 | 
			
		||||
 *         // handle early return from asynchronous execution
 | 
			
		||||
 *     } else {
 | 
			
		||||
 *         ASSERT(returnValue == size);
 | 
			
		||||
 *         // handle synchronous completion
 | 
			
		||||
 *     }
 | 
			
		||||
 * \endcode
 | 
			
		||||
 */
 | 
			
		||||
static inline int32_t FlashJournal_readFrom(struct FlashJournal_t *journal, size_t offset, void *blob, size_t n)
 | 
			
		||||
{
 | 
			
		||||
    return journal->ops.readFrom(journal, offset, blob, n);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Start logging a new blob or append to the one currently being logged.
 | 
			
		||||
 * A front-end for @ref FlashJournal_Ops_t::log().
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,252 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2006-2016, ARM Limited, All Rights Reserved
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
			
		||||
 * not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "storage-volume-manager/storage_volume_manager.h"
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
/* redefine tr_debug() to a printf() equivalent to emit trace */
 | 
			
		||||
#define tr_debug(...)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void StorageVolume::setup(uint64_t _addr, uint64_t _size, StorageVolumeManager *_volumeManager)
 | 
			
		||||
{
 | 
			
		||||
    volumeOffset  = _addr;
 | 
			
		||||
    volumeSize    = _size;
 | 
			
		||||
    volumeManager = _volumeManager;
 | 
			
		||||
    allocated     = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ARM_DRIVER_VERSION StorageVolume::GetVersion(void)
 | 
			
		||||
{
 | 
			
		||||
    ARM_DRIVER_VERSION bad_ver = {0, 0};
 | 
			
		||||
 | 
			
		||||
    if (!allocated) {
 | 
			
		||||
        return bad_ver;
 | 
			
		||||
    }
 | 
			
		||||
    return volumeManager->getStorage()->GetVersion();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ARM_STORAGE_CAPABILITIES StorageVolume::GetCapabilities(void)
 | 
			
		||||
{
 | 
			
		||||
    ARM_STORAGE_CAPABILITIES bad_cap;
 | 
			
		||||
 | 
			
		||||
    if (!allocated) {
 | 
			
		||||
        memset(&bad_cap, 0, sizeof(ARM_STORAGE_CAPABILITIES));
 | 
			
		||||
        return bad_cap;
 | 
			
		||||
    }
 | 
			
		||||
    return volumeManager->getStorage()->GetCapabilities();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t StorageVolume::Initialize(ARM_Storage_Callback_t _callback)
 | 
			
		||||
{
 | 
			
		||||
    if (!allocated) {
 | 
			
		||||
        return STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    callback = _callback; /* nothing else to do since we've already initialized the storage */
 | 
			
		||||
    return 1; /* synchronous completion. */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t StorageVolume::Uninitialize(void)
 | 
			
		||||
{
 | 
			
		||||
    if (!allocated) {
 | 
			
		||||
        return STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 1; /* synchronous completion. */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t StorageVolume::PowerControl(ARM_POWER_STATE state)
 | 
			
		||||
{
 | 
			
		||||
    tr_debug("called powerControl(%u)", state);
 | 
			
		||||
    if (!allocated) {
 | 
			
		||||
        return STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED;
 | 
			
		||||
    }
 | 
			
		||||
    if (volumeManager->activeVolume != NULL) {
 | 
			
		||||
        return ARM_DRIVER_ERROR_BUSY;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    volumeManager->activeVolume = this;
 | 
			
		||||
    int32_t rc = volumeManager->getStorage()->PowerControl(state);
 | 
			
		||||
    if (rc != ARM_DRIVER_OK) {
 | 
			
		||||
        volumeManager->activeVolume = NULL; /* we're certain that there is no more pending asynch. activity */
 | 
			
		||||
    }
 | 
			
		||||
    return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t StorageVolume::ReadData(uint64_t addr, void *data, uint32_t size)
 | 
			
		||||
{
 | 
			
		||||
    tr_debug("called ReadData(%" PRIu32 ", %" PRIu32 ")", (uint32_t)addr, size);
 | 
			
		||||
    if (!allocated) {
 | 
			
		||||
        return STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED;
 | 
			
		||||
    }
 | 
			
		||||
    if (volumeManager->activeVolume != NULL) {
 | 
			
		||||
        return ARM_DRIVER_ERROR_BUSY;
 | 
			
		||||
    }
 | 
			
		||||
    if ((size > volumeSize) || ((addr + size) > volumeSize)) {
 | 
			
		||||
        return ARM_DRIVER_ERROR_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    volumeManager->activeVolume = this;
 | 
			
		||||
    int32_t rc = volumeManager->getStorage()->ReadData(volumeOffset + addr, data, size);
 | 
			
		||||
    if (rc != ARM_DRIVER_OK) {
 | 
			
		||||
        volumeManager->activeVolume = NULL; /* we're certain that there is no more pending asynch. activity */
 | 
			
		||||
    }
 | 
			
		||||
    return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t StorageVolume::ProgramData(uint64_t addr, const void *data, uint32_t size)
 | 
			
		||||
{
 | 
			
		||||
    tr_debug("called ProgramData(%" PRIu32 ", %" PRIu32 ")", (uint32_t)addr, size);
 | 
			
		||||
    if (!allocated) {
 | 
			
		||||
        return STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED;
 | 
			
		||||
    }
 | 
			
		||||
    if (volumeManager->activeVolume != NULL) {
 | 
			
		||||
        return ARM_DRIVER_ERROR_BUSY;
 | 
			
		||||
    }
 | 
			
		||||
    if ((size > volumeSize) || ((addr + size) > volumeSize)) {
 | 
			
		||||
        return ARM_DRIVER_ERROR_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    volumeManager->activeVolume = this;
 | 
			
		||||
    int32_t rc = volumeManager->getStorage()->ProgramData(volumeOffset + addr, data, size);
 | 
			
		||||
    if (rc != ARM_DRIVER_OK) {
 | 
			
		||||
        volumeManager->activeVolume = NULL; /* we're certain that there is no more pending asynch. activity */
 | 
			
		||||
    }
 | 
			
		||||
    return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t StorageVolume::Erase(uint64_t addr, uint32_t size)
 | 
			
		||||
{
 | 
			
		||||
    tr_debug("called erase(%" PRIu32 ", %" PRIu32 ")", (uint32_t)addr, size);
 | 
			
		||||
    if (!allocated) {
 | 
			
		||||
        return STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED;
 | 
			
		||||
    }
 | 
			
		||||
    if (volumeManager->activeVolume != NULL) {
 | 
			
		||||
        return ARM_DRIVER_ERROR_BUSY;
 | 
			
		||||
    }
 | 
			
		||||
    if ((size > volumeSize) || ((addr + size) > volumeSize)) {
 | 
			
		||||
        return ARM_DRIVER_ERROR_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    volumeManager->activeVolume = this;
 | 
			
		||||
    int32_t rc = volumeManager->getStorage()->Erase(volumeOffset + addr, size);
 | 
			
		||||
    if (rc != ARM_DRIVER_OK) {
 | 
			
		||||
        volumeManager->activeVolume = NULL; /* we're certain that there is no more pending asynch. activity */
 | 
			
		||||
    }
 | 
			
		||||
    return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t StorageVolume::EraseAll(void)
 | 
			
		||||
{
 | 
			
		||||
    tr_debug("called eraseAll");
 | 
			
		||||
    if (!allocated) {
 | 
			
		||||
        return STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED;
 | 
			
		||||
    }
 | 
			
		||||
    if (volumeManager->activeVolume != NULL) {
 | 
			
		||||
        return ARM_DRIVER_ERROR_BUSY;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    /* Allow EraseAll() only if the volume spans the entire storage. */
 | 
			
		||||
    {
 | 
			
		||||
        ARM_STORAGE_INFO info;
 | 
			
		||||
        rc = volumeManager->getStorage()->GetInfo(&info);
 | 
			
		||||
        if (rc != ARM_DRIVER_OK) {
 | 
			
		||||
            return ARM_DRIVER_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ((volumeOffset != 0) || (volumeSize != info.total_storage)) {
 | 
			
		||||
            return ARM_DRIVER_ERROR_UNSUPPORTED;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    volumeManager->activeVolume = this;
 | 
			
		||||
    rc = volumeManager->getStorage()->EraseAll();
 | 
			
		||||
    if (rc != ARM_DRIVER_OK) {
 | 
			
		||||
        volumeManager->activeVolume = NULL; /* we're certain that there is no more pending asynch. activity */
 | 
			
		||||
    }
 | 
			
		||||
    return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ARM_STORAGE_STATUS StorageVolume::GetStatus(void)
 | 
			
		||||
{
 | 
			
		||||
    const uint32_t busy = ((volumeManager->activeVolume != NULL) ? (uint32_t)1 : (uint32_t)0);
 | 
			
		||||
    ARM_STORAGE_STATUS status = {0, 0};
 | 
			
		||||
    status.busy = busy;
 | 
			
		||||
    return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t StorageVolume::GetInfo(ARM_STORAGE_INFO *infoP)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
    rc = volumeManager->getStorage()->GetInfo(infoP);
 | 
			
		||||
    if (rc != ARM_DRIVER_OK) {
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    infoP->total_storage = volumeSize;
 | 
			
		||||
    return ARM_DRIVER_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t StorageVolume::ResolveAddress(uint64_t addr) {
 | 
			
		||||
    return (uint32_t)(volumeOffset + addr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t StorageVolume::GetNextBlock(const ARM_STORAGE_BLOCK* prevP, ARM_STORAGE_BLOCK *nextP)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
    ARM_STORAGE_BLOCK tmpBlock;
 | 
			
		||||
    do {
 | 
			
		||||
        /* iterate forward */
 | 
			
		||||
        rc = volumeManager->getStorage()->GetNextBlock(prevP, &tmpBlock);
 | 
			
		||||
        if (rc != ARM_DRIVER_OK) {
 | 
			
		||||
            return rc;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Stop iteration if we have progressed past the boundary of this volume. */
 | 
			
		||||
        if (tmpBlock.addr >= (volumeOffset + volumeSize)) {
 | 
			
		||||
            return ARM_DRIVER_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
    } while (!this->overlapsWithBlock(&tmpBlock));
 | 
			
		||||
 | 
			
		||||
    if (nextP) {
 | 
			
		||||
        memcpy(nextP, &tmpBlock, sizeof(ARM_STORAGE_BLOCK));
 | 
			
		||||
        transformBlockToVolume(nextP);
 | 
			
		||||
    }
 | 
			
		||||
    return ARM_DRIVER_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t StorageVolume::GetBlock(uint64_t addr, ARM_STORAGE_BLOCK *blockP)
 | 
			
		||||
{
 | 
			
		||||
    ARM_STORAGE_BLOCK tmpBlock;
 | 
			
		||||
    int32_t rc = volumeManager->getStorage()->GetBlock(ResolveAddress(addr), &tmpBlock);
 | 
			
		||||
    if (rc != ARM_DRIVER_OK) {
 | 
			
		||||
        return rc;
 | 
			
		||||
    }
 | 
			
		||||
    if (!this->overlapsWithBlock(&tmpBlock)) {
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (blockP) {
 | 
			
		||||
        memcpy(blockP, &tmpBlock, sizeof(ARM_STORAGE_BLOCK));
 | 
			
		||||
        transformBlockToVolume(blockP);
 | 
			
		||||
    }
 | 
			
		||||
    return ARM_DRIVER_OK;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,286 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2006-2016, ARM Limited, All Rights Reserved
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
			
		||||
 * not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "storage-volume-manager/storage_volume_manager.h"
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
/* redefine these macros to a printf() equivalent to emit trace */
 | 
			
		||||
#define tr_debug(...)
 | 
			
		||||
#define tr_error(...)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The following variable records the volume-manager instance which last setup
 | 
			
		||||
 * StorageVolumeManager::storageCallback() as a callback for a storage driver.
 | 
			
		||||
 * We use this value in the callback handler to de-multiplex the callback into a
 | 
			
		||||
 * volume-manager.
 | 
			
		||||
 */
 | 
			
		||||
static StorageVolumeManager *activeVolumeManager;
 | 
			
		||||
 | 
			
		||||
InitializeCallback_t initializeCallback;
 | 
			
		||||
 | 
			
		||||
#define STORAGE_API_DEFINITIONS_FOR_VOLUME(N)                                          \
 | 
			
		||||
extern "C" ARM_DRIVER_VERSION GetVersion_ ## N(void) {                                 \
 | 
			
		||||
    return activeVolumeManager->volumes[(N)].GetVersion();                             \
 | 
			
		||||
}                                                                                      \
 | 
			
		||||
ARM_STORAGE_CAPABILITIES GetCapabilities_ ## N(void) {                                 \
 | 
			
		||||
    return activeVolumeManager->volumes[(N)].GetCapabilities();                        \
 | 
			
		||||
}                                                                                      \
 | 
			
		||||
int32_t Initialize_ ## N(ARM_Storage_Callback_t callback) {                            \
 | 
			
		||||
    return activeVolumeManager->volumes[(N)].Initialize(callback);                     \
 | 
			
		||||
}                                                                                      \
 | 
			
		||||
int32_t Uninitialize_ ## N(void) {                                                     \
 | 
			
		||||
    return activeVolumeManager->volumes[(N)].Uninitialize();                           \
 | 
			
		||||
}                                                                                      \
 | 
			
		||||
int32_t PowerControl_ ## N(ARM_POWER_STATE state) {                                    \
 | 
			
		||||
    return activeVolumeManager->volumes[(N)].PowerControl(state);                      \
 | 
			
		||||
}                                                                                      \
 | 
			
		||||
int32_t ReadData_ ## N(uint64_t addr, void *data, uint32_t size) {                     \
 | 
			
		||||
    return activeVolumeManager->volumes[(N)].ReadData(addr, data, size);               \
 | 
			
		||||
}                                                                                      \
 | 
			
		||||
int32_t ProgramData_ ## N(uint64_t addr, const void *data, uint32_t size) {            \
 | 
			
		||||
    return activeVolumeManager->volumes[(N)].ProgramData(addr, data, size);            \
 | 
			
		||||
}                                                                                      \
 | 
			
		||||
int32_t Erase_ ## N(uint64_t addr, uint32_t size) {                                    \
 | 
			
		||||
    return activeVolumeManager->volumes[(N)].Erase(addr, size);                        \
 | 
			
		||||
}                                                                                      \
 | 
			
		||||
int32_t EraseAll_ ## N(void) {                                                         \
 | 
			
		||||
    return activeVolumeManager->volumes[(N)].EraseAll();                               \
 | 
			
		||||
}                                                                                      \
 | 
			
		||||
ARM_STORAGE_STATUS GetStatus_ ## N(void) {                                             \
 | 
			
		||||
    return activeVolumeManager->volumes[(N)].GetStatus();                              \
 | 
			
		||||
}                                                                                      \
 | 
			
		||||
int32_t GetInfo_ ## N(ARM_STORAGE_INFO *infoP) {                                       \
 | 
			
		||||
    return activeVolumeManager->volumes[(N)].GetInfo(infoP);                           \
 | 
			
		||||
}                                                                                      \
 | 
			
		||||
uint32_t ResolveAddress_ ## N(uint64_t addr) {                                         \
 | 
			
		||||
    return activeVolumeManager->volumes[(N)].ResolveAddress(addr);                     \
 | 
			
		||||
}                                                                                      \
 | 
			
		||||
int32_t GetNextBlock_ ## N(const ARM_STORAGE_BLOCK* prevP, ARM_STORAGE_BLOCK *nextP) { \
 | 
			
		||||
    return activeVolumeManager->volumes[(N)].GetNextBlock(prevP, nextP);               \
 | 
			
		||||
}                                                                                      \
 | 
			
		||||
int32_t GetBlock_ ## N(uint64_t addr, ARM_STORAGE_BLOCK *blockP) {                     \
 | 
			
		||||
    return activeVolumeManager->volumes[(N)].GetBlock(addr, blockP);                   \
 | 
			
		||||
}                                                                                      \
 | 
			
		||||
ARM_DRIVER_STORAGE VIRTUAL_MTD_ ## N = {                                               \
 | 
			
		||||
    .GetVersion      = GetVersion_ ## N,                                               \
 | 
			
		||||
    .GetCapabilities = GetCapabilities_ ## N,                                          \
 | 
			
		||||
    .Initialize      = Initialize_ ## N,                                               \
 | 
			
		||||
    .Uninitialize    = Uninitialize_ ## N,                                             \
 | 
			
		||||
    .PowerControl    = PowerControl_ ## N,                                             \
 | 
			
		||||
    .ReadData        = ReadData_ ## N,                                                 \
 | 
			
		||||
    .ProgramData     = ProgramData_ ## N,                                              \
 | 
			
		||||
    .Erase           = Erase_ ## N,                                                    \
 | 
			
		||||
    .EraseAll        = EraseAll_ ## N,                                                 \
 | 
			
		||||
    .GetStatus       = GetStatus_ ## N,                                                \
 | 
			
		||||
    .GetInfo         = GetInfo_ ## N,                                                  \
 | 
			
		||||
    .ResolveAddress  = ResolveAddress_ ## N,                                           \
 | 
			
		||||
    .GetNextBlock    = GetNextBlock_ ## N,                                             \
 | 
			
		||||
    .GetBlock        = GetBlock_ ## N,                                                 \
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define STORAGE_API_DEFINITIONS_LIST_FOR_VOLUME_1 STORAGE_API_DEFINITIONS_FOR_VOLUME(0)
 | 
			
		||||
#define STORAGE_API_DEFINITIONS_LIST_FOR_VOLUME_2 STORAGE_API_DEFINITIONS_LIST_FOR_VOLUME_1 STORAGE_API_DEFINITIONS_FOR_VOLUME(1)
 | 
			
		||||
#define STORAGE_API_DEFINITIONS_LIST_FOR_VOLUME_3 STORAGE_API_DEFINITIONS_LIST_FOR_VOLUME_2 STORAGE_API_DEFINITIONS_FOR_VOLUME(2)
 | 
			
		||||
#define STORAGE_API_DEFINITIONS_LIST_FOR_VOLUME_4 STORAGE_API_DEFINITIONS_LIST_FOR_VOLUME_3 STORAGE_API_DEFINITIONS_FOR_VOLUME(3)
 | 
			
		||||
/* ... add more of the above if ever needed */
 | 
			
		||||
 | 
			
		||||
#define STORAGE_API_DEFINITIONS_FOR_VOLUMES(N) EXPAND(CONCATENATE(STORAGE_API_DEFINITIONS_LIST_FOR_VOLUME_, N))
 | 
			
		||||
 | 
			
		||||
STORAGE_API_DEFINITIONS_FOR_VOLUMES(MAX_VOLUMES);
 | 
			
		||||
 | 
			
		||||
int32_t StorageVolumeManager::initialize(ARM_DRIVER_STORAGE *mtd, InitializeCallback_t callback)
 | 
			
		||||
{
 | 
			
		||||
    activeVolume        = NULL;
 | 
			
		||||
    initializeCallback  = callback;
 | 
			
		||||
 | 
			
		||||
    storage             = mtd;
 | 
			
		||||
    storageCapabilities = mtd->GetCapabilities();
 | 
			
		||||
 | 
			
		||||
    int32_t rc = mtd->GetInfo(&storageInfo);
 | 
			
		||||
    if (rc != ARM_DRIVER_OK) {
 | 
			
		||||
        tr_error("StorageVolumeManager::initialize: call to GetInfo() failed with %" PRId32, rc);
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    rc = mtd->Initialize(storageCallback);
 | 
			
		||||
    if (rc < ARM_DRIVER_OK) {
 | 
			
		||||
        tr_error("Initialize() failed with error %" PRId32, rc);
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    activeVolumeManager = this;
 | 
			
		||||
    if (rc == ARM_DRIVER_OK) {
 | 
			
		||||
        /* there is pending asynchronous activity which will result in a callback later */
 | 
			
		||||
        return ARM_DRIVER_OK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Clear previously allocated volumes */
 | 
			
		||||
    for (size_t i = 0; i < MAX_VOLUMES; i++) {
 | 
			
		||||
        if (volumes[i].isAllocated()) {
 | 
			
		||||
            volumes[i].deallocate();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* synchronous completion */
 | 
			
		||||
    initialized = true;
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t StorageVolumeManager::addVolume(uint64_t addr, uint64_t size, StorageVolume **volumePP)
 | 
			
		||||
{
 | 
			
		||||
    tr_debug("StorageVolumeManager_addVolume: addr = %" PRIu32 ", size = %" PRIu32, (uint32_t)addr, (uint32_t)size);
 | 
			
		||||
 | 
			
		||||
    *volumePP = NULL;
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * sanity checks for arguments
 | 
			
		||||
     */
 | 
			
		||||
    ARM_STORAGE_INFO info;
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
    rc = storage->GetInfo(&info);
 | 
			
		||||
    if (rc != ARM_DRIVER_OK) {
 | 
			
		||||
        tr_error("StorageVolumeManager_addVolume: storage->GetInfo() failed with %" PRId32, rc);
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    if (size > info.total_storage) {
 | 
			
		||||
        tr_error("StorageVolumeManager_addVolume: 'size' parameter too large: %" PRIu32, (uint32_t)size);
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    ARM_STORAGE_BLOCK firstBlock;
 | 
			
		||||
    rc = storage->GetNextBlock(NULL, &firstBlock);
 | 
			
		||||
    if (rc != ARM_DRIVER_OK) {
 | 
			
		||||
        tr_error("StorageVolumeManager_addVolume: storage->GetNextBlock() failed with %" PRId32, rc);
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    if ((addr < firstBlock.addr) || ((addr + size) > (firstBlock.addr + info.total_storage))) {
 | 
			
		||||
        tr_error("StorageVolumeManager_addVolume: given range [%" PRIu32 ", %" PRIu32 ") isn't entirely contained within available storage range [%" PRIu32 ", %" PRIu32 ")",
 | 
			
		||||
            (uint32_t)addr, (uint32_t)(addr + size), (uint32_t)firstBlock.addr, (uint32_t)(firstBlock.addr + info.total_storage));
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Find an unused volume. */
 | 
			
		||||
    uint32_t index = findIndexOfUnusedVolume();
 | 
			
		||||
    if (index == MAX_VOLUMES) {
 | 
			
		||||
        return STORAGE_VOLUME_MANAGER_STATUS_ERROR_EXHASTED_VOLUMES;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* setup volume */
 | 
			
		||||
    StorageVolume *volumeP = &volumes[index];
 | 
			
		||||
    volumeP->setup(addr, size, this);
 | 
			
		||||
    *volumePP = volumeP;
 | 
			
		||||
    tr_debug("StorageVolumeManager_addVolume: setup volume at index %" PRIu32, index);
 | 
			
		||||
 | 
			
		||||
    return ARM_DRIVER_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t StorageVolumeManager::addVolume_C(uint64_t addr, uint64_t size, _ARM_DRIVER_STORAGE *mtd)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
    StorageVolume *volumeP;
 | 
			
		||||
    if ((rc = addVolume(addr, size, &volumeP)) < ARM_DRIVER_OK) {
 | 
			
		||||
        return rc;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* locate index of the allocated volume */
 | 
			
		||||
    size_t index;
 | 
			
		||||
    for (index = 0; index < MAX_VOLUMES; index++) {
 | 
			
		||||
        if (volumes[index].isAllocated() && (&volumes[index] == volumeP)) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (index == MAX_VOLUMES) {
 | 
			
		||||
        return STORAGE_VOLUME_MANAGER_STATUS_ERROR_EXHASTED_VOLUMES;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (index == 0) {
 | 
			
		||||
        *mtd = VIRTUAL_MTD_0;
 | 
			
		||||
    } else if (index == 1) {
 | 
			
		||||
        *mtd = VIRTUAL_MTD_1;
 | 
			
		||||
    } else if (index == 2) {
 | 
			
		||||
        *mtd = VIRTUAL_MTD_2;
 | 
			
		||||
    } else if (index == 3) {
 | 
			
		||||
        *mtd = VIRTUAL_MTD_3;
 | 
			
		||||
    } else {
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ARM_DRIVER_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t StorageVolumeManager::lookupVolume(uint64_t addr, StorageVolume **volumePP)
 | 
			
		||||
{
 | 
			
		||||
    /*
 | 
			
		||||
     * Traverse the volumes in reverse order of creation; this allows newly created volumes to supersede the older ones.
 | 
			
		||||
     */
 | 
			
		||||
    for (size_t index = MAX_VOLUMES - 1; index > 0; --index) {
 | 
			
		||||
        StorageVolume *volume = &volumes[index];
 | 
			
		||||
        if ((addr >= volume->getVolumeOffset()) && (addr < (volume->getVolumeOffset() + volume->getVolumeSize()))) {
 | 
			
		||||
            *volumePP = volume;
 | 
			
		||||
            return ARM_DRIVER_OK;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ARM_DRIVER_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StorageVolumeManager::storageCallback(int32_t status, ARM_STORAGE_OPERATION operation)
 | 
			
		||||
{
 | 
			
		||||
    tr_debug("StorageVolumeManager_callback: operation = %u", operation);
 | 
			
		||||
    StorageVolumeManager *volumeManager = activeVolumeManager;
 | 
			
		||||
 | 
			
		||||
    switch (operation) {
 | 
			
		||||
        case ARM_STORAGE_OPERATION_INITIALIZE:
 | 
			
		||||
            volumeManager->initialized = true;
 | 
			
		||||
            if (initializeCallback != NULL) {
 | 
			
		||||
                initializeCallback(status);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case ARM_STORAGE_OPERATION_POWER_CONTROL:
 | 
			
		||||
        case ARM_STORAGE_OPERATION_READ_DATA:
 | 
			
		||||
        case ARM_STORAGE_OPERATION_PROGRAM_DATA:
 | 
			
		||||
        case ARM_STORAGE_OPERATION_ERASE:
 | 
			
		||||
        case ARM_STORAGE_OPERATION_ERASE_ALL:
 | 
			
		||||
            if (volumeManager->activeVolume != NULL) {
 | 
			
		||||
                /* Reset activeVolume and invoke callback. We reset activeVolume before the
 | 
			
		||||
                 * callback because the callback may attempt to launch another asynchronous
 | 
			
		||||
                 * operation, which requires 'activeVolume' to be NULL. */
 | 
			
		||||
                StorageVolume *callbackVolume = volumeManager->activeVolume; /* remember the volume which will receive the callback. */
 | 
			
		||||
                volumeManager->activeVolume   = NULL;
 | 
			
		||||
 | 
			
		||||
                if (callbackVolume->isAllocated() && callbackVolume->getCallback()) {
 | 
			
		||||
                    (callbackVolume->getCallback())(status, operation);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            tr_error("StorageVolumeManager_callback: unknown operation %u", operation);
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t StorageVolumeManager::findIndexOfUnusedVolume(void) const {
 | 
			
		||||
    size_t index;
 | 
			
		||||
    for (index = 0; index < MAX_VOLUMES; index++) {
 | 
			
		||||
        if (!volumes[index].isAllocated()) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return index;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,264 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2006-2016, ARM Limited, All Rights Reserved
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
			
		||||
 * not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __STORAGE_VOLUME_MANAGER_H__
 | 
			
		||||
#define __STORAGE_VOLUME_MANAGER_H__
 | 
			
		||||
 | 
			
		||||
#ifndef __cplusplus
 | 
			
		||||
#error "This abstraction requires a C++ toolchain"
 | 
			
		||||
#endif // __cplusplus
 | 
			
		||||
 | 
			
		||||
#include "storage_abstraction/Driver_Storage.h"
 | 
			
		||||
 | 
			
		||||
#if !defined(YOTTA_CFG_STORAGE_VOLUME_MANAGER_MAX_VOLUMES)
 | 
			
		||||
#define MAX_VOLUMES 4
 | 
			
		||||
#else
 | 
			
		||||
#define MAX_VOLUMES YOTTA_CFG_STORAGE_VOLUME_MANAGER_MAX_VOLUMES
 | 
			
		||||
#endif
 | 
			
		||||
/**<
 | 
			
		||||
 * A static assert to ensure that the size of SequentialJournal is smaller than
 | 
			
		||||
 * FlashJournal_t. The caller will only allocate a FlashJournal_t and expect the
 | 
			
		||||
 * Sequential Strategy to reuse that space for a SequentialFlashJournal_t.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef TOOLCHAIN_IAR
 | 
			
		||||
typedef char AssertStorageVolumeManagerMaxVolumesIsSane[(((MAX_VOLUMES) > 0) && ((MAX_VOLUMES) <= 8)) ? 0:-1];
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define CONCATENATE(A, B) A ## B
 | 
			
		||||
#define EXPAND(X) X /* this adds a level of indirection needed to allow macro-expansion following a token-paste operation (see use of CONCATENATE() below). */
 | 
			
		||||
 | 
			
		||||
#define STORAGE_API_EXTERN_C_DECLARATIONS_FOR_VOLUME(N)                                                               \
 | 
			
		||||
    extern "C" ARM_DRIVER_VERSION       GetVersion_ ## N(void);                                                       \
 | 
			
		||||
    extern "C" ARM_STORAGE_CAPABILITIES GetCapabilities_ ## N(void);                                                  \
 | 
			
		||||
    extern "C" int32_t                  Initialize_ ## N(ARM_Storage_Callback_t callback);                            \
 | 
			
		||||
    extern "C" int32_t                  Uninitialize_ ## N(void);                                                     \
 | 
			
		||||
    extern "C" int32_t                  PowerControl_ ## N(ARM_POWER_STATE state);                                    \
 | 
			
		||||
    extern "C" int32_t                  ReadData_ ## N(uint64_t addr, void *data, uint32_t size);                     \
 | 
			
		||||
    extern "C" int32_t                  ProgramData_ ## N(uint64_t addr, const void *data, uint32_t size);            \
 | 
			
		||||
    extern "C" int32_t                  Erase_ ## N(uint64_t addr, uint32_t size);                                    \
 | 
			
		||||
    extern "C" int32_t                  EraseAll_ ## N(void);                                                         \
 | 
			
		||||
    extern "C" ARM_STORAGE_STATUS       GetStatus_ ## N(void);                                                        \
 | 
			
		||||
    extern "C" int32_t                  GetInfo_ ## N(ARM_STORAGE_INFO *infoP);                                       \
 | 
			
		||||
    extern "C" uint32_t                 ResolveAddress_ ## N(uint64_t addr);                                          \
 | 
			
		||||
    extern "C" int32_t                  GetNextBlock_ ## N(const ARM_STORAGE_BLOCK* prevP, ARM_STORAGE_BLOCK *nextP); \
 | 
			
		||||
    extern "C" int32_t                  GetBlock_ ## N(uint64_t addr, ARM_STORAGE_BLOCK *blockP);
 | 
			
		||||
 | 
			
		||||
#define STORAGE_API_EXTERN_C_DECLARATIONS_LIST_FOR_1 STORAGE_API_EXTERN_C_DECLARATIONS_FOR_VOLUME(0)
 | 
			
		||||
#define STORAGE_API_EXTERN_C_DECLARATIONS_LIST_FOR_2 STORAGE_API_EXTERN_C_DECLARATIONS_LIST_FOR_1 STORAGE_API_EXTERN_C_DECLARATIONS_FOR_VOLUME(1)
 | 
			
		||||
#define STORAGE_API_EXTERN_C_DECLARATIONS_LIST_FOR_3 STORAGE_API_EXTERN_C_DECLARATIONS_LIST_FOR_2 STORAGE_API_EXTERN_C_DECLARATIONS_FOR_VOLUME(2)
 | 
			
		||||
#define STORAGE_API_EXTERN_C_DECLARATIONS_LIST_FOR_4 STORAGE_API_EXTERN_C_DECLARATIONS_LIST_FOR_3 STORAGE_API_EXTERN_C_DECLARATIONS_FOR_VOLUME(3)
 | 
			
		||||
/* ... add more of the above if ever needed */
 | 
			
		||||
 | 
			
		||||
#define STORAGE_API_EXTERN_C_DECLARATIONS_LIST(N) EXPAND(CONCATENATE(STORAGE_API_EXTERN_C_DECLARATIONS_LIST_FOR_, N))
 | 
			
		||||
 | 
			
		||||
STORAGE_API_EXTERN_C_DECLARATIONS_LIST(MAX_VOLUMES);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Error return codes specific to the Storage volume manager. These extend the
 | 
			
		||||
 * common error codes from ARM_DRIVER_STORAGE. All Volume-manager APIs return an
 | 
			
		||||
 * int32_t to allow for both error and success status returns. This enumeration
 | 
			
		||||
 * contains all possible error status values.
 | 
			
		||||
 */
 | 
			
		||||
typedef enum _StorageVolumeManager_Status
 | 
			
		||||
{
 | 
			
		||||
    STORAGE_VOLUME_MANAGER_STATUS_ERROR_EXHASTED_VOLUMES     = -7,  ///< exhausted the supply of available volumes
 | 
			
		||||
    STORAGE_VOLUME_MANAGER_STATUS_ERROR_NOT_ERASABLE         = -8,  ///< Part (or all) of the range provided to Erase() isn't erasable.
 | 
			
		||||
    STORAGE_VOLUME_MANAGER_STATUS_ERROR_NOT_PROGRAMMABLE     = -9,  ///< Part (or all) of the range provided to ProgramData() isn't programmable.
 | 
			
		||||
    STORAGE_VOLUME_MANAGER_STATUS_ERROR_PROTECTED            = -10, ///< Part (or all) of the range to Erase() or ProgramData() is protected.
 | 
			
		||||
    STORAGE_VOLUME_MANAGER_STATUS_ERROR_NOT_INITIALIZED      = -11, ///< underlying storage not initialized
 | 
			
		||||
    STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED = -12, ///< attempt to operate on an unallocated volume
 | 
			
		||||
} StorageVolumeManager_Status_t;
 | 
			
		||||
 | 
			
		||||
typedef void (*InitializeCallback_t)(int32_t status);
 | 
			
		||||
class StorageVolumeManager; /* forward declaration */
 | 
			
		||||
 | 
			
		||||
class StorageVolume {
 | 
			
		||||
public:
 | 
			
		||||
    StorageVolume() : allocated(false) { /* empty */ }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    void setup(uint64_t addr, uint64_t size, StorageVolumeManager *volumeManager);
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Mimic the API of ARM_DRIVER_STORAGE
 | 
			
		||||
     */
 | 
			
		||||
public:
 | 
			
		||||
    ARM_DRIVER_VERSION       GetVersion(void);
 | 
			
		||||
    ARM_STORAGE_CAPABILITIES GetCapabilities(void);
 | 
			
		||||
    int32_t                  Initialize(ARM_Storage_Callback_t callback);
 | 
			
		||||
    int32_t                  Uninitialize(void);
 | 
			
		||||
    int32_t                  PowerControl(ARM_POWER_STATE state);
 | 
			
		||||
    int32_t                  ReadData(uint64_t addr, void *data, uint32_t size);
 | 
			
		||||
    int32_t                  ProgramData(uint64_t addr, const void *data, uint32_t size);
 | 
			
		||||
    int32_t                  Erase(uint64_t addr, uint32_t size);
 | 
			
		||||
    int32_t                  EraseAll(void);
 | 
			
		||||
    ARM_STORAGE_STATUS       GetStatus(void);
 | 
			
		||||
    int32_t                  GetInfo(ARM_STORAGE_INFO *infoP);
 | 
			
		||||
    uint32_t                 ResolveAddress(uint64_t addr);
 | 
			
		||||
    int32_t                  GetNextBlock(const ARM_STORAGE_BLOCK* prevP, ARM_STORAGE_BLOCK *nextP);
 | 
			
		||||
    int32_t                  GetBlock(uint64_t addr, ARM_STORAGE_BLOCK *blockP);
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    bool isAllocated(void) const {
 | 
			
		||||
        return allocated;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void deallocate(void) {
 | 
			
		||||
        allocated = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Accessor methods.
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    uint64_t getVolumeOffset(void) const {
 | 
			
		||||
        return volumeOffset;
 | 
			
		||||
    }
 | 
			
		||||
    uint64_t getVolumeSize(void) const {
 | 
			
		||||
        return volumeSize;
 | 
			
		||||
    }
 | 
			
		||||
    const ARM_Storage_Callback_t &getCallback(void) const {
 | 
			
		||||
        return callback;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    bool overlapsWithBlock(const ARM_STORAGE_BLOCK* blockP) const {
 | 
			
		||||
        return (((blockP->addr + blockP->size) <= volumeOffset) || ((volumeOffset + volumeSize) <= blockP->addr)) ? false : true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void transformBlockToVolume(ARM_STORAGE_BLOCK *blockP) const {
 | 
			
		||||
        if (blockP->addr < volumeOffset) {
 | 
			
		||||
            blockP->addr = volumeOffset;
 | 
			
		||||
        }
 | 
			
		||||
        if ((blockP->addr + blockP->size) > (volumeOffset + volumeSize)) {
 | 
			
		||||
            blockP->size = (volumeOffset + volumeSize) - blockP->addr;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        blockP->addr -= volumeOffset;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    bool                    allocated;
 | 
			
		||||
    uint64_t                volumeOffset;
 | 
			
		||||
    uint64_t                volumeSize;
 | 
			
		||||
    ARM_Storage_Callback_t  callback;
 | 
			
		||||
    StorageVolumeManager   *volumeManager;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class StorageVolumeManager {
 | 
			
		||||
public:
 | 
			
		||||
    StorageVolumeManager()  { /* empty */ }
 | 
			
		||||
    ~StorageVolumeManager() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialize the storage MTD and prepare it for operation within the context of the volume manager.
 | 
			
		||||
     *
 | 
			
		||||
     * @param[in] storage
 | 
			
		||||
     *              The underlying MTD.
 | 
			
		||||
     * @param[in] callback
 | 
			
		||||
     *              A callback to be invoked upon completion of initialization.
 | 
			
		||||
     *
 | 
			
		||||
     * @return If asynchronous activity is launched, an invocation returns
 | 
			
		||||
     *     ARM_DRIVER_OK, and the caller can expect to receive a
 | 
			
		||||
     *     callback in the future with a status value of ARM_DRIVER_OK or an error-
 | 
			
		||||
     *     code. In the case of synchronous execution, control returns after
 | 
			
		||||
     *     completion with a value of 1. Return values less than
 | 
			
		||||
     *     ARM_DRIVER_OK (0) signify errors.
 | 
			
		||||
     */
 | 
			
		||||
    int32_t initialize(ARM_DRIVER_STORAGE *mtd, InitializeCallback_t callback);
 | 
			
		||||
 | 
			
		||||
    int32_t addVolume(uint64_t addr, uint64_t size, StorageVolume **volumePP);
 | 
			
		||||
    int32_t addVolume_C(uint64_t addr, uint64_t size, _ARM_DRIVER_STORAGE *mtd);
 | 
			
		||||
    int32_t lookupVolume(uint64_t addr, StorageVolume **volumePP);
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Accessor methods.
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    bool isInitialized() const {
 | 
			
		||||
        return initialized;
 | 
			
		||||
    }
 | 
			
		||||
    ARM_DRIVER_STORAGE *getStorage(void) const {
 | 
			
		||||
        return storage;
 | 
			
		||||
    }
 | 
			
		||||
    const ARM_STORAGE_INFO &getStorageInfo(void) const {
 | 
			
		||||
        return storageInfo;
 | 
			
		||||
    }
 | 
			
		||||
    const ARM_STORAGE_CAPABILITIES &getStorageCapabilities(void) const {
 | 
			
		||||
        return storageCapabilities;
 | 
			
		||||
    }
 | 
			
		||||
    StorageVolume *volumeAtIndex(size_t index) {
 | 
			
		||||
        return &volumes[index];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    static void storageCallback(int32_t status, ARM_STORAGE_OPERATION operation);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    friend int32_t StorageVolume::PowerControl(ARM_POWER_STATE state);
 | 
			
		||||
    friend int32_t StorageVolume::ReadData(uint64_t addr, void *data, uint32_t size);
 | 
			
		||||
    friend int32_t StorageVolume::ProgramData(uint64_t addr, const void *data, uint32_t size);
 | 
			
		||||
    friend int32_t StorageVolume::Erase(uint64_t addr, uint32_t size);
 | 
			
		||||
    friend int32_t StorageVolume::EraseAll(void);
 | 
			
		||||
    friend ARM_STORAGE_STATUS StorageVolume::GetStatus(void);
 | 
			
		||||
    StorageVolume *activeVolume; /* This state-variable is set to point to a volume
 | 
			
		||||
                                  * while there is pending activity. It tracks
 | 
			
		||||
                                  * the volume which is at the source of the
 | 
			
		||||
                                  * activity. Once the activity finishes, this
 | 
			
		||||
                                  * variable is reset. Having this variable set
 | 
			
		||||
                                  * might be used as an indication that the
 | 
			
		||||
                                  * underlying storage is busy. */
 | 
			
		||||
 | 
			
		||||
#define FRIEND_DECLARATIONS_FOR_VOLUME(N) \
 | 
			
		||||
  friend ARM_DRIVER_VERSION       GetVersion_ ## N(void);                                                       \
 | 
			
		||||
  friend ARM_STORAGE_CAPABILITIES GetCapabilities_ ## N(void);                                                  \
 | 
			
		||||
  friend int32_t                  Initialize_ ## N(ARM_Storage_Callback_t callback);                            \
 | 
			
		||||
  friend int32_t                  Uninitialize_ ## N(void);                                                     \
 | 
			
		||||
  friend int32_t                  PowerControl_ ## N(ARM_POWER_STATE state);                                    \
 | 
			
		||||
  friend int32_t                  ReadData_ ## N(uint64_t addr, void *data, uint32_t size);                     \
 | 
			
		||||
  friend int32_t                  ProgramData_ ## N(uint64_t addr, const void *data, uint32_t size);            \
 | 
			
		||||
  friend int32_t                  Erase_ ## N(uint64_t addr, uint32_t size);                                    \
 | 
			
		||||
  friend int32_t                  EraseAll_ ## N(void);                                                         \
 | 
			
		||||
  friend ARM_STORAGE_STATUS       GetStatus_ ## N(void);                                                        \
 | 
			
		||||
  friend int32_t                  GetInfo_ ## N(ARM_STORAGE_INFO *infoP);                                       \
 | 
			
		||||
  friend uint32_t                 ResolveAddress_ ## N(uint64_t addr);                                          \
 | 
			
		||||
  friend int32_t                  GetNextBlock_ ## N(const ARM_STORAGE_BLOCK* prevP, ARM_STORAGE_BLOCK *nextP); \
 | 
			
		||||
  friend int32_t                  GetBlock_ ## N(uint64_t addr, ARM_STORAGE_BLOCK *blockP);
 | 
			
		||||
 | 
			
		||||
#define FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES_FOR_1 FRIEND_DECLARATIONS_FOR_VOLUME(0)
 | 
			
		||||
#define FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES_FOR_2 FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES_FOR_1 FRIEND_DECLARATIONS_FOR_VOLUME(1)
 | 
			
		||||
#define FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES_FOR_3 FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES_FOR_2 FRIEND_DECLARATIONS_FOR_VOLUME(2)
 | 
			
		||||
#define FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES_FOR_4 FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES_FOR_3 FRIEND_DECLARATIONS_FOR_VOLUME(3)
 | 
			
		||||
/* ... add more of the above if ever needed */
 | 
			
		||||
 | 
			
		||||
#define FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES(N) EXPAND(CONCATENATE(FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES_FOR_, N))
 | 
			
		||||
 | 
			
		||||
    //todo: remove FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES(MAX_VOLUMES);
 | 
			
		||||
    FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES(MAX_VOLUMES)
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    size_t findIndexOfUnusedVolume(void) const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    bool                      initialized;
 | 
			
		||||
    ARM_DRIVER_STORAGE       *storage;
 | 
			
		||||
    ARM_STORAGE_INFO          storageInfo;
 | 
			
		||||
    ARM_STORAGE_CAPABILITIES  storageCapabilities;
 | 
			
		||||
    StorageVolume             volumes[MAX_VOLUMES];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* __STORAGE_VOLUME_MANAGER_H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -15,8 +15,6 @@
 | 
			
		|||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#if DEVICE_STORAGE
 | 
			
		||||
 | 
			
		||||
#include "Driver_Storage.h"
 | 
			
		||||
#include "cmsis_nvic.h"
 | 
			
		||||
#include "MK64F12.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -33,6 +31,10 @@
 | 
			
		|||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
/* Redefine this macro to a printf equivalent to print trace */
 | 
			
		||||
#define tr_debug(...)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef USING_KSDK2
 | 
			
		||||
/*!
 | 
			
		||||
 * @name Misc utility defines
 | 
			
		||||
| 
						 | 
				
			
			@ -142,6 +144,76 @@ extern volatile uint32_t *const kFCCOBx;
 | 
			
		|||
#define SIZEOF_DOUBLE_PHRASE              (16)
 | 
			
		||||
#endif /* #ifdef USING_KSDK2 */
 | 
			
		||||
 | 
			
		||||
/* While the K64F flash controller is capable of launching operations asynchronously and
 | 
			
		||||
 * allowing program execution to continue while an erase/program is active, it
 | 
			
		||||
 * doesn't allow simultaneous read accesses while and erase/program is active on
 | 
			
		||||
 * the same block of flash.
 | 
			
		||||
 *
 | 
			
		||||
 * Read/fetch accesses can originate arbitrarily as a result of program
 | 
			
		||||
 * execution. This means that code which operates on flash should not reside in
 | 
			
		||||
 * flash; or at least it should not reside in the same bank of flash as it is
 | 
			
		||||
 * operating upon. The only way to ensure that application code and flash driver
 | 
			
		||||
 * are residing on separate banks of flash is to reserve bank-0 (or BLOCK0) for
 | 
			
		||||
 * the application and bank-1 (BLOCK1) for the driver--this also happens to be
 | 
			
		||||
 * the default setting.
 | 
			
		||||
 *
 | 
			
		||||
 * But it is quite likely that this default will be over-ridden by the use of
 | 
			
		||||
 * config options depending upon the actual application. If we don't have a
 | 
			
		||||
 * clean separation between the application and the space managed by this
 | 
			
		||||
 * driver, then we need to enforce the following:
 | 
			
		||||
 *
 | 
			
		||||
 *   - Force synchronous mode of execution in the storage_driver.
 | 
			
		||||
 *   - Disable interrupts during erase/program operations.
 | 
			
		||||
 *   - Ensure all code and data structures used in the storage driver execute
 | 
			
		||||
 *     out of RAM. Refer to __RAMFUNC (below) which allows for this.
 | 
			
		||||
 *
 | 
			
		||||
 * It is difficult to determine the application's span of internal-flash at
 | 
			
		||||
 * compile time. Therefore we assume that STORAGE_START_ADDR is the
 | 
			
		||||
 * boundary between application and this driver. When this boundary is set to
 | 
			
		||||
 * lie at BLOCK1_START_ADDR, there is no possibility of read-while-write run-
 | 
			
		||||
 * time errors.
 | 
			
		||||
 *
 | 
			
		||||
 * In the following, caps.asynchronous_ops is defined to be 1 if and only if
 | 
			
		||||
 * asynchronous operation mode is requested and there doesn't exist the
 | 
			
		||||
 * possibility of concurrent reads.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#if (defined(STORAGE_START_ADDR) && (STORAGE_START_ADDR != BLOCK1_START_ADDR))
 | 
			
		||||
#define EXISTS_POSSIBILITY_OF_CONCURRENT_READ 1
 | 
			
		||||
#else
 | 
			
		||||
#define EXISTS_POSSIBILITY_OF_CONCURRENT_READ 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Define '__RAMFUNC' as an attribute to mark a function as residing in RAM.
 | 
			
		||||
 * Use of __RAMFUNC puts a function in the .data section--i.e. the
 | 
			
		||||
 * initialized data section. This will be copied into RAM automatically by the
 | 
			
		||||
 * startup sequence. */
 | 
			
		||||
#ifndef __RAMFUNC
 | 
			
		||||
#if defined(__GNUC__) || defined(__clang__) // GCC and llvm/clang
 | 
			
		||||
#define __RAMFUNC __attribute__ ((section (".data#"), noinline)) /* The '#' following ".data" needs a bit of
 | 
			
		||||
                        * explanation. Without it, we are liable to get the following warning 'Warning: ignoring
 | 
			
		||||
                        * changed section attributes for .data'. This is because __attribute__((section(".data")))
 | 
			
		||||
                        * generates the following assembly:
 | 
			
		||||
                        *
 | 
			
		||||
                        * .section .data,"ax",%progbits
 | 
			
		||||
                        *
 | 
			
		||||
                        * But .data doesn't need the 'x' (execute) attribute bit. To remove the warning, we specify
 | 
			
		||||
                        * the attribute with a '#' at the tail, which emits:
 | 
			
		||||
                        *
 | 
			
		||||
                        * .section .data#,"ax",%progbits
 | 
			
		||||
                        *
 | 
			
		||||
                        * Note that '#' (in the above) acts like a comment-start, and masks the additional
 | 
			
		||||
                        * attributes which don't apply to '.data'.
 | 
			
		||||
                        */
 | 
			
		||||
#elif defined (__CC_ARM)
 | 
			
		||||
#define __RAMFUNC __attribute__ ((section(".ramfunc"), noinline))
 | 
			
		||||
#elif defined ( __ICCARM__ )
 | 
			
		||||
#define __RAMFUNC __ramfunc
 | 
			
		||||
#else // unknown compiler
 | 
			
		||||
    #error "This compiler is not yet supported. If you can contribute support for defining a function to be RAM resident, please provide a definition for __RAMFUNC"
 | 
			
		||||
#endif
 | 
			
		||||
#endif /* #ifndef __RAMFUNC */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * forward declarations
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -169,16 +241,16 @@ struct mtd_k64f_data {
 | 
			
		|||
static const ARM_STORAGE_BLOCK blockTable[] = {
 | 
			
		||||
    {
 | 
			
		||||
        /**< This is the start address of the flash block. */
 | 
			
		||||
#ifdef DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_START_ADDR
 | 
			
		||||
        .addr       = DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_START_ADDR,
 | 
			
		||||
#ifdef STORAGE_START_ADDR
 | 
			
		||||
        .addr       = STORAGE_START_ADDR,
 | 
			
		||||
#else
 | 
			
		||||
        .addr       = BLOCK1_START_ADDR,
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        /**< This is the size of the flash block, in units of bytes.
 | 
			
		||||
         *   Together with addr, it describes a range [addr, addr+size). */
 | 
			
		||||
#ifdef DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_SIZE
 | 
			
		||||
        .size       = DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_SIZE,
 | 
			
		||||
#ifdef STORAGE_SIZE
 | 
			
		||||
        .size       = STORAGE_SIZE,
 | 
			
		||||
#else
 | 
			
		||||
        .size       = BLOCK1_SIZE,
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -200,7 +272,8 @@ static const ARM_DRIVER_VERSION version = {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if (!defined(DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS) || DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS)
 | 
			
		||||
#if ((!defined(STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS) || STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS) && \
 | 
			
		||||
     !EXISTS_POSSIBILITY_OF_CONCURRENT_READ)
 | 
			
		||||
#define ASYNC_OPS 1
 | 
			
		||||
#else
 | 
			
		||||
#define ASYNC_OPS 0
 | 
			
		||||
| 
						 | 
				
			
			@ -219,8 +292,8 @@ static const ARM_STORAGE_CAPABILITIES caps = {
 | 
			
		|||
    .asynchronous_ops = ASYNC_OPS,
 | 
			
		||||
 | 
			
		||||
    /* Enable chip-erase functionality if we own all of block-1. */
 | 
			
		||||
    #if ((!defined (DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_START_ADDR) || (DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_START_ADDR == BLOCK1_START_ADDR)) && \
 | 
			
		||||
         (!defined (DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_SIZE)       || (DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_SIZE == BLOCK1_SIZE)))
 | 
			
		||||
    #if ((!defined (STORAGE_START_ADDR) || (STORAGE_START_ADDR == BLOCK1_START_ADDR)) && \
 | 
			
		||||
         (!defined (STORAGE_SIZE)       || (STORAGE_SIZE == BLOCK1_SIZE)))
 | 
			
		||||
    .erase_all        = 1,    /**< Supports EraseChip operation. */
 | 
			
		||||
    #else
 | 
			
		||||
    .erase_all        = 0,    /**< Supports EraseChip operation. */
 | 
			
		||||
| 
						 | 
				
			
			@ -228,8 +301,8 @@ static const ARM_STORAGE_CAPABILITIES caps = {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
static const ARM_STORAGE_INFO info = {
 | 
			
		||||
#ifdef DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_SIZE
 | 
			
		||||
    .total_storage        = DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_SIZE, /**< Total available storage, in units of octets. */
 | 
			
		||||
#ifdef STORAGE_SIZE
 | 
			
		||||
    .total_storage        = STORAGE_SIZE, /**< Total available storage, in units of octets. */
 | 
			
		||||
#else
 | 
			
		||||
    .total_storage        = BLOCK1_SIZE, /**< Total available storage, in units of octets. By default, BLOCK0 is reserved to hold program code. */
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -410,6 +483,10 @@ static inline void launchCommand(void)
 | 
			
		|||
 | 
			
		||||
#else /* #if !ASYNC_OPS */
 | 
			
		||||
 | 
			
		||||
#if EXISTS_POSSIBILITY_OF_CONCURRENT_READ
 | 
			
		||||
/* This function needs to execute from RAM to avoid read-while-write errors. */
 | 
			
		||||
__RAMFUNC
 | 
			
		||||
#endif
 | 
			
		||||
static void launchCommandAndWaitForCompletion()
 | 
			
		||||
{
 | 
			
		||||
    // It contains the inlined equivalent of the following code snippet:
 | 
			
		||||
| 
						 | 
				
			
			@ -418,10 +495,17 @@ static void launchCommandAndWaitForCompletion()
 | 
			
		|||
    //         /* Spin waiting for the command execution to complete. */
 | 
			
		||||
    //     }
 | 
			
		||||
 | 
			
		||||
#ifdef USING_KSDK2
 | 
			
		||||
    FTFx->FSTAT = FTFx_FSTAT_CCIF_MASK; /* launchcommand() */
 | 
			
		||||
    while ((FTFx->FSTAT & FTFx_FSTAT_CCIF_MASK) == 0) {
 | 
			
		||||
        /* Spin waiting for the command execution to complete. */
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    BW_FTFE_FSTAT_CCIF(FTFE, 1); /* launchCommand() */
 | 
			
		||||
    while (BR_FTFE_FSTAT_CCIF(FTFE) == 0) {
 | 
			
		||||
        /* Spin waiting for the command execution to complete. */
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
#endif /* #if !ASYNC_OPS */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -562,6 +646,7 @@ static inline void setupNextProgramData(struct mtd_k64f_data *context)
 | 
			
		|||
    if ((context->amountLeftToOperate == PROGRAM_PHRASE_SIZEOF_INLINE_DATA) ||
 | 
			
		||||
        ((context->currentOperatingStorageAddress % SIZEOF_DOUBLE_PHRASE) == PROGRAM_PHRASE_SIZEOF_INLINE_DATA)) {
 | 
			
		||||
        setup8ByteWrite(context->currentOperatingStorageAddress, context->currentOperatingData);
 | 
			
		||||
        tr_debug("setupNextProgramData: W8, [%lu]", (uint32_t)context->currentOperatingStorageAddress);
 | 
			
		||||
 | 
			
		||||
        context->amountLeftToOperate            -= PROGRAM_PHRASE_SIZEOF_INLINE_DATA;
 | 
			
		||||
        context->currentOperatingStorageAddress += PROGRAM_PHRASE_SIZEOF_INLINE_DATA;
 | 
			
		||||
| 
						 | 
				
			
			@ -569,6 +654,7 @@ static inline void setupNextProgramData(struct mtd_k64f_data *context)
 | 
			
		|||
    } else {
 | 
			
		||||
        size_t amount = sizeofLargestProgramSection(context->currentOperatingStorageAddress, context->amountLeftToOperate);
 | 
			
		||||
        setupProgramSection(context->currentOperatingStorageAddress, context->currentOperatingData, amount);
 | 
			
		||||
        tr_debug("setupNextProgramData: W%u, [%lu]", amount, (uint32_t)context->currentOperatingStorageAddress);
 | 
			
		||||
 | 
			
		||||
        context->amountLeftToOperate            -= amount;
 | 
			
		||||
        context->currentOperatingStorageAddress += amount;
 | 
			
		||||
| 
						 | 
				
			
			@ -607,6 +693,8 @@ static inline void setupNextErase(struct mtd_k64f_data *context)
 | 
			
		|||
 | 
			
		||||
static int32_t executeCommand(struct mtd_k64f_data *context)
 | 
			
		||||
{
 | 
			
		||||
    tr_debug("executeCommand: top");
 | 
			
		||||
 | 
			
		||||
#if ASYNC_OPS
 | 
			
		||||
    /* Asynchronous operation */
 | 
			
		||||
    (void)context; /* avoid compiler warning about un-used variables */
 | 
			
		||||
| 
						 | 
				
			
			@ -624,12 +712,21 @@ static int32_t executeCommand(struct mtd_k64f_data *context)
 | 
			
		|||
 | 
			
		||||
    enableCommandCompletionInterrupt();
 | 
			
		||||
 | 
			
		||||
    tr_debug("executeCommand: async. return");
 | 
			
		||||
    return ARM_DRIVER_OK; /* signal asynchronous completion. An interrupt will signal completion later. */
 | 
			
		||||
#else /* #if ASYNC_OPS */
 | 
			
		||||
    /* Synchronous operation. */
 | 
			
		||||
    /* Synchronous operation. This is the common case. */
 | 
			
		||||
 | 
			
		||||
    while (1) {
 | 
			
		||||
        tr_debug("executeCommand: synchronous iteration");
 | 
			
		||||
 | 
			
		||||
        #if EXISTS_POSSIBILITY_OF_CONCURRENT_READ
 | 
			
		||||
        __disable_irq();
 | 
			
		||||
        #endif
 | 
			
		||||
        launchCommandAndWaitForCompletion();
 | 
			
		||||
        #if EXISTS_POSSIBILITY_OF_CONCURRENT_READ
 | 
			
		||||
        __enable_irq();
 | 
			
		||||
        #endif
 | 
			
		||||
 | 
			
		||||
        /* Execution may result in failure. Check for errors */
 | 
			
		||||
        if (failedWithAccessError() || failedWithProtectionError()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -664,6 +761,7 @@ static int32_t executeCommand(struct mtd_k64f_data *context)
 | 
			
		|||
                        break;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        /* erase can be skipped since this sector is already erased. */
 | 
			
		||||
                        tr_debug("fast forward erase");
 | 
			
		||||
                        progressEraseContextByEraseUnit(context);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -691,6 +789,7 @@ static inline void launchCommandFromIRQ(const struct mtd_k64f_data *context)
 | 
			
		|||
    if (failedWithAccessError() || failedWithProtectionError()) {
 | 
			
		||||
        clearErrorStatusBits();
 | 
			
		||||
        if (context->commandCompletionCallback) {
 | 
			
		||||
            tr_debug("irq: invoking callback with error");
 | 
			
		||||
            context->commandCompletionCallback(ARM_DRIVER_ERROR_PARAMETER, context->currentCommand);
 | 
			
		||||
        }
 | 
			
		||||
        return;
 | 
			
		||||
| 
						 | 
				
			
			@ -726,6 +825,7 @@ static void ftfe_ccie_irq_handler(void)
 | 
			
		|||
        case ARM_STORAGE_OPERATION_PROGRAM_DATA:
 | 
			
		||||
            if (context->amountLeftToOperate == 0) {
 | 
			
		||||
                if (context->commandCompletionCallback) {
 | 
			
		||||
                    tr_debug("irq: [PROGRAM] invoking callback");
 | 
			
		||||
                    context->commandCompletionCallback(context->sizeofCurrentOperation, ARM_STORAGE_OPERATION_PROGRAM_DATA);
 | 
			
		||||
                }
 | 
			
		||||
                return;
 | 
			
		||||
| 
						 | 
				
			
			@ -745,11 +845,13 @@ static void ftfe_ccie_irq_handler(void)
 | 
			
		|||
                    break;
 | 
			
		||||
                } else {
 | 
			
		||||
                    /* erase can be skipped since this sector is already erased. */
 | 
			
		||||
                    tr_debug("fast forward erase");
 | 
			
		||||
                    progressEraseContextByEraseUnit(context);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (context->amountLeftToOperate == 0) {
 | 
			
		||||
                if (context->commandCompletionCallback) {
 | 
			
		||||
                    tr_debug("irq: [ERASE] invoking callback");
 | 
			
		||||
                    context->commandCompletionCallback(context->sizeofCurrentOperation, ARM_STORAGE_OPERATION_ERASE);
 | 
			
		||||
                }
 | 
			
		||||
                return;
 | 
			
		||||
| 
						 | 
				
			
			@ -761,6 +863,7 @@ static void ftfe_ccie_irq_handler(void)
 | 
			
		|||
 | 
			
		||||
        default:
 | 
			
		||||
            if (context->commandCompletionCallback) {
 | 
			
		||||
                tr_debug("irq: [default] invoking callback");
 | 
			
		||||
                context->commandCompletionCallback(ARM_DRIVER_OK, context->currentCommand);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
| 
						 | 
				
			
			@ -827,6 +930,8 @@ static ARM_STORAGE_CAPABILITIES getCapabilities(void)
 | 
			
		|||
 | 
			
		||||
static int32_t initialize(ARM_Storage_Callback_t callback)
 | 
			
		||||
{
 | 
			
		||||
    tr_debug("called initialize(%p)", callback);
 | 
			
		||||
 | 
			
		||||
    struct mtd_k64f_data *context = &mtd_k64f_data;
 | 
			
		||||
    memset(context, 0, sizeof(mtd_k64f_data));
 | 
			
		||||
    context->currentCommand = ARM_STORAGE_OPERATION_INITIALIZE;
 | 
			
		||||
| 
						 | 
				
			
			@ -860,6 +965,8 @@ static int32_t initialize(ARM_Storage_Callback_t callback)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static int32_t uninitialize(void) {
 | 
			
		||||
    tr_debug("called uninitialize");
 | 
			
		||||
 | 
			
		||||
    struct mtd_k64f_data *context = &mtd_k64f_data;
 | 
			
		||||
    context->currentCommand = ARM_STORAGE_OPERATION_UNINITIALIZE;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -883,6 +990,8 @@ static int32_t uninitialize(void) {
 | 
			
		|||
 | 
			
		||||
static int32_t powerControl(ARM_POWER_STATE state)
 | 
			
		||||
{
 | 
			
		||||
    tr_debug("called powerControl(%u)", state);
 | 
			
		||||
 | 
			
		||||
    struct mtd_k64f_data *context = &mtd_k64f_data;
 | 
			
		||||
    context->currentCommand = ARM_STORAGE_OPERATION_POWER_CONTROL;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -892,6 +1001,8 @@ static int32_t powerControl(ARM_POWER_STATE state)
 | 
			
		|||
 | 
			
		||||
static int32_t readData(uint64_t addr, void *data, uint32_t size)
 | 
			
		||||
{
 | 
			
		||||
    tr_debug("called ReadData(%lu, %lu)", (uint32_t)addr, size);
 | 
			
		||||
 | 
			
		||||
    struct mtd_k64f_data *context = &mtd_k64f_data;
 | 
			
		||||
    context->currentCommand = ARM_STORAGE_OPERATION_READ_DATA;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -914,6 +1025,8 @@ static int32_t readData(uint64_t addr, void *data, uint32_t size)
 | 
			
		|||
 | 
			
		||||
static int32_t programData(uint64_t addr, const void *data, uint32_t size)
 | 
			
		||||
{
 | 
			
		||||
    tr_debug("called ProgramData(%lu, %lu)", (uint32_t)addr, size);
 | 
			
		||||
 | 
			
		||||
    struct mtd_k64f_data *context = &mtd_k64f_data;
 | 
			
		||||
    if (!context->initialized) {
 | 
			
		||||
        return (int32_t)ARM_DRIVER_ERROR; /* illegal */
 | 
			
		||||
| 
						 | 
				
			
			@ -955,6 +1068,8 @@ static int32_t programData(uint64_t addr, const void *data, uint32_t size)
 | 
			
		|||
 | 
			
		||||
static int32_t erase(uint64_t addr, uint32_t size)
 | 
			
		||||
{
 | 
			
		||||
    tr_debug("called erase(%lu, %lu)", (uint32_t)addr, size);
 | 
			
		||||
 | 
			
		||||
    struct mtd_k64f_data *context = &mtd_k64f_data;
 | 
			
		||||
 | 
			
		||||
    if (!context->initialized) {
 | 
			
		||||
| 
						 | 
				
			
			@ -995,6 +1110,8 @@ static int32_t erase(uint64_t addr, uint32_t size)
 | 
			
		|||
 | 
			
		||||
static int32_t eraseAll(void)
 | 
			
		||||
{
 | 
			
		||||
    tr_debug("called eraseAll");
 | 
			
		||||
 | 
			
		||||
    struct mtd_k64f_data *context = &mtd_k64f_data;
 | 
			
		||||
 | 
			
		||||
    if (!context->initialized) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1105,7 +1222,7 @@ int32_t getBlock(uint64_t addr, ARM_STORAGE_BLOCK *blockP)
 | 
			
		|||
    return ARM_DRIVER_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ARM_DRIVER_STORAGE ARM_Driver_Storage_(0) = {
 | 
			
		||||
ARM_DRIVER_STORAGE ARM_Driver_Storage_MTD_K64F = {
 | 
			
		||||
    .GetVersion      = getVersion,
 | 
			
		||||
    .GetCapabilities = getCapabilities,
 | 
			
		||||
    .Initialize      = initialize,
 | 
			
		||||
| 
						 | 
				
			
			@ -1121,5 +1238,3 @@ ARM_DRIVER_STORAGE ARM_Driver_Storage_(0) = {
 | 
			
		|||
    .GetNextBlock    = nextBlock,
 | 
			
		||||
    .GetBlock        = getBlock
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* #if DEVICE_STORAGE */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue