|
@ -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;
|
||||
static 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;
|
||||
static 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
|
||||
|
||||
static 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__ */
|
|
@ -572,7 +572,7 @@
|
|||
"progen": {"target": "frdm-k64f"},
|
||||
"detect_code": ["0240"],
|
||||
"device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "STORAGE"],
|
||||
"features": ["IPV4"],
|
||||
"features": ["IPV4", "STORAGE"],
|
||||
"release": true
|
||||
},
|
||||
"MTS_GAMBIT": {
|
||||
|
|
|
@ -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:
|
||||
|
|