Adding mbed-os/features/storage to mbed/features/storage/FEATURE_STORAGE (before deleting mbed-os/features/storage).
| 
						 | 
				
			
			@ -0,0 +1,309 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 add_del.cpp Test cases to add and delete key-value pairs in the CFSTORE.
 | 
			
		||||
 *
 | 
			
		||||
 * Please consult the documentation under the test-case functions for
 | 
			
		||||
 * a description of the individual test case.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#include "cfstore_utest.h"
 | 
			
		||||
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#include "cfstore_uvisor.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
static char cfstore_add_del_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE];
 | 
			
		||||
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
/* Create the main box ACL list for the application.
 | 
			
		||||
 * The main ACL gets inherited by all the other boxes
 | 
			
		||||
 */
 | 
			
		||||
CFSTORE_UVISOR_MAIN_ACL(cfstore_acl_uvisor_box_add_del_g);
 | 
			
		||||
 | 
			
		||||
/* Enable uVisor. */
 | 
			
		||||
UVISOR_SET_MODE_ACL(UVISOR_ENABLED, cfstore_acl_uvisor_box_add_del_g);
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
static cfstore_kv_data_t cfstore_add_del_test_07_data[] = {
 | 
			
		||||
        CFSTORE_INIT_1_TABLE_MID_NODE,
 | 
			
		||||
        { NULL, NULL},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* report whether built/configured for flash sync or async mode */
 | 
			
		||||
static control_t cfstore_add_del_test_00(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    ret = cfstore_test_startup();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to perform test startup (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @brief
 | 
			
		||||
 *
 | 
			
		||||
 * This test case does the following:
 | 
			
		||||
 * - creates a KV.
 | 
			
		||||
 * - deletes the KV.
 | 
			
		||||
 * - checks that the deleted KV can no longer be found in the store.
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_add_del_test_01_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    bool bfound = false;
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_SIZE len = 0;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
    memset(&flags, 0, sizeof(flags));
 | 
			
		||||
 | 
			
		||||
    kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE;
 | 
			
		||||
    len = strlen(cfstore_add_del_test_07_data[0].value);
 | 
			
		||||
 | 
			
		||||
    ret = cfstore_test_create(cfstore_add_del_test_07_data[0].key_name, (char*) cfstore_add_del_test_07_data[0].value, &len, &kdesc);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create KV in store (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* now delete KV*/
 | 
			
		||||
    ret = drv->Open(cfstore_add_del_test_07_data[0].key_name, flags, hkey);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to Open() (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    if(hkey != NULL){
 | 
			
		||||
        ret = drv->Delete(hkey);
 | 
			
		||||
        drv->Close(hkey);
 | 
			
		||||
        hkey = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    /* check that the KV has been deleted */
 | 
			
		||||
    /* revert to CFSTORE_LOG if more trace required */
 | 
			
		||||
    CFSTORE_DBGLOG("LOG: WARNING: About to look for non-existent key (key_name=%s) (which will generate internal trace reporting errors if debug trace enabled).\n", cfstore_add_del_test_07_data[0].key_name);
 | 
			
		||||
    ret = cfstore_test_kv_is_found(cfstore_add_del_test_07_data[0].key_name, &bfound);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error failed to delete a key (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND, cfstore_add_del_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Test failed: found KV that was previously deleted (key_name=%s)\n", __func__, cfstore_add_del_test_07_data[0].key_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(bfound == false, cfstore_add_del_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static cfstore_kv_data_t cfstore_add_del_test_08_data[] = {
 | 
			
		||||
        CFSTORE_INIT_1_TABLE_HEAD,
 | 
			
		||||
        CFSTORE_INIT_1_TABLE_MID_NODE,
 | 
			
		||||
        CFSTORE_INIT_1_TABLE_TAIL,
 | 
			
		||||
        { NULL, NULL},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @brief
 | 
			
		||||
 *
 | 
			
		||||
 * This test case adds a small number of KVs (~3), and then delete them.
 | 
			
		||||
 * - add key(s)
 | 
			
		||||
 * - delete key(s)
 | 
			
		||||
 * - make sure can't find key in cfstore
 | 
			
		||||
 * - loop over the above a number of times.
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_add_del_test_02_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    bool bResult = true;   // We'll do "&=" cumulative checking.
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_SIZE len = 0;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
    cfstore_kv_data_t* node = NULL;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
 | 
			
		||||
    /* create  */
 | 
			
		||||
    kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE;
 | 
			
		||||
    node = cfstore_add_del_test_08_data;
 | 
			
		||||
    while(node->key_name != NULL)
 | 
			
		||||
    {
 | 
			
		||||
        len = strlen(node->value);
 | 
			
		||||
        ret = cfstore_test_create(node->key_name, (char*) node->value, &len, &kdesc);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create kv (key_name=%s.\n", __func__, node->key_name);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g);
 | 
			
		||||
        /* revert CFSTORE_LOG for more trace */
 | 
			
		||||
        CFSTORE_DBGLOG("Created KV successfully (key_name=\"%s\", value=\"%s\")\n", node->key_name, node->value);
 | 
			
		||||
        node++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* test delete all */
 | 
			
		||||
    ret = cfstore_test_delete_all();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to delete all KVs.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* check there are no KVs present as expected */
 | 
			
		||||
    node = cfstore_add_del_test_08_data;
 | 
			
		||||
    while(node->key_name != NULL)
 | 
			
		||||
    {
 | 
			
		||||
        ret = cfstore_test_kv_is_found(node->key_name, &bResult);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: found key when should not be present.\n", __func__);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND && bResult == false, cfstore_add_del_utest_msg_g);
 | 
			
		||||
        /* revert CFSTORE_LOG for more trace */
 | 
			
		||||
        CFSTORE_DBGLOG("Found KV successfully (key_name=\"%s\")\n", node->key_name);
 | 
			
		||||
        node++;
 | 
			
		||||
    }
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @brief
 | 
			
		||||
 *
 | 
			
		||||
 * This test case adds ~50 KVs, and then delete entries at the start,
 | 
			
		||||
 * middle and end of list.
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_add_del_test_03_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    bool bfound = false;
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
    cfstore_kv_data_t *node;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    memset(&flags, 0, sizeof(flags));
 | 
			
		||||
 | 
			
		||||
    ret = cfstore_test_init_1();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to initialise cfstore area with entries\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* delete some keys */
 | 
			
		||||
    node = cfstore_add_del_test_08_data;
 | 
			
		||||
    while(node->key_name != NULL)
 | 
			
		||||
    {
 | 
			
		||||
        CFSTORE_DBGLOG("%s:about to delete key (key_name=%s).\n", __func__, node->key_name);
 | 
			
		||||
        cfstore_test_delete(node->key_name);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error failed to delete a key (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g);
 | 
			
		||||
        /* revert CFSTORE_LOG for more trace */
 | 
			
		||||
        CFSTORE_DBGLOG("Deleted KV successfully (key_name=\"%s\")\n", node->key_name);
 | 
			
		||||
        node++;
 | 
			
		||||
    }
 | 
			
		||||
    /* check the keys have been deleted */
 | 
			
		||||
    node = cfstore_add_del_test_08_data;
 | 
			
		||||
    while(node->key_name != NULL)
 | 
			
		||||
    {
 | 
			
		||||
        ret = cfstore_test_kv_is_found(node->key_name, &bfound);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to delete a key (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND, cfstore_add_del_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Test failed: found KV that was previously deleted (key_name=%s)\n", __func__, node->key_name);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(bfound == false, cfstore_add_del_utest_msg_g);
 | 
			
		||||
        node++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* clean up by deleting all remaining KVs. this is not part of the test */
 | 
			
		||||
    ret = cfstore_test_delete_all();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error failed to delete a all KVs (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to initialize CFSTORE (ret=%d)\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @brief
 | 
			
		||||
 *
 | 
			
		||||
 * This test case is as per test_03 but using delete_all() on all init_1 data.
 | 
			
		||||
 * This test case is yet to be implemented.
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_add_del_test_04(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    /*todo: implement test */
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Warn: Not implemented\n", __func__);
 | 
			
		||||
    CFSTORE_DBGLOG("%s: WARN: requires implementation\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(true, cfstore_add_del_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(100, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
           /*          1         2         3         4         5         6        7  */
 | 
			
		||||
           /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        Case("ADD_DEL_test_00", cfstore_add_del_test_00),
 | 
			
		||||
        Case("ADD_DEL_test_01_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("ADD_DEL_test_01_end", cfstore_add_del_test_01_end),
 | 
			
		||||
        Case("ADD_DEL_test_02_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("ADD_DEL_test_02_end", cfstore_add_del_test_02_end),
 | 
			
		||||
        Case("ADD_DEL_test_03_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("ADD_DEL_test_03_end", cfstore_add_del_test_03_end),
 | 
			
		||||
        Case("ADD_DEL_test_04", cfstore_add_del_test_04),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
/// @endcond
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,251 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 close.cpp Test cases to close KVs in the CFSTORE using the drv->Close() API function.
 | 
			
		||||
 *
 | 
			
		||||
 * Please consult the documentation under the test-case functions for
 | 
			
		||||
 * a description of the individual test case.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#include "cfstore_utest.h"
 | 
			
		||||
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
static char cfstore_close_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE];
 | 
			
		||||
 | 
			
		||||
/* Configure secure box. */
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
UVISOR_BOX_NAMESPACE("com.arm.mbed.cfstore.test.close.box1");
 | 
			
		||||
UVISOR_BOX_CONFIG(cfstore_close_box1, UVISOR_BOX_STACK_SIZE);
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
/* KV data for test_01 */
 | 
			
		||||
static cfstore_kv_data_t cfstore_close_test_01_kv_data[] = {
 | 
			
		||||
        { "yotta.hello-world.animal{wobbly-dog}{foot}frontLeft", "first_data_"},
 | 
			
		||||
        { "yotta.hello-world.animal{wobbly-dog}{foot}frontLeft", "second_data"},
 | 
			
		||||
        { NULL, NULL},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* report whether built/configured for flash sync or async mode */
 | 
			
		||||
static control_t cfstore_close_test_00(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    ret = cfstore_test_startup();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to perform test startup (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @brief
 | 
			
		||||
 *
 | 
			
		||||
 * The is a basic test case which does the following:
 | 
			
		||||
 * - 01. create a key with handle hkey1
 | 
			
		||||
 * - 02. write data of hkey
 | 
			
		||||
 * - 03. opens KV with 2nd handle, hkey2
 | 
			
		||||
 * - 04. read data with hkey2 and make sure its the same as that written with hkey1
 | 
			
		||||
 * - 05. write new data with hkey2
 | 
			
		||||
 * - 06. delete hkey2
 | 
			
		||||
 * - 07. close hkey2
 | 
			
		||||
 * - 08. read hkey1 and make sure the data is the newly written data i.e. the key hasnt
 | 
			
		||||
 *     been deleted yet
 | 
			
		||||
 * - 09. try to open KV and make sure unable to do so, as KV is deleting
 | 
			
		||||
 * - 10. close hkey1
 | 
			
		||||
 * - 11. try to open KV and make sure unable to do so because its now been deleted
 | 
			
		||||
 * - 12. create new KV with same key_name to make sure can re-create the key again.
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_close_test_01_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    char read_buf[CFSTORE_KEY_NAME_MAX_LENGTH];
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_SIZE len = 0;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(hkey1);
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(hkey2);
 | 
			
		||||
    cfstore_kv_data_t *node;
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    node = &cfstore_close_test_01_kv_data[0];
 | 
			
		||||
    memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
    memset(&flags, 0, sizeof(flags));
 | 
			
		||||
    memset(read_buf, 0, CFSTORE_KEY_NAME_MAX_LENGTH);
 | 
			
		||||
 | 
			
		||||
    /* step 01 */
 | 
			
		||||
    kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE;
 | 
			
		||||
    CFSTORE_DBGLOG("%s:About to create new node (key_name=\"%s\", value=\"%s\")\n", __func__, node->key_name, node->value);
 | 
			
		||||
    ret = drv->Create(node->key_name, strlen(node->value), &kdesc, hkey1);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create node (key_name=\"%s\", value=\"%s\")(ret=%d)\n", __func__, node->key_name, node->value, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g);
 | 
			
		||||
    CFSTORE_DBGLOG("%s:length of KV=%d (key_name=\"%s\", value=\"%s\")\n", __func__, (int) len, node->key_name, node->value);
 | 
			
		||||
 | 
			
		||||
    /* step 02 */
 | 
			
		||||
    len = strlen(node->value);
 | 
			
		||||
    ret = drv->Write(hkey1, (char*) node->value, &len);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write key (key_name=\"%s\", value=\"%s\")(ret=%d)\n", __func__, node->key_name, node->value, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write full value data (key_name=\"%s\", value=\"%s\"), len=%d, (ret=%d)\n", __func__, node->key_name, node->value, (int) len, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(len == strlen(node->value), cfstore_close_utest_msg_g);
 | 
			
		||||
    /* revert to CFSTORE_LOG if more trace required */
 | 
			
		||||
    CFSTORE_DBGLOG("Created KV successfully (key_name=\"%s\", value=\"%s\")\n", node->key_name, node->value);
 | 
			
		||||
 | 
			
		||||
    /* step 03: Now open second handle while keeping first handle open */
 | 
			
		||||
    flags.read = true;
 | 
			
		||||
    flags.write = true;
 | 
			
		||||
    ret = drv->Open(node->key_name, flags, hkey2);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open node (key_name=\"%s\", value=\"%s\")(ret=%d)\n", __func__, node->key_name, node->value, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g);
 | 
			
		||||
    len = strlen(node->value) + 1;
 | 
			
		||||
    /* revert to CFSTORE_LOG if more trace required */
 | 
			
		||||
    CFSTORE_DBGLOG("Opened KV successfully (key_name=\"%s\", value=\"%s\")\n", node->key_name, node->value);
 | 
			
		||||
 | 
			
		||||
    /* step 04 */
 | 
			
		||||
    ret = drv->Read(hkey2, read_buf, &len);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to read key (key_name=\"%s\", value=\"%s\")\n", __func__, node->key_name, node->value);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* check read data is as expected */
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: read value data (%s) != KV value data (key_name=\"%s\", value=\"%s\")\n", __func__, read_buf, node->key_name, node->value);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(strncmp(read_buf, node->value, strlen(node->value)) == 0, cfstore_close_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* step 05 write new data using hkey2 */
 | 
			
		||||
    node = &cfstore_close_test_01_kv_data[1];
 | 
			
		||||
    len = strlen(node->value);
 | 
			
		||||
    ret = drv->Write(hkey2, (char*) node->value, &len);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write key with 2nd handle (key_name=\"%s\", value=\"%s\")(ret=%d)\n", __func__, node->key_name, node->value, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write full value data (key_name=\"%s\", value=\"%s\"), len=%d, (ret=%d)\n", __func__, node->key_name, node->value, (int) len, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(len == strlen(node->value), cfstore_close_utest_msg_g);
 | 
			
		||||
    /* revert to CFSTORE_LOG if more trace required */
 | 
			
		||||
    CFSTORE_DBGLOG("Wrote KV successfully with new data (key_name=\"%s\", value=\"%s\")\n", node->key_name, node->value);
 | 
			
		||||
 | 
			
		||||
    /* step 06 delete hkey2 */
 | 
			
		||||
    ret = drv->Delete(hkey2);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to Delete KV with 2nd handle (key_name=\"%s\", value=\"%s\")(ret=%d)\n", __func__, node->key_name, node->value, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* step 07 close hkey2 */
 | 
			
		||||
    ret = drv->Close(hkey2);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to Close KV with 2nd handle (key_name=\"%s\", value=\"%s\")(ret=%d)\n", __func__, node->key_name, node->value, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* step 08 read hkey1 for updated data */
 | 
			
		||||
    len = strlen(node->value) + 1;
 | 
			
		||||
    memset(read_buf, 0, len);
 | 
			
		||||
    ret = drv->Read(hkey1, read_buf, &len);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to read key with hkey1 (key_name=\"%s\", value=\"%s\")\n", __func__, node->key_name, node->value);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* check read data is as expected */
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: read value data (%s) != KV value data (key_name=\"%s\", value=\"%s\")\n", __func__, read_buf, node->key_name, node->value);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(strncmp(read_buf, node->value, strlen(node->value)) == 0, cfstore_close_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* step 09  */
 | 
			
		||||
    ret = drv->Open(node->key_name, flags, hkey2);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Should not be able to open pre-existing key in deleting state (key_name=\"%s\", value=\"%s\")(ret=%d)\n", __func__, node->key_name, node->value, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret == ARM_CFSTORE_DRIVER_ERROR_PREEXISTING_KEY_DELETING || ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND, cfstore_close_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* step 10 close hkey1 */
 | 
			
		||||
    ret = drv->Close(hkey1);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to Close KV with 1st handle (key_name=\"%s\", value=\"%s\")(ret=%d)\n", __func__, node->key_name, node->value, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* step 11 try to open KV and make sure unable to do so because its now been deleted */
 | 
			
		||||
    ret = drv->Open(node->key_name, flags, hkey1);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Should not be able to open key as it should not be present in the CFSTORE (key_name=\"%s\", value=\"%s\")(ret=%d)\n", __func__, node->key_name, node->value, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND, cfstore_close_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* step 12. create new KV with same key_name to make sure can re-create the key again. */
 | 
			
		||||
    node = &cfstore_close_test_01_kv_data[0];
 | 
			
		||||
    len = strlen(node->value);
 | 
			
		||||
    kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE;
 | 
			
		||||
    CFSTORE_DBGLOG("%s:About to create new node (key_name=\"%s\", value=\"%s\")\n", __func__, node->key_name, node->value);
 | 
			
		||||
    ret = drv->Create(node->key_name, strlen(node->value), &kdesc, hkey1);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create node (key_name=\"%s\", value=\"%s\")(ret=%d)\n", __func__, node->key_name, node->value, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g);
 | 
			
		||||
    CFSTORE_DBGLOG("%s:length of KV=%d (key_name=\"%s\", value=\"%s\")\n", __func__, (int) len, node->key_name, node->value);
 | 
			
		||||
 | 
			
		||||
    len = strlen(node->value);
 | 
			
		||||
    ret = drv->Write(hkey1, (char*) node->value, &len);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write key (key_name=\"%s\", value=\"%s\")(ret=%d)\n", __func__, node->key_name, node->value, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write full value data (key_name=\"%s\", value=\"%s\"), len=%d, (ret=%d)\n", __func__, node->key_name, node->value, (int) len, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(len == strlen(node->value), cfstore_close_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* revert to CFSTORE_LOG if more trace required */
 | 
			
		||||
    CFSTORE_DBGLOG("Created KV successfully (key_name=\"%s\", value=\"%s\")\n", node->key_name, node->value);
 | 
			
		||||
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(100, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
           /*          1         2         3         4         5         6        7  */
 | 
			
		||||
           /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        Case("CLOSE_test_00", cfstore_close_test_00),
 | 
			
		||||
        Case("CLOSE_test_01_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("CLOSE_test_01_end", cfstore_close_test_01_end)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,700 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Test cases to create KVs in the CFSTORE using the drv->Create() API call.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/** @file create.cpp Test cases to close KVs in the CFSTORE using the
 | 
			
		||||
 *  drv->Create() API function.
 | 
			
		||||
 *
 | 
			
		||||
 * Please consult the documentation under the test-case functions for
 | 
			
		||||
 * a description of the individual test case.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#include "cfstore_utest.h"
 | 
			
		||||
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
#ifdef CFSTORE_DEBUG
 | 
			
		||||
#define CFSTORE_CREATE_GREENTEA_TIMEOUT_S     360
 | 
			
		||||
#else
 | 
			
		||||
#define CFSTORE_CREATE_GREENTEA_TIMEOUT_S     60
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static char cfstore_create_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE];
 | 
			
		||||
 | 
			
		||||
/* Configure secure box. */
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
UVISOR_BOX_NAMESPACE("com.arm.mbed.cfstore.test.create.box1");
 | 
			
		||||
UVISOR_BOX_CONFIG(cfstore_create_box1, UVISOR_BOX_STACK_SIZE);
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
#define CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_01     { "Lefkada.Vathi.Meganisi.Atokos.Vathi.Ithaki.PeriPigathi.AgiosAndreas.Sami.Kefalonia.AgiaEffimia.AgiaSofia.Fiskardo.Frikes.Kioni.Meganissi.Lefkada", "Penelope"}
 | 
			
		||||
#define CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_02     { "Iolcus.Lemnos.Salmydessus.Cyzicus.Cios.Berbryces.Symplegadese.IsleAres.Colchis.Anenea.Sirens.Scylia.Charybdis.Phaeacia.Triton.Iolcus", "Medea"}
 | 
			
		||||
#define CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_03     { "338.Chaeronea.336.Macedonia.334.Granicus.333.Issus.332.Tyre.331.Gaugamela.330.Persepolis.Philotas.Parmenion.329.Bactria.Oxus.Samarkand.328.Cleitus.327.Roxane.326.Hydaspes.Bucephalus.324.Hephaestion.323.AlexanderDies", "TheGreat"}
 | 
			
		||||
#define CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_01      { "0123456789abcdef0123456", "abcdefghijklmnopqrstuvwxyz"}
 | 
			
		||||
#define CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_02      { "0123456789abcdef0123456", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"}
 | 
			
		||||
#define CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_03      { "0123456789abcdef0123456", "nopqrstuvwxyz"}
 | 
			
		||||
#define CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_01     { "Time.Will.Explain.It.All", "Aegeus"}
 | 
			
		||||
#define CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_02     { "Cleverness.Is.Not.Wisdom", "Bacchae"}
 | 
			
		||||
#define CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_03     { "Talk.Sense.To.A.Fool.And.He.Calls.You.Foolish", "Bacchae"}
 | 
			
		||||
#define CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_04     { "There.is.in.the.worst.of.fortune.the.best.of.chances.for.a.happy.change", "Iphigenia.in.Tauris"}
 | 
			
		||||
 | 
			
		||||
static cfstore_kv_data_t cfstore_create_test_01_data[] = {
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_01,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_02,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_03,
 | 
			
		||||
        { NULL, NULL},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* table 1: to initialise cfstore with CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_01 */
 | 
			
		||||
static cfstore_kv_data_t cfstore_create_test_01_data_step_01[] = {
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_01,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_02,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_03,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_01,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_01,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_02,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_03,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_04,
 | 
			
		||||
        { NULL, NULL},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* table 2: to CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_01 grown to CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_02 */
 | 
			
		||||
static cfstore_kv_data_t cfstore_create_test_01_data_step_02[] = {
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_01,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_02,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_03,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_02,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_01,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_02,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_03,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_04,
 | 
			
		||||
        { NULL, NULL},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* table 3: to CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_02 shrunk to CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_03 */
 | 
			
		||||
static cfstore_kv_data_t cfstore_create_test_01_data_step_03[] = {
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_01,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_02,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_03,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_03,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_01,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_02,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_03,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_04,
 | 
			
		||||
        { NULL, NULL},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* table 3: CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_03 deleted */
 | 
			
		||||
static cfstore_kv_data_t cfstore_create_test_01_data_step_04[] = {
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_01,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_02,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_03,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_01,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_02,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_03,
 | 
			
		||||
        CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_04,
 | 
			
		||||
        { NULL, NULL},
 | 
			
		||||
};
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
/* support functions */
 | 
			
		||||
 | 
			
		||||
/* @brief   support function for generating value blob data */
 | 
			
		||||
static int32_t cfstore_create_kv_value_gen(char* value, const size_t len)
 | 
			
		||||
{
 | 
			
		||||
    size_t i = 0;
 | 
			
		||||
    size_t cpy_size = 0;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: value pointer is null.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(value != NULL, cfstore_create_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    while(i < len)
 | 
			
		||||
    {
 | 
			
		||||
        cpy_size = len - i > CFSTORE_TEST_BYTE_DATA_TABLE_SIZE ? CFSTORE_TEST_BYTE_DATA_TABLE_SIZE : len - i;
 | 
			
		||||
        memcpy(value + i, cfstore_test_byte_data_table, cpy_size);
 | 
			
		||||
        i += cpy_size;
 | 
			
		||||
    }
 | 
			
		||||
    return ARM_DRIVER_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static char* CFSTORE_CREATE_KV_CREATE_NO_TAG = NULL;
 | 
			
		||||
 | 
			
		||||
/** @brief
 | 
			
		||||
 *
 | 
			
		||||
 * support function to create a KV
 | 
			
		||||
 * - a kv name is generated with the length name_len
 | 
			
		||||
 * - a kv value blob is generated with the length value_len
 | 
			
		||||
 *
 | 
			
		||||
 * @param   name_len    the length of the kv_name
 | 
			
		||||
 * @param   name_tag    tag to append to name, intended to enable large number of unique strings
 | 
			
		||||
 * @param   value_buf   buffer to use for storing the generated value data
 | 
			
		||||
 * @param   value_len   the length of the value to generate
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static int32_t cfstore_create_kv_create(size_t name_len, char* name_tag, char* value_buf, size_t value_len)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_OK;
 | 
			
		||||
    size_t name_len_ex = name_len;
 | 
			
		||||
    char kv_name[CFSTORE_KEY_NAME_MAX_LENGTH+1];    /* extra char for terminating null */
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    memset(kv_name, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1);
 | 
			
		||||
    memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
    kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE;
 | 
			
		||||
 | 
			
		||||
    name_len_ex = name_len;
 | 
			
		||||
    if(name_tag){
 | 
			
		||||
        name_len_ex += strlen(name_tag);
 | 
			
		||||
    }
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: max supported KV name length for testing exceeded.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(name_len_ex < CFSTORE_KEY_NAME_MAX_LENGTH+1, cfstore_create_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    ret = cfstore_test_kv_name_gen(kv_name, name_len);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to generate kv_name.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK , cfstore_create_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* append name tag */
 | 
			
		||||
    if(name_tag){
 | 
			
		||||
        strncat(kv_name, name_tag, CFSTORE_KEY_NAME_MAX_LENGTH);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: kv_name is not the correct length (name_len_ex=%d, expected=%d).\n", __func__, (int) strlen(kv_name), (int) name_len_ex);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(strlen(kv_name) == name_len_ex, cfstore_create_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    ret = cfstore_create_kv_value_gen(value_buf, value_len);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to generate kv_name.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK , cfstore_create_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    ret = cfstore_test_create(kv_name, value_buf, &value_len, &kdesc);
 | 
			
		||||
 | 
			
		||||
    if(ret == ARM_CFSTORE_DRIVER_ERROR_OUT_OF_MEMORY){
 | 
			
		||||
        CFSTORE_ERRLOG("%s: Error: out of memory\n", __func__);
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create KV in store for kv_name_good(ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   cfstore_create_test_01() support function change the size of a value blob in the cfstore */
 | 
			
		||||
static int32_t cfstore_create_test_KV_change(const cfstore_kv_data_t* old_node, const cfstore_kv_data_t* new_node )
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    size_t len = 0;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s:entered\n", __func__);
 | 
			
		||||
    memset(&flags, 0, sizeof(flags));
 | 
			
		||||
    memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
 | 
			
		||||
    /* check node key_names are identical */
 | 
			
		||||
    if(strncmp(old_node->key_name, new_node->key_name, strlen(old_node->key_name)) != 0){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:old and new entries so not have the same key_name (old_key_name=%s, new_key_name=%s).\n", __func__, old_node->key_name, new_node->key_name);
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    len = strlen(new_node->value);
 | 
			
		||||
    /* supply NULL key descriptor to open a pre-existing key for increasing the blob size */
 | 
			
		||||
    ret = drv->Create(new_node->key_name, len, NULL, hkey);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: failed to change size of KV (key_name=%s)(ret=%d).\n", __func__, new_node->key_name, (int) ret);
 | 
			
		||||
        goto out1;
 | 
			
		||||
    }
 | 
			
		||||
    len = strlen(new_node->value);
 | 
			
		||||
    ret = drv->Write(hkey, new_node->value, &len);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: failed to write KV (key_name=%s)(ret=%d).\n", __func__, new_node->key_name, (int) ret);
 | 
			
		||||
        goto out2;
 | 
			
		||||
    }
 | 
			
		||||
    if(len != strlen(new_node->value)){
 | 
			
		||||
        CFSTORE_DBGLOG("%s:Failed wrote (%d) rather than the correct number of bytes (%d).\n", __func__, (int) len, (int) strlen(cfstore_create_test_01_data[1].value));
 | 
			
		||||
        goto out2;
 | 
			
		||||
    }
 | 
			
		||||
out2:
 | 
			
		||||
    drv->Close(hkey);
 | 
			
		||||
out1:
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* report whether built/configured for flash sync or async mode */
 | 
			
		||||
static control_t cfstore_create_test_00(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    ret = cfstore_test_startup();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to perform test startup (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @brief
 | 
			
		||||
 *
 | 
			
		||||
 * Test case to change the value blob size of pre-existing key.
 | 
			
		||||
 * The test does the following:
 | 
			
		||||
 * - creates a cfstore with ~10 entries.
 | 
			
		||||
 * - for a mid-cfstore entry, grow the value blob size
 | 
			
		||||
 * - check all the cfstore entries can be read correctly and their
 | 
			
		||||
 *   data agrees with the data supplied upon creation.
 | 
			
		||||
 * - grow the mid-entry value blob size to be ~double the initial size.
 | 
			
		||||
 * - check all the cfstore entries can be read correctly and their
 | 
			
		||||
 *   data agrees with the data supplied upon creation.
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_create_test_01_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
    cfstore_kv_data_t* node = NULL;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    memset(&flags, 0, sizeof(flags));
 | 
			
		||||
 | 
			
		||||
    ret = cfstore_test_create_table(cfstore_create_test_01_data_step_01);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Failed to add cfstore_create_test_01_data_head (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* find cfstore_create_test_01_data[0] and grow the KV MID_ENTRY_01 to MID_ENTRY_02 */
 | 
			
		||||
    ret = cfstore_create_test_KV_change(&cfstore_create_test_01_data[0], &cfstore_create_test_01_data[1]);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Failed to increase size of KV (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* Now check that the KVs are all present and correct */
 | 
			
		||||
    node = cfstore_create_test_01_data_step_02;
 | 
			
		||||
    while(node->key_name != NULL)
 | 
			
		||||
    {
 | 
			
		||||
        ret = cfstore_test_check_node_correct(node);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:node (key_name=\"%s\", value=\"%s\") not correct in cfstore\n", __func__, node->key_name, node->value);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
 | 
			
		||||
        node++;
 | 
			
		||||
    }
 | 
			
		||||
    /* revert CFSTORE_LOG for more trace */
 | 
			
		||||
    CFSTORE_DBGLOG("KV successfully increased in size and other KVs remained unchanged.%s", "\n");
 | 
			
		||||
    /* Shrink the KV from KV MID_ENTRY_02 to MID_ENTRY_03 */
 | 
			
		||||
    ret = cfstore_create_test_KV_change(&cfstore_create_test_01_data[1], &cfstore_create_test_01_data[2]);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Failed to decrease size of KV (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* Now check that the KVs are all present and correct */
 | 
			
		||||
    node = cfstore_create_test_01_data_step_03;
 | 
			
		||||
    while(node->key_name != NULL)
 | 
			
		||||
    {
 | 
			
		||||
        ret = cfstore_test_check_node_correct(node);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:node (key_name=\"%s\", value=\"%s\") not correct in cfstore\n", __func__, node->key_name, node->value);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
 | 
			
		||||
        node++;
 | 
			
		||||
    }
 | 
			
		||||
    /* revert CFSTORE_LOG for more trace */
 | 
			
		||||
    CFSTORE_DBGLOG("KV successfully decreased in size and other KVs remained unchanged.%s", "\n");
 | 
			
		||||
 | 
			
		||||
    /* Delete the KV */
 | 
			
		||||
    ret = cfstore_test_delete(cfstore_create_test_01_data[2].key_name);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:failed to delete node(key_name=\"%s\")\n", __func__, node->key_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* Now check that the KVs are all present and correct */
 | 
			
		||||
    node = cfstore_create_test_01_data_step_04;
 | 
			
		||||
    while(node->key_name != NULL)
 | 
			
		||||
    {
 | 
			
		||||
        ret = cfstore_test_check_node_correct(node);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:node (key_name=\"%s\", value=\"%s\") not correct in cfstore\n", __func__, node->key_name, node->value);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
 | 
			
		||||
        node++;
 | 
			
		||||
    }
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int32_t cfstore_create_test_02_core(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    uint32_t i = 0;
 | 
			
		||||
    uint32_t bytes_stored = 0;
 | 
			
		||||
    const uint32_t max_num_kvs_create = 10;
 | 
			
		||||
    const size_t kv_name_min_len = CFSTORE_KEY_NAME_MAX_LENGTH - max_num_kvs_create;
 | 
			
		||||
    const size_t kv_value_min_len = CFSTORE_TEST_BYTE_DATA_TABLE_SIZE;
 | 
			
		||||
    const size_t max_value_buf_size = kv_value_min_len * (max_num_kvs_create +1);
 | 
			
		||||
    char value_buf[max_value_buf_size];
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    memset(value_buf, 0, max_value_buf_size);
 | 
			
		||||
 | 
			
		||||
    for(i = 0; i < max_num_kvs_create; i++)
 | 
			
		||||
    {
 | 
			
		||||
        memset(value_buf, 0, max_value_buf_size);
 | 
			
		||||
        ret = cfstore_create_kv_create(kv_name_min_len +i, CFSTORE_CREATE_KV_CREATE_NO_TAG, value_buf, kv_value_min_len * (i+1));
 | 
			
		||||
        bytes_stored += kv_name_min_len + i;         /* kv_name */
 | 
			
		||||
        bytes_stored += kv_value_min_len * (i+1);    /* kv value blob */
 | 
			
		||||
        bytes_stored += 8;                           /* kv overhead */
 | 
			
		||||
        if(ret == ARM_CFSTORE_DRIVER_ERROR_OUT_OF_MEMORY){
 | 
			
		||||
            CFSTORE_ERRLOG("Out of memory on %d-th KV, trying to allocate memory totalling %d.\n", (int) i, (int) bytes_stored);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        CFSTORE_DBGLOG("Successfully stored %d-th KV bytes,  totalling %d.\n", (int) i, (int) bytes_stored);
 | 
			
		||||
    }
 | 
			
		||||
    ret = cfstore_test_delete_all();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to delete_all() attributes to clean up after test (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**@brief
 | 
			
		||||
 *
 | 
			
		||||
 * Test case to create ~10 kvs. The amount of data store in the cfstore is as follows:
 | 
			
		||||
 * - 10 kvs
 | 
			
		||||
 * - kv name lengths are ~220 => ~ 2200 bytes
 | 
			
		||||
 * - value blob length is 1x256, 2x256, 3x256, ... 10x256)) = 256(1+2+3+4+..10) = 256*10*11/2 = 14080
 | 
			
		||||
 * - kv overhead = 8bytes/kv = 8 * 10 = 80bytes
 | 
			
		||||
 * - total = (220*10)+256*10*11/2 10*8 = 143800 bytes
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_create_test_02_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
 | 
			
		||||
    ret = cfstore_create_test_02_core(call_count);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: something went wrong (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(drv->Uninitialize() >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**@brief
 | 
			
		||||
 *
 | 
			
		||||
 * Test to create the ~100 kvs to make the device run out of memory.
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_create_test_03_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t i = 0;
 | 
			
		||||
    int32_t ret;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    for(i = 0; i < 100; i++)
 | 
			
		||||
    {
 | 
			
		||||
        ret = cfstore_create_test_02_core(call_count);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: something went wrong (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
 | 
			
		||||
        /* revert CFSTORE_LOG for more trace */
 | 
			
		||||
        CFSTORE_DBGLOG("Successfully completed create/destroy loop %d.\n", (int) i);
 | 
			
		||||
    }
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(drv->Uninitialize() >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**@brief
 | 
			
		||||
 *
 | 
			
		||||
 * Test to create the 100 kvs to make the device run out of memory.
 | 
			
		||||
 * The amount of data store in the cfstore is as follows:
 | 
			
		||||
 * - total = (220*100)+256*100*101/2 100*8 = 1315600 = 1.315x10^6
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_create_test_04_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    uint32_t i = 0;
 | 
			
		||||
    uint32_t bytes_stored = 0;
 | 
			
		||||
    const uint32_t max_num_kvs_create = 100;
 | 
			
		||||
    const size_t kv_name_min_len = CFSTORE_KEY_NAME_MAX_LENGTH - max_num_kvs_create;
 | 
			
		||||
    const size_t kv_value_min_len = CFSTORE_TEST_BYTE_DATA_TABLE_SIZE;
 | 
			
		||||
    const size_t max_value_buf_size = kv_value_min_len/8 * (max_num_kvs_create +1);
 | 
			
		||||
    char* value_buf = NULL;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_LOG("%s: cfstore_test_dump: dump here contents of CFSTORE so we know whats present\n", __func__);
 | 
			
		||||
    ret = cfstore_test_dump();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  D.1.1 cfstore_test_dump failed (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    value_buf = (char*) malloc(max_value_buf_size);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: out of memory.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(value_buf != NULL, cfstore_create_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    for(i = 0; i < max_num_kvs_create; i++)
 | 
			
		||||
    {
 | 
			
		||||
        memset(value_buf, 0, max_value_buf_size);
 | 
			
		||||
        ret = cfstore_create_kv_create(kv_name_min_len +i, CFSTORE_CREATE_KV_CREATE_NO_TAG, value_buf, kv_value_min_len/8 * (i+1));
 | 
			
		||||
        bytes_stored += kv_name_min_len + i;         /* kv_name */
 | 
			
		||||
        bytes_stored += kv_value_min_len/8 * (i+1);  /* kv value blob */
 | 
			
		||||
        bytes_stored += 8;                           /* kv overhead */
 | 
			
		||||
        if(ret == ARM_CFSTORE_DRIVER_ERROR_OUT_OF_MEMORY){
 | 
			
		||||
            CFSTORE_ERRLOG("Out of memory on %d-th KV, trying to allocate memory totalling %d.\n", (int) i, (int) bytes_stored);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        /* revert CFSTORE_LOG for more trace */
 | 
			
		||||
        CFSTORE_DBGLOG("Successfully stored %d-th KV bytes,  totalling %d.\n", (int) i, (int) bytes_stored);
 | 
			
		||||
    }
 | 
			
		||||
    ret = cfstore_test_delete_all();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to delete_all() attributes to clean up after test (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
 | 
			
		||||
    free(value_buf);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(drv->Uninitialize() >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**@brief
 | 
			
		||||
 *
 | 
			
		||||
 * Test to create ~500 kvs. The amount of data store in the cfstore is as follows:
 | 
			
		||||
 * - total = (220*500)+(256/64)*500*501/2 500*8 = 8236000 = 8.236M
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_create_test_05_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    uint32_t i = 0;
 | 
			
		||||
    uint32_t bytes_stored = 0;
 | 
			
		||||
    const uint32_t max_num_kvs_create = 200;
 | 
			
		||||
    const size_t kv_name_tag_len = 3;
 | 
			
		||||
    const size_t kv_name_min_len = 10;
 | 
			
		||||
    const size_t kv_value_min_len = CFSTORE_TEST_BYTE_DATA_TABLE_SIZE;
 | 
			
		||||
    const size_t max_value_buf_size = kv_value_min_len/64 * (max_num_kvs_create+1);
 | 
			
		||||
    char kv_name_tag_buf[kv_name_tag_len+1];
 | 
			
		||||
    char* value_buf = NULL;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    value_buf = (char*) malloc(max_value_buf_size);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: out of memory.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(value_buf != NULL, cfstore_create_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    for(i = 0; i < max_num_kvs_create; i++)
 | 
			
		||||
    {
 | 
			
		||||
        memset(value_buf, 0, max_value_buf_size);
 | 
			
		||||
        snprintf(kv_name_tag_buf, kv_name_tag_len+1, "%0d", (int) i);
 | 
			
		||||
        ret = cfstore_create_kv_create(kv_name_min_len, kv_name_tag_buf, value_buf, kv_value_min_len/64 * (i+1));
 | 
			
		||||
        bytes_stored += kv_name_min_len + i + strlen(kv_name_tag_buf);         /* kv_name */
 | 
			
		||||
        bytes_stored += kv_value_min_len/64 * (i+1);                           /* kv value blob */
 | 
			
		||||
        bytes_stored += 8;                                                     /* kv overhead */
 | 
			
		||||
        if(ret == ARM_CFSTORE_DRIVER_ERROR_OUT_OF_MEMORY){
 | 
			
		||||
            CFSTORE_ERRLOG("Out of memory on %d-th KV, trying to allocate memory totalling %d.\n", (int) i, (int) bytes_stored);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        /* revert CFSTORE_LOG for more trace */
 | 
			
		||||
        CFSTORE_DBGLOG("Successfully stored %d-th KV bytes,  totalling %d.\n", (int) i, (int) bytes_stored);
 | 
			
		||||
    }
 | 
			
		||||
    ret = cfstore_test_delete_all();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to delete_all() attributes to clean up after test.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
 | 
			
		||||
    free(value_buf);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(drv->Uninitialize() >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
/* structure to encode test data */
 | 
			
		||||
typedef struct cfstore_create_key_name_validate_t {
 | 
			
		||||
    const char* key_name;
 | 
			
		||||
    uint32_t f_allowed : 1;
 | 
			
		||||
} cfstore_create_key_name_validate_t;
 | 
			
		||||
 | 
			
		||||
/* data table encoding test data */
 | 
			
		||||
cfstore_create_key_name_validate_t cfstore_create_test_06_data[] = {
 | 
			
		||||
        /* ruler for measuring text strings */
 | 
			
		||||
        /*                                                                                                    1         1         1         1         1         1         1         1         1         1         2         2         2 */
 | 
			
		||||
        /* 0        1         2         3         4         5         6         7         8         9         0         1         2         3         4         5         6         7         8         9         0         1         2 */
 | 
			
		||||
        /* 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        { "",  false},
 | 
			
		||||
        { "abc.{1}.efg", true },
 | 
			
		||||
        { "abc.{1.efg", false },
 | 
			
		||||
        { "abc.1}.efg", false },
 | 
			
		||||
        { "abc.{{1}}.efg", false },
 | 
			
		||||
        { "abc.{}.efg", true },
 | 
			
		||||
        { "abc.}1{.efg", false },
 | 
			
		||||
        { ".piety.demands.us.to.honour.truth.above.our.friends", false },
 | 
			
		||||
        { "basement.medicine.pavement.government.trenchcoat.off.cough.off.kid.did.when.again.alleyway.friend.cap.pen.dollarbills.ten.foot.soot.put.but.anyway.say.May.DA.kid.did.toes.bows.those.hose.nose.clothes.man.blows.{100000000}", false },
 | 
			
		||||
        { NULL, false},
 | 
			
		||||
};
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**@brief
 | 
			
		||||
 *
 | 
			
		||||
 * Test whether a key name can be created or not.
 | 
			
		||||
 *
 | 
			
		||||
 * @param	key_name
 | 
			
		||||
 * 			name of the key to create in the store
 | 
			
		||||
 * @param	should_create
 | 
			
		||||
 * 			if true, then create KV should succeed, otherwise should fail.
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
bool cfstore_create_key_name_validate(const char *key_name, bool should_create)
 | 
			
		||||
{
 | 
			
		||||
    bool bret = false;
 | 
			
		||||
    char* test_data = (char*) "test_data";
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_SIZE len = 0;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\r\n", __func__);
 | 
			
		||||
    memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
 | 
			
		||||
    /* create */
 | 
			
		||||
    kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE;
 | 
			
		||||
    len = strlen(test_data);
 | 
			
		||||
    ret = cfstore_test_create((const char*) key_name, test_data, &len, &kdesc);
 | 
			
		||||
    /* dont not use any functions that require finding the created item as they may not work,
 | 
			
		||||
     * depending on the construction of the test key_name & match strings */
 | 
			
		||||
    if(should_create == true)
 | 
			
		||||
    {
 | 
			
		||||
        if(ret < ARM_DRIVER_OK){
 | 
			
		||||
            CFSTORE_ERRLOG("%s:Error: failed to create kv (key_name=%s.\r\n", __func__, key_name);
 | 
			
		||||
            return bret;
 | 
			
		||||
        }
 | 
			
		||||
        CFSTORE_DBGLOG("%s:Success: Create() behaved as expected.\r\n", __func__);
 | 
			
		||||
        /* delete using the actual name */
 | 
			
		||||
        ret = cfstore_test_delete((const char*) key_name);
 | 
			
		||||
        if(ret < ARM_DRIVER_OK){
 | 
			
		||||
            CFSTORE_ERRLOG("%s:Error: failed to delete kv (key_name=%s)(ret=%d).\r\n", __func__, key_name, (int)ret);
 | 
			
		||||
        }
 | 
			
		||||
        bret = true;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        if(ret >= ARM_DRIVER_OK){
 | 
			
		||||
            CFSTORE_ERRLOG("%s:Error: created kv (key_name=%s) when Create() should have failed.\r\n", __func__, key_name);
 | 
			
		||||
            return bret;
 | 
			
		||||
        }
 | 
			
		||||
        /* the operation failed which was the expected result hence return true*/
 | 
			
		||||
        bret = true;
 | 
			
		||||
    }
 | 
			
		||||
    return bret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @brief
 | 
			
		||||
 *
 | 
			
		||||
 * Test that key names with non-matching braces etc do no get created.
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_create_test_06_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    bool ret = false;
 | 
			
		||||
    int32_t ret32 = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    cfstore_create_key_name_validate_t* node = cfstore_create_test_06_data;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
 | 
			
		||||
    while(node->key_name != NULL)
 | 
			
		||||
    {
 | 
			
		||||
        ret = cfstore_create_key_name_validate(node->key_name, node->f_allowed);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: test failed (ret=%d, key_name=%s, f_allowed=%d)\n", __func__, (int) ret, node->key_name, (int) node->f_allowed);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret == true, cfstore_create_utest_msg_g);
 | 
			
		||||
        node++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret32 = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret32 >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(CFSTORE_CREATE_GREENTEA_TIMEOUT_S, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
           /*          1         2         3         4         5         6        7  */
 | 
			
		||||
           /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        Case("CREATE_test_00", cfstore_create_test_00),
 | 
			
		||||
        Case("CREATE_test_01_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("CREATE_test_01_end", cfstore_create_test_01_end),
 | 
			
		||||
        Case("CREATE_test_02_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("CREATE_test_02_end", cfstore_create_test_02_end),
 | 
			
		||||
        Case("CREATE_test_03_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("CREATE_test_03_end", cfstore_create_test_03_end),
 | 
			
		||||
        Case("CREATE_test_04_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("CREATE_test_04_end", cfstore_create_test_04_end),
 | 
			
		||||
        Case("CREATE_test_05_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("CREATE_test_05_end", cfstore_create_test_05_end),
 | 
			
		||||
        Case("CREATE_test_06_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("CREATE_test_06_end", cfstore_create_test_06_end),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,86 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Simple tool (implemented as a test case) to dump cfstore contents.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/** @file dump.cpp test binary for dumping CFSTORE configuration.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#include "cfstore_utest.h"
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
control_t cfstore_dump_test_01_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    ret = cfstore_test_dump();
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_LOG("Error: failed to dump CFSTORE contents%s", "\n");
 | 
			
		||||
    }
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_LOG("Error: failed to Uninitialize() CFSTORE%s", "\n");
 | 
			
		||||
    }
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(400, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
           /*          1         2         3         4         5         6        7  */
 | 
			
		||||
           /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        Case("DUMP_test_01_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("DUMP_test_01_end", cfstore_dump_test_01_end),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,935 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 example1.cpp Test case to demonstrates each API function works correctly.
 | 
			
		||||
 *
 | 
			
		||||
 * \par Example 1 Notes
 | 
			
		||||
 *
 | 
			
		||||
 * The example test does the following CFSTORE operations:
 | 
			
		||||
 * - initialises
 | 
			
		||||
 * - creates a key-value pair (KV).
 | 
			
		||||
 * - writes the data for the KV
 | 
			
		||||
 * - closes KV.
 | 
			
		||||
 * - flushes the KV to flash
 | 
			
		||||
 * - opens KV for reading.
 | 
			
		||||
 * - reads KV and checks the value blob was the same as previously written.
 | 
			
		||||
 * - closes KV.
 | 
			
		||||
 * - finds a KV (there is only 1 to find).
 | 
			
		||||
 * - for the KV returned, get the key name.
 | 
			
		||||
 * - for the KV returned, get the value length.
 | 
			
		||||
 * - for the KV returned, delete the KV.
 | 
			
		||||
 * - find another KV (which fails as there are no more keys to find).
 | 
			
		||||
 * - flushes the updated state to flash to store the removal of the deleted KV.
 | 
			
		||||
 * - uninitialises
 | 
			
		||||
 * - stops
 | 
			
		||||
 *
 | 
			
		||||
 * This test is coded so as to work in the following modes:
 | 
			
		||||
 * - flash sync mode i.e. with caps.asynchronous_ops == false
 | 
			
		||||
 * - flash async mode i.e. with caps.asynchronous_ops == true
 | 
			
		||||
 *
 | 
			
		||||
 * The dual async/sync mode support with the same code is more complicated
 | 
			
		||||
 * than if the implementation just supported sync mode for example. However,
 | 
			
		||||
 * it has the benefit of being more versatile.
 | 
			
		||||
 *
 | 
			
		||||
 * The test leaves the flash in the same state as at the beginning of the test so
 | 
			
		||||
 * it can be run a second time on the device without flashing, and the test should
 | 
			
		||||
 * still work.
 | 
			
		||||
 *
 | 
			
		||||
 * \par How to Build Example1 as a Stand-alone Application
 | 
			
		||||
 *
 | 
			
		||||
 * This example can be build as a stand-alone application as follows:
 | 
			
		||||
 * - Create a new mbed application using the `mbed new .` command.
 | 
			
		||||
 * - Copy this file example1.cpp from the to the top level application directory and rename the file to main.cpp.
 | 
			
		||||
 * - Build the application with `mbed compile -v -m <target> -t <toolchain> -DCFSTORE_EXAMPLE1_APP` e.g. `mbed compile -v -m K64F -t GCC_ARM -DCFSTORE_EXAMPLE1_APP`.
 | 
			
		||||
 */
 | 
			
		||||
#if defined __MBED__ && ! defined TOOLCHAIN_GCC_ARM
 | 
			
		||||
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#include "cfstore_uvisor.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
static control_t cfstore_example1_test_00(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    printf("Not implemented for ARM toolchain\n");
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(100, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
           /*          1         2         3         4         5         6        7  */
 | 
			
		||||
           /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        Case("EXAMPLE1_test_00", cfstore_example1_test_00),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
 | 
			
		||||
#ifndef CFSTORE_EXAMPLE1_APP
 | 
			
		||||
/* when built as Configuration-Store example, include greentea support otherwise omit */
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
 | 
			
		||||
#else   // CFSTORE_EXAMPLE1_APP
 | 
			
		||||
// map utest types for building as stand alone example
 | 
			
		||||
#define control_t   void
 | 
			
		||||
#define CaseNext
 | 
			
		||||
#endif  // CFSTORE_EXAMPLE1_APP
 | 
			
		||||
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
 | 
			
		||||
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
#include "flash_journal_strategy_sequential.h"
 | 
			
		||||
#include "flash_journal.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
 | 
			
		||||
 | 
			
		||||
#ifdef YOTTA_CFG_CONFIG_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CONFIG_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
#ifndef CFSTORE_EXAMPLE1_APP
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_EX1_TEST_ASSERT(Expr)                       if (!(Expr)) { printf("%s:%u: assertion failure\r\n", __FUNCTION__, __LINE__); while (1) ;}
 | 
			
		||||
#define CFSTORE_EX1_TEST_ASSERT_EQUAL(expected, actual)     if ((expected) != (actual)) {printf("%s:%u: assertion failure\r\n", __FUNCTION__, __LINE__); while (1) ;}
 | 
			
		||||
#define CFSTORE_EX1_TEST_ASSERT_NOT_EQUAL(expected, actual) if ((expected) == (actual)) {printf("%s:%u: assertion failure\r\n", __FUNCTION__, __LINE__); while (1) ;}
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_EX1_TEST_ASSERT_MSG(Expr, _fmt, ...)      \
 | 
			
		||||
    do                                                    \
 | 
			
		||||
    {                                                     \
 | 
			
		||||
        if (!(Expr))                                      \
 | 
			
		||||
        {                                                 \
 | 
			
		||||
            printf(_fmt, __VA_ARGS__);                    \
 | 
			
		||||
            while (1) ;                                   \
 | 
			
		||||
        }                                                 \
 | 
			
		||||
    }while(0);
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_EX1_LOG(_fmt, ...)                        \
 | 
			
		||||
  do                                                      \
 | 
			
		||||
  {                                                       \
 | 
			
		||||
        printf(_fmt, __VA_ARGS__);                        \
 | 
			
		||||
  }while(0);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const char* cfstore_ex_opcode_str[] =
 | 
			
		||||
{
 | 
			
		||||
    "UNDEFINED",
 | 
			
		||||
    "CFSTORE_OPCODE_CLOSE",
 | 
			
		||||
    "CFSTORE_OPCODE_CREATE",
 | 
			
		||||
    "CFSTORE_OPCODE_DELETE",
 | 
			
		||||
    "CFSTORE_OPCODE_FIND",
 | 
			
		||||
    "CFSTORE_OPCODE_FLUSH",
 | 
			
		||||
    "CFSTORE_OPCODE_GET_KEY_NAME",
 | 
			
		||||
    "CFSTORE_OPCODE_GET_STATUS",
 | 
			
		||||
    "CFSTORE_OPCODE_GET_VALUE_LEN",
 | 
			
		||||
    "CFSTORE_OPCODE_INITIALIZE",
 | 
			
		||||
    "CFSTORE_OPCODE_OPEN",
 | 
			
		||||
    "CFSTORE_OPCODE_POWER_CONTROL",
 | 
			
		||||
    "CFSTORE_OPCODE_READ",
 | 
			
		||||
    "CFSTORE_OPCODE_RSEEK",
 | 
			
		||||
    "CFSTORE_OPCODE_UNINITIALIZE",
 | 
			
		||||
    "CFSTORE_OPCODE_WRITE",
 | 
			
		||||
    "CFSTORE_OPCODE_MAX"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
bool cfstore_example1_done = false;
 | 
			
		||||
const char* cfstore_ex_kv_name = "basement.medicine.pavement.government.trenchcoat.off.cough.off.kid.did.when.again.alleyway.friend.cap.pen.dollarbills.ten.foot.soot.put.but.anyway.say.May.DA.kid.did.toes.bows.those.hose.nose.clothes.man.blows.well.well";
 | 
			
		||||
const char* cfstore_ex_kv_value = "TheRollingStone";
 | 
			
		||||
#define CFSTORE_EX1_RSEEK_OFFSET    10   /* offset to S of Stone */
 | 
			
		||||
 | 
			
		||||
typedef enum cfstore_ex_state_t {
 | 
			
		||||
    CFSTORE_EX_STATE_INITIALIZING = 1,
 | 
			
		||||
    CFSTORE_EX_STATE_INIT_DONE,
 | 
			
		||||
    CFSTORE_EX_STATE_CREATING,
 | 
			
		||||
    CFSTORE_EX_STATE_CREATE_DONE,
 | 
			
		||||
    CFSTORE_EX_STATE_WRITING,
 | 
			
		||||
    CFSTORE_EX_STATE_WRITE_DONE,
 | 
			
		||||
    CFSTORE_EX_STATE_CLOSING1,
 | 
			
		||||
    CFSTORE_EX_STATE_CLOSE_DONE1,
 | 
			
		||||
    CFSTORE_EX_STATE_FLUSHING1,
 | 
			
		||||
    CFSTORE_EX_STATE_FLUSH_DONE1,
 | 
			
		||||
    CFSTORE_EX_STATE_OPENING,
 | 
			
		||||
    CFSTORE_EX_STATE_OPEN_DONE,
 | 
			
		||||
    CFSTORE_EX_STATE_READING1,
 | 
			
		||||
    CFSTORE_EX_STATE_READ_DONE1,
 | 
			
		||||
    CFSTORE_EX_STATE_RSEEKING,
 | 
			
		||||
    CFSTORE_EX_STATE_RSEEK_DONE,
 | 
			
		||||
    CFSTORE_EX_STATE_READING2,
 | 
			
		||||
    CFSTORE_EX_STATE_READ_DONE2,
 | 
			
		||||
    CFSTORE_EX_STATE_CLOSING2,
 | 
			
		||||
    CFSTORE_EX_STATE_CLOSE_DONE2,
 | 
			
		||||
    CFSTORE_EX_STATE_FINDING1,
 | 
			
		||||
    CFSTORE_EX_STATE_FIND_DONE1,
 | 
			
		||||
    CFSTORE_EX_STATE_GETTING_KEY_NAME,
 | 
			
		||||
    CFSTORE_EX_STATE_GET_KEY_NAME_DONE,
 | 
			
		||||
    CFSTORE_EX_STATE_GETTING_VALUE_LEN,
 | 
			
		||||
    CFSTORE_EX_STATE_GET_VALUE_LEN_DONE,
 | 
			
		||||
    CFSTORE_EX_STATE_DELETING,
 | 
			
		||||
    CFSTORE_EX_STATE_DELETE_DONE,
 | 
			
		||||
    CFSTORE_EX_STATE_FINDING2,
 | 
			
		||||
    CFSTORE_EX_STATE_FIND_DONE2,
 | 
			
		||||
    CFSTORE_EX_STATE_FLUSHING2,
 | 
			
		||||
    CFSTORE_EX_STATE_FLUSH_DONE2,
 | 
			
		||||
    CFSTORE_EX_STATE_UNINITIALIZING,
 | 
			
		||||
    CFSTORE_EX_STATE_UNINIT_DONE
 | 
			
		||||
} cfstore_ex_state_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef struct cfstore_example1_ctx_t
 | 
			
		||||
{
 | 
			
		||||
    ARM_CFSTORE_CAPABILITIES caps;
 | 
			
		||||
    uint8_t hkey[CFSTORE_HANDLE_BUFSIZE];
 | 
			
		||||
    uint8_t hkey_next_buf[CFSTORE_HANDLE_BUFSIZE];
 | 
			
		||||
    uint8_t hkey_prev_buf[CFSTORE_HANDLE_BUFSIZE];
 | 
			
		||||
    ARM_CFSTORE_HANDLE hkey_next;
 | 
			
		||||
    ARM_CFSTORE_HANDLE hkey_prev;
 | 
			
		||||
    cfstore_ex_state_t state;
 | 
			
		||||
    ARM_CFSTORE_SIZE len;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
    char value[CFSTORE_KEY_NAME_MAX_LENGTH+1];
 | 
			
		||||
    /* callback attributes*/
 | 
			
		||||
    int32_t callback_status;
 | 
			
		||||
    ARM_CFSTORE_HANDLE callback_handle;
 | 
			
		||||
} cfstore_example1_ctx_t;
 | 
			
		||||
 | 
			
		||||
static cfstore_example1_ctx_t cfstore_example1_ctx_g;
 | 
			
		||||
 | 
			
		||||
extern ARM_CFSTORE_DRIVER cfstore_driver;
 | 
			
		||||
ARM_CFSTORE_DRIVER *cfstore_drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
/* forward declarations */
 | 
			
		||||
static void cfstore_ex_fms_update(cfstore_example1_ctx_t* ctx);
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   test startup code to reset flash
 | 
			
		||||
 */
 | 
			
		||||
static int32_t cfstore_test_startup(void)
 | 
			
		||||
{
 | 
			
		||||
    ARM_CFSTORE_CAPABILITIES caps = cfstore_driver.GetCapabilities();
 | 
			
		||||
    CFSTORE_EX1_LOG("INITIALIZING: caps.asynchronous_ops=%d\n", (int) caps.asynchronous_ops);
 | 
			
		||||
 | 
			
		||||
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    FlashJournal_t jrnl;
 | 
			
		||||
    extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0);
 | 
			
		||||
    const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_(0);
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void cfstore_ex_callback(int32_t status, ARM_CFSTORE_OPCODE cmd_code, void *client_context, ARM_CFSTORE_HANDLE handle)
 | 
			
		||||
{
 | 
			
		||||
    (void) handle;
 | 
			
		||||
 | 
			
		||||
    cfstore_example1_ctx_t* ctx = (cfstore_example1_ctx_t*) client_context;
 | 
			
		||||
 | 
			
		||||
    /* CFSTORE_EX1_LOG("%s:entered: status=%d, cmd_code=%d (%s) handle=%p\r\n", __func__, (int) status, (int) cmd_code, cfstore_ex_opcode_str[cmd_code], handle); */
 | 
			
		||||
    switch(cmd_code)
 | 
			
		||||
    {
 | 
			
		||||
    case CFSTORE_OPCODE_INITIALIZE:
 | 
			
		||||
        ctx->state = CFSTORE_EX_STATE_INIT_DONE;
 | 
			
		||||
        break;
 | 
			
		||||
    case CFSTORE_OPCODE_CREATE:
 | 
			
		||||
        ctx->state = CFSTORE_EX_STATE_CREATE_DONE;
 | 
			
		||||
        break;
 | 
			
		||||
    case CFSTORE_OPCODE_WRITE:
 | 
			
		||||
        ctx->state = CFSTORE_EX_STATE_WRITE_DONE;
 | 
			
		||||
        break;
 | 
			
		||||
    case CFSTORE_OPCODE_CLOSE:
 | 
			
		||||
        switch(ctx->state)
 | 
			
		||||
        {
 | 
			
		||||
        case(CFSTORE_EX_STATE_CLOSING1):
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_CLOSE_DONE1;
 | 
			
		||||
            break;
 | 
			
		||||
        case(CFSTORE_EX_STATE_CLOSING2):
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_CLOSE_DONE2;
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown Close() error (line=%u)\r\n", __func__, __LINE__);
 | 
			
		||||
            /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
             * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
             * break; */
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case CFSTORE_OPCODE_FLUSH:
 | 
			
		||||
        switch(ctx->state)
 | 
			
		||||
        {
 | 
			
		||||
            case(CFSTORE_EX_STATE_FLUSHING1):
 | 
			
		||||
                ctx->state = CFSTORE_EX_STATE_FLUSH_DONE1;
 | 
			
		||||
                break;
 | 
			
		||||
            case(CFSTORE_EX_STATE_FLUSHING2):
 | 
			
		||||
                ctx->state = CFSTORE_EX_STATE_FLUSH_DONE2;
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown Find() error (line=%u)\r\n", __func__, __LINE__);
 | 
			
		||||
                /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
                 * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
                 * break; */
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case CFSTORE_OPCODE_OPEN:
 | 
			
		||||
        ctx->state = CFSTORE_EX_STATE_OPEN_DONE;
 | 
			
		||||
        break;
 | 
			
		||||
    case CFSTORE_OPCODE_FIND:
 | 
			
		||||
        switch(ctx->state)
 | 
			
		||||
        {
 | 
			
		||||
        case(CFSTORE_EX_STATE_FINDING1):
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_FIND_DONE1;
 | 
			
		||||
            break;
 | 
			
		||||
        case(CFSTORE_EX_STATE_FINDING2):
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_FIND_DONE2;
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown Find() error (line=%u)\r\n", __func__, __LINE__);
 | 
			
		||||
            /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
             * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
             * break; */
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case CFSTORE_OPCODE_GET_KEY_NAME:
 | 
			
		||||
        ctx->state = CFSTORE_EX_STATE_GET_KEY_NAME_DONE;
 | 
			
		||||
        break;
 | 
			
		||||
    case CFSTORE_OPCODE_GET_VALUE_LEN:
 | 
			
		||||
        ctx->state = CFSTORE_EX_STATE_GET_VALUE_LEN_DONE;
 | 
			
		||||
        break;
 | 
			
		||||
    case CFSTORE_OPCODE_READ:
 | 
			
		||||
        switch(ctx->state)
 | 
			
		||||
        {
 | 
			
		||||
        case(CFSTORE_EX_STATE_READING1):
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_READ_DONE1;
 | 
			
		||||
            break;
 | 
			
		||||
        case(CFSTORE_EX_STATE_READING2):
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_READ_DONE2;
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown Read() error (line=%u)\r\n", __func__, __LINE__);
 | 
			
		||||
            /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
             * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
             * break; */
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case CFSTORE_OPCODE_RSEEK:
 | 
			
		||||
        ctx->state = CFSTORE_EX_STATE_RSEEK_DONE;
 | 
			
		||||
        break;
 | 
			
		||||
    case CFSTORE_OPCODE_DELETE:
 | 
			
		||||
        ctx->state = CFSTORE_EX_STATE_DELETE_DONE;
 | 
			
		||||
        break;
 | 
			
		||||
    case CFSTORE_OPCODE_UNINITIALIZE:
 | 
			
		||||
        ctx->state = CFSTORE_EX_STATE_UNINIT_DONE;
 | 
			
		||||
        break;
 | 
			
		||||
    case CFSTORE_OPCODE_GET_STATUS:
 | 
			
		||||
    case CFSTORE_OPCODE_POWER_CONTROL:
 | 
			
		||||
    default:
 | 
			
		||||
        CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: received asynchronous notification for opcode=%d (%s)\r\b", __func__, cmd_code, cmd_code < CFSTORE_OPCODE_MAX ? cfstore_ex_opcode_str[cmd_code] : "unknown");
 | 
			
		||||
        /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
         * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
         * break; */
 | 
			
		||||
    }
 | 
			
		||||
    ctx->callback_status = status;
 | 
			
		||||
    ctx->callback_handle = handle;
 | 
			
		||||
    cfstore_ex_fms_update(ctx);
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cfstore_ex_fms_update(cfstore_example1_ctx_t* ctx)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret;
 | 
			
		||||
 | 
			
		||||
    switch (ctx->state)
 | 
			
		||||
    {
 | 
			
		||||
        case CFSTORE_EX_STATE_INITIALIZING:
 | 
			
		||||
            CFSTORE_EX1_LOG("INITIALIZING%s", "\r\n");
 | 
			
		||||
            // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_INITIALIZE can be invoked before Initialize() has returned
 | 
			
		||||
            ret = cfstore_drv->Initialize(cfstore_ex_callback, ctx);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Initialize() should return ret >= 0 for async/synch modes(ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
            if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) {
 | 
			
		||||
                ctx->state = CFSTORE_EX_STATE_INIT_DONE;
 | 
			
		||||
                break;
 | 
			
		||||
            } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) {
 | 
			
		||||
                // await pending notification of completion.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__);
 | 
			
		||||
            /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
             * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
             * break; */
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_INIT_DONE:
 | 
			
		||||
            CFSTORE_EX1_LOG("INIT_DONE%s", "\r\n");
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Initialize() completion failed (status=%ld)\r\n", __func__, ctx->callback_status);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == NULL, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_INITIALIZE) received non-NULL handle (%p)\r\n", __func__, ctx->callback_handle);
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_CREATING;
 | 
			
		||||
            // intentional fall-through
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_CREATING:
 | 
			
		||||
            CFSTORE_EX1_LOG("CREATING%s", "\r\n");
 | 
			
		||||
            memset(&ctx->kdesc, 0, sizeof(ARM_CFSTORE_KEYDESC));
 | 
			
		||||
            ctx->kdesc.drl = ARM_RETENTION_NVM;
 | 
			
		||||
            ctx->len = strlen(cfstore_ex_kv_value);
 | 
			
		||||
            // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_CREATE can be invoked before Create() has returned
 | 
			
		||||
            ret = cfstore_drv->Create(cfstore_ex_kv_name, ctx->len, &ctx->kdesc, ctx->hkey);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Create() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
            if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) {
 | 
			
		||||
                ctx->state = CFSTORE_EX_STATE_CREATE_DONE;
 | 
			
		||||
                break;
 | 
			
		||||
            } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) {
 | 
			
		||||
                // await pending notification of completion.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__);
 | 
			
		||||
            /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
             * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
             * break; */
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_CREATE_DONE:
 | 
			
		||||
            CFSTORE_EX1_LOG("CREATE_DONE%s", "\r\n");
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Create() completion failed (status=%ld)\r\n", __func__, ctx->callback_status);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == ctx->hkey, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_CREATE) received handle (%p) is not the hkey supplied to Create()(%p)\r\n", __func__, ctx->callback_handle, ctx->hkey);
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_WRITING;
 | 
			
		||||
            // intentional fall-through
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_WRITING:
 | 
			
		||||
            CFSTORE_EX1_LOG("WRITING%s", "\r\n");
 | 
			
		||||
            ctx->len = strlen(cfstore_ex_kv_value);
 | 
			
		||||
            // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_WRITE can be invoked before Write() has returned
 | 
			
		||||
            ret = cfstore_drv->Write(ctx->hkey, cfstore_ex_kv_value, &ctx->len);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Write() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
            if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) {
 | 
			
		||||
                ctx->state = CFSTORE_EX_STATE_WRITE_DONE;
 | 
			
		||||
                break;
 | 
			
		||||
            } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) {
 | 
			
		||||
                // await pending notification of completion.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__);
 | 
			
		||||
            /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
             * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
             * break; */
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_WRITE_DONE:
 | 
			
		||||
            CFSTORE_EX1_LOG("WRITE_DONE%s", "\r\n");
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Write() completion failed (status=%ld)\r\n", __func__, ctx->callback_status);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status == (int32_t) strlen(cfstore_ex_kv_value), "%s:Error: Write() number of octets written (i.e. completion status (%ld)) != strlen(ctx->value)(%ld)\r\n", __func__, ctx->callback_status, (int32_t) strlen(cfstore_ex_kv_value));
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status == (int32_t) ctx->len, "%s:Error: Write() number of octets written (i.e. completion status (%ld)) != updated value of len parameter (%ld)\r\n", __func__, ctx->callback_status, (int32_t) ctx->len);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == ctx->hkey, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_WRITE) received handle (%p) is not the hkey supplied to Write()(%p)\r\n", __func__, ctx->callback_handle, ctx->hkey);
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_CLOSING1;
 | 
			
		||||
            // intentional fall-through
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_CLOSING1:
 | 
			
		||||
            CFSTORE_EX1_LOG("CLOSING1%s", "\r\n");
 | 
			
		||||
            // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_CLOSE can be invoked before Close() has returned
 | 
			
		||||
            ret = cfstore_drv->Close(ctx->hkey);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Close() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
            if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) {
 | 
			
		||||
                ctx->state = CFSTORE_EX_STATE_CLOSE_DONE1;
 | 
			
		||||
                break;
 | 
			
		||||
            } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) {
 | 
			
		||||
                // await pending notification of completion.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__);
 | 
			
		||||
            /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
             * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
             * break; */
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_CLOSE_DONE1:
 | 
			
		||||
            CFSTORE_EX1_LOG("CLOSE_DONE1%s", "\r\n");
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Close() completion failed (status=%ld)\r\n", __func__, ctx->callback_status);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == NULL, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_CLOSE) received non-NULL handle (%p)\r\n", __func__, ctx->callback_handle);
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_FLUSHING1;
 | 
			
		||||
            // intentional fall-through
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_FLUSHING1:
 | 
			
		||||
            CFSTORE_EX1_LOG("FLUSHING1%s", "\r\n");
 | 
			
		||||
            // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_FLUSH can be invoked before Flush() has returned
 | 
			
		||||
            ret = cfstore_drv->Flush();
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Flush() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
            if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) {
 | 
			
		||||
                ctx->state = CFSTORE_EX_STATE_FLUSH_DONE1;
 | 
			
		||||
                break;
 | 
			
		||||
            } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) {
 | 
			
		||||
                // await pending notification of completion.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__);
 | 
			
		||||
            /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
             * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
             * break; */
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_FLUSH_DONE1:
 | 
			
		||||
            CFSTORE_EX1_LOG("FLUSH_DONE1%s", "\r\n");
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Flush() completion failed (status=%ld)\r\n", __func__, ctx->callback_status);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == NULL, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_FLUSH) received non-NULL handle (%p)\r\n", __func__, ctx->callback_handle);
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_OPENING;
 | 
			
		||||
            // intentional fall-through
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_OPENING:
 | 
			
		||||
            CFSTORE_EX1_LOG("OPENING%s", "\r\n");
 | 
			
		||||
            memset(&ctx->flags, 0, sizeof(ctx->flags));
 | 
			
		||||
            memset(&ctx->hkey, 0, CFSTORE_HANDLE_BUFSIZE);
 | 
			
		||||
            // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_OPEN can be invoked before Open() has returned
 | 
			
		||||
            ret = cfstore_drv->Open(cfstore_ex_kv_name, ctx->flags, ctx->hkey);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Open() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
            if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) {
 | 
			
		||||
                ctx->state = CFSTORE_EX_STATE_OPEN_DONE;
 | 
			
		||||
                break;
 | 
			
		||||
            } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) {
 | 
			
		||||
                // await pending notification of completion.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__);
 | 
			
		||||
            /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
             * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
             * break; */
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_OPEN_DONE:
 | 
			
		||||
            CFSTORE_EX1_LOG("OPEN_DONE%s", "\r\n");
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Open() completion failed (status=%ld)\r\n", __func__, ctx->callback_status);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == ctx->hkey, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_OPEN) received handle (%p) is not the hkey supplied to Open()(%p)\r\n", __func__, ctx->callback_handle, ctx->hkey);
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_READING1;
 | 
			
		||||
            // intentional fall-through
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_READING1:
 | 
			
		||||
            CFSTORE_EX1_LOG("READING1%s", "\r\n");
 | 
			
		||||
            ctx->len = CFSTORE_KEY_NAME_MAX_LENGTH;
 | 
			
		||||
            memset(ctx->value, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1);
 | 
			
		||||
            // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_READ can be invoked before Read() has returned
 | 
			
		||||
            ret = cfstore_drv->Read(ctx->hkey, ctx->value, &ctx->len);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Read() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
            if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) {
 | 
			
		||||
                ctx->state = CFSTORE_EX_STATE_READ_DONE1;
 | 
			
		||||
                break;
 | 
			
		||||
            } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) {
 | 
			
		||||
                // await pending notification of completion.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__);
 | 
			
		||||
            /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
             * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
             * break; */
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_READ_DONE1:
 | 
			
		||||
            CFSTORE_EX1_LOG("READ_DONE1%s", "\r\n");
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Read() completion failed (status=%ld)\r\n", __func__, ctx->callback_status);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status == (int32_t) strlen(cfstore_ex_kv_value), "%s:Error: Read() number of octets read (i.e. completion status (%ld)) != strlen(ctx->value)(%ld)\r\n", __func__, ctx->callback_status, (int32_t) strlen(cfstore_ex_kv_value));
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status == (int32_t) ctx->len, "%s:Error: Read() number of octets read (i.e. completion status (%ld)) != updated value of len parameter (%ld)\r\n", __func__, ctx->callback_status, (int32_t) ctx->len);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == ctx->hkey, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_READ) received handle (%p) is not the hkey supplied to Read()(%p)\r\n", __func__, ctx->callback_handle, ctx->hkey);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(strncmp(ctx->value, cfstore_ex_kv_value, strlen(cfstore_ex_kv_value)) == 0, "%s:Error: the read value (%s) is not as expected (%s)\r\n", __func__, ctx->value, cfstore_ex_kv_value);
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_RSEEKING;
 | 
			
		||||
            // intentional fall-through
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_RSEEKING:
 | 
			
		||||
            CFSTORE_EX1_LOG("RSEEKING%s", "\r\n");
 | 
			
		||||
            // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_READ can be invoked before Read() has returned
 | 
			
		||||
            ret = cfstore_drv->Rseek(ctx->hkey, CFSTORE_EX1_RSEEK_OFFSET);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Rseek() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
            if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) {
 | 
			
		||||
                ctx->state = CFSTORE_EX_STATE_RSEEK_DONE;
 | 
			
		||||
                break;
 | 
			
		||||
            } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) {
 | 
			
		||||
                // await pending notification of completion.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__);
 | 
			
		||||
            /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
             * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
             * break; */
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_RSEEK_DONE:
 | 
			
		||||
            CFSTORE_EX1_LOG("RSEEK_DONE%s", "\r\n");
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Read() completion failed (status=%ld)\r\n", __func__, ctx->callback_status);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == ctx->hkey, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_RSEEK) received handle (%p) is not the hkey supplied to Read()(%p)\r\n", __func__, ctx->callback_handle, ctx->hkey);
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_READING2;
 | 
			
		||||
            // intentional fall-through
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_READING2:
 | 
			
		||||
            CFSTORE_EX1_LOG("READING2%s", "\r\n");
 | 
			
		||||
            ctx->len = CFSTORE_KEY_NAME_MAX_LENGTH;
 | 
			
		||||
            memset(ctx->value, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1);
 | 
			
		||||
            // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_READ can be invoked before Read() has returned
 | 
			
		||||
            ret = cfstore_drv->Read(ctx->hkey, ctx->value, &ctx->len);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Read() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
            if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) {
 | 
			
		||||
                ctx->state = CFSTORE_EX_STATE_READ_DONE2;
 | 
			
		||||
                break;
 | 
			
		||||
            } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) {
 | 
			
		||||
                // await pending notification of completion.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__);
 | 
			
		||||
            /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
             * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
             * break; */
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_READ_DONE2:
 | 
			
		||||
            CFSTORE_EX1_LOG("READ_DONE2%s", "\r\n");
 | 
			
		||||
            CFSTORE_EX1_LOG("%s: value=%s\r\n", __func__, ctx->value);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Read() completion failed (status=%ld)\r\n", __func__, ctx->callback_status);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status == (int32_t) strlen(&cfstore_ex_kv_value[CFSTORE_EX1_RSEEK_OFFSET]), "%s:Error: Read() number of octets read (i.e. completion status (%ld)) != strlen(ctx->value)(%ld)\r\n", __func__, ctx->callback_status, (int32_t) strlen(&cfstore_ex_kv_value[CFSTORE_EX1_RSEEK_OFFSET]));
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status == (int32_t) ctx->len, "%s:Error: Read() number of octets read (i.e. completion status (%ld)) != updated value of len parameter (%ld)\r\n", __func__, ctx->callback_status, (int32_t) ctx->len);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == ctx->hkey, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_READ) received handle (%p) is not the hkey supplied to Read()(%p)\r\n", __func__, ctx->callback_handle, ctx->hkey);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(strncmp(ctx->value, &cfstore_ex_kv_value[CFSTORE_EX1_RSEEK_OFFSET], strlen(&cfstore_ex_kv_value[CFSTORE_EX1_RSEEK_OFFSET])) == 0, "%s:Error: the read value (%s) is not as expected (%s)\r\n", __func__, ctx->value, &cfstore_ex_kv_value[CFSTORE_EX1_RSEEK_OFFSET]);
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_CLOSING2;
 | 
			
		||||
            // intentional fall-through
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_CLOSING2:
 | 
			
		||||
            CFSTORE_EX1_LOG("CLOSING2%s", "\r\n");
 | 
			
		||||
            // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_CLOSE can be invoked before Close() has returned
 | 
			
		||||
            ret = cfstore_drv->Close(ctx->hkey);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Close() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
            if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) {
 | 
			
		||||
                ctx->state = CFSTORE_EX_STATE_CLOSE_DONE2;
 | 
			
		||||
                break;
 | 
			
		||||
            } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) {
 | 
			
		||||
                // await pending notification of completion.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__);
 | 
			
		||||
            /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
             * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
             * break; */
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_CLOSE_DONE2:
 | 
			
		||||
            CFSTORE_EX1_LOG("CLOSE_DONE2%s", "\r\n");
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Close() completion failed (status=%ld)\r\n", __func__, ctx->callback_status);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == NULL, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_CLOSE) received non-NULL handle (%p)\r\n", __func__, ctx->callback_handle);
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_FINDING1;
 | 
			
		||||
            // intentional fall-through
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_FINDING1:
 | 
			
		||||
            CFSTORE_EX1_LOG("FINDING1%s", "\r\n");
 | 
			
		||||
            // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_FIND can be invoked before Find() has returned
 | 
			
		||||
            ret = cfstore_drv->Find("*", ctx->hkey_next, ctx->hkey_prev);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Find() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
            if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) {
 | 
			
		||||
                ctx->state = CFSTORE_EX_STATE_FIND_DONE1;
 | 
			
		||||
                break;
 | 
			
		||||
            } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) {
 | 
			
		||||
                // await pending notification of completion.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__);
 | 
			
		||||
            /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
             * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
             * break; */
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_FIND_DONE1:
 | 
			
		||||
            CFSTORE_EX1_LOG("FIND_DONE1%s", "\r\n");
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status == ARM_DRIVER_OK, "%s:Error: Find() completion failed (status=%ld)\r\n", __func__, ctx->callback_status);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == ctx->hkey_prev, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_FIND) received handle (%p) is not the hkey supplied to Find()(%p)\r\n", __func__, ctx->callback_handle, ctx->hkey_prev);
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_GETTING_KEY_NAME;
 | 
			
		||||
            // intentional fall-through
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_GETTING_KEY_NAME:
 | 
			
		||||
            CFSTORE_EX1_LOG("GETTING_KEY_NAME%s", "\r\n");
 | 
			
		||||
            ctx->len = CFSTORE_KEY_NAME_MAX_LENGTH;
 | 
			
		||||
            memset(ctx->value, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1);
 | 
			
		||||
            // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_GET_KEY_NAME can be invoked before GetKeyName() has returned
 | 
			
		||||
            ret = cfstore_drv->GetKeyName(ctx->hkey_prev, ctx->value, (uint8_t*) &ctx->len);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: GetKeyName() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
            if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) {
 | 
			
		||||
                ctx->state = CFSTORE_EX_STATE_GET_KEY_NAME_DONE;
 | 
			
		||||
                break;
 | 
			
		||||
            } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) {
 | 
			
		||||
                // await pending notification of completion.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__);
 | 
			
		||||
            /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
             * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
             * break; */
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_GET_KEY_NAME_DONE:
 | 
			
		||||
            CFSTORE_EX1_LOG("GET_KEY_NAME_DONE%s", "\r\n");
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: GetKeyName() completion failed (status=%ld)\r\n", __func__, ctx->callback_status);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG( ((int32_t) ctx->len == ((int32_t) strlen(cfstore_ex_kv_name)+1)), "%s:Error: GetKeyName() updated value of len parameter (%ld) != strlen(cfstore_ex_kv_name) (%ld) (\r\n", __func__, (int32_t) ctx->len, (int32_t) strlen(cfstore_ex_kv_name));
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == ctx->hkey_prev, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_GET_KEY_NAME) received handle (%p) is not the hkey supplied to GetKeyName()(%p)\r\n", __func__, ctx->callback_handle, ctx->hkey_prev);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(strncmp(ctx->value, cfstore_ex_kv_name, strlen(cfstore_ex_kv_name)) == 0, "%s:Error: the key name (%s) is not as expected (%s)\r\n", __func__, ctx->value, cfstore_ex_kv_name);
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_GETTING_VALUE_LEN;
 | 
			
		||||
            // intentional fall-through
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_GETTING_VALUE_LEN:
 | 
			
		||||
            CFSTORE_EX1_LOG("GETTING_VALUE_LEN%s", "\r\n");
 | 
			
		||||
            ctx->len = CFSTORE_KEY_NAME_MAX_LENGTH;
 | 
			
		||||
            // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_GET_VALUE_LEN can be invoked before GetValueLen() has returned
 | 
			
		||||
            ret = cfstore_drv->GetValueLen(ctx->hkey_prev, &ctx->len);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: GetValueLen() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
            if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) {
 | 
			
		||||
                ctx->state = CFSTORE_EX_STATE_GET_VALUE_LEN_DONE;
 | 
			
		||||
                break;
 | 
			
		||||
            } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) {
 | 
			
		||||
                // await pending notification of completion.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__);
 | 
			
		||||
            /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
             * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
             * break; */
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_GET_VALUE_LEN_DONE:
 | 
			
		||||
            CFSTORE_EX1_LOG("GET_VALUE_LEN_DONE%s", "\r\n");
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: GetValueLen() completion failed (status=%ld)\r\n", __func__, ctx->callback_status);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG((int32_t) ctx->len == (int32_t) strlen(cfstore_ex_kv_value), "%s:Error: GetValueLen() updated value of len parameter (%ld) != strlen(cfstore_ex_kv_value)(%ld) \r\n", __func__, (int32_t) ctx->len, (int32_t) strlen(cfstore_ex_kv_value));
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == ctx->hkey_prev, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_GET_VALUE_LEN) received handle (%p) is not the hkey supplied to GetValueLen()(%p)\r\n", __func__, ctx->callback_handle, ctx->hkey_prev);
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_DELETING;
 | 
			
		||||
            // intentional fall-through
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_DELETING:
 | 
			
		||||
            CFSTORE_EX1_LOG("DELETING%s", "\r\n");
 | 
			
		||||
            // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_DELETE can be invoked before Delete() has returned
 | 
			
		||||
            ret = cfstore_drv->Delete(ctx->callback_handle);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Close() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
            if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) {
 | 
			
		||||
                ctx->state = CFSTORE_EX_STATE_DELETE_DONE;
 | 
			
		||||
                break;
 | 
			
		||||
            } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) {
 | 
			
		||||
                // await pending notification of completion.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__);
 | 
			
		||||
            /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
             * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
             * break; */
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_DELETE_DONE:
 | 
			
		||||
            CFSTORE_EX1_LOG("DELETE_DONE%s", "\r\n");
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Delete() completion failed (status=%ld)\r\n", __func__, ctx->callback_status);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == NULL, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_DELETE) received non-NULL handle (%p)\r\n", __func__, ctx->callback_handle);
 | 
			
		||||
            CFSTORE_HANDLE_SWAP(ctx->hkey_prev, ctx->hkey_next);
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_FINDING2;
 | 
			
		||||
            // intentional fall-through
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_FINDING2:
 | 
			
		||||
            CFSTORE_EX1_LOG("FINDING2%s", "\r\n");
 | 
			
		||||
            // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_FIND can be invoked before Find() has returned
 | 
			
		||||
            ret = cfstore_drv->Find("*", ctx->hkey_next, ctx->hkey_prev);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND, "%s:Error: Find() failed to return expected value of ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
            if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND && ctx->caps.asynchronous_ops == false) {
 | 
			
		||||
                ctx->state = CFSTORE_EX_STATE_FIND_DONE2;
 | 
			
		||||
                break;
 | 
			
		||||
            } else if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND && ctx->caps.asynchronous_ops == true) {
 | 
			
		||||
                // await pending notification of completion.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__);
 | 
			
		||||
            /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
             * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
             * break; */
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_FIND_DONE2:
 | 
			
		||||
            CFSTORE_EX1_LOG("FIND_DONE2%s", "\r\n");
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND, "%s:Error: Find() completion should have been ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND (status=%ld)\r\n", __func__, ctx->callback_status);
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_FLUSHING2;
 | 
			
		||||
            // intentional fall-through
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_FLUSHING2:
 | 
			
		||||
            CFSTORE_EX1_LOG("FLUSHING2%s", "\r\n");
 | 
			
		||||
            // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_FLUSH can be invoked before Flush() has returned
 | 
			
		||||
            ret = cfstore_drv->Flush();
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error:2: Flush() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
            if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) {
 | 
			
		||||
                ctx->state = CFSTORE_EX_STATE_FLUSH_DONE2;
 | 
			
		||||
                break;
 | 
			
		||||
            } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) {
 | 
			
		||||
                // await pending notification of completion.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__);
 | 
			
		||||
            /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
             * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
             * break; */
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_FLUSH_DONE2:
 | 
			
		||||
            CFSTORE_EX1_LOG("FLUSH_DONE2%s", "\r\n");
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Flush() completion failed (status=%ld)\r\n", __func__, ctx->callback_status);
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == NULL, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_FLUSH) received non-NULL handle (%p)\r\n", __func__, ctx->callback_handle);
 | 
			
		||||
            ctx->state = CFSTORE_EX_STATE_UNINITIALIZING;
 | 
			
		||||
            // intentional fall-through
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_UNINITIALIZING:
 | 
			
		||||
            CFSTORE_EX1_LOG("UNINITIALIZING%s", "\r\n");
 | 
			
		||||
            ret = cfstore_drv->Uninitialize();
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Uninitialize() should return ret >= 0 for async/synch modes(ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
            if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) {
 | 
			
		||||
                ctx->state = CFSTORE_EX_STATE_UNINIT_DONE;
 | 
			
		||||
                break;
 | 
			
		||||
            } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) {
 | 
			
		||||
                // await pending notification of completion.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__);
 | 
			
		||||
            /* The following 'break' statement generates ARMCC #111-D: statement is unreachable warning
 | 
			
		||||
             * and hence is commented out. Re-instate if previous assert is removed.
 | 
			
		||||
             * break; */
 | 
			
		||||
 | 
			
		||||
        case CFSTORE_EX_STATE_UNINIT_DONE:
 | 
			
		||||
            CFSTORE_EX1_LOG("UNINIT_DONE%s", "\r\n");
 | 
			
		||||
            CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == NULL, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_UNINITIALIZE) received non-NULL handle (%p)\r\n", __func__, ctx->callback_handle);
 | 
			
		||||
            cfstore_example1_done = true;
 | 
			
		||||
            CFSTORE_EX1_LOG("***************%s", "\r\n");
 | 
			
		||||
            CFSTORE_EX1_LOG("*** SUCCESS ***%s", "\r\n");
 | 
			
		||||
            CFSTORE_EX1_LOG("***************%s", "\r\n");
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static control_t cfstore_example1_app_start(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    cfstore_example1_ctx_t* ctx = &cfstore_example1_ctx_g;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
 | 
			
		||||
    /* initialise the context */
 | 
			
		||||
    memset(ctx, 0, sizeof(cfstore_example1_ctx_t));
 | 
			
		||||
    cfstore_example1_done = false;
 | 
			
		||||
    ctx->hkey_next = ctx->hkey_next_buf;
 | 
			
		||||
    ctx->hkey_prev = ctx->hkey_prev_buf;
 | 
			
		||||
    ctx->callback_status = ARM_DRIVER_ERROR;
 | 
			
		||||
    ctx->state = CFSTORE_EX_STATE_INITIALIZING;
 | 
			
		||||
    ctx->caps = cfstore_drv->GetCapabilities();
 | 
			
		||||
    cfstore_ex_fms_update(ctx);
 | 
			
		||||
 | 
			
		||||
    /* main application worker loop */
 | 
			
		||||
    while (!cfstore_example1_done)
 | 
			
		||||
    {
 | 
			
		||||
        // do some work
 | 
			
		||||
        CFSTORE_EX1_LOG("%s: going to sleep!\r\n", __func__);
 | 
			
		||||
 | 
			
		||||
#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3
 | 
			
		||||
        __WFE();
 | 
			
		||||
#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */
 | 
			
		||||
 | 
			
		||||
#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 4
 | 
			
		||||
        /* mbedosV3++
 | 
			
		||||
         * todo: port __WFE()
 | 
			
		||||
         */
 | 
			
		||||
#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 4 */
 | 
			
		||||
        CFSTORE_EX1_LOG("%s: woke up!\r\n", __func__);
 | 
			
		||||
    }
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifndef CFSTORE_EXAMPLE1_APP
 | 
			
		||||
/* when built as Configuration-Store example, include greentea support otherwise omit */
 | 
			
		||||
 | 
			
		||||
/* report whether built/configured for flash sync or async mode */
 | 
			
		||||
static control_t cfstore_example1_test_00(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
 | 
			
		||||
    ret = cfstore_test_startup();
 | 
			
		||||
    CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: failed to perform test startup (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(25, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
           /*          1         2         3         4         5         6        7  */
 | 
			
		||||
           /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        Case("EXAMPLE1_test_00", cfstore_example1_test_00),
 | 
			
		||||
        Case("EXAMPLE1_test_01_start", cfstore_example1_app_start),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#else   // CFSTORE_EXAMPLE1_APP
 | 
			
		||||
 | 
			
		||||
// stand alone Configuration-Store-Example
 | 
			
		||||
void app_start(int argc __unused, char** argv __unused)
 | 
			
		||||
{
 | 
			
		||||
    cfstore_example1_app_start(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif // CFSTORE_EXAMPLE1_APP
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif // __MBED__ && ! defined TOOLCHAIN_GCC_ARM
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,259 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 example2.cpp Test case to demonstrate a subset of the API functions each work correctly.
 | 
			
		||||
 *
 | 
			
		||||
 *  Overview of test:
 | 
			
		||||
 * - initialises cfstore
 | 
			
		||||
 * - creates a key called "com.arm.mbed.spv.assets.asset2.payload" with value blob length = 15 = strlen("Grumpy old man")+1.
 | 
			
		||||
 * - writes the data for the key to be "Grumpy old man"
 | 
			
		||||
 * - closes kv.
 | 
			
		||||
 * - opens kv for reading/writing
 | 
			
		||||
 * - reads the value blob and checks its == "Grumpy old man"
 | 
			
		||||
 * - writes the first 11 chars of the value blob to be "Grumpy man" plus a NULL;
 | 
			
		||||
 * - reads the value blob back and checks its as expected
 | 
			
		||||
 *
 | 
			
		||||
 * This test is coded so as to work in the following modes:
 | 
			
		||||
 * - flash sync mode i.e. with caps.asynchronous_ops == false
 | 
			
		||||
 * - flash async mode i.e. with caps.asynchronous_ops == true
 | 
			
		||||
 */
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#ifdef YOTTA_CFG_CONFIG_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CONFIG_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
static char cfstore_example2_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE];
 | 
			
		||||
 | 
			
		||||
/* defines */
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
#define PvMemSet memset
 | 
			
		||||
#define PvStrLen strlen
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
/* report whether built/configured for flash sync or async mode */
 | 
			
		||||
static control_t cfstore_example2_test_00(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    ret = cfstore_test_startup();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to perform test startup (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_example2_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
ARM_CFSTORE_DRIVER *drv = &cfstore_driver;
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int32_t CreateKeyValueStore(
 | 
			
		||||
	const char *keyName,
 | 
			
		||||
	const char *data,
 | 
			
		||||
	ARM_CFSTORE_SIZE *dataLength,
 | 
			
		||||
	ARM_CFSTORE_KEYDESC *keyDesc)
 | 
			
		||||
{
 | 
			
		||||
	int32_t cfsStatus = ARM_DRIVER_ERROR;
 | 
			
		||||
	ARM_CFSTORE_SIZE valueLength = 0;
 | 
			
		||||
	ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
 | 
			
		||||
	valueLength = *dataLength;
 | 
			
		||||
	cfsStatus = drv->Create(keyName, valueLength, keyDesc, hkey);
 | 
			
		||||
	TEST_ASSERT_EQUAL(ARM_DRIVER_OK, cfsStatus);
 | 
			
		||||
 | 
			
		||||
	valueLength = *dataLength;
 | 
			
		||||
	cfsStatus = drv->Write(hkey, data, &valueLength);
 | 
			
		||||
	/*
 | 
			
		||||
	 * (1) Note the following:
 | 
			
		||||
	 * - if cfsStatus > 0 then Write() has completed synchronously and returned the number of bytes written (irrespective of the caps.asynchronous_ops attribute).
 | 
			
		||||
	 * - if cfsStatus == ARM_DRIVER_OK then:
 | 
			
		||||
     *      - if caps.asynchronous_ops == true then the operation will be completed with registered client callback passed to Initialize().
 | 
			
		||||
     *      - if caps.asynchronous_ops == false then the operation has completed synchronously and no bytes were written.
 | 
			
		||||
     * - if cfsStatus < ARM_DRIVER_OK then an error has occurred
 | 
			
		||||
	 */
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write key (rc=%d)\n", __func__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example2_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%sError: valueLength(%d) does not match the expected dataLength(%d)\n", __func__, (int) valueLength, (int) *dataLength);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(*dataLength == valueLength, cfstore_example2_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%sError: Write() return value cfsStatus(%d) does not match the expected dataLength(%d)\n", __func__, (int) cfsStatus, (int) *dataLength);
 | 
			
		||||
    TEST_ASSERT_MESSAGE((int32_t) *dataLength == cfsStatus, cfstore_example2_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
	drv->Close(hkey);
 | 
			
		||||
	/* CreateKeyValueStore() returns what was returned from Write(). See (1) above for description. */
 | 
			
		||||
	return cfsStatus;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static control_t cfstore_example2_test_01(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
	int32_t cfsStatus;
 | 
			
		||||
	ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
	ARM_CFSTORE_HANDLE_INIT(updatedKeyH);
 | 
			
		||||
	ARM_CFSTORE_FMODE flags;
 | 
			
		||||
	ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
	ARM_CFSTORE_SIZE valueLen;
 | 
			
		||||
	char* ptr = NULL;
 | 
			
		||||
	
 | 
			
		||||
	const char key[]   = "com.arm.mbed.spv.assets.asset2.payload";
 | 
			
		||||
	const char value[] = "Grumpy old man";
 | 
			
		||||
 | 
			
		||||
	(void) call_count;
 | 
			
		||||
 | 
			
		||||
	// It must not exceed the value_len field specified when the Key-Value pair was created
 | 
			
		||||
	const char newDataToWrite[] = "Grumpy man";
 | 
			
		||||
	
 | 
			
		||||
	char readBuf[CFSTORE_KEY_NAME_MAX_LENGTH + 1];
 | 
			
		||||
	ARM_CFSTORE_SIZE len = 0;
 | 
			
		||||
 | 
			
		||||
	// Write a key-value pair
 | 
			
		||||
 | 
			
		||||
	PvMemSet(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
	PvMemSet(&flags, 0, sizeof(flags));
 | 
			
		||||
	PvMemSet(readBuf, 0, CFSTORE_KEY_NAME_MAX_LENGTH + 1);
 | 
			
		||||
 | 
			
		||||
	kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE;
 | 
			
		||||
	/* The length supplied to Write() is the number of octets to store in the blob.
 | 
			
		||||
	 * Specifying the following value for valueLen will store the terminating null to
 | 
			
		||||
	 * a string, for example.
 | 
			
		||||
	 */
 | 
			
		||||
	valueLen = PvStrLen(value) + 1;
 | 
			
		||||
 | 
			
		||||
	cfsStatus = drv->Initialize(NULL, NULL);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Initialize() failed (cfsStatus=%d)\n", __func__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example2_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
	cfsStatus = CreateKeyValueStore(key, value, &valueLen, &kdesc);
 | 
			
		||||
 | 
			
		||||
	/* CreateKeyValueStore() returns the number of characters written, which can vary between 0 and the supplied arg valueLen
 | 
			
		||||
	 * - in the case that this example is compiled for flash mode sync, CreateKeyValueStore(), on success should always return valueLen
 | 
			
		||||
	 * - in the case that this example is compiled for flash mode async, CreateKeyValueStore() on success may return a value 0 to valueLen
 | 
			
		||||
	 *   with async notification of the completed transaction.
 | 
			
		||||
	 */
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%sError: valueLen(%d) does not match the expected returned value from CreateKeyValueStore(%d)\n", __func__, (int) valueLen, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus == (int32_t) valueLen, cfstore_example2_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
	// Read key-value pair with 'Write' permission
 | 
			
		||||
 | 
			
		||||
	flags.read = true;
 | 
			
		||||
	flags.write = true;
 | 
			
		||||
	cfsStatus = drv->Open(key, flags, hkey);
 | 
			
		||||
	TEST_ASSERT_EQUAL(ARM_DRIVER_OK, cfsStatus);
 | 
			
		||||
 | 
			
		||||
	len = sizeof(readBuf);
 | 
			
		||||
	cfsStatus = drv->Read(hkey, readBuf, &len);
 | 
			
		||||
    /* Read() returns the number of characters read, which can vary between 0 and the size of the value blob, and the size of the supplied buffer  */
 | 
			
		||||
	CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Read() returned value (%d) does not match the created length of the value blob(%d)\n", __func__, (int) cfsStatus, (int) PvStrLen(value) + 1);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus == (int32_t) (PvStrLen(value) + 1), cfstore_example2_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Read() returned len value (%d) does not match the created length of the value blob(%d)\n", __func__, (int) len, (int) PvStrLen(value) + 1);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(len == PvStrLen(value) + 1, cfstore_example2_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* Note:
 | 
			
		||||
     * - original data = "Grumpy old man", which is 14+1 chars inc NULL
 | 
			
		||||
     * - New data = "Grumpy man" which is 10+1 chars inc NULL
 | 
			
		||||
     * - when the key "com.arm.mbed.spv.assets.asset2.payload"; was created, it was created with a value blob size of 14+1=15 chars.
 | 
			
		||||
     * - The new data is shorter that the old data so it will be accommodated in the value blob
 | 
			
		||||
     * - The size of the value blob will stay the same.
 | 
			
		||||
     */
 | 
			
		||||
	// Update the value and value length
 | 
			
		||||
    /* note len set to sizeof(newDataToWrite) which includes the terminating null of the string */
 | 
			
		||||
	len = sizeof(newDataToWrite);
 | 
			
		||||
	cfsStatus = drv->Write(hkey, newDataToWrite, &len);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Write() returned cfsStatus value (%d) does not match the length of new data written(%d)\n", __func__, (int) cfsStatus, (int)  sizeof(newDataToWrite));
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus == (int32_t) sizeof(newDataToWrite), cfstore_example2_utest_msg_g);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Write() returned len (%d) does not match the length of new data written(%d)\n", __func__, (int) len, (int) sizeof(newDataToWrite));
 | 
			
		||||
    TEST_ASSERT_MESSAGE((int32_t) len == (int32_t) sizeof(newDataToWrite), cfstore_example2_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
	drv->Close(hkey);
 | 
			
		||||
 | 
			
		||||
	// Check that the value was updated
 | 
			
		||||
	flags.write = false;
 | 
			
		||||
	cfsStatus = drv->Open(key, flags, updatedKeyH);
 | 
			
		||||
	TEST_ASSERT_EQUAL(ARM_DRIVER_OK, cfsStatus);
 | 
			
		||||
 | 
			
		||||
	len = CFSTORE_KEY_NAME_MAX_LENGTH;
 | 
			
		||||
	PvMemSet(readBuf, 0, len);
 | 
			
		||||
	cfsStatus = drv->Read(updatedKeyH, readBuf, &len);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Read() returned value (%d) does not match the created length of the value blob(%d)\n", __func__, (int) cfsStatus, (int) PvStrLen(value) + 1);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus == (int32_t) (PvStrLen(value) + 1), cfstore_example2_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Read() returned len value (%d) does not match the created length of the value blob(%d)\n", __func__, (int) len, (int) PvStrLen(value) + 1);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(len == (PvStrLen(value) + 1), cfstore_example2_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* convert any terminating nulls to '=' */
 | 
			
		||||
    while( (ptr = (char*) memchr(readBuf, 0, (PvStrLen(value) + 1))) != NULL)
 | 
			
		||||
    {
 | 
			
		||||
        *ptr = '=';
 | 
			
		||||
    }
 | 
			
		||||
    /* check the data is as expected */
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Read() returned unexpected string (%s) where nulls have been converted to '=' chars\n", __func__, readBuf);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(strncmp(readBuf, "Grumpy man=man=", (PvStrLen(value) + 1)) == 0, cfstore_example2_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* revert to CFSTORE_LOG if more trace required */
 | 
			
		||||
    CFSTORE_DBGLOG("Success: New value of KV (%s) value blob (with nulls converted to '=') = (%s)\n", key, readBuf);
 | 
			
		||||
 | 
			
		||||
	drv->Close(updatedKeyH);
 | 
			
		||||
 | 
			
		||||
	cfsStatus = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() failed (cfsStatus=%d)\n", __func__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example2_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
	return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(400, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
           /*          1         2         3         4         5         6        7  */
 | 
			
		||||
           /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        Case("EXAMPLE2_test_00", cfstore_example2_test_00),
 | 
			
		||||
        Case("EXAMPLE2_test_01", cfstore_example2_test_01),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
/// @endcond
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,329 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 example3.cpp Test case to demonstrate each API function works correctly.
 | 
			
		||||
 *
 | 
			
		||||
 * \par Example 3 Notes
 | 
			
		||||
 *
 | 
			
		||||
 * Example3 is a synchronous mode example for creating key-values in the persistent storage.
 | 
			
		||||
 *
 | 
			
		||||
 * The flash-journal synchronous mode example test does the following CFSTORE operations:
 | 
			
		||||
 * - initialises
 | 
			
		||||
 * - creates a key-value pair (KV).
 | 
			
		||||
 * - writes the data for the KV
 | 
			
		||||
 * - closes KV.
 | 
			
		||||
 * - flushes the KV to flash
 | 
			
		||||
 * - opens KV for reading.
 | 
			
		||||
 * - reads KV and checks the value blob was the same as previously written.
 | 
			
		||||
 * - closes KV.
 | 
			
		||||
 * - finds a KV (there is only 1 to find).
 | 
			
		||||
 * - for the KV returned, get the key name.
 | 
			
		||||
 * - for the KV returned, get the value length.
 | 
			
		||||
 * - for the KV returned, delete the KV.
 | 
			
		||||
 * - find another KV (which fails as there are no more keys to find).
 | 
			
		||||
 * - flushes the updated state to flash to store the removal of the deleted KV.
 | 
			
		||||
 * - uninitialises
 | 
			
		||||
 * - stops
 | 
			
		||||
 *
 | 
			
		||||
 * This test is coded so as to work only in flash journal sync mode
 | 
			
		||||
 * i.e. with caps.asynchronous_ops == false
 | 
			
		||||
 *
 | 
			
		||||
 * The test leaves the flash in the same state as at the beginning of the test so
 | 
			
		||||
 * it can be run a second time on the device without flashing, and the test should
 | 
			
		||||
 * still work.
 | 
			
		||||
 *
 | 
			
		||||
 * \par How to Build Example3 as a Stand-alone Application
 | 
			
		||||
 *
 | 
			
		||||
 * This example can be build as a stand-alone application as follows:
 | 
			
		||||
 * - Create a new mbed application using the `mbed new .` command.
 | 
			
		||||
 * - Copy this file example3.cpp from the to the top level application directory and rename the file to main.cpp.
 | 
			
		||||
 * - Build the application with `mbed compile -v -m <target> -t <toolchain> -DCFSTORE_EXAMPLE3_APP` e.g. `mbed compile -v -m K64F -t GCC_ARM -DCFSTORE_EXAMPLE3_APP`.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
#ifndef CFSTORE_EXAMPLE3_APP
 | 
			
		||||
/* when built as Configuration-Store example, include greentea support otherwise omit */
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#else   // CFSTORE_EXAMPLE3_APP
 | 
			
		||||
/* map utest types for building as stand alone example */
 | 
			
		||||
#define control_t   void
 | 
			
		||||
#define CaseNext
 | 
			
		||||
#endif  // CFSTORE_EXAMPLE3_APP
 | 
			
		||||
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
 | 
			
		||||
#ifdef YOTTA_CFG_CONFIG_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CONFIG_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#ifndef CFSTORE_EXAMPLE3_APP
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
#define CFSTORE_EX1_TEST_ASSERT(Expr)                       if (!(Expr)) { printf("%s:%u: assertion failure\r\n", __FUNCTION__, __LINE__); while (1) ;}
 | 
			
		||||
#define CFSTORE_EX1_TEST_ASSERT_EQUAL(expected, actual)     if ((expected) != (actual)) {printf("%s:%u: assertion failure\r\n", __FUNCTION__, __LINE__); while (1) ;}
 | 
			
		||||
#define CFSTORE_EX1_TEST_ASSERT_NOT_EQUAL(expected, actual) if ((expected) == (actual)) {printf("%s:%u: assertion failure\r\n", __FUNCTION__, __LINE__); while (1) ;}
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_EX1_TEST_ASSERT_MSG(Expr, _fmt, ...)      \
 | 
			
		||||
    do                                                    \
 | 
			
		||||
    {                                                     \
 | 
			
		||||
        if (!(Expr))                                      \
 | 
			
		||||
        {                                                 \
 | 
			
		||||
            printf(_fmt, __VA_ARGS__);                    \
 | 
			
		||||
            while (1) ;                                   \
 | 
			
		||||
        }                                                 \
 | 
			
		||||
    }while(0);
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_EX1_LOG(_fmt, ...)                        \
 | 
			
		||||
  do                                                      \
 | 
			
		||||
  {                                                       \
 | 
			
		||||
        printf(_fmt, __VA_ARGS__);                        \
 | 
			
		||||
  }while(0);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const char* cfstore_ex3_opcode_str[] =
 | 
			
		||||
{
 | 
			
		||||
    "UNDEFINED",
 | 
			
		||||
    "CFSTORE_OPCODE_CLOSE",
 | 
			
		||||
    "CFSTORE_OPCODE_CREATE",
 | 
			
		||||
    "CFSTORE_OPCODE_DELETE",
 | 
			
		||||
    "CFSTORE_OPCODE_FIND",
 | 
			
		||||
    "CFSTORE_OPCODE_FLUSH",
 | 
			
		||||
    "CFSTORE_OPCODE_GET_KEY_NAME",
 | 
			
		||||
    "CFSTORE_OPCODE_GET_STATUS",
 | 
			
		||||
    "CFSTORE_OPCODE_GET_VALUE_LEN",
 | 
			
		||||
    "CFSTORE_OPCODE_INITIALIZE",
 | 
			
		||||
    "CFSTORE_OPCODE_OPEN",
 | 
			
		||||
    "CFSTORE_OPCODE_POWER_CONTROL",
 | 
			
		||||
    "CFSTORE_OPCODE_READ",
 | 
			
		||||
    "CFSTORE_OPCODE_RSEEK",
 | 
			
		||||
    "CFSTORE_OPCODE_UNINITIALIZE",
 | 
			
		||||
    "CFSTORE_OPCODE_WRITE",
 | 
			
		||||
    "CFSTORE_OPCODE_MAX"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const char* cfstore_ex3_kv_name = "basement.medicine.pavement.government.trenchcoat.off.cough.off.kid.did.when.again.alleyway.friend.cap.pen.dollarbills.ten.foot.soot.put.but.anyway.say.May.DA.kid.did.toes.bows.those.hose.nose.clothes.man.blows.well.well";
 | 
			
		||||
const char* cfstore_ex3_kv_value = "TheRollingStone";
 | 
			
		||||
#define CFSTORE_EX1_RSEEK_OFFSET    10   /* offset to S of Stone */
 | 
			
		||||
 | 
			
		||||
typedef struct cfstore_example3_ctx_t
 | 
			
		||||
{
 | 
			
		||||
    ARM_CFSTORE_CAPABILITIES caps;
 | 
			
		||||
    uint8_t hkey[CFSTORE_HANDLE_BUFSIZE];
 | 
			
		||||
    uint8_t hkey_next_buf[CFSTORE_HANDLE_BUFSIZE];
 | 
			
		||||
    uint8_t hkey_prev_buf[CFSTORE_HANDLE_BUFSIZE];
 | 
			
		||||
    ARM_CFSTORE_HANDLE hkey_next;
 | 
			
		||||
    ARM_CFSTORE_HANDLE hkey_prev;
 | 
			
		||||
    ARM_CFSTORE_SIZE len;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
    char value[CFSTORE_KEY_NAME_MAX_LENGTH+1];
 | 
			
		||||
} cfstore_example3_ctx_t;
 | 
			
		||||
 | 
			
		||||
static cfstore_example3_ctx_t cfstore_example3_ctx_g;
 | 
			
		||||
 | 
			
		||||
extern ARM_CFSTORE_DRIVER cfstore_driver;
 | 
			
		||||
ARM_CFSTORE_DRIVER *cfstore_drv = &cfstore_driver;
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void cfstore_ex3_test_01(cfstore_example3_ctx_t* ctx)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret;
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX1_LOG("INITIALIZING%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Initialize(NULL, NULL);
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Initialize() should return ret >= 0 for async/synch modes(ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX1_LOG("CREATING%s", "\r\n");
 | 
			
		||||
	memset(&ctx->kdesc, 0, sizeof(ARM_CFSTORE_KEYDESC));
 | 
			
		||||
	ctx->kdesc.drl = ARM_RETENTION_NVM;
 | 
			
		||||
	ctx->len = strlen(cfstore_ex3_kv_value);
 | 
			
		||||
	ret = cfstore_drv->Create(cfstore_ex3_kv_name, ctx->len, &ctx->kdesc, ctx->hkey);
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Create() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX1_LOG("WRITING%s", "\r\n");
 | 
			
		||||
	ctx->len = strlen(cfstore_ex3_kv_value);
 | 
			
		||||
	ret = cfstore_drv->Write(ctx->hkey, cfstore_ex3_kv_value, &ctx->len);
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Write() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret == (int32_t) strlen(cfstore_ex3_kv_value), "%s:Error: Write() number of octets written (i.e. completion status (%ld)) != strlen(ctx->value)(%ld)\r\n", __func__, ret, (int32_t) strlen(cfstore_ex3_kv_value));
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret == (int32_t) ctx->len, "%s:Error: Write() number of octets written (i.e. completion status (%ld)) != updated value of len parameter (%ld)\r\n", __func__, ret, (int32_t) ctx->len);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX1_LOG("CLOSING1%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Close(ctx->hkey);
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Close() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX1_LOG("FLUSHING1%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Flush();
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Flush() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX1_LOG("OPENING%s", "\r\n");
 | 
			
		||||
	memset(&ctx->flags, 0, sizeof(ctx->flags));
 | 
			
		||||
	memset(&ctx->hkey, 0, CFSTORE_HANDLE_BUFSIZE);
 | 
			
		||||
	ret = cfstore_drv->Open(cfstore_ex3_kv_name, ctx->flags, ctx->hkey);
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Open() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX1_LOG("READING1%s", "\r\n");
 | 
			
		||||
	ctx->len = CFSTORE_KEY_NAME_MAX_LENGTH;
 | 
			
		||||
	memset(ctx->value, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1);
 | 
			
		||||
	ret = cfstore_drv->Read(ctx->hkey, ctx->value, &ctx->len);
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Read() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret == (int32_t) strlen(cfstore_ex3_kv_value), "%s:Error: Read() number of octets read (i.e. completion status (%ld)) != strlen(ctx->value)(%ld)\r\n", __func__, ret, (int32_t) strlen(cfstore_ex3_kv_value));
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret == (int32_t) ctx->len, "%s:Error: Read() number of octets read (i.e. completion status (%ld)) != updated value of len parameter (%ld)\r\n", __func__, ret, (int32_t) ctx->len);
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(strncmp(ctx->value, cfstore_ex3_kv_value, strlen(cfstore_ex3_kv_value)) == 0, "%s:Error: the read value (%s) is not as expected (%s)\r\n", __func__, ctx->value, cfstore_ex3_kv_value);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX1_LOG("RSEEKING%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Rseek(ctx->hkey, CFSTORE_EX1_RSEEK_OFFSET);
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Rseek() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX1_LOG("READING2%s", "\r\n");
 | 
			
		||||
	ctx->len = CFSTORE_KEY_NAME_MAX_LENGTH;
 | 
			
		||||
	memset(ctx->value, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1);
 | 
			
		||||
	ret = cfstore_drv->Read(ctx->hkey, ctx->value, &ctx->len);
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Read() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret == (int32_t) strlen(&cfstore_ex3_kv_value[CFSTORE_EX1_RSEEK_OFFSET]), "%s:Error: Read() number of octets read (i.e. completion status (%ld)) != strlen(ctx->value)(%ld)\r\n", __func__, ret, (int32_t) strlen(&cfstore_ex3_kv_value[CFSTORE_EX1_RSEEK_OFFSET]));
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret == (int32_t) ctx->len, "%s:Error: Read() number of octets read (i.e. completion status (%ld)) != updated value of len parameter (%ld)\r\n", __func__, ret, (int32_t) ctx->len);
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(strncmp(ctx->value, &cfstore_ex3_kv_value[CFSTORE_EX1_RSEEK_OFFSET], strlen(&cfstore_ex3_kv_value[CFSTORE_EX1_RSEEK_OFFSET])) == 0, "%s:Error: the read value (%s) is not as expected (%s)\r\n", __func__, ctx->value, &cfstore_ex3_kv_value[CFSTORE_EX1_RSEEK_OFFSET]);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX1_LOG("CLOSING2%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Close(ctx->hkey);
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Close() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX1_LOG("FINDING1%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Find("*", ctx->hkey_next, ctx->hkey_prev);
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Find() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX1_LOG("GETTING_KEY_NAME%s", "\r\n");
 | 
			
		||||
	ctx->len = CFSTORE_KEY_NAME_MAX_LENGTH;
 | 
			
		||||
	memset(ctx->value, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1);
 | 
			
		||||
	ret = cfstore_drv->GetKeyName(ctx->hkey_prev, ctx->value, (uint8_t*) &ctx->len);
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: GetKeyName() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG( ((int32_t) ctx->len == ((int32_t) strlen(cfstore_ex3_kv_name)+1)), "%s:Error: GetKeyName() updated value of len parameter (%ld) != strlen(cfstore_ex3_kv_name) (%ld) (\r\n", __func__, (int32_t) ctx->len, (int32_t) strlen(cfstore_ex3_kv_name));
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(strncmp(ctx->value, cfstore_ex3_kv_name, strlen(cfstore_ex3_kv_name)) == 0, "%s:Error: the key name (%s) is not as expected (%s)\r\n", __func__, ctx->value, cfstore_ex3_kv_name);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX1_LOG("GETTING_VALUE_LEN%s", "\r\n");
 | 
			
		||||
	ctx->len = CFSTORE_KEY_NAME_MAX_LENGTH;
 | 
			
		||||
	ret = cfstore_drv->GetValueLen(ctx->hkey_prev, &ctx->len);
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: GetValueLen() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG((int32_t) ctx->len == (int32_t) strlen(cfstore_ex3_kv_value), "%s:Error: GetValueLen() updated value of len parameter (%ld) != strlen(cfstore_ex3_kv_value)(%ld) \r\n", __func__, (int32_t) ctx->len, (int32_t) strlen(cfstore_ex3_kv_value));
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX1_LOG("DELETING%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Delete(ctx->hkey_prev);
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Close() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
	CFSTORE_HANDLE_SWAP(ctx->hkey_prev, ctx->hkey_next);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX1_LOG("FINDING2%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Find("*", ctx->hkey_next, ctx->hkey_prev);
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND, "%s:Error: Find() failed to return expected value of ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX1_LOG("FLUSHING2%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Flush();
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error:2: Flush() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX1_LOG("UNINITIALIZING%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Uninitialize();
 | 
			
		||||
	CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Uninitialize() should return ret >= 0 for synch mode(ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
	CFSTORE_EX1_LOG("***************%s", "\r\n");
 | 
			
		||||
	CFSTORE_EX1_LOG("*** SUCCESS ***%s", "\r\n");
 | 
			
		||||
	CFSTORE_EX1_LOG("***************%s", "\r\n");
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static control_t cfstore_example3_app_start(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    cfstore_example3_ctx_t* ctx = &cfstore_example3_ctx_g;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
 | 
			
		||||
    /* initialise the context */
 | 
			
		||||
    memset(ctx, 0, sizeof(cfstore_example3_ctx_t));
 | 
			
		||||
    ctx->hkey_next = ctx->hkey_next_buf;
 | 
			
		||||
    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){
 | 
			
		||||
    	/* 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");
 | 
			
		||||
        return CaseNext;
 | 
			
		||||
    }
 | 
			
		||||
    cfstore_ex3_test_01(ctx);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifndef CFSTORE_EXAMPLE3_APP
 | 
			
		||||
/* when built as Configuration-Store example, include greentea support otherwise omit */
 | 
			
		||||
 | 
			
		||||
/* report whether built/configured for flash sync or async mode */
 | 
			
		||||
static control_t cfstore_example3_test_00(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    ret = cfstore_test_startup();
 | 
			
		||||
    CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: failed to perform test startup (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(100, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
           /*          1         2         3         4         5         6        7  */
 | 
			
		||||
           /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        Case("EXAMPLE3_test_00", cfstore_example3_test_00),
 | 
			
		||||
        Case("EXAMPLE3_test_01_start", cfstore_example3_app_start),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#else   // CFSTORE_EXAMPLE3_APP
 | 
			
		||||
 | 
			
		||||
// stand alone Configuration-Store-Example
 | 
			
		||||
void app_start(int argc __unused, char** argv __unused)
 | 
			
		||||
{
 | 
			
		||||
    cfstore_example3_app_start(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif // CFSTORE_EXAMPLE3_APP
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,208 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 example4.cpp Test case to demonstrate a subset of the API functions each work correctly.
 | 
			
		||||
 *
 | 
			
		||||
 * Test case created from Issue 10 code supplied by Motti Gondabi. The code:
 | 
			
		||||
 * - creates a KV
 | 
			
		||||
 * - writes the KV
 | 
			
		||||
 * - closes the KV
 | 
			
		||||
 * - flushes the KV
 | 
			
		||||
 * - opens the KV.
 | 
			
		||||
 * - deletes the KV.
 | 
			
		||||
 * - flushes empty configuration store.
 | 
			
		||||
 *
 | 
			
		||||
 * The test case makes sure that the implementation can flush an empty configuration store
 | 
			
		||||
 * without causing errors. This has only been possible since flash-journal-strategy-sequential
 | 
			
		||||
 * v0.4.0.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#ifdef YOTTA_CFG_CONFIG_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CONFIG_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
static char cfstore_example4_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE];
 | 
			
		||||
 | 
			
		||||
/* defines */
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
#define PvMemSet memset
 | 
			
		||||
#define PvStrLen strlen
 | 
			
		||||
#define PvKeyValue_t cfstore_kv_data_t
 | 
			
		||||
 | 
			
		||||
ARM_CFSTORE_DRIVER *gCfStoreDriver = &cfstore_driver;
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
static control_t cfstore_example4_test_00(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_CAPABILITIES caps;;
 | 
			
		||||
 | 
			
		||||
    (void) 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){
 | 
			
		||||
    	/* 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");
 | 
			
		||||
        return CaseNext;
 | 
			
		||||
    }
 | 
			
		||||
    ret = cfstore_test_startup();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to perform test startup (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* used for sync mode build only */
 | 
			
		||||
#if defined STORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS && STORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS==0
 | 
			
		||||
 | 
			
		||||
static const PvKeyValue_t testDataKeyValue[] = {
 | 
			
		||||
    { "com.arm.mbed.spv.assets.dtls", "This Is my DTLS Secret" },
 | 
			
		||||
    { "com.arm.mbed.spv.assets.asset1.payload", "The Rolling Stone" },
 | 
			
		||||
    { "com.arm.mbed.spv.assets.asset2.payload", "Grumpy old man" },
 | 
			
		||||
    { "com.arm.mbed.spv.assets.asset3.payload", "Delete this asset payload" },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int32_t CreateKeyValueStore(
 | 
			
		||||
	const char *keyName,
 | 
			
		||||
	const char *data,
 | 
			
		||||
	ARM_CFSTORE_SIZE *dataLength,
 | 
			
		||||
	ARM_CFSTORE_KEYDESC *keyDesc)
 | 
			
		||||
{
 | 
			
		||||
	int32_t cfsStatus = ARM_DRIVER_ERROR;
 | 
			
		||||
	ARM_CFSTORE_SIZE valueLength = 0;
 | 
			
		||||
	ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
 | 
			
		||||
	valueLength = *dataLength;
 | 
			
		||||
	cfsStatus = gCfStoreDriver->Create(keyName, valueLength, keyDesc, hkey);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Create() failed (cfsStatus=%d)\n", __func__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
	valueLength = *dataLength;
 | 
			
		||||
	cfsStatus = gCfStoreDriver->Write(hkey, data, &valueLength);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Write() failed (cfsStatus=%d)\n", __func__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: valueLength != *dataLength\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(valueLength == *dataLength, cfstore_example4_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
	cfsStatus = gCfStoreDriver->Close(hkey);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Close() failed (cfsStatus=%d)\n", __func__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
	cfsStatus = gCfStoreDriver->Flush();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Flush() failed (cfsStatus=%d)\n", __func__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    return ARM_DRIVER_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static control_t cfstore_example4_test_01(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
	int32_t cfsStatus = ARM_DRIVER_ERROR;
 | 
			
		||||
	ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
	ARM_CFSTORE_SIZE valueLen;
 | 
			
		||||
	ARM_CFSTORE_FMODE flags;
 | 
			
		||||
	ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
 | 
			
		||||
	(void) call_count;
 | 
			
		||||
	PvMemSet(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
 | 
			
		||||
	kdesc.drl = ARM_RETENTION_NVM;
 | 
			
		||||
	valueLen = PvStrLen(testDataKeyValue[0].value);
 | 
			
		||||
 | 
			
		||||
	cfsStatus = gCfStoreDriver->Initialize(NULL, NULL);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Initialize() failed (cfsStatus=%d)\n", __func__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
	cfsStatus = CreateKeyValueStore(testDataKeyValue[0].key_name, testDataKeyValue[0].value, &valueLen, &kdesc);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: CreateKeyValueStore() failed (cfsStatus=%d)\n", __func__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
	PvMemSet(&flags, 0, sizeof(flags));
 | 
			
		||||
 | 
			
		||||
	cfsStatus = gCfStoreDriver->Open(testDataKeyValue[0].key_name, flags, hkey);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Open() failed (cfsStatus=%d)\n", __func__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
	cfsStatus = gCfStoreDriver->Delete(hkey);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Delete() failed (cfsStatus=%d)\n", __func__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
	cfsStatus = gCfStoreDriver->Close(hkey);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Close() failed (cfsStatus=%d)\n", __func__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
	cfsStatus = gCfStoreDriver->Flush();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Flush() failed (cfsStatus=%d)\n", __func__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
	cfsStatus = gCfStoreDriver->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() failed (cfsStatus=%d)\n", __func__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
	return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
#endif // STORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(400, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
           /*          1         2         3         4         5         6        7  */
 | 
			
		||||
           /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        Case("EXAMPLE4_test_00", cfstore_example4_test_00),
 | 
			
		||||
#if defined STORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS && STORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS==0
 | 
			
		||||
        Case("EXAMPLE4_test_01", cfstore_example4_test_01),
 | 
			
		||||
#endif // STORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
/// @endcond
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,330 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Test cases to add and delete KVs in the CFSTORE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @file example5.cpp
 | 
			
		||||
 *
 | 
			
		||||
 * Test case to demonstrate each API function works correctly.
 | 
			
		||||
 *
 | 
			
		||||
 * \par Example 5 Notes
 | 
			
		||||
 *
 | 
			
		||||
 * This flash-journal synchronous mode example test does the following CFSTORE operations:
 | 
			
		||||
 * - initialises
 | 
			
		||||
 * - creates a key-value pair (KV).
 | 
			
		||||
 * - writes the data for the KV
 | 
			
		||||
 * - closes KV.
 | 
			
		||||
 * - flushes the KV to flash
 | 
			
		||||
 * - flushes the KV to flash again
 | 
			
		||||
 * - uninitialises
 | 
			
		||||
 * - initialises
 | 
			
		||||
 * - opens KV for reading.
 | 
			
		||||
 * - deletes KV
 | 
			
		||||
 * - closes KV.
 | 
			
		||||
 * - flushes the updated state to flash to store the removal of the deleted KV.
 | 
			
		||||
 * - uninitialises
 | 
			
		||||
 * - stops
 | 
			
		||||
 *
 | 
			
		||||
 * This test is coded so as to work only in flash journal sync mode
 | 
			
		||||
 * i.e. with caps.asynchronous_ops == false
 | 
			
		||||
 *
 | 
			
		||||
 * The test leaves the flash in the same state as at the beginning of the test so
 | 
			
		||||
 * it can be run a second time on the device without flashing, and the test should
 | 
			
		||||
 * still work.
 | 
			
		||||
 *
 | 
			
		||||
 * \par How to Build Example5 as a Stand-alone Application
 | 
			
		||||
 *
 | 
			
		||||
 * This example can be build as a stand-alone application as follows:
 | 
			
		||||
 * - Create a new mbed application using the `mbed new .` command.
 | 
			
		||||
 * - Copy this file example5.cpp from the to the top level application directory and rename the file to main.cpp.
 | 
			
		||||
 * - Build the application with `mbed compile -v -m <target> -t <toolchain> -DCFSTORE_EXAMPLE5_APP` e.g. `mbed compile -v -m K64F -t GCC_ARM -DCFSTORE_EXAMPLE5_APP`.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
 | 
			
		||||
#ifndef CFSTORE_EXAMPLE5_APP
 | 
			
		||||
/* when built as Configuration-Store example, include greentea support otherwise omit */
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#else   // CFSTORE_EXAMPLE5_APP
 | 
			
		||||
/* map utest types for building as stand alone example */
 | 
			
		||||
#define control_t   void
 | 
			
		||||
#define CaseNext
 | 
			
		||||
#endif  // CFSTORE_EXAMPLE5_APP
 | 
			
		||||
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
 | 
			
		||||
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
#include "flash_journal_strategy_sequential.h"
 | 
			
		||||
#include "flash_journal.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef CFSTORE_EXAMPLE5_APP
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
#define CFSTORE_EX5_TEST_ASSERT(Expr)                       if (!(Expr)) { printf("%s:%u: assertion failure\r\n", __FUNCTION__, __LINE__); while (1) ;}
 | 
			
		||||
#define CFSTORE_EX5_TEST_ASSERT_EQUAL(expected, actual)     if ((expected) != (actual)) {printf("%s:%u: assertion failure\r\n", __FUNCTION__, __LINE__); while (1) ;}
 | 
			
		||||
#define CFSTORE_EX5_TEST_ASSERT_NOT_EQUAL(expected, actual) if ((expected) == (actual)) {printf("%s:%u: assertion failure\r\n", __FUNCTION__, __LINE__); while (1) ;}
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_EX5_TEST_ASSERT_MSG(Expr, _fmt, ...)      \
 | 
			
		||||
    do                                                    \
 | 
			
		||||
    {                                                     \
 | 
			
		||||
        if (!(Expr))                                      \
 | 
			
		||||
        {                                                 \
 | 
			
		||||
            printf(_fmt, __VA_ARGS__);                    \
 | 
			
		||||
            while (1) ;                                   \
 | 
			
		||||
        }                                                 \
 | 
			
		||||
    }while(0);
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_EX5_LOG(_fmt, ...)                        \
 | 
			
		||||
  do                                                      \
 | 
			
		||||
  {                                                       \
 | 
			
		||||
        printf(_fmt, __VA_ARGS__);                        \
 | 
			
		||||
  }while(0);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const char* cfstore_ex5_opcode_str[] =
 | 
			
		||||
{
 | 
			
		||||
    "UNDEFINED",
 | 
			
		||||
    "CFSTORE_OPCODE_CLOSE",
 | 
			
		||||
    "CFSTORE_OPCODE_CREATE",
 | 
			
		||||
    "CFSTORE_OPCODE_DELETE",
 | 
			
		||||
    "CFSTORE_OPCODE_FIND",
 | 
			
		||||
    "CFSTORE_OPCODE_FLUSH",
 | 
			
		||||
    "CFSTORE_OPCODE_GET_KEY_NAME",
 | 
			
		||||
    "CFSTORE_OPCODE_GET_STATUS",
 | 
			
		||||
    "CFSTORE_OPCODE_GET_VALUE_LEN",
 | 
			
		||||
    "CFSTORE_OPCODE_INITIALIZE",
 | 
			
		||||
    "CFSTORE_OPCODE_OPEN",
 | 
			
		||||
    "CFSTORE_OPCODE_POWER_CONTROL",
 | 
			
		||||
    "CFSTORE_OPCODE_READ",
 | 
			
		||||
    "CFSTORE_OPCODE_RSEEK",
 | 
			
		||||
    "CFSTORE_OPCODE_UNINITIALIZE",
 | 
			
		||||
    "CFSTORE_OPCODE_WRITE",
 | 
			
		||||
    "CFSTORE_OPCODE_MAX"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const char* cfstore_ex5_kv_name = "basement.medicine.pavement.government.trenchcoat.off.cough.off.kid.did.when.again.alleyway.friend.cap.pen.dollarbills.ten.foot.soot.put.but.anyway.say.May.DA.kid.did.toes.bows.those.hose.nose.clothes.man.blows.well.well";
 | 
			
		||||
const char* cfstore_ex5_kv_value = "TheRollingStone";
 | 
			
		||||
#define CFSTORE_EX5_RSEEK_OFFSET    10   /* offset to S of Stone */
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
typedef struct cfstore_EXAMPLE5_ctx_t
 | 
			
		||||
{
 | 
			
		||||
    ARM_CFSTORE_CAPABILITIES caps;
 | 
			
		||||
    uint8_t hkey[CFSTORE_HANDLE_BUFSIZE];
 | 
			
		||||
    uint8_t hkey_next_buf[CFSTORE_HANDLE_BUFSIZE];
 | 
			
		||||
    uint8_t hkey_prev_buf[CFSTORE_HANDLE_BUFSIZE];
 | 
			
		||||
    ARM_CFSTORE_HANDLE hkey_next;
 | 
			
		||||
    ARM_CFSTORE_HANDLE hkey_prev;
 | 
			
		||||
    ARM_CFSTORE_SIZE len;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
    char value[CFSTORE_KEY_NAME_MAX_LENGTH+1];
 | 
			
		||||
} cfstore_EXAMPLE5_ctx_t;
 | 
			
		||||
 | 
			
		||||
static cfstore_EXAMPLE5_ctx_t cfstore_EXAMPLE5_ctx_g;
 | 
			
		||||
 | 
			
		||||
extern ARM_CFSTORE_DRIVER cfstore_driver;
 | 
			
		||||
ARM_CFSTORE_DRIVER *cfstore_drv = &cfstore_driver;
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   test startup code to reset flash
 | 
			
		||||
 */
 | 
			
		||||
int32_t cfstore_test_startup(void)
 | 
			
		||||
{
 | 
			
		||||
    ARM_CFSTORE_CAPABILITIES caps = cfstore_driver.GetCapabilities();
 | 
			
		||||
    CFSTORE_EX5_LOG("INITIALIZING: caps.asynchronous_ops=%d\n", (int) caps.asynchronous_ops);
 | 
			
		||||
 | 
			
		||||
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    FlashJournal_t jrnl;
 | 
			
		||||
    extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0);
 | 
			
		||||
    const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_(0);
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
    ret = FlashJournal_reset(&jrnl);
 | 
			
		||||
    CFSTORE_EX5_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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void cfstore_ex5_test_01(cfstore_EXAMPLE5_ctx_t* ctx)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret;
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX5_LOG("INITIALIZING1%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Initialize(NULL, NULL);
 | 
			
		||||
	CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Initialize() should return ret >= 0 for async/synch modes(ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX5_LOG("CREATING%s", "\r\n");
 | 
			
		||||
	memset(&ctx->kdesc, 0, sizeof(ARM_CFSTORE_KEYDESC));
 | 
			
		||||
	ctx->kdesc.drl = ARM_RETENTION_NVM;
 | 
			
		||||
	ctx->len = strlen(cfstore_ex5_kv_value);
 | 
			
		||||
	ret = cfstore_drv->Create(cfstore_ex5_kv_name, ctx->len, &ctx->kdesc, ctx->hkey);
 | 
			
		||||
	CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Create() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX5_LOG("WRITING%s", "\r\n");
 | 
			
		||||
	ctx->len = strlen(cfstore_ex5_kv_value);
 | 
			
		||||
	ret = cfstore_drv->Write(ctx->hkey, cfstore_ex5_kv_value, &ctx->len);
 | 
			
		||||
	CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Write() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX5_TEST_ASSERT_MSG(ret == (int32_t) strlen(cfstore_ex5_kv_value), "%s:Error: Write() number of octets written (i.e. completion status (%ld)) != strlen(ctx->value)(%ld)\r\n", __func__, ret, (int32_t) strlen(cfstore_ex5_kv_value));
 | 
			
		||||
	CFSTORE_EX5_TEST_ASSERT_MSG(ret == (int32_t) ctx->len, "%s:Error: Write() number of octets written (i.e. completion status (%ld)) != updated value of len parameter (%ld)\r\n", __func__, ret, (int32_t) ctx->len);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX5_LOG("CLOSING1%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Close(ctx->hkey);
 | 
			
		||||
	CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Close() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX5_LOG("FLUSHING1%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Flush();
 | 
			
		||||
	CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Flush() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
	/* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED => flash storage support present.
 | 
			
		||||
	 * if this was not the case (i.e. cfstore running SRAM in memory mode) then
 | 
			
		||||
	 * we dont compile in the  Uninitialize()/Initialize() as the
 | 
			
		||||
	 * Uninitialize() clears the sram */
 | 
			
		||||
	CFSTORE_EX5_LOG("UNINITIALIZING1%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Uninitialize();
 | 
			
		||||
	CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Uninitialize() should return ret >= 0 for synch mode(ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX5_LOG("INITIALIZING2%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Initialize(NULL, NULL);
 | 
			
		||||
	CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Initialize() should return ret >= 0 for async/synch modes(ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX5_LOG("OPENING%s", "\r\n");
 | 
			
		||||
	memset(&ctx->flags, 0, sizeof(ctx->flags));
 | 
			
		||||
	memset(&ctx->hkey, 0, CFSTORE_HANDLE_BUFSIZE);
 | 
			
		||||
	ret = cfstore_drv->Open(cfstore_ex5_kv_name, ctx->flags, ctx->hkey);
 | 
			
		||||
	CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Open() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX5_LOG("DELETE1%s", "\r\n");
 | 
			
		||||
	ctx->len = CFSTORE_KEY_NAME_MAX_LENGTH;
 | 
			
		||||
	memset(ctx->value, 0, CFSTORE_KEY_NAME_MAX_LENGTH + 1);
 | 
			
		||||
	ret = cfstore_drv->Delete(ctx->hkey);
 | 
			
		||||
	CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Delete() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX5_LOG("CLOSING2%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Close(ctx->hkey);
 | 
			
		||||
	CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Close() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX5_LOG("FLUSHING3%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Flush();
 | 
			
		||||
	CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Flush() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX5_LOG("OPEN2 %s", "\r\n");
 | 
			
		||||
	memset(&ctx->flags, 0, sizeof(ctx->flags));
 | 
			
		||||
	memset(&ctx->hkey, 0, CFSTORE_HANDLE_BUFSIZE);
 | 
			
		||||
	ret = cfstore_drv->Open(cfstore_ex5_kv_name, ctx->flags, ctx->hkey);
 | 
			
		||||
	CFSTORE_EX5_TEST_ASSERT_MSG(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND, "%s:Error: Find() failed to return expected value of ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX5_LOG("FLUSHING2%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Flush();
 | 
			
		||||
	CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error:2: Flush() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_EX5_LOG("UNINITIALIZING3%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Uninitialize();
 | 
			
		||||
	CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Uninitialize() should return ret >= 0 for synch mode(ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
	CFSTORE_EX5_LOG("***************%s", "\r\n");
 | 
			
		||||
	CFSTORE_EX5_LOG("*** SUCCESS ***%s", "\r\n");
 | 
			
		||||
	CFSTORE_EX5_LOG("***************%s", "\r\n");
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static control_t cfstore_EXAMPLE5_app_start(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    cfstore_EXAMPLE5_ctx_t* ctx = &cfstore_EXAMPLE5_ctx_g;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
 | 
			
		||||
    /* initialise the context */
 | 
			
		||||
    memset(ctx, 0, sizeof(cfstore_EXAMPLE5_ctx_t));
 | 
			
		||||
    ctx->hkey_next = ctx->hkey_next_buf;
 | 
			
		||||
    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){
 | 
			
		||||
    	/* 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");
 | 
			
		||||
        return CaseNext;
 | 
			
		||||
    }
 | 
			
		||||
    ret = cfstore_test_startup();
 | 
			
		||||
    CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: failed to perform test startup (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    cfstore_ex5_test_01(ctx);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifndef CFSTORE_EXAMPLE5_APP
 | 
			
		||||
/* when built as Configuration-Store example, include greentea support otherwise omit */
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(100, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
           /*          1         2         3         4         5         6        7  */
 | 
			
		||||
           /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        Case("EXAMPLE5_test_01_start", cfstore_EXAMPLE5_app_start),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#else   // CFSTORE_EXAMPLE5_APP
 | 
			
		||||
 | 
			
		||||
// stand alone Configuration-Store-Example
 | 
			
		||||
void app_start(int argc __unused, char** argv __unused)
 | 
			
		||||
{
 | 
			
		||||
    cfstore_EXAMPLE5_app_start(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif // CFSTORE_EXAMPLE5_APP
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,472 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 find.cpp Test cases to find KVs in the CFSTORE using the drv->Find() interface.
 | 
			
		||||
 *
 | 
			
		||||
 * Please consult the documentation under the test-case functions for
 | 
			
		||||
 * a description of the individual test case.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#include "cfstore_utest.h"
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
static char cfstore_find_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE];
 | 
			
		||||
 | 
			
		||||
/* Configure secure box. */
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
UVISOR_BOX_NAMESPACE("com.arm.mbed.cfstore.test.find.box1");
 | 
			
		||||
UVISOR_BOX_CONFIG(cfstore_find_box1, UVISOR_BOX_STACK_SIZE);
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* report whether built/configured for flash sync or async mode */
 | 
			
		||||
static control_t cfstore_find_test_00(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    ret = cfstore_test_startup();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to perform test startup (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_find_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @brief  test to call cfstore_find() with a key_name string that exceeds
 | 
			
		||||
 *          the maximum length
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_find_test_01(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    /*todo: implement test */
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Warn: Not implemented\n", __func__);
 | 
			
		||||
    CFSTORE_DBGLOG("%s: WARN: requires implementation\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(true, cfstore_find_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @brief	test to call cfstore_find() with key_name that in includes
 | 
			
		||||
 *         	illegal characters
 | 
			
		||||
 *          - the character can be at the beginning of the key_name
 | 
			
		||||
 *          - the character can be at the end of the key_name
 | 
			
		||||
 *          - the character can be somewhere within the key_name string
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_find_test_02(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    /*todo: implement test
 | 
			
		||||
     *
 | 
			
		||||
     * specify the allowable characters in a set.
 | 
			
		||||
     * e.g. "0123456789ABCDEFGHIJKLMNOPQRSTUVQXYZabcdefghijklmnopqrstuvwxyz.[]*"
 | 
			
		||||
     * and use this set as the sell of allowable character codes.
 | 
			
		||||
     * All other 0-255 values for character codes should not be found in the key_name string
 | 
			
		||||
     * but the function should be tested for what happens in that case.
 | 
			
		||||
     *
 | 
			
		||||
     * Some code may be common here with other functions requiring a key_name e.g. cfstore_find(
 | 
			
		||||
     */
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    /*todo: implement test */
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Warn: Not implemented\n", __func__);
 | 
			
		||||
    CFSTORE_DBGLOG("%s: WARN: requires implementation\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(true, cfstore_find_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @brief  test to call cfstore_find() with key_name that in includes
 | 
			
		||||
 *          illegal characters
 | 
			
		||||
 *          - the character can be at the beginning of the key_name
 | 
			
		||||
 *          - the character can be at the end of the key_name
 | 
			
		||||
 *          - the character can be somewhere within the key_name string
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_find_test_03_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    char* read_buf = NULL;
 | 
			
		||||
    const uint8_t key_name_max_len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
 | 
			
		||||
    char key_name_buf[key_name_max_len];
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_SIZE len = 0;
 | 
			
		||||
    ARM_CFSTORE_SIZE max_len = 0;
 | 
			
		||||
    cfstore_kv_data_t* node;
 | 
			
		||||
    cfstore_kv_data_t* client_node = cfstore_test_init_1_data;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(prev);
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(next);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s:entered\r\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
    memset(key_name_buf, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1);
 | 
			
		||||
 | 
			
		||||
    /*scan for max length of value blob*/
 | 
			
		||||
    node = client_node;
 | 
			
		||||
    while(node->key_name != NULL)
 | 
			
		||||
    {
 | 
			
		||||
        len = strlen(node->value);
 | 
			
		||||
        if(len > max_len){
 | 
			
		||||
            max_len = len;
 | 
			
		||||
        }
 | 
			
		||||
        node++;
 | 
			
		||||
    }
 | 
			
		||||
    max_len++;  /* space for a terminating null, if required */
 | 
			
		||||
    read_buf = (char*) malloc(max_len);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Failed to allocated read buffer \r\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(read_buf != NULL, cfstore_find_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    ret = cfstore_test_init_1();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to initialise cfstore area with entries\r\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_find_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* now find and read back the key values  */
 | 
			
		||||
    ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    node = client_node;
 | 
			
		||||
    while(node->key_name != NULL)
 | 
			
		||||
    {
 | 
			
		||||
        CFSTORE_DBGLOG("%s:About to find node (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value);
 | 
			
		||||
        ret = drv->Find(node->key_name, prev, next);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Failed to find node (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_find_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Find failed to return valid key handle\r\n", __func__);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(next != NULL, cfstore_find_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
        ret = drv->GetValueLen(next, &len);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write key (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_find_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
        if(len > 0) {
 | 
			
		||||
            ret = drv->Read(next, read_buf, &len);
 | 
			
		||||
            CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to read value (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value);
 | 
			
		||||
            TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_find_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
            /* check read data is as expected */
 | 
			
		||||
            CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Read value data (%s) != KV value data (key_name=\"%s\", value=\"%s\")\r\n", __func__, read_buf, node->key_name, node->value);
 | 
			
		||||
            TEST_ASSERT_MESSAGE(strncmp(read_buf, node->value, strlen(node->value)) == 0, cfstore_find_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        read_buf[len] = '\0';
 | 
			
		||||
        /* revert to CFSTORE_LOG if more trace required */
 | 
			
		||||
        CFSTORE_DBGLOG("Successfully found KV and read value data (key_name=\"%s\", value=\"%s\")\r\n", node->key_name, read_buf);
 | 
			
		||||
        memset(read_buf, 0, len);
 | 
			
		||||
        drv->Close(next);
 | 
			
		||||
        node++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_find_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @brief  TODO: write test that uses cfstore_find_test_04_kv_data to grow {key, value}
 | 
			
		||||
 *          from 1 char to 221 chars long.
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
/*
 | 
			
		||||
 * use this data:
 | 
			
		||||
 *  static cfstore_kv_data_t cfstore_find_test_04_kv_data[] = {
 | 
			
		||||
 *        { "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", "abcdefghjklmnopqrstuvwxyzabcdefghjklmnopqrstuvwxyzabcdefghjklmnopqrstuvwxyzabcdefghjklmnopqrstuvwxyzabcdefghjklmnopqrstuvwxyzabcdefghjklmnopqrstuvwxyzabcdefghjklmnopqrstuvwxyzabcdefghjklmnopqrstuvwxyzabcdefghjklmnopqrstuvwxyz"},
 | 
			
		||||
 *        { NULL, NULL},
 | 
			
		||||
 * };
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_find_test_04(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    /*todo: implement test
 | 
			
		||||
     *
 | 
			
		||||
     * */
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    /*todo: implement test */
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Warn: Not implemented\n", __func__);
 | 
			
		||||
    CFSTORE_DBGLOG("%s: WARN: requires implementation\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(true, cfstore_find_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   function to test whether a key name is valid, can be added to the
 | 
			
		||||
 * 			cfstore and found by a wildcard string
 | 
			
		||||
 *
 | 
			
		||||
 * @param	key_name
 | 
			
		||||
 * 			name of the key to create in the store
 | 
			
		||||
 * @param	match
 | 
			
		||||
 * 			string to use to try and find key_name in the cfstore
 | 
			
		||||
 * @param	should_find
 | 
			
		||||
 * 			if true, then 'match' should find 'key_name' in the store
 | 
			
		||||
 * 			if false, then 'match' should not find 'key_name' in the store
 | 
			
		||||
 *
 | 
			
		||||
 * @return  status code
 | 
			
		||||
 *          ARM_DRIVER_OK, the test passed successfully
 | 
			
		||||
 *          ret < ARM_DRIVER_OK, the test failed with the return code
 | 
			
		||||
 *          supplying more details
 | 
			
		||||
 */
 | 
			
		||||
static bool cfstore_find_key_name_validate(const char *key_name, const char *match, bool should_find)
 | 
			
		||||
{
 | 
			
		||||
    bool bret = true;
 | 
			
		||||
    bool btest_status = false;
 | 
			
		||||
    char* test_data = (char*) "test_data";
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_SIZE len = 0;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\r\n", __func__);
 | 
			
		||||
    memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
 | 
			
		||||
    /* create  */
 | 
			
		||||
    kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE;
 | 
			
		||||
    len = strlen(test_data);
 | 
			
		||||
    ret = cfstore_test_create((const char*) key_name, test_data, &len, &kdesc);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: failed to create kv (key_name=%s.\r\n", "cfstore_find_test_05_ex", key_name);
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    ret = cfstore_test_kv_is_found(match, &bret);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK && ret != ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: cfstore_test_kv_is_found() failed.\r\n", "cfstore_find_test_05_ex");
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    /* dont not use any functions that require finding the created item as they may not work,
 | 
			
		||||
     * depending on the construction of the test key_name & match strings */
 | 
			
		||||
    if(should_find == bret)
 | 
			
		||||
    {
 | 
			
		||||
        CFSTORE_DBGLOG("%s:Success: Find() behaved as expected.\r\n", "cfstore_find_test_05_ex");
 | 
			
		||||
        btest_status = true;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        CFSTORE_ERRLOG("cfstore_find_test_05_ex: Failed match on %s vs. %s\n",  key_name, match);
 | 
			
		||||
    }
 | 
			
		||||
    /*delete using the actual name */
 | 
			
		||||
    ret = cfstore_test_delete((const char*) key_name);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: failed to delete kv (key_name=%s)(ret=%d).\r\n", "cfstore_find_test_05_ex", key_name, (int)ret);
 | 
			
		||||
    }
 | 
			
		||||
    return btest_status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
typedef struct cfstore_find_key_name_validate_t {
 | 
			
		||||
    const char* key_name;
 | 
			
		||||
    const char* match;
 | 
			
		||||
    uint32_t f_allowed : 1;
 | 
			
		||||
} cfstore_find_key_name_validate_t;
 | 
			
		||||
 | 
			
		||||
cfstore_find_key_name_validate_t cfstore_find_test_05_data[] = {
 | 
			
		||||
        { "yotta.hello-world.animal{wobbly-dog}{foot}backLeft", "yotta.hello-world.animal{*}{foot}backLeft", true},
 | 
			
		||||
        { "yotta.hello-world.animal{wobbly-dog}{foot}backLeft", "yotta.hello-world.animal{wobbly-dog}{*}backLeft", true},
 | 
			
		||||
        { "yotta.hello-world.animal{wobbly-dog}{foot}backLeft", "yotta.hello-world.animal{wobbly-dog}{*}*", true},
 | 
			
		||||
        { "yotta.hello-world.animal{1}{foot}backLeft", "yotta.hello-world.animal{?}{foot}backLeft", false},
 | 
			
		||||
        { "xyz", "xyz", true},
 | 
			
		||||
        { "xyzijkXYZ", "XYZ", false},
 | 
			
		||||
        { "xyzijkXYZ", "*XYZ", true},
 | 
			
		||||
        { "xyzijkXYZ", "xyz*XYZ", true},
 | 
			
		||||
        { "xyzijkXYZ", "*yz*XYZ", true},
 | 
			
		||||
        { "xyzijkXYZ", "*ijk*", true},
 | 
			
		||||
        { NULL, NULL, false},
 | 
			
		||||
};
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @brief  test whether a key name in the above table are valid, can be added to the
 | 
			
		||||
 *          cfstore and found by a wildcard string
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_find_test_05_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    bool ret = false;
 | 
			
		||||
    int32_t ret32 = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    cfstore_find_key_name_validate_t* node = cfstore_find_test_05_data;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
 | 
			
		||||
    while(node->key_name != NULL)
 | 
			
		||||
    {
 | 
			
		||||
        ret = cfstore_find_key_name_validate(node->key_name, node->match, node->f_allowed);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: test failed (ret=%d)\n", __func__, (int) ret);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret == true, cfstore_find_utest_msg_g);
 | 
			
		||||
        node++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret32 = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret32 >= ARM_DRIVER_OK, cfstore_find_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
#define CFSTORE_FIND_TEST_06_ENTRY_MATCH_03      { "0123456789abcdef0123456.yxxx.3", "abcdefghijklmnopqrstuvwxyz"}
 | 
			
		||||
#define CFSTORE_FIND_TEST_06_ENTRY_MATCH_05      { "0123456789abcdef0123456.yxxx.5", "abcdefghijklmnopqrstuvwxyz"}
 | 
			
		||||
#define CFSTORE_FIND_TEST_06_ENTRY_MATCH_07      { "0123456789abcdef0123456.yxxx.7", "abcdefghijklmnopqrstuvwxyz"}
 | 
			
		||||
#define CFSTORE_FIND_TEST_06_ENTRY_MATCH_09      { "0123456789abcdef0123456.yxxx.9", "abcdefghijklmnopqrstuvwxyz"}
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_FIND_TEST_06_ENTRY_NOMATCH_01      { "0123456789abcdef0123456.xxxx.1", "abcdefghijklmnopqrstuvwxyz"}
 | 
			
		||||
#define CFSTORE_FIND_TEST_06_ENTRY_NOMATCH_02      { "0123456789abcdef0123456.xxxx.2", "abcdefghijklmnopqrstuvwxyz"}
 | 
			
		||||
#define CFSTORE_FIND_TEST_06_ENTRY_NOMATCH_04      { "0123456789abcdef0123456.xxxx.4", "abcdefghijklmnopqrstuvwxyz"}
 | 
			
		||||
#define CFSTORE_FIND_TEST_06_ENTRY_NOMATCH_06      { "0123456789abcdef0123456.xxxx.6", "abcdefghijklmnopqrstuvwxyz"}
 | 
			
		||||
#define CFSTORE_FIND_TEST_06_ENTRY_NOMATCH_08      { "0123456789abcdef0123456.xxxx.8", "abcdefghijklmnopqrstuvwxyz"}
 | 
			
		||||
#define CFSTORE_FIND_TEST_06_ENTRY_NOMATCH_10      { "0123456789abcdef0123456.xxxx.10", "abcdefghijklmnopqrstuvwxyz"}
 | 
			
		||||
#define CFSTORE_FIND_TEST_06_ENTRY_NOMATCH_11      { "0123456789abcdef0123456.xxxx.11", "abcdefghijklmnopqrstuvwxyz"}
 | 
			
		||||
 | 
			
		||||
/* table 1: to initialise cfstore with CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_01 */
 | 
			
		||||
static cfstore_kv_data_t cfstore_find_test_06_data[] = {
 | 
			
		||||
        CFSTORE_FIND_TEST_06_ENTRY_NOMATCH_01,
 | 
			
		||||
        CFSTORE_FIND_TEST_06_ENTRY_NOMATCH_02,
 | 
			
		||||
        CFSTORE_FIND_TEST_06_ENTRY_MATCH_03,
 | 
			
		||||
        CFSTORE_FIND_TEST_06_ENTRY_NOMATCH_04,
 | 
			
		||||
        CFSTORE_FIND_TEST_06_ENTRY_MATCH_05,
 | 
			
		||||
        CFSTORE_FIND_TEST_06_ENTRY_NOMATCH_06,
 | 
			
		||||
        CFSTORE_FIND_TEST_06_ENTRY_MATCH_07,
 | 
			
		||||
        CFSTORE_FIND_TEST_06_ENTRY_NOMATCH_08,
 | 
			
		||||
        CFSTORE_FIND_TEST_06_ENTRY_MATCH_09,
 | 
			
		||||
        CFSTORE_FIND_TEST_06_ENTRY_NOMATCH_10,
 | 
			
		||||
        CFSTORE_FIND_TEST_06_ENTRY_NOMATCH_11,
 | 
			
		||||
        { NULL, NULL},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static cfstore_kv_data_t cfstore_find_test_06_data_match_results[] = {
 | 
			
		||||
        CFSTORE_FIND_TEST_06_ENTRY_MATCH_03,
 | 
			
		||||
        CFSTORE_FIND_TEST_06_ENTRY_MATCH_05,
 | 
			
		||||
        CFSTORE_FIND_TEST_06_ENTRY_MATCH_07,
 | 
			
		||||
        CFSTORE_FIND_TEST_06_ENTRY_MATCH_09,
 | 
			
		||||
        { NULL, NULL},
 | 
			
		||||
};
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   test to use find to find at least 2 entries in the cfstore,
 | 
			
		||||
 *          but the query string doesnt match the last 2 entries in the
 | 
			
		||||
 *          store.
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_find_test_06_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    const char* key_name_query = "0123456789abcdef0123456.y*";
 | 
			
		||||
    char key_name[CFSTORE_KEY_NAME_MAX_LENGTH+1];
 | 
			
		||||
    uint8_t len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    int32_t find_count = 0;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(next);
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(prev);
 | 
			
		||||
    cfstore_kv_data_t* node = NULL;
 | 
			
		||||
 | 
			
		||||
    ret = cfstore_test_create_table(cfstore_find_test_06_data);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Failed to add cfstore_find_test_06_data table data (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_find_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    while((ret = drv->Find(key_name_query, prev, next)) == ARM_DRIVER_OK)
 | 
			
		||||
    {
 | 
			
		||||
        len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
 | 
			
		||||
        ret = drv->GetKeyName(next, key_name, &len);
 | 
			
		||||
        if(ret < ARM_DRIVER_OK){
 | 
			
		||||
            CFSTORE_ERRLOG("Error: failed to get key name%s", "\n");
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        CFSTORE_LOG("%s:Found entry key_name=%s\n", __func__, key_name);
 | 
			
		||||
        node = cfstore_find_test_06_data_match_results;
 | 
			
		||||
        while(node->key_name != NULL){
 | 
			
		||||
            if(strncmp(node->key_name, key_name, CFSTORE_KEY_NAME_MAX_LENGTH) == 0){
 | 
			
		||||
                find_count++;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            node++;
 | 
			
		||||
        }
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to find match in match table for %s.\n", __func__, key_name);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(node->key_name != NULL, cfstore_find_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
        CFSTORE_HANDLE_SWAP(prev, next);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: find_count=%d doesnt match the number of entries in match table = %d.\n", __func__, (int) find_count, (int) (sizeof(cfstore_find_test_06_data_match_results)/sizeof(cfstore_kv_data_t))-1);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(find_count == (sizeof(cfstore_find_test_06_data_match_results)/sizeof(cfstore_kv_data_t))-1, cfstore_find_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: expected ret == ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND, but ret = %d.\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND, cfstore_find_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_find_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(400, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
           /*          1         2         3         4         5         6        7  */
 | 
			
		||||
           /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        Case("FIND_test_00", cfstore_find_test_00),
 | 
			
		||||
        Case("FIND_test_01", cfstore_find_test_01),
 | 
			
		||||
        Case("FIND_test_02", cfstore_find_test_02),
 | 
			
		||||
        Case("FIND_test_03_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("FIND_test_03_end", cfstore_find_test_03_end),
 | 
			
		||||
        Case("FIND_test_04", cfstore_find_test_04),
 | 
			
		||||
        Case("FIND_test_05_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("FIND_test_05_end", cfstore_find_test_05_end),
 | 
			
		||||
        Case("FIND_test_06_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("FIND_test_06_end", cfstore_find_test_06_end),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,245 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 find2.cpp Test cases to find KVs in the CFSTORE using the drv->Find() interface.
 | 
			
		||||
 *
 | 
			
		||||
 * Please consult the documentation under the test-case functions for
 | 
			
		||||
 * a description of the individual test case.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
static char cfstore_find2_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE];
 | 
			
		||||
 | 
			
		||||
/* Configure secure box. */
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
UVISOR_BOX_NAMESPACE("com.arm.mbed.cfstore.test.find2.box1");
 | 
			
		||||
UVISOR_BOX_CONFIG(cfstore_find2_box1, UVISOR_BOX_STACK_SIZE);
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
#ifdef CFSTORE_DEBUG
 | 
			
		||||
#define CFSTORE_FIND2_GREENTEA_TIMEOUT_S     360
 | 
			
		||||
#else
 | 
			
		||||
#define CFSTORE_FIND2_GREENTEA_TIMEOUT_S     60
 | 
			
		||||
#endif
 | 
			
		||||
#define CFSTORE_FIND2_TEST_02_VALUE_SIZE 191
 | 
			
		||||
 | 
			
		||||
extern ARM_CFSTORE_DRIVER cfstore_driver;
 | 
			
		||||
 | 
			
		||||
void cfstore_find2_callback(int32_t status, ARM_CFSTORE_OPCODE cmd_code, void *client_context, ARM_CFSTORE_HANDLE handle)
 | 
			
		||||
{
 | 
			
		||||
    (void) status;
 | 
			
		||||
    (void) cmd_code;
 | 
			
		||||
    (void) client_context;
 | 
			
		||||
    (void) handle;
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
/* report whether built/configured for flash sync or async mode */
 | 
			
		||||
static control_t cfstore_find2_test_00(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    ret = cfstore_test_startup();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_find2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to perform test startup (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_find2_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static control_t cfstore_find2_test_01(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
	char keyBuffer[128] = "com.arm.mbed.manifest-manager.root.AQAAAAAAAAA-.manifest";
 | 
			
		||||
	int32_t rc;
 | 
			
		||||
	ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
	ARM_CFSTORE_HANDLE_INIT(prev);
 | 
			
		||||
 | 
			
		||||
	// Initialize the config store
 | 
			
		||||
	(void) call_count;
 | 
			
		||||
	cfstore_driver.Initialize(cfstore_find2_callback, NULL);
 | 
			
		||||
	cfstore_driver.PowerControl(ARM_POWER_FULL);
 | 
			
		||||
 | 
			
		||||
	// Find the target key
 | 
			
		||||
	rc = cfstore_driver.Find(keyBuffer, prev, hkey);
 | 
			
		||||
 | 
			
		||||
	// If the target key was not found
 | 
			
		||||
	if (rc == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND) {
 | 
			
		||||
		ARM_CFSTORE_KEYDESC kdesc = {
 | 
			
		||||
			.acl = {
 | 
			
		||||
				.perm_owner_read = 1,
 | 
			
		||||
				.perm_owner_write = 1,
 | 
			
		||||
				.perm_owner_execute = 0,
 | 
			
		||||
				.perm_other_read = 1,
 | 
			
		||||
				.perm_other_write = 0,
 | 
			
		||||
				.perm_other_execute = 0,
 | 
			
		||||
				/* added initialisers */
 | 
			
		||||
                .reserved = 0
 | 
			
		||||
			}, .drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE,
 | 
			
		||||
			.security = {
 | 
			
		||||
				.acls = 1,
 | 
			
		||||
				.rollback_protection = 0,
 | 
			
		||||
				.tamper_proof = 0,
 | 
			
		||||
				.internal_flash = 0,
 | 
			
		||||
				/* added initialisers */
 | 
			
		||||
                .reserved1 = 0,
 | 
			
		||||
                .software_attacks = 0,
 | 
			
		||||
                .board_level_attacks = 0,
 | 
			
		||||
                .chip_level_attacks = 0,
 | 
			
		||||
                .side_channel_attacks = 0,
 | 
			
		||||
                .reserved2 = 0
 | 
			
		||||
			},
 | 
			
		||||
			.flags = {
 | 
			
		||||
				.continuous = 0,
 | 
			
		||||
				.lazy_flush = 1,
 | 
			
		||||
				.flush_on_close = 1,
 | 
			
		||||
				.read = 0,
 | 
			
		||||
				.write = 1,
 | 
			
		||||
				.execute = 0,
 | 
			
		||||
				.storage_detect = 1,
 | 
			
		||||
                /* added initialisers */
 | 
			
		||||
                .reserved = 0
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		// Create the target key
 | 
			
		||||
		rc = cfstore_driver.Create(keyBuffer, 191, &kdesc, hkey);
 | 
			
		||||
	}
 | 
			
		||||
	return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* fixed version of brendans code */
 | 
			
		||||
static control_t cfstore_find2_test_02(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
	char keyBuffer[128] = "com.arm.mbed.manifest-manager.root.AQAAAAAAAAA-.manifest";
 | 
			
		||||
 | 
			
		||||
	int32_t rc;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(prev);
 | 
			
		||||
    ARM_CFSTORE_SIZE length;
 | 
			
		||||
    char value[CFSTORE_FIND2_TEST_02_VALUE_SIZE];
 | 
			
		||||
 | 
			
		||||
    // Initialize the config store
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    cfstore_driver.Initialize(NULL, NULL); /* non-null client_callback not supported for MBED_V_0_1_x */
 | 
			
		||||
    cfstore_driver.PowerControl(ARM_POWER_FULL);
 | 
			
		||||
    memset(value, 0, 191);
 | 
			
		||||
 | 
			
		||||
    // Find the target key
 | 
			
		||||
    rc = cfstore_driver.Find(keyBuffer, prev, hkey);
 | 
			
		||||
 | 
			
		||||
    // If the target key was not found
 | 
			
		||||
    if (rc == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND) {
 | 
			
		||||
        ARM_CFSTORE_KEYDESC kdesc = {
 | 
			
		||||
            .acl = {
 | 
			
		||||
                .perm_owner_read = 1,
 | 
			
		||||
                .perm_owner_write = 1,
 | 
			
		||||
                .perm_owner_execute = 0,
 | 
			
		||||
                .perm_other_read = 1,
 | 
			
		||||
                .perm_other_write = 0,
 | 
			
		||||
                .perm_other_execute = 0,
 | 
			
		||||
                .reserved = 0
 | 
			
		||||
            }, .drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE,	/* DATA_RETENTION_NVM not supported for MBED_V_0_1_x */
 | 
			
		||||
            .security = {
 | 
			
		||||
                .acls = 0, /* protection against internal software attacks using ACLs not supported for MBED_V_0_1_x */
 | 
			
		||||
                .rollback_protection = 0,
 | 
			
		||||
                .tamper_proof = 0,
 | 
			
		||||
                .internal_flash = 0,
 | 
			
		||||
                .reserved1 = 0,
 | 
			
		||||
                .software_attacks = 0,
 | 
			
		||||
                .board_level_attacks = 0,
 | 
			
		||||
                .chip_level_attacks = 0,
 | 
			
		||||
                .side_channel_attacks = 0,
 | 
			
		||||
                .reserved2 = 0
 | 
			
		||||
            },
 | 
			
		||||
            .flags = {
 | 
			
		||||
                .continuous = 0,
 | 
			
		||||
                .lazy_flush = 0, 		/* lazy flush not supported for MBED_V_0_1_x */
 | 
			
		||||
                .flush_on_close = 0,	/* flush on close not supported for MBED_V_0_1_x */
 | 
			
		||||
                .read = 0,
 | 
			
		||||
                .write = 1,
 | 
			
		||||
                .execute = 0,
 | 
			
		||||
                .storage_detect = 0,    /* storage detect supported for MBED_V_0_1_x */
 | 
			
		||||
                /* added initialisers */
 | 
			
		||||
                .reserved = 0
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Create the target key
 | 
			
		||||
        rc = cfstore_driver.Create(keyBuffer, 191, &kdesc, hkey);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_find2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%sError: failed to create key\n", __func__);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(rc >= ARM_DRIVER_OK, cfstore_find2_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
        strncpy(value, "MyValueData", CFSTORE_FIND2_TEST_02_VALUE_SIZE);
 | 
			
		||||
		length = strlen(value);
 | 
			
		||||
		rc = cfstore_driver.Write(hkey, value, &length);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_find2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%sError: failed to write key\n", __func__);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(rc >= ARM_DRIVER_OK, cfstore_find2_utest_msg_g);
 | 
			
		||||
        /* revert to CFSTORE_LOG if more trace required */
 | 
			
		||||
		CFSTORE_DBGLOG("Success!%s", "\n");
 | 
			
		||||
    }
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(CFSTORE_FIND2_GREENTEA_TIMEOUT_S, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
           /*          1         2         3         4         5         6        7  */
 | 
			
		||||
           /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        Case("FIND2_test_00", cfstore_find2_test_00),
 | 
			
		||||
        Case("FIND2_test_01", cfstore_find2_test_01),
 | 
			
		||||
        Case("FIND2_test_02", cfstore_find2_test_02),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
/// @endcond
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,695 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 flash.cpp Test cases to flush KVs in the CFSTORE using the Flash-Journal interface.
 | 
			
		||||
 *
 | 
			
		||||
 * Please consult the documentation under the test-case functions for
 | 
			
		||||
 * a description of the individual test case.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
 | 
			
		||||
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
#include "flash_journal_strategy_sequential.h"
 | 
			
		||||
#include "flash_journal.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
 | 
			
		||||
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
/* Configure secure box. */
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
UVISOR_BOX_NAMESPACE("com.arm.mbed.cfstore.test.flash.box1");
 | 
			
		||||
UVISOR_BOX_CONFIG(cfstore_flash_box1, UVISOR_BOX_STACK_SIZE);
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* shared code common to both sync and async test cases */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Defines
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
#define CFSTORE_FREE                                    free
 | 
			
		||||
#define CFSTORE_MALLOC                                  malloc
 | 
			
		||||
#define CFSTORE_REALLOC                                 realloc
 | 
			
		||||
#define CFSTORE_FLASH_STACK_BUF_SIZE                    64
 | 
			
		||||
#define CFSTORE_FLASH_K64F_CURRENT_PROGRAM_UNIT_SIZE    8
 | 
			
		||||
#define CFSTORE_TEST_DATA_KEYNAME                       "com.arm.mbed.configurationstore.test.flush.cfstoreflushtest02"
 | 
			
		||||
#define CFSTORE_TEST_DATA_KEYNAME_SHORT                 "com.arm"
 | 
			
		||||
#define CFSTORE_TEST_DATA_VALUE_INIT                    "\1"
 | 
			
		||||
#define CFSTORE_TEST_DATA_KEYNAME_SIZE                  (sizeof(CFSTORE_TEST_DATA_KEYNAME) - 1)
 | 
			
		||||
#define CFSTORE_TEST_DATA_VALUE_SIZE                    (sizeof(CFSTORE_TEST_DATA_VALUE_INIT) - 1)
 | 
			
		||||
#define CFSTORE_FLASH_UTEST_MSG_BUF_SIZE                256
 | 
			
		||||
#define CFSTORE_FLASH_MTD_ASYNC_OPS_ON                  1
 | 
			
		||||
#define CFSTORE_FLASH_MTD_ASYNC_OPS_OFF                 0
 | 
			
		||||
#define CFSTORE_FLASH_CASE_TIMEOUT_MS                   5000
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Globals
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
char cfstore_flash_utest_msg_g[CFSTORE_FLASH_UTEST_MSG_BUF_SIZE];
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
uint16_t cfstore_flash_mtd_async_ops_g = 0;
 | 
			
		||||
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0);
 | 
			
		||||
 | 
			
		||||
/* KV data for test_01 */
 | 
			
		||||
static cfstore_kv_data_t cfstore_flush_test_01_kv_data[] = {
 | 
			
		||||
        { CFSTORE_TEST_DATA_KEYNAME, CFSTORE_TEST_DATA_VALUE_INIT},
 | 
			
		||||
        { NULL, NULL},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   key value header structure defining key_name length, value length
 | 
			
		||||
 * @note
 | 
			
		||||
 * 8 bytes long */
 | 
			
		||||
typedef struct cfstore_area_header_t
 | 
			
		||||
{
 | 
			
		||||
    uint32_t vlength;
 | 
			
		||||
    uint8_t klength;
 | 
			
		||||
    uint8_t perm_owner_read : 1;
 | 
			
		||||
    uint8_t perm_owner_write : 1;
 | 
			
		||||
    uint8_t perm_owner_execute : 1;
 | 
			
		||||
    uint8_t perm_other_read : 1;
 | 
			
		||||
    uint8_t perm_other_write : 1;
 | 
			
		||||
    uint8_t perm_other_execute : 1;
 | 
			
		||||
    uint8_t reserved : 2;
 | 
			
		||||
    uint8_t refcount;
 | 
			
		||||
    struct flags_t {
 | 
			
		||||
        uint8_t deleting : 1;
 | 
			
		||||
        uint8_t reserved : 7;
 | 
			
		||||
    } flags ;
 | 
			
		||||
} cfstore_area_header_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   data structure for managing test data */
 | 
			
		||||
typedef struct cfstore_flash_data_blob_t {
 | 
			
		||||
    cfstore_area_header_t hdr;
 | 
			
		||||
    uint8_t data[CFSTORE_TEST_DATA_KEYNAME_SIZE + CFSTORE_TEST_DATA_VALUE_SIZE]; /* 61 bytes for key_name, 1 byte for value */
 | 
			
		||||
} cfstore_flash_data_blob_t;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Defines
 | 
			
		||||
 *
 | 
			
		||||
 * CFSTORE_FLASH_AREA_SIZE_MIN
 | 
			
		||||
 *  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
 | 
			
		||||
 */
 | 
			
		||||
#define CFSTORE_FLASH_AREA_SIZE_MIN                     (sizeof(cfstore_area_header_t) - 1)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Shared implementation between sync and async tests
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* print key name string from area where key_name is not null terminated*/
 | 
			
		||||
static void cfstore_dump_key_name(uint8_t* keyname, uint8_t len, const char* tag)
 | 
			
		||||
{
 | 
			
		||||
     char blob_data[CFSTORE_KEY_NAME_MAX_LENGTH];
 | 
			
		||||
 | 
			
		||||
     (void) tag;
 | 
			
		||||
     assert(keyname != NULL);
 | 
			
		||||
     assert(tag != NULL);
 | 
			
		||||
     assert(len > 0);
 | 
			
		||||
     memcpy(blob_data, keyname, len);
 | 
			
		||||
     blob_data[len] = '\0';
 | 
			
		||||
     CFSTORE_DBGLOG("%s:keyname=%s\r\n", tag, blob_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* @brief  test fsm states and events */
 | 
			
		||||
typedef enum cfstore_flash_fsm_state_t {
 | 
			
		||||
    cfstore_flash_fsm_state_initializing = 0,
 | 
			
		||||
    cfstore_flash_fsm_state_reading,
 | 
			
		||||
    cfstore_flash_fsm_state_writing,
 | 
			
		||||
    cfstore_flash_fsm_state_committing,
 | 
			
		||||
    cfstore_flash_fsm_state_max
 | 
			
		||||
} cfstore_flash_fsm_state_t;
 | 
			
		||||
 | 
			
		||||
/* @brief  test fsm events */
 | 
			
		||||
typedef enum cfstore_flash_fsm_event_t {
 | 
			
		||||
    cfstore_flash_fsm_event_init_done = 0,
 | 
			
		||||
    cfstore_flash_fsm_event_read_done,
 | 
			
		||||
    cfstore_flash_fsm_event_write_done,
 | 
			
		||||
    cfstore_flash_fsm_event_commit_done,
 | 
			
		||||
    cfstore_flash_fsm_event_max,
 | 
			
		||||
} cfstore_flash_fsm_event_t;
 | 
			
		||||
 | 
			
		||||
typedef void (*cfstore_flash_fsm_handler)(void* ctx);
 | 
			
		||||
 | 
			
		||||
typedef struct cfstore_fsm_t
 | 
			
		||||
{
 | 
			
		||||
    cfstore_flash_fsm_state_t state;
 | 
			
		||||
    cfstore_flash_fsm_event_t event;
 | 
			
		||||
} cfstore_fsm_t;
 | 
			
		||||
 | 
			
		||||
typedef struct cfstore_flash_ctx_t
 | 
			
		||||
{
 | 
			
		||||
    uint8_t* area_0_head;
 | 
			
		||||
    uint8_t* area_0_tail;
 | 
			
		||||
    FlashJournal_t jrnl;
 | 
			
		||||
    uint64_t expected_blob_size;
 | 
			
		||||
    cfstore_fsm_t fsm;
 | 
			
		||||
    int32_t status;
 | 
			
		||||
    FlashJournal_OpCode_t cmd_code;
 | 
			
		||||
    uint64_t expected_read_size;
 | 
			
		||||
} cfstore_flash_ctx_t;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Globals
 | 
			
		||||
 */
 | 
			
		||||
static cfstore_flash_ctx_t cfstore_flash_ctx_g;
 | 
			
		||||
static const char* cfstore_flash_opcode_str[] =
 | 
			
		||||
{
 | 
			
		||||
    "FLASH_JOURNAL_OPCODE_INITIALIZE",
 | 
			
		||||
    "FLASH_JOURNAL_OPCODE_GET_INFO",
 | 
			
		||||
    "FLASH_JOURNAL_OPCODE_READ_BLOB",
 | 
			
		||||
    "FLASH_JOURNAL_OPCODE_LOG_BLOB",
 | 
			
		||||
    "FLASH_JOURNAL_OPCODE_COMMIT",
 | 
			
		||||
    "FLASH_JOURNAL_OPCODE_RESET",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifdef CFSTORE_DEBUG
 | 
			
		||||
static const char* cfstore_flash_state_str[] =
 | 
			
		||||
{
 | 
			
		||||
    "initializing",
 | 
			
		||||
    "reading",
 | 
			
		||||
    "writing",
 | 
			
		||||
    "committing",
 | 
			
		||||
    "unknown"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const char* cfstore_flash_event_str[] =
 | 
			
		||||
{
 | 
			
		||||
    "init_done",
 | 
			
		||||
    "read_done",
 | 
			
		||||
    "write_done",
 | 
			
		||||
    "commit_done",
 | 
			
		||||
    "unknown"
 | 
			
		||||
};
 | 
			
		||||
#endif /* CFSTORE_DEBUG */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Forward decl
 | 
			
		||||
 */
 | 
			
		||||
static void cfstore_fsm_state_handle_event(cfstore_fsm_t* fsm, cfstore_flash_fsm_event_t event, void* context);
 | 
			
		||||
static void cfstore_fsm_state_set(cfstore_fsm_t* fsm, cfstore_flash_fsm_state_t new_state, void* ctx);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * context related methods
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* @brief   get a pointer to the global context data structure */
 | 
			
		||||
static cfstore_flash_ctx_t* cfstore_flash_ctx_get(void)
 | 
			
		||||
{
 | 
			
		||||
    return &cfstore_flash_ctx_g;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   flash journal asynchronous callback handler */
 | 
			
		||||
void cfstore_flash_test_01_callback(int32_t status, FlashJournal_OpCode_t cmd_code)
 | 
			
		||||
{
 | 
			
		||||
    cfstore_flash_ctx_t* ctx = cfstore_flash_ctx_get();
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered: status=%d, cmd_code=%d (%s)\r\n", __func__, (int) status, (int) cmd_code, cfstore_flash_opcode_str[cmd_code]);
 | 
			
		||||
    switch(cmd_code)
 | 
			
		||||
    {
 | 
			
		||||
    case FLASH_JOURNAL_OPCODE_INITIALIZE:
 | 
			
		||||
        ctx->fsm.event = cfstore_flash_fsm_event_init_done;
 | 
			
		||||
        break;
 | 
			
		||||
    case FLASH_JOURNAL_OPCODE_READ_BLOB:
 | 
			
		||||
        ctx->fsm.event = cfstore_flash_fsm_event_read_done;
 | 
			
		||||
        break;
 | 
			
		||||
    case FLASH_JOURNAL_OPCODE_LOG_BLOB:
 | 
			
		||||
        ctx->fsm.event = cfstore_flash_fsm_event_write_done;
 | 
			
		||||
        break;
 | 
			
		||||
    case FLASH_JOURNAL_OPCODE_COMMIT:
 | 
			
		||||
        ctx->fsm.event = cfstore_flash_fsm_event_commit_done;
 | 
			
		||||
        break;
 | 
			
		||||
    case FLASH_JOURNAL_OPCODE_GET_INFO:
 | 
			
		||||
    case FLASH_JOURNAL_OPCODE_RESET:
 | 
			
		||||
    default:
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: received asynchronous notification for opcode=%d (%s) when api call should have been synchronous", __func__, cmd_code, cmd_code <= FLASH_JOURNAL_OPCODE_RESET ? cfstore_flash_opcode_str[cmd_code] : "unknown");
 | 
			
		||||
        TEST_ASSERT_MESSAGE(false, cfstore_flash_utest_msg_g)
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    ctx->status = status;
 | 
			
		||||
    ctx->cmd_code = cmd_code;
 | 
			
		||||
    cfstore_fsm_state_handle_event(&ctx->fsm, ctx->fsm.event, (void*) ctx);
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief  fsm handler called on entry to initializing state */
 | 
			
		||||
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);
 | 
			
		||||
    FlashJournal_Info_t info;
 | 
			
		||||
    FlashJournal_Status_t status = JOURNAL_STATUS_ERROR;
 | 
			
		||||
    cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context;
 | 
			
		||||
 | 
			
		||||
    /* check that the mtd is in synchronous mode */
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered: \r\n", __func__);
 | 
			
		||||
    memset(&info, 0, sizeof(info));
 | 
			
		||||
 | 
			
		||||
    /* FlashJournal_initialize() is potentially asynchronous */
 | 
			
		||||
    status = (FlashJournal_Status_t) FlashJournal_initialize(&ctx->jrnl, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, cfstore_flash_test_01_callback);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to initialize flash journaling layer (status=%d)\r\n", __func__, status);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(status >= JOURNAL_STATUS_OK, cfstore_flash_utest_msg_g);
 | 
			
		||||
    /* if status > 0, expect async callback, otherwise initialisation has been completed */
 | 
			
		||||
    if(status > 0) {
 | 
			
		||||
        cfstore_flash_test_01_callback(status, FLASH_JOURNAL_OPCODE_INITIALIZE);
 | 
			
		||||
    }
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* brief    callback handler when in state initializing */
 | 
			
		||||
static void cfstore_flash_fsm_initializing(void* context)
 | 
			
		||||
{
 | 
			
		||||
    cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\r\n", __func__);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: entered handler(%s) but not in initializing state (fsm->state=%d)\r\n", __func__, __func__, (int) ctx->fsm.state);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->fsm.state == cfstore_flash_fsm_state_initializing, cfstore_flash_utest_msg_g);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: cmd_code code (%d) is not as expected (%d)\r\n", __func__, ctx->cmd_code, FLASH_JOURNAL_OPCODE_INITIALIZE);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->cmd_code == FLASH_JOURNAL_OPCODE_INITIALIZE, cfstore_flash_utest_msg_g);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: status=%d\r\n", __func__, (int) ctx->status);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->status >= JOURNAL_STATUS_OK, cfstore_flash_utest_msg_g);
 | 
			
		||||
    /* only change state if status > 0*/
 | 
			
		||||
    if(ctx->status > 0){
 | 
			
		||||
        cfstore_fsm_state_set(&ctx->fsm, cfstore_flash_fsm_state_reading, ctx);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* static void cfstore_flash_fsm_init_on_exit(void* context){ (void) context;} */
 | 
			
		||||
 | 
			
		||||
/* brief    callback handler called when entering the reading state
 | 
			
		||||
 * note
 | 
			
		||||
 *  flash journal has initialised successfully. now
 | 
			
		||||
 */
 | 
			
		||||
static void cfstore_flash_fsm_read_on_entry(void* context)
 | 
			
		||||
{
 | 
			
		||||
    uint8_t* ptr = NULL;
 | 
			
		||||
    int32_t ret = 0;
 | 
			
		||||
    FlashJournal_Info_t info;
 | 
			
		||||
    FlashJournal_Status_t status = JOURNAL_STATUS_ERROR;
 | 
			
		||||
    cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\r\n", __func__);
 | 
			
		||||
    CFSTORE_ASSERT(ctx != NULL);
 | 
			
		||||
    /* drv->GetInfo() is synchronous */
 | 
			
		||||
    status = FlashJournal_getInfo(&ctx->jrnl, &info);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: failed get journal info (status=%d)\r\n", __func__, (int) status);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(status == JOURNAL_STATUS_OK, cfstore_flash_utest_msg_g);
 | 
			
		||||
    CFSTORE_DBGLOG("%s:FlashJournal_getInfo() done. info.sizeofJournaledBlob=%lu\r\n", __func__, (long unsigned int) info.sizeofJournaledBlob);
 | 
			
		||||
 | 
			
		||||
    if(info.sizeofJournaledBlob > 0)
 | 
			
		||||
    {
 | 
			
		||||
        /* setup the expected blob size for writing
 | 
			
		||||
         * This is a multiple of program unit so the write doesnt fail due to unaligned log */
 | 
			
		||||
        ctx->expected_blob_size = sizeof(cfstore_flash_data_blob_t);
 | 
			
		||||
        if(ctx->expected_blob_size % CFSTORE_FLASH_K64F_CURRENT_PROGRAM_UNIT_SIZE > 0){
 | 
			
		||||
            ctx->expected_blob_size += (CFSTORE_FLASH_K64F_CURRENT_PROGRAM_UNIT_SIZE - (sizeof(cfstore_flash_data_blob_t) % CFSTORE_FLASH_K64F_CURRENT_PROGRAM_UNIT_SIZE));
 | 
			
		||||
        }
 | 
			
		||||
        /* test that a blob size is the expected size for flash data that has been written before */
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error:  info.sizeofJournaledBlob does not match expect size. expected_blob_size (%lu) != info.sizeofJournaledBlob (%lu)\r\n", __func__, (unsigned long int) ctx->expected_blob_size, (unsigned long int) info.sizeofJournaledBlob);
 | 
			
		||||
        TEST_ASSERT_EQUAL_INT64_MESSAGE(ctx->expected_blob_size, info.sizeofJournaledBlob, cfstore_flash_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
        /* grow the area by the size of the stored blob */
 | 
			
		||||
        ptr = (uint8_t*) CFSTORE_REALLOC((void*) ctx->area_0_head, ctx->expected_blob_size);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:realloc failed flash blob (size=%d)\r\n", __func__, (int)info.sizeofJournaledBlob);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ptr != NULL, cfstore_flash_utest_msg_g);
 | 
			
		||||
        memset(ptr, 0, ctx->expected_blob_size);
 | 
			
		||||
        if(ptr != ctx->area_0_head){
 | 
			
		||||
            CFSTORE_DBGLOG("%s:cfstore_ctx_g.area_0_head pointer changed (cfstore_ctx_g.area_0_head=%p, ptr=%p)\r\n", __func__, ctx->area_0_head, ptr);
 | 
			
		||||
            ctx->area_0_head = ptr;
 | 
			
		||||
            ctx->area_0_tail = ctx->area_0_head + info.sizeofJournaledBlob;
 | 
			
		||||
        }
 | 
			
		||||
        ret = FlashJournal_read(&ctx->jrnl, (void*) ctx->area_0_head, info.sizeofJournaledBlob);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: unable to read flash journal (ret=%d. info.sizeofJournaledBlob=%d)\r\n", __func__, (int) ret, (int) info.sizeofJournaledBlob);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= JOURNAL_STATUS_OK, cfstore_flash_utest_msg_g);
 | 
			
		||||
        if(ret > 0){
 | 
			
		||||
            /* read has completed synchronously*/
 | 
			
		||||
            CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: unable to read all data from flash journal (expected size=%lu, read=%d)\r\n", __func__, (unsigned long int)info.sizeofJournaledBlob, (int) ret);
 | 
			
		||||
            TEST_ASSERT_EQUAL_INT32_MESSAGE( (int32_t) info.sizeofJournaledBlob, ret, cfstore_flash_utest_msg_g);
 | 
			
		||||
            cfstore_flash_test_01_callback(ret, FLASH_JOURNAL_OPCODE_READ_BLOB);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        /* there is no blob, move to next state. need a +ve status value to indicate async completion
 | 
			
		||||
         * to the fsm reading state handler. use CFSTORE_FLASH_AREA_SIZE_MIN for this value */
 | 
			
		||||
        ctx->expected_blob_size = CFSTORE_FLASH_AREA_SIZE_MIN;
 | 
			
		||||
        status = (FlashJournal_Status_t) CFSTORE_FLASH_AREA_SIZE_MIN;
 | 
			
		||||
        cfstore_flash_test_01_callback(status, FLASH_JOURNAL_OPCODE_READ_BLOB);
 | 
			
		||||
    }
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* @brief  fsm handler when in reading state */
 | 
			
		||||
void cfstore_flash_fsm_reading(void* context)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = 0;
 | 
			
		||||
    cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context;
 | 
			
		||||
    cfstore_flash_data_blob_t *blob = NULL;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\r\n", __func__);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: entered handler(%s) but not in reading state (fsm->state=%d)\r\n", __func__, __func__, (int) ctx->fsm.state);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->fsm.state == cfstore_flash_fsm_state_reading, cfstore_flash_utest_msg_g);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: cmd_code code (%d) is not as expected (%d)\r\n", __func__, ctx->cmd_code, FLASH_JOURNAL_OPCODE_READ_BLOB);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->cmd_code == FLASH_JOURNAL_OPCODE_READ_BLOB, cfstore_flash_utest_msg_g);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: status=%d\r\n", __func__, (int) ctx->status);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->status >= JOURNAL_STATUS_OK, cfstore_flash_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    if(ctx->status > 0)
 | 
			
		||||
    {
 | 
			
		||||
        if(ctx->status > (int32_t) CFSTORE_FLASH_AREA_SIZE_MIN)
 | 
			
		||||
        {
 | 
			
		||||
            /* check the correct amount of data was read, which is the status code */
 | 
			
		||||
            CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: unable to read all data from flash journal (expected size=%lu, read=%d)\r\n", __func__, (unsigned long int) ctx->expected_blob_size, (int) ctx->status);
 | 
			
		||||
            /* ctx->status contains the status of the read that was completed */
 | 
			
		||||
            TEST_ASSERT_EQUAL_INT64_MESSAGE(ctx->expected_blob_size, (int32_t) ctx->status, cfstore_flash_utest_msg_g);
 | 
			
		||||
            if(ctx->area_0_head != NULL)
 | 
			
		||||
            {
 | 
			
		||||
                /* check the key_name read from flash is correct */
 | 
			
		||||
                blob = (cfstore_flash_data_blob_t*) ctx->area_0_head;
 | 
			
		||||
                cfstore_dump_key_name(blob->data, CFSTORE_TEST_DATA_KEYNAME_SIZE, __func__);
 | 
			
		||||
                ret = memcmp(blob->data, cfstore_flush_test_01_kv_data[0].key_name, strlen(cfstore_flush_test_01_kv_data[0].key_name));
 | 
			
		||||
                CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: incorrect key_name read from flash (expected 0 from memcpy(keyname, flash_data), actual was non-zero)", __func__);
 | 
			
		||||
                TEST_ASSERT_EQUAL_INT_MESSAGE(0, ret, cfstore_flash_utest_msg_g);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        cfstore_fsm_state_set(&ctx->fsm, cfstore_flash_fsm_state_writing, ctx);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* void cfstore_flash_fsm_read_on_exit(void* context){ (void) context;} */
 | 
			
		||||
 | 
			
		||||
/* @brief   on entry to writing state, update value */
 | 
			
		||||
void cfstore_flash_fsm_write_on_entry(void* context)
 | 
			
		||||
{
 | 
			
		||||
    uint8_t value = 0;
 | 
			
		||||
    int32_t ret = 0;
 | 
			
		||||
    cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context;
 | 
			
		||||
    cfstore_flash_data_blob_t *blob = NULL;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered:\r\n", __func__);
 | 
			
		||||
    /* allocate memory for data if not already done so */
 | 
			
		||||
    if(ctx->area_0_head == NULL)
 | 
			
		||||
    {
 | 
			
		||||
        /* This is a multiple of program unit so the write doesnt fail due to unaligned log */
 | 
			
		||||
        ctx->expected_blob_size = sizeof(cfstore_flash_data_blob_t);
 | 
			
		||||
        if(ctx->expected_blob_size % CFSTORE_FLASH_K64F_CURRENT_PROGRAM_UNIT_SIZE > 0){
 | 
			
		||||
            ctx->expected_blob_size += (CFSTORE_FLASH_K64F_CURRENT_PROGRAM_UNIT_SIZE - (sizeof(cfstore_flash_data_blob_t) % CFSTORE_FLASH_K64F_CURRENT_PROGRAM_UNIT_SIZE));
 | 
			
		||||
        }
 | 
			
		||||
        ctx->area_0_head = (uint8_t*) CFSTORE_REALLOC((void*) ctx->area_0_head, ctx->expected_blob_size);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: unable to allocate memory for context\r\n", __func__);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ctx->area_0_head != NULL, cfstore_flash_utest_msg_g);
 | 
			
		||||
        ctx->area_0_tail = ctx->area_0_head + ctx->expected_blob_size;
 | 
			
		||||
        memset(ctx->area_0_head, 0, ctx->expected_blob_size);
 | 
			
		||||
        /* setup data to write to flash */
 | 
			
		||||
        blob = (cfstore_flash_data_blob_t*) ctx->area_0_head;
 | 
			
		||||
        blob->hdr.klength = strlen(cfstore_flush_test_01_kv_data->key_name);
 | 
			
		||||
        blob->hdr.vlength= 1;
 | 
			
		||||
        blob->hdr.perm_owner_read = true;
 | 
			
		||||
        blob->hdr.perm_owner_write = true;
 | 
			
		||||
        blob->hdr.refcount = 1;
 | 
			
		||||
        memcpy((void*) blob->data, (const void*) cfstore_flush_test_01_kv_data->key_name, strlen(cfstore_flush_test_01_kv_data->key_name));
 | 
			
		||||
        memcpy((void*) &blob->data[CFSTORE_TEST_DATA_KEYNAME_SIZE], (const void*) cfstore_flush_test_01_kv_data->value, strlen(cfstore_flush_test_01_kv_data->value));
 | 
			
		||||
    }
 | 
			
		||||
    if(ctx->area_0_head != NULL)
 | 
			
		||||
    {
 | 
			
		||||
        /* data has been read */
 | 
			
		||||
        /* check the key_name read from flash is correct */
 | 
			
		||||
        blob = (cfstore_flash_data_blob_t*) ctx->area_0_head;
 | 
			
		||||
        value = (uint8_t) blob->data[CFSTORE_TEST_DATA_KEYNAME_SIZE];
 | 
			
		||||
        CFSTORE_DBGLOG("INFO: value read from flash = %u\r\n", value);
 | 
			
		||||
        /* update the value */
 | 
			
		||||
        value++;
 | 
			
		||||
        memcpy((void*) &blob->data[CFSTORE_TEST_DATA_KEYNAME_SIZE], (const void*) &value, sizeof(uint8_t));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = FlashJournal_log(&ctx->jrnl, (const void*) ctx->area_0_head, ctx->expected_blob_size);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: ret = JOURNAL_STATUS_SMALL_LOG_REQUEST, bailing out.", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret != (int32_t) JOURNAL_STATUS_SMALL_LOG_REQUEST, cfstore_flash_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to perform log operation to flash journal (ret=%d)\r\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= 0, cfstore_flash_utest_msg_g);
 | 
			
		||||
    if(ret > 0){
 | 
			
		||||
        /* write has completed synchronously*/
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: unable to write all data from flash journal (expected size=%lu, read=%d)\r\n", __func__, (unsigned long int) ctx->expected_blob_size, (int) ret);
 | 
			
		||||
        TEST_ASSERT_EQUAL_INT32_MESSAGE(ret, (int32_t) ctx->expected_blob_size, cfstore_flash_utest_msg_g);
 | 
			
		||||
        cfstore_flash_test_01_callback(ret, FLASH_JOURNAL_OPCODE_LOG_BLOB);
 | 
			
		||||
    }
 | 
			
		||||
    /* wait for async completion handler*/
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* @brief  fsm handler when in reading state */
 | 
			
		||||
void cfstore_flash_fsm_writing(void* context)
 | 
			
		||||
{
 | 
			
		||||
    cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered:\r\n", __func__);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: entered handler(%s) but not in writing state (fsm->state=%d)\r\n", __func__, __func__, (int) ctx->fsm.state);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->fsm.state == cfstore_flash_fsm_state_writing, cfstore_flash_utest_msg_g);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: cmd_code code (%d) is not as expected (%d)\r\n", __func__, ctx->cmd_code, FLASH_JOURNAL_OPCODE_LOG_BLOB);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->cmd_code == FLASH_JOURNAL_OPCODE_LOG_BLOB, cfstore_flash_utest_msg_g);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: status=%d\r\n", __func__, (int) ctx->status);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->status >= JOURNAL_STATUS_OK, cfstore_flash_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    if(ctx->status > 0){
 | 
			
		||||
        /* check the correct amount of data was written */
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: unable to write all data from flash journal (expected size=%lu, read=%d)\r\n", __func__, (unsigned long int) ctx->expected_blob_size, (int) ctx->status);
 | 
			
		||||
        TEST_ASSERT_EQUAL_INT64_MESSAGE(ctx->expected_blob_size, ctx->status, cfstore_flash_utest_msg_g);
 | 
			
		||||
        cfstore_fsm_state_set(&ctx->fsm, cfstore_flash_fsm_state_committing, ctx);
 | 
			
		||||
    }
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* void cfstore_flash_fsm_write_on_exit(void* ctx){(void) ctx;} */
 | 
			
		||||
 | 
			
		||||
/* @brief  fsm handler when entering committing state */
 | 
			
		||||
void cfstore_flash_fsm_commit_on_entry(void* context)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = 0;
 | 
			
		||||
    cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered:\r\n", __func__);
 | 
			
		||||
    ret = FlashJournal_commit(&ctx->jrnl);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to perform commit operation to flash journal (ret=%d)\r\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= (int32_t) JOURNAL_STATUS_OK, cfstore_flash_utest_msg_g);
 | 
			
		||||
    /* for flash-journal-strategy-sequential version >0.4.0, commit() return no longer reports size of commit block */
 | 
			
		||||
    if(ret > 0){
 | 
			
		||||
        Harness::validate_callback();
 | 
			
		||||
    }
 | 
			
		||||
    /* wait for async completion handler*/
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief  fsm handler when in committing state */
 | 
			
		||||
void cfstore_flash_fsm_committing(void* context)
 | 
			
		||||
{
 | 
			
		||||
    cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\r\n", __func__);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: entered handler(%s) but not in committing state (fsm->state=%d)\r\n", __func__, __func__, (int) ctx->fsm.state);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->fsm.state == cfstore_flash_fsm_state_committing, cfstore_flash_utest_msg_g);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: cmd_code code (%d) is not as expected (%d)\r\n", __func__, ctx->cmd_code, FLASH_JOURNAL_OPCODE_COMMIT);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->cmd_code == FLASH_JOURNAL_OPCODE_COMMIT, cfstore_flash_utest_msg_g);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: status=%d\r\n", __func__, (int) ctx->status);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->status >= JOURNAL_STATUS_OK, cfstore_flash_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* check the correct amount of data was written */
 | 
			
		||||
    /* for flash-journal-strategy-sequential version >0.4.0, commit() return no longer reports size of commit block */
 | 
			
		||||
    Harness::validate_callback();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* @brief  fsm handler when exiting committing state */
 | 
			
		||||
void cfstore_flash_fsm_commit_on_exit(void* context)
 | 
			
		||||
{
 | 
			
		||||
    cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\r\n", __func__);
 | 
			
		||||
    /* test done. clean up*/
 | 
			
		||||
    if(ctx->area_0_head){
 | 
			
		||||
        CFSTORE_FREE(ctx->area_0_head);
 | 
			
		||||
        ctx->area_0_head = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    Harness::validate_callback();
 | 
			
		||||
 }
 | 
			
		||||
 | 
			
		||||
#define cfstore_flash_fsm_null  NULL
 | 
			
		||||
 | 
			
		||||
/* handler functions while in state */
 | 
			
		||||
static cfstore_flash_fsm_handler cfstore_flash_fsm[cfstore_flash_fsm_state_max][cfstore_flash_fsm_event_max] =
 | 
			
		||||
{
 | 
			
		||||
/* state\event:     init_done                           read_done                   write_done                  commit_done */
 | 
			
		||||
/* initialising */  {cfstore_flash_fsm_initializing,    cfstore_flash_fsm_null,     cfstore_flash_fsm_null,     cfstore_flash_fsm_null          },
 | 
			
		||||
/* reading      */  {cfstore_flash_fsm_null,            cfstore_flash_fsm_reading,  cfstore_flash_fsm_null,     cfstore_flash_fsm_null          },
 | 
			
		||||
/* writing      */  {cfstore_flash_fsm_null,            cfstore_flash_fsm_null,     cfstore_flash_fsm_writing,  cfstore_flash_fsm_null          },
 | 
			
		||||
/* committing   */  {cfstore_flash_fsm_null,            cfstore_flash_fsm_null,     cfstore_flash_fsm_null,     cfstore_flash_fsm_committing    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* handler functions for entering the state*/
 | 
			
		||||
cfstore_flash_fsm_handler cfstore_flash_fsm_on_entry[cfstore_flash_fsm_state_max] =
 | 
			
		||||
{
 | 
			
		||||
    cfstore_flash_fsm_init_on_entry,
 | 
			
		||||
    cfstore_flash_fsm_read_on_entry,
 | 
			
		||||
    cfstore_flash_fsm_write_on_entry,
 | 
			
		||||
    cfstore_flash_fsm_commit_on_entry,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* handler functions for exiting state, currently none used */
 | 
			
		||||
cfstore_flash_fsm_handler cfstore_flash_fsm_on_exit[cfstore_flash_fsm_state_max] =
 | 
			
		||||
{
 | 
			
		||||
    NULL, NULL, NULL, NULL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   inject event into fsm */
 | 
			
		||||
static void cfstore_fsm_state_handle_event(cfstore_fsm_t* fsm, cfstore_flash_fsm_event_t event, void* context)
 | 
			
		||||
{
 | 
			
		||||
    cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered: fsm=%p, event=%d (%s), ctx=%p\r\n", __func__, fsm, (int) event, cfstore_flash_event_str[event], ctx);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: invalid event (%d)\r\n", __func__, (int) event);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(event < cfstore_flash_fsm_event_max, cfstore_flash_utest_msg_g);
 | 
			
		||||
    fsm->event = event;
 | 
			
		||||
    if(cfstore_flash_fsm[fsm->state][fsm->event] != NULL){
 | 
			
		||||
        cfstore_flash_fsm[fsm->state][fsm->event](ctx);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* do not clear context data set by caller as it may be used later
 | 
			
		||||
     *  fsm->event = cfstore_flash_fsm_event_max;
 | 
			
		||||
     *  ctx->status = 0;
 | 
			
		||||
     *  ctx->cmd_code =  (FlashJournal_OpCode_t)((int) FLASH_JOURNAL_OPCODE_RESET+1);
 | 
			
		||||
     */
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   function to move to new fsm state, calling state exit function for old state and entry function for new state */
 | 
			
		||||
static void cfstore_fsm_state_set(cfstore_fsm_t* fsm, cfstore_flash_fsm_state_t new_state, void* ctx)
 | 
			
		||||
{
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered: fsm=%p, new_state=%d, ctx=%p\r\n", __func__, fsm, (int) new_state, ctx);
 | 
			
		||||
    CFSTORE_DBGLOG("%s:FSM:REQ RX:%s:%s\r\n", __func__, cfstore_flash_state_str[fsm->state], cfstore_flash_state_str[new_state]);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(fsm != NULL, "fsm is not a valid pointer");
 | 
			
		||||
    TEST_ASSERT_MESSAGE(new_state < cfstore_flash_fsm_state_max, "new_state is not a valid state");
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx != NULL, "ctx is not a valid pointer");
 | 
			
		||||
    TEST_ASSERT_MESSAGE(fsm->state < cfstore_flash_fsm_state_max, "fsm->state is not a valid state");
 | 
			
		||||
 | 
			
		||||
    if(cfstore_flash_fsm_on_exit[fsm->state] != NULL){
 | 
			
		||||
        cfstore_flash_fsm_on_exit[fsm->state](ctx);
 | 
			
		||||
    }
 | 
			
		||||
    fsm->state = new_state;
 | 
			
		||||
    if(cfstore_flash_fsm_on_entry[new_state] != NULL){
 | 
			
		||||
        cfstore_flash_fsm_on_entry[new_state](ctx);
 | 
			
		||||
    }
 | 
			
		||||
    CFSTORE_DBGLOG("%s:FSM:REQ DONE:\r\n", __func__);
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* @brief   initialize global context data structure */
 | 
			
		||||
static void cfstore_flash_ctx_init(cfstore_flash_ctx_t* ctx)
 | 
			
		||||
{
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx != NULL, "ctx is NULL");
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\r\n", __func__);
 | 
			
		||||
    memset(&cfstore_flash_ctx_g, 0, sizeof(cfstore_flash_ctx_g));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   asynchronous test 01 */
 | 
			
		||||
static control_t cfstore_flash_journal_async_test_01(void)
 | 
			
		||||
{
 | 
			
		||||
    cfstore_flash_ctx_t* ctx = cfstore_flash_ctx_get();
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered: \r\n", __func__);
 | 
			
		||||
    cfstore_flash_mtd_async_ops_g = CFSTORE_FLASH_MTD_ASYNC_OPS_ON;
 | 
			
		||||
    cfstore_flash_ctx_init(ctx);
 | 
			
		||||
    cfstore_fsm_state_set(&ctx->fsm, cfstore_flash_fsm_state_initializing, ctx);
 | 
			
		||||
 | 
			
		||||
    /* allow time for work to be done */
 | 
			
		||||
    return CaseTimeout(CFSTORE_FLASH_CASE_TIMEOUT_MS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* report whether built/configured for flash sync or async mode */
 | 
			
		||||
static control_t cfstore_flash_test_00(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    ret = cfstore_test_startup();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to perform test startup (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flash_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
#ifndef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
    CFSTORE_LOG("INITIALIZING: BACKEND=SRAM. Skipping flash test%s", "\n");
 | 
			
		||||
#endif
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
/* Specify all your test cases here */
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
        Case("flash_journal_async_test_00", cfstore_flash_test_00),
 | 
			
		||||
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
        Case("flash_journal_async_test_01", cfstore_flash_journal_async_test_01),
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(100, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
/// @endcond
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,116 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 flash_set.cpp Test tool to set flash to some data
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#include "cfstore_utest.h"
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#include "cfstore_uvisor.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
/* Create the main box ACL list for the application.
 | 
			
		||||
 * The main ACL gets inherited by all the other boxes
 | 
			
		||||
 */
 | 
			
		||||
CFSTORE_UVISOR_MAIN_ACL(cfstore_acl_uvisor_box_flash_set_g);
 | 
			
		||||
 | 
			
		||||
/* Enable uVisor. */
 | 
			
		||||
UVISOR_SET_MODE_ACL(UVISOR_ENABLED, cfstore_acl_uvisor_box_flash_set_g);
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   add ~50 KVs and store them in flash
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
static control_t cfstore_flash_set_test_01_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_CAPABILITIES caps = cfstore_driver.GetCapabilities();
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    memset(&flags, 0, sizeof(flags));
 | 
			
		||||
 | 
			
		||||
    CFSTORE_LOG("caps.asynchronous_ops : %d\n", (int) caps.asynchronous_ops);
 | 
			
		||||
    ret = cfstore_test_init_1();
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: failed to write data to falsh.", __func__);
 | 
			
		||||
    }
 | 
			
		||||
    ret = drv->Flush();
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Flush() call failed (ret=%d).\r\n", __func__, (int) ret);
 | 
			
		||||
    }
 | 
			
		||||
#ifdef CFSTORE_DEBUG
 | 
			
		||||
    ret = cfstore_test_dump();
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("Error: failed to dump CFSTORE contents%s", "\n");
 | 
			
		||||
    }
 | 
			
		||||
#endif /* CFSTORE_DEBUG */
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("Error: failed to Uninitialize() CFSTORE%s", "\n");
 | 
			
		||||
    }
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(100, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
           /*          1         2         3         4         5         6        7  */
 | 
			
		||||
           /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        Case("FLASH_SET_test_01_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("FLASH_SET_test_01_end", cfstore_flash_set_test_01_end),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
/// @endcond
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,630 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 flush.cpp Test cases to flush KVs in the CFSTORE using the drv->Flush() interface.
 | 
			
		||||
 *
 | 
			
		||||
 * Please consult the documentation under the test-case functions for
 | 
			
		||||
 * a description of the individual test case.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#if defined __MBED__ && ! defined TOOLCHAIN_GCC_ARM
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#include "cfstore_uvisor.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
static control_t cfstore_flush_test_00(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    CFSTORE_LOG("%s:Not implemented for ARM toolchain\n", __func__);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(100, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
           /*          1         2         3         4         5         6        7  */
 | 
			
		||||
           /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        Case("FLUSH_test_00", cfstore_flush_test_00),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Defines
 | 
			
		||||
 */
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
#define CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE                256
 | 
			
		||||
#define cfstore_flush_fsm_null                          NULL
 | 
			
		||||
#define CFSTORE_FLUSH_CASE_TIMEOUT_MS                   10000
 | 
			
		||||
#define CFSTORE_FLUSH_FSM_LOOPS                         20
 | 
			
		||||
 | 
			
		||||
#ifdef CFSTORE_DEBUG
 | 
			
		||||
#define CFSTORE_FLUSH_GREENTEA_TIMEOUT_S     360
 | 
			
		||||
#else
 | 
			
		||||
#define CFSTORE_FLUSH_GREENTEA_TIMEOUT_S     60
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Globals
 | 
			
		||||
 *
 | 
			
		||||
 * cfstore_flush_utest_msg_g
 | 
			
		||||
 *  buffer for storing TEST_ASSERT_xxx_MESSAGE messages
 | 
			
		||||
 */
 | 
			
		||||
char cfstore_flush_utest_msg_g[CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE];
 | 
			
		||||
 | 
			
		||||
/* Configure secure box. */
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
UVISOR_BOX_NAMESPACE("com.arm.mbed.cfstore.test.flush.box1");
 | 
			
		||||
UVISOR_BOX_CONFIG(cfstore_flush_box1, UVISOR_BOX_STACK_SIZE);
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef TARGET_LIKE_X86_LINUX_NATIVE
 | 
			
		||||
 | 
			
		||||
/** @brief  basic Flush() test
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
int32_t cfstore_flush_test_01_x86_sync(void)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    ret = drv->Initialize(NULL, NULL);
 | 
			
		||||
    if(ret != ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Initialize() call failed (ret=%d).\r\n", __func__, (int) ret);
 | 
			
		||||
        goto out0;
 | 
			
		||||
    }
 | 
			
		||||
    ret = drv->Flush();
 | 
			
		||||
    if(ret != ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Flush() call failed (ret=%d).\r\n", __func__, (int) ret);
 | 
			
		||||
    }
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    if(ret != ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Initialize() call failed to Uninitialise(ret=%d).\r\n", __func__, (int) ret);
 | 
			
		||||
        goto out0;
 | 
			
		||||
    }
 | 
			
		||||
 out0:
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
#endif /* TARGET_LIKE_X86_LINUX_NATIVE */
 | 
			
		||||
 | 
			
		||||
/* KV data for test_03 */
 | 
			
		||||
static cfstore_kv_data_t cfstore_flush_test_02_kv_data[] = {
 | 
			
		||||
        { "com.arm.mbed.configurationstore.test.flush.cfstoreflushtest02", "1"},
 | 
			
		||||
        /*          1         2         3         4         5         6        7  */
 | 
			
		||||
        /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        { NULL, NULL},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* async test version */
 | 
			
		||||
 | 
			
		||||
/* @brief  test fsm states and events */
 | 
			
		||||
typedef enum cfstore_flush_fsm_state_t {
 | 
			
		||||
    cfstore_flush_fsm_state_stopped = 0,
 | 
			
		||||
    cfstore_flush_fsm_state_initializing,
 | 
			
		||||
    cfstore_flush_fsm_state_flushing,
 | 
			
		||||
    cfstore_flush_fsm_state_uninitializing,
 | 
			
		||||
    cfstore_flush_fsm_state_max
 | 
			
		||||
} cfstore_flush_fsm_state_t;
 | 
			
		||||
 | 
			
		||||
/* @brief  test fsm events */
 | 
			
		||||
typedef enum cfstore_flush_fsm_event_t {
 | 
			
		||||
    cfstore_flush_fsm_event_init_done = 0,
 | 
			
		||||
    cfstore_flush_fsm_event_flush_done,
 | 
			
		||||
    cfstore_flush_fsm_event_uninit_done,
 | 
			
		||||
    cfstore_flush_fsm_event_max,
 | 
			
		||||
} cfstore_flush_fsm_event_t;
 | 
			
		||||
 | 
			
		||||
typedef void (*cfstore_flush_fsm_handler)(void* ctx);
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
typedef struct cfstore_fsm_t
 | 
			
		||||
{
 | 
			
		||||
    cfstore_flush_fsm_state_t state;
 | 
			
		||||
    cfstore_flush_fsm_event_t event;
 | 
			
		||||
} cfstore_fsm_t;
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
typedef struct cfstore_flush_ctx_t
 | 
			
		||||
{
 | 
			
		||||
    int32_t loops_done;
 | 
			
		||||
    cfstore_fsm_t fsm;
 | 
			
		||||
    int32_t status;
 | 
			
		||||
    ARM_CFSTORE_OPCODE cmd_code;
 | 
			
		||||
} cfstore_flush_ctx_t;
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Globals
 | 
			
		||||
 */
 | 
			
		||||
static cfstore_flush_ctx_t cfstore_flush_ctx_g;
 | 
			
		||||
 | 
			
		||||
#ifdef CFSTORE_DEBUG
 | 
			
		||||
static const char* cfstore_flush_state_str[] =
 | 
			
		||||
{
 | 
			
		||||
    "stopped",
 | 
			
		||||
    "initializing",
 | 
			
		||||
    "flushing",
 | 
			
		||||
    "uninitializing",
 | 
			
		||||
    "unknown"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const char* cfstore_flush_event_str[] =
 | 
			
		||||
{
 | 
			
		||||
    "init_done",
 | 
			
		||||
    "flush_done",
 | 
			
		||||
    "uninit_done",
 | 
			
		||||
    "unknown"
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Forward decl
 | 
			
		||||
 */
 | 
			
		||||
static void cfstore_flush_fsm_state_handle_event(cfstore_fsm_t* fsm, cfstore_flush_fsm_event_t event, void* context);
 | 
			
		||||
static void cfstore_flush_fsm_state_set(cfstore_fsm_t* fsm, cfstore_flush_fsm_state_t new_state, void* ctx);
 | 
			
		||||
/*
 | 
			
		||||
 * context related methods
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* @brief   get a pointer to the global context data structure */
 | 
			
		||||
static cfstore_flush_ctx_t* cfstore_flush_ctx_get(void)
 | 
			
		||||
{
 | 
			
		||||
    return &cfstore_flush_ctx_g;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* @brief   initialize global context data structure */
 | 
			
		||||
static void cfstore_flush_ctx_init(cfstore_flush_ctx_t* ctx)
 | 
			
		||||
{
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx != NULL, "ctx is NULL");
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\r\n", __func__);
 | 
			
		||||
    memset(&cfstore_flush_ctx_g, 0, sizeof(cfstore_flush_ctx_g));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   cfstore asynchronous callback handler */
 | 
			
		||||
void cfstore_flush_test_01_callback(int32_t status, ARM_CFSTORE_OPCODE cmd_code, void *client_context, ARM_CFSTORE_HANDLE handle)
 | 
			
		||||
{
 | 
			
		||||
    cfstore_flush_ctx_t* ctx = (cfstore_flush_ctx_t*) client_context;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered: status=%d, cmd_code=%d (%s) ctx=%p, handle=%p\r\n", __func__, (int) status, (int) cmd_code, cfstore_test_opcode_str[cmd_code], ctx, handle);
 | 
			
		||||
    (void) handle;
 | 
			
		||||
    switch(cmd_code)
 | 
			
		||||
    {
 | 
			
		||||
    case CFSTORE_OPCODE_INITIALIZE:
 | 
			
		||||
        ctx->fsm.event = cfstore_flush_fsm_event_init_done;
 | 
			
		||||
        break;
 | 
			
		||||
    case CFSTORE_OPCODE_FLUSH:
 | 
			
		||||
        ctx->fsm.event = cfstore_flush_fsm_event_flush_done;
 | 
			
		||||
        break;
 | 
			
		||||
    case CFSTORE_OPCODE_UNINITIALIZE:
 | 
			
		||||
        ctx->fsm.event = cfstore_flush_fsm_event_uninit_done;
 | 
			
		||||
        break;
 | 
			
		||||
    case CFSTORE_OPCODE_CLOSE:
 | 
			
		||||
    case CFSTORE_OPCODE_CREATE:
 | 
			
		||||
    case CFSTORE_OPCODE_DELETE:
 | 
			
		||||
    case CFSTORE_OPCODE_FIND:
 | 
			
		||||
    case CFSTORE_OPCODE_GET_KEY_NAME:
 | 
			
		||||
    case CFSTORE_OPCODE_GET_STATUS:
 | 
			
		||||
    case CFSTORE_OPCODE_GET_VALUE_LEN:
 | 
			
		||||
    case CFSTORE_OPCODE_OPEN:
 | 
			
		||||
    case CFSTORE_OPCODE_POWER_CONTROL:
 | 
			
		||||
    case CFSTORE_OPCODE_READ:
 | 
			
		||||
    case CFSTORE_OPCODE_RSEEK:
 | 
			
		||||
    case CFSTORE_OPCODE_WRITE:
 | 
			
		||||
    default:
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:WARN: received asynchronous notification for opcode=%d (%s) when api call should have been synchronous", __func__, cmd_code, cmd_code < CFSTORE_OPCODE_MAX ? cfstore_test_opcode_str[cmd_code] : "unknown");
 | 
			
		||||
        CFSTORE_DBGLOG("%s:WARN: received asynchronous notification for opcode=%d (%s) when api call should have been synchronous", __func__, cmd_code, cmd_code < CFSTORE_OPCODE_MAX ? cfstore_test_opcode_str[cmd_code] : "unknown");
 | 
			
		||||
        /* TEST_ASSERT_MESSAGE(false, cfstore_flush_utest_msg_g) */
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    ctx->status = status;
 | 
			
		||||
    ctx->cmd_code = cmd_code;
 | 
			
		||||
    cfstore_flush_fsm_state_handle_event(&ctx->fsm, ctx->fsm.event, client_context);
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* @brief  fsm handler called on entry to stopping state */
 | 
			
		||||
static void cfstore_flush_fsm_stop_on_entry(void* context)
 | 
			
		||||
{
 | 
			
		||||
    (void) context;
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered:\r\n", __func__);
 | 
			
		||||
    Harness::validate_callback();
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* @brief  fsm handler called on entry to initializing state */
 | 
			
		||||
static void cfstore_flush_fsm_init_on_entry(void* context)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    cfstore_flush_ctx_t* ctx = (cfstore_flush_ctx_t*) context;
 | 
			
		||||
    const ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    /* check that the mtd is in synchronous mode */
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered: callback=%p, ctx=%p\r\n", __func__, cfstore_flush_test_01_callback, ctx);
 | 
			
		||||
    ret = drv->Initialize(cfstore_flush_test_01_callback, ctx);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to initialize CFSTORE (ret=%d)\r\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g);
 | 
			
		||||
    CFSTORE_DBGLOG("%s:debug: ret=%d\r\n", __func__, (int) ret);
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* brief    callback handler when in state initializing */
 | 
			
		||||
static void cfstore_flush_fsm_initializing(void* context)
 | 
			
		||||
{
 | 
			
		||||
    cfstore_flush_ctx_t* ctx = (cfstore_flush_ctx_t*) context;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\r\n", __func__);
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered: status = %d\r\n", __func__, (int) ctx->status);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: entered handler(%s) but not in initializing state (fsm->state=%d)\r\n", __func__, __func__, (int) ctx->fsm.state);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->fsm.state == cfstore_flush_fsm_state_initializing, cfstore_flush_utest_msg_g);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: cmd_code code (%d) is not as expected (%d)\r\n", __func__, ctx->cmd_code, CFSTORE_OPCODE_INITIALIZE);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->cmd_code == CFSTORE_OPCODE_INITIALIZE, cfstore_flush_utest_msg_g);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: status=%d\r\n", __func__, (int) ctx->status);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->status >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g);
 | 
			
		||||
    /* only change state if status >= 0*/
 | 
			
		||||
    if(ctx->status >= 0){
 | 
			
		||||
        cfstore_flush_fsm_state_set(&ctx->fsm, cfstore_flush_fsm_state_flushing, ctx);
 | 
			
		||||
    }
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* static void cfstore_flush_fsm_init_on_exit(void* context){ (void) context;} */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief  fsm handler called on entry to flushing state */
 | 
			
		||||
static void cfstore_flush_fsm_flush_on_entry(void* context)
 | 
			
		||||
{
 | 
			
		||||
    bool bfound = false;
 | 
			
		||||
    int32_t ivalue = 0;
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    const char* key_name_query = "*";
 | 
			
		||||
    char value[CFSTORE_KEY_NAME_MAX_LENGTH+1];
 | 
			
		||||
    ARM_CFSTORE_SIZE len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(next);
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(prev);
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
    cfstore_flush_ctx_t* ctx = (cfstore_flush_ctx_t*) context;
 | 
			
		||||
 | 
			
		||||
    /* check that the mtd is in synchronous mode */
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered: \r\n", __func__);
 | 
			
		||||
    memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: entered handler(%s) but not in flushing state (fsm->state=%d)\r\n", __func__, __func__, (int) ctx->fsm.state);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->fsm.state == cfstore_flush_fsm_state_flushing, cfstore_flush_utest_msg_g);
 | 
			
		||||
    /* try to read key; should not be found */
 | 
			
		||||
    ret = cfstore_test_kv_is_found(cfstore_flush_test_02_kv_data->key_name, &bfound);
 | 
			
		||||
    if(ret != ARM_DRIVER_OK && ret != ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND){
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: cfstore_test_kv_is_found() call failed (ret=%d).\r\n", __func__, (int) ret);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(false, cfstore_flush_utest_msg_g);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(!bfound)
 | 
			
		||||
    {
 | 
			
		||||
        /* first time start up. nothing is stored in cfstore flash. check this is the case */
 | 
			
		||||
        while(drv->Find(key_name_query, prev, next) == ARM_DRIVER_OK)
 | 
			
		||||
        {
 | 
			
		||||
            CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: have found an entry in cfstore when none should be present", __func__);
 | 
			
		||||
            TEST_ASSERT_MESSAGE(false, cfstore_flush_utest_msg_g);
 | 
			
		||||
        }
 | 
			
		||||
        /* no entries found, which is correct.
 | 
			
		||||
         * store a value */
 | 
			
		||||
        len = strlen(cfstore_flush_test_02_kv_data->value);
 | 
			
		||||
        ret = cfstore_test_create(cfstore_flush_test_02_kv_data->key_name, cfstore_flush_test_02_kv_data->value, &len, &kdesc);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error:1: failed to write kv data (ret=%d).\r\n", __func__, (int) ret);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g);
 | 
			
		||||
        /* flush to flash */
 | 
			
		||||
        ret = drv->Flush();
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to flush data to cfstore flash (ret=%d).\r\n", __func__, (int) ret);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g);
 | 
			
		||||
        /* revert to CFSTORE_LOG if more trace required */
 | 
			
		||||
        CFSTORE_DBGLOG("FLUSH: Success pending for new KV creation (name=%s, value=%s)\n", cfstore_flush_test_02_kv_data->key_name, cfstore_flush_test_02_kv_data->value);
 | 
			
		||||
    } else {
 | 
			
		||||
        /*read the value, increment by 1 and write value back */
 | 
			
		||||
        len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
 | 
			
		||||
        ret = cfstore_test_read(cfstore_flush_test_02_kv_data->key_name, value, &len);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to read kv data (ret=%d).\r\n", __func__, (int) ret);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
        ivalue = atoi(value);
 | 
			
		||||
        /* revert to CFSTORE_LOG if more trace required */
 | 
			
		||||
        CFSTORE_DBGLOG("FLUSH: Read KV from flash (name=%s, value=%d)\n", cfstore_flush_test_02_kv_data->key_name, (int) ivalue);
 | 
			
		||||
        /* increment value */
 | 
			
		||||
        ++ivalue;
 | 
			
		||||
        snprintf(value, CFSTORE_KEY_NAME_MAX_LENGTH+1, "%d", (int) ivalue);
 | 
			
		||||
        len = strlen(value);
 | 
			
		||||
        ret = cfstore_test_write(cfstore_flush_test_02_kv_data->key_name, value, &len);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write kv data (ret=%d).\r\n", __func__, (int) ret);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
        /* flush to flash */
 | 
			
		||||
        ret = drv->Flush();
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to flush data to cfstore flash (ret=%d).\r\n", __func__, (int) ret);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g);
 | 
			
		||||
        /* revert to CFSTORE_LOG if more trace required */
 | 
			
		||||
        CFSTORE_DBGLOG("FLUSH: Success pending for new KV value to flash (name=%s, value=%d)\n", cfstore_flush_test_02_kv_data->key_name, (int) ivalue);
 | 
			
		||||
    }
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* brief    callback handler when in state flushing */
 | 
			
		||||
static void cfstore_flush_fsm_flushing(void* context)
 | 
			
		||||
{
 | 
			
		||||
    cfstore_flush_ctx_t* ctx = (cfstore_flush_ctx_t*) context;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\r\n", __func__);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: entered handler(%s) but not in flushing state (fsm->state=%d)\r\n", __func__, __func__, (int) ctx->fsm.state);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->fsm.state == cfstore_flush_fsm_state_flushing, cfstore_flush_utest_msg_g);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: cmd_code code (%d) is not as expected (%d)\r\n", __func__, ctx->cmd_code, CFSTORE_OPCODE_FLUSH);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->cmd_code == CFSTORE_OPCODE_FLUSH, cfstore_flush_utest_msg_g);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: status=%d\r\n", __func__, (int) ctx->status);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->status >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g);
 | 
			
		||||
    /* only change state if status >= 0*/
 | 
			
		||||
    if(ctx->status >= 0){
 | 
			
		||||
        /* revert to CFSTORE_LOG if more trace required */
 | 
			
		||||
        CFSTORE_DBGLOG("FLUSH: Successfully flushed data to flash.%s", "\n");
 | 
			
		||||
        cfstore_flush_fsm_state_set(&ctx->fsm, cfstore_flush_fsm_state_uninitializing, ctx);
 | 
			
		||||
    }
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* static void cfstore_flush_fsm_flush_on_exit(void* context){ (void) context;} */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief  fsm handler called on entry to uninitializing state */
 | 
			
		||||
static void cfstore_flush_fsm_uninit_on_entry(void* context)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    cfstore_flush_ctx_t* ctx = (cfstore_flush_ctx_t*) context;
 | 
			
		||||
    const ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    /* check that the mtd is in synchronous mode */
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered: \r\n", __func__);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: entered handler(%s) but not in uninitializing state (fsm->state=%d)\r\n", __func__, __func__, (int) ctx->fsm.state);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->fsm.state == cfstore_flush_fsm_state_uninitializing, cfstore_flush_utest_msg_g);
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to uninitialize CFSTORE (ret=%d)\r\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g);
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* brief    callback handler when in state uninitializing */
 | 
			
		||||
static void cfstore_flush_fsm_uninitializing(void* context)
 | 
			
		||||
{
 | 
			
		||||
    cfstore_flush_ctx_t* ctx = (cfstore_flush_ctx_t*) context;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\r\n", __func__);
 | 
			
		||||
    CFSTORE_DBGLOG("%s:ctx->status=%d, ctx->loops_done=%d\r\n", __func__, (int) ctx->status, (int) ctx->loops_done);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: entered handler(%s) but not in uninitializing state (fsm->state=%d)\r\n", __func__, __func__, (int) ctx->fsm.state);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->fsm.state == cfstore_flush_fsm_state_uninitializing, cfstore_flush_utest_msg_g);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: cmd_code code (%d) is not as expected (%d)\r\n", __func__, ctx->cmd_code, CFSTORE_OPCODE_UNINITIALIZE);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->cmd_code == CFSTORE_OPCODE_UNINITIALIZE, cfstore_flush_utest_msg_g);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: status=%d\r\n", __func__, (int) ctx->status);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx->status >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g);
 | 
			
		||||
    /* only change state if status >= 0*/
 | 
			
		||||
    if(ctx->status >= ARM_DRIVER_OK){
 | 
			
		||||
        ++ctx->loops_done;
 | 
			
		||||
        if(ctx->loops_done < CFSTORE_FLUSH_FSM_LOOPS){
 | 
			
		||||
            cfstore_flush_fsm_state_set(&ctx->fsm, cfstore_flush_fsm_state_initializing, ctx);
 | 
			
		||||
        } else {
 | 
			
		||||
            /* move to init state */
 | 
			
		||||
            cfstore_flush_fsm_state_set(&ctx->fsm, cfstore_flush_fsm_state_stopped, ctx);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* static void cfstore_flush_fsm_uninit_on_exit(void* context) {(void)context;} */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* handler functions while in state */
 | 
			
		||||
static cfstore_flush_fsm_handler cfstore_flush_fsm[cfstore_flush_fsm_state_max][cfstore_flush_fsm_event_max] =
 | 
			
		||||
{
 | 
			
		||||
/* state\event:         init_done                           flush_done                      unint_done */
 | 
			
		||||
/* stopped          */  {cfstore_flush_fsm_null,            cfstore_flush_fsm_null,         cfstore_flush_fsm_null              },
 | 
			
		||||
/* initialising     */  {cfstore_flush_fsm_initializing,    cfstore_flush_fsm_null,         cfstore_flush_fsm_null              },
 | 
			
		||||
/* flushing         */  {cfstore_flush_fsm_null,            cfstore_flush_fsm_flushing,     cfstore_flush_fsm_null              },
 | 
			
		||||
/* uninitializing   */  {cfstore_flush_fsm_null,            cfstore_flush_fsm_null,         cfstore_flush_fsm_uninitializing    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* handler functions for entering the state*/
 | 
			
		||||
static cfstore_flush_fsm_handler cfstore_flush_fsm_on_entry[cfstore_flush_fsm_state_max] =
 | 
			
		||||
{
 | 
			
		||||
    cfstore_flush_fsm_stop_on_entry,
 | 
			
		||||
    cfstore_flush_fsm_init_on_entry,
 | 
			
		||||
    cfstore_flush_fsm_flush_on_entry,
 | 
			
		||||
    cfstore_flush_fsm_uninit_on_entry
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* handler functions for exiting state, currently none used */
 | 
			
		||||
static cfstore_flush_fsm_handler cfstore_flush_fsm_on_exit[cfstore_flush_fsm_state_max] =
 | 
			
		||||
{
 | 
			
		||||
    cfstore_flush_fsm_null,
 | 
			
		||||
    cfstore_flush_fsm_null,
 | 
			
		||||
    cfstore_flush_fsm_null,
 | 
			
		||||
    cfstore_flush_fsm_null
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   inject event into fsm */
 | 
			
		||||
static void cfstore_flush_fsm_state_handle_event(cfstore_fsm_t* fsm, cfstore_flush_fsm_event_t event, void* context)
 | 
			
		||||
{
 | 
			
		||||
    cfstore_flush_ctx_t* ctx = (cfstore_flush_ctx_t*) context;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered: fsm=%p, state=(%s), event=%d (%s), ctx=%p\r\n", __func__, fsm, cfstore_flush_state_str[fsm->state], (int) event, cfstore_flush_event_str[event], ctx);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: invalid event (%d)\r\n", __func__, (int) event);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(event < cfstore_flush_fsm_event_max, cfstore_flush_utest_msg_g);
 | 
			
		||||
    fsm->event = event;
 | 
			
		||||
    if(cfstore_flush_fsm[fsm->state][fsm->event] != NULL){
 | 
			
		||||
        cfstore_flush_fsm[fsm->state][fsm->event](ctx);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* do not clear context data set by caller as it may be used later
 | 
			
		||||
     *  fsm->event = cfstore_flush_fsm_event_max;
 | 
			
		||||
     *  ctx->status = 0;
 | 
			
		||||
     *  ctx->cmd_code =  (FlashJournal_OpCode_t)((int) FLASH_JOURNAL_OPCODE_RESET+1);
 | 
			
		||||
     */
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   function to move to new fsm state, calling state exit function for old state and entry function for new state */
 | 
			
		||||
static void cfstore_flush_fsm_state_set(cfstore_fsm_t* fsm, cfstore_flush_fsm_state_t new_state, void* ctx)
 | 
			
		||||
{
 | 
			
		||||
    #ifdef CFSTORE_DEBUG
 | 
			
		||||
    cfstore_flush_fsm_state_t old_state = fsm->state;
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered: fsm=%p, ctx=%p\r\n", __func__, fsm, ctx);
 | 
			
		||||
    #ifdef CFSTORE_DEBUG
 | 
			
		||||
    CFSTORE_DBGLOG("%s:FSM:REQ RX:%s:%s\r\n", __func__, cfstore_flush_state_str[fsm->state], cfstore_flush_state_str[new_state]);
 | 
			
		||||
    #endif
 | 
			
		||||
    TEST_ASSERT_MESSAGE(fsm != NULL, "fsm is not a valid pointer");
 | 
			
		||||
    TEST_ASSERT_MESSAGE(new_state < cfstore_flush_fsm_state_max, "new_state is not a valid state");
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx != NULL, "ctx is not a valid pointer");
 | 
			
		||||
    TEST_ASSERT_MESSAGE(fsm->state < cfstore_flush_fsm_state_max, "fsm->state is not a valid state");
 | 
			
		||||
 | 
			
		||||
    if(cfstore_flush_fsm_on_exit[fsm->state] != NULL){
 | 
			
		||||
        cfstore_flush_fsm_on_exit[fsm->state](ctx);
 | 
			
		||||
    }
 | 
			
		||||
    fsm->state = new_state;
 | 
			
		||||
    if(cfstore_flush_fsm_on_entry[new_state] != NULL){
 | 
			
		||||
        cfstore_flush_fsm_on_entry[new_state](ctx);
 | 
			
		||||
    }
 | 
			
		||||
    #ifdef CFSTORE_DEBUG
 | 
			
		||||
    CFSTORE_DBGLOG("%s:FSM:REQ DONE fsm=%p, fsm->state (old_state)=%s, new_state=%s, ctx=%p\r\n", __func__, fsm, cfstore_flush_state_str[old_state], cfstore_flush_state_str[new_state], ctx);
 | 
			
		||||
    #endif
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   asynchronous test 01 */
 | 
			
		||||
static control_t cfstore_flush_test_02_k64f(void)
 | 
			
		||||
{
 | 
			
		||||
    cfstore_flush_ctx_t* ctx = cfstore_flush_ctx_get();
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered: \r\n", __func__);
 | 
			
		||||
    cfstore_flush_ctx_init(ctx);
 | 
			
		||||
    cfstore_flush_fsm_state_set(&ctx->fsm, cfstore_flush_fsm_state_initializing, ctx);
 | 
			
		||||
    return CaseTimeout(CFSTORE_FLUSH_GREENTEA_TIMEOUT_S*1000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* report whether built/configured for flash sync or async mode */
 | 
			
		||||
static control_t cfstore_flush_test_00(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    ret = cfstore_test_startup();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to perform test startup (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(CFSTORE_FLUSH_GREENTEA_TIMEOUT_S, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
        Case("FLUSH_test_00", cfstore_flush_test_00),
 | 
			
		||||
        Case("FLUSH_test_01", cfstore_flush_test_02_k64f),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif // __MBED__ && ! defined TOOLCHAIN_GCC_ARM
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,279 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 flush2.cpp Test cases to flush KVs in the CFSTORE using the drv->Flush() interface.
 | 
			
		||||
 *
 | 
			
		||||
 * Please consult the documentation under the test-case functions for
 | 
			
		||||
 * a description of the individual test case.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "cfstore_utest.h"
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
/*
 | 
			
		||||
 * Defines
 | 
			
		||||
 */
 | 
			
		||||
#define CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE                256
 | 
			
		||||
#define cfstore_flush_fsm_null                          NULL
 | 
			
		||||
#define CFSTORE_FLUSH_CASE_TIMEOUT_MS                   10000
 | 
			
		||||
 | 
			
		||||
/* Configure secure box. */
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
UVISOR_BOX_NAMESPACE("com.arm.mbed.cfstore.test.flush2.box1");
 | 
			
		||||
UVISOR_BOX_CONFIG(cfstore_flush2_box1, UVISOR_BOX_STACK_SIZE);
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Globals
 | 
			
		||||
 *
 | 
			
		||||
 * cfstore_flush_utest_msg_g
 | 
			
		||||
 *  buffer for storing TEST_ASSERT_xxx_MESSAGE messages
 | 
			
		||||
 */
 | 
			
		||||
static char cfstore_flush_utest_msg_g[CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE];
 | 
			
		||||
 | 
			
		||||
/* KV data for test_03 */
 | 
			
		||||
static cfstore_kv_data_t cfstore_flush_test_02_kv_data[] = {
 | 
			
		||||
        { "com.arm.mbed.configurationstore.test.flush.cfstoreflushtest02", "1"},
 | 
			
		||||
        /*          1         2         3         4         5         6        7  */
 | 
			
		||||
        /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        { NULL, NULL},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* async test version */
 | 
			
		||||
 | 
			
		||||
typedef struct cfstore_flush_ctx_t
 | 
			
		||||
{
 | 
			
		||||
    int32_t status;
 | 
			
		||||
    ARM_CFSTORE_OPCODE cmd_code;
 | 
			
		||||
} cfstore_flush_ctx_t;
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Globals
 | 
			
		||||
 */
 | 
			
		||||
static cfstore_flush_ctx_t cfstore_flush_ctx_g;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * context related methods
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* @brief   get a pointer to the global context data structure */
 | 
			
		||||
static cfstore_flush_ctx_t* cfstore_flush_ctx_get(void)
 | 
			
		||||
{
 | 
			
		||||
    return &cfstore_flush_ctx_g;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* @brief   initialize global context data structure */
 | 
			
		||||
static void cfstore_flush_ctx_init(cfstore_flush_ctx_t* ctx)
 | 
			
		||||
{
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ctx != NULL, "ctx is NULL");
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\r\n", __func__);
 | 
			
		||||
    memset(&cfstore_flush_ctx_g, 0, sizeof(cfstore_flush_ctx_g));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* report whether built/configured for flash sync or async mode */
 | 
			
		||||
static control_t cfstore_flush2_test_00(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    ret = cfstore_test_startup();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to perform test startup (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t  cfstore_flush2_test_01_start(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    cfstore_flush_ctx_t* ctx = cfstore_flush_ctx_get();
 | 
			
		||||
    const ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    /* check that the mtd is in synchronous mode */
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered:\r\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    cfstore_flush_ctx_init(ctx);
 | 
			
		||||
    ret = drv->Initialize(cfstore_utest_default_callback, ctx);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to initialize CFSTORE (ret=%d)\r\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g);
 | 
			
		||||
    return CaseTimeout(100000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_flush2_test_01_mid(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    bool bfound = false;
 | 
			
		||||
    int32_t ivalue = 0;
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    const char* key_name_query = "*";
 | 
			
		||||
    char value[CFSTORE_KEY_NAME_MAX_LENGTH+1];
 | 
			
		||||
    ARM_CFSTORE_SIZE len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(next);
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(prev);
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
 | 
			
		||||
    /* check that the mtd is in synchronous mode */
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered: \r\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
 | 
			
		||||
    /* try to read key; should not be found */
 | 
			
		||||
    ret = cfstore_test_kv_is_found(cfstore_flush_test_02_kv_data->key_name, &bfound);
 | 
			
		||||
    if(ret != ARM_DRIVER_OK && ret != ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND){
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: cfstore_test_kv_is_found() call failed (ret=%d).\r\n", __func__, (int) ret);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(false, cfstore_flush_utest_msg_g);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(!bfound)
 | 
			
		||||
    {
 | 
			
		||||
        /* first time start up. nothing is stored in cfstore flash. check this is the case */
 | 
			
		||||
        while(drv->Find(key_name_query, prev, next) == ARM_DRIVER_OK)
 | 
			
		||||
        {
 | 
			
		||||
            CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: have found an entry in cfstore when none should be present", __func__);
 | 
			
		||||
            TEST_ASSERT_MESSAGE(false, cfstore_flush_utest_msg_g);
 | 
			
		||||
        }
 | 
			
		||||
        /* no entries found, which is correct.
 | 
			
		||||
         * store a value */
 | 
			
		||||
        len = strlen(cfstore_flush_test_02_kv_data->value);
 | 
			
		||||
        ret = cfstore_test_create(cfstore_flush_test_02_kv_data->key_name, cfstore_flush_test_02_kv_data->value, &len, &kdesc);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error:1: failed to write kv data (ret=%d).\r\n", __func__, (int) ret);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g);
 | 
			
		||||
        /* flush to flash */
 | 
			
		||||
        ret = drv->Flush();
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to flush data to cfstore flash (ret=%d).\r\n", __func__, (int) ret);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    } else {
 | 
			
		||||
        /*read the value, increment by 1 and write value back */
 | 
			
		||||
        len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
 | 
			
		||||
        ret = cfstore_test_read(cfstore_flush_test_02_kv_data->key_name, value, &len);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to read kv data (ret=%d).\r\n", __func__, (int) ret);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
        /* increment value */
 | 
			
		||||
        ivalue = atoi(value);
 | 
			
		||||
        ++ivalue;
 | 
			
		||||
        snprintf(value, CFSTORE_KEY_NAME_MAX_LENGTH+1, "%d", (int) ivalue);
 | 
			
		||||
        len = strlen(value);
 | 
			
		||||
        ret = cfstore_test_write(cfstore_flush_test_02_kv_data->key_name, value, &len);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write kv data (ret=%d).\r\n", __func__, (int) ret);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
        /* flush to flash */
 | 
			
		||||
        ret = drv->Flush();
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to flush data to cfstore flash (ret=%d).\r\n", __func__, (int) ret);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g);
 | 
			
		||||
    }
 | 
			
		||||
    return CaseTimeout(100000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t  cfstore_flush2_test_01_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    const ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered:\r\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(drv->Uninitialize() >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   test to open(create) a very large value, write the data, close, then flush.
 | 
			
		||||
 *          for a N keys simultaneously.
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_flush2_test_02(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    //todo: implement test
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Warn: Not implemented\n", __func__);
 | 
			
		||||
    CFSTORE_DBGLOG("%s: WARN: requires implementation\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(true, cfstore_flush_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    // Call the default reporting function-
 | 
			
		||||
    GREENTEA_SETUP(100, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
        Case("CFSTORE_FLUSH2_test_00", cfstore_flush2_test_00),
 | 
			
		||||
        Case("CFSTORE_FLUSH2_test_01_start", cfstore_flush2_test_01_start),
 | 
			
		||||
        Case("CFSTORE_FLUSH2_test_01_mid", cfstore_flush2_test_01_mid),
 | 
			
		||||
        Case("CFSTORE_FLUSH2_test_01_end", cfstore_flush2_test_01_end),
 | 
			
		||||
        Case("CFSTORE_FLUSH2_test_02_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("CFSTORE_FLUSH2_test_02_end", cfstore_flush2_test_02),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Declare your test specification with a custom setup handler
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
/// @endcond
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,886 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 flush3.cpp Test cases to flush KVs in the CFSTORE using the drv->Flush() interface.
 | 
			
		||||
 *
 | 
			
		||||
 * Please consult the documentation under the test-case functions for
 | 
			
		||||
 * a description of the individual test case.
 | 
			
		||||
 *
 | 
			
		||||
 * CFSTORE flash-journal sync mode test for github issue Heap Corruption by Jenia Kogan:
 | 
			
		||||
 *      https://github.com/ARMmbed/configuration-store/issues/17
 | 
			
		||||
 * No evidence of heap corruption has been found but the test case put together to
 | 
			
		||||
 * investiage that problem did result in a bug being found, that being that
 | 
			
		||||
 * when the last attribute was deleted from CFSTORE, this was not properly committed to
 | 
			
		||||
 * flash, so that CFSTORE was re-initialised, the old attribute was read back from
 | 
			
		||||
 * flash into the store. This has now been fixed.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#include "cfstore_uvisor.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
static char cfstore_flush3_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE];
 | 
			
		||||
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
/* Create the main box ACL list for the application.
 | 
			
		||||
 * The main ACL gets inherited by all the other boxes
 | 
			
		||||
 */
 | 
			
		||||
CFSTORE_UVISOR_MAIN_ACL(cfstore_acl_uvisor_box_flush3_g);
 | 
			
		||||
 | 
			
		||||
/* Enable uVisor. */
 | 
			
		||||
UVISOR_SET_MODE_ACL(UVISOR_ENABLED, cfstore_acl_uvisor_box_flush3_g);
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
#ifdef CFSTORE_DEBUG
 | 
			
		||||
#define CFSTORE_FLUSH3_GREENTEA_TIMEOUT_S     1000
 | 
			
		||||
#else
 | 
			
		||||
#define CFSTORE_FLUSH3_GREENTEA_TIMEOUT_S     100
 | 
			
		||||
#endif
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
/* used for sync mode build only */
 | 
			
		||||
#if defined STORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS && STORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS==0
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_UNUSED_PARAM(param)      (void)(param)
 | 
			
		||||
 | 
			
		||||
int32_t cfstore_flush3_end(void)
 | 
			
		||||
{
 | 
			
		||||
    int32_t cfsStatus;
 | 
			
		||||
    ARM_CFSTORE_DRIVER *cfstoreDriver = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s:IN\n", __func__);
 | 
			
		||||
    cfsStatus = cfstoreDriver->Uninitialize();
 | 
			
		||||
    if(cfsStatus < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_DBGLOG("CFStore Finalization failed (err %ld)\n", cfsStatus);
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    CFSTORE_DBGLOG("%s:OUT:returning ARM_DRIVER_OK\n", __func__);
 | 
			
		||||
    return ARM_DRIVER_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int32_t cfstore_flush3_delete_file(const char *fileDir, size_t maxFilePathSize, const char *fileName)
 | 
			
		||||
{
 | 
			
		||||
    int32_t cfsStatus;
 | 
			
		||||
    int32_t status = ARM_DRIVER_OK;
 | 
			
		||||
 | 
			
		||||
    ARM_CFSTORE_DRIVER *cfstoreDriver = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s:IN. File name %s\n", __func__, fileName);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_UNUSED_PARAM(fileDir);
 | 
			
		||||
    CFSTORE_UNUSED_PARAM(maxFilePathSize);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Uninitialize Cfstore\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfstoreDriver != NULL, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Invalid file name\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(fileName != NULL, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    memset(&flags, 0, sizeof(flags));
 | 
			
		||||
    flags.write = true;
 | 
			
		||||
    cfsStatus = cfstoreDriver->Open(fileName, flags, hkey);
 | 
			
		||||
    if (cfsStatus == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND) {
 | 
			
		||||
        /* printf added: modification to original code supplied by Jenia Kogan. */
 | 
			
		||||
        CFSTORE_DBGLOG("%s: cfsStatus == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND. returning success\n", __func__);
 | 
			
		||||
        return ARM_DRIVER_OK;
 | 
			
		||||
    }
 | 
			
		||||
    if(cfsStatus < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_DBGLOG("Open failed (err %ld)\n", cfsStatus);
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    cfsStatus = cfstoreDriver->Delete(hkey);
 | 
			
		||||
    if(cfsStatus < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_DBGLOG("Failed deleting (%s) failed (err %ld)\n", fileName, cfsStatus);
 | 
			
		||||
        status = ARM_DRIVER_ERROR;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
out:
 | 
			
		||||
    cfsStatus = cfstoreDriver->Close(hkey);
 | 
			
		||||
    if(cfsStatus < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_DBGLOG("Close failed (err %ld)\n", cfsStatus);
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    /* Flash-to-flash only on success */
 | 
			
		||||
    if (status == ARM_DRIVER_OK) {
 | 
			
		||||
        cfsStatus = cfstoreDriver->Flush();
 | 
			
		||||
        if(cfsStatus < ARM_DRIVER_OK){
 | 
			
		||||
            CFSTORE_DBGLOG("Flush to flash failed (err %ld)\n", cfsStatus);
 | 
			
		||||
            return ARM_DRIVER_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    CFSTORE_DBGLOG("%s:OUT: status=%d\n", __func__, (int) status);
 | 
			
		||||
    return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int32_t cfstore_flush3_read_file(const char *fileDir, size_t maxFilePathSize, const char *fileName, uint8_t *buff, size_t buffSize)
 | 
			
		||||
{
 | 
			
		||||
	int32_t cfsStatus;
 | 
			
		||||
	int32_t status = ARM_DRIVER_OK;
 | 
			
		||||
 | 
			
		||||
	ARM_CFSTORE_DRIVER *cfstoreDriver = &cfstore_driver;
 | 
			
		||||
	ARM_CFSTORE_FMODE flags;
 | 
			
		||||
	ARM_CFSTORE_SIZE readCount = buffSize;
 | 
			
		||||
	ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_DBGLOG("%s:IN. File name %s, buffer %p, buffsize %d\n", __func__, fileName, buff, buffSize);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_UNUSED_PARAM(fileDir);
 | 
			
		||||
	CFSTORE_UNUSED_PARAM(maxFilePathSize);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Uninitialize Cfstore\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfstoreDriver != NULL, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Invalid file name\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(fileName != NULL, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Invalid buff\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(buff != NULL, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
	memset(&flags, 0, sizeof(flags));
 | 
			
		||||
	flags.read = true;
 | 
			
		||||
 | 
			
		||||
	cfsStatus = cfstoreDriver->Open(fileName, flags, hkey);
 | 
			
		||||
	if(cfsStatus == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND){
 | 
			
		||||
	    CFSTORE_DBGLOG("File (%s) not found (err %ld)\n", fileName, cfsStatus);
 | 
			
		||||
	    return ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
    if(cfsStatus < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_DBGLOG("Open failed (err %ld)\n", cfsStatus);
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
	cfsStatus = cfstoreDriver->Read(hkey, buff, &readCount);
 | 
			
		||||
    if(cfsStatus < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_DBGLOG("Read failed (err %ld)\n", cfsStatus);
 | 
			
		||||
        status = ARM_DRIVER_ERROR;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
    if(readCount < buffSize){
 | 
			
		||||
        CFSTORE_DBGLOG("Read failed, amount is %zu while requested %zu\n", readCount, buffSize);
 | 
			
		||||
        status = ARM_DRIVER_ERROR;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
out:
 | 
			
		||||
	cfsStatus = cfstoreDriver->Close(hkey);
 | 
			
		||||
    if(cfsStatus < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_DBGLOG("Close failed (err %ld)\n", cfsStatus);
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    CFSTORE_DBGLOG("%s:OUT: status=%d\n", __func__, (int) status);
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t cfstore_flush3_write_file(const char *fileDir, size_t maxFilePathSize, const char *fileName, const uint8_t *buff, size_t buffSize)
 | 
			
		||||
{
 | 
			
		||||
	int32_t cfsStatus;
 | 
			
		||||
	int32_t status = ARM_DRIVER_ERROR;
 | 
			
		||||
 | 
			
		||||
	ARM_CFSTORE_DRIVER *cfstoreDriver = &cfstore_driver;
 | 
			
		||||
	ARM_CFSTORE_SIZE writeCount = buffSize;
 | 
			
		||||
	ARM_CFSTORE_KEYDESC keyDesc;
 | 
			
		||||
	ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_DBGLOG("%s:IN. File name %s, buffer %p, buffsize %d\n", __func__, fileName, buff, buffSize);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Uninitialize Cfstore\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfstoreDriver != NULL, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Invalid file name\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(fileName != NULL, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Invalid buff\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(buff != NULL, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
	/* We always deleting the old file and recreating a new one to preserve simplicity */
 | 
			
		||||
	CFSTORE_DBGLOG("Before delete%s", "\n");
 | 
			
		||||
 | 
			
		||||
	/* Delete the old file */
 | 
			
		||||
	status = cfstore_flush3_delete_file(fileDir, maxFilePathSize, fileName);
 | 
			
		||||
    if(status != ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_DBGLOG("Failed deleting (%s)\n", fileName);
 | 
			
		||||
        return status;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	CFSTORE_DBGLOG("After delete%s", "\n");
 | 
			
		||||
	/* Create a new file */
 | 
			
		||||
	memset(&keyDesc, 0, sizeof(keyDesc));
 | 
			
		||||
	keyDesc.drl = ARM_RETENTION_NVM;
 | 
			
		||||
	keyDesc.flags.read = true;
 | 
			
		||||
	keyDesc.flags.write = true;
 | 
			
		||||
	cfsStatus = cfstoreDriver->Create(fileName, buffSize, &keyDesc, hkey);
 | 
			
		||||
    if(cfsStatus < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_DBGLOG("Fail creating (%s) key-store (%ld)\n", fileName, cfsStatus);
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
	CFSTORE_DBGLOG("After create%s", "\n");
 | 
			
		||||
	cfsStatus = cfstoreDriver->Write(hkey, (const char *)buff, &writeCount);
 | 
			
		||||
    if(cfsStatus < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_DBGLOG("Write failed (err %ld)\n", cfsStatus);
 | 
			
		||||
        status = ARM_DRIVER_ERROR;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
    if(writeCount != buffSize){
 | 
			
		||||
        CFSTORE_DBGLOG("Write failed, amount is %d while requested is %d\n", (int)writeCount, (int)buffSize);
 | 
			
		||||
        status = ARM_DRIVER_ERROR;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
	CFSTORE_DBGLOG("After write%s", "\n");
 | 
			
		||||
out:
 | 
			
		||||
	cfsStatus = cfstoreDriver->Close(hkey);
 | 
			
		||||
    if(cfsStatus < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_DBGLOG("Close failed (err %ld)\n", cfsStatus);
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
	CFSTORE_DBGLOG("After close%s", "\n");
 | 
			
		||||
	/* Flash-to-flash only on success */
 | 
			
		||||
	if (status == ARM_DRIVER_OK) {
 | 
			
		||||
		cfsStatus = cfstoreDriver->Flush();
 | 
			
		||||
	    if(cfsStatus < ARM_DRIVER_OK){
 | 
			
		||||
	        CFSTORE_DBGLOG("Flush to flash failed(err %ld)\n", cfsStatus);
 | 
			
		||||
	        return ARM_DRIVER_ERROR;
 | 
			
		||||
	    }
 | 
			
		||||
		CFSTORE_DBGLOG("After flush%s", "\n");
 | 
			
		||||
	}		
 | 
			
		||||
    CFSTORE_DBGLOG("%s:OUT: status=%d\n", __func__, (int) status);
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int32_t cfstore_flush3_start(void)
 | 
			
		||||
{
 | 
			
		||||
	int32_t status = ARM_DRIVER_OK;
 | 
			
		||||
	int32_t cfsStatus;
 | 
			
		||||
	ARM_CFSTORE_DRIVER *cfstoreDriver = &cfstore_driver;
 | 
			
		||||
	ARM_CFSTORE_CAPABILITIES caps;
 | 
			
		||||
 | 
			
		||||
	CFSTORE_DBGLOG("%s:IN\n", __func__);
 | 
			
		||||
 | 
			
		||||
	/* Initialize configuration store */
 | 
			
		||||
	cfsStatus = cfstoreDriver->Initialize(NULL, NULL);
 | 
			
		||||
    if(cfsStatus < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_DBGLOG("CFStore Initialization failed (err %lu)\n", cfsStatus);
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
	/* Get capabilities */
 | 
			
		||||
	memset(&caps, 0, sizeof(caps));
 | 
			
		||||
	caps = cfstoreDriver->GetCapabilities();
 | 
			
		||||
    if(caps.asynchronous_ops == true){
 | 
			
		||||
        CFSTORE_DBGLOG("%s:Please configure CFstore to work in synchronous mode. This can be change in config.json file.\n", __func__);
 | 
			
		||||
        status = ARM_DRIVER_ERROR;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
    if(caps.uvisor_support_enabled == true){
 | 
			
		||||
        CFSTORE_DBGLOG("%s:Please enable uvisor spv box.\n", __func__);
 | 
			
		||||
        status = ARM_DRIVER_ERROR;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
	CFSTORE_DBGLOG("%s:OUT: returning ARM_DRIVER_OK\n", __func__);
 | 
			
		||||
	return ARM_DRIVER_OK; /* init succeeded */
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	/* init failed */
 | 
			
		||||
	(void) cfstore_flush3_end();
 | 
			
		||||
    CFSTORE_DBGLOG("%s:OUT: status=%d\n", __func__, (int) status);
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t cfstore_flush3_check_data(uint8_t* data, int32_t len, uint8_t val)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    for(i = 0; i < len; i++) {
 | 
			
		||||
        if(data[i] != val){
 | 
			
		||||
            /* found byte which doesnt have the expected data value */
 | 
			
		||||
            return ARM_DRIVER_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return ARM_DRIVER_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* @brief   test case to recreate the transactions documented in the
 | 
			
		||||
 *          issue 17 trace log.
 | 
			
		||||
 *
 | 
			
		||||
 * the test case was created by recreating the entries found in the
 | 
			
		||||
 * log report grepped from the trace log attached to githug issue 17:
 | 
			
		||||
 *  20160622_1321_grep_pv_configuration_store_issue_17_heap_corruption.txt
 | 
			
		||||
 *
 | 
			
		||||
 * This is what the test is intended to do:
 | 
			
		||||
 *  - A (setup)
 | 
			
		||||
 *  - cfstore_flush3_start
 | 
			
		||||
 *  - cfstore_flush3_write_file(com.arm.mbed.spv.sst.meta, len: 2280) to create KV
 | 
			
		||||
 *  - cfstore_flush3_write_file(com.arm.mbed.spv.sst.node.0, len: 220) to create KV
 | 
			
		||||
 *  - cfstore_flush3_end
 | 
			
		||||
 *  - B (setup?)
 | 
			
		||||
 *  - cfstore_flush3_start
 | 
			
		||||
 *  - cfstore_flush3_read_file(com.arm.mbed.spv.sst.meta)
 | 
			
		||||
 *  - cfstore_flush3_read_file(com.arm.mbed.spv.sst.node.0)
 | 
			
		||||
 *  - cfstore_flush3_end
 | 
			
		||||
 *  - C (delete everything)
 | 
			
		||||
 *  - cfstore_flush3_start
 | 
			
		||||
 *  - cfstore_flush3_delete_file(com.arm.mbed.spv.sst.node.0). this will work as the KV is present
 | 
			
		||||
 *  - cfstore_flush3_delete_file(com.arm.mbed.spv.sst.node.x) where x = {1..29}
 | 
			
		||||
 *  - cfstore_flush3_delete_file(name com.arm.mbed.spv.sst.meta).
 | 
			
		||||
 *      - this should work as the KV is present
 | 
			
		||||
 *      - however, its is seen to fail in the trace log for the issue.
 | 
			
		||||
 *  - cfstore_flush3_end
 | 
			
		||||
 *  - D
 | 
			
		||||
 *  - cfstore_flush3_start
 | 
			
		||||
 *  - cfstore_flush3_read_file(com.arm.mbed.spv.sst.meta). readd 2280 bytes and check correct
 | 
			
		||||
 *      - this should fail as the kv has been deleted.
 | 
			
		||||
 *  - cfstore_flush3_write_file(com.arm.mbed.spv.sst.node.0, len: 220) to create KV
 | 
			
		||||
 *  - cfstore_flush3_write_file(com.arm.mbed.spv.sst.meta, len: 2280) to create KV
 | 
			
		||||
 *  - cfstore_flush3_end
 | 
			
		||||
 *  - E
 | 
			
		||||
 *  - run C-D again, to delete everything
 | 
			
		||||
 *  - F
 | 
			
		||||
 *  - cfstore_flush3_start
 | 
			
		||||
 *  - cfstore_flush3_read_file(com.arm.mbed.spv.sst.meta). readd 2280 bytes and check correct
 | 
			
		||||
 *      - this should fail as the kv has been deleted.
 | 
			
		||||
 *  - cfstore_flush3_write_file(com.arm.mbed.spv.sst.node.0, len: 220) to create KV
 | 
			
		||||
 *  - cfstore_flush3_write_file(com.arm.mbed.spv.sst.meta, len: 2280) to create KV
 | 
			
		||||
 *  - cfstore_flush3_write_file(com.arm.mbed.spv.sst.node.0, len: 816) to create KV
 | 
			
		||||
 *  - cfstore_flush3_write_file(com.arm.mbed.spv.sst.meta, len: 2280) to create KV
 | 
			
		||||
 *  - cfstore_flush3_write_file(com.arm.mbed.spv.sst.node.1, len: 217) to create KV
 | 
			
		||||
 *  - cfstore_flush3_write_file(com.arm.mbed.spv.sst.meta, len: 2280) to create KV
 | 
			
		||||
 *  - cfstore_flush3_write_file(com.arm.mbed.spv.sst.node.0, len: 818) to create KV
 | 
			
		||||
 *  - cfstore_flush3_write_file(com.arm.mbed.spv.sst.meta, len: 2280) to create KV
 | 
			
		||||
 *  - cfstore_flush3_end
 | 
			
		||||
 *  - G
 | 
			
		||||
 *  - cfstore_flush3_start
 | 
			
		||||
 *  - cfstore_flush3_read_file(com.arm.mbed.spv.sst.meta) 2280 bytes should be read
 | 
			
		||||
 *  - cfstore_flush3_read_file(com.arm.mbed.spv.sst.node.0) 818 bytes should be read
 | 
			
		||||
 *  - cfstore_flush3_read_file(com.arm.mbed.spv.sst.node.1) 217 bytes should be read
 | 
			
		||||
 *  - cfstore_flush3_read_file(com.arm.mbed.spv.sst.node.1) 217 bytes should be read
 | 
			
		||||
 *  - cfstore_flush3_read_file(com.arm.mbed.spv.sst.node.1) 217 bytes should be read
 | 
			
		||||
 *  - cfstore_flush3_read_file(com.arm.mbed.spv.sst.node.1) 217 bytes should be read
 | 
			
		||||
 *  - cfstore_flush3_write_file(com.arm.mbed.spv.sst.node.2, len: 235) to create KV
 | 
			
		||||
 *  - cfstore_flush3_write_file(com.arm.mbed.spv.sst.meta, len: 2280) to create KV
 | 
			
		||||
 *  - cfstore_flush3_end
 | 
			
		||||
 *
 | 
			
		||||
 *  The issue reported heap corruption. To this end, a heap buffer
 | 
			
		||||
 *  is allocated and checked as a canary against heap corruption
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_FLUSH3_TEST_DATA_CHAR      'A'         /* 0b1010 bit pattern */
 | 
			
		||||
#define CFSTORE_FLUSH3_HEAP_DATA_CHAR      'Z'
 | 
			
		||||
#define CFSTORE_FLUSH3_TEST_DATA_BUF_LEN   3000        /* 2280 was the largest buffer used*/
 | 
			
		||||
 | 
			
		||||
#ifdef TARGET_K64F
 | 
			
		||||
#define CFSTORE_FLUSH3_TEST_HEAP_BUF_LEN   87500       /* alloc a heap buffer to use up some memory: value tuned to K64F */
 | 
			
		||||
#else
 | 
			
		||||
#define CFSTORE_FLUSH3_TEST_HEAP_BUF_LEN   1000        /* alloc a heap buffer to use up some memory (minimal for non-k64f targets until tuned */
 | 
			
		||||
#endif /* TARGET_K64F */
 | 
			
		||||
 | 
			
		||||
static control_t cfstore_flush3_test_01(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t i;
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    const char* kv_name_root = "com.arm.mbed.spv.sst";
 | 
			
		||||
    const char* kv_name_node= "node";
 | 
			
		||||
    const char* kv_name_meta= "meta";
 | 
			
		||||
    char kv_name[CFSTORE_KEY_NAME_MAX_LENGTH+1];
 | 
			
		||||
    uint8_t data[CFSTORE_FLUSH3_TEST_DATA_BUF_LEN];
 | 
			
		||||
    void* heap_buf = NULL;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    heap_buf = malloc(CFSTORE_FLUSH3_TEST_HEAP_BUF_LEN);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  malloc() failed .\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(heap_buf != NULL, cfstore_flush3_utest_msg_g);
 | 
			
		||||
    memset(heap_buf, CFSTORE_FLUSH3_HEAP_DATA_CHAR, CFSTORE_FLUSH3_TEST_HEAP_BUF_LEN);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: - A (setup)\n", __func__);
 | 
			
		||||
    CFSTORE_DBGLOG("%s: - cfstore_flush3_start\n", __func__);
 | 
			
		||||
    ret = cfstore_flush3_start();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  A.1 cfstore_flush3_start() failed (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_write_file(com.arm.mbed.spv.sst.meta, len: 2280) to create KV\n", __func__);
 | 
			
		||||
    memset(data, CFSTORE_FLUSH3_TEST_DATA_CHAR, CFSTORE_FLUSH3_TEST_DATA_BUF_LEN);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s", (char*) kv_name_root, kv_name_meta);
 | 
			
		||||
    ret = cfstore_flush3_write_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name, (const uint8_t*) data, 2280);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  A.2 cfstore_flush3_write_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_write_file(com.arm.mbed.spv.sst.node.0, len: 220) to create KV\n", __func__);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s.0", (char*) kv_name_root, (char*) kv_name_node);
 | 
			
		||||
    ret = cfstore_flush3_write_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name, (const uint8_t*) data, 220);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  A.3 cfstore_flush3_write_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: - cfstore_flush3_end\n", __func__);
 | 
			
		||||
    ret = cfstore_flush3_end();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  A.4 cfstore_flush3_end() failed (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: check for heap corruption\n", __func__);
 | 
			
		||||
    ret = cfstore_flush3_check_data((uint8_t*) heap_buf, CFSTORE_FLUSH3_TEST_HEAP_BUF_LEN, CFSTORE_FLUSH3_HEAP_DATA_CHAR);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  A.5 cfstore_flush3_check_data() failed for heap (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: - B\n", __func__);
 | 
			
		||||
    CFSTORE_DBGLOG("%s: - cfstore_flush3_start\n", __func__);
 | 
			
		||||
    ret = cfstore_flush3_start();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  B.1 cfstore_flush3_start() failed (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_read_file(com.arm.mbed.spv.sst.meta). read 2280\n", __func__);
 | 
			
		||||
    memset(data, 0, CFSTORE_FLUSH3_TEST_DATA_BUF_LEN);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s", (char*) kv_name_root, (char*) kv_name_meta);
 | 
			
		||||
    ret = cfstore_flush3_read_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name, data, 2280);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  B.2 cfstore_flush3_read_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    ret = cfstore_flush3_check_data(data, 2280, CFSTORE_FLUSH3_TEST_DATA_CHAR);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  B.3 cfstore_flush3_check_data() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_read_file(com.arm.mbed.spv.sst.node.0). read 220\n", __func__);
 | 
			
		||||
    memset(data, 0, CFSTORE_FLUSH3_TEST_DATA_BUF_LEN);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s.0", (char*) kv_name_root, (char*) kv_name_node);
 | 
			
		||||
    ret = cfstore_flush3_read_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name, data, 220);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  B.4 cfstore_flush3_read_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    ret = cfstore_flush3_check_data(data, 220, CFSTORE_FLUSH3_TEST_DATA_CHAR);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  B.5 cfstore_flush3_check_data() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: - cfstore_flush3_end\n", __func__);
 | 
			
		||||
    ret = cfstore_flush3_end();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  B.6 cfstore_flush3_end() failed (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: check for heap corruption\n", __func__);
 | 
			
		||||
    ret = cfstore_flush3_check_data((uint8_t*) heap_buf, CFSTORE_FLUSH3_TEST_HEAP_BUF_LEN, CFSTORE_FLUSH3_HEAP_DATA_CHAR);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  B.7 cfstore_flush3_check_data() failed for heap (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: - C (delete everything)\n", __func__);
 | 
			
		||||
    CFSTORE_DBGLOG("%s: - cfstore_flush3_start\n", __func__);
 | 
			
		||||
    ret = cfstore_flush3_start();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  C.1 cfstore_flush3_start() failed (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_delete_file(com.arm.mbed.spv.sst.node.0). this will work as the KV is present\n", __func__);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s.0", (char*) kv_name_root, (char*) kv_name_node);
 | 
			
		||||
    ret = cfstore_flush3_delete_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  C.2 cfstore_flush3_delete_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_delete_file(com.arm.mbed.spv.sst.node.x) where x = {1..29}, each of which should fail\n", __func__);
 | 
			
		||||
    for(i = 1; i <= 29; i++){
 | 
			
		||||
        snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s.%d", (char*) kv_name_root, (char*) kv_name_node, (int) i);
 | 
			
		||||
        ret = cfstore_flush3_delete_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  C.%d cfstore_flush3_delete_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) i+2, (int) ret, kv_name);
 | 
			
		||||
        /* The delete operations are expected to fail as the keys dont exist
 | 
			
		||||
         * but cfstore_flush3_delete_file() returns ARM_DRIVER_OK when key isnt found, so cant test the return code.
 | 
			
		||||
         */
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_delete_file(name com.arm.mbed.spv.sst.meta). this is expected to succeed as the KV is present\n", __func__);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s", (char*) kv_name_root, (char*) kv_name_meta);
 | 
			
		||||
    ret = cfstore_flush3_delete_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  C.32 cfstore_flush3_delete_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
#ifdef CFSTORE_DEBUG
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_test_dump: dump here contents of CFSTORE so we know whats present\n", __func__);
 | 
			
		||||
    ret = cfstore_test_dump();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  D.1.1 cfstore_test_dump failed (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
#endif  /* CFSTORE_DEBUG */
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: - cfstore_flush3_end\n", __func__);
 | 
			
		||||
    ret = cfstore_flush3_end();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  C.33 cfstore_flush3_end() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: check for heap corruption\n", __func__);
 | 
			
		||||
    ret = cfstore_flush3_check_data((uint8_t*) heap_buf, CFSTORE_FLUSH3_TEST_HEAP_BUF_LEN, CFSTORE_FLUSH3_HEAP_DATA_CHAR);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  C.34 cfstore_flush3_check_data() failed for heap (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: - D\n", __func__);
 | 
			
		||||
    CFSTORE_DBGLOG("%s: - cfstore_flush3_start\n", __func__);
 | 
			
		||||
    ret = cfstore_flush3_start();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  D.1 cfstore_flush3_start() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
#ifdef CFSTORE_DEBUG
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_test_dump: dump here contents of CFSTORE so we know whats present\n", __func__);
 | 
			
		||||
    ret = cfstore_test_dump();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  D.1.1 cfstore_test_dump failed (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
#endif  /* CFSTORE_DEBUG */
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_read_file(com.arm.mbed.spv.sst.meta). this should fail as the kv has been deleted.\n", __func__);
 | 
			
		||||
    memset(data, 0, CFSTORE_FLUSH3_TEST_DATA_BUF_LEN);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s", (char*) kv_name_root, (char*) kv_name_meta);
 | 
			
		||||
    ret = cfstore_flush3_read_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name, data, 2280);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  D.2 cfstore_flush3_read_file() succeeded when expected to fail (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret < ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_write_file(com.arm.mbed.spv.sst.node.0, len: 220) to create KV.\n", __func__);
 | 
			
		||||
    memset(data, CFSTORE_FLUSH3_TEST_DATA_CHAR, CFSTORE_FLUSH3_TEST_DATA_BUF_LEN);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s.0", (char*) kv_name_root, (char*) kv_name_node);
 | 
			
		||||
    ret = cfstore_flush3_write_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name, (const uint8_t*) data, 220);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  D.3 cfstore_flush3_write_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_write_file(com.arm.mbed.spv.sst.meta, len: 2280) to create KV.\n", __func__);
 | 
			
		||||
    memset(data, CFSTORE_FLUSH3_TEST_DATA_CHAR, CFSTORE_FLUSH3_TEST_DATA_BUF_LEN);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s", (char*) kv_name_root, (char*) kv_name_meta);
 | 
			
		||||
    ret = cfstore_flush3_write_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name, (const uint8_t*) data, 2280);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  D.4 cfstore_flush3_write_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: - cfstore_flush3_end\n", __func__);
 | 
			
		||||
    ret = cfstore_flush3_end();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  D.5 cfstore_flush3_end() failed (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: check for heap corruption\n", __func__);
 | 
			
		||||
    ret = cfstore_flush3_check_data((uint8_t*) heap_buf, CFSTORE_FLUSH3_TEST_HEAP_BUF_LEN, CFSTORE_FLUSH3_HEAP_DATA_CHAR);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  D.6 cfstore_flush3_check_data() failed for heap (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: - E: run C-D again, to delete everything\n", __func__);
 | 
			
		||||
    CFSTORE_DBGLOG("%s: - cfstore_flush3_start\n", __func__);
 | 
			
		||||
    ret = cfstore_flush3_start();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  E.1 cfstore_flush3_start() failed (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_delete_file(com.arm.mbed.spv.sst.node.0). this will work as the KV is present.\n", __func__);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s.0", (char*) kv_name_root, (char*) kv_name_node);
 | 
			
		||||
    ret = cfstore_flush3_delete_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  E.2 cfstore_flush3_delete_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_delete_file(com.arm.mbed.spv.sst.node.x) where x = {1..29}, each of which should fail.\n", __func__);
 | 
			
		||||
    for(i = 1; i <= 29; i++){
 | 
			
		||||
        snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s.%d", (char*) kv_name_root, (char*) kv_name_node, (int) i);
 | 
			
		||||
        ret = cfstore_flush3_delete_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  E.%d cfstore_flush3_delete_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) i+2, (int) ret, kv_name);
 | 
			
		||||
        /* The delete operations are expected to fail as the keys dont exist
 | 
			
		||||
         * but cfstore_flush3_delete_file() returns ARM_DRIVER_OK when key isnt found, so cant test the return code.
 | 
			
		||||
         */
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_delete_file(name com.arm.mbed.spv.sst.meta). this is expected to succeed as the KV is present.\n", __func__);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s", (char*) kv_name_root, (char*) kv_name_meta);
 | 
			
		||||
    ret = cfstore_flush3_delete_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  E.32 cfstore_flush3_delete_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: - cfstore_flush3_end\n", __func__);
 | 
			
		||||
    ret = cfstore_flush3_end();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  E.33 cfstore_flush3_end() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: check for heap corruption\n", __func__);
 | 
			
		||||
    ret = cfstore_flush3_check_data((uint8_t*) heap_buf, CFSTORE_FLUSH3_TEST_HEAP_BUF_LEN, CFSTORE_FLUSH3_HEAP_DATA_CHAR);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  E.34 cfstore_flush3_check_data() failed for heap (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: - F\n", __func__);
 | 
			
		||||
    CFSTORE_DBGLOG("%s: - cfstore_flush3_start\n", __func__);
 | 
			
		||||
    ret = cfstore_flush3_start();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  F.1 cfstore_flush3_start() failed (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_read_file(com.arm.mbed.spv.sst.meta). this should fail as the kv has been deleted.\n", __func__);
 | 
			
		||||
    memset(data, 0, CFSTORE_FLUSH3_TEST_DATA_BUF_LEN);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s", (char*) kv_name_root, (char*) kv_name_meta);
 | 
			
		||||
    ret = cfstore_flush3_read_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name, data, 2280);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  F.2 cfstore_flush3_read_file() succeeded when expected to fail (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret < ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    memset(data, CFSTORE_FLUSH3_TEST_DATA_CHAR, CFSTORE_FLUSH3_TEST_DATA_BUF_LEN);
 | 
			
		||||
    /* cfstore_flush3_write_file(com.arm.mbed.spv.sst.node.0, len: 220) to create KV */
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s.0", (char*) kv_name_root, (char*) kv_name_node);
 | 
			
		||||
    ret = cfstore_flush3_write_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name, (const uint8_t*) data, 220);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  F.3 cfstore_flush3_write_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_write_file(com.arm.mbed.spv.sst.meta, len: 2280) to create KV.\n", __func__);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s", (char*) kv_name_root, (char*) kv_name_meta);
 | 
			
		||||
    ret = cfstore_flush3_write_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name, (const uint8_t*) data, 2280);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  F.4 cfstore_flush3_write_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_write_file(com.arm.mbed.spv.sst.node.0, len: 816) to create KV.\n", __func__);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s.0", (char*) kv_name_root, (char*) kv_name_node);
 | 
			
		||||
    ret = cfstore_flush3_write_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name, (const uint8_t*) data, 816);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  F.5 cfstore_flush3_write_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_write_file(com.arm.mbed.spv.sst.meta, len: 2280) to create KV.\n", __func__);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s", (char*) kv_name_root, (char*) kv_name_meta);
 | 
			
		||||
    ret = cfstore_flush3_write_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name, (const uint8_t*) data, 2280);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  F.6 cfstore_flush3_write_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_write_file(com.arm.mbed.spv.sst.node.1, len: 217) to create KV.\n", __func__);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s.1", (char*) kv_name_root, (char*) kv_name_node);
 | 
			
		||||
    ret = cfstore_flush3_write_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name, (const uint8_t*) data, 217);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  F.7 cfstore_flush3_write_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_write_file(com.arm.mbed.spv.sst.meta, len: 2280) to create KV.\n", __func__);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s", (char*) kv_name_root, (char*) kv_name_meta);
 | 
			
		||||
    ret = cfstore_flush3_write_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name, (const uint8_t*) data, 2280);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  F.8 cfstore_flush3_write_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_write_file(com.arm.mbed.spv.sst.node.0, len: 818) to create KV.\n", __func__);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s.0", (char*) kv_name_root, (char*) kv_name_node);
 | 
			
		||||
    ret = cfstore_flush3_write_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name, (const uint8_t*) data, 818);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  F.9 cfstore_flush3_write_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_write_file(com.arm.mbed.spv.sst.meta, len: 2280) to create KV.\n", __func__);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s", (char*) kv_name_root, (char*) kv_name_meta);
 | 
			
		||||
    ret = cfstore_flush3_write_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name, (const uint8_t*) data, 2280);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  F.10 cfstore_flush3_write_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: - cfstore_flush3_end\n", __func__);
 | 
			
		||||
    ret = cfstore_flush3_end();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  F.11 cfstore_flush3_end() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: check for heap corruption\n", __func__);
 | 
			
		||||
    ret = cfstore_flush3_check_data((uint8_t*) heap_buf, CFSTORE_FLUSH3_TEST_HEAP_BUF_LEN, CFSTORE_FLUSH3_HEAP_DATA_CHAR);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  F.12 cfstore_flush3_check_data() failed for heap (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: - G\n", __func__);
 | 
			
		||||
    CFSTORE_DBGLOG("%s: - cfstore_flush3_start\n", __func__);
 | 
			
		||||
    ret = cfstore_flush3_start();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  G.1 cfstore_flush3_start() failed (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_read_file(com.arm.mbed.spv.sst.meta) 2280 bytes should be read.\n", __func__);
 | 
			
		||||
    memset(data, 0, CFSTORE_FLUSH3_TEST_DATA_BUF_LEN);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s", (char*) kv_name_root, (char*) kv_name_meta);
 | 
			
		||||
    ret = cfstore_flush3_read_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name, data, 2280);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  G.2 cfstore_flush3_read_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    ret = cfstore_flush3_check_data(data, 2280, CFSTORE_FLUSH3_TEST_DATA_CHAR);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  G.3 cfstore_flush3_check_data() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_read_file(com.arm.mbed.spv.sst.node.0) 818 bytes should be read.\n", __func__);
 | 
			
		||||
    memset(data, 0, CFSTORE_FLUSH3_TEST_DATA_BUF_LEN);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s.0", (char*) kv_name_root, (char*) kv_name_node);
 | 
			
		||||
    ret = cfstore_flush3_read_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name, data, 818);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  G.4 cfstore_flush3_read_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    ret = cfstore_flush3_check_data(data, 818, CFSTORE_FLUSH3_TEST_DATA_CHAR);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  G.5 cfstore_flush3_check_data() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_read_file(com.arm.mbed.spv.sst.node.1) 217 bytes should be read. repeat 4 times.\n", __func__);
 | 
			
		||||
    for(i = 0; i < 4; i++){
 | 
			
		||||
        memset(data, 0, CFSTORE_FLUSH3_TEST_DATA_BUF_LEN);
 | 
			
		||||
        snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s.1", (char*) kv_name_root, (char*) kv_name_node);
 | 
			
		||||
        ret = cfstore_flush3_read_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name, data, 217);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  G.%d.1 cfstore_flush3_read_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) i+6, (int) ret, kv_name);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
        ret = cfstore_flush3_check_data(data, 217, CFSTORE_FLUSH3_TEST_DATA_CHAR);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  G.%d.2 cfstore_flush3_check_data() failed (ret=%d, kv_name=%s).\n", __func__, (int) i+6, (int) ret, kv_name);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    memset(data, CFSTORE_FLUSH3_TEST_DATA_CHAR, CFSTORE_FLUSH3_TEST_DATA_BUF_LEN);
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_write_file(com.arm.mbed.spv.sst.node.2, len: 235) to create KV.\n", __func__);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s.0", (char*) kv_name_root, (char*) kv_name_node);
 | 
			
		||||
    ret = cfstore_flush3_write_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name, (const uint8_t*) data, 235);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  F.3 cfstore_flush3_write_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: cfstore_flush3_write_file(com.arm.mbed.spv.sst.meta, len: 2280) to create KV.\n", __func__);
 | 
			
		||||
    memset(data, CFSTORE_FLUSH3_TEST_DATA_CHAR, CFSTORE_FLUSH3_TEST_DATA_BUF_LEN);
 | 
			
		||||
    snprintf(kv_name, CFSTORE_KEY_NAME_MAX_LENGTH, "%s.%s", (char*) kv_name_root, (char*) kv_name_meta);
 | 
			
		||||
    ret = cfstore_flush3_write_file(NULL, CFSTORE_KEY_NAME_MAX_LENGTH, (const char*) kv_name, (const uint8_t*) data, 2280);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  A.2 cfstore_flush3_write_file() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: - cfstore_flush3_end\n", __func__);
 | 
			
		||||
    ret = cfstore_flush3_end();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  F.11 cfstore_flush3_end() failed (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s: check for heap corruption\n", __func__);
 | 
			
		||||
    ret = cfstore_flush3_check_data((uint8_t*) heap_buf, CFSTORE_FLUSH3_TEST_HEAP_BUF_LEN, CFSTORE_FLUSH3_HEAP_DATA_CHAR);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:  A.5 cfstore_flush3_check_data() failed for heap (ret=%d, kv_name=%s).\n", __func__, (int) ret, kv_name);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    if(heap_buf){
 | 
			
		||||
        free(heap_buf);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   simple flush test */
 | 
			
		||||
static control_t cfstore_flush3_test_02(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t cfsStatus = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
    ARM_CFSTORE_SIZE len = strlen("key0");
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
    memset(&flags, 0, sizeof(flags));
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s:Initialize()\n", __func__);
 | 
			
		||||
    cfsStatus = drv->Initialize(NULL, NULL);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:%d:cfsStatus=%d", __func__, __LINE__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s:Create()\n", __func__);
 | 
			
		||||
    cfsStatus = drv->Create("key0", len, &kdesc, hkey);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:%d:cfsStatus=%d", __func__, __LINE__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    len = strlen("some-value");
 | 
			
		||||
    CFSTORE_DBGLOG("%s:Write()\n", __func__);
 | 
			
		||||
    cfsStatus = drv->Write(hkey, "some-value", &len);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:%d:cfsStatus=%d", __func__, __LINE__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s:Close()\n", __func__);
 | 
			
		||||
    cfsStatus = drv->Close(hkey);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:%d:cfsStatus=%d", __func__, __LINE__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s:Flush()\n", __func__);
 | 
			
		||||
    cfsStatus = drv->Flush();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:%d:cfsStatus=%d", __func__, __LINE__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s:Open()\n", __func__);
 | 
			
		||||
    cfsStatus = drv->Open("key0", flags, hkey);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:%d:cfsStatus=%d", __func__, __LINE__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s:Delete()\n", __func__);
 | 
			
		||||
    cfsStatus = drv->Delete(hkey);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:%d:cfsStatus=%d", __func__, __LINE__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s:Close()\n", __func__);
 | 
			
		||||
    cfsStatus = drv->Close(hkey);       ///////  <--- cfsStatus = ARM_CFSTORE_DRIVER_ERROR_PREEXISTING_KEY
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:%d:cfsStatus=%d", __func__, __LINE__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s:got status = %d\n", __func__, (int) cfsStatus);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s:Uninitialize()\n", __func__);
 | 
			
		||||
    cfsStatus = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error:%d:cfsStatus=%d", __func__, __LINE__, (int) cfsStatus);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* STORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS && STORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS==0 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static control_t cfstore_flush3_test_00(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_CAPABILITIES caps;;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    (void) 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){
 | 
			
		||||
        /* 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");
 | 
			
		||||
        return CaseNext;
 | 
			
		||||
    }
 | 
			
		||||
    ret = cfstore_test_startup();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush3_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to perform test startup (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush3_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(CFSTORE_FLUSH3_GREENTEA_TIMEOUT_S, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
           /*          1         2         3         4         5         6        7  */
 | 
			
		||||
           /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        Case("FLUSH3_test_00", cfstore_flush3_test_00),
 | 
			
		||||
#if defined STORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS && STORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS==0
 | 
			
		||||
        Case("FLUSH3_test_01", cfstore_flush3_test_01),
 | 
			
		||||
        Case("FLUSH3_test_02", cfstore_flush3_test_02),
 | 
			
		||||
#endif // STORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
/* mbedosV3++*/
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
/// @cond
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,156 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 init.cpp Test cases to test CFSTORE initialization/uninitialization code.
 | 
			
		||||
 *
 | 
			
		||||
 * Please consult the documentation under the test-case functions for
 | 
			
		||||
 * a description of the individual test case.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#ifdef YOTTA_CFG_CONFIG_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CONFIG_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
static char cfstore_init_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE];
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
typedef struct cfstore_init_ctx_t
 | 
			
		||||
{
 | 
			
		||||
    ARM_CFSTORE_CAPABILITIES caps;
 | 
			
		||||
} cfstore_init_ctx_t;
 | 
			
		||||
 | 
			
		||||
static cfstore_init_ctx_t cfstore_init_ctx_g;
 | 
			
		||||
extern ARM_CFSTORE_DRIVER cfstore_driver;
 | 
			
		||||
ARM_CFSTORE_DRIVER *cfstore_drv = &cfstore_driver;
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* report whether built/configured for flash sync or async mode */
 | 
			
		||||
static control_t cfstore_init_test_00(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    ret = cfstore_test_startup();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_init_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to perform test startup (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_init_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cfstore_init_test_01(cfstore_init_ctx_t* ctx)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret;
 | 
			
		||||
 | 
			
		||||
    (void) ctx;
 | 
			
		||||
	CFSTORE_DBGLOG("INITIALIZING%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Initialize(NULL, NULL);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_init_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Initialize() should return ret >= 0 for async/synch modes(ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
	TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_init_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_DBGLOG("FLUSHING1%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Flush();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_init_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Flush() failed (ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
	TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_init_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_DBGLOG("UNINITIALIZING%s", "\r\n");
 | 
			
		||||
	ret = cfstore_drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_init_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() should return ret >= 0 for synch mode(ret=%ld)\r\n", __func__, ret);
 | 
			
		||||
	TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_init_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
	CFSTORE_DBGLOG("***************%s", "\r\n");
 | 
			
		||||
	CFSTORE_DBGLOG("*** SUCCESS ***%s", "\r\n");
 | 
			
		||||
	CFSTORE_DBGLOG("***************%s", "\r\n");
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static control_t cfstore_init_app_start(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    cfstore_init_ctx_t* ctx = &cfstore_init_ctx_g;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
 | 
			
		||||
    /* initialise the context */
 | 
			
		||||
    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){
 | 
			
		||||
    	/* 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");
 | 
			
		||||
        return CaseNext;
 | 
			
		||||
    }
 | 
			
		||||
    cfstore_init_test_01(ctx);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifndef YOTTA_CONFIGURATION_STORE_INIT_VERSION_STRING
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* when built as Configuration-Store example, include greentea support otherwise omit */
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(100, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
           /*          1         2         3         4         5         6        7  */
 | 
			
		||||
           /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        Case("INIT_test_00", cfstore_init_test_00),
 | 
			
		||||
        Case("INIT_test_01_start", cfstore_init_app_start),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#else   // YOTTA_CONFIGURATION_STORE_INIT_VERSION_STRING
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// stand alone Configuration-Store-Example
 | 
			
		||||
void app_start(int argc __unused, char** argv __unused)
 | 
			
		||||
{
 | 
			
		||||
    cfstore_init_app_start(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif // YOTTA_CONFIGURATION_STORE_INIT_VERSION_STRING
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,340 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 misc.cpp Test cases for miscellaneous API drv->Xxx() functions.
 | 
			
		||||
 *
 | 
			
		||||
 * Please consult the documentation under the test-case functions for
 | 
			
		||||
 * a description of the individual test case.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#include "cfstore_utest.h"
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#include "cfstore_uvisor.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
static char cfstore_misc_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE];
 | 
			
		||||
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
/* Create the main box ACL list for the application.
 | 
			
		||||
 * The main ACL gets inherited by all the other boxes
 | 
			
		||||
 */
 | 
			
		||||
CFSTORE_UVISOR_MAIN_ACL(cfstore_acl_uvisor_box_misc_g);
 | 
			
		||||
 | 
			
		||||
/* Enable uVisor. */
 | 
			
		||||
UVISOR_SET_MODE_ACL(UVISOR_ENABLED, cfstore_acl_uvisor_box_misc_g);
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* report whether built/configured for flash sync or async mode */
 | 
			
		||||
static control_t cfstore_misc_test_00(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    ret = cfstore_test_startup();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to perform test startup (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @brief  basic PowerControl() test
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_misc_test_00_start(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_POWER_STATE state = ARM_POWER_OFF;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
 | 
			
		||||
    /* try setting the power control state before initialised, which should fail */
 | 
			
		||||
    ret = drv->PowerControl(state);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Eror: PowerControl() call should have failed as CFSTORE not initialised, but the call succeeded\r\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret < ARM_DRIVER_OK, 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);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g);
 | 
			
		||||
    return CaseTimeout(CFSTORE_UTEST_DEFAULT_TIMEOUT_MS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static control_t cfstore_misc_test_00_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_POWER_STATE state = ARM_POWER_OFF;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
 | 
			
		||||
    while(state <= ARM_POWER_FULL)
 | 
			
		||||
    {
 | 
			
		||||
        ret = drv->PowerControl(state);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: PowerControl() call failed\r\n", __func__);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g);
 | 
			
		||||
        state = (ARM_POWER_STATE)((uint32_t) state + 1);
 | 
			
		||||
    }
 | 
			
		||||
    /*try invalid value which should fail*/
 | 
			
		||||
    ret = drv->PowerControl((ARM_POWER_STATE ) 0xffffffff);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:ERror: PowerControl() did not fail with bad value 0xffffffff (not as expected)\r\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret < ARM_DRIVER_OK, 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__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @brief  basic GetVersion() test
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_misc_test_01(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_DRIVER_VERSION version;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    memset(&version, 0, sizeof(version));
 | 
			
		||||
 | 
			
		||||
    version = drv->GetVersion();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:GetVersion() failed to return correct API version.\r\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(version.api == ARM_CFSTORE_API_VERSION, cfstore_misc_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:GetVersion() to return correct driver version.\r\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(version.drv == ARM_CFSTORE_DRV_VERSION, cfstore_misc_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* KV data for test_03 */
 | 
			
		||||
static cfstore_kv_data_t cfstore_misc_test_03_kv_data[] = {
 | 
			
		||||
        /*          1         2         3         4         5         6        7  */
 | 
			
		||||
        /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        { "The.principles.of.least.action.in.quantum.mechanics", "DoctoralThesis"},
 | 
			
		||||
        { "Space.Time.Approach.to.Quantum.Electrodynamic", " PhysicalReview766)"},
 | 
			
		||||
        { "An.Operator.Calculus.Having.Applications.in.Quantum.Electrodynamics", "PhysicalReview84)"},
 | 
			
		||||
        { NULL, NULL},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @brief  basic GetKeyName() test
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_misc_test_02_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    uint8_t key_name_len = 0;
 | 
			
		||||
    char key_name_buf[CFSTORE_KEY_NAME_MAX_LENGTH+1];
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    cfstore_kv_data_t* node = NULL;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\r\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    memset(key_name_buf, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1);
 | 
			
		||||
    /* dont set any flags to get default settings */
 | 
			
		||||
    memset(&flags, 0, sizeof(flags));
 | 
			
		||||
 | 
			
		||||
    ret = cfstore_test_create_table(cfstore_misc_test_03_kv_data);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to create keys from table.\r\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    node = cfstore_misc_test_03_kv_data;
 | 
			
		||||
    while(node->key_name != NULL)
 | 
			
		||||
    {
 | 
			
		||||
        CFSTORE_DBGLOG("%s:About to open KV (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value);
 | 
			
		||||
        ret = drv->Open(node->key_name, flags, hkey);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Failed to open node (key_name=\"%s\", value=\"%s\")(ret=%d)\r\n", __func__, node->key_name, node->value, (int) ret);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
        key_name_len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
 | 
			
		||||
        memset(key_name_buf, 0, key_name_len);
 | 
			
		||||
        drv->GetKeyName(hkey, key_name_buf, &key_name_len);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to GetKeyName() (key_name (expected)=\"%s\", key_name (returned)=\"%s\", value=\"%s\"), len return=%d, len expected=%d\r\n", __func__, node->key_name, key_name_buf, node->value, (int) key_name_len, (int) strlen(node->key_name));
 | 
			
		||||
        TEST_ASSERT_MESSAGE(key_name_len == strlen(node->key_name)+1, cfstore_misc_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
        /* revert to CFSTORE_LOG if more trace required */
 | 
			
		||||
        CFSTORE_DBGLOG("GetKeyName() successfully reported key_name (key_name=\"%s\")\r\n", key_name_buf);
 | 
			
		||||
        ret = drv->Close(hkey);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Failed to close key (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g);
 | 
			
		||||
        node++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    cfstore_test_delete_all();
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @brief  basic GetValueLen() test
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_misc_test_03_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_SIZE len = 0;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    cfstore_kv_data_t* node = NULL;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    /* dont set any flags to get default settings */
 | 
			
		||||
    memset(&flags, 0, sizeof(flags));
 | 
			
		||||
 | 
			
		||||
    ret = cfstore_test_create_table(cfstore_misc_test_03_kv_data);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to create keys from table.\r\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    node = cfstore_misc_test_03_kv_data;
 | 
			
		||||
    while(node->key_name != NULL)
 | 
			
		||||
    {
 | 
			
		||||
        CFSTORE_DBGLOG("%s:About to open KV (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value);
 | 
			
		||||
        ret = drv->Open(node->key_name, flags, hkey);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Failed to open node (key_name=\"%s\", value=\"%s\")(ret=%d)\r\n", __func__, node->key_name, node->value, (int) ret);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
        drv->GetValueLen(hkey, &len);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Errro: GetValueLen() retrieve incorrect length of value blob(expected=%d, returned=%d)\r\n", __func__, (int) strlen(node->value), (int) len);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(len == strlen(node->value), cfstore_misc_utest_msg_g);
 | 
			
		||||
        /* revert to CFSTORE_LOG if more trace required */
 | 
			
		||||
        CFSTORE_DBGLOG("GetValueLen() successfully reported correct value blob length%s", "\r\n");
 | 
			
		||||
 | 
			
		||||
        ret = drv->Close(hkey);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Failed to close key (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g);
 | 
			
		||||
        node++;
 | 
			
		||||
    }
 | 
			
		||||
    cfstore_test_delete_all();
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @brief  basic GetStatus() test
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_misc_test_04_start(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_STATUS status;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) 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);
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g);
 | 
			
		||||
    return CaseTimeout(CFSTORE_UTEST_DEFAULT_TIMEOUT_MS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @brief  basic GetStatus() test
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_misc_test_04_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_STATUS status;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) 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);
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(200, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
           /*          1         2         3         4         5         6        7  */
 | 
			
		||||
           /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        Case("MISC_test_00", cfstore_misc_test_00),
 | 
			
		||||
        Case("MISC_test_00_start", cfstore_misc_test_00_start),
 | 
			
		||||
        Case("MISC_test_00_end", cfstore_misc_test_00_end),
 | 
			
		||||
        Case("MISC_test_01", cfstore_misc_test_01),
 | 
			
		||||
        Case("MISC_test_02_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("MISC_test_02_end", cfstore_misc_test_02_end),
 | 
			
		||||
        Case("MISC_test_03_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("MISC_test_03_end", cfstore_misc_test_03_end),
 | 
			
		||||
        Case("MISC_test_04_start", cfstore_misc_test_04_start),
 | 
			
		||||
        Case("MISC_test_05_end", cfstore_misc_test_04_end),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
/// @endcond
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,641 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 open.cpp Test cases to open KVs in the CFSTORE using the drv->Open() interface.
 | 
			
		||||
 *
 | 
			
		||||
 * Please consult the documentation under the test-case functions for
 | 
			
		||||
 * a description of the individual test case.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#include "cfstore_utest.h"
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>     /*rand()*/
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
static char cfstore_open_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE];
 | 
			
		||||
 | 
			
		||||
/* Configure secure box. */
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
UVISOR_BOX_NAMESPACE("com.arm.mbed.cfstore.test.open.box1");
 | 
			
		||||
UVISOR_BOX_CONFIG(cfstore_open_box1, UVISOR_BOX_STACK_SIZE);
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
#ifdef CFSTORE_DEBUG
 | 
			
		||||
#define CFSTORE_OPEN_GREENTEA_TIMEOUT_S     3000
 | 
			
		||||
#else
 | 
			
		||||
#define CFSTORE_OPEN_GREENTEA_TIMEOUT_S     1000
 | 
			
		||||
#endif
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* support functions */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * open tests that focus on testing cfstore_open()
 | 
			
		||||
 * cfstore_handle_t cfstore_open(const char* key_name, char* data, ARM_CFSTORE_SIZE* len, cfstore_key_desc_t* kdesc)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* KV data for test_01 */
 | 
			
		||||
static cfstore_kv_data_t cfstore_open_test_01_kv_data[] = {
 | 
			
		||||
        { "yotta.hello-world.animal{wobbly-dog}{foot}frontLeft", "missing"},
 | 
			
		||||
        { NULL, NULL},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* report whether built/configured for flash sync or async mode */
 | 
			
		||||
static control_t cfstore_open_test_00(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    ret = cfstore_test_startup();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to perform test startup (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @brief
 | 
			
		||||
 * Basic open test which does the following:
 | 
			
		||||
 * - creates KV with default rw perms and writes some data to the value blob.
 | 
			
		||||
 * - closes the newly created KV.
 | 
			
		||||
 * - opens the KV with the default permissions (r-only)
 | 
			
		||||
 * - reads the KV data and checks its the same as the previously created data.
 | 
			
		||||
 * - closes the opened key
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_open_test_01_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    char* read_buf;
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_SIZE len = 0;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
    cfstore_kv_data_t *node;
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    node = cfstore_open_test_01_kv_data;
 | 
			
		||||
    memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
    memset(&flags, 0, sizeof(flags));
 | 
			
		||||
 | 
			
		||||
    kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE;
 | 
			
		||||
    CFSTORE_DBGLOG("%s:About to create new node (key_name=\"%s\", value=\"%s\")\n", __func__, node->key_name, node->value);
 | 
			
		||||
    ret = drv->Create(node->key_name, strlen(node->value), &kdesc, hkey);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create node (key_name=\"%s\", value=\"%s\")(ret=%d)\n", __func__, node->key_name, node->value, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s:length of KV=%d (key_name=\"%s\", value=\"%s\")\n", __func__, (int) len, node->key_name, node->value);
 | 
			
		||||
    len = strlen(node->value);
 | 
			
		||||
    ret = drv->Write(hkey, (char*) node->value, &len);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write key (key_name=\"%s\", value=\"%s\")(ret=%d)\n", __func__, node->key_name, node->value, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write full value data (key_name=\"%s\", value=\"%s\"), len=%d, (ret=%d)\n", __func__, node->key_name, node->value, (int) len, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(len == strlen(node->value), cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("Created KV successfully (key_name=\"%s\", value=\"%s\")\n", node->key_name, node->value);
 | 
			
		||||
    ret = drv->Close(hkey);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to close handle (ret=%d)\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* now open the newly created key */
 | 
			
		||||
    ret = drv->Open(node->key_name, flags, hkey);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open node (key_name=\"%s\", value=\"%s\")(ret=%d)\n", __func__, node->key_name, node->value, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    len = strlen(node->value) + 1;
 | 
			
		||||
    read_buf = (char*) malloc(len);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to allocated read buffer \n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(read_buf != NULL, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("Opened KV successfully (key_name=\"%s\", value=\"%s\")\n", node->key_name, node->value);
 | 
			
		||||
    memset(read_buf, 0, len);
 | 
			
		||||
    ret = drv->Read(hkey, read_buf, &len);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write key (key_name=\"%s\", value=\"%s\")\n", __func__, node->key_name, node->value);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* check read data is as expected */
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: read value data (%s) != KV value data (key_name=\"%s\", value=\"%s\")\n", __func__, read_buf, node->key_name, node->value);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(strncmp(read_buf, node->value, strlen(node->value)) == 0, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    if(read_buf){
 | 
			
		||||
        free(read_buf);
 | 
			
		||||
    }
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Close() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(drv->Close(hkey) >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static cfstore_kv_data_t cfstore_open_test_02_data[] = {
 | 
			
		||||
        CFSTORE_INIT_1_TABLE_MID_NODE,
 | 
			
		||||
        { NULL, NULL},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   test to open() a pre-existing key and try to write it, which should fail
 | 
			
		||||
 *          as by default pre-existing keys are opened read-only
 | 
			
		||||
 *
 | 
			
		||||
 * Basic open test which does the following:
 | 
			
		||||
 * - creates KV with default rw perms and writes some data to the value blob.
 | 
			
		||||
 * - closes the newly created KV.
 | 
			
		||||
 * - opens the KV with the default permissions (read-only)
 | 
			
		||||
 * - tries to write the KV data which should fail because KV was not opened with write flag set.
 | 
			
		||||
 * - closes the opened key
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_open_test_02_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_SIZE len = 0;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
    /* dont set any flags to get default settings */
 | 
			
		||||
    memset(&flags, 0, sizeof(flags));
 | 
			
		||||
    kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE;
 | 
			
		||||
    len = strlen(cfstore_open_test_02_data[0].value);
 | 
			
		||||
    ret = cfstore_test_create(cfstore_open_test_02_data[0].key_name, (char*) cfstore_open_test_02_data[0].value, &len, &kdesc);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create KV in store (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* by default, owner of key opens with read-only permissions*/
 | 
			
		||||
    ret = drv->Open(cfstore_open_test_02_data[0].key_name, flags, hkey);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open node (key_name=\"%s\")(ret=%d)\n", __func__, cfstore_open_test_02_data[0].key_name, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    len = strlen(cfstore_open_test_02_data[0].value);
 | 
			
		||||
    ret = drv->Write(hkey, cfstore_open_test_02_data[0].value, &len);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: call to Write() succeeded when should have failed (key_name=\"%s\")(ret=%d).\n", __func__, cfstore_open_test_02_data[0].key_name, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_READ_ONLY, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Close() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(drv->Close(hkey) >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   test to open() a pre-existing key and try to write it, which should succeed
 | 
			
		||||
 *          because the key was opened read-write permissions explicitly
 | 
			
		||||
 *
 | 
			
		||||
 * Basic open test which does the following:
 | 
			
		||||
 * - creates KV with default rw perms and writes some data to the value blob.
 | 
			
		||||
 * - closes the newly created KV.
 | 
			
		||||
 * - opens the KV with the rw permissions (non default)
 | 
			
		||||
 * - tries to write the KV data which should succeeds because KV was opened with write flag set.
 | 
			
		||||
 * - closes the opened key
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_open_test_03_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_SIZE len = 0;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
    /* dont set any flags to get default settings */
 | 
			
		||||
    memset(&flags, 0, sizeof(flags));
 | 
			
		||||
    kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE;
 | 
			
		||||
    len = strlen(cfstore_open_test_02_data[0].value);
 | 
			
		||||
    ret = cfstore_test_create(cfstore_open_test_02_data[0].key_name, (char*) cfstore_open_test_02_data[0].value, &len, &kdesc);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create KV in store (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* opens with read-write permissions*/
 | 
			
		||||
    flags.read = true;
 | 
			
		||||
    flags.write = true;
 | 
			
		||||
    ret = drv->Open(cfstore_open_test_02_data[0].key_name, flags, hkey);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open node (key_name=\"%s\")(ret=%d)\n", __func__, cfstore_open_test_02_data[0].key_name, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    len = strlen(cfstore_open_test_02_data[0].value);
 | 
			
		||||
    ret = drv->Write(hkey, cfstore_open_test_02_data[0].value, &len);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: call to Write() failed when should have succeeded (key_name=\"%s\")(ret=%d).\n", __func__, cfstore_open_test_02_data[0].key_name, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Close() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(drv->Close(hkey) >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @brief  test to call cfstore_open() with a key_name string that exceeds
 | 
			
		||||
 *          the maximum length
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_open_test_04_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    char kv_name_good[CFSTORE_KEY_NAME_MAX_LENGTH+1]; /* extra char for terminating null */
 | 
			
		||||
    char kv_name_bad[CFSTORE_KEY_NAME_MAX_LENGTH+2];
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_SIZE len = 0;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    memset(kv_name_good, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1);
 | 
			
		||||
    memset(kv_name_bad, 0, CFSTORE_KEY_NAME_MAX_LENGTH+2);
 | 
			
		||||
    memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
    /* dont set any flags to get default settings */
 | 
			
		||||
    memset(&flags, 0, sizeof(flags));
 | 
			
		||||
 | 
			
		||||
    len = CFSTORE_KEY_NAME_MAX_LENGTH;
 | 
			
		||||
    ret = cfstore_test_kv_name_gen(kv_name_good, len);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to generate kv_name_good.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK , cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: kv_name_good is not the correct length (len=%d, expected=%d).\n", __func__, (int) strlen(kv_name_good), (int) len);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(strlen(kv_name_good) == CFSTORE_KEY_NAME_MAX_LENGTH, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    ret = cfstore_test_create(kv_name_good, kv_name_good, &len, &kdesc);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create KV in store for kv_name_good(ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
 | 
			
		||||
    ret = cfstore_test_kv_name_gen(kv_name_bad, len);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to generate kv_name_bad.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK , cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: kv_name_bad is not the correct length (len=%d, expected=%d).\n", __func__, (int) strlen(kv_name_bad), (int) len);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(strlen(kv_name_bad) == CFSTORE_KEY_NAME_MAX_LENGTH+1, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
    ret = cfstore_test_create(kv_name_bad, kv_name_bad, &len, &kdesc);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: created KV in store for kv_name_bad when should have failed(ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret < ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
typedef struct cfstore_open_kv_name_ascii_node {
 | 
			
		||||
    uint32_t code;
 | 
			
		||||
    uint32_t f_allowed : 1;
 | 
			
		||||
} cfstore_open_kv_name_ascii_node;
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
static const uint32_t cfstore_open_kv_name_ascii_table_code_sentinel_g = 256;
 | 
			
		||||
 | 
			
		||||
/*@brief    table recording ascii character codes permitted in kv names */
 | 
			
		||||
static cfstore_open_kv_name_ascii_node cfstore_open_kv_name_ascii_table[] =
 | 
			
		||||
{
 | 
			
		||||
        {0, false},         /* codes 0-44 not allowed */
 | 
			
		||||
        {45, true},         /* codes 45-46 == [-.] allowed */
 | 
			
		||||
        {47, false},        /* code 47 not allowed */
 | 
			
		||||
        {48, true},         /* codes 48-57 not allowed */
 | 
			
		||||
        {58, false},        /* codes 46-64 not allowed */
 | 
			
		||||
        {64, true},         /* codes 64-91 allowed [@A-Z] */
 | 
			
		||||
        {91, false},        /* code 91-96 not allowed */
 | 
			
		||||
        {95, true},         /* code 95 allowed '_' */
 | 
			
		||||
        {96, false},        /* codes 96 not allowed */
 | 
			
		||||
        {97, true},         /* codes 65-90 allowed [A-Z] and {*/
 | 
			
		||||
        {123, false},       /* codes 123 '}' not allowed on its own*/
 | 
			
		||||
        {124, false},       /* codes 124 not allowed */
 | 
			
		||||
        {125, false},       /* code 125 '}' not allowed on its own*/
 | 
			
		||||
        {126, false},       /* codes 126-255 not allowed */
 | 
			
		||||
        {cfstore_open_kv_name_ascii_table_code_sentinel_g, false},       /* sentinel */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
enum cfstore_open_kv_name_pos {
 | 
			
		||||
    cfstore_open_kv_name_pos_start = 0x0,
 | 
			
		||||
    cfstore_open_kv_name_pos_mid,
 | 
			
		||||
    cfstore_open_kv_name_pos_end,
 | 
			
		||||
    cfstore_open_kv_name_pos_max
 | 
			
		||||
};
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
/** @brief  test to call cfstore_open() with key_name that in includes
 | 
			
		||||
 *          illegal characters
 | 
			
		||||
 *          - the character(s) can be at the beginning of the key_name
 | 
			
		||||
 *          - the character(s) can be at the end of the key_name
 | 
			
		||||
 *          - the character(s) can be somewhere within the key_name string
 | 
			
		||||
 *          - a max-length string of random characters (legal and illegal)
 | 
			
		||||
 *          - a max-length string of random illegal characters only
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_open_test_05_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    bool f_allowed = false;
 | 
			
		||||
    char kv_name[CFSTORE_KEY_NAME_MAX_LENGTH+1];    /* extra char for terminating null */
 | 
			
		||||
    uint32_t j = 0;
 | 
			
		||||
    int32_t ret = ARM_DRIVER_OK;
 | 
			
		||||
    size_t name_len = CFSTORE_KEY_NAME_MAX_LENGTH;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
    cfstore_open_kv_name_ascii_node* node = NULL;
 | 
			
		||||
    uint32_t pos;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
 | 
			
		||||
#ifdef CFSTORE_DEBUG
 | 
			
		||||
    /* symbol only used why debug is enabled */
 | 
			
		||||
    const char* pos_str = NULL;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    /* create bad keyname strings with invalid character code at start of keyname */
 | 
			
		||||
    node = cfstore_open_kv_name_ascii_table;
 | 
			
		||||
    while(node->code !=  cfstore_open_kv_name_ascii_table_code_sentinel_g)
 | 
			
		||||
    {
 | 
			
		||||
        /* loop over range */
 | 
			
		||||
        for(j = node->code; j < (node+1)->code; j++)
 | 
			
		||||
        {
 | 
			
		||||
            /* set the start, mid, last character of the name to the test char code */
 | 
			
		||||
            for(pos = (uint32_t) cfstore_open_kv_name_pos_start; pos < (uint32_t) cfstore_open_kv_name_pos_max; pos++)
 | 
			
		||||
            {
 | 
			
		||||
                name_len = CFSTORE_KEY_NAME_MAX_LENGTH;
 | 
			
		||||
                memset(kv_name, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1);
 | 
			
		||||
                memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
                kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE;
 | 
			
		||||
 | 
			
		||||
                ret = cfstore_test_kv_name_gen(kv_name, name_len);
 | 
			
		||||
                CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to generate kv_name.\n", __func__);
 | 
			
		||||
                TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK , cfstore_open_utest_msg_g);
 | 
			
		||||
                CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: kv_name incorrect length (len=%d, expected= %d).\n", __func__, (int) strlen(kv_name), (int) name_len);
 | 
			
		||||
                TEST_ASSERT_MESSAGE(strlen(kv_name) == name_len, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
                /* overwrite a char at the pos start, mid, end of the kv_name with an ascii char code (both illegal and legal)*/
 | 
			
		||||
                switch(pos)
 | 
			
		||||
                {
 | 
			
		||||
                case cfstore_open_kv_name_pos_start:
 | 
			
		||||
                    kv_name[0] = (char) j;
 | 
			
		||||
                    break;
 | 
			
		||||
                case cfstore_open_kv_name_pos_mid:
 | 
			
		||||
                    /* create bad keyname strings with invalid character code in the middle of keyname */
 | 
			
		||||
                    kv_name[name_len/2] = (char) j;
 | 
			
		||||
                    break;
 | 
			
		||||
                case cfstore_open_kv_name_pos_end:
 | 
			
		||||
                    /* create bad keyname strings with invalid character code at end of keyname */
 | 
			
		||||
                    kv_name[name_len-1] = (char) j;
 | 
			
		||||
                    break;
 | 
			
		||||
                default:
 | 
			
		||||
                    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: unexpected value of pos (pos=%d).\n", __func__, (int) pos);
 | 
			
		||||
                    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
#ifdef CFSTORE_DEBUG
 | 
			
		||||
                /* processing only required when debug trace enabled */
 | 
			
		||||
                switch(pos)
 | 
			
		||||
                {
 | 
			
		||||
                case cfstore_open_kv_name_pos_start:
 | 
			
		||||
                    pos_str = "start";
 | 
			
		||||
                    break;
 | 
			
		||||
                case cfstore_open_kv_name_pos_mid:
 | 
			
		||||
                    pos_str = "middle";
 | 
			
		||||
                    break;
 | 
			
		||||
                case cfstore_open_kv_name_pos_end:
 | 
			
		||||
                    pos_str = "end";
 | 
			
		||||
                    break;
 | 
			
		||||
                default:
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
#endif
 | 
			
		||||
                ret = cfstore_test_create(kv_name, kv_name, &name_len, &kdesc);
 | 
			
		||||
 | 
			
		||||
                /* special cases */
 | 
			
		||||
                switch(j)
 | 
			
		||||
                {
 | 
			
		||||
                case 0 :
 | 
			
		||||
				case 46 :
 | 
			
		||||
                    switch(pos)
 | 
			
		||||
                    {
 | 
			
		||||
                    /* for code = 0 (null terminator). permitted at mid and end of string */
 | 
			
		||||
                    /* for code = 46 ('.'). permitted at mid and end of string but not at start */
 | 
			
		||||
                    case cfstore_open_kv_name_pos_start:
 | 
			
		||||
                        f_allowed = false;
 | 
			
		||||
                        break;
 | 
			
		||||
                    case cfstore_open_kv_name_pos_mid:
 | 
			
		||||
                    case cfstore_open_kv_name_pos_end:
 | 
			
		||||
                    default:
 | 
			
		||||
                        f_allowed = true;
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
				default:
 | 
			
		||||
					f_allowed = node->f_allowed;
 | 
			
		||||
					break;
 | 
			
		||||
                }
 | 
			
		||||
                if(f_allowed == true)
 | 
			
		||||
                {
 | 
			
		||||
                    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create KV in store when kv_name contains valid characters (code=%d, ret=%d).\n", __func__, (int) j, (int) ret);
 | 
			
		||||
                    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
                    /* revert CFSTORE_LOG for more trace */
 | 
			
		||||
                    CFSTORE_DBGLOG("Successfully created a KV with valid keyname containing ascii character code %d (%c) at the %s of the keyname.\n", (int) j, (int) j, pos_str);
 | 
			
		||||
                    CFSTORE_LOG("%c", '.');
 | 
			
		||||
 | 
			
		||||
                    ret = cfstore_test_delete(kv_name);
 | 
			
		||||
                    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to delete KV previously created (code=%d, ret=%d).\n", __func__, (int) j, (int) ret);
 | 
			
		||||
                    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {   /*node->f_allowed == false => not allowed to create kv name with ascii code */
 | 
			
		||||
                    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: created KV in store when kv_name contains an invalid character (code=%d, ret=%d).\n", __func__, (int) j, (int) ret);
 | 
			
		||||
                    TEST_ASSERT_MESSAGE(ret < ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
                    /* revert CFSTORE_LOG for more trace */
 | 
			
		||||
                    CFSTORE_DBGLOG("Successfully failed to create a KV with an invalid keyname containing ascii character code %d at the %s of the keyname.\n", (int) j, pos_str);
 | 
			
		||||
                    CFSTORE_LOG("%c", '.');
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        node++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    CFSTORE_LOG("%c", '\n');
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(drv->Uninitialize() >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const char cfstore_open_ascii_illegal_buf_g[] = "!\"<EFBFBD>$%&'()*+,./:;<=>?@[\\]^_`{|}~"; /* 31 chars */
 | 
			
		||||
 | 
			
		||||
/** @brief  test to call cfstore_open() with key_name that in includes
 | 
			
		||||
 *          illegal characters
 | 
			
		||||
 *          - a max-length string of random illegal characters only
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_open_test_06_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    char kv_name[CFSTORE_KEY_NAME_MAX_LENGTH+1];    /* extra char for terminating null */
 | 
			
		||||
    size_t i = 0;
 | 
			
		||||
    uint32_t pos = 0;
 | 
			
		||||
    int32_t ret = ARM_DRIVER_OK;
 | 
			
		||||
    size_t name_len = CFSTORE_KEY_NAME_MAX_LENGTH;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
    size_t buf_data_max = 0;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
 | 
			
		||||
    /* create bad keyname strings with invalid character code at start of keyname */
 | 
			
		||||
    buf_data_max = strlen(cfstore_open_ascii_illegal_buf_g);
 | 
			
		||||
    name_len = CFSTORE_KEY_NAME_MAX_LENGTH;
 | 
			
		||||
    memset(kv_name, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1);
 | 
			
		||||
    kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE;
 | 
			
		||||
 | 
			
		||||
    /* generate a kv name of illegal chars*/
 | 
			
		||||
    for(i = 0; i < name_len; i++)
 | 
			
		||||
    {
 | 
			
		||||
        pos = rand() % (buf_data_max+1);
 | 
			
		||||
        kv_name[i] = cfstore_open_ascii_illegal_buf_g[pos];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = cfstore_test_create(kv_name, kv_name, &name_len, &kdesc);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: created KV in store when kv_name contains invalid characters (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret < ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(drv->Uninitialize() >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @brief  test to call cfstore_open() with key_name that in includes
 | 
			
		||||
 *          illegal characters
 | 
			
		||||
 *          - a max-length string of random characters (legal and illegal)
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_open_test_07_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    char kv_name[CFSTORE_KEY_NAME_MAX_LENGTH+1];    /* extra char for terminating null */
 | 
			
		||||
    size_t i = 0;
 | 
			
		||||
    int32_t ret = ARM_DRIVER_OK;
 | 
			
		||||
    size_t name_len = CFSTORE_KEY_NAME_MAX_LENGTH;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
    size_t buf_data_max = 0;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
 | 
			
		||||
    /* create bad keyname strings with invalid character code at start of keyname */
 | 
			
		||||
    buf_data_max = strlen(cfstore_open_ascii_illegal_buf_g);
 | 
			
		||||
    name_len = CFSTORE_KEY_NAME_MAX_LENGTH;
 | 
			
		||||
    memset(kv_name, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1);
 | 
			
		||||
    kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE;
 | 
			
		||||
 | 
			
		||||
    ret = cfstore_test_kv_name_gen(kv_name, name_len);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to generate kv_name.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK , cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* pepper the illegal chars across the string*/
 | 
			
		||||
    for(i++; i < buf_data_max; i++){
 | 
			
		||||
        kv_name[rand() % (name_len+1)] = cfstore_open_ascii_illegal_buf_g[i];
 | 
			
		||||
    }
 | 
			
		||||
    ret = cfstore_test_create(kv_name, kv_name, &name_len, &kdesc);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: created KV in store when kv_name contains invalid characters (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret < ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(drv->Uninitialize() >= ARM_DRIVER_OK, cfstore_open_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(CFSTORE_OPEN_GREENTEA_TIMEOUT_S, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
           /*          1         2         3         4         5         6        7  */
 | 
			
		||||
           /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        Case("OPEN_test_00", cfstore_open_test_00),
 | 
			
		||||
        Case("OPEN_test_01_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("OPEN_test_01_end", cfstore_open_test_01_end),
 | 
			
		||||
        Case("OPEN_test_02_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("OPEN_test_02_end", cfstore_open_test_02_end),
 | 
			
		||||
        Case("OPEN_test_03_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("OPEN_test_03_end", cfstore_open_test_03_end),
 | 
			
		||||
        Case("OPEN_test_04_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("OPEN_test_04_end", cfstore_open_test_04_end),
 | 
			
		||||
        Case("OPEN_test_05_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("OPEN_test_05_end", cfstore_open_test_05_end),
 | 
			
		||||
        Case("OPEN_test_06_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("OPEN_test_06_end", cfstore_open_test_06_end),
 | 
			
		||||
        Case("OPEN_test_07_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("OPEN_test_07_end", cfstore_open_test_07_end),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
/// @endcond
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,188 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 read.cpp Test cases to read KVs in the CFSTORE using the drv->Read() API call.
 | 
			
		||||
 *
 | 
			
		||||
 * Please consult the documentation under the test-case functions for
 | 
			
		||||
 * a description of the individual test case.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#include "cfstore_utest.h"
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
static char cfstore_read_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE];
 | 
			
		||||
 | 
			
		||||
/* Configure secure box. */
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
UVISOR_BOX_NAMESPACE("com.arm.mbed.cfstore.test.read.box1");
 | 
			
		||||
UVISOR_BOX_CONFIG(cfstore_read_box1, UVISOR_BOX_STACK_SIZE);
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* KV data for test_01 */
 | 
			
		||||
static cfstore_kv_data_t cfstore_read_test_01_kv_data[] = {
 | 
			
		||||
        CFSTORE_INIT_1_TABLE_MID_NODE,
 | 
			
		||||
        { NULL, NULL},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* report whether built/configured for flash sync or async mode */
 | 
			
		||||
static control_t cfstore_read_test_00(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    ret = cfstore_test_startup();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_read_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to perform test startup (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_read_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief check char at offset is as expected */
 | 
			
		||||
static int32_t cfstore_read_seek_test(ARM_CFSTORE_HANDLE hkey, uint32_t offset, const char expected)
 | 
			
		||||
{
 | 
			
		||||
    ARM_CFSTORE_SIZE len = 1;
 | 
			
		||||
    char read_buf[1];
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    ret = drv->Rseek(hkey, offset);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:failed to Rseek() to desired offset (offset=%d) (ret=%d).\n", __func__, (int) offset, (int) ret);
 | 
			
		||||
        goto out0;
 | 
			
		||||
    }
 | 
			
		||||
    ret = drv->Read(hkey, read_buf, &len);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:failed to Read() (offset=%d)(ret=%d).\n", __func__, (int) offset, (int) ret);
 | 
			
		||||
        goto out0;
 | 
			
		||||
    }
 | 
			
		||||
    if(read_buf[0] != expected){
 | 
			
		||||
        ret = ARM_DRIVER_ERROR;
 | 
			
		||||
        goto out0;
 | 
			
		||||
    }
 | 
			
		||||
out0:
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @brief
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_read_test_01_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_SIZE len = 0;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
    cfstore_test_rw_data_entry_t *node;
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
    memset(&flags, 0, sizeof(flags));
 | 
			
		||||
 | 
			
		||||
    /* create a key for reading */
 | 
			
		||||
    kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE;
 | 
			
		||||
    len = strlen(cfstore_read_test_01_kv_data[0].value);
 | 
			
		||||
    ret = cfstore_test_create(cfstore_read_test_01_kv_data[0].key_name, (char*) cfstore_read_test_01_kv_data[0].value, &len, &kdesc);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_read_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create KV in store (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_read_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* now open the newly created key */
 | 
			
		||||
    ret = drv->Open(cfstore_read_test_01_kv_data[0].key_name, flags, hkey);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_read_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open node (key_name=\"%s\", value=\"%s\")(ret=%d)\n", __func__, cfstore_read_test_01_kv_data[0].key_name, cfstore_read_test_01_kv_data[0].value, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_read_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* seek back and forth in key and check the characters are as expected */
 | 
			
		||||
    node = cfstore_test_rw_data_table;
 | 
			
		||||
    while(node->offset != CFSTORE_TEST_RW_TABLE_SENTINEL)
 | 
			
		||||
    {
 | 
			
		||||
        ret = cfstore_read_seek_test(hkey, node->offset, node->rw_char);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_read_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Rseek() to offset (%d) didn't read expected char (\'%c\') (ret=%d)\n", __func__, (int) node->offset, node->rw_char, (int) ret);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_read_utest_msg_g);
 | 
			
		||||
        node++;
 | 
			
		||||
    }
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_read_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Close() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(drv->Close(hkey) >= ARM_DRIVER_OK, cfstore_read_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_read_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_read_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @brief
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_read_test_02_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    /*todo: implement test */
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_read_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Warn: Not implemented\n", __func__);
 | 
			
		||||
    CFSTORE_DBGLOG("%s: WARN: requires implementation\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(true, cfstore_read_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(200, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
           /*          1         2         3         4         5         6        7  */
 | 
			
		||||
           /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        Case("READ_test_00", cfstore_read_test_00),
 | 
			
		||||
        Case("READ_test_01_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("READ_test_01_end", cfstore_read_test_01_end),
 | 
			
		||||
        Case("READ_test_02_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("READ_test_02_end", cfstore_read_test_02_end),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
/// @endcond
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,193 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 write.cpp Test cases to write KVs in the CFSTORE using the drv->Write() API call.
 | 
			
		||||
 *
 | 
			
		||||
 * Please consult the documentation under the test-case functions for
 | 
			
		||||
 * a description of the individual test case.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#include "cfstore_utest.h"
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
#include "uvisor-lib/uvisor-lib.h"
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
static char cfstore_write_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE];
 | 
			
		||||
 | 
			
		||||
/* Configure secure box. */
 | 
			
		||||
#ifdef YOTTA_CFG_CFSTORE_UVISOR
 | 
			
		||||
UVISOR_BOX_NAMESPACE("com.arm.mbed.cfstore.test.write.box1");
 | 
			
		||||
UVISOR_BOX_CONFIG(cfstore_write_box1, UVISOR_BOX_STACK_SIZE);
 | 
			
		||||
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * write tests
 | 
			
		||||
 * cfstore_handle_t cfstore_write()
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* KV data for test_01 */
 | 
			
		||||
static cfstore_kv_data_t cfstore_write_test_01_kv_data[] = {
 | 
			
		||||
        CFSTORE_INIT_1_TABLE_MID_NODE,
 | 
			
		||||
        { NULL, NULL},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* report whether built/configured for flash sync or async mode */
 | 
			
		||||
static control_t cfstore_write_test_00(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    ret = cfstore_test_startup();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_write_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to perform test startup (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_write_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @brief  test to write many times to an open KV to test data is appended
 | 
			
		||||
 *          sequentially to the end of the value blob
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_write_test_01_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    char read_buf[CFSTORE_KEY_NAME_MAX_LENGTH+1];
 | 
			
		||||
    uint32_t i = 0;
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_SIZE len = 0;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    memset(read_buf, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1);
 | 
			
		||||
    memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
    memset(&flags, 0, sizeof(flags));
 | 
			
		||||
 | 
			
		||||
    /* create an empty KV of the required length */
 | 
			
		||||
    kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE;
 | 
			
		||||
    len = strlen(cfstore_write_test_01_kv_data[0].value);
 | 
			
		||||
    ret = cfstore_test_create(cfstore_write_test_01_kv_data[0].key_name, "one", &len, &kdesc);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_write_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create new KV (key_name=%s, ret=%d).\n", __func__, cfstore_write_test_01_kv_data[0].key_name, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_write_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* now open the newly created key and write repeated to created the string */
 | 
			
		||||
    flags.write = true;
 | 
			
		||||
    ret = drv->Open(cfstore_write_test_01_kv_data[0].key_name, flags, hkey);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_write_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open node (key_name=\"%s\", value=\"%s\")(ret=%d)\n", __func__, cfstore_write_test_01_kv_data[0].key_name, cfstore_write_test_01_kv_data[0].value, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_write_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    for(i = 0; i < strlen(cfstore_write_test_01_kv_data[0].value); i++)
 | 
			
		||||
    {
 | 
			
		||||
        len = 1;
 | 
			
		||||
        ret = drv->Write(hkey, &cfstore_write_test_01_kv_data[0].value[i], &len);
 | 
			
		||||
        CFSTORE_TEST_UTEST_MESSAGE(cfstore_write_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Write failed for char (\'%c\') (ret=%d)\n", __func__, cfstore_write_test_01_kv_data[0].value[i], (int) ret);
 | 
			
		||||
        TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_write_utest_msg_g);
 | 
			
		||||
    }
 | 
			
		||||
    /* check that the value created in the key is as expected*/
 | 
			
		||||
    len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
 | 
			
		||||
    ret = drv->Read(hkey, read_buf, &len);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_write_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Read failed (ret=%d)\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_write_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    /* check node key_names are identical */
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_write_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: KV value (%s) is not as expected (%s).\n", __func__, read_buf, cfstore_write_test_01_kv_data[0].value);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(strncmp(read_buf, cfstore_write_test_01_kv_data[0].value, strlen(cfstore_write_test_01_kv_data[0].value)) == 0, cfstore_write_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_write_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Close() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(drv->Close(hkey) >= ARM_DRIVER_OK, cfstore_write_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    cfstore_test_delete_all();
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_write_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_write_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @brief  test to write with a NULL buffer, which should fail gracefully
 | 
			
		||||
 *
 | 
			
		||||
 * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
 | 
			
		||||
 */
 | 
			
		||||
control_t cfstore_write_test_02_end(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_SIZE len = 0;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_DBGLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
 | 
			
		||||
    /* create an empty KV of the required length */
 | 
			
		||||
    kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE;
 | 
			
		||||
    len = strlen(cfstore_write_test_01_kv_data[0].value);
 | 
			
		||||
    ret = cfstore_test_create(cfstore_write_test_01_kv_data[0].key_name, NULL, &len, &kdesc);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_write_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error KV creation should have failed due to null write buffer but something else happended (ret=%d).\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret == ARM_CFSTORE_DRIVER_ERROR_INVALID_WRITE_BUFFER, cfstore_write_utest_msg_g);
 | 
			
		||||
 | 
			
		||||
    ret = drv->Uninitialize();
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_write_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_write_utest_msg_g);
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(200, "default_auto");
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
           /*          1         2         3         4         5         6        7  */
 | 
			
		||||
           /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
        Case("WRITE_test_00", cfstore_write_test_00),
 | 
			
		||||
        Case("WRITE_test_01_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("WRITE_test_01_end", cfstore_write_test_01_end),
 | 
			
		||||
        Case("WRITE_test_02_start", cfstore_utest_default_start),
 | 
			
		||||
        Case("WRITE_test_02_end", cfstore_write_test_02_end),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Declare your test specification with a custom setup handler */
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
/// @endcond
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,893 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#if !DEVICE_STORAGE
 | 
			
		||||
    #error [NOT_SUPPORTED] Storage not supported for this target
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef TARGET_LIKE_POSIX
 | 
			
		||||
#define AVOID_GREENTEA
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef AVOID_GREENTEA
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#endif
 | 
			
		||||
#include "utest/utest.h"
 | 
			
		||||
#include "unity/unity.h"
 | 
			
		||||
 | 
			
		||||
#include "flash-journal-strategy-sequential/flash_journal_strategy_sequential.h"
 | 
			
		||||
#include "flash-journal-strategy-sequential/flash_journal_private.h"
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0);
 | 
			
		||||
ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_(0);
 | 
			
		||||
 | 
			
		||||
FlashJournal_t      journal;
 | 
			
		||||
 | 
			
		||||
static const size_t BUFFER_SIZE = 8192;
 | 
			
		||||
static uint8_t      buffer[BUFFER_SIZE];
 | 
			
		||||
 | 
			
		||||
static const size_t SIZEOF_SMALL_WRITE = 8;
 | 
			
		||||
static const size_t SIZEOF_LARGE_WRITE = BUFFER_SIZE;
 | 
			
		||||
static int32_t      callbackStatus;
 | 
			
		||||
 | 
			
		||||
void callbackHandler(int32_t status, FlashJournal_OpCode_t cmd_code)
 | 
			
		||||
{
 | 
			
		||||
    callbackStatus = status;
 | 
			
		||||
 | 
			
		||||
    switch (cmd_code) {
 | 
			
		||||
        case FLASH_JOURNAL_OPCODE_INITIALIZE:
 | 
			
		||||
            // 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);
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case FLASH_JOURNAL_OPCODE_LOG_BLOB:
 | 
			
		||||
            // 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);
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case FLASH_JOURNAL_OPCODE_RESET:
 | 
			
		||||
            // printf("journal_callbackHandler: callback for reset with status %" PRId32 "\n", status);
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            // printf("journal_callbackHandler: callback for opcode %u with status %" PRId32 "\n", cmd_code, status);
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
    Harness::validate_callback(); // Validate the callback
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
control_t test_initialize()
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc = FlashJournal_initialize(&journal, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, callbackHandler);
 | 
			
		||||
    TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
 | 
			
		||||
    if (rc == JOURNAL_STATUS_OK) {
 | 
			
		||||
        return CaseTimeout(200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* ensure that something got written into the memory of journal_t */
 | 
			
		||||
    FlashJournal_t mockJournal;
 | 
			
		||||
    memset(&mockJournal, 0, sizeof(FlashJournal_t));
 | 
			
		||||
    TEST_ASSERT_NOT_EQUAL(0, memcmp(&mockJournal, &journal, sizeof(FlashJournal_t)));
 | 
			
		||||
 | 
			
		||||
    FlashJournal_Info_t info;
 | 
			
		||||
    rc = FlashJournal_getInfo(&journal, &info);
 | 
			
		||||
    TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
 | 
			
		||||
    TEST_ASSERT(info.capacity > 0);
 | 
			
		||||
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
control_t test_resetAndInitialize(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
    FlashJournal_Info_t info;
 | 
			
		||||
    SequentialFlashJournal_t *sequentialJournal = (SequentialFlashJournal_t *)&journal;
 | 
			
		||||
 | 
			
		||||
    static uint64_t previousCapacity;
 | 
			
		||||
 | 
			
		||||
    static enum {
 | 
			
		||||
        NEEDS_INITIAL_RESET,
 | 
			
		||||
        NEEDS_INITIALIZE_FOLLOWING_RESET,
 | 
			
		||||
        NEEDS_VERIFICATION_FOLLOWING_INITIALIZE,
 | 
			
		||||
    } state;
 | 
			
		||||
 | 
			
		||||
    printf("test_resetAndInitialize: entered with call_count %u\n", call_count);
 | 
			
		||||
    if (call_count == 1) {
 | 
			
		||||
        state = NEEDS_INITIAL_RESET;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (state) {
 | 
			
		||||
        case NEEDS_INITIAL_RESET:
 | 
			
		||||
            rc = FlashJournal_getInfo(&journal, &info);
 | 
			
		||||
            TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
 | 
			
		||||
            TEST_ASSERT(info.capacity > 0);
 | 
			
		||||
            previousCapacity = info.capacity;
 | 
			
		||||
 | 
			
		||||
            printf("test_resetAndInitialize: calling reset()\n");
 | 
			
		||||
            rc = FlashJournal_reset(&journal);
 | 
			
		||||
            TEST_ASSERT_NOT_EQUAL(JOURNAL_STATUS_UNSUPPORTED, rc);
 | 
			
		||||
            TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
 | 
			
		||||
            state = NEEDS_INITIALIZE_FOLLOWING_RESET;
 | 
			
		||||
            if (rc == JOURNAL_STATUS_OK) {
 | 
			
		||||
                TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
 | 
			
		||||
                return CaseTimeout(1000) + CaseRepeatAll;
 | 
			
		||||
            }
 | 
			
		||||
            TEST_ASSERT_EQUAL(1, rc); /* synchronous completion of reset() is expected to return 1 */
 | 
			
		||||
 | 
			
		||||
            /* fall through */
 | 
			
		||||
        case NEEDS_INITIALIZE_FOLLOWING_RESET:
 | 
			
		||||
            /* ensure that the journal has been re-initialized */
 | 
			
		||||
            TEST_ASSERT_EQUAL(0, sequentialJournal->nextSequenceNumber);
 | 
			
		||||
            TEST_ASSERT_EQUAL((uint32_t)-1, sequentialJournal->currentBlobIndex);
 | 
			
		||||
            TEST_ASSERT_EQUAL(SEQUENTIAL_JOURNAL_STATE_INITIALIZED, sequentialJournal->state);
 | 
			
		||||
 | 
			
		||||
            rc = FlashJournal_getInfo(&journal, &info);
 | 
			
		||||
            TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
 | 
			
		||||
            TEST_ASSERT(info.capacity > 0);
 | 
			
		||||
            TEST_ASSERT_EQUAL(previousCapacity, info.capacity);
 | 
			
		||||
            TEST_ASSERT_EQUAL(0, info.sizeofJournaledBlob);
 | 
			
		||||
 | 
			
		||||
            /* attempt an initialize following reset() */
 | 
			
		||||
            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;
 | 
			
		||||
            if (rc == JOURNAL_STATUS_OK) {
 | 
			
		||||
                return CaseTimeout(200);
 | 
			
		||||
            }
 | 
			
		||||
            TEST_ASSERT_EQUAL(1, rc); /* synchronous completion of initialize() is expected to return 1 */
 | 
			
		||||
 | 
			
		||||
            /* fall through */
 | 
			
		||||
        case NEEDS_VERIFICATION_FOLLOWING_INITIALIZE:
 | 
			
		||||
        default:
 | 
			
		||||
            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);
 | 
			
		||||
 | 
			
		||||
            rc = FlashJournal_getInfo(&journal, &info);
 | 
			
		||||
            TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
 | 
			
		||||
            TEST_ASSERT(info.capacity > 0);
 | 
			
		||||
            TEST_ASSERT_EQUAL(previousCapacity, info.capacity);
 | 
			
		||||
            TEST_ASSERT_EQUAL(0, info.sizeofJournaledBlob);
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
control_t test_commitWithoutLogs(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    printf("test_commitWithoutLogs: entered with call_count %u\n", call_count);
 | 
			
		||||
 | 
			
		||||
    switch (call_count) {
 | 
			
		||||
        case 1:
 | 
			
		||||
            /* initialize */
 | 
			
		||||
            rc = FlashJournal_initialize(&journal, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, callbackHandler);
 | 
			
		||||
            TEST_ASSERT(rc >= ARM_DRIVER_OK);
 | 
			
		||||
            if (rc == ARM_DRIVER_OK) {
 | 
			
		||||
                return CaseTimeout(200) + CaseRepeatAll;
 | 
			
		||||
            }
 | 
			
		||||
            TEST_ASSERT_EQUAL(1, rc); /* synchronous completion of initialize() is expected to return 1 */
 | 
			
		||||
            return CaseRepeatAll;
 | 
			
		||||
 | 
			
		||||
        case 2:
 | 
			
		||||
            rc = FlashJournal_commit(&journal);
 | 
			
		||||
            // 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);
 | 
			
		||||
                return CaseTimeout(500) + CaseRepeatAll;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* intentional fall through*/
 | 
			
		||||
            callbackStatus = rc;
 | 
			
		||||
 | 
			
		||||
        case 3:
 | 
			
		||||
            TEST_ASSERT_EQUAL(1, callbackStatus);
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
control_t test_logSmallWithoutCommit(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    printf("test_logSmallWithoutCommit: entered with call_count %u\n", call_count);
 | 
			
		||||
 | 
			
		||||
    switch (call_count) {
 | 
			
		||||
        case 1:
 | 
			
		||||
            /* initialize */
 | 
			
		||||
            rc = FlashJournal_initialize(&journal, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, callbackHandler);
 | 
			
		||||
            TEST_ASSERT(rc >= ARM_DRIVER_OK);
 | 
			
		||||
            if (rc == ARM_DRIVER_OK) {
 | 
			
		||||
                return CaseTimeout(200) + CaseRepeatAll;
 | 
			
		||||
            }
 | 
			
		||||
            TEST_ASSERT_EQUAL(1, rc); /* synchronous completion of initialize() is expected to return 1 */
 | 
			
		||||
            return CaseRepeatAll;
 | 
			
		||||
 | 
			
		||||
        case 2:
 | 
			
		||||
            /* log without commit */
 | 
			
		||||
            memset(buffer, 0xAA, SIZEOF_SMALL_WRITE);
 | 
			
		||||
            rc = FlashJournal_log(&journal, buffer, SIZEOF_SMALL_WRITE);
 | 
			
		||||
            TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
 | 
			
		||||
            if (rc == JOURNAL_STATUS_OK) {
 | 
			
		||||
                TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
 | 
			
		||||
                return CaseTimeout(500) + CaseRepeatAll;
 | 
			
		||||
            }
 | 
			
		||||
            /* else, fall through to synchronous verification */
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            rc = FlashJournal_read(&journal, buffer, SIZEOF_SMALL_WRITE);
 | 
			
		||||
            TEST_ASSERT(rc < JOURNAL_STATUS_OK);
 | 
			
		||||
            return CaseNext;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <uint8_t PATTERN>
 | 
			
		||||
control_t test_logSmallAndCommit(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    printf("test_logSmallAndCommit: entered with call_count %u\n", call_count);
 | 
			
		||||
 | 
			
		||||
    switch (call_count) {
 | 
			
		||||
        case 1:
 | 
			
		||||
            memset(buffer, PATTERN, SIZEOF_SMALL_WRITE);
 | 
			
		||||
            rc = FlashJournal_log(&journal, buffer, SIZEOF_SMALL_WRITE);
 | 
			
		||||
            TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
 | 
			
		||||
            if (rc == JOURNAL_STATUS_OK) {
 | 
			
		||||
                TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
 | 
			
		||||
                return CaseTimeout(500) + CaseRepeatAll;
 | 
			
		||||
            }
 | 
			
		||||
            /* else, fall through to synchronous verification */
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
            }
 | 
			
		||||
            /* else, fall through to synchronous verification */
 | 
			
		||||
 | 
			
		||||
        case 3:
 | 
			
		||||
            {
 | 
			
		||||
                FlashJournal_Info_t info;
 | 
			
		||||
                rc = FlashJournal_getInfo(&journal, &info);
 | 
			
		||||
                TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
 | 
			
		||||
                TEST_ASSERT_EQUAL(SIZEOF_SMALL_WRITE, info.sizeofJournaledBlob);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            rc = FlashJournal_read(&journal, buffer, SIZEOF_SMALL_WRITE);
 | 
			
		||||
            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_EQUAL(SIZEOF_SMALL_WRITE, rc);
 | 
			
		||||
            /* intentional fall-through */
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            for (unsigned i = 0; i < SIZEOF_SMALL_WRITE; i++) {
 | 
			
		||||
                // printf("index %u value %x\n", i, buffer[i]);
 | 
			
		||||
                TEST_ASSERT_EQUAL(PATTERN, buffer[i]);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return CaseNext;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
control_t test_initializeAfterLogSmallAndCommit(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    printf("test_initializeAfterLogSmallAndCommit: entered with call_count %u\n", 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");
 | 
			
		||||
            return CaseTimeout(200) + CaseRepeatAll;
 | 
			
		||||
        }
 | 
			
		||||
        TEST_ASSERT_EQUAL(1, rc); /* synchronous completion of initialize() is expected to return 1 */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    FlashJournal_Info_t info;
 | 
			
		||||
    rc = FlashJournal_getInfo(&journal, &info);
 | 
			
		||||
    TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
 | 
			
		||||
    TEST_ASSERT_EQUAL(SIZEOF_SMALL_WRITE, info.sizeofJournaledBlob);
 | 
			
		||||
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
control_t test_logLargeWithoutCommit(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    printf("test_logLargeWithoutCommit: entered with call_count %u\n", call_count);
 | 
			
		||||
 | 
			
		||||
    switch (call_count) {
 | 
			
		||||
        case 1:
 | 
			
		||||
            rc = FlashJournal_initialize(&journal, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, callbackHandler);
 | 
			
		||||
            TEST_ASSERT(rc >= ARM_DRIVER_OK);
 | 
			
		||||
            if (rc == ARM_DRIVER_OK) {
 | 
			
		||||
                return CaseTimeout(200) + CaseRepeatAll;
 | 
			
		||||
            }
 | 
			
		||||
            TEST_ASSERT_EQUAL(1, rc); /* synchronous completion of initialize() is expected to return 1 */
 | 
			
		||||
            return CaseRepeatAll;
 | 
			
		||||
 | 
			
		||||
        case 2:
 | 
			
		||||
            memset(buffer, 0xAA, SIZEOF_LARGE_WRITE);
 | 
			
		||||
            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(5000) + CaseRepeatAll;
 | 
			
		||||
            }
 | 
			
		||||
            /* intentional fall-through */
 | 
			
		||||
 | 
			
		||||
        case 3:
 | 
			
		||||
        default:
 | 
			
		||||
            rc = FlashJournal_read(&journal, buffer, SIZEOF_LARGE_WRITE);
 | 
			
		||||
            TEST_ASSERT(rc < JOURNAL_STATUS_OK);
 | 
			
		||||
            return CaseNext;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<uint8_t PATTERN>
 | 
			
		||||
control_t test_logLargeAndCommit(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    printf("test_logLargeAndCommit: entered with call_count %u\n", call_count);
 | 
			
		||||
 | 
			
		||||
    switch (call_count) {
 | 
			
		||||
        case 1:
 | 
			
		||||
            memset(buffer, PATTERN, SIZEOF_LARGE_WRITE);
 | 
			
		||||
            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 */
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
            }
 | 
			
		||||
            /* intentional fall-through */
 | 
			
		||||
 | 
			
		||||
        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);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            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;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            TEST_ASSERT_EQUAL(SIZEOF_LARGE_WRITE, rc);
 | 
			
		||||
            /* intentional fall-through */
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            for (unsigned i = 0; i < SIZEOF_LARGE_WRITE; i++) {
 | 
			
		||||
                // printf("index %u value %x\n", i, buffer[i]);
 | 
			
		||||
                TEST_ASSERT_EQUAL(PATTERN, buffer[i]);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return CaseNext;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
control_t test_initializeAfterLogLargeAndCommit(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    printf("test_initializeAfterLogLargeAndCommit: entered with call_count %u\n", 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");
 | 
			
		||||
            return CaseTimeout(200) + CaseRepeatAll;
 | 
			
		||||
        }
 | 
			
		||||
        TEST_ASSERT_EQUAL(1, rc); /* synchronous completion of initialize() is expected to return 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);
 | 
			
		||||
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<uint8_t PATTERN>
 | 
			
		||||
control_t test_logLargeAndReadSmallChunks(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    printf("test_logLargeAndReadSmallChunks: entered with call_count %u\n", call_count);
 | 
			
		||||
 | 
			
		||||
    static const size_t SMALL_CHUNK_COUNT = 4;
 | 
			
		||||
 | 
			
		||||
    switch (call_count) {
 | 
			
		||||
        case 1:
 | 
			
		||||
            memset(buffer, PATTERN, SIZEOF_LARGE_WRITE);
 | 
			
		||||
            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 */
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
            }
 | 
			
		||||
            /* intentional fall-through */
 | 
			
		||||
 | 
			
		||||
        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 */
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (call_count > 3) {
 | 
			
		||||
        if (drv->GetCapabilities().asynchronous_ops) {
 | 
			
		||||
            if (callbackStatus == 0) {
 | 
			
		||||
                return CaseNext; /* termination condition */
 | 
			
		||||
            }
 | 
			
		||||
            TEST_ASSERT_EQUAL(SIZEOF_LARGE_WRITE / SMALL_CHUNK_COUNT, callbackStatus);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (unsigned i = 0; i < SIZEOF_LARGE_WRITE / SMALL_CHUNK_COUNT; i++) {
 | 
			
		||||
            // printf("index %u value %x\n", i, buffer[i]);
 | 
			
		||||
            TEST_ASSERT_EQUAL(PATTERN, buffer[i]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while ((rc = FlashJournal_read(&journal, buffer, SIZEOF_LARGE_WRITE / SMALL_CHUNK_COUNT)) != JOURNAL_STATUS_EMPTY) {
 | 
			
		||||
        // printf("read returned %ld\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_EQUAL(SIZEOF_LARGE_WRITE / SMALL_CHUNK_COUNT, rc);
 | 
			
		||||
        for (unsigned i = 0; i < SIZEOF_LARGE_WRITE / SMALL_CHUNK_COUNT; i++) {
 | 
			
		||||
            // printf("index %u value %x\n", i, buffer[i]);
 | 
			
		||||
            TEST_ASSERT_EQUAL(PATTERN, buffer[i]);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<uint8_t PATTERN, size_t SIZEOF_READS>
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
    } 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(PATTERN, buffer[i]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while ((rc = FlashJournal_read(&journal, buffer, SIZEOF_READS)) != JOURNAL_STATUS_EMPTY) {
 | 
			
		||||
        // printf("read returned %ld\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(PATTERN, buffer[i]);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t SIZEOF_ODD_CHUNK, size_t N_WRITES>
 | 
			
		||||
control_t test_logSeveralOddSizedChunks(size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    TEST_ASSERT(N_WRITES >= 1);
 | 
			
		||||
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
    TEST_ASSERT(SIZEOF_ODD_CHUNK <= BUFFER_SIZE);
 | 
			
		||||
 | 
			
		||||
    /* check the status of the previous asynchronous operation */
 | 
			
		||||
    if ((call_count > 1) && (call_count <= (N_WRITES + 1))) {
 | 
			
		||||
        TEST_ASSERT((callbackStatus >= JOURNAL_STATUS_OK) || (callbackStatus == JOURNAL_STATUS_SMALL_LOG_REQUEST));
 | 
			
		||||
        if (callbackStatus == JOURNAL_STATUS_SMALL_LOG_REQUEST) {
 | 
			
		||||
            FlashJournal_Info_t info;
 | 
			
		||||
            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");
 | 
			
		||||
            return CaseNext;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        size_t sizeofLoggedData = callbackStatus;
 | 
			
		||||
        TEST_ASSERT((size_t)sizeofLoggedData <= SIZEOF_ODD_CHUNK);
 | 
			
		||||
        if (sizeofLoggedData < SIZEOF_ODD_CHUNK) {
 | 
			
		||||
            FlashJournal_Info_t info;
 | 
			
		||||
            rc = FlashJournal_getInfo(&journal, &info);
 | 
			
		||||
            TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
 | 
			
		||||
            TEST_ASSERT((sizeofLoggedData % info.program_unit) == 0);
 | 
			
		||||
        }
 | 
			
		||||
        totalDataLogged += sizeofLoggedData;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while (call_count <= N_WRITES) {
 | 
			
		||||
        printf("test_logSeveralOddSizedChunks: iteration with call_count %u\n", 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);
 | 
			
		||||
        TEST_ASSERT((rc >= JOURNAL_STATUS_OK) || (rc == JOURNAL_STATUS_SMALL_LOG_REQUEST));
 | 
			
		||||
        if (rc == JOURNAL_STATUS_OK) {
 | 
			
		||||
            TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
 | 
			
		||||
            return CaseTimeout(500) + CaseRepeatAll;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (rc == JOURNAL_STATUS_SMALL_LOG_REQUEST) {
 | 
			
		||||
            FlashJournal_Info_t info;
 | 
			
		||||
            rc = FlashJournal_getInfo(&journal, &info);
 | 
			
		||||
            TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
 | 
			
		||||
            TEST_ASSERT(SIZEOF_ODD_CHUNK < info.program_unit);
 | 
			
		||||
            return CaseNext;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        size_t sizeofLoggedData = rc;
 | 
			
		||||
        TEST_ASSERT(sizeofLoggedData <= SIZEOF_ODD_CHUNK); /* the amount actually written is expected to be less than the original */
 | 
			
		||||
        if (sizeofLoggedData < SIZEOF_ODD_CHUNK) {
 | 
			
		||||
            FlashJournal_Info_t info;
 | 
			
		||||
            rc = FlashJournal_getInfo(&journal, &info);
 | 
			
		||||
            TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
 | 
			
		||||
            TEST_ASSERT((sizeofLoggedData % info.program_unit) == 0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        totalDataLogged += sizeofLoggedData;
 | 
			
		||||
        ++call_count; /* simulate CaseRepeatAll for the synchronous case */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (call_count == (N_WRITES + 1)) {
 | 
			
		||||
        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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    TEST_ASSERT_EQUAL(1, callbackStatus);
 | 
			
		||||
    {
 | 
			
		||||
        FlashJournal_Info_t info;
 | 
			
		||||
        rc = FlashJournal_getInfo(&journal, &info);
 | 
			
		||||
        TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
 | 
			
		||||
        TEST_ASSERT_EQUAL(totalDataLogged, info.sizeofJournaledBlob);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
control_t test_multipleWritesFollowedByCommitFollowedByMultipleReads(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    static const uint8_t PATTERN      = 0xAA;
 | 
			
		||||
    static const size_t  N_WRITES     = 4;
 | 
			
		||||
    static const size_t  N_READS      = N_WRITES;
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
    if (call_count <= N_WRITES) {
 | 
			
		||||
        printf("writing pattern %02x\n", 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);
 | 
			
		||||
        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_EQUAL(SIZEOF_WRITE, rc);
 | 
			
		||||
        return CaseRepeatAll;
 | 
			
		||||
    } else if (call_count == (N_WRITES + 1)) {
 | 
			
		||||
        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;
 | 
			
		||||
        }
 | 
			
		||||
        // 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);
 | 
			
		||||
        if (call_count == (N_WRITES + 1 /* commit */ + 1 /* first iteration after commit */)) {
 | 
			
		||||
            TEST_ASSERT_EQUAL(1, callbackStatus);
 | 
			
		||||
 | 
			
		||||
            FlashJournal_Info_t info;
 | 
			
		||||
            rc = FlashJournal_getInfo(&journal, &info);
 | 
			
		||||
            TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
 | 
			
		||||
            TEST_ASSERT_EQUAL(BUFFER_SIZE, info.sizeofJournaledBlob);
 | 
			
		||||
        } else {
 | 
			
		||||
            TEST_ASSERT_EQUAL(SIZEOF_READ, callbackStatus);
 | 
			
		||||
            for (unsigned i = 0; i < SIZEOF_READ; i++) {
 | 
			
		||||
                // printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: index %u value %x\n", i, buffer[i]);
 | 
			
		||||
                TEST_ASSERT_EQUAL(PATTERN ^ (readIteration - 1), buffer[i]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        while ((rc = FlashJournal_read(&journal, buffer, SIZEOF_READ)) != JOURNAL_STATUS_EMPTY) {
 | 
			
		||||
            // printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: read returned %ld\n", rc);
 | 
			
		||||
            TEST_ASSERT((rc == JOURNAL_STATUS_OK) || (rc == SIZEOF_READ));
 | 
			
		||||
            if (rc == JOURNAL_STATUS_OK) {
 | 
			
		||||
                TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
 | 
			
		||||
                return CaseTimeout(500) + CaseRepeatAll;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            TEST_ASSERT_EQUAL(SIZEOF_READ, rc);
 | 
			
		||||
            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]);
 | 
			
		||||
            }
 | 
			
		||||
            ++readIteration;
 | 
			
		||||
        };
 | 
			
		||||
        TEST_ASSERT_EQUAL(N_READS + 1, readIteration);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
control_t test_failedSmallWriteFollowedByPaddedWrite(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    static const uint8_t PATTERN = 0xAA;
 | 
			
		||||
 | 
			
		||||
    printf("test_failedSmallWriteFollowedByPaddedWrite: entered with call_count %u\n", call_count);
 | 
			
		||||
 | 
			
		||||
    FlashJournal_Info_t info;
 | 
			
		||||
    rc = FlashJournal_getInfo(&journal, &info);
 | 
			
		||||
    TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
 | 
			
		||||
    TEST_ASSERT(info.program_unit >= 1);
 | 
			
		||||
    if (info.program_unit == 1) {
 | 
			
		||||
        return CaseNext;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static const size_t SMALL_CONSTANT = 8 * info.program_unit;
 | 
			
		||||
    static const size_t SIZEOF_WRITE   = (info.program_unit - 1) + SMALL_CONSTANT;
 | 
			
		||||
    TEST_ASSERT(SIZEOF_WRITE <= BUFFER_SIZE);
 | 
			
		||||
 | 
			
		||||
    memset(buffer, PATTERN, SIZEOF_WRITE);
 | 
			
		||||
 | 
			
		||||
    if (call_count == 1) {
 | 
			
		||||
        rc = FlashJournal_log(&journal, buffer, SIZEOF_WRITE);
 | 
			
		||||
        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_EQUAL(SMALL_CONSTANT, rc);
 | 
			
		||||
        callbackStatus = rc;
 | 
			
		||||
        return CaseRepeatAll;
 | 
			
		||||
    } else if (call_count == 2) {
 | 
			
		||||
        TEST_ASSERT_EQUAL(SMALL_CONSTANT, callbackStatus);
 | 
			
		||||
        rc = FlashJournal_log(&journal, buffer, SIZEOF_WRITE - callbackStatus);
 | 
			
		||||
        TEST_ASSERT_EQUAL(JOURNAL_STATUS_SMALL_LOG_REQUEST, rc);
 | 
			
		||||
 | 
			
		||||
        rc = FlashJournal_getInfo(&journal, &info);
 | 
			
		||||
        TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
 | 
			
		||||
        TEST_ASSERT(info.program_unit >= 1);
 | 
			
		||||
        TEST_ASSERT(info.program_unit <= BUFFER_SIZE);
 | 
			
		||||
 | 
			
		||||
        rc = FlashJournal_log(&journal, buffer, info.program_unit);
 | 
			
		||||
        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_EQUAL(info.program_unit, rc);
 | 
			
		||||
        callbackStatus = rc;
 | 
			
		||||
        return CaseRepeatAll;
 | 
			
		||||
    } else if (call_count == 3) {
 | 
			
		||||
        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;
 | 
			
		||||
        }
 | 
			
		||||
        TEST_ASSERT_EQUAL(1, rc);
 | 
			
		||||
        callbackStatus = rc;
 | 
			
		||||
        return CaseRepeatAll;
 | 
			
		||||
    } else {
 | 
			
		||||
        TEST_ASSERT_EQUAL(1, callbackStatus);
 | 
			
		||||
 | 
			
		||||
        rc = FlashJournal_getInfo(&journal, &info);
 | 
			
		||||
        TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
 | 
			
		||||
        TEST_ASSERT_EQUAL((SIZEOF_WRITE + 1), info.sizeofJournaledBlob);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return CaseNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifndef AVOID_GREENTEA
 | 
			
		||||
// Custom setup handler required for proper Greentea support
 | 
			
		||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(60, "default_auto");
 | 
			
		||||
    // Call the default reporting function
 | 
			
		||||
    return greentea_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
status_t default_setup(const size_t)
 | 
			
		||||
{
 | 
			
		||||
    return STATUS_CONTINUE;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Specify all your test cases here
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
    Case("initialize",                                  test_initialize),
 | 
			
		||||
    Case("reset and initialize1",                       test_resetAndInitialize),
 | 
			
		||||
 | 
			
		||||
    Case("log small item without commit",               test_logSmallWithoutCommit),
 | 
			
		||||
    Case("reset and initialize2",                       test_resetAndInitialize),
 | 
			
		||||
 | 
			
		||||
    Case("commit without logs",                         test_commitWithoutLogs),
 | 
			
		||||
    Case("initialize",                                  test_initialize),
 | 
			
		||||
 | 
			
		||||
    /* log small item, and reinitialize */
 | 
			
		||||
    Case("log small item and commit1",                  test_logSmallAndCommit<0xAA>),
 | 
			
		||||
    Case("initialize after small log and commit1",      test_initializeAfterLogSmallAndCommit),
 | 
			
		||||
    Case("log small item and commit2",                  test_logSmallAndCommit<0x11>),
 | 
			
		||||
    Case("initialize after small log and commit2",      test_initializeAfterLogSmallAndCommit),
 | 
			
		||||
    Case("log small item and commit3",                  test_logSmallAndCommit<0x22>),
 | 
			
		||||
    Case("initialize after small log and commit3",      test_initializeAfterLogSmallAndCommit),
 | 
			
		||||
    Case("log small item and commit4",                  test_logSmallAndCommit<0x55>),
 | 
			
		||||
    Case("initialize after small log and commit4",      test_initializeAfterLogSmallAndCommit),
 | 
			
		||||
    Case("log small item and commit5",                  test_logSmallAndCommit<0xAB>),
 | 
			
		||||
    Case("initialize after small log and commit5",      test_initializeAfterLogSmallAndCommit),
 | 
			
		||||
    Case("reset and initialize3",                       test_resetAndInitialize),
 | 
			
		||||
 | 
			
		||||
    Case("log large item without commit",               test_logLargeWithoutCommit),
 | 
			
		||||
 | 
			
		||||
    /* initialize, log large item, and reinitialize */
 | 
			
		||||
    Case("initialize2",                                 test_initialize),
 | 
			
		||||
    Case("reset and initialize4",                       test_resetAndInitialize),
 | 
			
		||||
    Case("log large item and commit1",                  test_logLargeAndCommit<0xAA>),
 | 
			
		||||
    Case("initialize after large log and commit1",      test_initializeAfterLogLargeAndCommit),
 | 
			
		||||
    Case("log large item and commit2",                  test_logLargeAndCommit<0x55>),
 | 
			
		||||
    Case("initialize after large log and commit2",      test_initializeAfterLogLargeAndCommit),
 | 
			
		||||
    Case("log large item and commit3",                  test_logLargeAndCommit<0x11>),
 | 
			
		||||
    Case("initialize after large log and commit3",      test_initializeAfterLogLargeAndCommit),
 | 
			
		||||
    Case("log large item and commit4",                  test_logLargeAndCommit<0xAB>),
 | 
			
		||||
    Case("initialize after large log and commit4",      test_initializeAfterLogLargeAndCommit),
 | 
			
		||||
    Case("log large item and commit5",                  test_logLargeAndCommit<0x22>),
 | 
			
		||||
    Case("initialize after large log and commit5",      test_initializeAfterLogLargeAndCommit),
 | 
			
		||||
    Case("reset and initialize5",                       test_resetAndInitialize),
 | 
			
		||||
 | 
			
		||||
    Case("log large item and read smaller chunks",      test_logLargeAndReadSmallChunks<0xAA>),
 | 
			
		||||
    Case("read large item in small, odd-sized chunks1", test_readLargeInSmallOddChunks<0xAA, ((BUFFER_SIZE / 2) - 1)>),
 | 
			
		||||
    Case("read large item in small, odd-sized chunks2", test_readLargeInSmallOddChunks<0xAA, 255>),
 | 
			
		||||
    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>),
 | 
			
		||||
 | 
			
		||||
    /* 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>),
 | 
			
		||||
    Case("log odd-sized chunk",                         test_logSeveralOddSizedChunks<101, 11>),
 | 
			
		||||
    Case("log odd-sized chunk",                         test_logSeveralOddSizedChunks<1217, 4>),
 | 
			
		||||
    Case("log odd-sized chunk",                         test_logSeveralOddSizedChunks<2402, 5>),
 | 
			
		||||
    Case("log odd-sized chunk",                         test_logSeveralOddSizedChunks<4803, 3>),
 | 
			
		||||
    Case("log odd-sized chunk",                         test_logSeveralOddSizedChunks<(BUFFER_SIZE-1), 7>),
 | 
			
		||||
 | 
			
		||||
    Case("initialize4",                                 test_initialize),
 | 
			
		||||
    Case("multiple writes, commit, multiple reads",     test_multipleWritesFollowedByCommitFollowedByMultipleReads),
 | 
			
		||||
 | 
			
		||||
    Case("failed small write followed by padded write", test_failedSmallWriteFollowedByPaddedWrite),
 | 
			
		||||
 | 
			
		||||
    Case("reset and initialize6",                       test_resetAndInitialize),
 | 
			
		||||
    // Case("uninitialize", test_uninitialize),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Declare your test specification with a custom setup handler
 | 
			
		||||
#ifndef AVOID_GREENTEA
 | 
			
		||||
Specification specification(greentea_setup, cases);
 | 
			
		||||
#else
 | 
			
		||||
Specification specification(default_setup, cases);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
int main(int argc, char** argv)
 | 
			
		||||
{
 | 
			
		||||
    // Run the test specification
 | 
			
		||||
    Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
Unless specifically indicated otherwise in a file, files are licensed 
 | 
			
		||||
2 under the Apache 2.0 license, as can be found in: apache-2.0.txt 
 | 
			
		||||
 | 
			
		||||
Source code in cfstore_fnmatch.c is licensed under the agreements in the 
 | 
			
		||||
following files:
 | 
			
		||||
- berkeley.txt
 | 
			
		||||
- chernov.txt
 | 
			
		||||
- tatmanjants.txt 
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,65 @@
 | 
			
		|||
###########################################################################
 | 
			
		||||
#
 | 
			
		||||
#  Copyright (c) 2013-2015, 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.
 | 
			
		||||
#
 | 
			
		||||
###########################################################################
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# inline debugging/flashing scripts
 | 
			
		||||
#
 | 
			
		||||
define __SCRIPT_GDB
 | 
			
		||||
	target remote $(DEBUG_HOST)
 | 
			
		||||
	monitor endian little
 | 
			
		||||
	monitor reset
 | 
			
		||||
	monitor halt
 | 
			
		||||
	monitor semihosting enable
 | 
			
		||||
	monitor speed 1000
 | 
			
		||||
	monitor loadbin $(TARGET_BIN) 0
 | 
			
		||||
	monitor flash device = $(CPU)
 | 
			
		||||
	load $(TARGET)
 | 
			
		||||
	file $(TARGET)
 | 
			
		||||
	$(GDB_DEBUG_UVISOR)
 | 
			
		||||
	b vmpu_init_post
 | 
			
		||||
	b app_start
 | 
			
		||||
endef
 | 
			
		||||
export __SCRIPT_GDB
 | 
			
		||||
 | 
			
		||||
define __SCRIPT_FLASH
 | 
			
		||||
	r
 | 
			
		||||
	loadbin $(TARGET_BIN) 0
 | 
			
		||||
	r
 | 
			
		||||
	g
 | 
			
		||||
	q
 | 
			
		||||
endef
 | 
			
		||||
export __SCRIPT_FLASH
 | 
			
		||||
 | 
			
		||||
define __SCRIPT_ERASE
 | 
			
		||||
	h
 | 
			
		||||
	Sleep 100
 | 
			
		||||
	unlock kinetis
 | 
			
		||||
	Sleep 100
 | 
			
		||||
	erase
 | 
			
		||||
	q
 | 
			
		||||
endef
 | 
			
		||||
export __SCRIPT_ERASE
 | 
			
		||||
 | 
			
		||||
define __SCRIPT_RESET
 | 
			
		||||
	h
 | 
			
		||||
	r
 | 
			
		||||
	g
 | 
			
		||||
	q
 | 
			
		||||
endef
 | 
			
		||||
export __SCRIPT_RESET
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,103 @@
 | 
			
		|||
# Secure Key-Value Storage #
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Executive Summary
 | 
			
		||||
 | 
			
		||||
The Configuration Store (CFSTORE) is a secure, 
 | 
			
		||||
associative key-value (KV) store C-Language Hardware Abstraction Layer. 
 | 
			
		||||
CFSTORE provides the secure and persistent storage for:
 | 
			
		||||
- Storing encryption keys data.
 | 
			
		||||
- Storing configuration data.
 | 
			
		||||
- Storing firmware, firmware updates and incremental firmware blocks for assembling into a firmware update.
 | 
			
		||||
 | 
			
		||||
These services are presented to clients with:
 | 
			
		||||
- A conceptually simple, file-like interface for storing and managing data using (key, value) pairs in 
 | 
			
		||||
  persistent storage media. 
 | 
			
		||||
- A simple, hardware-independent API to promote portability across multiple platforms and a low attack surface. 
 | 
			
		||||
- A very small code/memory footprint so CFSTORE is capable of running on highly-constrained memory systems (~10kB free memory)
 | 
			
		||||
  where typically available SRAM << NV storage. 
 | 
			
		||||
- A simple (low complexity) storage capability at the expense of features. For example, CFSTORE only supports the storage of 
 | 
			
		||||
  binary blobs rather than a rich set of data types.  
 | 
			
		||||
 | 
			
		||||
Current support includes:
 | 
			
		||||
- NV-backed support. Integration with Flash Abstraction (Flash Journal Strategy Sequential) for persistent storage on the Freescale FRDM K64F target.
 | 
			
		||||
- SRAM backed support. 
 | 
			
		||||
- More than 60 test cases with >80% test coverage.
 | 
			
		||||
- Comprehensive documentation including doxygen generated API and test case documentation. 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Configuration-Store Software Architecture
 | 
			
		||||
 | 
			
		||||
```C
 | 
			
		||||
    
 | 
			
		||||
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+     
 | 
			
		||||
    |  Configuration Store Client   |     
 | 
			
		||||
    |  e.g. FOTA                    |
 | 
			
		||||
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+     
 | 
			
		||||
 | 
			
		||||
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 | 
			
		||||
    |  Configuration Store          |     |  uvisor                       |
 | 
			
		||||
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+     |                               |
 | 
			
		||||
                                          |                               |
 | 
			
		||||
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+     |                               |
 | 
			
		||||
    |  Flash Abstraction Layer      |     |                               |
 | 
			
		||||
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+     |                               |
 | 
			
		||||
                                          |                               |
 | 
			
		||||
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+     |                               |
 | 
			
		||||
    |  Flash Driver Layer           |     |                               |
 | 
			
		||||
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 | 
			
		||||
 | 
			
		||||
    SW
 | 
			
		||||
    -----------------------------------------------------------------------
 | 
			
		||||
    HW
 | 
			
		||||
 | 
			
		||||
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 | 
			
		||||
    |  NV Storage Media e.g. Flash  |
 | 
			
		||||
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 | 
			
		||||
 | 
			
		||||
    Configuration Store Software Architecture
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The above figure shows the following entities (from top to bottom):
 | 
			
		||||
- A Configuration Store client e.g. FOTA.
 | 
			
		||||
- Configuration Store, the associative KV pair store.
 | 
			
		||||
- Flash Abstraction Layer, portable across the driver layer.
 | 
			
		||||
- Flash Driver layer e.g. CMSIS-Driver.
 | 
			
		||||
- NV Storage Media. These are the physical storage media. 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Providing Feedback
 | 
			
		||||
 | 
			
		||||
If you would like to make a contribution to CFSTORE, please provide feedback/designs/comments/code in one of the following ways:
 | 
			
		||||
- By logging an issue in the CFSTORE repo.
 | 
			
		||||
- By submitting a Pull Request to the CFSTORE repo.
 | 
			
		||||
- By sending an email to:
 | 
			
		||||
-- simon.hughes@arm.com 
 | 
			
		||||
-- milosch.meriac@arm.com
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
# Further Reading
 | 
			
		||||
 | 
			
		||||
* The [CFSTORE Getting Started Guide][CFSTORE_GETSTART] including examples.
 | 
			
		||||
* The [CFSTORE Engineering Requirements.][CFSTORE_ENGREQ]
 | 
			
		||||
* The [CFSTORE High Level Design Document.][CFSTORE_HLD]
 | 
			
		||||
* The [CFSTORE Low Level Design Document.][CFSTORE_LLD]
 | 
			
		||||
* The [CFSTORE Test Plan.][CFSTORE_TESTPLAN]
 | 
			
		||||
* The [CFSTORE Application Note 0001: NXP Freescale Kinetis FRDM-K64F Flash Memory Usage.][CFSTORE_APPNOTE_0001]
 | 
			
		||||
* The [CFSTORE Releases][CFSTORE_RELEASE] provides requirements tracking by listing the requirements supported for a CFSTORE version.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
20160714
 | 
			
		||||
 | 
			
		||||
[CFSTORE_ENGREQ]: doc/design/configuration_store_requirements.md
 | 
			
		||||
[CFSTORE_EX1]: ../TESTS/cfstore/example1/example1.cpp
 | 
			
		||||
[CFSTORE_EX3]: ../TESTS/cfstore/example3/example3.cpp
 | 
			
		||||
[CFSTORE_GETSTART]: doc/design/configuration_store_getting_started.md
 | 
			
		||||
[CFSTORE_HLD]: doc/design/configuration_store_hld.md
 | 
			
		||||
[CFSTORE_LLD]: doc/design/configuration_store_lld.md
 | 
			
		||||
[CFSTORE_TESTPLAN]: doc/design/configuration_store_test_plan.md
 | 
			
		||||
[CFSTORE_PROJPLAN]:doc/design/configuration_store_project.md
 | 
			
		||||
[CFSTORE_RELEASE]: doc/project/configuration_store_releases.md
 | 
			
		||||
[CFSTORE_TERM]: doc/design/configuration_store_terminology.md
 | 
			
		||||
[CFSTORE_APPNOTE_0001]: doc/design/configuration_store_app_note_0001.md
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
{
 | 
			
		||||
  "version": "0.3.3",
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
Copyright (c) 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.
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,31 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 1989, 1993, 1994
 | 
			
		||||
 *	The Regents of the University of California.  All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This code is derived from software contributed to Berkeley by
 | 
			
		||||
 * Guido van Rossum.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *    documentation and/or other materials provided with the distribution.
 | 
			
		||||
 * 4. Neither the name of the University nor the names of its contributors
 | 
			
		||||
 *    may be used to endorse or promote products derived from this software
 | 
			
		||||
 *    without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 | 
			
		||||
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 | 
			
		||||
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
			
		||||
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
			
		||||
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
			
		||||
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
			
		||||
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
			
		||||
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
			
		||||
 * SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (C) 1996 by Andrey A. Chernov, Moscow, Russia.
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *    documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
 | 
			
		||||
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 | 
			
		||||
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
			
		||||
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
			
		||||
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
			
		||||
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
			
		||||
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
			
		||||
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
			
		||||
 * SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,882 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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  configuration_store.h
 | 
			
		||||
 *
 | 
			
		||||
 * This is the interface file to configuration store.
 | 
			
		||||
 *
 | 
			
		||||
 * The following (referred to as [REFERENCE_1] in other parts of the documentation)
 | 
			
		||||
 * discusses synchronous/asynchronous completion of \ref ARM_CFSTORE_DRIVER methods
 | 
			
		||||
 * and the inter-relationship of
 | 
			
		||||
 * \ref ARM_CFSTORE_OPCODE and \ref ARM_CFSTORE_CALLBACK.
 | 
			
		||||
 *
 | 
			
		||||
 * Configuration Store driver dispatch methods can operate in 2 modes:
 | 
			
		||||
 | 
			
		||||
 * - Synchronous (i.e. when
 | 
			
		||||
 *      \ref ARM_CFSTORE_CAPABILITIES ::asynchronous_ops == 0)
 | 
			
		||||
 *   then the \ref ARM_CFSTORE_DRIVER ::Dispatch_Method_Xxx() will return:
 | 
			
		||||
 *      - >= 0 => CFSTORE Dispatch_Method_Xxx() completed successfully
 | 
			
		||||
 *      - otherwise CFSTORE Dispatch_Method_Xxx() did not complete successfully
 | 
			
		||||
 *        (return code supplies further details).
 | 
			
		||||
 *
 | 
			
		||||
 *   In synchronous mode it is optional as to whether the client registers
 | 
			
		||||
 *   a client callback with the Initialize() method. If one is registered, it
 | 
			
		||||
 *   will be called to indicate the synchronous completion status.
 | 
			
		||||
 *
 | 
			
		||||
 * - Asynchronous (i.e. when
 | 
			
		||||
 *      \ref ARM_CFSTORE_CAPABILITIES ::asynchronous_ops == 1)
 | 
			
		||||
 *   then the \ref ARM_CFSTORE_DRIVER ::Dispatch_Method_Xxx() will return:
 | 
			
		||||
 *    - return_value = ARM_DRIVER_OK (i.e. ==0) implies CFSTORE
 | 
			
		||||
 *      Dispatch_Method_Xxx() transaction pending. Dispatch_Method_Xxx()
 | 
			
		||||
 *      completion status will be indicated via
 | 
			
		||||
 *      an asynchronous call to \ref ARM_CFSTORE_CALLBACK registered with the
 | 
			
		||||
 *      \ref ARM_CFSTORE_DRIVER ::(*Initialize)(), where the status supplied to
 | 
			
		||||
 *      the callback will be the final status of the call.
 | 
			
		||||
 *    - return_value > ARM_DRIVER_OK (i.e. > 0) implies CFSTORE Dispatch_Method_Xxx() completely
 | 
			
		||||
 *      synchronously and successfully. The return_value has specific
 | 
			
		||||
 *      meaning for the Dispatch_Method_Xxx() e.g. for the Read() method
 | 
			
		||||
 *      return_value is the number of bytes read.
 | 
			
		||||
 *    - otherwise return_value < 0 => CFSTORE Dispatch_Method_Xxx()
 | 
			
		||||
 *      completed unsuccessfully (return code supplies further details).
 | 
			
		||||
 *
 | 
			
		||||
 * The client registered asynchronous callback method \ref ARM_CFSTORE_CALLBACK is
 | 
			
		||||
 * registered by the client using:
 | 
			
		||||
 *   \ref ARM_CFSTORE_DRIVER ::(*Initialize)(\ref ARM_CFSTORE_CALLBACK callback, void* client_context)
 | 
			
		||||
 * See the (*Initialize) documentation for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * The registered callback has the following prototype:
 | 
			
		||||
 *
 | 
			
		||||
 * typedef void (* \refARM_CFSTORE_CALLBACK)(
 | 
			
		||||
 *                          int32_t status,
 | 
			
		||||
 *                          \ref ARM_CFSTORE_OPCODE cmd_code,
 | 
			
		||||
 *                          void *client_context,
 | 
			
		||||
 *                          \ref ARM_CFSTORE_HANDLE handle);
 | 
			
		||||
 *
 | 
			
		||||
 * Before an asynchronous notification is received, a client can check on the
 | 
			
		||||
 * status of the call by calling \ref ARM_CFSTORE_DRIVER ::(*GetStatus)().
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __CONFIGURATION_STORE_H
 | 
			
		||||
#define __CONFIGURATION_STORE_H
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>								/* requierd for memset() in ARM_CFSTORE_HANDLE_INIT() */
 | 
			
		||||
 | 
			
		||||
#define DEVICE_STORAGE 1						/* enable storage */
 | 
			
		||||
/// @cond CFSTORE_DOXYGEN_DISABLE
 | 
			
		||||
#include <Driver_Storage.h>
 | 
			
		||||
#include <Driver_Common.h>
 | 
			
		||||
 | 
			
		||||
#define ARM_CFSTORE_API_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(1,0)  /* API version */
 | 
			
		||||
#define ARM_CFSTORE_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(0,1)  /* DRV version */
 | 
			
		||||
 | 
			
		||||
/* CFSTORE Specific error codes*/
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED                                      -1000  /* Start of driver specific errors */
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_PREEXISTING_KEY                                    -1001
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND                                      -1002
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE                                     -1003
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_OUT_OF_MEMORY                                      -1004
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_PREEXISTING_KEY_DELETING                           -1005
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE_BUF                                 -1006
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_INTERNAL                                           -1007
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME                                   -1008
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_VALUE_SIZE_TOO_LARGE                               -1009
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_KEY_READ_ONLY                                      -1010
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_INVALID_SEEK                                       -1011
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_KEY_UNREADABLE                                     -1012
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_INVALID_WRITE_BUFFER                               -1013
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_LEN                                    -1014
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED                                      -1015
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_INVALID_READ_BUFFER                                -1016
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_DESCRIPTOR                             -1017
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_PERM_NO_READ_ACCESS                                -1018
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_PERM_NO_WRITE_ACCESS                               -1019
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_PERM_NO_EXECUTE_ACCESS                             -1020
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_NO_PERMISSIONS                                     -1021
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_HANDLE_COUNT_MAX                                   -1022
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_ERROR                               -1023
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_BUSY                                -1024
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_TIMEOUT                             -1025
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_UNSUPPORTED                         -1026
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_PARAMETER                           -1027
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_BOUNDED_CAPACITY                    -1028
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_STORAGE_API_ERROR                   -1029
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_STORAGE_IO_ERROR                    -1030
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_NOT_INITIALIZED                     -1031
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_ATTEMPTING_COMMIT_WITHOUT_WRITE     -1032
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_EMPTY                               -1033
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_SMALL_LOG_REQUEST                   -1034
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING                                  -1035
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_UVISOR_BOX_ID                                      -1036
 | 
			
		||||
#define ARM_CFSTORE_DRIVER_ERROR_UVISOR_NAMESPACE                                   -1037
 | 
			
		||||
/// @endcond
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Type Definitions */
 | 
			
		||||
typedef void *ARM_CFSTORE_HANDLE;   //!< opaque cfstore handle for manipulating cfstore data objects e.g. KV pairs.
 | 
			
		||||
typedef size_t ARM_CFSTORE_SIZE;    //!< CFSTORE type for size parameters.
 | 
			
		||||
typedef size_t ARM_CFSTORE_OFFSET;  //!< CFSTORE type for offset parameters.
 | 
			
		||||
 | 
			
		||||
/** @brief
 | 
			
		||||
 *
 | 
			
		||||
 * Status structure returned from the \ref ARM_CFSTORE_DRIVER (*GetStatus)() function.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct _ARM_CFSTORE_STATUS {
 | 
			
		||||
    uint32_t in_progress  : 1;      //!< indicates a previous \ref ARM_CFSTORE_DRIVER ::Dispatch_Method_Xxx()
 | 
			
		||||
                                    //!< function is still in progress and will complete sometime in the future.
 | 
			
		||||
    uint32_t error : 1;             //!< indicates a previous \ref ARM_CFSTORE_DRIVER ::Dispatch_Method_Xxx()
 | 
			
		||||
                                    //!< function is errored and will complete  sometime in the future.
 | 
			
		||||
} ARM_CFSTORE_STATUS;
 | 
			
		||||
 | 
			
		||||
/* Defines */
 | 
			
		||||
#define CFSTORE_KEY_NAME_MAX_LENGTH     220         //!< The maximum length of the null terminated character
 | 
			
		||||
                                                    //!< string used as a key name string.
 | 
			
		||||
#define CFSTORE_VALUE_SIZE_MAX          (1<<26)     //!< Max size of the KV value blob (currently 64MB)
 | 
			
		||||
#define CFSTORE_HANDLE_BUFSIZE          24          //!< size of the buffer owned and supplied by client
 | 
			
		||||
                                                    //!< to CFSTORE to hold internal data structures, referenced by the key handle.
 | 
			
		||||
 | 
			
		||||
/** @brief   Helper macro to declare handle and client owned buffer supplied
 | 
			
		||||
 *           to CFSTORE for storing opaque handle state
 | 
			
		||||
 */
 | 
			
		||||
#define ARM_CFSTORE_HANDLE_INIT(__name)                                         \
 | 
			
		||||
    uint8_t (__name##_buf_cFsToRe)[CFSTORE_HANDLE_BUFSIZE];                     \
 | 
			
		||||
    ARM_CFSTORE_HANDLE (__name) = (ARM_CFSTORE_HANDLE) (__name##_buf_cFsToRe);  \
 | 
			
		||||
    memset((__name##_buf_cFsToRe), 0, CFSTORE_HANDLE_BUFSIZE)
 | 
			
		||||
 | 
			
		||||
#if defined __MBED__ && defined TOOLCHAIN_GCC_ARM
 | 
			
		||||
/** @brief  Helper macro to swap 2 handles, which is useful for the Find() idiom. */
 | 
			
		||||
#define CFSTORE_HANDLE_SWAP(__a_HaNdLe, __b_HaNdLe)         \
 | 
			
		||||
    do{ ARM_CFSTORE_HANDLE __temp_HaNdLe = (__a_HaNdLe);    \
 | 
			
		||||
        __asm volatile("" ::: "memory");                    \
 | 
			
		||||
        (__a_HaNdLe) = (__b_HaNdLe);                        \
 | 
			
		||||
        __asm volatile("" ::: "memory");                    \
 | 
			
		||||
        (__b_HaNdLe) = (__temp_HaNdLe);                     \
 | 
			
		||||
        __asm volatile("" ::: "memory");                    \
 | 
			
		||||
    }while(0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined __MBED__ && defined TOOLCHAIN_ARM
 | 
			
		||||
/** @brief  Helper macro to swap 2 handles, which is useful for the Find() idiom. */
 | 
			
		||||
#define CFSTORE_HANDLE_SWAP(__a_HaNdLe, __b_HaNdLe)         \
 | 
			
		||||
    do{ ARM_CFSTORE_HANDLE __temp_HaNdLe = (__a_HaNdLe);    \
 | 
			
		||||
        __dmb(0xf);                                         \
 | 
			
		||||
        (__a_HaNdLe) = (__b_HaNdLe);                        \
 | 
			
		||||
        __dmb(0xf);                                         \
 | 
			
		||||
        (__b_HaNdLe) = (__temp_HaNdLe);                     \
 | 
			
		||||
        __dmb(0xf);                                         \
 | 
			
		||||
    }while(0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined __MBED__ && defined TOOLCHAIN_IAR
 | 
			
		||||
/** @brief  Helper macro to swap 2 handles, which is useful for the Find() idiom. */
 | 
			
		||||
/* note, memory barriers may be required in the following implementation */
 | 
			
		||||
#define CFSTORE_HANDLE_SWAP(__a_HaNdLe, __b_HaNdLe)         \
 | 
			
		||||
    do{ ARM_CFSTORE_HANDLE __temp_HaNdLe = (__a_HaNdLe);    \
 | 
			
		||||
        (__a_HaNdLe) = (__b_HaNdLe);                        \
 | 
			
		||||
        (__b_HaNdLe) = (__temp_HaNdLe);                     \
 | 
			
		||||
    }while(0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** @brief   The access control permissions for the key-value. */
 | 
			
		||||
typedef struct ARM_CFSTORE_ACCESS_CONTROL_LIST
 | 
			
		||||
{
 | 
			
		||||
    uint32_t perm_owner_read : 1;       //!< When set this KV is owner readable
 | 
			
		||||
    uint32_t perm_owner_write : 1;      //!< When set this KV is owner writable. The owner should set this bit to be able delete the KV.
 | 
			
		||||
    uint32_t perm_owner_execute : 1;    //!< When set this KV is owner executable
 | 
			
		||||
    uint32_t perm_other_read : 1;       //!< When set this KV is world readable
 | 
			
		||||
    uint32_t perm_other_write : 1;      //!< When set this KV is world writable. If set then a world client can delete this KV.
 | 
			
		||||
    uint32_t perm_other_execute : 1;    //!< When set this KV is world executable (currently not supported)
 | 
			
		||||
    uint32_t reserved : 26;             //!< reserved for future use.
 | 
			
		||||
} ARM_CFSTORE_ACCESS_CONTROL_LIST;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @brief
 | 
			
		||||
 *
 | 
			
		||||
 * File mode bit-field structure for specifying flags for the
 | 
			
		||||
 * following operations:
 | 
			
		||||
 * - ARM_CFSTORE_DRIVER::(*Create)(), when creating a KV.
 | 
			
		||||
 * - ARM_CFSTORE_DRIVER::(*Open)(), when opening a pre-existing KV.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct ARM_CFSTORE_FMODE
 | 
			
		||||
{
 | 
			
		||||
    uint32_t continuous : 1;        //!< If set, the key value should be stored in a continuous sequence
 | 
			
		||||
                                    //!< of hardware addresses (not implemented).
 | 
			
		||||
    uint32_t lazy_flush : 1;        //!< If set then configuration store will defer flushing the KV
 | 
			
		||||
                                    //!< changes until an optimal time. e.g. to save energy rather than
 | 
			
		||||
                                    //!< performing the operation immediately (not implemented).
 | 
			
		||||
    uint32_t flush_on_close : 1;    //!< If set then the key-value should be flushed to the backing store
 | 
			
		||||
                                    //!< when the key is closed (not implemented).
 | 
			
		||||
    uint32_t read : 1;              //!< If set then the KV can be read.
 | 
			
		||||
    uint32_t write : 1;             //!< If set then the KV can be written.
 | 
			
		||||
    uint32_t execute : 1;           //!< If set then the KV can be executed (not implemented).
 | 
			
		||||
    uint32_t storage_detect : 1;    //!< If set then the call to ARM_CFSTORE_DRIVER::(*Create)() returns
 | 
			
		||||
                                    //!< whether a key could be created with the required storage
 | 
			
		||||
                                    //!< characteristics. The key is not created.
 | 
			
		||||
    uint32_t reserved : 25;         //!< Reserved.
 | 
			
		||||
} ARM_CFSTORE_FMODE;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @brief   Descriptor used to create keys */
 | 
			
		||||
typedef struct ARM_CFSTORE_KEYDESC
 | 
			
		||||
{
 | 
			
		||||
    /*key descriptor attributes */
 | 
			
		||||
    ARM_CFSTORE_ACCESS_CONTROL_LIST acl;        //!< Access Control List specifying the access permissions of the KV.
 | 
			
		||||
    uint8_t drl;                                //!< Data retention level for the KV required by the client.
 | 
			
		||||
                                                //!< CFSTORE will store the KV in the specified type store/media.
 | 
			
		||||
    ARM_STORAGE_SECURITY_FEATURES security;     //!< flash security properties for the KV required by the client.
 | 
			
		||||
                                                //!< CFSTORE will store the KV in a storage media supporting
 | 
			
		||||
                                                //!< the specified security attributes.
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;                    //!< A bitfield containing the access mode setting for the key.
 | 
			
		||||
} ARM_CFSTORE_KEYDESC;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @brief
 | 
			
		||||
 *
 | 
			
		||||
 * These are the command code values used for the cmd_code argument to the
 | 
			
		||||
 * \ref ARM_CFSTORE_CALLBACK callback handler. The command code indicates the
 | 
			
		||||
 * \ref ARM_CFSTORE_DRIVER dispatch method previously invocated.
 | 
			
		||||
 */
 | 
			
		||||
typedef enum ARM_CFSTORE_OPCODE {
 | 
			
		||||
    CFSTORE_OPCODE_CLOSE = 1,       //!< used for \ref ARM_CFSTORE_CALLBACK ::cmd_code argument when indicating status for a previous \ref ARM_CFSTORE_DRIVER ::(*Close)() call.
 | 
			
		||||
    CFSTORE_OPCODE_CREATE,          //!< used for \ref ARM_CFSTORE_CALLBACK ::cmd_code argument when indicating status for a previous \ref ARM_CFSTORE_DRIVER ::(*Create)() call.
 | 
			
		||||
    CFSTORE_OPCODE_DELETE,          //!< used for \ref ARM_CFSTORE_CALLBACK ::cmd_code argument when indicating status for a previous \ref ARM_CFSTORE_DRIVER ::(*Delete)() call.
 | 
			
		||||
    CFSTORE_OPCODE_FIND,            //!< used for \ref ARM_CFSTORE_CALLBACK ::cmd_code argument when indicating status for a previous \ref ARM_CFSTORE_DRIVER ::(*Find)() call.
 | 
			
		||||
    CFSTORE_OPCODE_FLUSH,           //!< used for \ref ARM_CFSTORE_CALLBACK ::cmd_code argument when indicating status for a previous \ref ARM_CFSTORE_DRIVER ::(*Flush)() call.
 | 
			
		||||
    CFSTORE_OPCODE_GET_KEY_NAME,    //!< used for \ref ARM_CFSTORE_CALLBACK ::cmd_code argument when indicating status for a previous \ref ARM_CFSTORE_DRIVER ::(*GetKeyName)() call.
 | 
			
		||||
    CFSTORE_OPCODE_GET_STATUS,      //!< used for \ref ARM_CFSTORE_CALLBACK ::cmd_code argument when indicating status for a previous \ref ARM_CFSTORE_DRIVER ::(*GetStatus)() call.
 | 
			
		||||
    CFSTORE_OPCODE_GET_VALUE_LEN,   //!< used for \ref ARM_CFSTORE_CALLBACK ::cmd_code argument when indicating status for a previous \ref ARM_CFSTORE_DRIVER ::(*GetValueLen)() call.
 | 
			
		||||
    CFSTORE_OPCODE_INITIALIZE,      //!< used for \ref ARM_CFSTORE_CALLBACK ::cmd_code argument when indicating status for a previous \ref ARM_CFSTORE_DRIVER ::(*Initialize)() call.
 | 
			
		||||
    CFSTORE_OPCODE_OPEN,            //!< used for \ref ARM_CFSTORE_CALLBACK ::cmd_code argument when indicating status for a previous \ref ARM_CFSTORE_DRIVER ::(*Open)() call.
 | 
			
		||||
    CFSTORE_OPCODE_POWER_CONTROL,   //!< used for \ref ARM_CFSTORE_CALLBACK ::cmd_code argument when indicating status for a previous \ref ARM_CFSTORE_DRIVER ::(*PowerControl)() call.
 | 
			
		||||
    CFSTORE_OPCODE_READ,            //!< used for \ref ARM_CFSTORE_CALLBACK ::cmd_code argument when indicating status for a previous \ref ARM_CFSTORE_DRIVER ::(*Read)() call.
 | 
			
		||||
    CFSTORE_OPCODE_RSEEK,           //!< used for \ref ARM_CFSTORE_CALLBACK ::cmd_code argument when indicating status for a previous \ref ARM_CFSTORE_DRIVER ::(*Rseek)() call.
 | 
			
		||||
    CFSTORE_OPCODE_UNINITIALIZE,    //!< used for \ref ARM_CFSTORE_CALLBACK ::cmd_code argument when indicating status for a previous \ref ARM_CFSTORE_DRIVER ::(*Uninitialize)() call.
 | 
			
		||||
    CFSTORE_OPCODE_WRITE,           //!< used for \ref ARM_CFSTORE_CALLBACK ::cmd_code argument when indicating status for a previous \ref ARM_CFSTORE_DRIVER ::(*Write)() call.
 | 
			
		||||
    CFSTORE_OPCODE_MAX              //!< Sentinel
 | 
			
		||||
} ARM_CFSTORE_OPCODE;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @brief   client registered callback type for receiving asynchronous event
 | 
			
		||||
 *           notifications.
 | 
			
		||||
 *
 | 
			
		||||
 * @param   status
 | 
			
		||||
 *          In the case that cmd_code is one of ARM_CFSTORE_OPCODE then this
 | 
			
		||||
 *          is the asynchronous completion status of the associated
 | 
			
		||||
 *          ARM_CFSTORE_DRIVER::Dispatch_Method_Xxx()
 | 
			
		||||
 * @param   cmd_code
 | 
			
		||||
 *          ARM_CFSTORE_OPCODE for the
 | 
			
		||||
 *          ARM_CFSTORE_DRIVER::Dispatch_Method_Xxx() for which this
 | 
			
		||||
 *          invocation of the callback is an asynchronous completion event.
 | 
			
		||||
 * @param   client_context
 | 
			
		||||
 *          The client ARM_CFSTORE_CALLBACK context registered with the
 | 
			
		||||
 *          ARM_CFSTORE_DRIVER::(*Initialize)() method.
 | 
			
		||||
 * @param   handle
 | 
			
		||||
 *          For certain ARM_CFSTORE_DRIVER::Dispatch_Method_Xxx() e.g.
 | 
			
		||||
 *              ARM_CFSTORE_DRIVER::(*Create)()
 | 
			
		||||
 *              ARM_CFSTORE_DRIVER::(*Open)()
 | 
			
		||||
 *              ARM_CFSTORE_DRIVER::(*Find)()
 | 
			
		||||
 *          then an open key handle is supplied upon asynchronous completion.
 | 
			
		||||
 *          See the documentation of the ARM_CFSTORE_OpCode_e and the
 | 
			
		||||
 *          ARM_CFSTORE_DRIVER::Dispatch_Method_Xxx() for further details.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
typedef void (*ARM_CFSTORE_CALLBACK)(int32_t status, ARM_CFSTORE_OPCODE cmd_code, void *client_context, ARM_CFSTORE_HANDLE handle);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @brief   Find the capabilities of the configuration store. */
 | 
			
		||||
typedef struct ARM_CFSTORE_CAPABILITIES
 | 
			
		||||
{
 | 
			
		||||
    uint32_t asynchronous_ops : 1;          //!< When set then the configuration store dispatch interface is operating in non-blocking (asynchronous) mode.
 | 
			
		||||
                                            //!< When unset then the configuration store dispatch interface is operating in blocking (synchronous) mode.
 | 
			
		||||
    uint32_t uvisor_support_enabled : 1;    //!< The configuration store is using uvisor security contexts.
 | 
			
		||||
} ARM_CFSTORE_CAPABILITIES;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This is the set of operations constituting the Configuration Store driver.
 | 
			
		||||
 *
 | 
			
		||||
 * The functions dispatch methods can operate synchronously or asynchronously
 | 
			
		||||
 * depending on the underlying implementation. The client of this interface
 | 
			
		||||
 * should not assume one or other mode of operation but use the
 | 
			
		||||
 * (*GetCapabilities) method to determine the operational mode and then
 | 
			
		||||
 * behave accordingly.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct _ARM_DRIVER_CFSTORE
 | 
			
		||||
{
 | 
			
		||||
    /** @brief  Get driver version.
 | 
			
		||||
     *
 | 
			
		||||
     * The synchronous function GetVersion() returns version information of the
 | 
			
		||||
     * driver implementation in ARM_DRIVER_VERSION.
 | 
			
		||||
     *    - ARM_DRIVER_VERSION::api
 | 
			
		||||
     *        the version of the CMSIS-Driver specification used to implement
 | 
			
		||||
     *        this driver.
 | 
			
		||||
     *    - ARM_DRIVER_VERSION::drv
 | 
			
		||||
     *        the source code version of the actual configuration store driver
 | 
			
		||||
     *        implementation.
 | 
			
		||||
     *
 | 
			
		||||
     * @return    \ref ARM_DRIVER_VERSION, the configuration store driver
 | 
			
		||||
     *            version information
 | 
			
		||||
     */
 | 
			
		||||
    ARM_DRIVER_VERSION (*GetVersion)(void);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** @brief  Close the hkey context previously recovered from CFSTORE.
 | 
			
		||||
     *
 | 
			
		||||
     * @param   hkey
 | 
			
		||||
     *          IN: a previously returned handle from (*Create((), (*Open)()
 | 
			
		||||
     *          or (*Find)() to close.
 | 
			
		||||
     *
 | 
			
		||||
     * @return
 | 
			
		||||
     *
 | 
			
		||||
     * See REFERENCE_1 and the ARM_CFSTORE_CALLBACK documentation.
 | 
			
		||||
     * ARM_CFSTORE_DRIVER::(*Close)() asynchronous completion command code
 | 
			
		||||
     * (*ARM_CFSTORE_CALLBACK) function argument values on return:
 | 
			
		||||
     * @param   status
 | 
			
		||||
     *          ARM_DRIVER_OK => success, KV deleted, else failure.
 | 
			
		||||
     * @param   cmd_code == CFSTORE_OPCODE_CLOSE
 | 
			
		||||
     * @param   client context
 | 
			
		||||
     *          as registered with ARM_CFSTORE_DRIVER::(*Initialize)()
 | 
			
		||||
     * @param   hkey == NULL
 | 
			
		||||
     */
 | 
			
		||||
    int32_t (*Close)(ARM_CFSTORE_HANDLE hkey);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** @brief  Create a key-value int he configuration strore.
 | 
			
		||||
     *
 | 
			
		||||
     * Once created, the following attributes of a KV cannot be changed:
 | 
			
		||||
     *  - the key_name
 | 
			
		||||
     *  - the permissions or attributes specifies by the key descriptor kdesc.
 | 
			
		||||
     * To change these properties, the key must be deleted and then created
 | 
			
		||||
     * again with the new properties.
 | 
			
		||||
     *
 | 
			
		||||
     * @param   key_name
 | 
			
		||||
     *          IN: zero terminated string specifying the key name.
 | 
			
		||||
     * @param   value_len
 | 
			
		||||
     *          the client specifies the length of the value data item in the
 | 
			
		||||
     *          KV being created.
 | 
			
		||||
     * @param   kdesc
 | 
			
		||||
     *
 | 
			
		||||
     * IN: key descriptor, specifying how the details of the key
 | 
			
		||||
     * create operations. Note the following cases:
 | 
			
		||||
     * - 1) if key_name is not present in the CFSTORE and kdesc is NULL
 | 
			
		||||
     *      (i.e. a new KV pair is being created),
 | 
			
		||||
     *      then CFSTORE will chose the most appropriate defaults
 | 
			
		||||
     *      e.g. CFSTORE will store the KV in nv store if the value size
 | 
			
		||||
     *      is large, with no security guarantees just safety.
 | 
			
		||||
     * - 2) if key_name is present in the CFSTORE and kdesc is NULL
 | 
			
		||||
     *      (i.e. there is a pre-existing KV pair),
 | 
			
		||||
     *      then CFSTORE will grow/shrink the value data buffer to
 | 
			
		||||
     *      value_len octets. This idiom can be used to increase/decrease
 | 
			
		||||
     *      the size of the KV value storage.
 | 
			
		||||
     * - 3) If the kdesc->flags.storage_detect == 1 then the function
 | 
			
		||||
     *      does not create the key but reports whether the key
 | 
			
		||||
     *      with the specified size and storage media attributes
 | 
			
		||||
     *      could/could not be created by configuration storage.
 | 
			
		||||
     *
 | 
			
		||||
     * @param   hkey
 | 
			
		||||
     *          IN: pointer to client owned buffer of CFSTORE_HANDLE_BUFSIZE
 | 
			
		||||
     *          bytes
 | 
			
		||||
     *          OUT: on success, hkey is a valid handle to a KV.
 | 
			
		||||
     *
 | 
			
		||||
     * @return
 | 
			
		||||
     *
 | 
			
		||||
     * See REFERENCE_1 and the ARM_CFSTORE_CALLBACK documentation.
 | 
			
		||||
     * ARM_CFSTORE_DRIVER::(*Create)() asynchronous completion command code
 | 
			
		||||
     * (*ARM_CFSTORE_CALLBACK) function argument values on return:
 | 
			
		||||
     * @param    status
 | 
			
		||||
     *           ARM_DRIVER_OK => success, KV deleted, else failure.
 | 
			
		||||
     * @param    cmd_code == CFSTORE_OPCODE_CREATE
 | 
			
		||||
     * @param    client context
 | 
			
		||||
     *           as registered with ARM_CFSTORE_DRIVER::(*Initialize)()
 | 
			
		||||
     * @param    hkey now contains returned handle to newly created key.
 | 
			
		||||
     */
 | 
			
		||||
    int32_t (*Create)(const char* key_name, ARM_CFSTORE_SIZE value_len, const ARM_CFSTORE_KEYDESC* kdesc, ARM_CFSTORE_HANDLE hkey);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** @brief  Delete key-value from configuration store
 | 
			
		||||
     *
 | 
			
		||||
     * This method is used in the following ways:
 | 
			
		||||
     * - (*Open)() to get a handle to the key, (*Delete)() to delete the key,
 | 
			
		||||
     *   (*Close)() to close the handle to the key.
 | 
			
		||||
     * - (*Find)() to get a handle to the key, (*Delete)() to delete the key,
 | 
			
		||||
     *   (*Close)() to close the handle to the key.
 | 
			
		||||
     *
 | 
			
		||||
     * @param   hkey
 | 
			
		||||
     *          IN: the handle of the key to delete.
 | 
			
		||||
     *
 | 
			
		||||
     * @return
 | 
			
		||||
     *
 | 
			
		||||
     * See REFERENCE_1 and the ARM_CFSTORE_CALLBACK documentation.
 | 
			
		||||
     * ARM_CFSTORE_DRIVER::(*Delete)() asynchronous completion command code
 | 
			
		||||
     * (*ARM_CFSTORE_CALLBACK) function argument values on return:
 | 
			
		||||
     * @param    status
 | 
			
		||||
     *           ARM_DRIVER_OK => success, KV deleted, else failure.
 | 
			
		||||
     * @param    cmd_code == CFSTORE_OPCODE_DELETE
 | 
			
		||||
     * @param    client context
 | 
			
		||||
     *           as registered with ARM_CFSTORE_DRIVER::(*Initialize)()
 | 
			
		||||
     * @param    hkey, unused.
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
    int32_t (*Delete)(ARM_CFSTORE_HANDLE hkey);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** @brief   find stored keys that match a query string
 | 
			
		||||
     *
 | 
			
		||||
     *          find a list of pre-existing keys according to a query pattern.
 | 
			
		||||
     *          The search pattern can have the following formats
 | 
			
		||||
     *           - 'com.arm.mbed.wifi.accesspoint.essid'. Find whether an object
 | 
			
		||||
     *              exists that has a key matching
 | 
			
		||||
     *              'com.arm.mbed.wifi.accesspoint.essid'
 | 
			
		||||
     *           - 'com.arm.mbed.wifi.accesspoint*.essid'. Find all keys that
 | 
			
		||||
     *             start with the substring 'com.arm.mbed.wifi.accesspoint' and
 | 
			
		||||
     *             end with the substring '.essid'
 | 
			
		||||
     *           - 'com.arm.mbed.your-registry-module-name.*'. Find all key_name
 | 
			
		||||
     *             strings that begin with the substring
 | 
			
		||||
     *             'com.arm.mbed.your-registry-module-name.'
 | 
			
		||||
     *           - 'com.arm.mbed.hello-world.animal{dog}{foot}{*}'. Find all key_name
 | 
			
		||||
     *             strings beginning com.arm.mbed.hello-world.animal{dog}{foot}
 | 
			
		||||
     *           - 'com.arm.mbed.hello-world.animal{dog}{foot}*'
 | 
			
		||||
     *           - 'com.arm.mbed.hello-world.animal{dog*3}'
 | 
			
		||||
     *
 | 
			
		||||
     *          It is possible to iterate over the list of matching keys by
 | 
			
		||||
     *          using the idiom below (in the synchronous case):
 | 
			
		||||
     * ```
 | 
			
		||||
     *          int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
     *          const char* key_name_query = "*";
 | 
			
		||||
     *          char key_name[CFSTORE_KEY_NAME_MAX_LENGTH+1];
 | 
			
		||||
     *          uint8_t len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
 | 
			
		||||
     *          ARM_CFSTORE_HANDLE_INIT(next);
 | 
			
		||||
     *          ARM_CFSTORE_HANDLE_INIT(prev);
 | 
			
		||||
     *
 | 
			
		||||
     *          while(drv->Find(key_name_query, prev, next) == ARM_DRIVER_OK)
 | 
			
		||||
     *          {
 | 
			
		||||
     *              len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
 | 
			
		||||
     *              drv->GetKeyName(next, key_name, &len);
 | 
			
		||||
     *              printf("Found matching key-value with key_name=%s\n", key_name);
 | 
			
		||||
     *              CFSTORE_HANDLE_SWAP(prev, next);
 | 
			
		||||
     *          }
 | 
			
		||||
     * ```
 | 
			
		||||
     *          The iteration over the find results can be terminated before
 | 
			
		||||
     *          the end of the list is reached by closing the last open
 | 
			
		||||
     *          file handle and not making any further calls to
 | 
			
		||||
     *          find() e.g.
 | 
			
		||||
     *
 | 
			
		||||
     * ```
 | 
			
		||||
     *          int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
     *          const char* key_name_query = "*";
 | 
			
		||||
     *          char key_name[CFSTORE_KEY_NAME_MAX_LENGTH+1];
 | 
			
		||||
     *          uint8_t len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
 | 
			
		||||
     *          ARM_CFSTORE_HANDLE_INIT(next);
 | 
			
		||||
     *          ARM_CFSTORE_HANDLE_INIT(prev);
 | 
			
		||||
     *
 | 
			
		||||
     *          while(drv->Find(key_name_query, prev, next) == ARM_DRIVER_OK)
 | 
			
		||||
     *          {
 | 
			
		||||
     *              len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
 | 
			
		||||
     *              drv->GetKeyName(next, key_name, &len);
 | 
			
		||||
     *              if(strncmp(key_name, "my.key_name", CFSTORE_KEY_NAME_MAX_LENGTH))
 | 
			
		||||
     *              {
 | 
			
		||||
     *                  printf("Found matching key-value with key_name=%s\n", key_name;
 | 
			
		||||
     *                  // terminating walk of find results
 | 
			
		||||
     *                  drv->Close(next);
 | 
			
		||||
     *                  break;
 | 
			
		||||
     *              CFSTORE_HANDLE_SWAP(prev, next);
 | 
			
		||||
     *          }
 | 
			
		||||
     * ```
 | 
			
		||||
     *
 | 
			
		||||
     * @param   key_name_query
 | 
			
		||||
     *          IN: a search string to find. This can include the wildcard '*'
 | 
			
		||||
     *          character
 | 
			
		||||
     * @param   previous
 | 
			
		||||
     *          IN: On the first call to (*Find) then previous is a pointer
 | 
			
		||||
     *          (the handle) to a buffer initialised to 0.
 | 
			
		||||
     *          On the subsequent calls to (*Find), a previously returned
 | 
			
		||||
     *          key handle can be supplied as the previous argument. The next
 | 
			
		||||
     *          available search result will be returned. If no further search
 | 
			
		||||
     *          results are available then (*Find) will return
 | 
			
		||||
     *          ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND. Once the
 | 
			
		||||
     *          file handle has been supplied to the function as the prev
 | 
			
		||||
     *          argument, CFSTORE close the open file handle. Otherwise, the
 | 
			
		||||
     *          client must call (*Close)() on the open file handle.
 | 
			
		||||
     * @param   next
 | 
			
		||||
     *          IN: pointer to client owned buffer of CFSTORE_HANDLE_BUFSIZE
 | 
			
		||||
     *          bytes to hold the
 | 
			
		||||
     *          OUT: Success: In the case that a match has been found then hkey
 | 
			
		||||
     *          is a valid handle to an open KV. The key must be explicitly closed
 | 
			
		||||
     *          by the client. Note this is a read-only key.
 | 
			
		||||
     *          Async operation: The storage at hkey must be available until after
 | 
			
		||||
     *          the completion notification has been received by the client.
 | 
			
		||||
     * @return
 | 
			
		||||
     *          On success (finding a KV matching the query) ARM_DRIVER_OK is
 | 
			
		||||
     *          returned. If a KV is not found matching the description then
 | 
			
		||||
     *          ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND is returned.
 | 
			
		||||
     * See REFERENCE_1 and the ARM_CFSTORE_CALLBACK documentation.
 | 
			
		||||
     * ARM_CFSTORE_DRIVER::(*Find)() asynchronous completion command code
 | 
			
		||||
     * (*ARM_CFSTORE_CALLBACK) function argument values on return:
 | 
			
		||||
     * @param    status
 | 
			
		||||
     *           ARM_DRIVER_OK => success, hkey contains open key
 | 
			
		||||
     *           else failure.
 | 
			
		||||
     * @param    cmd_code == CFSTORE_OPCODE_FIND
 | 
			
		||||
     * @param    client context
 | 
			
		||||
     *           as registered with ARM_CFSTORE_DRIVER::(*Initialize)()
 | 
			
		||||
     * @param    hkey
 | 
			
		||||
     *           ARM_DRIVER_OK => contains returned handle to newly found key.
 | 
			
		||||
     *           else, indeterminate data.
 | 
			
		||||
     */
 | 
			
		||||
    int32_t (*Find)(const char* key_name_query, const ARM_CFSTORE_HANDLE previous, ARM_CFSTORE_HANDLE next);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** @brief
 | 
			
		||||
     *
 | 
			
		||||
     * Flush (write) the configuration changes to the nv backing store.
 | 
			
		||||
     *
 | 
			
		||||
     * All open key handles must be closed before flushing the CFSTORE to nv
 | 
			
		||||
     * backing store.
 | 
			
		||||
     *
 | 
			
		||||
     * @return
 | 
			
		||||
     * See REFERENCE_1 and the ARM_CFSTORE_CALLBACK documentation.
 | 
			
		||||
     * ARM_CFSTORE_DRIVER::(*Flush)() asynchronous completion command code
 | 
			
		||||
     * (*ARM_CFSTORE_CALLBACK) function argument values on return:
 | 
			
		||||
     * @param    status
 | 
			
		||||
     *           ARM_DRIVER_OK => success, hkey contains open key
 | 
			
		||||
     *           else failure.
 | 
			
		||||
     * @param    cmd_code == CFSTORE_OPCODE_FLUSH
 | 
			
		||||
     * @param    client context, registered ARM_CFSTORE_DRIVER::(*Initialize)()
 | 
			
		||||
     * @param    hkey, unused
 | 
			
		||||
     */
 | 
			
		||||
    int32_t (*Flush)(void);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** @brief  Get configuration store capabilities.
 | 
			
		||||
     *
 | 
			
		||||
     * This synchronous function returns a ARM_CFSTORE_CAPABILITIES
 | 
			
		||||
     * information structure describing configuration store implementation
 | 
			
		||||
     * attributes.
 | 
			
		||||
     *
 | 
			
		||||
     * @return \ref ARM_CFSTORE_CAPABILITIES
 | 
			
		||||
     */
 | 
			
		||||
    ARM_CFSTORE_CAPABILITIES (*GetCapabilities)(void);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** @brief  Get the name of an open key handle.
 | 
			
		||||
     *
 | 
			
		||||
     * @param   hkey
 | 
			
		||||
     *          open handle of key to get the key_name
 | 
			
		||||
     * @param   key_name. The key name string is guaranteed to be terminated
 | 
			
		||||
     *          with '\0'.
 | 
			
		||||
     * @param   key_len, the length of the buffer available at data to receive
 | 
			
		||||
     *          the key_name string
 | 
			
		||||
     * @return
 | 
			
		||||
     * See REFERENCE_1 and the ARM_CFSTORE_CALLBACK documentation.
 | 
			
		||||
     * ARM_CFSTORE_DRIVER::(*GetKeyName)() asynchronous completion command code
 | 
			
		||||
     * (*ARM_CFSTORE_CALLBACK) function argument values on return:
 | 
			
		||||
     * @param    status
 | 
			
		||||
     *           ARM_DRIVER_OK => success, key_name contains key_name string, len
 | 
			
		||||
     *           contains length of string.
 | 
			
		||||
     *           else failure.
 | 
			
		||||
     * @param    cmd_code == CFSTORE_OPCODE_GET_KEY_NAME
 | 
			
		||||
     * @param    client context, registered ARM_CFSTORE_DRIVER::(*Initialize)()
 | 
			
		||||
     * @param    hkey supplied to the GetKeyName() call at hkey.
 | 
			
		||||
     * @param    key_name
 | 
			
		||||
     *           on success, the buffer holds the name of the key
 | 
			
		||||
     * @param    key_len
 | 
			
		||||
     *           on success, the supplied integer is set to strlen(key_name)+1, where
 | 
			
		||||
     *           the additional character corresponds to the terminating null.
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
    int32_t (*GetKeyName)(ARM_CFSTORE_HANDLE hkey, char* key_name, uint8_t *key_len);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** @brief  Get the status of the configuration store.
 | 
			
		||||
     *
 | 
			
		||||
     * @return
 | 
			
		||||
     * See REFERENCE_1 and the ARM_CFSTORE_CALLBACK documentation
 | 
			
		||||
     * ARM_DRIVER_OK if the command has been accepted and
 | 
			
		||||
     * enqueued by the underlying controller, else an appropriate
 | 
			
		||||
     * error code. Getting a return value of ARM_DRIVER_OK
 | 
			
		||||
     * implies that basic argument validation was successful, and the
 | 
			
		||||
     * caller can expect a command completion callback to be invoked
 | 
			
		||||
     * at a later time.
 | 
			
		||||
     *
 | 
			
		||||
     * ARM_CFSTORE_DRIVER::(*GetStatus)() asynchronous completion command code
 | 
			
		||||
     * (*ARM_CFSTORE_CALLBACK) function argument values on return:
 | 
			
		||||
     * @param    status
 | 
			
		||||
     *           status of next command pending completion
 | 
			
		||||
     * @param    cmd_code
 | 
			
		||||
     *           next command pending completion.
 | 
			
		||||
     * @param    client context registered ARM_CFSTORE_DRIVER::(*Initialize)()
 | 
			
		||||
     * @param    hkey
 | 
			
		||||
     *              unused.
 | 
			
		||||
     */
 | 
			
		||||
    ARM_CFSTORE_STATUS (*GetStatus)(void);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** @brief  Get the value length from an open key handle
 | 
			
		||||
     *
 | 
			
		||||
     * @param   hkey
 | 
			
		||||
     *          open handle of key for which to get value length
 | 
			
		||||
     * @param   value_len, the location in which to store the value length.
 | 
			
		||||
     * @return
 | 
			
		||||
     * See REFERENCE_1 and the ARM_CFSTORE_CALLBACK documentation.
 | 
			
		||||
     * ARM_CFSTORE_DRIVER::(*GetValueLen)() asynchronous completion command code
 | 
			
		||||
     * (*ARM_CFSTORE_CALLBACK) function argument values on return:
 | 
			
		||||
     * @param    status
 | 
			
		||||
     *           ARM_DRIVER_OK => success, value_len contains length value.
 | 
			
		||||
     *           else failure.
 | 
			
		||||
     * @param    cmd_code == CFSTORE_OPCODE_GET_VALUE_LEN
 | 
			
		||||
     * @param    client context, registered ARM_CFSTORE_DRIVER::(*Initialize)()
 | 
			
		||||
     * @param    hkey supplied to the GetValueLen() call at hkey.
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
    int32_t (*GetValueLen)(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_SIZE *value_len);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** @brief  Initialize the Configuration Store
 | 
			
		||||
     *
 | 
			
		||||
     * This function:
 | 
			
		||||
     *    - initialised the configuration store service
 | 
			
		||||
     *    - allows the client to subscribe to event notifications, in particular
 | 
			
		||||
     *      the asynchronous completion events for the driver dispatch interface
 | 
			
		||||
     *      (see ARM_CFSTORE_OPCODE).
 | 
			
		||||
     *
 | 
			
		||||
     * The configuration store should be initialised as follows:
 | 
			
		||||
     *    drv->initialise(client_callback, client_callback_context);
 | 
			
		||||
     *    drv->PowerControl(ARM_POWER_FULL)
 | 
			
		||||
     * where:
 | 
			
		||||
     *    - client_callback is a client implemented callback function.
 | 
			
		||||
     *    - client_callback_context is a client registered context that
 | 
			
		||||
     *      will be supplied as an argument to the client_callback
 | 
			
		||||
     *      when called.
 | 
			
		||||
     *    - PowerControl indicates that any underlying system services
 | 
			
		||||
     *      that are in the low power state should be powered up.
 | 
			
		||||
     *
 | 
			
		||||
     * The configuration store should be de-initialised as follows:
 | 
			
		||||
     *    drv->PowerControl(ARM_POWER_OFF)
 | 
			
		||||
     *    drv->Deinitialise();
 | 
			
		||||
     *
 | 
			
		||||
     * @param client_callback
 | 
			
		||||
     *        this is a client implemented callback function for
 | 
			
		||||
     *        receiving asynchronous event notifications (see
 | 
			
		||||
     *        ARM_CFSTORE_CALLBACK). NULL indicates client does
 | 
			
		||||
     *        not subscribed to event notifications.
 | 
			
		||||
     *
 | 
			
		||||
     * @param client_callback_context
 | 
			
		||||
     *        this is the client registered context that
 | 
			
		||||
     *        will be supplied as an argument to the client_callback
 | 
			
		||||
     *        when called. This argument can be NULL.
 | 
			
		||||
     *
 | 
			
		||||
     * @return
 | 
			
		||||
     * See REFERENCE_1 and the ARM_CFSTORE_CALLBACK documentation.
 | 
			
		||||
     * ARM_CFSTORE_DRIVER::(*Initialize)() asynchronous completion command code
 | 
			
		||||
     * (*ARM_CFSTORE_CALLBACK) function argument values on return:
 | 
			
		||||
     * @param    status
 | 
			
		||||
     *           ARM_DRIVER_OK => success, configuration store initialised,
 | 
			
		||||
     *           else failure
 | 
			
		||||
     * @param    CFSTORE_OPCODE_INITIALIZE
 | 
			
		||||
     * @param    client context registered ARM_CFSTORE_DRIVER::(*Initialize)()
 | 
			
		||||
     * @param    hkey, unused.
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
    int32_t (*Initialize)(ARM_CFSTORE_CALLBACK callback, void* client_context);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** @brief  Function to set the target configuration store power state.
 | 
			
		||||
     *
 | 
			
		||||
     * @param state
 | 
			
		||||
     *        \ref ARM_POWER_STATE. The target power-state for the
 | 
			
		||||
     *        configuration store. The parameter state can have the
 | 
			
		||||
     *        following values:
 | 
			
		||||
     *          - ARM_POWER_FULL => set the mode to full power state
 | 
			
		||||
     *          - ARM_POWER_LOW  => set the mode to low power state
 | 
			
		||||
     *          - ARM_POWER_OFF  => set the mode to off power state
 | 
			
		||||
     *
 | 
			
		||||
     * @return
 | 
			
		||||
     * See REFERENCE_1 and the ARM_CFSTORE_CALLBACK documentation.
 | 
			
		||||
     * CFSTORE_OPCODE_POWER_CONTROL
 | 
			
		||||
     * ARM_CFSTORE_DRIVER::(*PowerControl)() asynchronous completion command code
 | 
			
		||||
     * (*ARM_CFSTORE_CALLBACK) function argument values on return:
 | 
			
		||||
     * @param    status
 | 
			
		||||
     *           ARM_DRIVER_OK => success, power control set, else failure.
 | 
			
		||||
     * @param    cmd_code == CFSTORE_OPCODE_POWER_CONTROL
 | 
			
		||||
     * @param    client context, registered ARM_CFSTORE_DRIVER::(*Initialize)()
 | 
			
		||||
     * @param    hkey, unused.
 | 
			
		||||
     */
 | 
			
		||||
    int32_t (*PowerControl)(ARM_POWER_STATE state);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** @brief  Read the value data associated with a specified key.
 | 
			
		||||
     *
 | 
			
		||||
     * @param   hkey
 | 
			
		||||
     *          IN: the handle returned from a previous call to (*Open)() to
 | 
			
		||||
     *          get a handle to the key
 | 
			
		||||
     * @param   data
 | 
			
		||||
     *          IN: a pointer to a data buffer supplied by the caller for CFSTORE to
 | 
			
		||||
     *          fill with value data
 | 
			
		||||
     *          OUT: on ARM_DRIVER_OK the data is (or will be when asynchronously
 | 
			
		||||
     *          completed) available in the buffer. The data will be read from
 | 
			
		||||
     *          the current form the current location (see (*Rseek)().
 | 
			
		||||
     * @param   len
 | 
			
		||||
     *          IN: the client specifies the length of the buffer available at data
 | 
			
		||||
     *          OUT: the CFSTORE specifies how many octets have been stored in the
 | 
			
		||||
     *          supplied buffer. Note fewer octets may be stored than the input len
 | 
			
		||||
     *          depending on the CFSTORE internal representation of the value.
 | 
			
		||||
     *
 | 
			
		||||
     * @return
 | 
			
		||||
     * See REFERENCE_1 and the ARM_CFSTORE_CALLBACK documentation.
 | 
			
		||||
     *          return_value == ARM_DRIVER_OK (==0) => asynchronous
 | 
			
		||||
     *          transaction pending.
 | 
			
		||||
     *          return_value > 0 => synchronous completion of read with the
 | 
			
		||||
     *          number of bytes read == return_value
 | 
			
		||||
     *          return_value < 0, error condition.
 | 
			
		||||
     *
 | 
			
		||||
     * ARM_CFSTORE_DRIVER::(*Read)() asynchronous completion command code
 | 
			
		||||
     * (*ARM_CFSTORE_CALLBACK) function argument values on return:
 | 
			
		||||
     * @param    status
 | 
			
		||||
     *           >= 0 => success with number of bytes read as indicated by
 | 
			
		||||
     *           the value of status
 | 
			
		||||
     *           < 0 => error, data in the data buffer is undefined, len is
 | 
			
		||||
     *           undefined.
 | 
			
		||||
     * @param    cmd_code == CFSTORE_OPCODE_READ
 | 
			
		||||
     * @param    client context, registered ARM_CFSTORE_DRIVER::(*Initialize)()
 | 
			
		||||
     * @param    hkey, unused.
 | 
			
		||||
     */
 | 
			
		||||
    int32_t (*Read)(ARM_CFSTORE_HANDLE hkey, void* data, ARM_CFSTORE_SIZE* len);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** @brief  Open a key-value object for future operations.
 | 
			
		||||
     *
 | 
			
		||||
     * @param   key_name
 | 
			
		||||
     *          IN: zero terminated string specifying the key name.
 | 
			
		||||
     * @param   flags
 | 
			
		||||
     *          can open a RW key in read only mode.
 | 
			
		||||
     * @param   hkey
 | 
			
		||||
     *          IN: pointer to client owned buffer of CFSTORE_HANDLE_BUFSIZE
 | 
			
		||||
     *          bytes
 | 
			
		||||
     *          OUT: on success, hkey is a valid handle to an open KV.
 | 
			
		||||
     *
 | 
			
		||||
     * @return
 | 
			
		||||
     * See REFERENCE_1 and the ARM_CFSTORE_CALLBACK documentation.
 | 
			
		||||
     * ARM_CFSTORE_DRIVER::(*Open)() asynchronous completion command code
 | 
			
		||||
     * (*ARM_CFSTORE_CALLBACK) function argument values on return:
 | 
			
		||||
     * @param    status
 | 
			
		||||
     *           ARM_DRIVER_OK => success, KV opened, else failure.
 | 
			
		||||
     * @param    cmd_code == CFSTORE_OPCODE_OPEN
 | 
			
		||||
     * @param    client context, registered ARM_CFSTORE_DRIVER::(*Initialize)()
 | 
			
		||||
     * @param    hkey now contains returned handle to newly opened key.
 | 
			
		||||
     */
 | 
			
		||||
    int32_t (*Open)(const char* key_name, ARM_CFSTORE_FMODE flags, ARM_CFSTORE_HANDLE hkey);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** @brief  Move the position of the read pointer within a value
 | 
			
		||||
     *
 | 
			
		||||
     * @param   hkey
 | 
			
		||||
     *          IN: the key referencing the value data for which the read
 | 
			
		||||
     *          location should be updated. Note that this function can
 | 
			
		||||
     *          only be called on pre-existing keys opened with read-only
 | 
			
		||||
     *          flag. Performing a seek operation on a writable key will fail.
 | 
			
		||||
     * @param   offset
 | 
			
		||||
     *          IN: the new offset position from the start of the value data
 | 
			
		||||
     *
 | 
			
		||||
     * @return
 | 
			
		||||
     * See REFERENCE_1 and the ARM_CFSTORE_CALLBACK documentation.
 | 
			
		||||
     * ARM_CFSTORE_DRIVER::(*Rseek)() asynchronous completion command code
 | 
			
		||||
     * (*ARM_CFSTORE_CALLBACK) function argument values on return:
 | 
			
		||||
     * @param    status
 | 
			
		||||
     *           >=0 => success, read location set, else failure.
 | 
			
		||||
     *           upon success, the function returns the current read
 | 
			
		||||
     *           location measured from the beginning of the data value.
 | 
			
		||||
     *           <0 => error
 | 
			
		||||
     * @param    cmd_code == CFSTORE_OPCODE_RSEEK
 | 
			
		||||
     * @param    client context, registered ARM_CFSTORE_DRIVER::(*Initialize)()
 | 
			
		||||
     * @param    hkey, unused.
 | 
			
		||||
     */
 | 
			
		||||
    int32_t (*Rseek)(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_OFFSET offset);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** @brief  Function to de-initialise the Configuration Store
 | 
			
		||||
     *
 | 
			
		||||
     * @return
 | 
			
		||||
     * See REFERENCE_1 and the ARM_CFSTORE_CALLBACK documentation.
 | 
			
		||||
     * CFSTORE_OPCODE_UNINITIALIZE
 | 
			
		||||
     * ARM_CFSTORE_DRIVER::(*Uninitialize)() asynchronous completion command code
 | 
			
		||||
     * (*ARM_CFSTORE_CALLBACK) function argument values on return:
 | 
			
		||||
     * @param    status
 | 
			
		||||
     *           ARM_DRIVER_OK => success, read location set, else failure.
 | 
			
		||||
     * @param    cmd_code == CFSTORE_OPCODE_UNINITIALIZE
 | 
			
		||||
     * @param    client context, registered ARM_CFSTORE_DRIVER::(*Initialize)()
 | 
			
		||||
     * @param    hkey, unused.
 | 
			
		||||
     */
 | 
			
		||||
    int32_t (*Uninitialize)(void);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** @brief  Write the value data associated with a specified key
 | 
			
		||||
     *
 | 
			
		||||
     * @note    Note that Write() only supports sequential-access.
 | 
			
		||||
     *
 | 
			
		||||
     * @param   hkey
 | 
			
		||||
     *          IN: the key for which value data will be written
 | 
			
		||||
     * @param   data
 | 
			
		||||
     *          IN: a pointer to a data buffer supplied by the caller for CFSTORE to
 | 
			
		||||
     *          write as the binary blob value data.
 | 
			
		||||
     *          Async operation: the buffer must be available until after
 | 
			
		||||
     *          completion notification is received by the client.
 | 
			
		||||
     * @param   len
 | 
			
		||||
     *          IN: the client specifies the length of the data buffer available.
 | 
			
		||||
     *          len must not exceed the value_len field specified when the
 | 
			
		||||
     *          KV pair was created.
 | 
			
		||||
     *          OUT: the CFSTORE specifies how many octets have been stored.
 | 
			
		||||
     *          Note that fewer octets may be stored than the input len
 | 
			
		||||
     *          depending on the CFSTORE internal representation of the value.
 | 
			
		||||
     *          Async operation: the len storage location must be available
 | 
			
		||||
     *          until after completion notification is received by the client.
 | 
			
		||||
     *
 | 
			
		||||
     * @return
 | 
			
		||||
     * See REFERENCE_1 and the ARM_CFSTORE_CALLBACK documentation.
 | 
			
		||||
     *          return_value == ARM_DRIVER_OK (==0) => asynchronous
 | 
			
		||||
     *          transaction pending.
 | 
			
		||||
     *          return_value > 0 => synchronous completion of write with the
 | 
			
		||||
     *          number of bytes written == return_value
 | 
			
		||||
     *          return_value < 0, error condition.
 | 
			
		||||
     *
 | 
			
		||||
     * ARM_CFSTORE_DRIVER::(*Write)() asynchronous completion
 | 
			
		||||
     * (*ARM_CFSTORE_CALLBACK) function argument values on return:
 | 
			
		||||
     * @param    status
 | 
			
		||||
     *           >= 0 => success with the number bytes written equal to the value
 | 
			
		||||
     *           of the return status
 | 
			
		||||
     *           ARM_CFSTORE_CALLBACK status argument < 0 => error
 | 
			
		||||
     * @param    cmd_code == CFSTORE_OPCODE_WRITE
 | 
			
		||||
     * @param    client context, registered ARM_CFSTORE_DRIVER::(*Initialize)()
 | 
			
		||||
     * @param    hkey, unused.
 | 
			
		||||
     */
 | 
			
		||||
    int32_t (*Write)(ARM_CFSTORE_HANDLE hkey, const char* data, ARM_CFSTORE_SIZE* len);
 | 
			
		||||
 | 
			
		||||
} const ARM_CFSTORE_DRIVER;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
extern ARM_CFSTORE_DRIVER cfstore_driver;
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __CONFIGURATION_STORE_H */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,444 @@
 | 
			
		|||
# Configuration Store Application Note 0001: NXP Freescale Kinetis FRDM-K64F Flash Memory Usage 
 | 
			
		||||
Author: Simon Hughes
 | 
			
		||||
Revision: v1.0.0
 | 
			
		||||
Date: 7 Jul 2016
 | 
			
		||||
DOCID: CFSTORE_APPNOTE_0001_v1_0_0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Executive Summary
 | 
			
		||||
 | 
			
		||||
The Configuration-Store (CFSTORE)/Flash-Journal Subsystem can be used to store
 | 
			
		||||
application data in the same non-volatile storage medium as the firmware binary image. 
 | 
			
		||||
Flash storage is typically composed of 1..n blocks (the FRDM K64F devboard has 2 x 512kB blocks
 | 
			
		||||
for example) each with its own support logic. Blocks usually have the limitation of: 
 | 
			
		||||
- Prohibiting simultaneous READ and WRITE/ERASE operations in the same flash block, which would otherwise cause
 | 
			
		||||
  READ While WRITE (RWW) errors and consequent system faults.
 | 
			
		||||
- Taking ~100ms for flash WRITE/ERASE operations of ~4kB in size. 
 | 
			
		||||
 | 
			
		||||
This document outlines the impact of these limitations on the system as a whole, including: 
 | 
			
		||||
- Allowing applications to use both CFSTORE/Flash Journal asynchronous and synchronous modes at the 
 | 
			
		||||
  expense of storing CFSTORE data and firmware in separate flash blocks. See Scenario 1 
 | 
			
		||||
  discussed in the next section. 
 | 
			
		||||
- Limiting applications to CFSTORE/Flash Journal synchronous mode when storing CFSTORE data 
 | 
			
		||||
  and firmware in the same flash block. See Scenario 2 below for further details.
 | 
			
		||||
- Increasing interrupt latency in Scenario 2 where interrupts have to be disabled to 
 | 
			
		||||
  prevent RWW errors.
 | 
			
		||||
 | 
			
		||||
### Scenario 1: Firmware & CFSTORE Data Stored In Different Flash Blocks
 | 
			
		||||
 | 
			
		||||
When firmware and CFSTORE data are stored in different flash blocks then: 
 | 
			
		||||
- Both CFSTORE/Flash Journal asynchronous or synchronous modes can be used.
 | 
			
		||||
- Interrupts are not disabled during flash transactions and 
 | 
			
		||||
  interrupt latency is not adversely affected.
 | 
			
		||||
 | 
			
		||||
### Scenario 2: Firmware & CFSTORE Data Stored the Same Flash Block
 | 
			
		||||
 | 
			
		||||
When firmware and CFSTORE data are stored in the same flash block then: 
 | 
			
		||||
- Only CFSTORE/Flash Journal synchronous mode can be used. Flash Journal busy-waits while flash
 | 
			
		||||
  WRITE/ERASE transactions are in-progress.
 | 
			
		||||
- Interrupts are disabled when a flash transaction is in-progress causing
 | 
			
		||||
  interrupt latency to increase.
 | 
			
		||||
 | 
			
		||||
### Consequences of Disabling Interrupts
 | 
			
		||||
 | 
			
		||||
- The disabling of interrupts increases interrupt latency to ~115ms for erasing a 4kB flash sector. 
 | 
			
		||||
  The interrupt latency depends on the number of bytes written/erased in the transaction with ~30us/byte
 | 
			
		||||
  an indicative metric.
 | 
			
		||||
- For applications requiring low interrupt latency 
 | 
			
		||||
  (e.g. BLE, 6LowPAN, 3G, LTE communication stacks requiring ~1ms interrupt latency)
 | 
			
		||||
  then the application must be cognisant of the impact on
 | 
			
		||||
  interrupt latency and perform flash operations at times which will not have a 
 | 
			
		||||
  detrimental impact on communication.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Problem Statement: Freescale Kinetis FRDM-K64F Co-Existence of CFSTORE/Flash-Journal Key-Value Data with Firmware Binary Image in Non-Volatile (Flash) Storage  
 | 
			
		||||
 | 
			
		||||
A design goal of Configuration-Store/Flash-Journal subsystem is to offer persistence storage of:
 | 
			
		||||
- CFSTORE Key Value data items (application data), and 
 | 
			
		||||
- the application firmware image
 | 
			
		||||
 | 
			
		||||
in the *same* non-volatile storage component (e.g. flash).  
 | 
			
		||||
 | 
			
		||||
To achieve this goal the implementation must ensure READ while WRITE errors are avoided when implementing 
 | 
			
		||||
in-software flash-programming applications (e.g. CFSTORE/Flash-Journal) as discussed in the 
 | 
			
		||||
[NXP Application Note on Avoiding Read While Write Errors][NXP_FREESCALE_AN4695]: 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
> Embedded flash memory is grouped into blocks. Each block contains the 
 | 
			
		||||
> circuitry required to read, erase, and program within
 | 
			
		||||
> that block. Most of the flash memory technologies have a 
 | 
			
		||||
> limitation of not allowing read operations at the same time as an
 | 
			
		||||
> erase or program operation is occurring within the same block. 
 | 
			
		||||
> Thus, erasing/programming a sector is not allowed if code
 | 
			
		||||
> execution (fetching instructions = reading) is taking place within 
 | 
			
		||||
> the same block even if the read is in a different flash sector
 | 
			
		||||
> than the erase/program. This is called a Read While Write (RWW) 
 | 
			
		||||
> violation and will result in a Read Collision error on
 | 
			
		||||
> Kinetis and other microcontrollers.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
To summarise the above, the CFSTORE/Flash-Journal implementation must not cause 
 | 
			
		||||
READ while WRITE (RWW) violations. 
 | 
			
		||||
 | 
			
		||||
## Freescale FRDM K64 Flash Address Maps for CFSTORE and Firmware Storage
 | 
			
		||||
 | 
			
		||||
### Scenario 1: Firmware & CFSTORE Data Stored In Different Flash Blocks
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 -------------------------------- 0x00100000 = 1MB      flash_addr_end      ^
 | 
			
		||||
 |                              |                                           |
 | 
			
		||||
 | CFSTORE Flash Journal Slot 3 |                                           |
 | 
			
		||||
 |                              |                                           |
 | 
			
		||||
 |- - - - - - - - - - - - - - - |                                           |
 | 
			
		||||
 |                              |                                           B
 | 
			
		||||
 | CFSTORE Flash Journal Slot 2 |                                           L
 | 
			
		||||
 |                              |                                           O
 | 
			
		||||
 |- - - - - - - - - - - - - - - |                                           C
 | 
			
		||||
 |                              |                                           K
 | 
			
		||||
 | CFSTORE Flash Journal Slot 1 |                                           1
 | 
			
		||||
 |                              |                                           |
 | 
			
		||||
 |- - - - - - - - - - - - - - - |                                           |
 | 
			
		||||
 |                              |                                           |
 | 
			
		||||
 | CFSTORE Flash Journal Slot 0 |                                           |
 | 
			
		||||
 |                              |                                           v
 | 
			
		||||
 -------------------------------- 0x00080000 = 512kB                        ^
 | 
			
		||||
 |                              | CONFIG_HARDWARE_MTD_START_ADDR            |
 | 
			
		||||
 |       Unused Flash           | (defaults to 0x80000UL)                   |
 | 
			
		||||
 |                              |                                           |
 | 
			
		||||
 |------------------------------| firmware_addr_end == __uvisor_flash_end   |
 | 
			
		||||
 |//////////////////////////////|                                           |
 | 
			
		||||
 |//////////////////////////////|                                           |
 | 
			
		||||
 |//////////////////////////////|                                           |
 | 
			
		||||
 |//////////////////////////////|                                           B
 | 
			
		||||
 |//////////////////////////////|                                           L
 | 
			
		||||
 |////////          ////////////|                                           O
 | 
			
		||||
 |//////// Firmware ////////////|                                           C
 | 
			
		||||
 |////////          ////////////|                                           K
 | 
			
		||||
 |//////////////////////////////|                                           0
 | 
			
		||||
 |//////////////////////////////|                                           |
 | 
			
		||||
 |//////////////////////////////|                                           |
 | 
			
		||||
 |//////////////////////////////|                                           |
 | 
			
		||||
 |//////////////////////////////|  											|
 | 
			
		||||
 --------------------------------  0x00000000           flash_addr_start    v
 | 
			
		||||
                                                    == firmware_addr_start
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
 Figure 1: Scenario 1 K64F Flash Address Map Showing Default Firmware and CFSTORE Allocations. 
 | 
			
		||||
 
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The K64F has 2 flash blocks (see Figure 1):
 | 
			
		||||
- BLOCK0 for 0x00000000-0x00007ffff of the flash memory map (lower 512kB).
 | 
			
		||||
- BLOCK1 for 0x00007ffff-0x000fffff of the flash memory map (upper 512kB).
 | 
			
		||||
 | 
			
		||||
In this scenario (which is also the default CFSTORE/Flash Journal configuration) 
 | 
			
		||||
BLOCK0 is used exclusively to store program code/data and 
 | 
			
		||||
BLOCK1 is used exclusively for CFSTORE key-value data. It's therefore possible to operate flash-journal 
 | 
			
		||||
in both flash journal synchronous and asynchronous modes provided certain restrictions are observed in the implementation. 
 | 
			
		||||
 | 
			
		||||
Figure 1 shows the flash memory layout on the K64F for Scenario 1 where the following points can be noted:
 | 
			
		||||
- The K64F has 1MB of flash divided into 2 x 512kB blocks, shown as BLOCK0 and BLOCK1 in the figure.
 | 
			
		||||
- By default, CFSTORE is configured to occupy the whole of BLOCK1 (512kB) leaving BLOCK0 (512kB) 
 | 
			
		||||
  for the firmware image. This can be changed with configuration options (see the next section for details).
 | 
			
		||||
- CFSTORE/Flash Journal are written so that the CFSTORE can be configured to occupy as small a space 
 | 
			
		||||
  as required using configuration options.
 | 
			
		||||
- CFSTORE should always be at the top of flash memory i.e. there should not be a gap after the 
 | 
			
		||||
  end of the CFSTORE area, as this space can be used to store a firmware image (and would 
 | 
			
		||||
  otherwise be wasted).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#### Scenario 1 Advantages and Disadvantages
 | 
			
		||||
 | 
			
		||||
This scenario has the following advantages/disadvantages:
 | 
			
		||||
- Advantage: the separation of the firmware image and CFSTORE KV data into different
 | 
			
		||||
  blocks implicitly avoids RWW violations. The model is also simple to picture 
 | 
			
		||||
  and understand.
 | 
			
		||||
- Advantage: CFSTORE/Flash-journal can be operated in both synchronous or asynchronous modes. Asynchronous
 | 
			
		||||
  mode has performance benefits as CPU/SRAM bound processing can proceed in parallel
 | 
			
		||||
  with the flash IO transaction.
 | 
			
		||||
- Disadvantage: The maximum firmware image size is 512kB because the other 
 | 
			
		||||
  flash block is being used exclusively by CFSTORE, even if only small amounts of 
 | 
			
		||||
  KV data are being persisted to flash. 
 | 
			
		||||
- Disadvantage: Release binary sizes may typically be smaller than 512kB but debug
 | 
			
		||||
  build binaries, or firmware instrumented with test code/harnesses may typically
 | 
			
		||||
  be larger, making testing/debugging problematic.
 | 
			
		||||
 | 
			
		||||
  
 | 
			
		||||
#### Scenario 1 Eliminates Flash READ While WRITE Collisions 
 | 
			
		||||
 | 
			
		||||
Flash-Journal asynchronous mode can be used because RWW collisions are not possible i.e. 
 | 
			
		||||
a flash READ operation for program instructions during 
 | 
			
		||||
an in-progress WRITE/ERASE transaction in the same flash block are not possible. Flash READs for 
 | 
			
		||||
instructions are read from BLOCK0; flash WRITE/ERASE operations are made to BLOCK1. Hence there is no
 | 
			
		||||
possibility of RWW collisions.
 | 
			
		||||
 | 
			
		||||
  	
 | 
			
		||||
### Scenario 2: Firmware & CFSTORE Data Stored In The Same Flash Block 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 -------------------------------- 0x00080000 = 512kB    flash_addr_end      ^
 | 
			
		||||
 |                              |                                           |
 | 
			
		||||
 | CFSTORE Flash Journal Slot 3 |                                           |
 | 
			
		||||
 |                              |                                           |
 | 
			
		||||
 |- - - - - - - - - - - - - - - |                                           |
 | 
			
		||||
 |                              |                                           B
 | 
			
		||||
 | CFSTORE Flash Journal Slot 2 |                                           L
 | 
			
		||||
 |                              |                                           O
 | 
			
		||||
 |- - - - - - - - - - - - - - - |                                           C
 | 
			
		||||
 |                              |                                           K
 | 
			
		||||
 | CFSTORE Flash Journal Slot 1 |                                           0
 | 
			
		||||
 |                              |                                           |
 | 
			
		||||
 |- - - - - - - - - - - - - - - |                                           |
 | 
			
		||||
 |                              |                                           |
 | 
			
		||||
 | CFSTORE Flash Journal Slot 0 |                                           |
 | 
			
		||||
 |                              |                                           |
 | 
			
		||||
 -------------------------------- CONFIG_HARDWARE_MTD_START_ADDR            |
 | 
			
		||||
 |                              |                                           |
 | 
			
		||||
 |       Unused Flash           |                                           |
 | 
			
		||||
 |                              |                                           |
 | 
			
		||||
 |------------------------------| firmware_addr_end == __uvisor_flash_end   |
 | 
			
		||||
 |//////////////////////////////|                                           |
 | 
			
		||||
 |//////////////////////////////|                                           |
 | 
			
		||||
 |//////////////////////////////|                                           |
 | 
			
		||||
 |//////////////////////////////|                                           |
 | 
			
		||||
 |//////////////////////////////|                                           |
 | 
			
		||||
 |////////          ////////////|                                           |
 | 
			
		||||
 |//////// Firmware ////////////|                                           |
 | 
			
		||||
 |////////          ////////////|                                           |
 | 
			
		||||
 |//////////////////////////////|                                           |
 | 
			
		||||
 |//////////////////////////////|                                           |
 | 
			
		||||
 |//////////////////////////////|                                           |
 | 
			
		||||
 |//////////////////////////////|                                           |
 | 
			
		||||
 |//////////////////////////////|  											|
 | 
			
		||||
 --------------------------------  0x00000000           flash_addr_start    v
 | 
			
		||||
                                                    == firmware_addr_start
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
 Figure 2: Scenario 2 K64F Flash Address Map Showing Default Firmware and CFSTORE Allocations. 
 | 
			
		||||
 
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
In this scenario BLOCK0 is used for both program code/data and CFSTORE key-value data, and therefore
 | 
			
		||||
the application must only use CFSTORE/Flash Journal synchronous mode to store data. This is explained in the following:
 | 
			
		||||
- BLOCK0 is used to store the firmware image. Program execution therefore reads code instructions
 | 
			
		||||
  from flash BLOCK0.
 | 
			
		||||
- BLOCK0 is used to write/erase CFSTORE configuration data (the same block used for reading coding instructions).
 | 
			
		||||
- Hence there is the possibility of a concurrent READ access while a WRITE/ERASE transaction is in progress, 
 | 
			
		||||
  which must not happen. This is prevented by the CFSTORE/Flash Journal implementation.
 | 
			
		||||
- Sync mode is used and Flash Journal busy waits for the pending flash transaction to complete. 
 | 
			
		||||
- All interrupts are disabled to prevent the execution of interrupt handlers concurrently with the in-progress flash
 | 
			
		||||
  transaction. If permitted, executing the interrupt handler will cause instructions to be read from BLOCK0 leaving the 
 | 
			
		||||
  possibility of a RWW error.
 | 
			
		||||
- Flash Journal functions executing while the flash transaction is outstanding must be resident in memory 
 | 
			
		||||
  (otherwise their execution would cause a RWW error when the instructions are read from BLOCK0).
 | 
			
		||||
  This is done with the RAMFUNC function decoration (see implementation).
 | 
			
		||||
	  
 | 
			
		||||
In this scenario, it is not possible to use CFSTORE asynchronous mode because execution requires 
 | 
			
		||||
the reading of instructions from BLOCK0 at the same time as the in-progress flash transaction, 
 | 
			
		||||
which is not allowed as it causes RWW errors.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#### Scenario 2 Advantages and Disadvantages
 | 
			
		||||
 | 
			
		||||
This scenario has the following advantages/disadvantages:
 | 
			
		||||
- Advantage: the combined storage of the firmware image and CFSTORE KV data into a single
 | 
			
		||||
  block reduces the bill of material costs. 
 | 
			
		||||
- Disadvantage: CFSTORE/Flash-journal can only be operated in synchronous modes.
 | 
			
		||||
- Disadvantage: Interrupt latency times increase because interrupts have to be disabled
 | 
			
		||||
  during flash WRITE/ERASE transactions to prevent interrupt handlers reading code 
 | 
			
		||||
  instructions from the same block.
 | 
			
		||||
 | 
			
		||||
## Configuring the CFSTORE Flash Area Start Address and Size 
 | 
			
		||||
 | 
			
		||||
The default configuration is controlled by the following symbols:
 | 
			
		||||
- CONFIG_HARDWARE_MTD_START_ADDR. This is the start address of 
 | 
			
		||||
  the CFSTORE area in the flash storage. It defaults to the start of 
 | 
			
		||||
  BLOCK1 i.e. 0x80000. See Figure 1 for the location of the
 | 
			
		||||
  CONFIG_HARDWARE_MTD_START_ADDR in the flash address map. 
 | 
			
		||||
- CONFIG_HARDWARE_MTD_SIZE. This is the size of CFSTORE flash 
 | 
			
		||||
  memory area, and defaults to the size of BLOCK1 (i.e. 0x00080000 = 512kB).
 | 
			
		||||
 | 
			
		||||
The following file contains CONFIG_HARDWARE_MTD_START_ADDR and 
 | 
			
		||||
CONFIG_HARDWARE_MTD_SIZE processing:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
mbed-os_root\core\hal\targets\hal\TARGET_Freescale\TARGET_KSDK2_MCUS\TARGET_K64F\storage_driver.c
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
as shown here:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
        /**< This is the start address of the flash block. */
 | 
			
		||||
#ifdef CONFIG_HARDWARE_MTD_START_ADDR
 | 
			
		||||
        .addr       = CONFIG_HARDWARE_MTD_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 CONFIG_HARDWARE_MTD_SIZE
 | 
			
		||||
        .size       = CONFIG_HARDWARE_MTD_SIZE,
 | 
			
		||||
#else
 | 
			
		||||
        .size       = BLOCK1_SIZE,
 | 
			
		||||
#endif
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Use `CONFIG_HARDWARE_MTD_START_ADDR` to set the start address of the 
 | 
			
		||||
storage area and `CONFIG_HARDWARE_MTD_SIZE` to specify its size.
 | 
			
		||||
 | 
			
		||||
The storage area used by flash-journal is divided into a number of slots, 
 | 
			
		||||
where log/commit operations are rotated through the slots rather than 
 | 
			
		||||
writing/re-writing a single slot. This gives wear-levelling and reliability benefits.
 | 
			
		||||
Currently its configured here:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
mbed-os_root\features\storage\flash-journal\flash-journal-strategy-sequential\config.h
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
which defines the number of slots (`SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS`) to be 4:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
#define SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS 4
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## CFSTORE/Flash-Journal Impact on System Resources and Operation
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Code Size
 | 
			
		||||
 | 
			
		||||
It is possible to compute the CFSTORE/Flash-Journal code size by simply building the tree and 
 | 
			
		||||
adding the following binary sizes together e.g. for CFSTORE version 0.3.3 the total is 35896 bytes:
 | 
			
		||||
 | 
			
		||||
The following are the CFSTORE code sizes:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
(mx2_venv3) cfstore_mbedos_blinky9/.build/tests/K64F/GCC_ARM/mbed-os/features/storage/cfstore/source$ ls -la *.o
 | 
			
		||||
-rw-r--r--    1 simhug01 Administ     2544 Jul  7 11:26 cfstore_fnmatch.o
 | 
			
		||||
-rw-r--r--    1 simhug01 Administ    18760 Jul  7 11:26 configuration_store.o
 | 
			
		||||
<line removed as cfstore_test.o bound to test case binaries and therefore not relevant>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The following are the flash journal code sizes:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
(mx2_venv3) cfstore_mbedos_blinky9/.build/tests/K64F/GCC_ARM/mbed-os/features/storage/flash-journal/flash-journal-strategy-sequential$ ls -la *.o
 | 
			
		||||
-rw-r--r--    1 simhug01 Administ     3408 Jul  7 11:26 strategy.o
 | 
			
		||||
-rw-r--r--    1 simhug01 Administ     4324 Jul  7 11:26 support_funcs.o
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The following is the platform flash device driver:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
mx2_venv3) cfstore_mbedos_blinky9/.build/tests/K64F/GCC_ARM/mbed-os/core/hal/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARG
 | 
			
		||||
T_K64F $ ls -la *.o
 | 
			
		||||
rw-r--r--    1 simhug01 Administ     6860 Jul  7 11:25 storage_driver.o
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### SRAM Footprint
 | 
			
		||||
 | 
			
		||||
The CFSTORE implementation uses SRAM in the following way:
 | 
			
		||||
- The size in memory of each key-value pair is the sum of the following component sizes:
 | 
			
		||||
    - KEY_NAME_LEN: the keyname length in bytes (not including a terminating null).
 | 
			
		||||
    - VALUE_LEN: the length of the value specified to the Create() call.
 | 
			
		||||
    - HEADER_SIZE: each attribute has a header the length of sizeof(cfstore_area_header_t) = 8 bytes
 | 
			
		||||
       used to store housekeeping information. Hence, each KV has an 8 byte overhead which is typically 
 | 
			
		||||
       small compared with the size of the information stored.   
 | 
			
		||||
- As an example, to store 100 key-value attributes with keynames 30 chars long and values each 1kB in size, the
 | 
			
		||||
  total_SRAM_used = 100 * (30 + 1024 + 8) = 106200 == ~104kB.  
 | 
			
		||||
- CFSTORE maintains an SRAM area containing all the stored attributes. 
 | 
			
		||||
    - Flush() causes the memory area to be stored in a Flash-Journal slot in non-volatile storage (flash).
 | 
			
		||||
    - Initialize() reads the data from the last used Flash-Journal slot into SRAM for use by the 
 | 
			
		||||
      system.
 | 
			
		||||
    - Hence, the current CFSTORE implementation has the limitation that the maximum 
 | 
			
		||||
      size of data stored in flash is limited by the maximum amount of SRAM that can be used to store
 | 
			
		||||
      the KVs prior to being flushed to flash. In the previous
 | 
			
		||||
      example 104kB of SRAM must be available to store 104kB of data in flash. This limitation will be
 | 
			
		||||
      removed in a future implementation.
 | 
			
		||||
 | 
			
		||||
### Non-Volatile Storage (Flash) Footprint
 | 
			
		||||
 | 
			
		||||
CFSTORE uses Flash Journal slots as the non-volatile backing store for key-value attributes.
 | 
			
		||||
- By default, Flash Journal is configured to have n_slots=4 slots.
 | 
			
		||||
- A sequence of {0, 1, 2, 3, 4, 5, ..., i} CFSTORE API Flush() operations write to the slots in sequential
 | 
			
		||||
  order to provide wear-levelling across the flash, i.e. :
 | 
			
		||||
    - Flush() call number 0 stores data in slot 0.
 | 
			
		||||
    - Flush() call number 1 stores data in slot 1.
 | 
			
		||||
    - Flush() call number 2 stores data in slot 2.
 | 
			
		||||
    - Flush() call number 3 stores data in slot 3.
 | 
			
		||||
    - Flush() call number 4 stores data in slot 0.
 | 
			
		||||
    - Flush() call number 5 stores data in slot 1.
 | 
			
		||||
    - Flush() call number i stores data in slot (i % n_slots).
 | 
			
		||||
- The size of the flash storage area CONFIG_HARDWARE_MTD_SIZE must therefore be (at a minimum) 
 | 
			
		||||
  CFSTORE_flash_size = n_slots * total_SRAM_used, rounded up to the nearest ERASE_SIZE size (4kB on K64F). 
 | 
			
		||||
  To continue the previous example where total_SRAM_used = 104kB, CFSTORE_flash_size = 4 * 104 = 416kB.
 | 
			
		||||
 | 
			
		||||
### CFSTORE Key-Value Data Read/Write Times From Flash
 | 
			
		||||
 | 
			
		||||
The CFSTORE API Initialize() call reads the key-value data from non-volatile storage. 
 | 
			
		||||
Measurements have not been made on how long CFSTORE takes to read data.
 | 
			
		||||
 | 
			
		||||
The CFSTORE API Uninitialize() call writes the key-value data to non-volatile storage if any of
 | 
			
		||||
the attributes have changed since the Initialize() call. The write operation:
 | 
			
		||||
- erases the flash slot being used. Erase operations have been measured at ~1.4us/byte for 
 | 
			
		||||
  erase sizes of 4-32kB in increments of 4kB (averaged over ~20 measurements).  
 | 
			
		||||
- programs the flash slot being used. Program operations have been measured at ~9.2 us/byte
 | 
			
		||||
  for program sizes of 8b-8kB (averaged over ~20 measurements).
 | 
			
		||||
Thus an Uninitialize() operation for 104kB data will take ~1.1s 
 | 
			
		||||
( = (9.2+1.4)* 1e^-6 *104 8 1024 seconds) to complete.
 | 
			
		||||
 | 
			
		||||
### Access Times
 | 
			
		||||
 | 
			
		||||
As all CFSTORE key-value attributes are held in SRAM, key-value attribute access times are restricted
 | 
			
		||||
only by the speed of SRAM memory access times.   
 | 
			
		||||
 | 
			
		||||
### Interrupt Latency
 | 
			
		||||
 | 
			
		||||
See NXP Freescale Kinetis K64F Sub-Family Data Sheet K64P144M120SF5.pdf. section 
 | 
			
		||||
3.4.1.2 Flash timing specifications, commands Table 24. Flash command timing specifications 
 | 
			
		||||
for flash transaction times.
 | 
			
		||||
 | 
			
		||||
The above document reference indicates the duration of a flash ERASE operation to take ~115ms for a 4kB ERASE operation. This can 
 | 
			
		||||
therefore delay an interrupt by 115ms. This is much slower that the previously reported measurements and 
 | 
			
		||||
therefore suggests a worst case scenario factoring in device aging. Further investigation is recommended.
 | 
			
		||||
 | 
			
		||||
### Typical Embedded System Flash Configuration
 | 
			
		||||
 
 | 
			
		||||
Embedded systems commonly have the following configurations:
 | 
			
		||||
- flash partition0: bootloader (single system copy, and boot environment data e.g. active bank).
 | 
			
		||||
- flash partition1: firmware image copy 0 (optionally including bootloader image).
 | 
			
		||||
- flash partition2: filesystem/data for image copy 0 (e.g. certificates, keys, kernel boot parameters).
 | 
			
		||||
- flash partition3: firmware image copy 0 (optionally including bootloader image).
 | 
			
		||||
- flash partition4: filesystem/data for image copy 0 (e.g. certificates, keys, kernel boot parameters).
 | 
			
		||||
 | 
			
		||||
Typical platform (system) configurations may be dimensioned (depending on cost, reliability, etc) as follows:
 | 
			
		||||
- partitions 0, 1, 2, 3, 4, 5 stored on single flash part are typically ~{128MB, 256MB, 512MB} in size. This 
 | 
			
		||||
  configuration corresponds to Scenario 2.
 | 
			
		||||
- partitions 0, 1, 2 stored on 1st flash part (BANK0),  partitions 3, 4 stored on 2nd flash (BANK1), where parts 
 | 
			
		||||
  are typically ~{128MB, 256MB, 512MB} in size. This configuration corresponds to Scenario 1. 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Recommendations for System Designers When Adopting CFSTORE/Flash-Journal
 | 
			
		||||
 | 
			
		||||
The following conclusions can be drawn from the considerations in the previous sections:
 | 
			
		||||
- A system designer optimising for performance would use at least 2 flash BLOCKs, 
 | 
			
		||||
  sized to allow the firmware code to be located in one block and CFSTORE data in another.
 | 
			
		||||
  This equates to Scenario 1 described in previous sections.   
 | 
			
		||||
- A system designer optimising for cost would select a single flash BLOCK part and accept
 | 
			
		||||
  the lower performance of CFSTORE/Flash-Journal operating in synchronous mode. This equates to
 | 
			
		||||
  scenario 2.
 | 
			
		||||
- SRAM is needed to hold all stored CFSTORE data in memory for processing.
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
## References 
 | 
			
		||||
 | 
			
		||||
* [NXP Freescale Application Note AN4695.pdf: Avoiding Read While Write Errors][NXP_FREESCALE_AN4695]
 | 
			
		||||
* NXP Freescale Kinetis K64F Sub-Family Data Sheet K64P144M120SF5.pdf.
 | 
			
		||||
 | 
			
		||||
[NXP_FREESCALE_AN4695]: http://cache.freescale.com/files/32bit/doc/app_note/AN4695.pdf
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,461 @@
 | 
			
		|||
# Configuration Store Getting Started Guide
 | 
			
		||||
Author: Simon Hughes
 | 
			
		||||
 | 
			
		||||
# Overview
 | 
			
		||||
 | 
			
		||||
## Executive Summary
 | 
			
		||||
 | 
			
		||||
This document describes how to get started with the configuration store module. 
 | 
			
		||||
 | 
			
		||||
## Terminology
 | 
			
		||||
 | 
			
		||||
The terminology used throughout this document is defined on the [CFSTORE Terminology](configuration_store_terminology.md) page.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Pre-requisites
 | 
			
		||||
 | 
			
		||||
It is assumed that you have the following:
 | 
			
		||||
- The mbed-cli tool installed on your computer.
 | 
			
		||||
- GCC_ARM compiler installed on your computer
 | 
			
		||||
- The mbed greentea test suite tool installed on you computer.
 | 
			
		||||
- A Freescale FRDM K64F connected to your computer for running the test cases on this target.
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
# Overview of Steps Covered to Build Tests 
 | 
			
		||||
 | 
			
		||||
The following steps will be covered:
 | 
			
		||||
1. Creating a new mbed-os project in for building the test cases
 | 
			
		||||
2. Building the test cases
 | 
			
		||||
3. Running the test cases on a Freescale FRDM K64F.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Step 1: Creating a New mbed-os Project
 | 
			
		||||
 | 
			
		||||
First create an empty working directory e.g. called cfstore. Move into the directoy and perfom the `mbed new .` command:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
---
 | 
			
		||||
C:\Jenkins\jobs\cfstore_mbedos_blinky\workspace>mbed new . 
 | 
			
		||||
[mbed WARNING] Directory "." is not empty.
 | 
			
		||||
---
 | 
			
		||||
[mbed] Creating new program "." (git)
 | 
			
		||||
[mbed] Adding library "mbed-os" from "https://github.com/ARMmbed/mbed-os/" at latest revision in the current branch
 | 
			
		||||
[mbed] Adding library "mbed-os\core" from "https://github.com/mbedmicro/mbed/" at rev #ce830296d0297a8da543c24134bf859710fd7698
 | 
			
		||||
[mbed] Adding library "mbed-os\features\FEATURE_CLIENT\coap-service" from "https://github.com/ARMmbed/coap-service/" at rev #7a11be1ccb07b2ea953a37d6a5445baa9fd380b8
 | 
			
		||||
[mbed] Adding library "mbed-os\features\FEATURE_CLIENT\mbed-client-c" from "https://github.com/ARMmbed/mbed-client-c/" at rev #2aae9fd392af75704d6a40219647a71495ffe291
 | 
			
		||||
[mbed] Adding library "mbed-os\features\FEATURE_CLIENT\mbed-client-classic" from "https://github.com/ARMmbed/mbed-client-classic/" at rev #30260f355273100e9a2de47e26502d7b6ebe2f33
 | 
			
		||||
[mbed] Adding library "mbed-os\features\FEATURE_CLIENT\mbed-client-mbed-tls" from "https://github.com/ARMmbed/mbed-client-mbed-tls/" at rev #f644e7b9c350c92c43caace7f28330416b69ae45
 | 
			
		||||
[mbed] Adding library "mbed-os\features\FEATURE_CLIENT\mbed-client-randlib" from "https://github.com/ARMmbed/mbed-client-randlib/" at rev #80f5c491dd4d7c8e30b94eb575cdb402e9a17e83
 | 
			
		||||
[mbed] Adding library "mbed-os\features\FEATURE_CLIENT\mbed-client" from "https://github.com/ARMmbed/mbed-client/" at rev #7e09a3bc6a81eeb7032e61412bcfee09b8361132
 | 
			
		||||
[mbed] Adding library "mbed-os\features\FEATURE_IPV6\mbed-mesh-api" from "https://github.com/ARMmbed/mbed-mesh-api/" at rev #0e92921f3dcebd73925479156a02a5f40206bd5e
 | 
			
		||||
[mbed] Adding library "mbed-os\features\FEATURE_IPV6\mbed-trace" from "https://github.com/ARMmbed/mbed-trace/" at rev #e419c488f4f8079fbd14f90e61b6018308e33d73
 | 
			
		||||
[mbed] Adding library "mbed-os\features\FEATURE_IPV6\nanostack-hal-mbed-cmsis-rtos" from "https://github.com/ARMmbed/nanostack-hal-mbed-cmsis-rtos/" at rev #36968fc133c74cb43d95588ae324623fe0d20f78
 | 
			
		||||
[mbed] Adding library "mbed-os\features\FEATURE_IPV6\nanostack-libservice" from "https://github.com/ARMmbed/nanostack-libservice/" at rev #f61c845e0c59f9e0c033ae3de2ea4f190b7edef1
 | 
			
		||||
[mbed] Adding library "mbed-os\features\FEATURE_IPV6\sal-stack-nanostack-eventloop" from "https://github.com/ARMmbed/sal-stack-nanostack-eventloop/" at rev #c163be9183b09d7513532c50f2bc9ac52d3e580c
 | 
			
		||||
[mbed] Adding library "mbed-os\features\FEATURE_IPV6\sal-stack-nanostack-private" from "https://github.com/ARMmbed/sal-stack-nanostack-private/" at rev #5d3365ce7df303b31d88bdddf08d296088edd24d
 | 
			
		||||
[mbed] Adding library "mbed-os\frameworks\greentea-client" from "https://github.com/ARMmbed/greentea-client/" at rev #d0cbb41ae7939e1a0b159c110244ceea5ddaca49
 | 
			
		||||
[mbed] Adding library "mbed-os\frameworks\unity" from "https://github.com/ARMmbed/unity/" at rev #14fd303f30f9578b0ef6767c88e2fbc262db5fa1
 | 
			
		||||
[mbed] Updating reference "mbed-os" -> "https://github.com/ARMmbed/mbed-os/#f4790ce69f273f5138ff23bf628bbe0e3a62b9d2"
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
As shown in the above trace, the mbed new command creates a clone of the mbed-os repository, and the linked repostories. 
 | 
			
		||||
It takes some time to execute as the command downloads ~300MB of source files from github.
 | 
			
		||||
 | 
			
		||||
Once complete, you can see the list of linked repositories by using the mbed ls command:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
(mx2_venv3) simhug01@E107851:/d/datastore/public/jobs/yr2016/2253/sdh_dev_mx2/cfstore_mbedos_blinky9$ mbed ls
 | 
			
		||||
cfstore_mbedos_blinky9 (69e5d843463c)
 | 
			
		||||
`- mbed-os (aafb02d090d1)
 | 
			
		||||
   |- core (7810829df18e)
 | 
			
		||||
   |- features\FEATURE_CLIENT\coap-service (7a11be1ccb07)
 | 
			
		||||
   |- features\FEATURE_CLIENT\mbed-client (7e09a3bc6a81)
 | 
			
		||||
   |- features\FEATURE_CLIENT\mbed-client-c (2aae9fd392af)
 | 
			
		||||
   |- features\FEATURE_CLIENT\mbed-client-classic (30260f355273)
 | 
			
		||||
   |- features\FEATURE_CLIENT\mbed-client-mbed-tls (f644e7b9c350)
 | 
			
		||||
   |- features\FEATURE_CLIENT\mbed-client-randlib (80f5c491dd4d)
 | 
			
		||||
   |- features\FEATURE_IPV6\mbed-mesh-api (0e92921f3dce)
 | 
			
		||||
   |- features\FEATURE_IPV6\mbed-trace (e419c488f4f8)
 | 
			
		||||
   |- features\FEATURE_IPV6\nanostack-hal-mbed-cmsis-rtos (36968fc133c7)
 | 
			
		||||
   |- features\FEATURE_IPV6\nanostack-libservice (f61c845e0c59)
 | 
			
		||||
   |- features\FEATURE_IPV6\sal-stack-nanostack-eventloop (c163be9183b0)
 | 
			
		||||
   |- features\FEATURE_IPV6\sal-stack-nanostack-private (5d3365ce7df3)
 | 
			
		||||
   |- frameworks\greentea-client (d0cbb41ae793)
 | 
			
		||||
   `- frameworks\unity (14fd303f30f9)
 | 
			
		||||
(mx2_venv3) simhug01@E107851:/d/datastore/public/jobs/yr2016/2253/sdh_dev_mx2/cfstore_mbedos_blinky9$
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Step 2: Build the Test Cases
 | 
			
		||||
 | 
			
		||||
Next, build the mbed-os test with the following command line:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
C:\Jenkins\jobs\cfstore_mbedos_blinky\workspace>mbed compile --tests -m K64F -t GCC_ARM 
 | 
			
		||||
Building library mbed-build (K64F, GCC_ARM)
 | 
			
		||||
Copy: AnalogIn.h
 | 
			
		||||
Copy: AnalogOut.h
 | 
			
		||||
Copy: BusIn.h
 | 
			
		||||
Copy: BusInOut.h
 | 
			
		||||
Copy: BusOut.h
 | 
			
		||||
Copy: Callback.h
 | 
			
		||||
Copy: CallChain.h
 | 
			
		||||
Copy: CAN.h
 | 
			
		||||
Copy: can_helper.h
 | 
			
		||||
Copy: CircularBuffer.h
 | 
			
		||||
Copy: critical.h
 | 
			
		||||
Copy: CThunk.h
 | 
			
		||||
Copy: DigitalIn.h
 | 
			
		||||
Copy: DigitalInOut.h
 | 
			
		||||
Copy: DigitalOut.h
 | 
			
		||||
Copy: DirHandle.h
 | 
			
		||||
Copy: Ethernet.h
 | 
			
		||||
Copy: FileBase.h
 | 
			
		||||
... 
 | 
			
		||||
<lines deleted to save space>
 | 
			
		||||
...
 | 
			
		||||
Building project GCC_ARM to mbed-os-features-storage-tests-cfstore-flush2 (K64F, GCC_ARM)
 | 
			
		||||
Compile: flush2.cpp
 | 
			
		||||
Link: mbed-os-features-storage-tests-cfstore-flush2
 | 
			
		||||
Elf2Bin: mbed-os-features-storage-tests-cfstore-flush2
 | 
			
		||||
+----------------------------+-------+-------+------+
 | 
			
		||||
| Module                     | .text | .data | .bss |
 | 
			
		||||
+----------------------------+-------+-------+------+
 | 
			
		||||
| Fill                       |    95 |     7 | 2090 |
 | 
			
		||||
| Misc                       | 43411 |  2224 | 2152 |
 | 
			
		||||
| core/hal                   | 19188 |    16 |  795 |
 | 
			
		||||
| core/rtos                  |  6815 |    24 | 2662 |
 | 
			
		||||
| features/FEATURE_IPV4      |    96 |     0 |   48 |
 | 
			
		||||
| features/storage           | 15578 |   340 |  576 |
 | 
			
		||||
| frameworks/greentea-client |  1580 |    56 |   52 |
 | 
			
		||||
| frameworks/unity           |   584 |     0 |  160 |
 | 
			
		||||
| frameworks/utest           |  5444 |     5 |  805 |
 | 
			
		||||
| Subtotals                  | 92791 |  2672 | 9340 |
 | 
			
		||||
+----------------------------+-------+-------+------+
 | 
			
		||||
Allocated Heap: 65540 bytes
 | 
			
		||||
Allocated Stack: 32768 bytes
 | 
			
		||||
Total Static RAM memory (data + bss): 12012 bytes
 | 
			
		||||
Total RAM memory (data + bss + heap + stack): 110320 bytes
 | 
			
		||||
Total Flash memory (text + data + misc): 96503 bytes
 | 
			
		||||
Image: .build/tests/K64F/GCC_ARM/mbed-os/features/storage/TESTS/cfstore/flush2/mbed-os-features-storage-tests-cfstore-flush2.bin
 | 
			
		||||
Building project GCC_ARM to mbed-os-features-storage-tests-cfstore-flush3 (K64F, GCC_ARM)
 | 
			
		||||
Compile: flush3.cpp
 | 
			
		||||
Link: mbed-os-features-storage-tests-cfstore-flush3
 | 
			
		||||
Elf2Bin: mbed-os-features-storage-tests-cfstore-flush3
 | 
			
		||||
+----------------------------+-------+-------+------+
 | 
			
		||||
| Module                     | .text | .data | .bss |
 | 
			
		||||
+----------------------------+-------+-------+------+
 | 
			
		||||
| Fill                       |    99 |     7 | 2238 |
 | 
			
		||||
| Misc                       | 43095 |  2224 | 2152 |
 | 
			
		||||
| core/hal                   | 19188 |    16 |  795 |
 | 
			
		||||
| core/rtos                  |  6815 |    24 | 2662 |
 | 
			
		||||
| features/FEATURE_IPV4      |    96 |     0 |   48 |
 | 
			
		||||
| features/storage           | 13598 |   340 |  428 |
 | 
			
		||||
| frameworks/greentea-client |  1580 |    56 |   52 |
 | 
			
		||||
| frameworks/unity           |   584 |     0 |  160 |
 | 
			
		||||
| frameworks/utest           |  5312 |     5 |  805 |
 | 
			
		||||
| Subtotals                  | 90367 |  2672 | 9340 |
 | 
			
		||||
+----------------------------+-------+-------+------+
 | 
			
		||||
Allocated Heap: 65540 bytes
 | 
			
		||||
Allocated Stack: 32768 bytes
 | 
			
		||||
Total Static RAM memory (data + bss): 12012 bytes
 | 
			
		||||
Total RAM memory (data + bss + heap + stack): 110320 bytes
 | 
			
		||||
Total Flash memory (text + data + misc): 94079 bytes
 | 
			
		||||
Image: .build/tests/K64F/GCC_ARM/mbed-os/features/storage/TESTS/cfstore/flush3/mbed-os-features-storage-tests-cfstore-flush3.bin
 | 
			
		||||
 | 
			
		||||
<lines deleted to save space>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Building project GCC_ARM to mbed-os-tests-mbedmicro-rtos-mbed-semaphore (K64F, GCC_ARM)
 | 
			
		||||
Compile: main.cpp
 | 
			
		||||
[Warning] main.cpp@72: 'rtos::Thread::Thread(void (*)(const void*), void*, osPriority, uint32_t, unsigned char*)' is deprecated (declared at C:/Jenkins/jobs/cfstore_mbedos_blinky/workspace/.build/tests/K64F/GCC_ARM/mbed-os/core/rtos/rtos/Thread.h:138): Thread-spawning constructors hide errors and may lead to complex program state when a thread is declared [-Wdeprecated-declarations]
 | 
			
		||||
[Warning] main.cpp@73: 'rtos::Thread::Thread(void (*)(const void*), void*, osPriority, uint32_t, unsigned char*)' is deprecated (declared at C:/Jenkins/jobs/cfstore_mbedos_blinky/workspace/.build/tests/K64F/GCC_ARM/mbed-os/core/rtos/rtos/Thread.h:138): Thread-spawning constructors hide errors and may lead to complex program state when a thread is declared [-Wdeprecated-declarations]
 | 
			
		||||
[Warning] main.cpp@74: 'rtos::Thread::Thread(void (*)(const void*), void*, osPriority, uint32_t, unsigned char*)' is deprecated (declared at C:/Jenkins/jobs/cfstore_mbedos_blinky/workspace/.build/tests/K64F/GCC_ARM/mbed-os/core/rtos/rtos/Thread.h:138): Thread-spawning constructors hide errors and may lead to complex program state when a thread is declared [-Wdeprecated-declarations]
 | 
			
		||||
Link: mbed-os-tests-mbedmicro-rtos-mbed-semaphore
 | 
			
		||||
Elf2Bin: mbed-os-tests-mbedmicro-rtos-mbed-semaphore
 | 
			
		||||
+----------------------------+-------+-------+------+
 | 
			
		||||
| Module                     | .text | .data | .bss |
 | 
			
		||||
+----------------------------+-------+-------+------+
 | 
			
		||||
| Fill                       |    96 |     4 | 2232 |
 | 
			
		||||
| Misc                       | 42479 |  2224 | 2152 |
 | 
			
		||||
| TESTS/mbedmicro-rtos-mbed  |   459 |     0 |   25 |
 | 
			
		||||
| core/hal                   | 16055 |    16 |  565 |
 | 
			
		||||
| core/rtos                  |  7662 |    24 | 2662 |
 | 
			
		||||
| features/FEATURE_IPV4      |    96 |     0 |   48 |
 | 
			
		||||
| frameworks/greentea-client |  1580 |    52 |   52 |
 | 
			
		||||
| frameworks/utest           |  2988 |     0 |  732 |
 | 
			
		||||
| Subtotals                  | 71415 |  2320 | 8468 |
 | 
			
		||||
+----------------------------+-------+-------+------+
 | 
			
		||||
Allocated Heap: 65540 bytes
 | 
			
		||||
Allocated Stack: 32768 bytes
 | 
			
		||||
Total Static RAM memory (data + bss): 10788 bytes
 | 
			
		||||
Total RAM memory (data + bss + heap + stack): 109096 bytes
 | 
			
		||||
Total Flash memory (text + data + misc): 74775 bytes
 | 
			
		||||
Image: .build/tests/K64F/GCC_ARM/mbed-os/TESTS/mbedmicro-rtos-mbed/semaphore/mbed-os-tests-mbedmicro-rtos-mbed-semaphore.bin
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Build successes:
 | 
			
		||||
  * K64F::GCC_ARM::MBED-BUILD
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-FEATURE_IPV4-TESTS-MBEDMICRO-NET-NIST_INTERNET_TIME_SERVICE
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-FEATURE_IPV4-TESTS-MBEDMICRO-NET-TCP_CLIENT_ECHO
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-FEATURE_IPV4-TESTS-MBEDMICRO-NET-TCP_CLIENT_HELLO_WORLD
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-FEATURE_IPV4-TESTS-MBEDMICRO-NET-UDP_ECHO_CLIENT
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-CFSTORE-ADD_DEL
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-CFSTORE-CLOSE
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-CFSTORE-CREATE
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-CFSTORE-DUMP
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-CFSTORE-EXAMPLE1
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-CFSTORE-EXAMPLE2
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-CFSTORE-EXAMPLE3
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-CFSTORE-EXAMPLE4
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-CFSTORE-EXAMPLE5
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-CFSTORE-FIND
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-CFSTORE-FIND2
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-CFSTORE-FLASH
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-CFSTORE-FLASH_SET
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-CFSTORE-FLUSH
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-CFSTORE-FLUSH2
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-CFSTORE-FLUSH3
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-CFSTORE-INIT
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-CFSTORE-MISC
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-CFSTORE-OPEN
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-CFSTORE-READ
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-CFSTORE-WRITE
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FEATURES-STORAGE-TESTS-FLASH_JOURNAL-BASICAPI
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FRAMEWORKS-UTEST-TESTS-UNIT_TESTS-BASIC_TEST
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FRAMEWORKS-UTEST-TESTS-UNIT_TESTS-BASIC_TEST_DEFAULT
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FRAMEWORKS-UTEST-TESTS-UNIT_TESTS-CASE_ASYNC_VALIDATE
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FRAMEWORKS-UTEST-TESTS-UNIT_TESTS-CASE_CONTROL_ASYNC
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FRAMEWORKS-UTEST-TESTS-UNIT_TESTS-CASE_CONTROL_REPEAT
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FRAMEWORKS-UTEST-TESTS-UNIT_TESTS-CASE_SELECTION
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FRAMEWORKS-UTEST-TESTS-UNIT_TESTS-CASE_SETUP_FAILURE
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FRAMEWORKS-UTEST-TESTS-UNIT_TESTS-CASE_TEARDOWN_FAILURE
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FRAMEWORKS-UTEST-TESTS-UNIT_TESTS-CONTROL_TYPE
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FRAMEWORKS-UTEST-TESTS-UNIT_TESTS-MINIMAL_ASYNC_SCHEDULER
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FRAMEWORKS-UTEST-TESTS-UNIT_TESTS-MINIMAL_SCHEDULER
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FRAMEWORKS-UTEST-TESTS-UNIT_TESTS-TEST_ASSERTION_FAILURE_TEST_SETUP
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FRAMEWORKS-UTEST-TESTS-UNIT_TESTS-TEST_SETUP_CASE_SELECTION_FAILURE
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-FRAMEWORKS-UTEST-TESTS-UNIT_TESTS-TEST_SETUP_FAILURE
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-INTEGRATION-BASIC
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-INTEGRATION-THREADED_BLINKY
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBEDMICRO-MBED-ATTRIBUTES
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBEDMICRO-MBED-CALL_BEFORE_MAIN
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBEDMICRO-MBED-CPP
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBEDMICRO-MBED-DIV
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBEDMICRO-RTOS-MBED-BASIC
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBEDMICRO-RTOS-MBED-ISR
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBEDMICRO-RTOS-MBED-MAIL
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBEDMICRO-RTOS-MBED-MUTEX
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBEDMICRO-RTOS-MBED-QUEUE
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBEDMICRO-RTOS-MBED-SEMAPHORE
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBEDMICRO-RTOS-MBED-SIGNALS
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBEDMICRO-RTOS-MBED-THREADS
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBEDMICRO-RTOS-MBED-TIMER
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBED_DRIVERS-CALLBACK
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBED_DRIVERS-C_STRINGS
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBED_DRIVERS-DEV_NULL
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBED_DRIVERS-ECHO
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBED_DRIVERS-GENERIC_TESTS
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBED_DRIVERS-RTC
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBED_DRIVERS-STL_FEATURES
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBED_DRIVERS-TICKER
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBED_DRIVERS-TICKER_2
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBED_DRIVERS-TICKER_3
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBED_DRIVERS-TIMEOUT
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-MBED_DRIVERS-WAIT_US
 | 
			
		||||
  * K64F::GCC_ARM::MBED-OS-TESTS-STORAGE_ABSTRACTION-BASICAPI
 | 
			
		||||
 | 
			
		||||
<lines deleted to save space>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Step 3: Run the Test Cases
 | 
			
		||||
 | 
			
		||||
Next run the mbed-os Tests usings the following command line
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
C:\Jenkins\jobs\cfstore_mbedos_blinky\workspace>mbedgt -VS --test-spec=.build/tests/K64F/GCC_ARM/test_spec.json 
 | 
			
		||||
mbedgt: test specification file '.build/tests/K64F/GCC_ARM/test_spec.json' (specified with --test-spec option)
 | 
			
		||||
mbedgt: using '.build/tests/K64F/GCC_ARM/test_spec.json' from current directory!
 | 
			
		||||
mbedgt: detecting connected mbed-enabled devices...
 | 
			
		||||
mbedgt: detected 1 device
 | 
			
		||||
	detected 'K64F' -> 'K64F[0]', console at 'COM64', mounted at 'E:', target id '0240000029304e450014500878a3003cf131000097969900'
 | 
			
		||||
mbedgt: processing target 'K64F' toolchain 'GCC_ARM' compatible platforms...
 | 
			
		||||
mbedgt: using platform 'K64F' for test:
 | 
			
		||||
	target_id_mbed_htm = '0240000029304e450014500878a3003cf131000097969900'
 | 
			
		||||
	daplink_interface_crc = '0xdc4d98a8'
 | 
			
		||||
	mount_point = 'E:'
 | 
			
		||||
	daplink_automation_allowed = '0'
 | 
			
		||||
	daplink_daplink_mode = 'Interface'
 | 
			
		||||
	daplink_local_mods = '0'
 | 
			
		||||
	daplink_unique_id = '0240000029304e450014500878a3003cf131000097969900'
 | 
			
		||||
	daplink_hif_id = '97969900'
 | 
			
		||||
	target_id = '0240000029304e450014500878a3003cf131000097969900'
 | 
			
		||||
	serial_port = 'COM64:9600'
 | 
			
		||||
	target_id_usb_id = '0240000029304e450014500878a3003cf131000097969900'
 | 
			
		||||
	platform_name = 'K64F'
 | 
			
		||||
	platform_name_unique = 'K64F[0]'
 | 
			
		||||
	daplink_git_sha = '3c733e851ea6d453b6834232466f7d2b17fff1b6'
 | 
			
		||||
	daplink_interface_version = '0240'
 | 
			
		||||
	daplink_auto_reset = '0'
 | 
			
		||||
	daplink_usb_interfaces = 'MSD, CDC, HID'
 | 
			
		||||
	daplink_version = '0240'
 | 
			
		||||
mbedgt: running 68 tests for platform 'K64F' and toolchain 'GCC_ARM'
 | 
			
		||||
	use 1 instance for testing
 | 
			
		||||
mbedgt: selecting test case observer...
 | 
			
		||||
	calling mbedhtrun: mbedhtrun -d E: -p COM64:9600 -f ".build/tests/K64F/GCC_ARM/mbed-os/features/storage/TESTS/cfstore/flush/mbed-os-features-storage-tests-cfstore-flush.bin" -C 4 -c shell -m K64F -t 0240000029304e450014500878a3003cf131000097969900
 | 
			
		||||
mbedgt: mbed-host-test-runner: started
 | 
			
		||||
[1467848528.72][HTST][INF] host test executor ver. 0.2.13
 | 
			
		||||
[1467848528.72][HTST][INF] copy image onto target...
 | 
			
		||||
        1 file(s) copied.
 | 
			
		||||
Plugin info: HostTestPluginCopyMethod_Shell::CopyMethod: Waiting up to 60 sec for '0240000029304e450014500878a3003cf131000097969900' mount point (current is 'E:')...
 | 
			
		||||
[1467848539.87][HTST][INF] starting host test process...
 | 
			
		||||
[1467848540.48][CONN][INF] starting serial connection process...
 | 
			
		||||
[1467848540.48][CONN][INF] notify event queue about extra 60 sec timeout for serial port pooling
 | 
			
		||||
[1467848540.48][CONN][INF] initializing serial port listener...
 | 
			
		||||
[1467848540.48][SERI][INF] serial(port=COM64, baudrate=9600, timeout=0)
 | 
			
		||||
[1467848540.48][HTST][INF] setting timeout to: 60 sec
 | 
			
		||||
Plugin info: HostTestPluginBase::BasePlugin: Waiting up to 60 sec for '0240000029304e450014500878a3003cf131000097969900' serial port (current is 'COM64')...
 | 
			
		||||
[1467848540.64][SERI][INF] reset device using 'default' plugin...
 | 
			
		||||
[1467848540.90][SERI][INF] wait for it...
 | 
			
		||||
[1467848541.91][CONN][INF] sending preamble 'eb507531-ae47-4c98-852b-c16efa1b2e4f'...
 | 
			
		||||
[1467848541.91][SERI][TXD] mbedmbedmbedmbedmbedmbedmbedmbedmbedmbed
 | 
			
		||||
[1467848541.91][SERI][TXD] {{__sync;eb507531-ae47-4c98-852b-c16efa1b2e4f}}
 | 
			
		||||
[1467848542.93][CONN][RXD] {{__sync;eb507531-ae47-4c98-852b-c16efa1b2e4f}}
 | 
			
		||||
[1467848542.93][CONN][RXD] {{__version;1.3.0}}
 | 
			
		||||
[1467848542.93][CONN][RXD] {{__timeout;60}}
 | 
			
		||||
[1467848542.93][CONN][RXD] {{__host_test_name;default_auto}}
 | 
			
		||||
[1467848542.93][CONN][RXD] {{__testcase_count;2}}
 | 
			
		||||
[1467848542.93][CONN][RXD] >>> Running 2 test cases...
 | 
			
		||||
[1467848542.93][CONN][RXD] {{__testcase_name;FLUSH_test_00}}
 | 
			
		||||
[1467848542.93][CONN][RXD] {{__testcase_name;FLUSH_test_01}}
 | 
			
		||||
[1467848542.93][CONN][RXD] >>> Running case #1: 'FLUSH_test_00'...
 | 
			
		||||
[1467848542.93][CONN][RXD] {{__testcase_start;FLUSH_test_00}}
 | 
			
		||||
[1467848542.93][CONN][RXD] INITIALIZING: caps.asynchronous_ops=1
 | 
			
		||||
[1467848542.93][CONN][RXD] CFSTORE Flash Entries
 | 
			
		||||
[1467848542.93][CONN][RXD] =====================
 | 
			
		||||
[1467848542.93][CONN][RXD] .
 | 
			
		||||
[1467848542.93][CONN][RXD]   caps.asynchronous_ops : 1
 | 
			
		||||
[1467848542.93][CONN][RXD] .
 | 
			
		||||
[1467848542.93][CONN][RXD] == End ==============
 | 
			
		||||
[1467848542.93][CONN][RXD] {{__testcase_finish;FLUSH_test_00;1;0}}
 | 
			
		||||
[1467848542.93][CONN][RXD] >>> 'FLUSH_test_00': 1 passed, 0 failed
 | 
			
		||||
[1467848542.93][CONN][RXD] >>> Running case #2: 'FLUSH_test_01'...
 | 
			
		||||
[1467848542.93][CONN][RXD] {{__testcase_start;FLUSH_test_01}}
 | 
			
		||||
[1467848542.93][CONN][INF] found SYNC in stream: {{__sync;eb507531-ae47-4c98-852b-c16efa1b2e4f}}, queued...
 | 
			
		||||
[1467848542.93][HTST][INF] sync KV found, uuid=eb507531-ae47-4c98-852b-c16efa1b2e4f, timestamp=1467848542.929000
 | 
			
		||||
[1467848542.93][CONN][INF] found KV pair in stream: {{__version;1.3.0}}, queued...
 | 
			
		||||
[1467848542.93][HTST][INF] DUT greentea-client version: 1.3.0
 | 
			
		||||
[1467848542.93][CONN][INF] found KV pair in stream: {{__timeout;60}}, queued...
 | 
			
		||||
[1467848542.93][HTST][INF] setting timeout to: 60 sec
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
At the end of the test run, you should see the following from the results summary table:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
mbedgt: test suite report:
 | 
			
		||||
+--------------+---------------+------------------------------------------------------------------------------+---------+--------------------+-------------+
 | 
			
		||||
| target       | platform_name | test suite                                                                   | result  | elapsed_time (sec) | copy_method |
 | 
			
		||||
+--------------+---------------+------------------------------------------------------------------------------+---------+--------------------+-------------+
 | 
			
		||||
<lines deleted to save space>
 | 
			
		||||
| K64F-GCC_ARM | K64F          | mbed-os-features-storage-tests-cfstore-add_del                               | OK      | 16.87              | shell       |
 | 
			
		||||
| K64F-GCC_ARM | K64F          | mbed-os-features-storage-tests-cfstore-close                                 | OK      | 15.91              | shell       |
 | 
			
		||||
| K64F-GCC_ARM | K64F          | mbed-os-features-storage-tests-cfstore-create                                | OK      | 20.09              | shell       |
 | 
			
		||||
| K64F-GCC_ARM | K64F          | mbed-os-features-storage-tests-cfstore-dump                                  | OK      | 14.72              | shell       |
 | 
			
		||||
| K64F-GCC_ARM | K64F          | mbed-os-features-storage-tests-cfstore-example1                              | OK      | 15.94              | shell       |
 | 
			
		||||
| K64F-GCC_ARM | K64F          | mbed-os-features-storage-tests-cfstore-example2                              | OK      | 14.8               | shell       |
 | 
			
		||||
| K64F-GCC_ARM | K64F          | mbed-os-features-storage-tests-cfstore-example3                              | OK      | 15.76              | shell       |
 | 
			
		||||
| K64F-GCC_ARM | K64F          | mbed-os-features-storage-tests-cfstore-example4                              | OK      | 14.64              | shell       |
 | 
			
		||||
| K64F-GCC_ARM | K64F          | mbed-os-features-storage-tests-cfstore-example5                              | OK      | 14.59              | shell       |
 | 
			
		||||
| K64F-GCC_ARM | K64F          | mbed-os-features-storage-tests-cfstore-find                                  | OK      | 17.11              | shell       |
 | 
			
		||||
| K64F-GCC_ARM | K64F          | mbed-os-features-storage-tests-cfstore-find2                                 | OK      | 15.67              | shell       |
 | 
			
		||||
| K64F-GCC_ARM | K64F          | mbed-os-features-storage-tests-cfstore-flash                                 | OK      | 15.91              | shell       |
 | 
			
		||||
| K64F-GCC_ARM | K64F          | mbed-os-features-storage-tests-cfstore-flash_set                             | OK      | 14.67              | shell       |
 | 
			
		||||
| K64F-GCC_ARM | K64F          | mbed-os-features-storage-tests-cfstore-flush                                 | OK      | 18.14              | shell       |
 | 
			
		||||
| K64F-GCC_ARM | K64F          | mbed-os-features-storage-tests-cfstore-flush2                                | OK      | 16.85              | shell       |
 | 
			
		||||
| K64F-GCC_ARM | K64F          | mbed-os-features-storage-tests-cfstore-flush3                                | OK      | 14.57              | shell       |
 | 
			
		||||
| K64F-GCC_ARM | K64F          | mbed-os-features-storage-tests-cfstore-init                                  | OK      | 15.75              | shell       |
 | 
			
		||||
| K64F-GCC_ARM | K64F          | mbed-os-features-storage-tests-cfstore-misc                                  | OK      | 16.92              | shell       |
 | 
			
		||||
| K64F-GCC_ARM | K64F          | mbed-os-features-storage-tests-cfstore-open                                  | OK      | 19.13              | shell       |
 | 
			
		||||
| K64F-GCC_ARM | K64F          | mbed-os-features-storage-tests-cfstore-read                                  | OK      | 15.73              | shell       |
 | 
			
		||||
| K64F-GCC_ARM | K64F          | mbed-os-features-storage-tests-cfstore-write                                 | OK      | 15.75              | shell       |
 | 
			
		||||
<lines deleted to save space>
 | 
			
		||||
+--------------+---------------+------------------------------------------------------------------------------+---------+--------------------+-------------+
 | 
			
		||||
mbedgt: test suite results: 64 OK / 4 TIMEOUT
 | 
			
		||||
mbedgt: test case report:
 | 
			
		||||
...
 | 
			
		||||
<lines deleted to save space>
 | 
			
		||||
...
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
# CFSTORE Build Configurations
 | 
			
		||||
 | 
			
		||||
CFSTORE can be configured using compilation options to build in the following configurations:
 | 
			
		||||
- CFSTORE SRAM-backed in-memory version. 
 | 
			
		||||
- CFSTORE Non-Volatile-Storage-backed (Flash-Journal) for persisting key-value attributes.
 | 
			
		||||
 | 
			
		||||
## CFSTORE SRAM-backed in-memory Version
 | 
			
		||||
 | 
			
		||||
The CFSTORE SRAM version can be described as follows:
 | 
			
		||||
- CFSTORE API implementation backed by SRAM (non-persistent).
 | 
			
		||||
- Synchronous mode implementation.
 | 
			
		||||
- Supported on the K64F target.
 | 
			
		||||
 | 
			
		||||
Use the following command line to build an application with SRAM support:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
	mbed compile -v -m K64F -t GCC_ARM -DCFSTORE_STORAGE_DISABLE=0
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Use the following command line to build the CFSTORE tests with SRAM support:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
	mbed compile -v --tests -m K64F -t GCC_ARM -DCFSTORE_STORAGE_DISABLE=0
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## CFSTORE Non-Volatile-Storage-backed (Flash-Journal) Version
 | 
			
		||||
 | 
			
		||||
The CFSTORE Flash-Journal Version can be described as follows:
 | 
			
		||||
- CFSTORE API implementation backed by SRAM and Non-Volatile (NV) storage for persisting key-value attributes.
 | 
			
		||||
- Flash-jounral asynchronous mode support.
 | 
			
		||||
- Flash-jounral synchronous mode support.
 | 
			
		||||
- Flash-jounral supported on the K64F target.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Use the following command line to build an application with Flash-Journal asynchronous mode support:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
	mbed compile -v -m K64F -t GCC_ARM
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Use the following command line to build an application with Flash-Journal synchronous mode support:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
	mbed compile -v --tests -m K64F -t GCC_ARM -DSTORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS=0
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Use the following command line to build the CFSTORE tests with Flash-Journal asynchronous mode support:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
	mbed compile -v --tests -m K64F -t GCC_ARM
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Use the following command line to build the CFSTORE tests with Flash-Journal synchronous mode support:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
	mbed compile -v --tests -m K64F -t GCC_ARM -DSTORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS=0
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# CFSTORE Code Examples
 | 
			
		||||
 | 
			
		||||
There are a number of code examples to help illustrate how to use the CFSTORE API.
 | 
			
		||||
* The CFSTORE Client Example 3 for flash-journal synchronous mode only (simpler code). 
 | 
			
		||||
  See the explantory comments in example3.cpp for more details. 
 | 
			
		||||
* The CFSTORE Client Example 1 for both flash-journal modes (asynchronous and synchronous)
 | 
			
		||||
  (more complicated but versatile code). See the explantory comments in example1.cpp for more details.
 | 
			
		||||
* The CFSTORE Client Example 5 for flash-journal synchronous mode only (simpler code) alternative example. 
 | 
			
		||||
  See the explantory comments in example5.cpp for more details. 
 | 
			
		||||
 | 
			
		||||
Instructions are included in the exampleX.cpp files for building as stand-alone applications. 
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
# Configuration Store Low Level Design
 | 
			
		||||
Author: Simon Hughes
 | 
			
		||||
 | 
			
		||||
# Revision History
 | 
			
		||||
20160127: first version.
 | 
			
		||||
 | 
			
		||||
# API
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## CFSTORE Client API interface
 | 
			
		||||
 | 
			
		||||
The CFSTORE client API interface is represented diagramatically in the following UML digarm  
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
The above UML diagram shows the low level design of the CFSTORE API.
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,32 @@
 | 
			
		|||
# Configuration Store Project Documentation
 | 
			
		||||
 | 
			
		||||
# Guidance for Submitting Issues
 | 
			
		||||
 | 
			
		||||
Here are the guidelines for submitting issues to the configuration-store repository:
 | 
			
		||||
 | 
			
		||||
- If you have an issue with configuration-store then please file an issue at github.com/armmbed/configuration-store.git
 | 
			
		||||
- The issue should be filed with a stand-alone testcase or sample application that only depends on configuration-store and shows the fault on the target platform. 
 | 
			
		||||
- The issue should include the following information under separate SUMMARY and DETAILS headings:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
    
 | 
			
		||||
    SUMMARY
 | 
			
		||||
    =======
 | 
			
		||||
    APPLCIATION/Library NAME:   <e.g. configuration_store, example3, myappname> 
 | 
			
		||||
    OS VERSION:                 <e.g. MBEDOSv3>
 | 
			
		||||
    TARGET:                     <e.g. k64f>
 | 
			
		||||
    TOOLCHAIN:                  <e.g. GCC_ARM, ARM>
 | 
			
		||||
    DESCRIPTION:                <e.g. a 1-line summary description of the problem >
 | 
			
		||||
    MODULE DEPENDENCIES:        <e.g. the version of the modules used to build the application, output from yotta ls, etc>
 | 
			
		||||
    
 | 
			
		||||
    DETAILS
 | 
			
		||||
    =======
 | 
			
		||||
    <step by step guide about how to build and test the provided resources so as to reproduce the problem. 
 | 
			
		||||
    
 | 
			
		||||
    CODE
 | 
			
		||||
    ====
 | 
			
		||||
    <details of supplied code sample showing problem>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,434 @@
 | 
			
		|||
# Configuration Store Engineering Requirements
 | 
			
		||||
 | 
			
		||||
## Definition of Terms
 | 
			
		||||
 | 
			
		||||
The [CFSTORE Terminology][CFSTORE_TERM] defines terms used in this document. 
 | 
			
		||||
 | 
			
		||||
## Design Goals
 | 
			
		||||
 | 
			
		||||
A number of design goals should be met for the configuration store to be used widely. The configuration store should:
 | 
			
		||||
 | 
			
		||||
* Offer hierarchical storage of data:
 | 
			
		||||
    * Configuration data should be groupable.
 | 
			
		||||
    * Groups of configuration data should be handled as a unit.
 | 
			
		||||
* Support multiple degrees of persistence:
 | 
			
		||||
    * Permanent.
 | 
			
		||||
    * Non-Volatile.
 | 
			
		||||
    * Volatile.
 | 
			
		||||
* Allow configuration to be superceded different persistence levels (e.g. volatile being the highest priority and permanent the lowest).
 | 
			
		||||
* Support multiple sources of configuration:
 | 
			
		||||
    * Build configuration tools.
 | 
			
		||||
    * Application configuration.
 | 
			
		||||
    * Runtime configuration including remote configuration from a network management entity.
 | 
			
		||||
* Support multiple kinds of values:
 | 
			
		||||
    * Integer.
 | 
			
		||||
    * Floating point.
 | 
			
		||||
    * String
 | 
			
		||||
    * Arbitrary binary blob.
 | 
			
		||||
* Globally accessible by any module with the system.
 | 
			
		||||
* Able to enforce permissions on entire branches of the configuration data.
 | 
			
		||||
* Accessible early in the system initialisation process.
 | 
			
		||||
* Low memory footprint.
 | 
			
		||||
* Low CPU overhead for data accesses.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Secure Key Value Storage\Rationale (REQ-1.xx-SKVS-R) Requirements
 | 
			
		||||
 | 
			
		||||
#### REQ-1.01-SKVS-R:
 | 
			
		||||
The CFSTORE must provide a non-volatile, hardware-independent secure storage
 | 
			
		||||
service that can be used by CFSTORE API clients for storing data owned
 | 
			
		||||
by a client security context (uvisor box).
 | 
			
		||||
 | 
			
		||||
#### REQ-1.02-SKVS-R:
 | 
			
		||||
Clients of the CFSTORE API must be security contexts (boxes) so that security
 | 
			
		||||
policies can be enforced.
 | 
			
		||||
 | 
			
		||||
#### REQ-1.03-SKVS-R:
 | 
			
		||||
The CFSTORE design values simplicity over complexity to promote security by
 | 
			
		||||
minimizing the attack surface to secure data.
 | 
			
		||||
 | 
			
		||||
#### REQ-1.04-SKVS-R:
 | 
			
		||||
The CFSTORE must be implemented as a uvisor secure box.
 | 
			
		||||
 | 
			
		||||
#### REQ-1.05-SKVS-R:
 | 
			
		||||
The CFSTORE must support the use of Access Control Lists for policing access to
 | 
			
		||||
secure data.
 | 
			
		||||
 | 
			
		||||
#### REQ-1.06-SKVS-R:
 | 
			
		||||
The CFSTORE must support the storage of a {key, value} tuples where
 | 
			
		||||
- the key is a zero terminated string of arbitrary length.
 | 
			
		||||
- the value is a binary blob of data of arbitrary length
 | 
			
		||||
 | 
			
		||||
The {key, value} tuple is a CFSTORE object.
 | 
			
		||||
 | 
			
		||||
##### Discussion
 | 
			
		||||
A null key (i.e. "" which includes a terminating null) is not a valid because the null string is not a valid security_prefix_name. 
 | 
			
		||||
 | 
			
		||||
#### REQ-1.07-SKVS-R: CFSTORE Stores Binary Blobs
 | 
			
		||||
The CFSTORE must provide support so that other (client) components can implement
 | 
			
		||||
more complex storage types other than a binary blob e.g. by
 | 
			
		||||
wrapping the underlying CFSTORE {key, value} tuple with additional
 | 
			
		||||
type information.
 | 
			
		||||
 | 
			
		||||
#### REQ-1.08-SKVS-R: CFSTORE Key Structure as Name Strings
 | 
			
		||||
This requirement has been removed as it is a subset of REQ-1.06-SKVS-R [REQ-1.06-SKVS-R]. 
 | 
			
		||||
 | 
			
		||||
#### REQ-1.09-SKVS-R: Key Creation and Ownership Part 1
 | 
			
		||||
CFSTORE keys must be owned by the security context. A security context (box)
 | 
			
		||||
is identified by a unique security_name_prefix and this identifier
 | 
			
		||||
must be used when the key is created. CFSTORE must support the use of the
 | 
			
		||||
security_name_prefix as the leading substring of the CFSTORE key string, in which
 | 
			
		||||
case the key_name_prefix is the security_name_prefix and identifies the
 | 
			
		||||
owner of the key.
 | 
			
		||||
 | 
			
		||||
#### REQ-1.10-SKVS-R: Security Context
 | 
			
		||||
In order to create objects in the CFSTORE, a security context (box) must have
 | 
			
		||||
a security_name_prefix.
 | 
			
		||||
 | 
			
		||||
#### REQ-1.11-SKVS-R: CFSTORE object
 | 
			
		||||
This requirement has been removed as it is a duplicate of REQ-1.10-SKVS-R 
 | 
			
		||||
 | 
			
		||||
## Secure Key Value Storage High Level Design (REQ-1.2.xx-SKVS-HLD) Requirements
 | 
			
		||||
 | 
			
		||||
#### REQ-1.2.01-SKVS-HLD:
 | 
			
		||||
The CFSTORE must be able to detect the available types of storage media
 | 
			
		||||
in the system and report associated storage media attributes.
 | 
			
		||||
 | 
			
		||||
#### REQ-1.2.02-SKVS-HLD:
 | 
			
		||||
The CFSTORE may report the following storage media data retention level attribute,
 | 
			
		||||
when available:
 | 
			
		||||
- only during device activity
 | 
			
		||||
- during sleep
 | 
			
		||||
- during deep-sleep
 | 
			
		||||
- battery-backed, device can be powered off
 | 
			
		||||
- internal non-volatile memory
 | 
			
		||||
- external non-volatile memory
 | 
			
		||||
 | 
			
		||||
#### REQ-1.2.03-SKVS-HLD:
 | 
			
		||||
For a particular storage medium, the CFSTORE may report the following device
 | 
			
		||||
data security protection features, when available:
 | 
			
		||||
- no security, just safety
 | 
			
		||||
- write-once-read-only-memory (WORM)
 | 
			
		||||
- against internal software attacks using ACLs
 | 
			
		||||
- roll-back protection
 | 
			
		||||
- immovable (for internal memory mapping, to stop relocated block to move).
 | 
			
		||||
  This attribute must only be set provided:
 | 
			
		||||
  - the device memory is mapped into the CPU address space
 | 
			
		||||
  - access is only granted to specific CFSTORE API system clients e.g. FOTA,
 | 
			
		||||
     DMA.
 | 
			
		||||
- hardening against device software (malware running on the device)
 | 
			
		||||
- hardening against board level attacks (debug probes, copy protection
 | 
			
		||||
  fuses)
 | 
			
		||||
- hardening against chip level attacks (tamper-protection)
 | 
			
		||||
- hardening against side channel attacks
 | 
			
		||||
- tamper-proof memory (will be deleted on tamper-attempts using board level
 | 
			
		||||
  or chip level sensors)
 | 
			
		||||
 | 
			
		||||
#### REQ-1.2.04-SKVS-HLD:
 | 
			
		||||
The CFSTORE may be used to implement KV storage protection services
 | 
			
		||||
(e.g. flash image roll-back protection, confidentiality) for off-chip
 | 
			
		||||
(external) storage media (e.g. SPI/I2C/NAND Flash).
 | 
			
		||||
 | 
			
		||||
#### REQ-1.2.05-SKVS-HLD:
 | 
			
		||||
The device data security protection immovable attribute may only be set
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Secure Key Value Storage\High Level API Description\Key Value Storage (REQ-3.1.xx-SKVS-HLAPID-KVS) Requirements.
 | 
			
		||||
 | 
			
		||||
#### REQ-3.1.01-SKVS-HLAPID-KVS: CFSTORE Global Key Namespace
 | 
			
		||||
The CFSTORE must implement a system global hierarchical tree name-space for
 | 
			
		||||
keys. The namespace is shared by all software components operating within
 | 
			
		||||
the system. Examples of key names include the following:
 | 
			
		||||
 - 'com.arm.mbed.wifi.accesspoint[5].essid'
 | 
			
		||||
 - 'com.arm.mbed.wifi.accesspoint[home].essid'
 | 
			
		||||
 - 'yotta.your-yotta-registry-module-name.your-value'
 | 
			
		||||
 - 'yotta.hello-world.animal{dog}{foot}[3]'
 | 
			
		||||
 The key name string forms a path where 'Path Directory Entries' are
 | 
			
		||||
 separated by the '.' character.
 | 
			
		||||
 | 
			
		||||
#### REQ-3.1.02-SKVS-HLAPID-KVS: CFSTORE Key Name String Format Max Length
 | 
			
		||||
For CFSTORE keys The maximum length of a CFSTORE key is 220 characters excluding
 | 
			
		||||
the terminating null.
 | 
			
		||||
 | 
			
		||||
#### REQ-3.1.03-SKVS-HLAPID-KVS: CFSTORE Key Name String Allowed Characters
 | 
			
		||||
CFSTORE key name strings must only contain the following characters:
 | 
			
		||||
- [a-zA-Z0-9.]
 | 
			
		||||
- '-'
 | 
			
		||||
 | 
			
		||||
#### REQ-3.1.04-SKVS-HLAPID-KVS: Key Name Path Directory Entry List {}
 | 
			
		||||
Path Directory Entries may have list indicators designated by {}. For
 | 
			
		||||
example,
 | 
			
		||||
 - 'com.arm.mbed.wifi.accesspoint{5}.essid'
 | 
			
		||||
 - 'com.arm.mbed.wifi.accesspoint{home}.essid'
 | 
			
		||||
 - 'yotta.hello-world.animal{dog}{foot}{3}'
 | 
			
		||||
In the above the list item specifiers are respectively:
 | 
			
		||||
 - '5'
 | 
			
		||||
 - 'home'
 | 
			
		||||
 - 'dog', 'foot, '3'
 | 
			
		||||
As list item specifiers are part of the key name string, the list item
 | 
			
		||||
substring must be composed of allowable characters.
 | 
			
		||||
 | 
			
		||||
#### REQ-3.1.05-SKVS-HLAPID-KVS: CFSTORE Global Key Yotta Namespace
 | 
			
		||||
The key name prefix 'yotta' is reserved for use by the yotta module. Other
 | 
			
		||||
prefixes may be reserved.
 | 
			
		||||
 | 
			
		||||
#### REQ-3.1.06-SKVS-HLAPID-KVS: CFSTORE Key Names Mapable to Common OS Filesystem Name
 | 
			
		||||
The CFSTORE key names must be mappable to common OS Filesystem file names. This requirment 
 | 
			
		||||
permits a CFSTORE backend to map individual KVs to files with the filename being the 
 | 
			
		||||
key name, for example. Supported OS Filesytems must include DOS, NTFS, EXT3, EXT4 and
 | 
			
		||||
JFFS. 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Secure Key Value Storage\High Level API Description\Access Control Security (REQ-3.2.xx-SKVS-HLAPID-ACS) Requirements.
 | 
			
		||||
 | 
			
		||||
#### REQ-3.2.01-SKVS-HLAPID-KACS:
 | 
			
		||||
The CFSTORE must enforce security policies as defined by Access Control Lists.
 | 
			
		||||
 | 
			
		||||
#### REQ-3.2.02-SKVS-HLAPID-KACS: CFSTORE Key Creation Part 2
 | 
			
		||||
The CFSTORE objects must be created with an ACL. The ACL is attached to the object
 | 
			
		||||
so that access permissions to the KV data can be enforced.
 | 
			
		||||
 | 
			
		||||
#### REQ-3.2.03-SKVS-HLAPID-KACS:
 | 
			
		||||
The CFSTORE Access Control Lists must support the groups for 'owner' and 'other',
 | 
			
		||||
with optional permissions read, write and executable. The owner group
 | 
			
		||||
permissions describe the access permissions of the owner of the object. The
 | 
			
		||||
other group permissions describe the access permissions for entities other
 | 
			
		||||
than the owner. The writable and executable permissions are mutually
 | 
			
		||||
exclusive.
 | 
			
		||||
 | 
			
		||||
#### REQ-3.2.04-SKVS-HLAPID-KACS:
 | 
			
		||||
A CFSTORE API client must be able to query the CFSTORE for a list of KV pairs provided
 | 
			
		||||
the KV pair ACL permissions allow the client access. The query result must
 | 
			
		||||
contain all client owner KVs. The query results may include non-client
 | 
			
		||||
owned KVs provided the other group permissions grant access.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Secure Key Value Storage\API Logic\Finding Keys (REQ-5.1.xx-SKVS-APIL-FK) Requirements.
 | 
			
		||||
 | 
			
		||||
#### REQ-5.1.01-SKVS-APIL-FK: Key Searching/Finding Scoped by ACL
 | 
			
		||||
The CFSTORE must provide an interface to query for active keys in the global
 | 
			
		||||
storage. The query must:
 | 
			
		||||
- return results based on the ACL provided by the client
 | 
			
		||||
- support wild card searches using the '*' character. The '*' character
 | 
			
		||||
  can occur at most once any point in the search string. For example:
 | 
			
		||||
  - com.arm.mbed.wifi.accesspoint*.essid
 | 
			
		||||
  - yotta.your-yotta-registry-module-name.*
 | 
			
		||||
  - yotta.hello-world.animal{dog}{foot}{*}
 | 
			
		||||
  - yotta.hello-world.animal{dog}{foot}*
 | 
			
		||||
  - yotta.hello-world.animal{dog*3}
 | 
			
		||||
 | 
			
		||||
#### REQ-5.1.02-SKVS-APIL-FK: CFSTORE Global Key Namespace Reserves Character '*'
 | 
			
		||||
The character '*' is reserved in the CFSTORE global key namespace. The current
 | 
			
		||||
functions of this character as follows:
 | 
			
		||||
- a wild card character in searches.
 | 
			
		||||
- a wild card character used in the delete operation.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#### REQ-5.1.03-SKVS-APIL-FK: Key Searching/Finding Resume
 | 
			
		||||
In order to support the return of a large list of key query results (perhaps
 | 
			
		||||
exceeding the ability of the caller to consume in a single operation), the
 | 
			
		||||
query interface must support the ability to restart/resume the query to
 | 
			
		||||
retrieve a subsequent set of records to those already received.
 | 
			
		||||
 | 
			
		||||
#### REQ-5.1.04-SKVS-APIL-FK: Key Searching/Finding Internals (key versions)
 | 
			
		||||
The CFSTORE must be robust against incomplete, corrupted or aborted write 
 | 
			
		||||
operations to NV store caused for example, by loss of power during the 
 | 
			
		||||
write. 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Secure Key Value Storage\API Logic\Get Storage Information (REQ-5.2.xx-SKVS-APIL-GSI) Requirements.
 | 
			
		||||
 | 
			
		||||
#### REQ-5.2.01-SKVS-APIL-GSI: storage_detect
 | 
			
		||||
The CFSTORE must provide an API so that clients can discover the CFSTORE storage
 | 
			
		||||
capabilities. Storage capabilities may include:
 | 
			
		||||
- write-block sizes for O_BLOCK_WRITE mode (sequence of writes into the
 | 
			
		||||
  same value)
 | 
			
		||||
- supported Data Retention Levels
 | 
			
		||||
- supported Device Data Security Protection Features
 | 
			
		||||
 | 
			
		||||
#### REQ-5.2.02-SKVS-APIL-GSI: Minimal Storage Support
 | 
			
		||||
The CFSTORE must provide minimal storage media services including the following:
 | 
			
		||||
- SRAM/SDRAM memory with no security guarantees.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Secure Key Value Storage\API Logic\Creating & Opening Keys for Writing (REQ-5.3.xx-SKVS-APIL-COKFW) Requirements.
 | 
			
		||||
 | 
			
		||||
#### REQ-5.3.01-SKVS-APIL-COKFW: storage_key_create with O_CREATE
 | 
			
		||||
CFSTORE keys must be explicitly created using 'storage_key_create' with the following
 | 
			
		||||
parameters:
 | 
			
		||||
- security ACLs (owner & others)
 | 
			
		||||
- the intended retention levels (bit mask to allow caching if needed)
 | 
			
		||||
- indicating the expected Device Data Security Protection Features
 | 
			
		||||
- the key pointer (zero-terminated)
 | 
			
		||||
- the value size
 | 
			
		||||
- alignment bits of the value hardware address (only for O_CONTINUOUS).
 | 
			
		||||
  The structure start is aligned accordingly to ensure that the value
 | 
			
		||||
  blob is aligned on a multiple of the 2^alignment_bits
 | 
			
		||||
- mode flags (O_CREATE, O_CONTINUOUS, O_LAZY_FLUSH, O_BLOCK_WRITE,
 | 
			
		||||
  O_ALLOCATE_AT_OFFEST).
 | 
			
		||||
  - O_CREATE. The call will create the KV pair. If a
 | 
			
		||||
     pre-existing KV with the same name is present in CFSTORE then the
 | 
			
		||||
     storage_key_create will fail with FILE_EXISTS.
 | 
			
		||||
  - O_CONTINUOUS. The KV value will be stored in a continuous range
 | 
			
		||||
     of hardware addresses.
 | 
			
		||||
  - O_LAZY_FLUSH 
 | 
			
		||||
  - O_BLOCK_WRITE
 | 
			
		||||
  - O_ALLOCATE_AT_OFFEST 
 | 
			
		||||
 | 
			
		||||
##### Discussion
 | 
			
		||||
The following should not be included in the API (e.g. because the principle of encapsulation is broken, or specific to a particular clients requirements):
 | 
			
		||||
- optionally the offset address (restricted feature, ideally only granted
 | 
			
		||||
  to the FOTA security context)
 | 
			
		||||
 | 
			
		||||
#### REQ-5.3.02-SKVS-APIL-COKFW: storage_key_create without O_CREATE
 | 
			
		||||
Pre-existing CFSTORE objects can be updated by calling the storage_key_create
 | 
			
		||||
API with the O_CREATE not set.
 | 
			
		||||
In case a pre-existing key is updated (O_CREATE not set) and the previous
 | 
			
		||||
ACL allows writing to the caller:
 | 
			
		||||
- all key-value fragments of the previous key are set as inactive
 | 
			
		||||
- the new key is allocated (in fragments if permitted)
 | 
			
		||||
- all permissions and settings are copied from the previous key
 | 
			
		||||
- the version number is incremented compared to the previous key (see 
 | 
			
		||||
  REQ-5.3.05-SKVS-APIL-COKFW). 
 | 
			
		||||
 | 
			
		||||
#### REQ-5.3.03-SKVS-APIL-COKFW: O_CONTINUOUS for executable objects
 | 
			
		||||
CFSTORE will manage an executable KV as though the mode O_CONTINUOUS flag
 | 
			
		||||
is set.
 | 
			
		||||
 | 
			
		||||
#### REQ-5.3.04-SKVS-APIL-COKFW: O_CONTINUOUS for non-executable objects
 | 
			
		||||
A CFSTORE client may specify the mode O_CONTINUOUS flag for non-executable
 | 
			
		||||
objects.
 | 
			
		||||
 | 
			
		||||
#### REQ-5.3.05-SKVS-APIL-COKFW: Versioning of KVs
 | 
			
		||||
KVs in NV storage should have version numbers. When writing an updated 
 | 
			
		||||
KV (with changed value data for example), a new copy of the KV data with
 | 
			
		||||
updated version number should be written to NV store. The earlier version is 
 | 
			
		||||
left as a fallback copy of data that may be deleted at some point in time,
 | 
			
		||||
when the NV storage is required, or more than a certain number of 
 | 
			
		||||
versions is exceeded. 
 | 
			
		||||
 | 
			
		||||
## Secure Key Value Storage\Updating and Settings and Permissions (REQ-6.1.xx-SKVS-USP) Requirements.
 | 
			
		||||
 | 
			
		||||
#### REQ-6.1.01-SKVS-USP:
 | 
			
		||||
CFSTORE does not permit the updating of KV pair permissions or settings. This is to promote security.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Secure Key Value Storage\Updating and Settings and Permissions\Deleting Keys (REQ-6.2.xx-SKVS-USP-DK) Requirements.
 | 
			
		||||
 | 
			
		||||
#### REQ-6.2.01-SKVS-USP-DK:
 | 
			
		||||
Only the owner of the CFSTORE KV pair can delete the object. The wildcard
 | 
			
		||||
'*' character can be specified to delete an owned subtree of the CFSTORE
 | 
			
		||||
global key namespace.
 | 
			
		||||
 | 
			
		||||
#### REQ-6.2.02-SKVS-USP-DK:
 | 
			
		||||
This requirement has been removed.
 | 
			
		||||
 | 
			
		||||
## Secure Key Value Storage\Updating and Settings and Permissions\Opening Keys for Reading (REQ-6.2.xx-SKVS-USP-OKFR) Requirements.
 | 
			
		||||
 | 
			
		||||
#### REQ-6.3.xx-SKVS-USP-OKFR storage_key_open_read
 | 
			
		||||
CFSTORE objects must be explicitly opened with storage_key_open_read(key_name)
 | 
			
		||||
before operations on the KV pair can be performed. The KV must
 | 
			
		||||
pre-exist in the store before it can be opened.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Secure Key Value Storage\Updating and Settings and Permissions\Seeking in Key Values (REQ-6.3.xx-SKVS-USP-SIKV) Requirements.
 | 
			
		||||
 | 
			
		||||
#### REQ-6.4.01-SKVS-USP-SIKV storage_value_rseek
 | 
			
		||||
The function storage_value_rseek can be used on a opaque reference to a KV
 | 
			
		||||
to change the read position inside a value i.e. the storage_value_read
 | 
			
		||||
method supports random-access.  
 | 
			
		||||
 | 
			
		||||
#### REQ-6.4.02-SKVS-USP-SIKV storage_value_write has no write location
 | 
			
		||||
storage_value_write does not support the concept of a write location that can be modified i.e. random access write support is not supported. 
 | 
			
		||||
 | 
			
		||||
#### REQ-6.4.03-SKVS-USP-SIKV storage_value_write sequential-access
 | 
			
		||||
storage_value_write supports sequential-access. Random-access to the value data is not supported.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Secure Key Value Storage\Updating and Settings and Permissions\Writing Keys (REQ-6.4.xx-SKVS-USP-WK) Requirements.
 | 
			
		||||
 | 
			
		||||
#### REQ-6.5.01-SKVS-USP-WK
 | 
			
		||||
CFSTORE KV values can be written in one or more operation. For example, if a value blob has size n bytes, then 2 n/2 byte write operations have the following effect:
 | 
			
		||||
- the first write sets bytes 0-n/2-1 in the value blob.
 | 
			
		||||
- the second write sets bytes n/2 to n-1 in the value blob.
 | 
			
		||||
This may require a write position to be maintained, for example. The ability to seek the write location must not be supported.
 | 
			
		||||
 | 
			
		||||
#### REQ-6.5.02-SKVS-USP-WK
 | 
			
		||||
This requirement has been removed.
 | 
			
		||||
 | 
			
		||||
#### REQ-6.5.03-SKVS-USP-WK
 | 
			
		||||
The KV stored in NV store should have an associated CRC so that: 
 | 
			
		||||
- the integrity of the data can be protected
 | 
			
		||||
- the corruption of the data can be detected e.g. if power is lost during the flush to NV store. 
 | 
			
		||||
The CRC should be stored at the end of the KV so it is written last. The CRC write transaction is termed "finalising" the KV.  
 | 
			
		||||
 | 
			
		||||
#### REQ-6.5.04-SKVS-USP-WK
 | 
			
		||||
KVs that have not been flushed to NV storage should be flushed at reboot time. 
 | 
			
		||||
 | 
			
		||||
#### REQ-6.5.05-SKVS-USP-WK
 | 
			
		||||
KVs may be fragmented into several smaller pieces for NV storage. In the case that a KV is fragmented, each fragment should have a an associated CRC as per REQ-6.5.03-SKVS-USP-WK.  
 | 
			
		||||
 | 
			
		||||
#### REQ-6.5.06-SKVS-USP-WK
 | 
			
		||||
A KV value or KV fragment can only be finalised by its owner.  
 | 
			
		||||
 | 
			
		||||
#### REQ-6.5.07-SKVS-USP-WK
 | 
			
		||||
Closing of a written KV in the finalization of all open value-fragment for that KV.  
 | 
			
		||||
 | 
			
		||||
#### REQ-6.5.08-SKVS-USP-WK
 | 
			
		||||
Flushing of the KVs causes finalisation of the store.
 | 
			
		||||
 | 
			
		||||
#### REQ-6.5.09-SKVS-USP-WK
 | 
			
		||||
Non-finalised object must not be readable.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Secure Key Value Storage\Updating and Settings and Permissions\Executable Keys and Firmware Updates (REQ-6.6.xx-SKVS-USP-EKFU)
 | 
			
		||||
Requirements.
 | 
			
		||||
 | 
			
		||||
#### REQ-6.6.01-SKVS-USP-EKFU
 | 
			
		||||
To facilitate modular firmware updates in future, executable keys are supported by the API 
 | 
			
		||||
 | 
			
		||||
#### REQ-6.6.02-SKVS-USP-EKFU
 | 
			
		||||
For immovable & O_CONTINUOUS keys, the absolute hardware address and the relative address of a value key can be queried using the API
 | 
			
		||||
This API feature is restricted to boxes that require that function (FOTA, DMA). By keeping most key-value pairs movable the flash can be de-fragmented.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Secure Key Value Storage\Miscellaneous (REQ-7.1.xx-SKVS-M)Requirements.
 | 
			
		||||
 | 
			
		||||
#### REQ-7.1.01-SKVS-M
 | 
			
		||||
The CFSTORE will implement a C Language interface.
 | 
			
		||||
 | 
			
		||||
#### REQ-7.1.02-SKVS-M
 | 
			
		||||
The CFSTORE does not support hot-pluggable storage devices e.g. SD flash. 
 | 
			
		||||
 | 
			
		||||
#### REQ-7.1.03-SKVS-M KV Value Data May Not Fit into Available (SRAM) Memory. 
 | 
			
		||||
CFSTORE must be capable of writing a KV to NV backing store where the value
 | 
			
		||||
data length >> size of available SRAM. This requirement therefore implies 
 | 
			
		||||
that CFSTORE must support the case that the whole of the KV value data cannot all be
 | 
			
		||||
resident in SRAM memory at one time.  
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Outstanding Issues With This Document
 | 
			
		||||
 | 
			
		||||
#### REQ-5.3.01-SKVS-APIL-COKFW: storage_key_create with O_CREATE
 | 
			
		||||
- How does the offset-address work?
 | 
			
		||||
- What is the definition of O_LAZY_FLUSH 
 | 
			
		||||
- What is the definition of O_BLOCK_WRITE 
 | 
			
		||||
- What is the definition of O_ALLOCATE_AT_OFFEST 
 | 
			
		||||
 | 
			
		||||
#### REQ-5.3.02-SKVS-APIL-COKFW: storage_key_create without O_CREATE
 | 
			
		||||
- To which "previous ACL" does this requirement refer?
 | 
			
		||||
- Is an implementation internally creating a new copy of the key?
 | 
			
		||||
 | 
			
		||||
#### REQ-6.5.01-SKVS-USP-WK
 | 
			
		||||
- Are there any additional requirements arising from these statements?
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Contributors
 | 
			
		||||
 | 
			
		||||
This document was made possible through the contributions of the following people:
 | 
			
		||||
- Rohit Grover
 | 
			
		||||
- Simon Hughes
 | 
			
		||||
- Milosch Meriac
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[CFSTORE_TERM]: doc/design/configuration_store_terminology.md
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
# Configuration-Store Terminology
 | 
			
		||||
 | 
			
		||||
## Defintion of Terms
 | 
			
		||||
 | 
			
		||||
### ACL 
 | 
			
		||||
Access Control List
 | 
			
		||||
 | 
			
		||||
### CFSTORE 
 | 
			
		||||
Configuration Store
 | 
			
		||||
 | 
			
		||||
### FOTA 
 | 
			
		||||
Firmware Over The Air
 | 
			
		||||
 | 
			
		||||
### HLD 
 | 
			
		||||
High Level Design
 | 
			
		||||
 | 
			
		||||
### KV
 | 
			
		||||
Key Value Pair, also represented as {key, value}
 | 
			
		||||
 | 
			
		||||
### Key Name Prefix
 | 
			
		||||
This is indentical tot he Security Name Prefix. 
 | 
			
		||||
 | 
			
		||||
### LLD
 | 
			
		||||
Low Level Design
 | 
			
		||||
 | 
			
		||||
### NV
 | 
			
		||||
Non Volatile
 | 
			
		||||
 | 
			
		||||
### OS 
 | 
			
		||||
Operating System
 | 
			
		||||
 | 
			
		||||
### Security Name Prefix
 | 
			
		||||
If a client security context (uvisor box) needs to create CFSTORE KV entries, it must have a (mandatory) key name prefix. This is called the security_prefix_name.
 | 
			
		||||
 
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,74 @@
 | 
			
		|||
# Configuration Store Test Plan
 | 
			
		||||
 | 
			
		||||
# Overview
 | 
			
		||||
 | 
			
		||||
This document describes the test plan and test cases for the configuration-store project.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Overview of Test Binaries
 | 
			
		||||
 | 
			
		||||
The test cases are divided into a number of test case binaries:
 | 
			
		||||
- Access Control List (ACL) test cases implemented by acl.cpp. The ACL test binary verifies 
 | 
			
		||||
  the ACL related functionality is working correctly. 
 | 
			
		||||
- Add/Delete test cases implemented by add_del.cpp. The ADD_DEL test binary verifies
 | 
			
		||||
  that key-value attributes can be added/deleted to/from the store as expected using
 | 
			
		||||
  the Create()/Delete() API functions.
 | 
			
		||||
- Close test cases implemented by close.cpp. The CLOSE test binary verifies
 | 
			
		||||
  that the key-value Close() API function works correctly.
 | 
			
		||||
- Create test cases implemented by create.cpp. The CREATE test binary verifies 
 | 
			
		||||
  the Create() API function works correctly. 
 | 
			
		||||
- Find test cases implemented by find.cpp. The FIND test binary verifies 
 | 
			
		||||
  the Find() API function works correctly. 
 | 
			
		||||
- Find2 test cases implemented by find2.cpp. The FIND test binary verifies 
 | 
			
		||||
  the Find()/Create() API functions works correctly. 
 | 
			
		||||
- Flash test cases implemented by flash.cpp. The FLASH test binary verifies 
 | 
			
		||||
  the Flash-Journal API functions works correctly from the CFSTORE perspective. 
 | 
			
		||||
- Flush test cases implemented by flush.cpp. The FLUSH test binary verifies 
 | 
			
		||||
  the Flush() API functions works correctly. The test case uses a finite state
 | 
			
		||||
  machine to track asynchronous completion of operations. 
 | 
			
		||||
- Flush2 test cases implemented by flush2.cpp. The FLUSH2 test binary verifies 
 | 
			
		||||
  the Flush() API functions works correctly.  
 | 
			
		||||
- Flush3 test cases implemented by flush3.cpp. The FLUSH3 test binary verifies 
 | 
			
		||||
  the Flush() API functions works correctly.  
 | 
			
		||||
- Initialize/Uninitialize test cases implemented by init.cpp. The INIT test binary verifies 
 | 
			
		||||
  the Initialize()/Uninitialize() API functions works correctly.  
 | 
			
		||||
- Misc test cases implemented by misc.cpp. The MISC test binary verifies 
 | 
			
		||||
  the GetCapabilities()/PowerControl() API functions works correctly, for example.  
 | 
			
		||||
- Read test cases implemented by read.cpp. The READ test binary verifies 
 | 
			
		||||
  the Read()/Rseek() API functions works correctly.  
 | 
			
		||||
- Write test cases implemented by write.cpp. The WRITE test binary verifies 
 | 
			
		||||
  the Write() API function works correctly.  
 | 
			
		||||
 | 
			
		||||
There are a number of test cases that are also examples:
 | 
			
		||||
- Example1 test case implemented by example1.cpp. 
 | 
			
		||||
    - The EXAMPLE1 test binary demonstrates each API function works correctly. 
 | 
			
		||||
    - The example code shows how to write application code that works for both
 | 
			
		||||
      asynchronous and synchronous modes of operation.
 | 
			
		||||
    - example1.cpp can be compiled as mbed greentea test case or a stand-alone test
 | 
			
		||||
      application. 
 | 
			
		||||
- Example2 test case implemented by example2.cpp. 
 | 
			
		||||
    - The EXAMPLE2 test binary demonstrates a subset of the API functions each work correctly. 
 | 
			
		||||
    - The example code shows how to write application code that works for both
 | 
			
		||||
      asynchronous and synchronous modes of operation.
 | 
			
		||||
    - example2.cpp can be compiled only as mbed greentea test case 
 | 
			
		||||
- Example3 test case implemented by example3.cpp. 
 | 
			
		||||
    - The EXAMPLE3 test binary demonstrates each API function works correctly. 
 | 
			
		||||
    - The example code shows how to write application code that works for synchronous mode only.
 | 
			
		||||
    - example3.cpp can be compiled as mbed greentea test case or a stand-alone test
 | 
			
		||||
      application. 
 | 
			
		||||
- Example4 test case implemented by example4.cpp. 
 | 
			
		||||
    - The EXAMPLE2 test binary demonstrates a subset of the API functions each work correctly. 
 | 
			
		||||
    - The example code shows how to write application code that works for synchronous modes only.
 | 
			
		||||
    - example2.cpp can be compiled only as mbed greentea test case 
 | 
			
		||||
- Example5 test case implemented by example5.cpp. 
 | 
			
		||||
    - The EXAMPLE5 test binary demonstrates each API function works correctly. 
 | 
			
		||||
    - The example code shows how to write application code that works for synchronous mode only.
 | 
			
		||||
    - example5.cpp can be compiled as mbed greentea test case or a stand-alone test
 | 
			
		||||
      application. 
 | 
			
		||||
 | 
			
		||||
# Test Case Documentation
 | 
			
		||||
 | 
			
		||||
The individual test cases implemented in each test binary are described in the doxygen test case function
 | 
			
		||||
documentation. For example, for the test case documentation for ADD_DEL,
 | 
			
		||||
see the doxygen generated documentation for each test case function generated from the add_del.cpp file. 
 | 
			
		||||
Alternatively, see the comments in the add_del.cpp file.   
 | 
			
		||||
| 
		 After Width: | Height: | Size: 100 KiB  | 
| 
		 After Width: | Height: | Size: 79 KiB  | 
| 
		 After Width: | Height: | Size: 78 KiB  | 
| 
		 After Width: | Height: | Size: 47 KiB  | 
| 
		 After Width: | Height: | Size: 89 KiB  | 
| 
		 After Width: | Height: | Size: 59 KiB  | 
| 
		 After Width: | Height: | Size: 85 KiB  | 
| 
		 After Width: | Height: | Size: 68 KiB  | 
| 
		 After Width: | Height: | Size: 26 KiB  | 
| 
		 After Width: | Height: | Size: 48 KiB  | 
| 
		 After Width: | Height: | Size: 28 KiB  | 
| 
		 After Width: | Height: | Size: 86 KiB  | 
| 
		 After Width: | Height: | Size: 55 KiB  | 
| 
		 After Width: | Height: | Size: 83 KiB  | 
| 
		 After Width: | Height: | Size: 52 KiB  | 
| 
		 After Width: | Height: | Size: 22 KiB  | 
| 
		 After Width: | Height: | Size: 289 KiB  | 
| 
						 | 
				
			
			@ -0,0 +1,363 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<diagram program="umlet" version="13.2">
 | 
			
		||||
  <zoom_level>8</zoom_level>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>UMLInterface</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>0</x>
 | 
			
		||||
      <y>872</y>
 | 
			
		||||
      <w>784</w>
 | 
			
		||||
      <h>312</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes>ARM_DRIVER_CFSTORE
 | 
			
		||||
Config-Store (CS) Interface
 | 
			
		||||
--
 | 
			
		||||
ARM_DRIVER_VERSION (*GetVersion)(void);
 | 
			
		||||
int32_t (*Close)(ARM_CFSTORE_HANDLE hkey);
 | 
			
		||||
int32_t (*Create)(const char* key_name, ARM_CFSTORE_SIZE value_len, const ARM_CFSTORE_KEYDESC* kdesc, ARM_CFSTORE_HANDLE hkey);
 | 
			
		||||
int32_t (*Delete)(ARM_CFSTORE_HANDLE hkey);
 | 
			
		||||
int32_t (*Find)(const char* key_name_query, const ARM_CFSTORE_HANDLE previous, ARM_CFSTORE_HANDLE next);
 | 
			
		||||
int32_t (*Flush)(void);
 | 
			
		||||
int32_t (*GetKeyName)(ARM_CFSTORE_HANDLE hkey, char* key_name, uint8_t *key_len);
 | 
			
		||||
ARM_CFSTORE_CAPABILITIES (*GetCapabilities)(void);
 | 
			
		||||
ARM_CFSTORE_STATUS (*GetStatus)(void);
 | 
			
		||||
int32_t (*GetValueLen)(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_SIZE *value_len);
 | 
			
		||||
int32_t (*Initialize)(ARM_CFSTORE_CALLBACK callback, void* client_context);
 | 
			
		||||
int32_t (*PowerControl)(ARM_POWER_STATE state);
 | 
			
		||||
int32_t (*Read)(ARM_CFSTORE_HANDLE hkey, void* data, ARM_CFSTORE_SIZE* len);
 | 
			
		||||
int32_t (*Open)(const char* key_name, ARM_CFSTORE_FMODE flags, ARM_CFSTORE_HANDLE hkey);
 | 
			
		||||
int32_t (*Rseek)(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_OFFSET offset);
 | 
			
		||||
int32_t (*Uninitialise)(void);
 | 
			
		||||
int32_t (*Write)(ARM_CFSTORE_HANDLE hkey, const char* data, ARM_CFSTORE_SIZE* len);
 | 
			
		||||
 | 
			
		||||
</panel_attributes>
 | 
			
		||||
    <additional_attributes/>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>UMLClass</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>488</x>
 | 
			
		||||
      <y>1168</y>
 | 
			
		||||
      <w>192</w>
 | 
			
		||||
      <h>112</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes>ARM_CFSTORE_ACCESS_CONTROL_LIST
 | 
			
		||||
--
 | 
			
		||||
uint32_t perm_owner_read : 1;
 | 
			
		||||
uint32_t perm_owner_write : 1;
 | 
			
		||||
uint32_t perm_owner_execute : 1;
 | 
			
		||||
uint32_t perm_other_read : 1;
 | 
			
		||||
uint32_t perm_other_write : 1;
 | 
			
		||||
uint32_t perm_other_execute : 1;
 | 
			
		||||
</panel_attributes>
 | 
			
		||||
    <additional_attributes/>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>UMLClass</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>688</x>
 | 
			
		||||
      <y>1168</y>
 | 
			
		||||
      <w>264</w>
 | 
			
		||||
      <h>144</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes>ARM_STOR_DATA_RETENTION_LEVEL
 | 
			
		||||
--
 | 
			
		||||
/* supported volatility values of different sotrage mediums */
 | 
			
		||||
DATA_RETENTION_WHILE_DEVICE_ACTIVE,
 | 
			
		||||
DATA_RETENTION_ACROSS_SLEEP,
 | 
			
		||||
DATA_RETENTION_ACROSS_DEEP_SLEEP,
 | 
			
		||||
DATA_RETENTION_BATTERY_BACKED,
 | 
			
		||||
DATA_RETENTION_NVM,
 | 
			
		||||
</panel_attributes>
 | 
			
		||||
    <additional_attributes/>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>UMLClass</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>1320</x>
 | 
			
		||||
      <y>1168</y>
 | 
			
		||||
      <w>184</w>
 | 
			
		||||
      <h>136</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes>ARM_CFSTORE_FMODE
 | 
			
		||||
--
 | 
			
		||||
uint32_t continuous : 1;
 | 
			
		||||
uint32_t lazy_flush : 1;
 | 
			
		||||
uint32_t flush_on_close : 1;
 | 
			
		||||
uint32_t read : 1;
 | 
			
		||||
uint32_t write : 1;
 | 
			
		||||
uint32_t execute : 1;
 | 
			
		||||
uint32_t storage_detect : 1;
 | 
			
		||||
 | 
			
		||||
</panel_attributes>
 | 
			
		||||
    <additional_attributes/>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>Relation</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>536</x>
 | 
			
		||||
      <y>1072</y>
 | 
			
		||||
      <w>544</w>
 | 
			
		||||
      <h>112</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes>lt=<-</panel_attributes>
 | 
			
		||||
    <additional_attributes>10.0;120.0;660.0;10.0</additional_attributes>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>Relation</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>1056</x>
 | 
			
		||||
      <y>1072</y>
 | 
			
		||||
      <w>368</w>
 | 
			
		||||
      <h>112</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes>lt=<-</panel_attributes>
 | 
			
		||||
    <additional_attributes>440.0;120.0;10.0;10.0</additional_attributes>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>UMLClass</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>968</x>
 | 
			
		||||
      <y>1168</y>
 | 
			
		||||
      <w>344</w>
 | 
			
		||||
      <h>256</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes>ARM_STOR_SECURITY_FEATURES
 | 
			
		||||
--
 | 
			
		||||
uint8_t acls                : 1; ///< protection against internal software attacks using ACLs.
 | 
			
		||||
uint8_t rollback_protection : 1; ///< roll-back protection.
 | 
			
		||||
uint8_t tamper_proof        : 1; ///< tamper-proof memory (will be deleted on tamper-attempts using board level or chip level sensors).
 | 
			
		||||
uint8_t internal_flash      : 1; ///< Internal flash.
 | 
			
		||||
uint8_t reserved            : 4;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* Encode support for hardening against various classes of attacks.
 | 
			
		||||
*/
 | 
			
		||||
struct ARM_STOR_HARDENING 
 | 
			
		||||
{
 | 
			
		||||
 uint8_t device_software      : 1; ///< device software (malware running on the device).
 | 
			
		||||
 uint8_t board_level_attacks  : 1; ///< board level attacks (debug probes, copy protection fuses.)
 | 
			
		||||
 uint8_t chip_level_attacks   : 1; ///< chip level attacks (tamper-protection).
 | 
			
		||||
 uint8_t side_channel_attacks : 1; ///< side channel attacks.
 | 
			
		||||
 uint8_t reserved             : 4;
 | 
			
		||||
} hardening_against; ///< hardening.
 | 
			
		||||
</panel_attributes>
 | 
			
		||||
    <additional_attributes/>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>Relation</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>816</x>
 | 
			
		||||
      <y>1072</y>
 | 
			
		||||
      <w>264</w>
 | 
			
		||||
      <h>112</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes>lt=<-</panel_attributes>
 | 
			
		||||
    <additional_attributes>10.0;120.0;310.0;10.0</additional_attributes>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>Relation</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>1056</x>
 | 
			
		||||
      <y>1072</y>
 | 
			
		||||
      <w>24</w>
 | 
			
		||||
      <h>112</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes>lt=<-</panel_attributes>
 | 
			
		||||
    <additional_attributes>10.0;120.0;10.0;10.0</additional_attributes>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>UMLActor</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>1304</x>
 | 
			
		||||
      <y>0</y>
 | 
			
		||||
      <w>104</w>
 | 
			
		||||
      <h>96</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes>Box 1
 | 
			
		||||
Security Context</panel_attributes>
 | 
			
		||||
    <additional_attributes/>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>UMLActor</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>1408</x>
 | 
			
		||||
      <y>0</y>
 | 
			
		||||
      <w>104</w>
 | 
			
		||||
      <h>96</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes>Box i
 | 
			
		||||
Security Context</panel_attributes>
 | 
			
		||||
    <additional_attributes/>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>UMLActor</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>1504</x>
 | 
			
		||||
      <y>0</y>
 | 
			
		||||
      <w>104</w>
 | 
			
		||||
      <h>96</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes>Box n
 | 
			
		||||
Security Context</panel_attributes>
 | 
			
		||||
    <additional_attributes/>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>UMLUseCase</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>1376</x>
 | 
			
		||||
      <y>160</y>
 | 
			
		||||
      <w>184</w>
 | 
			
		||||
      <h>96</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes>Config Store
 | 
			
		||||
{key,value} storage operations
 | 
			
		||||
 </panel_attributes>
 | 
			
		||||
    <additional_attributes/>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>Relation</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>1360</x>
 | 
			
		||||
      <y>48</y>
 | 
			
		||||
      <w>128</w>
 | 
			
		||||
      <h>128</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes><<uses>></panel_attributes>
 | 
			
		||||
    <additional_attributes>10.0;10.0;140.0;140.0</additional_attributes>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>Relation</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>1464</x>
 | 
			
		||||
      <y>48</y>
 | 
			
		||||
      <w>56</w>
 | 
			
		||||
      <h>128</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes><<uses>></panel_attributes>
 | 
			
		||||
    <additional_attributes>10.0;10.0;10.0;140.0</additional_attributes>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>Relation</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>1464</x>
 | 
			
		||||
      <y>48</y>
 | 
			
		||||
      <w>120</w>
 | 
			
		||||
      <h>128</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes><<uses>></panel_attributes>
 | 
			
		||||
    <additional_attributes>130.0;10.0;10.0;140.0</additional_attributes>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>UMLNote</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>224</x>
 | 
			
		||||
      <y>656</y>
 | 
			
		||||
      <w>304</w>
 | 
			
		||||
      <h>64</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes>Note..
 | 
			
		||||
mbed_config_store_hld
 | 
			
		||||
v0.04
 | 
			
		||||
20160225
 | 
			
		||||
 | 
			
		||||
</panel_attributes>
 | 
			
		||||
    <additional_attributes/>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>UMLClass</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>824</x>
 | 
			
		||||
      <y>968</y>
 | 
			
		||||
      <w>264</w>
 | 
			
		||||
      <h>112</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes>ARM_CFSTORE_KEYDESC
 | 
			
		||||
--
 | 
			
		||||
/*key descriptor attributes */
 | 
			
		||||
ARM_CFSTORE_ACCESS_CONTROL_LIST acl;
 | 
			
		||||
ARM_STOR_DATA_RETENTION_LEVEL drl;
 | 
			
		||||
ARM_STOR_SECURITY_FEATURES security;
 | 
			
		||||
ARM_CFSTORE_FMODE flags;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</panel_attributes>
 | 
			
		||||
    <additional_attributes/>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>UMLClass</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>904</x>
 | 
			
		||||
      <y>720</y>
 | 
			
		||||
      <w>240</w>
 | 
			
		||||
      <h>232</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes>ARM_CFSTORE_OPCODE;
 | 
			
		||||
--
 | 
			
		||||
CFSTORE_OPCODE_CLOSE
 | 
			
		||||
CFSTORE_OPCODE_CREATE
 | 
			
		||||
CFSTORE_OPCODE_DELETE
 | 
			
		||||
CFSTORE_OPCODE_FIND
 | 
			
		||||
CFSTORE_OPCODE_FLUSH
 | 
			
		||||
CFSTORE_OPCODE_GET_KEY_NAME
 | 
			
		||||
CFSTORE_OPCODE_GET_STATUS
 | 
			
		||||
CFSTORE_OPCODE_GET_VALUE_LEN
 | 
			
		||||
CFSTORE_OPCODE_INITIALIZE
 | 
			
		||||
CFSTORE_OPCODE_OPEN
 | 
			
		||||
CFSTORE_OPCODE_POWER_CONTROL
 | 
			
		||||
CFSTORE_OPCODE_READ
 | 
			
		||||
CFSTORE_OPCODE_RSEEK
 | 
			
		||||
CFSTORE_OPCODE_UNINITIALIZE
 | 
			
		||||
CFSTORE_OPCODE_WRITE
 | 
			
		||||
CFSTORE_OPCODE_MAX
 | 
			
		||||
</panel_attributes>
 | 
			
		||||
    <additional_attributes/>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>UMLClass</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>576</x>
 | 
			
		||||
      <y>608</y>
 | 
			
		||||
      <w>808</w>
 | 
			
		||||
      <h>64</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes>ARM_CFSTORE_CALLBACK
 | 
			
		||||
--
 | 
			
		||||
typedef void (*ARM_CFSTORE_CALLBACK)(int32_t status, ARM_CFSTORE_OPCODE cmd_code, void *client_context, ARM_CFSTORE_HANDLE handle);
 | 
			
		||||
</panel_attributes>
 | 
			
		||||
    <additional_attributes/>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>Relation</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>392</x>
 | 
			
		||||
      <y>880</y>
 | 
			
		||||
      <w>576</w>
 | 
			
		||||
      <h>104</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes>lt=<-</panel_attributes>
 | 
			
		||||
    <additional_attributes>700.0;110.0;10.0;10.0</additional_attributes>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>Relation</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>392</x>
 | 
			
		||||
      <y>664</y>
 | 
			
		||||
      <w>536</w>
 | 
			
		||||
      <h>240</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes>lt=<-</panel_attributes>
 | 
			
		||||
    <additional_attributes>650.0;10.0;10.0;280.0</additional_attributes>
 | 
			
		||||
  </element>
 | 
			
		||||
  <element>
 | 
			
		||||
    <id>Relation</id>
 | 
			
		||||
    <coordinates>
 | 
			
		||||
      <x>392</x>
 | 
			
		||||
      <y>816</y>
 | 
			
		||||
      <w>528</w>
 | 
			
		||||
      <h>88</h>
 | 
			
		||||
    </coordinates>
 | 
			
		||||
    <panel_attributes>lt=<-</panel_attributes>
 | 
			
		||||
    <additional_attributes>640.0;10.0;10.0;90.0</additional_attributes>
 | 
			
		||||
  </element>
 | 
			
		||||
</diagram>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,68 @@
 | 
			
		|||
# Configuration Store Releases
 | 
			
		||||
Author: Simon Hughes
 | 
			
		||||
 | 
			
		||||
# Overview
 | 
			
		||||
 | 
			
		||||
This page documents the supported requirements in each release. See the [Configuration Store Requirements][CFSTORE_ENGREQ] 
 | 
			
		||||
for the definitions of the REQ-xxx reference numbers used in this document.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Releases
 | 
			
		||||
 | 
			
		||||
## Release 0.3.2
 | 
			
		||||
 | 
			
		||||
The requirements status (supported versus not supported) in this release are as follows:
 | 
			
		||||
 | 
			
		||||
- REQ-1.01-SKVS-R: Not supported. Currently only SRAM back CFSTORE is supported.
 | 
			
		||||
- REQ-1.02-SKVS-R: Not supported. uvisor integration is still outstanding.
 | 
			
		||||
- REQ-1.03-SKVS-R: Supported.
 | 
			
		||||
- REQ-1.04-SKVS-R: Supported.
 | 
			
		||||
- REQ-1.05-SKVS-R: Supported.
 | 
			
		||||
- REQ-1.06-SKVS-R: Supported.
 | 
			
		||||
- REQ-1.07-SKVS-R: CS Stores Binary Blobs:  Supported.
 | 
			
		||||
- REQ-1.08-SKVS-R: CS Key Structure as Name Strings: Supported.
 | 
			
		||||
- REQ-1.09-SKVS-R: Key Creation and Ownership Part 1: Not supported. uvisor integration is still outstanding.
 | 
			
		||||
- REQ-1.10-SKVS-R: Security Context: Not supported. uvisor integration is still outstanding.
 | 
			
		||||
- REQ-1.2.01-SKVS-HLD: Not supported. Currently only SRAM back CFSTORE is supported.
 | 
			
		||||
- REQ-1.2.02-SKVS-HLD: "only during device activity" supported but other options not supported.
 | 
			
		||||
- REQ-1.2.03-SKVS-HLD: Not supported.
 | 
			
		||||
- REQ-1.2.04-SKVS-HLD: Not supported.
 | 
			
		||||
- REQ-1.2.05-SKVS-HLD: Supported.
 | 
			
		||||
- REQ-3.1.01-SKVS-HLAPID-KVS: CS Global Key Namespace: Supported.
 | 
			
		||||
- REQ-3.1.02-SKVS-HLAPID-KVS: CS Key Name String Format Max Length: Supported.
 | 
			
		||||
- REQ-3.1.03-SKVS-HLAPID-KVS: CS Key Name String Allowed Characters: Supported.
 | 
			
		||||
- REQ-3.1.04-SKVS-HLAPID-KVS: Key Name Path Directory Entry List []:  Supported.
 | 
			
		||||
- REQ-3.1.05-SKVS-HLAPID-KVS: CS Global Key Yotta Namespace:  Supported.
 | 
			
		||||
- REQ-3.2.01-SKVS-HLAPID-KACS: Not supported as requires uvisor integration.
 | 
			
		||||
- REQ-3.2.02-SKVS-HLAPID-KACS: CS Key Creation Part 2: Supported.
 | 
			
		||||
- REQ-3.2.03-SKVS-HLAPID-KACS: Partially supported as requires uvisor integration.
 | 
			
		||||
- REQ-3.2.04-SKVS-HLAPID-KACS: Supported.
 | 
			
		||||
- REQ-5.1.01-SKVS-APIL-FK: Key Searching/Finding Scoped by ACL: Supported.
 | 
			
		||||
- REQ-5.1.02-SKVS-APIL-FK: CS Global Key Namespace Reserves Character '*': Supported.
 | 
			
		||||
- REQ-5.1.03-SKVS-APIL-FK: Key Searching/Finding Resume:  Supported.
 | 
			
		||||
- REQ-5.1.04-SKVS-APIL-FK: Key Searching/Finding Internals (key versions): Not supported.
 | 
			
		||||
- REQ-5.2.01-SKVS-APIL-GSI: storage_detect: Not supported.
 | 
			
		||||
- REQ-5.2.02-SKVS-APIL-GSI: Minimal Storage Support: Supported.
 | 
			
		||||
- REQ-5.3.01-SKVS-APIL-COKFW: storage_key_create with O_CREATE: Partially suppported.
 | 
			
		||||
- REQ-5.3.02-SKVS-APIL-COKFW: storage_key_create without O_CREATE: Not supported.
 | 
			
		||||
- REQ-5.3.03-SKVS-APIL-COKFW: O_CONTINUOUS for executable objects: Not supported.
 | 
			
		||||
- REQ-5.3.04-SKVS-APIL-COKFW: O_CONTINUOUS for non-executable objects: Not supported.
 | 
			
		||||
- REQ-6.1.01-SKVS-USP: Supported.
 | 
			
		||||
- REQ-6.2.01-SKVS-USP-DK: Supported.
 | 
			
		||||
- REQ-6.2.02-SKVS-USP-DK: Supported.
 | 
			
		||||
- REQ-6.3.01-SKVS-USP-OKFR storage_key_open_read:  Supported.
 | 
			
		||||
- REQ-6.4.01-SKVS-USP-SIKV storage_value_rseek: Supported.
 | 
			
		||||
- REQ-6.4.02-SKVS-USP-SIKV storage_value_write has no write location: Supported.
 | 
			
		||||
- REQ-6.4.03-SKVS-USP-SIKV storage_value_write sequential-access: Supported.
 | 
			
		||||
- REQ-6.5.01-SKVS-USP-WK: Partially supported.
 | 
			
		||||
- REQ-6.5.01-SKVS-USP-WK: Not supported.
 | 
			
		||||
- REQ-6.6.01-SKVS-USP-EKFU: Not supported.
 | 
			
		||||
- REQ-6.6.02-SKVS-USP-EKFU: Not supported.
 | 
			
		||||
- REQ-7.1.01-SKVS-M: Supported.
 | 
			
		||||
- REQ-7.1.02-SKVS-M: Supported.
 | 
			
		||||
- REQ-7.1.03-SKVS-M KV Value Data May Not Fit into Available (SRAM) Memory. Not supported. 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[CFSTORE_ENGREQ]: doc/design/configuration_store_requirements.md
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
{
 | 
			
		||||
    "name": "configuration-store",
 | 
			
		||||
    "config": {
 | 
			
		||||
        "storage_disable": {
 | 
			
		||||
            "help": "Configuration parameter to disable flash storage if present. Default = 0, implying that by default flash storage is used if present.",
 | 
			
		||||
            "macro_name": "CFSTORE_STORAGE_DISABLE",
 | 
			
		||||
            "value": 0
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,59 @@
 | 
			
		|||
/** @file cfstore_debug.h
 | 
			
		||||
 *
 | 
			
		||||
 * component debug header file.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef __CFSTORE_CONFIG_H
 | 
			
		||||
#define __CFSTORE_CONFIG_H
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
 *  = 1 >1 build with the flash
 | 
			
		||||
 * CFSTORE_CONFIG_BACKEND_UVISOR_ENABLED
 | 
			
		||||
 * CFSTORE_CONFIG_MBED_OS_VERSION
 | 
			
		||||
 *  3 => mbedosV3
 | 
			
		||||
 *  4 => morpheus
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* default values */
 | 
			
		||||
#define CFSTORE_CONFIG_BACKEND_UVISOR_ENABLED   0
 | 
			
		||||
#define CFSTORE_CONFIG_MBED_OS_VERSION		    3
 | 
			
		||||
 | 
			
		||||
/* default build config overridden by package manager configuration
 | 
			
		||||
 *
 | 
			
		||||
 * __MBED__
 | 
			
		||||
 *   Morpheus build system (mbed-classic) defines the __MBED__ symbol
 | 
			
		||||
 *
 | 
			
		||||
 * YOTTA_CFG_CFSTORE_BACKEND_SRAM
 | 
			
		||||
 *   build only for sram backend (no flash integration)
 | 
			
		||||
 * YOTTA_CFG_CFSTORE_UVISOR_ENABLE
 | 
			
		||||
 *   build with uvisor enable
 | 
			
		||||
 *
 | 
			
		||||
 * */
 | 
			
		||||
 | 
			
		||||
#ifdef __MBED__
 | 
			
		||||
#undef CFSTORE_CONFIG_MBED_OS_VERSION
 | 
			
		||||
#define CFSTORE_CONFIG_MBED_OS_VERSION    4
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* at present time building for sram so set yotta symbol for sync mode i.e. async_ops = 0*/
 | 
			
		||||
#define YOTTA_CFG_CONFIG_HARDWARE_MTD_ASYNC_OPS     0
 | 
			
		||||
#endif /* __MBED__ */
 | 
			
		||||
 | 
			
		||||
/* DEVICE_STORAGE
 | 
			
		||||
 *   defined by the mbed configuration system if a target supports flash storage
 | 
			
		||||
 *   back-end. See targets.json for target flash support.
 | 
			
		||||
 *    - If a target supports storage then by default cfstore will persist KVs to
 | 
			
		||||
 *      storage.
 | 
			
		||||
 *    - If a target does not support storage then (by default) cfstore will store KVs
 | 
			
		||||
 *      in SRAM only (i.e. operate in SRAM in-memory mode).
 | 
			
		||||
 *
 | 
			
		||||
 * CFSTORE_STORAGE_DISABLE
 | 
			
		||||
 *   Disable use of storage support (if present)
 | 
			
		||||
 */
 | 
			
		||||
#if defined DEVICE_STORAGE && CFSTORE_STORAGE_DISABLE==0
 | 
			
		||||
#define CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /*__CFSTORE_CONFIG_H*/
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,119 @@
 | 
			
		|||
/** @file cfstore_debug.h
 | 
			
		||||
 *
 | 
			
		||||
 * component debug header file.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef __CFSTORE_DEBUG
 | 
			
		||||
#define __CFSTORE_DEBUG
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Debug Support */
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_LOG_NONE        0
 | 
			
		||||
#define CFSTORE_LOG_ERR         1
 | 
			
		||||
#define CFSTORE_LOG_WARN        2
 | 
			
		||||
#define CFSTORE_LOG_NOTICE      3
 | 
			
		||||
#define CFSTORE_LOG_INFO        4
 | 
			
		||||
#define CFSTORE_LOG_DEBUG       5
 | 
			
		||||
#define CFSTORE_LOG_FENTRY      6
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_LOG(_fmt, ...)                          \
 | 
			
		||||
  do                                                    \
 | 
			
		||||
  {                                                     \
 | 
			
		||||
        printf(_fmt, __VA_ARGS__);                      \
 | 
			
		||||
  }while(0);
 | 
			
		||||
 | 
			
		||||
#define noCFSTORE_DEBUG
 | 
			
		||||
#ifdef CFSTORE_DEBUG
 | 
			
		||||
 | 
			
		||||
extern uint32_t cfstore_optDebug_g;
 | 
			
		||||
extern uint32_t cfstore_optLogLevel_g;
 | 
			
		||||
extern uint32_t cfstore_optLogTracepoint_g;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* uncomment for asserts to work */
 | 
			
		||||
/* #undef NDEBUG */
 | 
			
		||||
// todo: port to mbedOSV3++ #include <core-util/assert.h>
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_INLINE
 | 
			
		||||
// todo: port to mbedOSV3++ #define CFSTORE_ASSERT  CORE_UTIL_ASSERT
 | 
			
		||||
#define CFSTORE_ASSERT(...)
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_DBGLOG(_fmt, ...)                       \
 | 
			
		||||
  do                                                    \
 | 
			
		||||
  {                                                     \
 | 
			
		||||
    if(cfstore_optDebug_g && (cfstore_optLogLevel_g >= CFSTORE_LOG_DEBUG))  \
 | 
			
		||||
    {                                                   \
 | 
			
		||||
        printf(_fmt, __VA_ARGS__);                      \
 | 
			
		||||
    }                                                   \
 | 
			
		||||
  }while(0);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_ERRLOG(_fmt, ...)                       \
 | 
			
		||||
  do                                                    \
 | 
			
		||||
  {                                                     \
 | 
			
		||||
    if(cfstore_optDebug_g && (cfstore_optLogLevel_g >= CFSTORE_LOG_ERR))  \
 | 
			
		||||
    {                                                   \
 | 
			
		||||
        printf(_fmt, __VA_ARGS__);                      \
 | 
			
		||||
    }                                                   \
 | 
			
		||||
  }while(0);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_FENTRYLOG(_fmt, ...)                       \
 | 
			
		||||
  do                                                    \
 | 
			
		||||
  {                                                     \
 | 
			
		||||
    if(cfstore_optDebug_g && (cfstore_optLogLevel_g >= CFSTORE_LOG_FENTRY))  \
 | 
			
		||||
    {                                                   \
 | 
			
		||||
        printf(_fmt, __VA_ARGS__);                      \
 | 
			
		||||
    }                                                   \
 | 
			
		||||
  }while(0);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* tracepoints */
 | 
			
		||||
#define CFSTORE_TP_NONE         0x0
 | 
			
		||||
#define CFSTORE_TP_CLOSE        (1<<0)
 | 
			
		||||
#define CFSTORE_TP_CREATE       (1<<1)
 | 
			
		||||
#define CFSTORE_TP_DELETE       (1<<2)
 | 
			
		||||
#define CFSTORE_TP_FILE         (1<<3)
 | 
			
		||||
#define CFSTORE_TP_FIND         (1<<4)
 | 
			
		||||
#define CFSTORE_TP_FLUSH        (1<<5)
 | 
			
		||||
#define CFSTORE_TP_FSM          (1<<6)
 | 
			
		||||
#define CFSTORE_TP_INIT         (1<<7)
 | 
			
		||||
#define CFSTORE_TP_MEM          (1<<8)
 | 
			
		||||
#define CFSTORE_TP_OPEN         (1<<9)
 | 
			
		||||
#define CFSTORE_TP_READ         (1<<10)
 | 
			
		||||
#define CFSTORE_TP_WRITE        (1<<11)
 | 
			
		||||
#define CFSTORE_TP_VERBOSE1     (1<<12)
 | 
			
		||||
#define CFSTORE_TP_VERBOSE2     (1<<13)
 | 
			
		||||
#define CFSTORE_TP_VERBOSE3     (1<<14)
 | 
			
		||||
#define CFSTORE_TP_CALLBACK     (1<<15)
 | 
			
		||||
#define CFSTORE_TP_FENTRY       (1<<31)
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_TP(_tp, _fmt, ...)                                              \
 | 
			
		||||
do                                                                              \
 | 
			
		||||
{                                                                               \
 | 
			
		||||
    if(cfstore_optDebug_g && (cfstore_optLogLevel_g >= CFSTORE_LOG_DEBUG))      \
 | 
			
		||||
    {                                                                           \
 | 
			
		||||
        if((cfstore_optLogTracepoint_g & (_tp)) == (uint32_t)(_tp))             \
 | 
			
		||||
        {                                                                       \
 | 
			
		||||
            printf(_fmt, __VA_ARGS__);                                          \
 | 
			
		||||
        }                                                                       \
 | 
			
		||||
    }                                                                           \
 | 
			
		||||
}while(0);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
#define CFSTORE_ASSERT(_x)                   do { } while(0)
 | 
			
		||||
#define CFSTORE_INLINE                       inline
 | 
			
		||||
#define CFSTORE_DBGLOG(_fmt, ...)            do { } while(0)
 | 
			
		||||
#define CFSTORE_ERRLOG(_fmt, ...)            do { } while(0)
 | 
			
		||||
#define CFSTORE_FENTRYLOG(_fmt, ...)         do { } while(0)
 | 
			
		||||
#define CFSTORE_TP(_tp, _fmt, ...)           do { } while(0)
 | 
			
		||||
#endif /* CFSTORE_DEBUG */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif /*__CFSTORE_DEBUG*/
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,326 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 1989, 1993, 1994
 | 
			
		||||
 *	The Regents of the University of California.  All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This code is derived from software contributed to Berkeley by
 | 
			
		||||
 * Guido van Rossum.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *    documentation and/or other materials provided with the distribution.
 | 
			
		||||
 * 4. Neither the name of the University nor the names of its contributors
 | 
			
		||||
 *    may be used to endorse or promote products derived from this software
 | 
			
		||||
 *    without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 | 
			
		||||
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 | 
			
		||||
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
			
		||||
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
			
		||||
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
			
		||||
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
			
		||||
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
			
		||||
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
			
		||||
 * SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef CFSTORE_NO_FNMATCH
 | 
			
		||||
#define CFSTORE_NO_FNMATCH
 | 
			
		||||
 | 
			
		||||
#if defined(LIBC_SCCS) && !defined(lint)
 | 
			
		||||
static char sccsid[] = "@(#)cfstore_fnmatch.c	8.2 (Berkeley) 4/16/94";
 | 
			
		||||
#endif /* LIBC_SCCS and not lint */
 | 
			
		||||
 | 
			
		||||
/* In order to support ARM toolchain, this have been removed from the original
 | 
			
		||||
 * cfstore_fnmatch.c from newlib.
 | 
			
		||||
 * #include <sys/cdefs.h>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Function cfstore_fnmatch() as specified in POSIX 1003.2-1992, section B.6.
 | 
			
		||||
 * Compares a filename or pathname to a pattern.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "cfstore_fnmatch.h"
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
 | 
			
		||||
/* code copied from the original cfstore_fnmatch.h */
 | 
			
		||||
 | 
			
		||||
#define	FNM_NOESCAPE	0x01	/* Disable backslash escaping. */
 | 
			
		||||
#define	FNM_PATHNAME	0x02	/* Slash must be matched by slash. */
 | 
			
		||||
#define	FNM_PERIOD	0x04	/* Period must be matched by period. */
 | 
			
		||||
 | 
			
		||||
#define	FNM_LEADING_DIR	0x08	/* Ignore /<tail> after Imatch. */
 | 
			
		||||
#define	FNM_CASEFOLD	0x10	/* Case insensitive search. */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define	EOS	'\0'
 | 
			
		||||
 | 
			
		||||
#define RANGE_MATCH     1
 | 
			
		||||
#define RANGE_NOMATCH   0
 | 
			
		||||
#define RANGE_ERROR     (-1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* In order to support ARM toolchain and simplify the number of newlib posix files used,
 | 
			
		||||
 * this have been copied from collate.c, and the license for this code has been included at the
 | 
			
		||||
 * here:
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
 | 
			
		||||
 *		at Electronni Visti IA, Kiev, Ukraine.
 | 
			
		||||
 *			All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *    documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
 | 
			
		||||
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
 | 
			
		||||
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
			
		||||
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
			
		||||
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
			
		||||
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
			
		||||
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
			
		||||
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
			
		||||
 * SUCH DAMAGE.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
int __collate_load_error = 1;
 | 
			
		||||
 | 
			
		||||
/* In order to support ARM toolchain and simplify the number of newlib posix files used,
 | 
			
		||||
 * the following has been copied from collcmp.c, and the license for this code is
 | 
			
		||||
 * included here:
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 1996 by Andrey A. Chernov, Moscow, Russia.
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *    documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
 | 
			
		||||
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 | 
			
		||||
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
			
		||||
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
			
		||||
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
			
		||||
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
			
		||||
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
			
		||||
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
			
		||||
 * SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Compare two characters converting collate information
 | 
			
		||||
 * into ASCII-compatible range, it allows to handle
 | 
			
		||||
 * "[a-z]"-type ranges with national characters.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static int __collate_range_cmp (int c1, int c2)
 | 
			
		||||
{
 | 
			
		||||
	static char s1[2], s2[2];
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	c1 &= UCHAR_MAX;
 | 
			
		||||
	c2 &= UCHAR_MAX;
 | 
			
		||||
	if (c1 == c2)
 | 
			
		||||
		return (0);
 | 
			
		||||
 | 
			
		||||
	s1[0] = c1;
 | 
			
		||||
	s2[0] = c2;
 | 
			
		||||
	if ((ret = strcoll(s1, s2)) != 0)
 | 
			
		||||
		return (ret);
 | 
			
		||||
	return (c1 - c2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int rangematch(const char *, char, int, char **);
 | 
			
		||||
 | 
			
		||||
int cfstore_fnmatch(const char *pattern, const char *string, int flags)
 | 
			
		||||
{
 | 
			
		||||
	const char *stringstart;
 | 
			
		||||
	char *newp;
 | 
			
		||||
	char c, test;
 | 
			
		||||
 | 
			
		||||
	for (stringstart = string;;)
 | 
			
		||||
		switch (c = *pattern++) {
 | 
			
		||||
		case EOS:
 | 
			
		||||
			if ((flags & FNM_LEADING_DIR) && *string == '/')
 | 
			
		||||
				return (0);
 | 
			
		||||
			return (*string == EOS ? 0 : CFSTORE_FNM_NOMATCH);
 | 
			
		||||
		case '?':
 | 
			
		||||
			if (*string == EOS)
 | 
			
		||||
				return (CFSTORE_FNM_NOMATCH);
 | 
			
		||||
			if (*string == '/' && (flags & FNM_PATHNAME))
 | 
			
		||||
				return (CFSTORE_FNM_NOMATCH);
 | 
			
		||||
			if (*string == '.' && (flags & FNM_PERIOD) &&
 | 
			
		||||
			    (string == stringstart ||
 | 
			
		||||
			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
 | 
			
		||||
				return (CFSTORE_FNM_NOMATCH);
 | 
			
		||||
			++string;
 | 
			
		||||
			break;
 | 
			
		||||
		case '*':
 | 
			
		||||
			c = *pattern;
 | 
			
		||||
			/* Collapse multiple stars. */
 | 
			
		||||
			while (c == '*')
 | 
			
		||||
				c = *++pattern;
 | 
			
		||||
 | 
			
		||||
			if (*string == '.' && (flags & FNM_PERIOD) &&
 | 
			
		||||
			    (string == stringstart ||
 | 
			
		||||
			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
 | 
			
		||||
				return (CFSTORE_FNM_NOMATCH);
 | 
			
		||||
 | 
			
		||||
			/* Optimize for pattern with * at end or before /. */
 | 
			
		||||
			if (c == EOS)
 | 
			
		||||
				if (flags & FNM_PATHNAME)
 | 
			
		||||
					return ((flags & FNM_LEADING_DIR) ||
 | 
			
		||||
					    strchr(string, '/') == NULL ?
 | 
			
		||||
					    0 : CFSTORE_FNM_NOMATCH);
 | 
			
		||||
				else
 | 
			
		||||
					return (0);
 | 
			
		||||
			else if (c == '/' && flags & FNM_PATHNAME) {
 | 
			
		||||
				if ((string = strchr(string, '/')) == NULL)
 | 
			
		||||
					return (CFSTORE_FNM_NOMATCH);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* General case, use recursion. */
 | 
			
		||||
			while ((test = *string) != EOS) {
 | 
			
		||||
				if (!cfstore_fnmatch(pattern, string, flags & ~FNM_PERIOD))
 | 
			
		||||
					return (0);
 | 
			
		||||
				if (test == '/' && flags & FNM_PATHNAME)
 | 
			
		||||
					break;
 | 
			
		||||
				++string;
 | 
			
		||||
			}
 | 
			
		||||
			return (CFSTORE_FNM_NOMATCH);
 | 
			
		||||
		case '[':
 | 
			
		||||
			if (*string == EOS)
 | 
			
		||||
				return (CFSTORE_FNM_NOMATCH);
 | 
			
		||||
			if (*string == '/' && (flags & FNM_PATHNAME))
 | 
			
		||||
				return (CFSTORE_FNM_NOMATCH);
 | 
			
		||||
			if (*string == '.' && (flags & FNM_PERIOD) &&
 | 
			
		||||
			    (string == stringstart ||
 | 
			
		||||
			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
 | 
			
		||||
				return (CFSTORE_FNM_NOMATCH);
 | 
			
		||||
 | 
			
		||||
			switch (rangematch(pattern, *string, flags, &newp)) {
 | 
			
		||||
			case RANGE_ERROR:
 | 
			
		||||
				goto norm;
 | 
			
		||||
			case RANGE_MATCH:
 | 
			
		||||
				pattern = newp;
 | 
			
		||||
				break;
 | 
			
		||||
			case RANGE_NOMATCH:
 | 
			
		||||
				return (CFSTORE_FNM_NOMATCH);
 | 
			
		||||
			}
 | 
			
		||||
			++string;
 | 
			
		||||
			break;
 | 
			
		||||
		case '\\':
 | 
			
		||||
			if (!(flags & FNM_NOESCAPE)) {
 | 
			
		||||
				if ((c = *pattern++) == EOS) {
 | 
			
		||||
					c = '\\';
 | 
			
		||||
					--pattern;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			/* FALLTHROUGH */
 | 
			
		||||
		default:
 | 
			
		||||
		norm:
 | 
			
		||||
			if (c == *string)
 | 
			
		||||
				;
 | 
			
		||||
			else if ((flags & FNM_CASEFOLD) &&
 | 
			
		||||
				 (tolower((unsigned char)c) ==
 | 
			
		||||
				  tolower((unsigned char)*string)))
 | 
			
		||||
				;
 | 
			
		||||
			else
 | 
			
		||||
				return (CFSTORE_FNM_NOMATCH);
 | 
			
		||||
			string++;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	/* NOTREACHED */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
rangematch(const char *pattern, char test, int flags, char **newp)
 | 
			
		||||
{
 | 
			
		||||
	int negate, ok;
 | 
			
		||||
	char c, c2;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * A bracket expression starting with an unquoted circumflex
 | 
			
		||||
	 * character produces unspecified results (IEEE 1003.2-1992,
 | 
			
		||||
	 * 3.13.2).  This implementation treats it like '!', for
 | 
			
		||||
	 * consistency with the regular expression syntax.
 | 
			
		||||
	 * J.T. Conklin (conklin@ngai.kaleida.com)
 | 
			
		||||
	 */
 | 
			
		||||
	negate = (*pattern == '!' || *pattern == '^');
 | 
			
		||||
	if ( negate )
 | 
			
		||||
		++pattern;
 | 
			
		||||
 | 
			
		||||
	if (flags & FNM_CASEFOLD)
 | 
			
		||||
		test = tolower((unsigned char)test);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * A right bracket shall lose its special meaning and represent
 | 
			
		||||
	 * itself in a bracket expression if it occurs first in the list.
 | 
			
		||||
	 * -- POSIX.2 2.8.3.2
 | 
			
		||||
	 */
 | 
			
		||||
	ok = 0;
 | 
			
		||||
	c = *pattern++;
 | 
			
		||||
	do {
 | 
			
		||||
		if (c == '\\' && !(flags & FNM_NOESCAPE))
 | 
			
		||||
			c = *pattern++;
 | 
			
		||||
		if (c == EOS)
 | 
			
		||||
			return (RANGE_ERROR);
 | 
			
		||||
 | 
			
		||||
		if (c == '/' && (flags & FNM_PATHNAME))
 | 
			
		||||
			return (RANGE_NOMATCH);
 | 
			
		||||
 | 
			
		||||
		if (flags & FNM_CASEFOLD)
 | 
			
		||||
			c = tolower((unsigned char)c);
 | 
			
		||||
 | 
			
		||||
		if (*pattern == '-'
 | 
			
		||||
		    && (c2 = *(pattern+1)) != EOS && c2 != ']') {
 | 
			
		||||
			pattern += 2;
 | 
			
		||||
			if (c2 == '\\' && !(flags & FNM_NOESCAPE))
 | 
			
		||||
				c2 = *pattern++;
 | 
			
		||||
			if (c2 == EOS)
 | 
			
		||||
				return (RANGE_ERROR);
 | 
			
		||||
 | 
			
		||||
			if (flags & FNM_CASEFOLD)
 | 
			
		||||
				c2 = tolower((unsigned char)c2);
 | 
			
		||||
 | 
			
		||||
			if (__collate_load_error ?
 | 
			
		||||
			    c <= test && test <= c2 :
 | 
			
		||||
			       __collate_range_cmp(c, test) <= 0
 | 
			
		||||
			    && __collate_range_cmp(test, c2) <= 0
 | 
			
		||||
			   )
 | 
			
		||||
				ok = 1;
 | 
			
		||||
		} else if (c == test)
 | 
			
		||||
			ok = 1;
 | 
			
		||||
	} while ((c = *pattern++) != ']');
 | 
			
		||||
 | 
			
		||||
	*newp = (char *)pattern;
 | 
			
		||||
	return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* CFSTORE_NO_FNMATCH  */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,40 @@
 | 
			
		|||
/*-
 | 
			
		||||
 * Copyright (c) 1992, 1993
 | 
			
		||||
 *	The Regents of the University of California.  All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *    documentation and/or other materials provided with the distribution.
 | 
			
		||||
 * 4. Neither the name of the University nor the names of its contributors
 | 
			
		||||
 *    may be used to endorse or promote products derived from this software
 | 
			
		||||
 *    without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 | 
			
		||||
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 | 
			
		||||
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
			
		||||
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
			
		||||
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
			
		||||
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
			
		||||
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
			
		||||
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
			
		||||
 * SUCH DAMAGE.
 | 
			
		||||
 *
 | 
			
		||||
 * $FreeBSD: src/include/fnmatch.h,v 1.10 2002/03/23 17:24:53 imp Exp $
 | 
			
		||||
 *	@(#)fnmatch.h	8.1 (Berkeley) 6/2/93
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef	__CFSTORE_FNMATCH_H_
 | 
			
		||||
#define	__CFSTORE_FNMATCH_H_
 | 
			
		||||
 | 
			
		||||
#define	CFSTORE_FNM_NOMATCH	1	/* Match failed. */
 | 
			
		||||
 | 
			
		||||
int	 cfstore_fnmatch(const char *, const char *, int);
 | 
			
		||||
 | 
			
		||||
#endif /* !__CFSTORE_FNMATCH_H_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,65 @@
 | 
			
		|||
/** @file cfstore_list.h
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef _CFSTORE_LIST_H_
 | 
			
		||||
#define _CFSTORE_LIST_H_
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Doubly linked list implementation based on the following design
 | 
			
		||||
 * and psuedo-code:
 | 
			
		||||
 *  Introduction to Algorithms, TH Cormen, CE Leiserson, Rl Rivest,
 | 
			
		||||
 *  ISBN 0-262-03141-8 (1989), Pages 206-207.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct cfstore_list_node_t
 | 
			
		||||
{
 | 
			
		||||
    struct cfstore_list_node_t *next;
 | 
			
		||||
    struct cfstore_list_node_t *prev;
 | 
			
		||||
} cfstore_list_node_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_ZERO_NODE(_node_cFStOrE)            \
 | 
			
		||||
    do{                                             \
 | 
			
		||||
        (_node_cFStOrE)->next=NULL;                 \
 | 
			
		||||
        (_node_cFStOrE)->prev=NULL;                 \
 | 
			
		||||
    }while(0)
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_INIT_LIST_HEAD(_node_cFStOrE)       \
 | 
			
		||||
    do {                                            \
 | 
			
		||||
        (_node_cFStOrE)->next = (_node_cFStOrE);    \
 | 
			
		||||
        (_node_cFStOrE)->prev = (_node_cFStOrE);    \
 | 
			
		||||
    } while (0)
 | 
			
		||||
 | 
			
		||||
/* brief insert the new_node between 2 other nodes, the one before being node_before, the one after being node_after */
 | 
			
		||||
static inline void cfstore_listAdd(cfstore_list_node_t* node_before, cfstore_list_node_t * new_node, cfstore_list_node_t* node_after)
 | 
			
		||||
{
 | 
			
		||||
    /* init new node before insertion */
 | 
			
		||||
    new_node->next = node_after;
 | 
			
		||||
    new_node->prev = node_before;
 | 
			
		||||
    node_before->next = new_node;
 | 
			
		||||
    node_after->prev = new_node;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* brief remove the node D from the list by making the nodes before and after D point to each other */
 | 
			
		||||
static inline void cfstore_listDel(cfstore_list_node_t *node)
 | 
			
		||||
{
 | 
			
		||||
    node->prev->next = node->next;
 | 
			
		||||
    node->next->prev = node->prev;
 | 
			
		||||
    CFSTORE_ZERO_NODE(node);
 | 
			
		||||
}
 | 
			
		||||
#endif /* _CFSTORE_LIST_H_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,738 @@
 | 
			
		|||
/* @file cfstore_test.c
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * test support code implementation file.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "cfstore_config.h"
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
 | 
			
		||||
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
#include "flash_journal_strategy_sequential.h"
 | 
			
		||||
#include "flash_journal.h"
 | 
			
		||||
#include "Driver_Common.h"
 | 
			
		||||
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ruler for measuring text strings */
 | 
			
		||||
/*                                                                                                    1         1         1         1         1         1         1         1         1         1         2         2         2 */
 | 
			
		||||
/* 0        1         2         3         4         5         6         7         8         9         0         1         2         3         4         5         6         7         8         9         0         1         2 */
 | 
			
		||||
/* 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 */
 | 
			
		||||
 | 
			
		||||
const uint8_t cfstore_test_byte_data_table[CFSTORE_TEST_BYTE_DATA_TABLE_SIZE] = {
 | 
			
		||||
    0x2d, 0xf3, 0x31, 0x4c, 0x11, 0x4f, 0xde, 0x0d, 0xbd, 0xbc, 0xa6, 0x78, 0x36, 0x5c, 0x1d, 0x28,
 | 
			
		||||
    0x5f, 0xa9, 0x10, 0x65, 0x54, 0x45, 0x21, 0x1a, 0x88, 0xfe, 0x76, 0x45, 0xb9, 0xac, 0x65, 0x9a,
 | 
			
		||||
    0x34, 0x9d, 0x73, 0x10, 0xb4, 0xa9, 0x2e, 0x90, 0x95, 0x68, 0xac, 0xfe, 0xc5, 0x2d, 0x15, 0x03,
 | 
			
		||||
    0x34, 0x70, 0xf1, 0x1d, 0x48, 0xa1, 0xa0, 0xed, 0x5c, 0x2f, 0xf5, 0x2b, 0xb9, 0x84, 0xbb, 0x45,
 | 
			
		||||
    0x32, 0xdd, 0xb1, 0x33, 0x95, 0x2a, 0xbc, 0x26, 0xf0, 0x89, 0xba, 0xf4, 0xbd, 0xf9, 0x5d, 0x2e,
 | 
			
		||||
    0x6e, 0x11, 0xc6, 0xa7, 0x78, 0xfc, 0xc9, 0x0e, 0x6b, 0x38, 0xba, 0x14, 0x1b, 0xab, 0x4c, 0x20,
 | 
			
		||||
    0x91, 0xe4, 0xb0, 0xf1, 0x2b, 0x14, 0x07, 0x6b, 0xb5, 0xcd, 0xe3, 0x49, 0x75, 0xac, 0xe8, 0x98,
 | 
			
		||||
    0xf1, 0x58, 0x8f, 0xd9, 0xc4, 0x8f, 0x00, 0x17, 0xb5, 0x06, 0x6a, 0x33, 0xbd, 0xa7, 0x40, 0x5a,
 | 
			
		||||
    0xbf, 0x49, 0xf7, 0x27, 0x1b, 0x4c, 0x3e, 0x6f, 0xe3, 0x08, 0x1f, 0xfd, 0xa6, 0xd4, 0xc7, 0x5f,
 | 
			
		||||
    0xa4, 0xa6, 0x82, 0xad, 0x19, 0xd5, 0x5c, 0xd8, 0x3a, 0x49, 0x85, 0xc9, 0x21, 0x83, 0xf6, 0xc6,
 | 
			
		||||
    0x84, 0xf9, 0x76, 0x89, 0xf3, 0x2d, 0x17, 0x50, 0x97, 0x38, 0x48, 0x9a, 0xe1, 0x82, 0xcd, 0xac,
 | 
			
		||||
    0xa8, 0x1d, 0xd7, 0x96, 0x5e, 0xb3, 0x08, 0xa8, 0x3a, 0xc7, 0x2b, 0x05, 0xaf, 0xdc, 0x16, 0xdf,
 | 
			
		||||
    0x48, 0x0f, 0x2a, 0x7e, 0x3a, 0x82, 0xd7, 0x80, 0xd6, 0x49, 0x27, 0x5d, 0xe3, 0x07, 0x62, 0xb3,
 | 
			
		||||
    0xc3, 0x6c, 0xba, 0xb2, 0xaa, 0x9f, 0xd9, 0x03, 0x0d, 0x27, 0xa8, 0xe0, 0xd6, 0xee, 0x79, 0x4b,
 | 
			
		||||
    0xd6, 0x97, 0x99, 0xb7, 0x11, 0xd6, 0x0d, 0x34, 0xae, 0x99, 0x4a, 0x93, 0x95, 0xd0, 0x5a, 0x34,
 | 
			
		||||
    0x19, 0xa2, 0x69, 0x57, 0xcf, 0x7c, 0x3d, 0x98, 0x88, 0x5d, 0x04, 0xf2, 0xd7, 0xac, 0xa5, 0x63
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   set of test data for sequential write tests */
 | 
			
		||||
cfstore_test_rw_data_entry_t cfstore_test_rw_data_table[] =
 | 
			
		||||
{
 | 
			
		||||
        { 25, 'z' },
 | 
			
		||||
        { 00, 'a' },
 | 
			
		||||
        { 24, 'y' },
 | 
			
		||||
        { 01, 'b' },
 | 
			
		||||
        { 23, 'x' },
 | 
			
		||||
        { 02, 'c' },
 | 
			
		||||
        { 22, 'w' },
 | 
			
		||||
        { 03, 'd' },
 | 
			
		||||
        { 21, 'v' },
 | 
			
		||||
        { 04, 'e' },
 | 
			
		||||
        { 20, 'u' },
 | 
			
		||||
        { 05, 'f' },
 | 
			
		||||
        { 19, 't' },
 | 
			
		||||
        { 06, 'g' },
 | 
			
		||||
        { 18, 's' },
 | 
			
		||||
        { 07, 'h' },
 | 
			
		||||
        { 17, 'r' },
 | 
			
		||||
        {  8, 'i' },
 | 
			
		||||
        { 16, 'q' },
 | 
			
		||||
        {  9, 'j' },
 | 
			
		||||
        { 15, 'p' },
 | 
			
		||||
        { 10, 'k' },
 | 
			
		||||
        { 14, 'o' },
 | 
			
		||||
        { 11, 'l' },
 | 
			
		||||
        { 13, 'n' },
 | 
			
		||||
        { 12, 'm' },
 | 
			
		||||
        { CFSTORE_TEST_RW_TABLE_SENTINEL, '@' },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const char* cfstore_test_opcode_str[] =
 | 
			
		||||
{
 | 
			
		||||
    "UNDEFINED",
 | 
			
		||||
    "CFSTORE_OPCODE_CLOSE",
 | 
			
		||||
    "CFSTORE_OPCODE_CREATE",
 | 
			
		||||
    "CFSTORE_OPCODE_DELETE",
 | 
			
		||||
    "CFSTORE_OPCODE_FIND",
 | 
			
		||||
    "CFSTORE_OPCODE_FLUSH",
 | 
			
		||||
    "CFSTORE_OPCODE_GET_KEY_NAME",
 | 
			
		||||
    "CFSTORE_OPCODE_GET_STATUS",
 | 
			
		||||
    "CFSTORE_OPCODE_GET_VALUE_LEN",
 | 
			
		||||
    "CFSTORE_OPCODE_INITIALIZE",
 | 
			
		||||
    "CFSTORE_OPCODE_OPEN",
 | 
			
		||||
    "CFSTORE_OPCODE_POWER_CONTROL",
 | 
			
		||||
    "CFSTORE_OPCODE_READ",
 | 
			
		||||
    "CFSTORE_OPCODE_RSEEK",
 | 
			
		||||
    "CFSTORE_OPCODE_UNINITIALIZE",
 | 
			
		||||
    "CFSTORE_OPCODE_WRITE",
 | 
			
		||||
    "CFSTORE_OPCODE_MAX"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int32_t cfstore_test_dump_print_array(const char* data, ARM_CFSTORE_SIZE len)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    char buf[80];
 | 
			
		||||
    char sbuf[80];
 | 
			
		||||
    char* outbuf = buf;
 | 
			
		||||
    char* soutbuf = sbuf;
 | 
			
		||||
 | 
			
		||||
    memset(outbuf, 0, 80);
 | 
			
		||||
    memset(soutbuf, 0, 80);
 | 
			
		||||
    outbuf += sprintf(outbuf, "      ");
 | 
			
		||||
    soutbuf += sprintf(soutbuf, "      ");
 | 
			
		||||
    for (i = 0; i < (int) len; i++){
 | 
			
		||||
        outbuf += sprintf(outbuf, "%02X ", data[i]);
 | 
			
		||||
 | 
			
		||||
        if( !(isalnum( (int) data[i]) || ispunct( (int) data[i])) ){
 | 
			
		||||
            *soutbuf++ =  '*';
 | 
			
		||||
        } else {
 | 
			
		||||
            *soutbuf++ = data[i];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if( (i % 16 == 0) && i > 0){
 | 
			
		||||
            CFSTORE_LOG("%s", buf);
 | 
			
		||||
            CFSTORE_LOG("%s\n", sbuf);
 | 
			
		||||
            outbuf = buf;
 | 
			
		||||
            soutbuf = sbuf;
 | 
			
		||||
            memset(outbuf, 0, 80);
 | 
			
		||||
            memset(soutbuf, 0, 80);
 | 
			
		||||
            outbuf += sprintf(outbuf, "      ");
 | 
			
		||||
            soutbuf += sprintf(soutbuf, "      ");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if(i % 16){
 | 
			
		||||
        /* Pad the end of the string to align string data. */
 | 
			
		||||
        while(i % 16){
 | 
			
		||||
            outbuf += sprintf(outbuf, "   ");
 | 
			
		||||
            i++;
 | 
			
		||||
        }
 | 
			
		||||
        CFSTORE_LOG("%s", buf);
 | 
			
		||||
        CFSTORE_LOG("      %s", sbuf);
 | 
			
		||||
    }
 | 
			
		||||
    CFSTORE_LOG("%s", "\n");
 | 
			
		||||
    return ARM_DRIVER_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   function to dump contents of cfstore
 | 
			
		||||
 */
 | 
			
		||||
int32_t cfstore_test_dump(void)
 | 
			
		||||
{
 | 
			
		||||
    const char* key_name_query = "*";
 | 
			
		||||
    char* read_buf = NULL;
 | 
			
		||||
    char key_name[CFSTORE_KEY_NAME_MAX_LENGTH+1];
 | 
			
		||||
    uint8_t len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
 | 
			
		||||
    ARM_CFSTORE_SIZE vlen = 0;
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(next);
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(prev);
 | 
			
		||||
    ARM_CFSTORE_CAPABILITIES caps = cfstore_driver.GetCapabilities();
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_LOG("CFSTORE Flash Entries%s", "\n");
 | 
			
		||||
    CFSTORE_LOG("=====================%s", "\n\n");
 | 
			
		||||
    while((ret = drv->Find(key_name_query, prev, next)) == ARM_DRIVER_OK)
 | 
			
		||||
    {
 | 
			
		||||
        len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
 | 
			
		||||
        ret = drv->GetKeyName(next, key_name, &len);
 | 
			
		||||
        if(ret < ARM_DRIVER_OK){
 | 
			
		||||
            CFSTORE_ERRLOG("Error: failed to get key name%s", "\n");
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        ret = drv->GetValueLen(next, &vlen);
 | 
			
		||||
        if(ret < ARM_DRIVER_OK){
 | 
			
		||||
            CFSTORE_ERRLOG("Error: failed to get value length%s", "\n");
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        read_buf = (char*) malloc(vlen+1);
 | 
			
		||||
        if(read_buf == NULL){
 | 
			
		||||
            CFSTORE_ERRLOG("Error: failed to malloc() read buffer%s", "\n");
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        ret = drv->Read(next, read_buf, &vlen);
 | 
			
		||||
        if(ret < ARM_DRIVER_OK){
 | 
			
		||||
            CFSTORE_ERRLOG("Error: failed to read key value%s", "\n");
 | 
			
		||||
            free(read_buf);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        CFSTORE_LOG("  keyname : %s\n", key_name);
 | 
			
		||||
        CFSTORE_LOG("    name len : %d\n", (int) len);
 | 
			
		||||
        CFSTORE_LOG("    value len : %d\n", (int) vlen);
 | 
			
		||||
        CFSTORE_LOG("    data :%s", "\n");
 | 
			
		||||
        cfstore_test_dump_print_array((const char*) read_buf, vlen);
 | 
			
		||||
        CFSTORE_LOG("%s", ".\n");
 | 
			
		||||
        free(read_buf);
 | 
			
		||||
        CFSTORE_HANDLE_SWAP(prev, next);
 | 
			
		||||
    }
 | 
			
		||||
    CFSTORE_LOG("%s", ".\n");
 | 
			
		||||
    CFSTORE_LOG("  caps.asynchronous_ops : %d\n", (int) caps.asynchronous_ops);
 | 
			
		||||
    CFSTORE_LOG("%s", ".\n");
 | 
			
		||||
    CFSTORE_LOG("== End ==============%s", "\n\n");
 | 
			
		||||
 | 
			
		||||
    if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND) {
 | 
			
		||||
        /* As expected, no more keys have been found by the Find(). */
 | 
			
		||||
        ret = ARM_DRIVER_OK;
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   test startup code to reset flash
 | 
			
		||||
 */
 | 
			
		||||
int32_t cfstore_test_startup(void)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* cfstore_drv = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_CAPABILITIES caps = cfstore_driver.GetCapabilities();
 | 
			
		||||
 | 
			
		||||
    CFSTORE_LOG("INITIALIZING: caps.asynchronous_ops=%d\n", (int) caps.asynchronous_ops);
 | 
			
		||||
 | 
			
		||||
    /* Dump contents of CFSTORE */
 | 
			
		||||
    ret = cfstore_drv->Initialize(NULL, NULL);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: failed to initialize CFSTORE (ret=%d)\n", __func__, (int) ret);
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    ret = cfstore_test_dump();
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: failed to dump CFSTORE (ret=%d)\n", __func__, (int) ret);
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    ret = cfstore_drv->Uninitialize();
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: failed to uninitialize CFSTORE (ret=%d)\n", __func__, (int) ret);
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
 | 
			
		||||
 | 
			
		||||
    FlashJournal_t jrnl;
 | 
			
		||||
    extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0);
 | 
			
		||||
    const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_(0);
 | 
			
		||||
 | 
			
		||||
    ret = FlashJournal_initialize(&jrnl, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, NULL);
 | 
			
		||||
    if(ret < JOURNAL_STATUS_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: failed to initialize flash journaling layer (ret=%d)\n", __func__, (int) ret);
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    ret = FlashJournal_reset(&jrnl);
 | 
			
		||||
    if(ret < JOURNAL_STATUS_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: failed to reset flash journal (ret=%d)\n", __func__, (int) ret);
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#endif /*  CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
 | 
			
		||||
 | 
			
		||||
    return ARM_DRIVER_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   test utility function to check a node appears correctly in the cfstore
 | 
			
		||||
 * @note    this function expects cfstore to have been initialised with
 | 
			
		||||
 *          a call to ARM_CFSTORE_DRIVER::Initialize()
 | 
			
		||||
 */
 | 
			
		||||
int32_t cfstore_test_check_node_correct(const cfstore_kv_data_t* node)
 | 
			
		||||
{
 | 
			
		||||
    char* read_buf;
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_SIZE len = 0;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\r\n", __func__);
 | 
			
		||||
    memset(&flags, 0, sizeof(flags));
 | 
			
		||||
 | 
			
		||||
    ret = drv->Open(node->key_name, flags, hkey);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: failed to open node (key_name=\"%s\", value=\"%s\")(ret=%d)\r\n", __func__, node->key_name, node->value, (int) ret);
 | 
			
		||||
        goto out0;
 | 
			
		||||
    }
 | 
			
		||||
    len = strlen(node->value) + 1;
 | 
			
		||||
    read_buf = (char*) malloc(len);
 | 
			
		||||
    if(read_buf == NULL) {
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: failed to allocated read buffer \r\n", __func__);
 | 
			
		||||
        goto out1;
 | 
			
		||||
    }
 | 
			
		||||
    memset(read_buf, 0, len);
 | 
			
		||||
    ret = drv->Read(hkey, read_buf, &len);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: failed to write key (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value);
 | 
			
		||||
        goto out2;
 | 
			
		||||
    }
 | 
			
		||||
    /* check read data is as expected */
 | 
			
		||||
    if(strncmp(read_buf, node->value, strlen(node->value)) != 0){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: read value data (%s) != KV value data (key_name=\"%s\", value=\"%s\")\r\n", __func__, read_buf, node->key_name, node->value);
 | 
			
		||||
        ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
out2:
 | 
			
		||||
    if(read_buf) free(read_buf);
 | 
			
		||||
out1:
 | 
			
		||||
    drv->Close(hkey);
 | 
			
		||||
    hkey = NULL;
 | 
			
		||||
out0:
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief  test utility function to delete the cfstore key identified by key_name
 | 
			
		||||
 * @note    this function expects cfstore to have been initialised with
 | 
			
		||||
 *          a call to ARM_CFSTORE_DRIVER::Initialize()
 | 
			
		||||
 */
 | 
			
		||||
int32_t cfstore_test_delete(const char* key_name)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered.\r\n", __func__);
 | 
			
		||||
    memset(&flags, 0, sizeof(flags));
 | 
			
		||||
    ret = drv->Open(key_name, flags, hkey);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    if(hkey != NULL){
 | 
			
		||||
        ret = drv->Delete(hkey);
 | 
			
		||||
        drv->Close(hkey);
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* @brief   test utility function to delete all of the KVs in the cfstore
 | 
			
		||||
 * @note    this function expects cfstore to have been initialised with
 | 
			
		||||
 *          a call to ARM_CFSTORE_DRIVER::Initialize()
 | 
			
		||||
 */
 | 
			
		||||
int32_t cfstore_test_delete_all(void)
 | 
			
		||||
{
 | 
			
		||||
    const char* key_name_query = "*";
 | 
			
		||||
    char key_name[CFSTORE_KEY_NAME_MAX_LENGTH+1];
 | 
			
		||||
    uint8_t len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(next);
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(prev);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered.\r\n", __func__);
 | 
			
		||||
    while((ret = drv->Find(key_name_query, prev, next)) == ARM_DRIVER_OK)
 | 
			
		||||
    {
 | 
			
		||||
        len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
 | 
			
		||||
        drv->GetKeyName(next, key_name, &len);
 | 
			
		||||
        CFSTORE_TP(CFSTORE_TP_DELETE, "%s:deleting key_name=%s, len=%d\r\n", __func__, key_name, (int) len);
 | 
			
		||||
        ret = drv->Delete(next);
 | 
			
		||||
        if(ret < ARM_DRIVER_OK){
 | 
			
		||||
            CFSTORE_ERRLOG("%s:Error: failed to delete key_name=%s, len=%d\r\n", __func__, key_name, (int) len);
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
        CFSTORE_HANDLE_SWAP(prev, next);
 | 
			
		||||
    }
 | 
			
		||||
    if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND) {
 | 
			
		||||
        /* as expected, no more keys have been found by the Find()*/
 | 
			
		||||
        ret = ARM_DRIVER_OK;
 | 
			
		||||
    }
 | 
			
		||||
    // todo: find portable format specification CFSTORE_FENTRYLOG("%s:exiting (ret=%ld).\r\n", __func__, ret);
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:exiting (ret=%d).\r\n", __func__, (int) ret);
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   test utility function to create a KV in the cfstore
 | 
			
		||||
 * @note    this function expects cfstore to have been initialised with
 | 
			
		||||
 *          a call to ARM_CFSTORE_DRIVER::Initialize()
 | 
			
		||||
 */
 | 
			
		||||
int32_t cfstore_test_create(const char* key_name, const char* data, ARM_CFSTORE_SIZE* len, ARM_CFSTORE_KEYDESC* kdesc)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_SIZE value_len = 0;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered.\r\n", __func__);
 | 
			
		||||
    value_len = *len;
 | 
			
		||||
    kdesc->drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE;
 | 
			
		||||
    ret = drv->Create(key_name, value_len, kdesc, hkey);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    value_len = *len;
 | 
			
		||||
    ret = drv->Write(hkey, data, &value_len);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        drv->Close(hkey);
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    if(value_len != *len){
 | 
			
		||||
        drv->Close(hkey);
 | 
			
		||||
        return ARM_DRIVER_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    drv->Close(hkey);
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* @brief   test utility function to create KVs from the supplied table
 | 
			
		||||
 * @note    this function expects cfstore to have been initialised with
 | 
			
		||||
 *          a call to ARM_CFSTORE_DRIVER::Initialize()
 | 
			
		||||
 */
 | 
			
		||||
int32_t cfstore_test_create_table(const cfstore_kv_data_t* table)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_SIZE len = 0;
 | 
			
		||||
    cfstore_kv_data_t* node = NULL;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
 | 
			
		||||
    (void) node; /* suppresses warning when building release */
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered.\r\n", __func__);
 | 
			
		||||
    memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
    kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE;
 | 
			
		||||
    while(table->key_name != NULL)
 | 
			
		||||
    {
 | 
			
		||||
        len = strlen(table->value);
 | 
			
		||||
        ret = cfstore_test_create(table->key_name, table->value, &len, &kdesc);
 | 
			
		||||
        if(ret < ARM_DRIVER_OK){
 | 
			
		||||
            CFSTORE_ERRLOG("%s:Error: failed to create node (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value);
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
        table++;
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
cfstore_kv_data_t cfstore_test_init_1_data[] = {
 | 
			
		||||
        CFSTORE_INIT_1_TABLE_HEAD,
 | 
			
		||||
        { "b", "1"},
 | 
			
		||||
        { "c", "12"},
 | 
			
		||||
        { "d", "123"},
 | 
			
		||||
        { "e", "1234"},
 | 
			
		||||
        { "g", "12345"},
 | 
			
		||||
        { "h", "123456"},
 | 
			
		||||
        { "i", "1234567"},
 | 
			
		||||
        { "j", "12345678"},
 | 
			
		||||
        { "k", "123456789"},
 | 
			
		||||
        { "l", "1234567890"},
 | 
			
		||||
        { "m", "12345678901"},
 | 
			
		||||
        { "n", "123456789012"},
 | 
			
		||||
        { "o", "1234567890123"},
 | 
			
		||||
        { "p", "12345678901234"},
 | 
			
		||||
        { "q", "123456789012345"},
 | 
			
		||||
        { "r", "1234567890123456"},
 | 
			
		||||
        { "0", "a"},
 | 
			
		||||
        { "01", "ab"},
 | 
			
		||||
        { "012", "abc"},
 | 
			
		||||
        { "0123", "abcd"},
 | 
			
		||||
        { "01234", "abcde"},
 | 
			
		||||
        { "012345", "abcdef"},
 | 
			
		||||
        { "0123456", "abcdefg"},
 | 
			
		||||
        { "01234567", "abcdefgh"},
 | 
			
		||||
        { "012345678", "abcdefghi"},
 | 
			
		||||
        { "0123456789", "abcdefghj"},
 | 
			
		||||
        { "0123456789a", "abcdefghjk"},
 | 
			
		||||
        { "0123456789ab", "abcdefghjkl"},
 | 
			
		||||
        { "0123456789abc", "abcdefghjklm"},
 | 
			
		||||
        { "0123456789abcd", "abcdefghjklmn"},
 | 
			
		||||
        { "0123456789abcde", "abcdefghjklmno"},
 | 
			
		||||
        { "0123456789abcdef", "abcdefghjklmnop"},
 | 
			
		||||
        { "0123456789abcdef0", "abcdefghjklmnopq"},
 | 
			
		||||
        { "0123456789abcdef01", "abcdefghjklmnopqr"},
 | 
			
		||||
        { "0123456789abcdef012", "abcdefghjklmnopqrs"},
 | 
			
		||||
        { "0123456789abcdef0123", "abcdefghjklmnopqrst"},
 | 
			
		||||
        { "0123456789abcdef01234", "abcdefghjklmnopqrstu"},
 | 
			
		||||
        { "0123456789abcdef012345", "abcdefghjklmnopqrstuv"},
 | 
			
		||||
        CFSTORE_INIT_1_TABLE_MID_NODE,
 | 
			
		||||
        { "0123456789abcdef01234567", "abcdefghjklmnopqrstuvwx"},
 | 
			
		||||
        { "0123456789abcdef012345678", "abcdefghjklmnopqrstuvwxy"},
 | 
			
		||||
        { "0123456789abcdef0123456789", "abcdefghjklmnopqrstuvwxyz"},
 | 
			
		||||
        { "0123456789abcdef0123456789a", "b"},
 | 
			
		||||
        { "0123456789abcdef0123456789ab", "c"},
 | 
			
		||||
        { "0123456789abcdef0123456789abc", "d"},
 | 
			
		||||
        { "0123456789abcdef0123456789abcd", "e"},
 | 
			
		||||
        { "0123456789abcdef0123456789abcde", "f"},
 | 
			
		||||
        { "0123456789abcdef0123456789abcdef", "g"},
 | 
			
		||||
        { "com.arm.mbed.wifi.accesspoint.essid", ""},
 | 
			
		||||
        { "com.arm.mbed.wifi.accesspoint.essid2", ""},
 | 
			
		||||
        { "yotta.your-yotta-registry-module-name.module1", ""},
 | 
			
		||||
        { "yotta.hello-world.animal{wobbly-dog}{foot}frontLeft", "missing"},
 | 
			
		||||
        { "yotta.hello-world.animal{wobbly-dog}{foot}frontRight", "present"},
 | 
			
		||||
        { "yotta.hello-world.animal{wobbly-dog}{foot}backLeft", "half present"},
 | 
			
		||||
        { "piety.demands.us.to.honour.truth.above.our.friends", "Aristotle"},
 | 
			
		||||
        { "basement.medicine.pavement.government.trenchcoat.off.cough.off.kid.did.when.again.alleyway.friend.cap.pen.dollarbills.ten.foot.soot.put.but.anyway.say.May.DA.kid.did.toes.bows.those.hose.nose.clothes.man.blows.well.well", "TheRollingStone" },
 | 
			
		||||
        CFSTORE_INIT_1_TABLE_TAIL,
 | 
			
		||||
        { NULL, NULL},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   utility test function to initialise cfstore sram area with some
 | 
			
		||||
 *          KV's to manipulate
 | 
			
		||||
 * @note    this function expects cfstore to have been initialised with
 | 
			
		||||
 *          a call to ARM_CFSTORE_DRIVER::Initialize()
 | 
			
		||||
 */
 | 
			
		||||
int32_t cfstore_test_init_1(void)
 | 
			
		||||
{
 | 
			
		||||
    char* read_buf = NULL;
 | 
			
		||||
    const uint8_t key_name_max_len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
 | 
			
		||||
    uint8_t key_name_len = 0;
 | 
			
		||||
    char key_name_buf[CFSTORE_KEY_NAME_MAX_LENGTH+1];
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_SIZE len = 0;
 | 
			
		||||
    ARM_CFSTORE_SIZE max_len = 0;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    cfstore_kv_data_t* node = NULL;
 | 
			
		||||
    ARM_CFSTORE_KEYDESC kdesc;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\r\n", __func__);
 | 
			
		||||
    memset(&kdesc, 0, sizeof(kdesc));
 | 
			
		||||
    memset(key_name_buf, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1);
 | 
			
		||||
 | 
			
		||||
    /*scan for max length of value blob*/
 | 
			
		||||
    node = cfstore_test_init_1_data;
 | 
			
		||||
    while(node->key_name != NULL)
 | 
			
		||||
    {
 | 
			
		||||
        len = strlen(node->value);
 | 
			
		||||
        if(len > max_len){
 | 
			
		||||
            max_len = len;
 | 
			
		||||
            max_len++;
 | 
			
		||||
        }
 | 
			
		||||
        node++;
 | 
			
		||||
    }
 | 
			
		||||
    read_buf = (char*) malloc(max_len);
 | 
			
		||||
    if(read_buf == NULL) {
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: failed to allocated read buffer \r\n", __func__);
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE;
 | 
			
		||||
    node = cfstore_test_init_1_data;
 | 
			
		||||
    while(node->key_name != NULL)
 | 
			
		||||
    {
 | 
			
		||||
        CFSTORE_DBGLOG("%s:About to create new node (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value);
 | 
			
		||||
        ret = drv->Create(node->key_name, strlen(node->value), &kdesc, hkey);
 | 
			
		||||
        if(ret < ARM_DRIVER_OK){
 | 
			
		||||
            CFSTORE_ERRLOG("%s:Error: failed to create node (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value);
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        CFSTORE_DBGLOG("%s:length of KV=%d (key_name=\"%s\", value=\"%s\")\r\n", __func__, (int) len, node->key_name, node->value);
 | 
			
		||||
        len = strlen(node->value);
 | 
			
		||||
        ret = drv->Write(hkey, (char*) node->value, &len);
 | 
			
		||||
        if(ret < ARM_DRIVER_OK){
 | 
			
		||||
            CFSTORE_ERRLOG("%s:Error: failed to write key (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value);
 | 
			
		||||
            drv->Close(hkey);
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
        if(len != strlen(node->value)){
 | 
			
		||||
            CFSTORE_ERRLOG("%s:Error: failed to write full value data (key_name=\"%s\", value=\"%s\"), len=%d\r\n", __func__, node->key_name, node->value, (int) len);
 | 
			
		||||
            drv->Close(hkey);
 | 
			
		||||
            return ARM_DRIVER_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
        /* read the data back*/
 | 
			
		||||
        len = strlen(node->value);
 | 
			
		||||
        memset(read_buf, 0, max_len);
 | 
			
		||||
        ret = drv->Read(hkey, read_buf, &len);
 | 
			
		||||
        if(ret < ARM_DRIVER_OK){
 | 
			
		||||
            CFSTORE_ERRLOG("%s:Error: failed to read key (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value);
 | 
			
		||||
            drv->Close(hkey);
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
        if(len != strlen(node->value)){
 | 
			
		||||
            CFSTORE_ERRLOG("%s:Error: failed to read full value data (key_name=\"%s\", value=\"%s\"), len=%d, ret=%d\r\n", __func__, node->key_name, node->value, (int) len, (int) ret);
 | 
			
		||||
            drv->Close(hkey);
 | 
			
		||||
            return ARM_DRIVER_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
        key_name_len = key_name_max_len;
 | 
			
		||||
        memset(key_name_buf, 0, key_name_len);
 | 
			
		||||
        drv->GetKeyName(hkey, key_name_buf, &key_name_len);
 | 
			
		||||
        if(len != strlen(node->value)){
 | 
			
		||||
            CFSTORE_ERRLOG("%s:Error: failed to GetKeyName() (key_name=\"%s\", value=\"%s\"), len=%d\r\n", __func__, node->key_name, node->value, (int) len);
 | 
			
		||||
            drv->Close(hkey);
 | 
			
		||||
            return ARM_DRIVER_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
        /* revert CFSTORE_LOG for more trace */
 | 
			
		||||
        CFSTORE_DBGLOG("Created KV successfully (key_name=\"%s\", value=\"%s\")\r\n", key_name_buf, read_buf);
 | 
			
		||||
        drv->Close(hkey);
 | 
			
		||||
        node++;
 | 
			
		||||
    }
 | 
			
		||||
    free(read_buf);
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* @brief   test utility function to check a particular KV exists in the
 | 
			
		||||
 *          cfstore using Find() interface
 | 
			
		||||
 * @note    this function expects cfstore to have been initialised with
 | 
			
		||||
 *          a call to ARM_CFSTORE_DRIVER::Initialize()
 | 
			
		||||
 */
 | 
			
		||||
int32_t cfstore_test_kv_is_found(const char* key_name, bool* bfound)
 | 
			
		||||
{
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered.\r\n", __func__);
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(prev);
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(next);
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_ASSERT(bfound != NULL);
 | 
			
		||||
    CFSTORE_ASSERT(key_name != NULL);
 | 
			
		||||
    *bfound = 0;
 | 
			
		||||
 | 
			
		||||
    ret = drv->Find(key_name, prev, next);
 | 
			
		||||
    if(ret == ARM_DRIVER_OK){
 | 
			
		||||
        *bfound = 1;
 | 
			
		||||
        CFSTORE_DBGLOG("%s:Found key_name=\"%s\", about to call close.\r\n", __func__, key_name);
 | 
			
		||||
        drv->Close(next);
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* @brief   support function for generating a kv_name
 | 
			
		||||
 * @param   name    buffer to hold kv name
 | 
			
		||||
 * @param   len     length of kv name to generate
 | 
			
		||||
 * @note	braces are not included in the generated names as the names are
 | 
			
		||||
 *          of varible length and theyre may be unmatched
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
#define CFSTORE_TEST_KV_NAME_BUF_MAX_DATA (10+26+26+4)
 | 
			
		||||
int32_t cfstore_test_kv_name_gen(char* name, const size_t len)
 | 
			
		||||
{
 | 
			
		||||
    size_t i;
 | 
			
		||||
    const char buf[CFSTORE_TEST_KV_NAME_BUF_MAX_DATA+1] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_@";
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    for(i = 0; i < len; i++)
 | 
			
		||||
    {
 | 
			
		||||
        name[i] = buf[i % CFSTORE_TEST_KV_NAME_BUF_MAX_DATA];
 | 
			
		||||
    }
 | 
			
		||||
    return ARM_DRIVER_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* @brief   test utility function to read the value blob of a specified KV
 | 
			
		||||
 * @note    this function expects cfstore to have been initialised with
 | 
			
		||||
 *          a call to ARM_CFSTORE_DRIVER::Initialize()
 | 
			
		||||
 */
 | 
			
		||||
int32_t cfstore_test_read(const char* key_name, char* data, ARM_CFSTORE_SIZE* len)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\r\n", __func__);
 | 
			
		||||
    memset(&flags, 0, sizeof(flags));
 | 
			
		||||
    if(key_name == NULL) {
 | 
			
		||||
        CFSTORE_ERRLOG("%s:invalid key_name argument \r\n", __func__);
 | 
			
		||||
        goto out0;
 | 
			
		||||
    }
 | 
			
		||||
    if(data == NULL) {
 | 
			
		||||
        CFSTORE_ERRLOG("%s:invalid data argument \r\n", __func__);
 | 
			
		||||
        goto out0;
 | 
			
		||||
    }
 | 
			
		||||
    if(len == NULL) {
 | 
			
		||||
        CFSTORE_ERRLOG("%s:invalid len argument \r\n", __func__);
 | 
			
		||||
        goto out0;
 | 
			
		||||
    }
 | 
			
		||||
    ret = drv->Open(key_name, flags, hkey);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: failed to open node (key_name=\"%s\")(ret=%d)\r\n", __func__, key_name, (int) ret);
 | 
			
		||||
        goto out1;
 | 
			
		||||
    }
 | 
			
		||||
    ret = drv->Read(hkey, data, len);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: failed to read key (key_name=\"%s\"\r\n", __func__, key_name);
 | 
			
		||||
        goto out2;
 | 
			
		||||
    }
 | 
			
		||||
out2:
 | 
			
		||||
    drv->Close(hkey);
 | 
			
		||||
out1:
 | 
			
		||||
out0:
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* @brief   write the value blob of a specified KV
 | 
			
		||||
 * @note    this function expects cfstore to have been initialised with
 | 
			
		||||
 *          a call to ARM_CFSTORE_DRIVER::Initialize()
 | 
			
		||||
 */
 | 
			
		||||
int32_t cfstore_test_write(const char* key_name, const char* data, ARM_CFSTORE_SIZE* len)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    ARM_CFSTORE_HANDLE_INIT(hkey);
 | 
			
		||||
    ARM_CFSTORE_FMODE flags;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\r\n", __func__);
 | 
			
		||||
    memset(&flags, 0, sizeof(flags));
 | 
			
		||||
    if(key_name == NULL) {
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: invalid key_name argument \r\n", __func__);
 | 
			
		||||
        goto out0;
 | 
			
		||||
    }
 | 
			
		||||
    if(data == NULL) {
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: invalid data argument \r\n", __func__);
 | 
			
		||||
        goto out0;
 | 
			
		||||
    }
 | 
			
		||||
    if(len == NULL) {
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: invalid len argument \r\n", __func__);
 | 
			
		||||
        goto out0;
 | 
			
		||||
    }
 | 
			
		||||
    flags.write = 1;
 | 
			
		||||
    ret = drv->Open(key_name, flags, hkey);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: failed to open node (key_name=\"%s\")(ret=%d)\r\n", __func__, key_name, (int) ret);
 | 
			
		||||
        goto out1;
 | 
			
		||||
    }
 | 
			
		||||
    ret = drv->Write(hkey, data, len);
 | 
			
		||||
    if(ret < ARM_DRIVER_OK){
 | 
			
		||||
        CFSTORE_ERRLOG("%s:Error: failed to write key (key_name=\"%s\")\r\n", __func__, key_name);
 | 
			
		||||
        goto out2;
 | 
			
		||||
    }
 | 
			
		||||
out2:
 | 
			
		||||
    drv->Close(hkey);
 | 
			
		||||
out1:
 | 
			
		||||
out0:
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,86 @@
 | 
			
		|||
/** @file cfstore_test.h
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Header file for test support data structures and function API.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef __CFSTORE_TEST_H
 | 
			
		||||
#define __CFSTORE_TEST_H
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "configuration_store.h"
 | 
			
		||||
 | 
			
		||||
/* Defines */
 | 
			
		||||
#define CFSTORE_INIT_1_TABLE_HEAD               { "a", ""}
 | 
			
		||||
#define CFSTORE_INIT_1_TABLE_MID_NODE           { "0123456789abcdef0123456", "abcdefghijklmnopqrstuvwxyz"}
 | 
			
		||||
#define CFSTORE_INIT_1_TABLE_TAIL               { "yotta.hello-world.animal{wobbly-dog}{foot}backRight", "present"}
 | 
			
		||||
#define CFSTORE_TEST_RW_TABLE_SENTINEL          0xffffffff
 | 
			
		||||
#define CFSTORE_TEST_BYTE_DATA_TABLE_SIZE       256
 | 
			
		||||
#define CFSTORE_UTEST_MSG_BUF_SIZE              256
 | 
			
		||||
#define CFSTORE_UTEST_DEFAULT_TIMEOUT_MS        10000
 | 
			
		||||
#define CFSTORE_MBED_HOSTTEST_TIMEOUT 			60
 | 
			
		||||
 | 
			
		||||
/* support macro for make string for utest _MESSAGE macros, which dont support formatted output */
 | 
			
		||||
#define CFSTORE_TEST_UTEST_MESSAGE(_buf, _max_len, _fmt, ...)   \
 | 
			
		||||
  do                                                            \
 | 
			
		||||
  {                                                             \
 | 
			
		||||
      snprintf((_buf), (_max_len), (_fmt), __VA_ARGS__);        \
 | 
			
		||||
  }while(0);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Structures
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* kv data for test */
 | 
			
		||||
typedef struct cfstore_kv_data_t {
 | 
			
		||||
    const char* key_name;
 | 
			
		||||
    const char* value;
 | 
			
		||||
} cfstore_kv_data_t;
 | 
			
		||||
 | 
			
		||||
typedef struct cfstore_test_rw_data_entry_t
 | 
			
		||||
{
 | 
			
		||||
    uint32_t offset;
 | 
			
		||||
    char rw_char;
 | 
			
		||||
} cfstore_test_rw_data_entry_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
extern cfstore_kv_data_t cfstore_test_init_1_data[];
 | 
			
		||||
extern cfstore_test_rw_data_entry_t cfstore_test_rw_data_table[];
 | 
			
		||||
extern const char* cfstore_test_opcode_str[];
 | 
			
		||||
extern const uint8_t cfstore_test_byte_data_table[CFSTORE_TEST_BYTE_DATA_TABLE_SIZE];
 | 
			
		||||
 | 
			
		||||
int32_t cfstore_test_check_node_correct(const cfstore_kv_data_t* node);
 | 
			
		||||
int32_t cfstore_test_create(const char* key_name, const char* data, size_t* len, ARM_CFSTORE_KEYDESC* kdesc);
 | 
			
		||||
int32_t cfstore_test_create_table(const cfstore_kv_data_t* table);
 | 
			
		||||
int32_t cfstore_test_delete(const char* key_name);
 | 
			
		||||
int32_t cfstore_test_delete_all(void);
 | 
			
		||||
int32_t cfstore_test_dump(void);
 | 
			
		||||
int32_t cfstore_test_init_1(void);
 | 
			
		||||
int32_t cfstore_test_kv_is_found(const char* key_name, bool* bfound);
 | 
			
		||||
int32_t cfstore_test_kv_name_gen(char* name, const size_t len);
 | 
			
		||||
int32_t cfstore_test_read(const char* key_name, char* data, size_t* len);
 | 
			
		||||
int32_t cfstore_test_startup(void);
 | 
			
		||||
int32_t cfstore_test_write(const char* key_name, const char* data, size_t* len);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __CFSTORE_TEST_H */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,76 @@
 | 
			
		|||
/** @file cfstore_test.h
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Header file for test support data structures and function API.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef __CFSTORE_UTEST_H
 | 
			
		||||
#define __CFSTORE_UTEST_H
 | 
			
		||||
 | 
			
		||||
#include "cfstore_debug.h"
 | 
			
		||||
#include "cfstore_test.h"
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
void cfstore_utest_default_callback(int32_t status, ARM_CFSTORE_OPCODE cmd_code, void *client_context, ARM_CFSTORE_HANDLE handle)
 | 
			
		||||
{
 | 
			
		||||
    (void) status;
 | 
			
		||||
    (void) client_context;
 | 
			
		||||
    (void) handle;
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered: status=%d, cmd_code=%d (%s) handle=%p\n", __func__, (int) status, (int) cmd_code, cfstore_test_opcode_str[cmd_code], handle);
 | 
			
		||||
    switch(cmd_code)
 | 
			
		||||
    {
 | 
			
		||||
    case CFSTORE_OPCODE_INITIALIZE:
 | 
			
		||||
    case CFSTORE_OPCODE_FLUSH:
 | 
			
		||||
    case CFSTORE_OPCODE_UNINITIALIZE:
 | 
			
		||||
    case CFSTORE_OPCODE_CLOSE:
 | 
			
		||||
    case CFSTORE_OPCODE_CREATE:
 | 
			
		||||
    case CFSTORE_OPCODE_DELETE:
 | 
			
		||||
    case CFSTORE_OPCODE_FIND:
 | 
			
		||||
    case CFSTORE_OPCODE_GET_KEY_NAME:
 | 
			
		||||
    case CFSTORE_OPCODE_GET_STATUS:
 | 
			
		||||
    case CFSTORE_OPCODE_GET_VALUE_LEN:
 | 
			
		||||
    case CFSTORE_OPCODE_OPEN:
 | 
			
		||||
    case CFSTORE_OPCODE_POWER_CONTROL:
 | 
			
		||||
    case CFSTORE_OPCODE_READ:
 | 
			
		||||
    case CFSTORE_OPCODE_RSEEK:
 | 
			
		||||
    case CFSTORE_OPCODE_WRITE:
 | 
			
		||||
    default:
 | 
			
		||||
        CFSTORE_DBGLOG("%s:debug: received asynchronous notification for opcode=%d (%s)", __func__, cmd_code, cmd_code < CFSTORE_OPCODE_MAX ? cfstore_test_opcode_str[cmd_code] : "unknown");
 | 
			
		||||
    }
 | 
			
		||||
    CFSTORE_DBGLOG("%s:about to validate callback\n", __func__);
 | 
			
		||||
    Harness::validate_callback();
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static control_t cfstore_utest_default_start(const size_t call_count)
 | 
			
		||||
{
 | 
			
		||||
    int32_t ret = ARM_DRIVER_ERROR;
 | 
			
		||||
    ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
 | 
			
		||||
    char cfstore_utest_msg[CFSTORE_UTEST_MSG_BUF_SIZE];
 | 
			
		||||
 | 
			
		||||
    CFSTORE_FENTRYLOG("%s:entered\n", __func__);
 | 
			
		||||
    (void) call_count;
 | 
			
		||||
    ret = drv->Initialize(cfstore_utest_default_callback, NULL);
 | 
			
		||||
    CFSTORE_TEST_UTEST_MESSAGE(cfstore_utest_msg, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to initialize CFSTORE (ret=%d)\n", __func__, (int) ret);
 | 
			
		||||
    TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_utest_msg);
 | 
			
		||||
    return CaseTimeout(CFSTORE_UTEST_DEFAULT_TIMEOUT_MS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* __CFSTORE_UTEST_H */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,121 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2013-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 __CFSTORE_UVISOR_H__
 | 
			
		||||
#define __CFSTORE_UVISOR_H__
 | 
			
		||||
 | 
			
		||||
/* target specifc ACLs */
 | 
			
		||||
#if   defined(TARGET_LIKE_FRDM_K64F)
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_UVISOR_LED_ON  false
 | 
			
		||||
#define CFSTORE_UVISOR_LED_OFF true
 | 
			
		||||
#define CFSTORE_UVISOR_MAIN_LED LED_BLUE
 | 
			
		||||
#define CFSTORE_UVISOR_MAIN_BTN SW2
 | 
			
		||||
#define CFSTORE_UVISOR_MAIN_BTN_PUPD PullUp
 | 
			
		||||
#define CFSTORE_UVISOR_MAIN_ACL(acl_list_name) \
 | 
			
		||||
    static const UvisorBoxAclItem acl_list_name[] = {     \
 | 
			
		||||
        {MCG,    sizeof(*MCG),    UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {SIM,    sizeof(*SIM),    UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {PORTB,  sizeof(*PORTB),  UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {PORTC,  sizeof(*PORTC),  UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {RTC,    sizeof(*RTC),    UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {LPTMR0, sizeof(*LPTMR0), UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {PIT,    sizeof(*PIT),    UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {SMC,    sizeof(*SMC),    UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {UART0,  sizeof(*UART0),  UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#elif defined(TARGET_LIKE_STM32F429I_DISCO)
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_UVISOR_LED_ON  false
 | 
			
		||||
#define CFSTORE_UVISOR_LED_OFF true
 | 
			
		||||
#define CFSTORE_UVISOR_MAIN_LED LED1
 | 
			
		||||
#define CFSTORE_UVISOR_MAIN_BTN USER_BUTTON
 | 
			
		||||
#define CFSTORE_UVISOR_MAIN_BTN_PUPD PullDown
 | 
			
		||||
#define CFSTORE_UVISOR_MAIN_ACL(acl_list_name)                           \
 | 
			
		||||
    static const UvisorBoxAclItem acl_list_name[] = {     \
 | 
			
		||||
        {TIM2,   sizeof(*TIM2),   UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {TIM5,   sizeof(*TIM5),   UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {GPIOA,  sizeof(*GPIOA),  UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {GPIOG,  sizeof(*GPIOG),  UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        /* FIXME: secure RCC/EXTI/SYSCFG/FLASH */         \
 | 
			
		||||
        {RCC,    sizeof(*RCC),    UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {EXTI,   sizeof(*EXTI),   UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {SYSCFG, sizeof(*SYSCFG), UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {FLASH,  sizeof(*FLASH),  UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {PWR,    sizeof(*PWR),    UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {USART1, sizeof(*USART1), UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {(void *) 0x42470000, 0x1000, UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#elif  defined(TARGET_LIKE_EFM32GG_STK) \
 | 
			
		||||
    || defined(TARGET_LIKE_EFM32LG_STK) \
 | 
			
		||||
    || defined(TARGET_LIKE_EFM32WG_STK)
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_UVISOR_LED_ON  false
 | 
			
		||||
#define CFSTORE_UVISOR_LED_OFF true
 | 
			
		||||
#define CFSTORE_UVISOR_MAIN_LED LED1
 | 
			
		||||
#define CFSTORE_UVISOR_MAIN_BTN BTN0
 | 
			
		||||
#define CFSTORE_UVISOR_MAIN_BTN_PUPD PullUp
 | 
			
		||||
#define CFSTORE_UVISOR_MAIN_ACL(acl_list_name)                              \
 | 
			
		||||
    static const UvisorBoxAclItem acl_list_name[] = {        \
 | 
			
		||||
        {GPIO,      sizeof(*GPIO),   UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {UART0,     sizeof(*UART0),  UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {TIMER0,    sizeof(*TIMER0), UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        /* FIXME: Secure CMU */                              \
 | 
			
		||||
        {CMU,       sizeof(*CMU),    UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {RTC,       sizeof(*RTC),    UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        /* FIXME: Secure MSC */                              \
 | 
			
		||||
        {MSC,       sizeof(*MSC),    UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        /* mbed-hal-silabs requires the DI page to be readable */  \
 | 
			
		||||
        {(void*) 0x0FE08000, 0x1000, UVISOR_TACLDEF_SECURE_CONST}, \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#elif defined(TARGET_LIKE_EFM32PG_STK)
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_UVISOR_LED_ON  false
 | 
			
		||||
#define CFSTORE_UVISOR_LED_OFF true
 | 
			
		||||
#define CFSTORE_UVISOR_MAIN_LED LED1
 | 
			
		||||
#define CFSTORE_UVISOR_MAIN_BTN BTN0
 | 
			
		||||
#define CFSTORE_UVISOR_MAIN_BTN_PUPD PullUp
 | 
			
		||||
#define CFSTORE_UVISOR_MAIN_ACL(acl_list_name)                              \
 | 
			
		||||
    static const UvisorBoxAclItem acl_list_name[] = {        \
 | 
			
		||||
        {GPIO,      sizeof(*GPIO),   UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {USART0,    sizeof(*USART0), UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {TIMER0,    sizeof(*TIMER0), UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        /* FIXME: Secure CMU */                              \
 | 
			
		||||
        {CMU,       sizeof(*CMU),    UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {EMU,       sizeof(*EMU),    UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        {RTCC,      sizeof(*RTCC),   UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        /* FIXME: Secure MSC */                              \
 | 
			
		||||
        {MSC,       sizeof(*MSC),    UVISOR_TACLDEF_PERIPH}, \
 | 
			
		||||
        /* mbed-hal-silabs requires the DI page to be readable */  \
 | 
			
		||||
        {(void*) 0x0FE08000, 0x1000, UVISOR_TACLDEF_SECURE_CONST}, \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
#define CFSTORE_UVISOR_LED_ON  true
 | 
			
		||||
#define CFSTORE_UVISOR_LED_OFF false
 | 
			
		||||
#define CFSTORE_UVISOR_MAIN_LED NC
 | 
			
		||||
#define CFSTORE_UVISOR_MAIN_BTN NC
 | 
			
		||||
#define CFSTORE_UVISOR_MAIN_BTN_PUPD PullNone
 | 
			
		||||
#define CFSTORE_UVISOR_MAIN_ACL(acl_list_name) \
 | 
			
		||||
    static const UvisorBoxAclItem acl_list_name[] = {}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
/* In order to support ARM toolchain and simplify the number of newlib posix files used,
 | 
			
		||||
 * this have been copied from collate.c, and the license for this code has been included at the
 | 
			
		||||
 * here:
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
 | 
			
		||||
 *		at Electronni Visti IA, Kiev, Ukraine.
 | 
			
		||||
 *			All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *    documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
 | 
			
		||||
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
 | 
			
		||||
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
			
		||||
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
			
		||||
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
			
		||||
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
			
		||||
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
			
		||||
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
			
		||||
 * SUCH DAMAGE.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,23 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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__
 | 
			
		||||
 | 
			
		||||
#define SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS 4
 | 
			
		||||
 | 
			
		||||
#endif /* __FLASH_JOURNAL_CONFIG_H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,146 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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_PRIVATE_H__
 | 
			
		||||
#define __FLASH_JOURNAL_PRIVATE_H__
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif // __cplusplus
 | 
			
		||||
 | 
			
		||||
#include "flash-journal/flash_journal.h"
 | 
			
		||||
#include "flash-journal-strategy-sequential/config.h"
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED,
 | 
			
		||||
    SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS,
 | 
			
		||||
    SEQUENTIAL_JOURNAL_STATE_INITIALIZED,
 | 
			
		||||
    SEQUENTIAL_JOURNAL_STATE_RESETING,
 | 
			
		||||
    SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE,
 | 
			
		||||
    SEQUENTIAL_JOURNAL_STATE_LOGGING_HEAD,
 | 
			
		||||
    SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY,
 | 
			
		||||
    SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL,
 | 
			
		||||
    SEQUENTIAL_JOURNAL_STATE_READING,
 | 
			
		||||
} SequentialFlashJournalState_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Meta-data placed at the head of a sequential-log entry.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct _SequentialFlashJournalLogHead {
 | 
			
		||||
    uint32_t version;
 | 
			
		||||
    uint32_t magic;
 | 
			
		||||
    uint32_t sequenceNumber;
 | 
			
		||||
    uint32_t reserved;
 | 
			
		||||
} SequentialFlashJournalLogHead_t;
 | 
			
		||||
 | 
			
		||||
#define SEQUENTIAL_JOURNAL_VALID_HEAD(PTR) \
 | 
			
		||||
    (((PTR)->version == SEQUENTIAL_FLASH_JOURNAL_VERSION) && ((PTR)->magic == SEQUENTIAL_FLASH_JOURNAL_MAGIC))
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Meta-data placed at the tail of a sequential-log entry.
 | 
			
		||||
 *
 | 
			
		||||
 * @note the most crucial items (the ones which play a role in the validation of
 | 
			
		||||
 *     the log-entry) are placed at the end of this structure; this ensures that
 | 
			
		||||
 *     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 magic;
 | 
			
		||||
    uint32_t sequenceNumber;
 | 
			
		||||
} SequentialFlashJournalLogTail_t;
 | 
			
		||||
 | 
			
		||||
#define SEQUENTIAL_JOURNAL_VALID_TAIL(TAIL_PTR) ((TAIL_PTR)->magic == SEQUENTIAL_FLASH_JOURNAL_MAGIC)
 | 
			
		||||
 | 
			
		||||
typedef struct _SequentialFlashJournal_t {
 | 
			
		||||
    FlashJournal_Ops_t             ops;                /**< the mandatory OPS table defining the strategy. */
 | 
			
		||||
    FlashJournal_Callback_t        callback;           /**< command completion callback. */
 | 
			
		||||
    FlashJournal_Info_t            info;               /**< the info structure returned from GetInfo(). */
 | 
			
		||||
    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                       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. */
 | 
			
		||||
    FlashJournal_OpCode_t          prevCommand;        /**< the last command issued to the journal. */
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The following is a union of sub-structures meant to keep state relevant
 | 
			
		||||
     * to the commands during their execution.
 | 
			
		||||
     */
 | 
			
		||||
    union {
 | 
			
		||||
        /** state relevant to initialization. */
 | 
			
		||||
        struct {
 | 
			
		||||
            uint64_t currentOffset;
 | 
			
		||||
            union {
 | 
			
		||||
                SequentialFlashJournalLogHead_t head;
 | 
			
		||||
                struct {
 | 
			
		||||
                    uint32_t                        headSequenceNumber;
 | 
			
		||||
                    SequentialFlashJournalLogTail_t tail;
 | 
			
		||||
                };
 | 
			
		||||
            };
 | 
			
		||||
        } initScan;
 | 
			
		||||
 | 
			
		||||
        /** state relevant to logging of data. */
 | 
			
		||||
        struct {
 | 
			
		||||
            const uint8_t *blob;           /**< the original buffer holding source data. */
 | 
			
		||||
            size_t         sizeofBlob;
 | 
			
		||||
            union {
 | 
			
		||||
                struct {
 | 
			
		||||
                    uint64_t eraseOffset;
 | 
			
		||||
                };
 | 
			
		||||
                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. */
 | 
			
		||||
                    const uint8_t *dataBeingLogged; /**< temporary pointer aimed at the next data to be logged. */
 | 
			
		||||
                    size_t         amountLeftToLog;
 | 
			
		||||
                    union {
 | 
			
		||||
                        SequentialFlashJournalLogHead_t head;
 | 
			
		||||
                        SequentialFlashJournalLogTail_t tail;
 | 
			
		||||
                    };
 | 
			
		||||
                };
 | 
			
		||||
            };
 | 
			
		||||
        } log;
 | 
			
		||||
 | 
			
		||||
        /** state relevant to read-back of data. */
 | 
			
		||||
        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. */
 | 
			
		||||
            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. */
 | 
			
		||||
        } read;
 | 
			
		||||
    };
 | 
			
		||||
} SequentialFlashJournal_t;
 | 
			
		||||
 | 
			
		||||
/**<
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
typedef char AssertSequentialJournalSizeLessThanOrEqualToGenericJournal[sizeof(SequentialFlashJournal_t)<=sizeof(FlashJournal_t)?1:-1];
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif // __cplusplus
 | 
			
		||||
 | 
			
		||||
#endif /* __FLASH_JOURNAL_PRIVATE_H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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_STRATEGY_SEQUENTIAL_H__
 | 
			
		||||
#define __FLASH_JOURNAL_STRATEGY_SEQUENTIAL_H__
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif // __cplusplus
 | 
			
		||||
 | 
			
		||||
#include "flash-journal/flash_journal.h"
 | 
			
		||||
 | 
			
		||||
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_log(FlashJournal_t *journal, const void *blob, size_t n);
 | 
			
		||||
int32_t               flashJournalStrategySequential_commit(FlashJournal_t *journal);
 | 
			
		||||
int32_t               flashJournalStrategySequential_reset(FlashJournal_t *journal);
 | 
			
		||||
 | 
			
		||||
static const FlashJournal_Ops_t FLASH_JOURNAL_STRATEGY_SEQUENTIAL = {
 | 
			
		||||
    flashJournalStrategySequential_initialize,
 | 
			
		||||
    flashJournalStrategySequential_getInfo,
 | 
			
		||||
    flashJournalStrategySequential_read,
 | 
			
		||||
    flashJournalStrategySequential_log,
 | 
			
		||||
    flashJournalStrategySequential_commit,
 | 
			
		||||
    flashJournalStrategySequential_reset
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif // __cplusplus
 | 
			
		||||
 | 
			
		||||
#endif /* __FLASH_JOURNAL_STRATEGY_SEQUENTIAL_H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,269 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 "flash-journal-strategy-sequential/flash_journal_private.h"
 | 
			
		||||
#include "flash-journal-strategy-sequential/flash_journal_strategy_sequential.h"
 | 
			
		||||
#include "support_funcs.h"
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
SequentialFlashJournal_t *activeJournal;
 | 
			
		||||
 | 
			
		||||
/* forward declarations */
 | 
			
		||||
void mtdHandler(int32_t status, ARM_STORAGE_OPERATION operation);
 | 
			
		||||
 | 
			
		||||
static inline 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline 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: 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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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). */
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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. */
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return JOURNAL_STATUS_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t flashJournalStrategySequential_initialize(FlashJournal_t           *_journal,
 | 
			
		||||
                                                  ARM_DRIVER_STORAGE       *mtd,
 | 
			
		||||
                                                  const FlashJournal_Ops_t *ops,
 | 
			
		||||
                                                  FlashJournal_Callback_t   callback)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    SequentialFlashJournal_t *journal;
 | 
			
		||||
    activeJournal = journal = (SequentialFlashJournal_t *)_journal;
 | 
			
		||||
    journal->state          = SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED;
 | 
			
		||||
 | 
			
		||||
    /* fetch MTD's total capacity */
 | 
			
		||||
    uint64_t mtdCapacity;
 | 
			
		||||
    if ((rc = mtdGetTotalCapacity(mtd, &mtdCapacity)) != JOURNAL_STATUS_OK) {
 | 
			
		||||
        return rc;
 | 
			
		||||
    }
 | 
			
		||||
    ARM_STORAGE_INFO mtdInfo;
 | 
			
		||||
    if ((rc = mtd->GetInfo(&mtdInfo)) != ARM_DRIVER_OK) {
 | 
			
		||||
        return JOURNAL_STATUS_STORAGE_API_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* 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->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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 1; /* synchronous completion */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FlashJournal_Status_t flashJournalStrategySequential_getInfo(FlashJournal_t *_journal, FlashJournal_Info_t *infoP)
 | 
			
		||||
{
 | 
			
		||||
    SequentialFlashJournal_t *journal;
 | 
			
		||||
    activeJournal = journal = (SequentialFlashJournal_t *)_journal;
 | 
			
		||||
 | 
			
		||||
    memcpy(infoP, &journal->info, sizeof(FlashJournal_Info_t));
 | 
			
		||||
    return JOURNAL_STATUS_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t flashJournalStrategySequential_read(FlashJournal_t *_journal, void *blob, size_t sizeofBlob)
 | 
			
		||||
{
 | 
			
		||||
    SequentialFlashJournal_t *journal;
 | 
			
		||||
    activeJournal = journal = (SequentialFlashJournal_t *)_journal;
 | 
			
		||||
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
    if ((rc = flashJournalStrategySequential_read_sanityChecks(journal, blob, sizeofBlob)) != JOURNAL_STATUS_OK) {
 | 
			
		||||
        return rc;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
    } 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;
 | 
			
		||||
    // 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_log(FlashJournal_t *_journal, const void *blob, size_t size)
 | 
			
		||||
{
 | 
			
		||||
    SequentialFlashJournal_t *journal;
 | 
			
		||||
    activeJournal = journal = (SequentialFlashJournal_t *)_journal;
 | 
			
		||||
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
    if ((rc = flashJournalStrategySequential_log_sanityChecks(journal, blob, size)) != JOURNAL_STATUS_OK) {
 | 
			
		||||
        return rc;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    journal->log.blob       = blob;
 | 
			
		||||
    journal->log.sizeofBlob = size;
 | 
			
		||||
 | 
			
		||||
    if (journal->prevCommand != FLASH_JOURNAL_OPCODE_LOG_BLOB) {
 | 
			
		||||
        uint32_t logBlobIndex = journal->currentBlobIndex + 1;
 | 
			
		||||
        if (logBlobIndex == SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS) {
 | 
			
		||||
            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;
 | 
			
		||||
    } else {
 | 
			
		||||
        journal->log.dataBeingLogged = blob;
 | 
			
		||||
        journal->log.amountLeftToLog = size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return flashJournalStrategySequential_log_progress();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t flashJournalStrategySequential_commit(FlashJournal_t *_journal)
 | 
			
		||||
{
 | 
			
		||||
    SequentialFlashJournal_t *journal;
 | 
			
		||||
    activeJournal = journal = (SequentialFlashJournal_t *)_journal;
 | 
			
		||||
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
    if ((rc = flashJournalStrategySequential_commit_sanityChecks(journal)) != JOURNAL_STATUS_OK) {
 | 
			
		||||
        return rc;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (journal->prevCommand == FLASH_JOURNAL_OPCODE_LOG_BLOB) {
 | 
			
		||||
        journal->log.offset          = journal->log.tailOffset;
 | 
			
		||||
        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) {
 | 
			
		||||
            logBlobIndex = 0;
 | 
			
		||||
        }
 | 
			
		||||
        journal->log.eraseOffset = journal->mtdStartOffset + (logBlobIndex * journal->sequentialSkip);
 | 
			
		||||
        journal->state           = SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    journal->prevCommand = FLASH_JOURNAL_OPCODE_COMMIT;
 | 
			
		||||
    return flashJournalStrategySequential_log_progress();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t flashJournalStrategySequential_reset(FlashJournal_t *_journal)
 | 
			
		||||
{
 | 
			
		||||
    SequentialFlashJournal_t *journal;
 | 
			
		||||
    activeJournal = journal = (SequentialFlashJournal_t *)_journal;
 | 
			
		||||
 | 
			
		||||
    journal->state = SEQUENTIAL_JOURNAL_STATE_RESETING;
 | 
			
		||||
 | 
			
		||||
    journal->prevCommand = FLASH_JOURNAL_OPCODE_RESET;
 | 
			
		||||
    return flashJournalStrategySequential_reset_progress();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,510 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 "support_funcs.h"
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
static inline int32_t mtdGetStartAddr(ARM_DRIVER_STORAGE *mtd, uint64_t *startAddrP)
 | 
			
		||||
{
 | 
			
		||||
    ARM_STORAGE_BLOCK mtdBlock;
 | 
			
		||||
    if ((mtd->GetNextBlock(NULL, &mtdBlock)) != ARM_DRIVER_OK) {
 | 
			
		||||
        return JOURNAL_STATUS_STORAGE_API_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    if (!ARM_STORAGE_VALID_BLOCK(&mtdBlock)) {
 | 
			
		||||
        return JOURNAL_STATUS_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *startAddrP = mtdBlock.addr;
 | 
			
		||||
    return JOURNAL_STATUS_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t discoverLatestLoggedBlob(SequentialFlashJournal_t *journal)
 | 
			
		||||
{
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
 | 
			
		||||
    /* 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->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;
 | 
			
		||||
 | 
			
		||||
    // printf("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);
 | 
			
		||||
        /* 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;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            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);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // printf("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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 */
 | 
			
		||||
            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 */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    journal->nextSequenceNumber       = 0;
 | 
			
		||||
    journal->currentBlobIndex         = (uint32_t)-1;
 | 
			
		||||
    journal->info.sizeofJournaledBlob = 0;
 | 
			
		||||
    journal->state                    = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t flashJournalStrategySequential_read_progress(void)
 | 
			
		||||
{
 | 
			
		||||
    SequentialFlashJournal_t *journal = activeJournal;
 | 
			
		||||
 | 
			
		||||
    // printf("flashJournalStrategySequential_read_progress\n");
 | 
			
		||||
    if (journal->state != SEQUENTIAL_JOURNAL_STATE_READING) {
 | 
			
		||||
        return JOURNAL_STATUS_ERROR; /* journal is in an un-expected state. */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int32_t rc;
 | 
			
		||||
    ARM_STORAGE_BLOCK storageBlock;
 | 
			
		||||
 | 
			
		||||
    if ((journal->read.amountLeftToRead) &&
 | 
			
		||||
        ((rc = journal->mtd->GetBlock(journal->read.offset, &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);
 | 
			
		||||
 | 
			
		||||
    while (journal->read.amountLeftToRead) {
 | 
			
		||||
        while (!storageBlockAvailableCapacity) {
 | 
			
		||||
            if ((rc = journal->mtd->GetNextBlock(&storageBlock, &storageBlock)) < 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. */
 | 
			
		||||
            }
 | 
			
		||||
            journal->read.offset          =  storageBlock.addr; /* This should not be necessary since we assume
 | 
			
		||||
                                                                 * storage map manages a contiguous address space. */
 | 
			
		||||
            storageBlockAvailableCapacity = storageBlock.size;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* compute the transfer size for this iteration. */
 | 
			
		||||
        uint32_t xfer = (journal->read.amountLeftToRead < storageBlockAvailableCapacity) ?
 | 
			
		||||
                            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);
 | 
			
		||||
        if (rc < 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)) {
 | 
			
		||||
            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.amountLeftToRead -= rc;
 | 
			
		||||
            journal->read.dataBeingRead    += rc;
 | 
			
		||||
            journal->read.totalDataRead    += rc;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
 | 
			
		||||
    return (journal->read.dataBeingRead - journal->read.blob);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t flashJournalStrategySequential_log_progress(void)
 | 
			
		||||
{
 | 
			
		||||
    SequentialFlashJournal_t *journal = activeJournal;
 | 
			
		||||
 | 
			
		||||
    if ((journal->state != SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE) &&
 | 
			
		||||
        (journal->state != SEQUENTIAL_JOURNAL_STATE_LOGGING_HEAD)  &&
 | 
			
		||||
        (journal->state != SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY)  &&
 | 
			
		||||
        (journal->state != SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL)) {
 | 
			
		||||
        return JOURNAL_STATUS_ERROR; /* journal is in an un-expected state. */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint32_t blobIndexBeingLogged = journal->currentBlobIndex + 1;
 | 
			
		||||
    if (blobIndexBeingLogged == SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS) {
 | 
			
		||||
        blobIndexBeingLogged = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while (true) {
 | 
			
		||||
        int32_t rc;
 | 
			
		||||
 | 
			
		||||
        if (journal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE) {
 | 
			
		||||
            uint64_t amountLeftToErase = journal->mtdStartOffset
 | 
			
		||||
                                         + (blobIndexBeingLogged + 1) * journal->sequentialSkip
 | 
			
		||||
                                         - journal->log.eraseOffset;
 | 
			
		||||
            // 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) {
 | 
			
		||||
                    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 ((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;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            ARM_STORAGE_BLOCK storageBlock;
 | 
			
		||||
 | 
			
		||||
            /* find the available capacity in the current storage block */
 | 
			
		||||
            while (journal->log.amountLeftToLog) {
 | 
			
		||||
                if (journal->log.amountLeftToLog < journal->info.program_unit) {
 | 
			
		||||
                    /* We cannot log any smaller than info.program_unit. 'xfer'
 | 
			
		||||
                     * amount of data would remain unlogged. We'll break out of this loop and report
 | 
			
		||||
                     * the amount actually logged. */
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                /* check for alignment of next log offset with program_unit */
 | 
			
		||||
                if ((rc = journal->mtd->GetBlock(journal->log.offset, &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) {
 | 
			
		||||
                    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. */
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                uint32_t xfer = journal->log.amountLeftToLog;
 | 
			
		||||
                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);
 | 
			
		||||
                if (rc < 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)) {
 | 
			
		||||
                    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.amountLeftToLog -= rc;
 | 
			
		||||
                    journal->log.dataBeingLogged += rc;
 | 
			
		||||
                    if (journal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY) {
 | 
			
		||||
                        journal->log.tail.sizeofBlob += rc;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } /* while (journal->log.amountLeftToLog) */
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // printf("flashJournalStrategySequential_log_progress: state switch\n");
 | 
			
		||||
 | 
			
		||||
        /* state transition */
 | 
			
		||||
        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.head.version        = SEQUENTIAL_FLASH_JOURNAL_VERSION;
 | 
			
		||||
                journal->log.head.magic          = SEQUENTIAL_FLASH_JOURNAL_MAGIC;
 | 
			
		||||
                journal->log.head.sequenceNumber = journal->nextSequenceNumber;
 | 
			
		||||
                journal->log.head.reserved       = 0;
 | 
			
		||||
                journal->log.dataBeingLogged     = (const uint8_t *)&journal->log.head;
 | 
			
		||||
                journal->log.amountLeftToLog     = sizeof(SequentialFlashJournalLogHead_t);
 | 
			
		||||
                // printf("newstate: program HEAD; amount to log %u\n", journal->log.amountLeftToLog);
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case SEQUENTIAL_JOURNAL_STATE_LOGGING_HEAD: /* 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.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. */
 | 
			
		||||
 | 
			
		||||
                if (journal->prevCommand == FLASH_JOURNAL_OPCODE_COMMIT) {
 | 
			
		||||
                    /* This branch is taken only when commit() is called without any preceding log() operations. */
 | 
			
		||||
                    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);
 | 
			
		||||
                } else {
 | 
			
		||||
                    journal->state                   = SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY;
 | 
			
		||||
                    journal->log.dataBeingLogged     = journal->log.blob;
 | 
			
		||||
                    journal->log.amountLeftToLog     = journal->log.sizeofBlob;
 | 
			
		||||
                    // printf("newstate: program BODY; amount to log %u\n", journal->log.amountLeftToLog);
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY:
 | 
			
		||||
                // printf("finished logging BODY; amount logged %u\n", journal->log.dataBeingLogged - journal->log.blob);
 | 
			
		||||
                if (journal->log.dataBeingLogged == journal->log.blob) {
 | 
			
		||||
                    return JOURNAL_STATUS_SMALL_LOG_REQUEST;
 | 
			
		||||
                } else {
 | 
			
		||||
                    return (journal->log.dataBeingLogged - journal->log.blob);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            case SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL:
 | 
			
		||||
                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) {
 | 
			
		||||
                    journal->currentBlobIndex = 0;
 | 
			
		||||
                }
 | 
			
		||||
                // printf("currentBlobIndex: %lu\n", journal->currentBlobIndex);
 | 
			
		||||
 | 
			
		||||
                /* increment next sequence number */
 | 
			
		||||
                ++journal->nextSequenceNumber;
 | 
			
		||||
                if (journal->nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) {
 | 
			
		||||
                    ++journal->nextSequenceNumber;
 | 
			
		||||
                }
 | 
			
		||||
                // printf("nextSequenceNumber %lu\n", journal->nextSequenceNumber);
 | 
			
		||||
 | 
			
		||||
                return 1; /* commit returns 1 upon completion. */
 | 
			
		||||
 | 
			
		||||
            default:
 | 
			
		||||
                journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
 | 
			
		||||
                return JOURNAL_STATUS_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
        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);
 | 
			
		||||
                }
 | 
			
		||||
                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);
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case SEQUENTIAL_JOURNAL_STATE_INITIALIZED:
 | 
			
		||||
            case SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE:
 | 
			
		||||
            case SEQUENTIAL_JOURNAL_STATE_LOGGING_HEAD:
 | 
			
		||||
            case SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY:
 | 
			
		||||
            case SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL:
 | 
			
		||||
                /* reset journal state to allow further operation. */
 | 
			
		||||
                activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
 | 
			
		||||
 | 
			
		||||
                if (activeJournal->callback) {
 | 
			
		||||
                    activeJournal->callback(JOURNAL_STATUS_STORAGE_IO_ERROR, FLASH_JOURNAL_OPCODE_LOG_BLOB);
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            case SEQUENTIAL_JOURNAL_STATE_READING:
 | 
			
		||||
                /* reset journal state to allow further operation. */
 | 
			
		||||
                activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
 | 
			
		||||
 | 
			
		||||
                if (activeJournal->callback) {
 | 
			
		||||
                    activeJournal->callback(JOURNAL_STATUS_STORAGE_IO_ERROR, FLASH_JOURNAL_OPCODE_READ_BLOB);
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (operation) {
 | 
			
		||||
        case ARM_STORAGE_OPERATION_INITIALIZE:
 | 
			
		||||
            if (activeJournal->callback) {
 | 
			
		||||
                activeJournal->callback(JOURNAL_STATUS_OK, FLASH_JOURNAL_OPCODE_INITIALIZE);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case ARM_STORAGE_OPERATION_ERASE_ALL:
 | 
			
		||||
            if (activeJournal->state == SEQUENTIAL_JOURNAL_STATE_RESETING) {
 | 
			
		||||
                activeJournal->nextSequenceNumber       = 0;
 | 
			
		||||
                activeJournal->currentBlobIndex         = (uint32_t)-1;
 | 
			
		||||
                activeJournal->info.sizeofJournaledBlob = 0;
 | 
			
		||||
                activeJournal->state                    = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
 | 
			
		||||
                if (activeJournal->callback) {
 | 
			
		||||
                    activeJournal->callback(JOURNAL_STATUS_OK, FLASH_JOURNAL_OPCODE_RESET);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case ARM_STORAGE_OPERATION_ERASE:
 | 
			
		||||
            if (activeJournal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE) {
 | 
			
		||||
                if (status <= ARM_DRIVER_OK) {
 | 
			
		||||
                    if (activeJournal->callback) {
 | 
			
		||||
                        activeJournal->callback(JOURNAL_STATUS_STORAGE_API_ERROR, FLASH_JOURNAL_OPCODE_LOG_BLOB);
 | 
			
		||||
                    }
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                activeJournal->log.eraseOffset += status;
 | 
			
		||||
 | 
			
		||||
                if ((rc = flashJournalStrategySequential_log_progress()) != JOURNAL_STATUS_OK) {
 | 
			
		||||
                    activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
 | 
			
		||||
                    if (activeJournal->callback) {
 | 
			
		||||
                        activeJournal->callback(rc, FLASH_JOURNAL_OPCODE_LOG_BLOB);
 | 
			
		||||
                    }
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            } else if (activeJournal->state == SEQUENTIAL_JOURNAL_STATE_RESETING) {
 | 
			
		||||
                activeJournal->nextSequenceNumber       = 0;
 | 
			
		||||
                activeJournal->currentBlobIndex         = (uint32_t)-1;
 | 
			
		||||
                activeJournal->info.sizeofJournaledBlob = 0;
 | 
			
		||||
                activeJournal->state                    = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
 | 
			
		||||
                if (activeJournal->callback) {
 | 
			
		||||
                    activeJournal->callback(JOURNAL_STATUS_OK, FLASH_JOURNAL_OPCODE_RESET);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case ARM_STORAGE_OPERATION_PROGRAM_DATA:
 | 
			
		||||
            // printf("PROGRAM_DATA: received status of %ld\n", status);
 | 
			
		||||
            rc = status;
 | 
			
		||||
            activeJournal->log.offset          += rc;
 | 
			
		||||
            activeJournal->log.amountLeftToLog -= rc;
 | 
			
		||||
            activeJournal->log.dataBeingLogged += rc;
 | 
			
		||||
            if (activeJournal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY) {
 | 
			
		||||
                activeJournal->log.tail.sizeofBlob += rc;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ((rc = flashJournalStrategySequential_log_progress()) < JOURNAL_STATUS_OK) {
 | 
			
		||||
                activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
 | 
			
		||||
                if (activeJournal->callback) {
 | 
			
		||||
                    activeJournal->callback(rc,
 | 
			
		||||
                                            (activeJournal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL) ?
 | 
			
		||||
                                                FLASH_JOURNAL_OPCODE_COMMIT : FLASH_JOURNAL_OPCODE_LOG_BLOB);
 | 
			
		||||
                }
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            if ((rc == JOURNAL_STATUS_OK) && (activeJournal->log.amountLeftToLog > 0)) {
 | 
			
		||||
                return; /* we've got pending asynchronous activity */
 | 
			
		||||
            }
 | 
			
		||||
            if (activeJournal->callback) {
 | 
			
		||||
                activeJournal->callback(rc, (activeJournal->state == SEQUENTIAL_JOURNAL_STATE_INITIALIZED) ?
 | 
			
		||||
                                                FLASH_JOURNAL_OPCODE_COMMIT : FLASH_JOURNAL_OPCODE_LOG_BLOB);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            printf("mtdHandler: unknown operation %u\n", operation);
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,32 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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_SEQUENTIAL_STRATEGY_SUPPORT_FUNCTIONS_H__
 | 
			
		||||
#define __FLASH_JOURNAL_SEQUENTIAL_STRATEGY_SUPPORT_FUNCTIONS_H__
 | 
			
		||||
 | 
			
		||||
#include "flash-journal-strategy-sequential/flash_journal_private.h"
 | 
			
		||||
#include "flash-journal-strategy-sequential/flash_journal_strategy_sequential.h"
 | 
			
		||||
 | 
			
		||||
extern SequentialFlashJournal_t *activeJournal;
 | 
			
		||||
 | 
			
		||||
int32_t discoverLatestLoggedBlob(SequentialFlashJournal_t *journal);
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
#endif /*__FLASH_JOURNAL_SEQUENTIAL_STRATEGY_SUPPORT_FUNCTIONS_H__*/
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,619 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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_H__
 | 
			
		||||
#define __FLASH_JOURNAL_H__
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
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
 | 
			
		||||
 * both error and success status returns. This enumeration contains all
 | 
			
		||||
 * possible error status values.
 | 
			
		||||
 */
 | 
			
		||||
typedef enum _FlashJournal_Status
 | 
			
		||||
{
 | 
			
		||||
    JOURNAL_STATUS_OK                =   0,
 | 
			
		||||
    JOURNAL_STATUS_ERROR             =  -1, ///< Unspecified error
 | 
			
		||||
    JOURNAL_STATUS_BUSY              =  -2, ///< Underlying storage is currently unavailable
 | 
			
		||||
    JOURNAL_STATUS_TIMEOUT           =  -3, ///< Timeout occurred
 | 
			
		||||
    JOURNAL_STATUS_UNSUPPORTED       =  -4, ///< Operation not supported
 | 
			
		||||
    JOURNAL_STATUS_PARAMETER         =  -5, ///< Parameter error
 | 
			
		||||
    JOURNAL_STATUS_BOUNDED_CAPACITY  =  -6, ///< Attempt to write larger than available capacity
 | 
			
		||||
    JOURNAL_STATUS_STORAGE_API_ERROR =  -7, ///< Failure from some Storage API
 | 
			
		||||
    JOURNAL_STATUS_STORAGE_IO_ERROR  =  -8, ///< Failure from underlying storage during an IO operation.
 | 
			
		||||
    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.
 | 
			
		||||
} FlashJournal_Status_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Command opcodes for flash. Completion callbacks use these codes to refer to
 | 
			
		||||
 * completing commands. Refer to \ref ARM_Flash_Callback_t.
 | 
			
		||||
 */
 | 
			
		||||
typedef enum _FlashJournal_OpCode {
 | 
			
		||||
    FLASH_JOURNAL_OPCODE_INITIALIZE,
 | 
			
		||||
    FLASH_JOURNAL_OPCODE_GET_INFO,
 | 
			
		||||
    FLASH_JOURNAL_OPCODE_READ_BLOB,
 | 
			
		||||
    FLASH_JOURNAL_OPCODE_LOG_BLOB,
 | 
			
		||||
    FLASH_JOURNAL_OPCODE_COMMIT,
 | 
			
		||||
    FLASH_JOURNAL_OPCODE_RESET,
 | 
			
		||||
} FlashJournal_OpCode_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Flash Journal information. This contains journal-metadata, and is the
 | 
			
		||||
 *     return value from calling GetInfo() on the journal driver.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct _FlashJournal_Info {
 | 
			
		||||
    uint64_t capacity;             ///< Maximum capacity (in octets) of the flash journal--i.e. the largest 'blob' which can be contained as payload.
 | 
			
		||||
    uint64_t sizeofJournaledBlob;  ///< size (in octets) of the most recently logged blob.
 | 
			
		||||
    uint32_t program_unit;         ///< Minimum programming size (in units of octets) for
 | 
			
		||||
                                   ///<   the current storage block--the one which will be used
 | 
			
		||||
                                   ///<   for the next log() operation. This value may change as we
 | 
			
		||||
                                   ///<   cycle through the blocks of the underlying MTD.
 | 
			
		||||
                                   ///<   Callers of FlashJournal_log() should refer to this field
 | 
			
		||||
                                   ///<   upon receiving the error JOURNAL_STATUS_SMALL_LOG_REQUEST
 | 
			
		||||
                                   ///<   (of when the actual amount of data logged is smaller than
 | 
			
		||||
                                   ///<   the requested amount).
 | 
			
		||||
} FlashJournal_Info_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This is the type of the command completion callback handler for the
 | 
			
		||||
 * asynchronous flash-journal APIs: initialize(), read(), log(), commit() and
 | 
			
		||||
 * reset() (which is nearly all APIs).
 | 
			
		||||
 *
 | 
			
		||||
 * @param status
 | 
			
		||||
 *          A code to indicate the status of the completed operation. For data
 | 
			
		||||
 *          transfer operations, the status field is overloaded in case of
 | 
			
		||||
 *          success to return the amount of data successfully transferred; this
 | 
			
		||||
 *          can be done safely because error codes are negative values.
 | 
			
		||||
 *
 | 
			
		||||
 * @param cmd_code
 | 
			
		||||
 *          The command op-code of type FlashJournal_OpCode_t. This value isn't
 | 
			
		||||
 *          essential for the callback, but it is expected that this information
 | 
			
		||||
 *          could be a quick and useful filter.
 | 
			
		||||
 */
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @ref FlashJournal_t is an abstraction implemented by a table of generic
 | 
			
		||||
 * operations (i.e. strategy) together with an opaque, strategy-specific
 | 
			
		||||
 * data. Taken together, the FlashJournal_t is an opaque handle containing
 | 
			
		||||
 * such top-level metadata.
 | 
			
		||||
 *
 | 
			
		||||
 * Algorithms depending on the FlashJournal can be generic (i.e. independent of
 | 
			
		||||
 * the strategy) in their use of the Flash-Journal APIs. For the sake of being
 | 
			
		||||
 * able to allocate a FlashJournal_t for use in such generic algorithms, the
 | 
			
		||||
 * FlashJournal_t contains a MAX_SIZE to accommodate the largest of the
 | 
			
		||||
 * 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
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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 {
 | 
			
		||||
    /**
 | 
			
		||||
     * \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);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * \brief fetch journal metadata. Refer to @ref FlashJournal_getInfo.
 | 
			
		||||
     */
 | 
			
		||||
    FlashJournal_Status_t (*getInfo)   (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);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @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);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @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);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief Reset the journal. This has the effect of erasing all valid blobs.
 | 
			
		||||
     *     Refer to @ref FlashJournal_reset.
 | 
			
		||||
     */
 | 
			
		||||
    int32_t               (*reset)     (FlashJournal_t *journal);
 | 
			
		||||
} FlashJournal_Ops_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief An opaque handle constituting the Flash Journal.
 | 
			
		||||
 *
 | 
			
		||||
 * @details This structure is intentionally opaque to avoid exposing data
 | 
			
		||||
 *     internal to an implementation strategy; this prevents accesses through any
 | 
			
		||||
 *     means other than through the defined API.
 | 
			
		||||
 *
 | 
			
		||||
 * Having a known size for the handle allows the caller to remain malloc-free.
 | 
			
		||||
 *
 | 
			
		||||
 * @note: There should be static asserts in the code to verify our assumption
 | 
			
		||||
 * that the real FlashJournal handle fits within FLASH_JOURNAL_HANDLE_MAX_SIZE
 | 
			
		||||
 * bytes.
 | 
			
		||||
 *
 | 
			
		||||
 * @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 {
 | 
			
		||||
    FlashJournal_Ops_t       ops;
 | 
			
		||||
 | 
			
		||||
    union {
 | 
			
		||||
        ARM_DRIVER_STORAGE  *mtd;
 | 
			
		||||
        FlashJournal_Info_t  info;
 | 
			
		||||
        void                *pointer;
 | 
			
		||||
        uint8_t              octet;
 | 
			
		||||
        uint32_t             data[FLASH_JOURNAL_HANDLE_MAX_SIZE / sizeof(uint32_t)];
 | 
			
		||||
    } opaque;
 | 
			
		||||
} FlashJournal_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Initialize a flash journal.
 | 
			
		||||
 *
 | 
			
		||||
 * This is a front-end for @ref FlashJournal_Ops_t::initialize() of the
 | 
			
		||||
 * underlying strategy.
 | 
			
		||||
 *
 | 
			
		||||
 * This function must be called *before* the middle-ware component starts
 | 
			
		||||
 * using a journal. As a part of bringing the journal to a ready state, it
 | 
			
		||||
 * also discovers the most recently logged blob.
 | 
			
		||||
 *
 | 
			
		||||
 * Initialize() receives a callback handler to be invoked upon completion of
 | 
			
		||||
 * asynchronous operations.
 | 
			
		||||
 *
 | 
			
		||||
 * @param [out] journal
 | 
			
		||||
 *                A caller-supplied buffer large enough to hold an
 | 
			
		||||
 *                initialized journal. The internals of the actual journal
 | 
			
		||||
 *                are opaque to the caller and depend on the logging
 | 
			
		||||
 *                strategy (as defined by the parameter 'ops'). This memory
 | 
			
		||||
 *                should be at least as large as 'FLASH_JOURNAL_HANDLE_MAX_SIZE'.
 | 
			
		||||
 *                Upon successful return, the journal is setup in an
 | 
			
		||||
 *                initialized state.
 | 
			
		||||
 *
 | 
			
		||||
 * @param  [in] mtd
 | 
			
		||||
 *                The underlying Storage_Driver targeted by the journal. MTD
 | 
			
		||||
 *                stands for Memory-Technology-Device.
 | 
			
		||||
 *
 | 
			
		||||
 * @param  [in] ops
 | 
			
		||||
 *                This is the set of operations which define the logging strategy.
 | 
			
		||||
 *
 | 
			
		||||
 * @param  [in] callback
 | 
			
		||||
 *                Caller-defined callback to be invoked upon command completion of
 | 
			
		||||
 *                initialization; and also for all future invocations of
 | 
			
		||||
 *                asynchronous APIs. 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
 | 
			
		||||
 *     JOURNAL_STATUS_OK 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 = FlashJournal_initialize(&journal, MTD, &STRATEGY_SEQUENTIAL, 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
 | 
			
		||||
 */
 | 
			
		||||
static inline int32_t FlashJournal_initialize(FlashJournal_t           *journal,
 | 
			
		||||
                                              ARM_DRIVER_STORAGE       *mtd,
 | 
			
		||||
                                              const FlashJournal_Ops_t *ops,
 | 
			
		||||
                                              FlashJournal_Callback_t   callback)
 | 
			
		||||
{
 | 
			
		||||
    return ops->initialize(journal, mtd, ops, callback);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Fetch journal metadata. A front-end for @ref FlashJournal_Ops_t::getInfo().
 | 
			
		||||
 *
 | 
			
		||||
 * @param [in] journal
 | 
			
		||||
 *                A previously initialized journal.
 | 
			
		||||
 *
 | 
			
		||||
 * @param [out] info
 | 
			
		||||
 *                A caller-supplied buffer capable of being filled in with an
 | 
			
		||||
 *                FlashJournal_Info_t.
 | 
			
		||||
 *
 | 
			
		||||
 * @return JOURNAL_STATUS_OK if a FlashJournal_Info_t structure containing
 | 
			
		||||
 *         top level metadata about the journal is filled into the supplied
 | 
			
		||||
 *         buffer, else an appropriate error value.
 | 
			
		||||
 *
 | 
			
		||||
 * @note It is the caller's responsibility to ensure that the buffer passed in
 | 
			
		||||
 *         is able to be initialized with a FlashJournal_Info_t.
 | 
			
		||||
 *
 | 
			
		||||
 * @note getInfo()s can still be called during a sequence of
 | 
			
		||||
 *     log()s.
 | 
			
		||||
 *
 | 
			
		||||
 * @note This API returns synchronously--it does not result in an invocation
 | 
			
		||||
 *     of a completion callback.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 *     FlashJournal_Info_t info;
 | 
			
		||||
 *     int32_t returnValue = FlashJournal_getInfo(&journal, &info);
 | 
			
		||||
 *     if (returnValue < JOURNAL_STATUS_OK) {
 | 
			
		||||
 *         // handle error
 | 
			
		||||
 *     } else {
 | 
			
		||||
 *         ASSERT(returnValue == JOURNAL_STATUS_OK);
 | 
			
		||||
 *         // work with the 'info'.
 | 
			
		||||
 *     }
 | 
			
		||||
 * \endcode
 | 
			
		||||
 */
 | 
			
		||||
static inline FlashJournal_Status_t FlashJournal_getInfo(FlashJournal_t *journal, FlashJournal_Info_t *info)
 | 
			
		||||
{
 | 
			
		||||
    return journal->ops.getInfo(journal, info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Read from the most recently logged blob. A front-end for @ref
 | 
			
		||||
 * FlashJournal_Ops_t::read().
 | 
			
		||||
 *
 | 
			
		||||
 * @details Read off a chunk of the logged blob sequentially. The blob may
 | 
			
		||||
 *     be larger than the size of the read (or even of available SRAM), so
 | 
			
		||||
 *     multiple calls to read() could be necessary before the entire blob is
 | 
			
		||||
 *     read off. The journal maintains a read-pointer internally to allow
 | 
			
		||||
 *     reads to continue where the previous one left off.
 | 
			
		||||
 *
 | 
			
		||||
 * @note: Once the entire blob is read, the final read() 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 [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_read(&journal, 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_read(FlashJournal_t *journal, void *blob, size_t n)
 | 
			
		||||
{
 | 
			
		||||
    return journal->ops.read(journal, 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().
 | 
			
		||||
 *
 | 
			
		||||
 * @details Extend (or start off) the currently logged blob sequentially.
 | 
			
		||||
 *     There could be several calls to log() before the entire blob is
 | 
			
		||||
 *     accumulated. A sequence of one or more log() must be terminated by a
 | 
			
		||||
 *     commit() before the state of the blob is sealed and made persistent.
 | 
			
		||||
 *     The journal maintains a log-pointer internally to allow
 | 
			
		||||
 *     log()s to continue where the previous one left off.
 | 
			
		||||
 *
 | 
			
		||||
 * @param [in] journal
 | 
			
		||||
 *               A previously initialized journal.
 | 
			
		||||
 *
 | 
			
		||||
 * @param [in] blob
 | 
			
		||||
 *               The source of the log operation. The memory is owned
 | 
			
		||||
 *               by the caller and should remain valid for the lifetime
 | 
			
		||||
 *               of this operation.
 | 
			
		||||
 *
 | 
			
		||||
 * @param [in] size
 | 
			
		||||
 *               The amount of data being logged in this operation. The
 | 
			
		||||
 *               buffer pointed to by 'blob' should be as large as this
 | 
			
		||||
 *               amount.
 | 
			
		||||
 *
 | 
			
		||||
 * @return [please be sure to read notes (below) regarding other return values]
 | 
			
		||||
 *   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
 | 
			
		||||
 *     logged, 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 log
 | 
			
		||||
 *     operation can be finished synchronously in spite of
 | 
			
		||||
 *     ARM_STORAGE_CAPABILITIES::asynchronous_ops being set, returning the
 | 
			
		||||
 *     number of data items logged 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.
 | 
			
		||||
 *
 | 
			
		||||
 * @note If a log operation will exceed available capacity, it fails with the
 | 
			
		||||
 *     error JOURNAL_STATUS_BOUNDED_CAPACITY.
 | 
			
		||||
 *
 | 
			
		||||
 * @note The actual size of data transfer (as reported by the status
 | 
			
		||||
 *     parameter of the callback or the return value from log() in case of
 | 
			
		||||
 *     synchronous operation) may be smaller than the amount requested. This
 | 
			
		||||
 *     could be due to the 'program_unit' of the underlying storage block--
 | 
			
		||||
 *     i.e. the minimum programmable size. Refer to @ref
 | 
			
		||||
 *     FlashJournal_Info_t::program_unit. It is the caller's responsibility
 | 
			
		||||
 *     for resubmitting this left-over data in a subsequent call to log.
 | 
			
		||||
 *     When logging an arbitrary amount of data, the last of a sequence of
 | 
			
		||||
 *     logs may need to be padded in order to align with the
 | 
			
		||||
 *     programming unit.
 | 
			
		||||
 *
 | 
			
		||||
 * @note If the total size requested to be logged is smaller
 | 
			
		||||
 *     than the MTD's program_unit, log() fails with an error value of
 | 
			
		||||
 *     JOURNAL_STATUS_SMALL_LOG_REQUEST.
 | 
			
		||||
 *
 | 
			
		||||
 * @note the data being logged isn't made persistent (or available for read-
 | 
			
		||||
 *     backs) until a commit. A sequence of log() operations is expected to end
 | 
			
		||||
 *     in a commit(). A new sequence of log()s should be initiated by the caller
 | 
			
		||||
 *     only after a commit() has completed. If a sequence of logs() is followed
 | 
			
		||||
 *     by an operation other than a commit, that operation will very likely
 | 
			
		||||
 *     return an error code. getInfo()s can still be called during a sequence of
 | 
			
		||||
 *     log()s.
 | 
			
		||||
 *
 | 
			
		||||
 * 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_log(&journal, 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
 | 
			
		||||
 *
 | 
			
		||||
 *         if (returnValue < size) {
 | 
			
		||||
 *     #if DEBUG
 | 
			
		||||
 *             FlashJournal_Info_t info;
 | 
			
		||||
 *             int32_t rc = FlashJournal_getInfo(&journal, &info);
 | 
			
		||||
 *             ASSERT(rc == JOURNAL_STATUS_OK);
 | 
			
		||||
 *             ASSERT(returnValue == (size - (size % info.program_unit)));
 | 
			
		||||
 *     #endif
 | 
			
		||||
 *             // move the last (size - returnValue) bytes of the buffer to the
 | 
			
		||||
 *             // beginning of the buffer to be used for the successive request.
 | 
			
		||||
 *         }
 | 
			
		||||
 *     }
 | 
			
		||||
 * \endcode
 | 
			
		||||
 */
 | 
			
		||||
static inline int32_t FlashJournal_log(FlashJournal_t *journal, const void *blob, size_t n)
 | 
			
		||||
{
 | 
			
		||||
    return journal->ops.log(journal, blob, n);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Commit a blob accumulated through a (possibly empty) sequence of previously
 | 
			
		||||
 *     successful log() operations. A front-end for @ref FlashJournal_Ops_t::commit().
 | 
			
		||||
 *
 | 
			
		||||
 * @param  [in] journal
 | 
			
		||||
 *                A previously initialized journal.
 | 
			
		||||
 *
 | 
			
		||||
 * @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 1 passed in as the 'status' parameter of the callback to indicate
 | 
			
		||||
 *     success. 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 1 to indicate success, 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
 | 
			
		||||
 *     commit operation can be finished synchronously in spite of
 | 
			
		||||
 *     ARM_STORAGE_CAPABILITIES::asynchronous_ops being set, returning the
 | 
			
		||||
 *     total size of the committed blob 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_commit(&journal);
 | 
			
		||||
 *     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 {
 | 
			
		||||
 *         // handle synchronous completion
 | 
			
		||||
 *         ASSERT(returnValue == 1);
 | 
			
		||||
 *         ...
 | 
			
		||||
 *     }
 | 
			
		||||
 * \endcode
 | 
			
		||||
 *
 | 
			
		||||
 * @note A sequence of log() operations is expected to end in a commit(). A new
 | 
			
		||||
 *     sequence of log()s should be initiated by the caller only after a
 | 
			
		||||
 *     commit() has completed. If a sequence of logs() is followed
 | 
			
		||||
 *     by an operation other than a commit, that operation will very likely
 | 
			
		||||
 *     return an error code.
 | 
			
		||||
 */
 | 
			
		||||
static inline int32_t FlashJournal_commit(FlashJournal_t *journal)
 | 
			
		||||
{
 | 
			
		||||
    return journal->ops.commit(journal);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Reset the journal. This has the effect of erasing all valid blobs. A
 | 
			
		||||
 *     front-end for @ref FlashJournal_Ops_t::reset().
 | 
			
		||||
 *
 | 
			
		||||
 * @param [in] journal
 | 
			
		||||
 *               A previously initialized journal.
 | 
			
		||||
 *
 | 
			
		||||
 * @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
 | 
			
		||||
 *     JOURNAL_STATUS_OK 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 1 to signal
 | 
			
		||||
 *     successful completion, 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
 | 
			
		||||
 *     reset operation can be finished synchronously in spite of
 | 
			
		||||
 *     ARM_STORAGE_CAPABILITIES::asynchronous_ops being set, returning 1 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_reset(&journal);
 | 
			
		||||
 *     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
 | 
			
		||||
 */
 | 
			
		||||
static inline int32_t FlashJournal_reset(FlashJournal_t *journal)
 | 
			
		||||
{
 | 
			
		||||
    return journal->ops.reset(journal);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif // __cplusplus
 | 
			
		||||
 | 
			
		||||
#endif /* __FLASH_JOURNAL_H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -187,7 +187,7 @@ class Config:
 | 
			
		|||
 | 
			
		||||
    # Allowed features in configurations
 | 
			
		||||
    __allowed_features = [
 | 
			
		||||
        "UVISOR", "BLE", "CLIENT", "IPV4", "IPV6", "COMMON_PAL"
 | 
			
		||||
        "UVISOR", "BLE", "CLIENT", "IPV4", "IPV6", "COMMON_PAL", "STORAGE"
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    # The initialization arguments for Config are:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||