Merge pull request #10258 from davidsaada/david_remove_feature_storage

Remove FEATURE_STORAGE and all underlying deprecated features
pull/10503/head
Anna Bridge 2019-04-26 13:31:37 +01:00 committed by GitHub
commit b1cd3dab16
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
103 changed files with 2 additions and 29583 deletions

View File

@ -16,7 +16,6 @@
^features/nanostack/sal-stack-nanostack
^features/nanostack/targets
^features/netsocket/emac-drivers
^features/storage/FEATURE_STORAGE
^features/storage/filesystem/fat/ChaN
^features/storage/filesystem/littlefs/littlefs/
^features/unsupported/

View File

@ -843,8 +843,6 @@ EXCLUDE_PATTERNS = */tools/* \
*/cmsis/* \
*/features/cryptocell/* \
*/features/mbedtls/* \
*/features/storage/cfstore/* \
*/features/storage/FEATURE_STORAGE/* \
*/features/unsupported/* \
*/features/lwipstack/* \
*/features/nanostack/sal-stack-nanostack/* \

View File

@ -10,7 +10,7 @@
"EXPAND_AS_DEFINED": "",
"SKIP_FUNCTION_MACROS": "NO",
"STRIP_CODE_COMMENTS": "NO",
"EXCLUDE_PATTERNS": "*/tools/* */targets/* */features/mbedtls/* */features/storage/cfstore/* */features/storage/FEATURE_STORAGE/* */features/unsupported/* */BUILD/* */rtos/TARGET_CORTEX/rtx*/* */cmsis/* */features/lwipstack/* */nanostack/sal-stack-nanostack/* */nanostack/coap-service/* */ble/generic/* */ble/pal/* */mbed-trace/* */mbed-coap/* */nanostack-libservice/* */mbed-client-randlib/* */nanostack/sal-stack-nanostack-eventloop/* */components/802.15.4_RF/* */components/wifi/* */features/nfc/stack/* */UNITTESTS/* */features/cryptocell/*",
"EXCLUDE_PATTERNS": "*/tools/* */targets/* */features/mbedtls/* */features/unsupported/* */BUILD/* */rtos/TARGET_CORTEX/rtx*/* */cmsis/* */features/lwipstack/* */nanostack/sal-stack-nanostack/* */nanostack/coap-service/* */ble/generic/* */ble/pal/* */mbed-trace/* */mbed-coap/* */nanostack-libservice/* */mbed-client-randlib/* */nanostack/sal-stack-nanostack-eventloop/* */components/802.15.4_RF/* */components/wifi/* */features/nfc/stack/* */UNITTESTS/* */features/cryptocell/*",
"ALPHABETICAL_INDEX": "NO",
"CASE_SENSE_NAMES": "NO",
"DOT_MULTI_TARGETS": "YES",

View File

@ -1,663 +0,0 @@
/*
* Copyright (c) 2016, 2018, Arm Limited and affiliates.
* 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.
*/
/*
* NVM adaptation to Configuration Store that is storing Key-Value pairs to SRAM or flash.
*/
/*
* Application needs to enable MBED_CONF_NANOSTACK_HAL_NVM_CFSTORE in its configuration in
* order to use configuration-store. Application also needs to define storage area start
* address in flash (CONFIG_HARDWARE_MTD_START_ADDR) and storage size (CONFIG_HARDWARE_MTD_SIZE).
*/
#if MBED_CONF_NANOSTACK_HAL_NVM_CFSTORE
#include <stdio.h>
#include <string.h>
#include <ns_types.h>
#include "configuration-store/configuration_store.h"
// #define HAVE_DEBUG
#include "ns_trace.h"
#include "nsdynmemLIB.h"
#include "eventOS_event_timer.h"
#include "platform/arm_hal_nvm.h"
#define TRACE_GROUP "pnvm"
// Timeout for polling response from configuration store
#define NVM_CB_POLLING_TIMEOUT 50
// Check if synchronous mode is enabled
#define IS_SYNC_MODE(cs_ctx) ((cs_ctx)->capabilities.asynchronous_ops == 0)
// NVM internal states
typedef enum cfstore_state_t {
NVM_STATE_NONE,
NVM_STATE_INIT_DONE,
NVM_STATE_CREATING,
NVM_STATE_CREATE_DONE,
NVM_STATE_OPENING,
NVM_STATE_OPEN_DONE,
NVM_STATE_WRITING,
NVM_STATE_WRITE_DONE,
NVM_STATE_CLOSING,
NVM_STATE_CLOSE_DONE,
NVM_STATE_FLUSHING,
NVM_STATE_FLUSH_DONE,
NVM_STATE_READING,
NVM_STATE_READ_DONE,
NVM_STATE_DELETING,
NVM_STATE_DELETE_DONE,
NVM_STATE_UNINITIALIZING,
NVM_STATE_UNINIT_DONE
} nvm_state_e;
// NVM context
typedef struct cfstore_context_s {
ARM_CFSTORE_CAPABILITIES capabilities;
//TODO: Fix hkey length once CFSTORE_HANDLE_BUFSIZE becomes visible
uint8_t hkey[/*CFSTORE_HANDLE_BUFSIZE*/40]; // Handle to the key in process
ARM_CFSTORE_SIZE data_len; // Data length cfstore is using
nvm_state_e state; // current nvm_state_e
timeout_t *callback_timer; // timer handle for informing client
nvm_callback *client_cb; // callback provided by client
void *client_context; // context provided by client
platform_nvm_status client_status; // status to be returned to client
uint8_t *client_buf; // buffer provided by client
uint16_t *client_buf_len; // client buffer length
} cs_context_t;
ARM_CFSTORE_DRIVER *drv = &cfstore_driver;
static cs_context_t *cs_context_ptr = NULL;
// forward declarations
static bool nvm_write_internal(cs_context_t *cf_context);
static bool nvm_read_internal(cs_context_t *cf_context);
static bool nvm_delete_internal(cs_context_t *cf_context);
static bool nvm_close_internal(cs_context_t *cf_context);
static bool nvm_status_check(cs_context_t *cf_context);
static platform_nvm_status nvm_error_map(int32_t cs_error);
static void nvm_fsm_timer_start(void);
static void nvm_fsm_timer_cb(void *arg);
/**
* Configuration store callback
*/
static void configuration_store_cb(int32_t status, ARM_CFSTORE_OPCODE cmd_code, void *ctx, ARM_CFSTORE_HANDLE handle)
{
tr_debug("configuration_store_cb status=%d, cmd_code=%d, ctx=%x, hndl=%x", (int)status, (int)cmd_code, (unsigned int)ctx, (unsigned int)handle);
cs_context_t *cf_context = (cs_context_t *)ctx;
switch (cmd_code) {
case CFSTORE_OPCODE_INITIALIZE:
tr_debug("CFSTORE_OPCODE_INITIALIZE %d", (int)status);
cf_context->state = NVM_STATE_INIT_DONE;
cf_context->client_status = nvm_error_map(status);
break;
case CFSTORE_OPCODE_POWER_CONTROL:
tr_debug("CFSTORE_OPCODE_POWER_CONTROL %d", (int)status);
// do nothing for power control
break;
case CFSTORE_OPCODE_CREATE:
tr_debug("CFSTORE_OPCODE_CREATE %d", (int)status);
cf_context->client_status = nvm_error_map(status);
cf_context->state = NVM_STATE_CREATE_DONE;
if (status >= ARM_DRIVER_OK) {
// key created successfully, close the key
if (nvm_close_internal(cf_context) == false) {
// closing failed
// Ignore errors in close as closing recreated keys returns error
// cf_context->state = NVM_STATE_CLOSE_DONE;
// cf_context->client_status = PLATFORM_NVM_ERROR;
} else {
// closing OK, wait for CFSTORE_OPCODE_CLOSE callback
}
}
break;
case CFSTORE_OPCODE_OPEN:
tr_debug("CFSTORE_OPCODE_OPEN %d", (int)status);
if (status < ARM_DRIVER_OK) {
// opening failed, do not continue any further
cf_context->client_status = nvm_error_map(status);
cf_context->state = NVM_STATE_OPEN_DONE;
break;
}
// proceed to client action read/write/delete
if (cf_context->state == NVM_STATE_WRITING) {
if (nvm_write_internal(cf_context) == false) {
/* reading failed set client_status */
cf_context->client_status = PLATFORM_NVM_ERROR;
} else {
// writing OK, wait for CFSTORE_OPCODE_WRITE callback
}
} else if (cf_context->state == NVM_STATE_READING) {
if (nvm_read_internal(cf_context) == false) {
/* reading failed set client_status */
cf_context->client_status = PLATFORM_NVM_ERROR;
} else {
// reading in progress, wait for CFSTORE_OPCODE_READ callback
}
} else if (cf_context->state == NVM_STATE_DELETING) {
if (nvm_delete_internal(cf_context) == false) {
/* reading failed set client_status */
cf_context->client_status = PLATFORM_NVM_ERROR;
} else {
// deleting in progress, wait for CFSTORE_OPCODE_DELETE callback
}
}
if (cf_context->client_status == PLATFORM_NVM_ERROR) {
// read/write/delete operation failed, close the handle
if (nvm_close_internal(cf_context) == false) {
cf_context->state = NVM_STATE_CLOSE_DONE;
cf_context->client_status = PLATFORM_NVM_ERROR;
}
}
break;
case CFSTORE_OPCODE_WRITE:
tr_debug("CFSTORE_OPCODE_WRITE %d", (int)status);
cf_context->state = NVM_STATE_WRITE_DONE;
*cf_context->client_buf_len = cf_context->data_len;
if (nvm_close_internal(cf_context) == false) {
/* writing failed set status and start callback timer */
cf_context->state = NVM_STATE_CLOSE_DONE;
cf_context->client_status = PLATFORM_NVM_ERROR;
} else {
// closing OK, wait for CFSTORE_OPCODE_CLOSE callback
}
break;
case CFSTORE_OPCODE_READ:
tr_debug("CFSTORE_OPCODE_READ %d", (int)status);
cf_context->state = NVM_STATE_READ_DONE;
if (nvm_close_internal(cf_context) == false) {
cf_context->state = NVM_STATE_CLOSE_DONE;
cf_context->client_status = PLATFORM_NVM_ERROR;
} else {
// closing OK, wait for CFSTORE_OPCODE_CLOSE callback
*cf_context->client_buf_len = (uint16_t)status; // save the bytes read
}
break;
case CFSTORE_OPCODE_DELETE:
tr_debug("CFSTORE_OPCODE_DELETE %d", (int)status);
if (nvm_close_internal(cf_context) == false) {
/* closing failed set client_status */
cf_context->state = NVM_STATE_CLOSE_DONE;
cf_context->client_status = PLATFORM_NVM_ERROR;
} else {
// closing OK, wait for CFSTORE_OPCODE_CLOSE callback
}
break;
case CFSTORE_OPCODE_CLOSE:
tr_debug("CFSTORE_OPCODE_CLOSE %d", (int)status);
cf_context->state = NVM_STATE_CLOSE_DONE;
// client_status is already set by read/write/delete operation, do not override it
break;
case CFSTORE_OPCODE_UNINITIALIZE:
tr_debug("CFSTORE_OPCODE_UNINITIALIZE %d", (int)status);
cf_context->state = NVM_STATE_UNINIT_DONE;
cf_context->client_status = nvm_error_map(status);
break;
case CFSTORE_OPCODE_FLUSH:
tr_debug("CFSTORE_OPCODE_FLUSH %d", (int)status);
cf_context->state = NVM_STATE_FLUSH_DONE;
cf_context->client_status = nvm_error_map(status);
break;
default:
tr_debug("unhandled cmd_code %d", cmd_code);
break;
}
return;
}
static int nvm_fsm_update(cs_context_t *cs_context)
{
int ret_val = 0;
tr_debug("nvm_fsm_update() state=%d", (int)cs_context->state);
switch (cs_context->state) {
case NVM_STATE_UNINIT_DONE:
cs_context->client_cb(cs_context->client_status, cs_context->client_context);
cs_context->state = NVM_STATE_NONE;
if (cs_context->client_status == PLATFORM_NVM_OK) {
ns_dyn_mem_free(cs_context_ptr);
cs_context_ptr = NULL;
}
ret_val = 1;
break;
case NVM_STATE_INIT_DONE:
case NVM_STATE_CREATE_DONE:
case NVM_STATE_OPEN_DONE:
case NVM_STATE_WRITE_DONE:
case NVM_STATE_READ_DONE:
case NVM_STATE_DELETE_DONE:
case NVM_STATE_CLOSE_DONE:
case NVM_STATE_FLUSH_DONE:
cs_context->state = NVM_STATE_NONE;
cs_context->client_cb(cs_context->client_status, cs_context->client_context);
ret_val = 1;
break;
default:
tr_error("unknown state %d", cs_context->state);
break;
}
return ret_val;
}
/**
* Initialize NVM
*/
platform_nvm_status platform_nvm_init(nvm_callback *callback, void *context)
{
int32_t ret;
tr_debug("platform_nvm_init()");
if (callback == NULL || cs_context_ptr) {
return PLATFORM_NVM_ERROR;
}
if (cs_context_ptr == NULL) {
cs_context_ptr = ns_dyn_mem_alloc(sizeof(cs_context_t));
}
if (cs_context_ptr == NULL) {
return PLATFORM_NVM_ERROR;
}
memset(cs_context_ptr, 0, sizeof(cs_context_t));
cs_context_ptr->client_cb = callback;
cs_context_ptr->client_context = context;
cs_context_ptr->capabilities = drv->GetCapabilities();
tr_debug("mode: %s", IS_SYNC_MODE(cs_context_ptr) ? "sync" : "async");
ret = drv->Initialize(configuration_store_cb, cs_context_ptr);
if (ret < ARM_DRIVER_OK) {
tr_error("initialisation failed %d", (int)ret);
ns_dyn_mem_free(cs_context_ptr);
cs_context_ptr = NULL;
return PLATFORM_NVM_ERROR;
}
drv->PowerControl(ARM_POWER_FULL);
// start timer to report initialization status back to client
nvm_fsm_timer_start();
return PLATFORM_NVM_OK;
}
/*
* Deinitialize NVM.
*/
platform_nvm_status platform_nvm_finalize(nvm_callback *callback, void *context)
{
int32_t ret;
tr_debug("platform_nvm_deinit()");
if (!nvm_status_check(cs_context_ptr)) {
return PLATFORM_NVM_ERROR;
}
if (callback == NULL) {
return PLATFORM_NVM_ERROR;
}
cs_context_ptr->client_cb = callback;
cs_context_ptr->client_context = context;
cs_context_ptr->state = NVM_STATE_UNINITIALIZING;
cs_context_ptr->client_status = PLATFORM_NVM_OK;
drv->PowerControl(ARM_POWER_OFF);
ret = drv->Uninitialize();
if (ret < ARM_DRIVER_OK) {
tr_error("deinit failed %d", (int)ret);
cs_context_ptr->state = NVM_STATE_UNINIT_DONE;
cs_context_ptr->client_status = nvm_error_map(ret);
}
nvm_fsm_timer_start();
return PLATFORM_NVM_OK;
}
/*
* Create key to NVM
*/
platform_nvm_status platform_nvm_key_create(nvm_callback *callback, const char *key_name, uint16_t value_len, uint32_t flags, void *context)
{
int32_t ret;
ARM_CFSTORE_KEYDESC keydesc;
(void)flags;
tr_debug("platform_nvm_key_create() %s len=%d", key_name, value_len);
if (callback == NULL || key_name == NULL) {
return PLATFORM_NVM_ERROR;
}
if (!nvm_status_check(cs_context_ptr)) {
return PLATFORM_NVM_ERROR;
}
cs_context_ptr->client_cb = callback;
cs_context_ptr->client_context = context;
cs_context_ptr->state = NVM_STATE_CREATING;
cs_context_ptr->client_status = PLATFORM_NVM_OK;
memset(&keydesc, 0, sizeof(ARM_CFSTORE_KEYDESC));
keydesc.drl = ARM_RETENTION_NVM;
ret = drv->Create(key_name, value_len, &keydesc, cs_context_ptr->hkey);
if (ret < ARM_DRIVER_OK) {
if (ret == ARM_CFSTORE_DRIVER_ERROR_PREEXISTING_KEY) {
tr_debug("adjust value len to %d", value_len);
ret = drv->Create(key_name, value_len, NULL, cs_context_ptr->hkey);
}
}
if (ret < ARM_DRIVER_OK) {
tr_error("Key creation failed %d", (int)ret);
cs_context_ptr->state = NVM_STATE_CREATE_DONE;
cs_context_ptr->client_status = nvm_error_map(ret);
}
nvm_fsm_timer_start();
return PLATFORM_NVM_OK;
}
/**
* Delete key from NVM
*/
platform_nvm_status platform_nvm_key_delete(nvm_callback *callback, const char *key_name, void *context)
{
int32_t ret;
ARM_CFSTORE_FMODE flags;
tr_debug("platform_nvm_key_delete() %s", key_name);
if (callback == NULL || key_name == NULL) {
return PLATFORM_NVM_ERROR;
}
if (!nvm_status_check(cs_context_ptr)) {
return PLATFORM_NVM_ERROR;
}
cs_context_ptr->client_cb = callback;
cs_context_ptr->client_context = context;
cs_context_ptr->client_status = PLATFORM_NVM_OK;
cs_context_ptr->state = NVM_STATE_DELETING;
memset(&flags, 0, sizeof(ARM_CFSTORE_FMODE));
flags.read = 1;
flags.write = 1;
ret = drv->Open(key_name, flags, cs_context_ptr->hkey);
if (ret < ARM_DRIVER_OK) {
tr_error("Key delete, open failed %d", (int)ret);
cs_context_ptr->state = NVM_STATE_DELETE_DONE;
cs_context_ptr->client_status = nvm_error_map(ret);
}
// start callback timer in both asynch and synch mode
nvm_fsm_timer_start();
return PLATFORM_NVM_OK;
}
/**
* Reading from NVM
*/
platform_nvm_status platform_nvm_read(nvm_callback *callback, const char *key_name, void *buf, uint16_t *buf_len, void *context)
{
int32_t ret;
ARM_CFSTORE_FMODE flags;
tr_debug("platform_nvm_read()");
if (callback == NULL || key_name == NULL || buf == NULL || buf_len == NULL) {
return PLATFORM_NVM_ERROR;
}
if (!nvm_status_check(cs_context_ptr)) {
return PLATFORM_NVM_ERROR;
}
cs_context_ptr->client_cb = callback;
cs_context_ptr->client_context = context;
cs_context_ptr->client_buf = buf;
cs_context_ptr->client_buf_len = buf_len;
cs_context_ptr->data_len = *buf_len;
cs_context_ptr->client_status = PLATFORM_NVM_OK;
cs_context_ptr->state = NVM_STATE_READING;
// Open handle for reading
memset(&flags, 0, sizeof(ARM_CFSTORE_FMODE));
flags.read = 1;
ret = drv->Open(key_name, flags, cs_context_ptr->hkey);
if (ret < ARM_DRIVER_OK) {
tr_error("Read failed to open handle %d", (int)ret);
cs_context_ptr->state = NVM_STATE_READ_DONE;
cs_context_ptr->client_status = nvm_error_map(ret);
}
// start callback timer in both async and synch mode
nvm_fsm_timer_start();
return PLATFORM_NVM_OK;
}
/**
* Write to NVM.
*/
platform_nvm_status platform_nvm_write(nvm_callback *callback, const char *key_name, const void *data, uint16_t *data_len, void *context)
{
int32_t ret;
ARM_CFSTORE_FMODE flags;
tr_debug("platform_nvm_write()");
if (callback == NULL || key_name == NULL || data == NULL || data_len == NULL) {
return PLATFORM_NVM_ERROR;
}
if (!nvm_status_check(cs_context_ptr)) {
return PLATFORM_NVM_ERROR;
}
cs_context_ptr->client_cb = callback;
cs_context_ptr->client_context = context;
cs_context_ptr->client_buf = (void *)data;
cs_context_ptr->client_buf_len = data_len;
cs_context_ptr->data_len = *data_len;
cs_context_ptr->client_status = PLATFORM_NVM_OK;
cs_context_ptr->state = NVM_STATE_WRITING;
// Open handle for writing, execution continues in callback
memset(&flags, 0, sizeof(ARM_CFSTORE_FMODE));
flags.write = 1;
ret = drv->Open(key_name, flags, cs_context_ptr->hkey);
if (ret < ARM_DRIVER_OK) {
tr_error("Write failed %d", (int)ret);
cs_context_ptr->state = NVM_STATE_WRITE_DONE;
cs_context_ptr->client_status = nvm_error_map(ret);
}
// start callback timer in both asynch and synch mode
nvm_fsm_timer_start();
return PLATFORM_NVM_OK;
}
/**
* Flush the NVM
*/
platform_nvm_status platform_nvm_flush(nvm_callback *callback, void *context)
{
tr_debug("platform_nvm_flush()");
int32_t ret;
if (callback == NULL) {
return PLATFORM_NVM_ERROR;
}
if (!nvm_status_check(cs_context_ptr)) {
return PLATFORM_NVM_ERROR;
}
cs_context_ptr->client_cb = callback;
cs_context_ptr->client_context = context;
cs_context_ptr->client_status = PLATFORM_NVM_OK;
cs_context_ptr->state = NVM_STATE_FLUSHING;
ret = drv->Flush();
if (ret < ARM_DRIVER_OK) {
cs_context_ptr->state = NVM_STATE_FLUSH_DONE;
cs_context_ptr->client_status = nvm_error_map(ret);
}
// start callback timer in both asynch and synch mode
nvm_fsm_timer_start();
return PLATFORM_NVM_OK;
}
static bool nvm_write_internal(cs_context_t *cf_context)
{
int32_t ret;
cf_context->state = NVM_STATE_WRITING;
ret = drv->Write(cf_context->hkey, (const char *)cf_context->client_buf, &cf_context->data_len);
if (ret >= ARM_DRIVER_OK) {
return true;
} else {
tr_error("Write failed %d", (int)ret);
return false;
}
}
static bool nvm_read_internal(cs_context_t *cf_context)
{
int32_t ret;
cf_context->state = NVM_STATE_READING;
ret = drv->Read(cf_context->hkey, (void *)cf_context->client_buf, &cf_context->data_len);
if (ret >= ARM_DRIVER_OK) {
return true;
} else {
tr_error("Read failed %d", (int)ret);
return false;
}
}
static bool nvm_delete_internal(cs_context_t *cf_context)
{
int32_t ret;
cf_context->state = NVM_STATE_DELETING;
ret = drv->Delete(cf_context->hkey);
if (ret >= ARM_DRIVER_OK) {
return true;
} else {
tr_error("Delete failed %d", (int)ret);
return false;
}
}
static bool nvm_close_internal(cs_context_t *cf_context)
{
int32_t ret;
cf_context->state = NVM_STATE_CLOSING;
ret = drv->Close(cf_context->hkey);
if (ret >= ARM_DRIVER_OK) {
return true;
} else {
tr_error("Close failed %d", (int)ret);
return false;
}
}
/*
* Check NVM state before executing client action
*/
static bool nvm_status_check(cs_context_t *cf_context)
{
if (!cs_context_ptr) {
// not initialized
tr_error("NVM not initialized");
return false;
}
if (cf_context->state != NVM_STATE_NONE) {
tr_error("NVM busy, operation in progress %d", cf_context->state);
return false;
}
return true;
}
static platform_nvm_status nvm_error_map(int32_t cs_error)
{
platform_nvm_status client_error;
if (cs_error >= ARM_DRIVER_OK) {
return PLATFORM_NVM_OK;
}
switch (cs_error) {
case ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND:
client_error = PLATFORM_NVM_KEY_NOT_FOUND;
break;
default:
client_error = PLATFORM_NVM_ERROR;
break;
}
return client_error;
}
static void nvm_fsm_timer_cb(void *args)
{
(void) args;
switch (nvm_fsm_update(cs_context_ptr)) {
case 0:
// Nothing processed, restart timer
tr_debug("nvm_fsm_timer_cb not handled event in () %d", (int)cs_context_ptr->state);
nvm_fsm_timer_start();
break;
default:
break;
}
}
/*
* Start timer for polling callback from
*/
static void nvm_fsm_timer_start(void)
{
cs_context_ptr->callback_timer = eventOS_timeout_ms(nvm_fsm_timer_cb, NVM_CB_POLLING_TIMEOUT, NULL);
}
#endif /* MBED_CONF_NANOSTACK_HAL_NVM_CFSTORE */

View File

@ -1,562 +0,0 @@
#---------
#
# MakefileWorker.mk
#
# Include this helper file in your makefile
# It makes
# A static library
# A test executable
#
# See this example for parameter settings
# examples/Makefile
#
#----------
# Inputs - these variables describe what to build
#
# INCLUDE_DIRS - Directories used to search for include files.
# This generates a -I for each directory
# SRC_DIRS - Directories containing source file to built into the library
# SRC_FILES - Specific source files to build into library. Helpful when not all code
# in a directory can be built for test (hopefully a temporary situation)
# TEST_SRC_DIRS - Directories containing unit test code build into the unit test runner
# These do not go in a library. They are explicitly included in the test runner
# TEST_SRC_FILES - Specific source files to build into the unit test runner
# These do not go in a library. They are explicitly included in the test runner
# MOCKS_SRC_DIRS - Directories containing mock source files to build into the test runner
# These do not go in a library. They are explicitly included in the test runner
#----------
# You can adjust these variables to influence how to build the test target
# and where to put and name outputs
# See below to determine defaults
# COMPONENT_NAME - the name of the thing being built
# TEST_TARGET - name the test executable. By default it is
# $(COMPONENT_NAME)_tests
# Helpful if you want 1 > make files in the same directory with different
# executables as output.
# CPPUTEST_HOME - where CppUTest home dir found
# TARGET_PLATFORM - Influences how the outputs are generated by modifying the
# CPPUTEST_OBJS_DIR and CPPUTEST_LIB_DIR to use a sub-directory under the
# normal objs and lib directories. Also modifies where to search for the
# CPPUTEST_LIB to link against.
# CPPUTEST_OBJS_DIR - a directory where o and d files go
# CPPUTEST_LIB_DIR - a directory where libs go
# CPPUTEST_ENABLE_DEBUG - build for debug
# CPPUTEST_USE_MEM_LEAK_DETECTION - Links with overridden new and delete
# CPPUTEST_USE_STD_CPP_LIB - Set to N to keep the standard C++ library out
# of the test harness
# CPPUTEST_USE_GCOV - Turn on coverage analysis
# Clean then build with this flag set to Y, then 'make gcov'
# CPPUTEST_MAPFILE - generate a map file
# CPPUTEST_WARNINGFLAGS - overly picky by default
# OTHER_MAKEFILE_TO_INCLUDE - a hook to use this makefile to make
# other targets. Like CSlim, which is part of fitnesse
# CPPUTEST_USE_VPATH - Use Make's VPATH functionality to support user
# specification of source files and directories that aren't below
# the user's Makefile in the directory tree, like:
# SRC_DIRS += ../../lib/foo
# It defaults to N, and shouldn't be necessary except in the above case.
#----------
#
# Other flags users can initialize to sneak in their settings
# CPPUTEST_CXXFLAGS - flags for the C++ compiler
# CPPUTEST_CPPFLAGS - flags for the C++ AND C preprocessor
# CPPUTEST_CFLAGS - flags for the C complier
# CPPUTEST_LDFLAGS - Linker flags
#----------
# Some behavior is weird on some platforms. Need to discover the platform.
# Platforms
UNAME_OUTPUT = "$(shell uname -a)"
MACOSX_STR = Darwin
MINGW_STR = MINGW
CYGWIN_STR = CYGWIN
LINUX_STR = Linux
SUNOS_STR = SunOS
UNKNWOWN_OS_STR = Unknown
# Compilers
CC_VERSION_OUTPUT ="$(shell $(CXX) -v 2>&1)"
CLANG_STR = clang
SUNSTUDIO_CXX_STR = SunStudio
UNAME_OS = $(UNKNWOWN_OS_STR)
ifeq ($(findstring $(MINGW_STR),$(UNAME_OUTPUT)),$(MINGW_STR))
UNAME_OS = $(MINGW_STR)
endif
ifeq ($(findstring $(CYGWIN_STR),$(UNAME_OUTPUT)),$(CYGWIN_STR))
UNAME_OS = $(CYGWIN_STR)
endif
ifeq ($(findstring $(LINUX_STR),$(UNAME_OUTPUT)),$(LINUX_STR))
UNAME_OS = $(LINUX_STR)
endif
ifeq ($(findstring $(MACOSX_STR),$(UNAME_OUTPUT)),$(MACOSX_STR))
UNAME_OS = $(MACOSX_STR)
#lion has a problem with the 'v' part of -a
UNAME_OUTPUT = "$(shell uname -pmnrs)"
endif
ifeq ($(findstring $(SUNOS_STR),$(UNAME_OUTPUT)),$(SUNOS_STR))
UNAME_OS = $(SUNOS_STR)
SUNSTUDIO_CXX_ERR_STR = CC -flags
ifeq ($(findstring $(SUNSTUDIO_CXX_ERR_STR),$(CC_VERSION_OUTPUT)),$(SUNSTUDIO_CXX_ERR_STR))
CC_VERSION_OUTPUT ="$(shell $(CXX) -V 2>&1)"
COMPILER_NAME = $(SUNSTUDIO_CXX_STR)
endif
endif
ifeq ($(findstring $(CLANG_STR),$(CC_VERSION_OUTPUT)),$(CLANG_STR))
COMPILER_NAME = $(CLANG_STR)
endif
#Kludge for mingw, it does not have cc.exe, but gcc.exe will do
ifeq ($(UNAME_OS),$(MINGW_STR))
CC := gcc
endif
#And another kludge. Exception handling in gcc 4.6.2 is broken when linking the
# Standard C++ library as a shared library. Unbelievable.
ifeq ($(UNAME_OS),$(MINGW_STR))
CPPUTEST_LDFLAGS += -static
endif
ifeq ($(UNAME_OS),$(CYGWIN_STR))
CPPUTEST_LDFLAGS += -static
endif
#Kludge for MacOsX gcc compiler on Darwin9 who can't handle pendantic
ifeq ($(UNAME_OS),$(MACOSX_STR))
ifeq ($(findstring Version 9,$(UNAME_OUTPUT)),Version 9)
CPPUTEST_PEDANTIC_ERRORS = N
endif
endif
ifndef COMPONENT_NAME
COMPONENT_NAME = name_this_in_the_makefile
endif
# Debug on by default
ifndef CPPUTEST_ENABLE_DEBUG
CPPUTEST_ENABLE_DEBUG = Y
endif
# new and delete for memory leak detection on by default
ifndef CPPUTEST_USE_MEM_LEAK_DETECTION
CPPUTEST_USE_MEM_LEAK_DETECTION = Y
endif
# Use the standard C library
ifndef CPPUTEST_USE_STD_C_LIB
CPPUTEST_USE_STD_C_LIB = Y
endif
# Use the standard C++ library
ifndef CPPUTEST_USE_STD_CPP_LIB
CPPUTEST_USE_STD_CPP_LIB = Y
endif
# Use gcov, off by default
ifndef CPPUTEST_USE_GCOV
CPPUTEST_USE_GCOV = N
endif
ifndef CPPUTEST_PEDANTIC_ERRORS
CPPUTEST_PEDANTIC_ERRORS = Y
endif
# Default warnings
ifndef CPPUTEST_WARNINGFLAGS
CPPUTEST_WARNINGFLAGS = -Wall -Wextra -Wshadow -Wswitch-default -Wswitch-enum -Wconversion
ifeq ($(CPPUTEST_PEDANTIC_ERRORS), Y)
# CPPUTEST_WARNINGFLAGS += -pedantic-errors
CPPUTEST_WARNINGFLAGS += -pedantic
endif
ifeq ($(UNAME_OS),$(LINUX_STR))
CPPUTEST_WARNINGFLAGS += -Wsign-conversion
endif
CPPUTEST_CXX_WARNINGFLAGS = -Woverloaded-virtual
CPPUTEST_C_WARNINGFLAGS = -Wstrict-prototypes
endif
#Wonderful extra compiler warnings with clang
ifeq ($(COMPILER_NAME),$(CLANG_STR))
# -Wno-disabled-macro-expansion -> Have to disable the macro expansion warning as the operator new overload warns on that.
# -Wno-padded -> I sort-of like this warning but if there is a bool at the end of the class, it seems impossible to remove it! (except by making padding explicit)
# -Wno-global-constructors Wno-exit-time-destructors -> Great warnings, but in CppUTest it is impossible to avoid as the automatic test registration depends on the global ctor and dtor
# -Wno-weak-vtables -> The TEST_GROUP macro declares a class and will automatically inline its methods. Thats ok as they are only in one translation unit. Unfortunately, the warning can't detect that, so it must be disabled.
CPPUTEST_CXX_WARNINGFLAGS += -Weverything -Wno-disabled-macro-expansion -Wno-padded -Wno-global-constructors -Wno-exit-time-destructors -Wno-weak-vtables
CPPUTEST_C_WARNINGFLAGS += -Weverything -Wno-padded
endif
# Uhm. Maybe put some warning flags for SunStudio here?
ifeq ($(COMPILER_NAME),$(SUNSTUDIO_CXX_STR))
CPPUTEST_CXX_WARNINGFLAGS =
CPPUTEST_C_WARNINGFLAGS =
endif
# Default dir for temporary files (d, o)
ifndef CPPUTEST_OBJS_DIR
ifndef TARGET_PLATFORM
CPPUTEST_OBJS_DIR = objs
else
CPPUTEST_OBJS_DIR = objs/$(TARGET_PLATFORM)
endif
endif
# Default dir for the outout library
ifndef CPPUTEST_LIB_DIR
ifndef TARGET_PLATFORM
CPPUTEST_LIB_DIR = lib
else
CPPUTEST_LIB_DIR = lib/$(TARGET_PLATFORM)
endif
endif
# No map by default
ifndef CPPUTEST_MAP_FILE
CPPUTEST_MAP_FILE = N
endif
# No extentions is default
ifndef CPPUTEST_USE_EXTENSIONS
CPPUTEST_USE_EXTENSIONS = N
endif
# No VPATH is default
ifndef CPPUTEST_USE_VPATH
CPPUTEST_USE_VPATH := N
endif
# Make empty, instead of 'N', for usage in $(if ) conditionals
ifneq ($(CPPUTEST_USE_VPATH), Y)
CPPUTEST_USE_VPATH :=
endif
ifndef TARGET_PLATFORM
#CPPUTEST_LIB_LINK_DIR = $(CPPUTEST_HOME)/lib
CPPUTEST_LIB_LINK_DIR = /usr/lib/x86_64-linux-gnu
else
CPPUTEST_LIB_LINK_DIR = $(CPPUTEST_HOME)/lib/$(TARGET_PLATFORM)
endif
# --------------------------------------
# derived flags in the following area
# --------------------------------------
# Without the C library, we'll need to disable the C++ library and ...
ifeq ($(CPPUTEST_USE_STD_C_LIB), N)
CPPUTEST_USE_STD_CPP_LIB = N
CPPUTEST_USE_MEM_LEAK_DETECTION = N
CPPUTEST_CPPFLAGS += -DCPPUTEST_STD_C_LIB_DISABLED
CPPUTEST_CPPFLAGS += -nostdinc
endif
CPPUTEST_CPPFLAGS += -DCPPUTEST_COMPILATION
ifeq ($(CPPUTEST_USE_MEM_LEAK_DETECTION), N)
CPPUTEST_CPPFLAGS += -DCPPUTEST_MEM_LEAK_DETECTION_DISABLED
else
ifndef CPPUTEST_MEMLEAK_DETECTOR_NEW_MACRO_FILE
CPPUTEST_MEMLEAK_DETECTOR_NEW_MACRO_FILE = -include $(CPPUTEST_HOME)/include/CppUTest/MemoryLeakDetectorNewMacros.h
endif
ifndef CPPUTEST_MEMLEAK_DETECTOR_MALLOC_MACRO_FILE
CPPUTEST_MEMLEAK_DETECTOR_MALLOC_MACRO_FILE = -include $(CPPUTEST_HOME)/include/CppUTest/MemoryLeakDetectorMallocMacros.h
endif
endif
ifeq ($(CPPUTEST_ENABLE_DEBUG), Y)
CPPUTEST_CXXFLAGS += -g
CPPUTEST_CFLAGS += -g
CPPUTEST_LDFLAGS += -g
endif
ifeq ($(CPPUTEST_USE_STD_CPP_LIB), N)
CPPUTEST_CPPFLAGS += -DCPPUTEST_STD_CPP_LIB_DISABLED
ifeq ($(CPPUTEST_USE_STD_C_LIB), Y)
CPPUTEST_CXXFLAGS += -nostdinc++
endif
endif
ifdef $(GMOCK_HOME)
GTEST_HOME = $(GMOCK_HOME)/gtest
CPPUTEST_CPPFLAGS += -I$(GMOCK_HOME)/include
GMOCK_LIBRARY = $(GMOCK_HOME)/lib/.libs/libgmock.a
LD_LIBRARIES += $(GMOCK_LIBRARY)
CPPUTEST_CPPFLAGS += -DINCLUDE_GTEST_TESTS
CPPUTEST_WARNINGFLAGS =
CPPUTEST_CPPFLAGS += -I$(GTEST_HOME)/include -I$(GTEST_HOME)
GTEST_LIBRARY = $(GTEST_HOME)/lib/.libs/libgtest.a
LD_LIBRARIES += $(GTEST_LIBRARY)
endif
ifeq ($(CPPUTEST_USE_GCOV), Y)
CPPUTEST_CXXFLAGS += -fprofile-arcs -ftest-coverage
CPPUTEST_CFLAGS += -fprofile-arcs -ftest-coverage
endif
CPPUTEST_CXXFLAGS += $(CPPUTEST_WARNINGFLAGS) $(CPPUTEST_CXX_WARNINGFLAGS)
CPPUTEST_CPPFLAGS += $(CPPUTEST_WARNINGFLAGS)
CPPUTEST_CXXFLAGS += $(CPPUTEST_MEMLEAK_DETECTOR_NEW_MACRO_FILE)
CPPUTEST_CPPFLAGS += $(CPPUTEST_MEMLEAK_DETECTOR_MALLOC_MACRO_FILE)
CPPUTEST_CFLAGS += $(CPPUTEST_C_WARNINGFLAGS)
TARGET_MAP = $(COMPONENT_NAME).map.txt
ifeq ($(CPPUTEST_MAP_FILE), Y)
CPPUTEST_LDFLAGS += -Wl,-map,$(TARGET_MAP)
endif
# Link with CppUTest lib
CPPUTEST_LIB = $(CPPUTEST_LIB_LINK_DIR)/libCppUTest.a
ifeq ($(CPPUTEST_USE_EXTENSIONS), Y)
CPPUTEST_LIB += $(CPPUTEST_LIB_LINK_DIR)/libCppUTestExt.a
endif
ifdef CPPUTEST_STATIC_REALTIME
LD_LIBRARIES += -lrt
endif
TARGET_LIB = \
$(CPPUTEST_LIB_DIR)/lib$(COMPONENT_NAME).a
ifndef TEST_TARGET
ifndef TARGET_PLATFORM
TEST_TARGET = $(COMPONENT_NAME)_tests
else
TEST_TARGET = $(COMPONENT_NAME)_$(TARGET_PLATFORM)_tests
endif
endif
#Helper Functions
get_src_from_dir = $(wildcard $1/*.cpp) $(wildcard $1/*.cc) $(wildcard $1/*.c)
get_dirs_from_dirspec = $(wildcard $1)
get_src_from_dir_list = $(foreach dir, $1, $(call get_src_from_dir,$(dir)))
__src_to = $(subst .c,$1, $(subst .cc,$1, $(subst .cpp,$1,$(if $(CPPUTEST_USE_VPATH),$(notdir $2),$2))))
src_to = $(addprefix $(CPPUTEST_OBJS_DIR)/,$(call __src_to,$1,$2))
src_to_o = $(call src_to,.o,$1)
src_to_d = $(call src_to,.d,$1)
src_to_gcda = $(call src_to,.gcda,$1)
src_to_gcno = $(call src_to,.gcno,$1)
time = $(shell date +%s)
delta_t = $(eval minus, $1, $2)
debug_print_list = $(foreach word,$1,echo " $(word)";) echo;
#Derived
STUFF_TO_CLEAN += $(TEST_TARGET) $(TEST_TARGET).exe $(TARGET_LIB) $(TARGET_MAP)
SRC += $(call get_src_from_dir_list, $(SRC_DIRS)) $(SRC_FILES)
OBJ = $(call src_to_o,$(SRC))
STUFF_TO_CLEAN += $(OBJ)
TEST_SRC += $(call get_src_from_dir_list, $(TEST_SRC_DIRS)) $(TEST_SRC_FILES)
TEST_OBJS = $(call src_to_o,$(TEST_SRC))
STUFF_TO_CLEAN += $(TEST_OBJS)
MOCKS_SRC += $(call get_src_from_dir_list, $(MOCKS_SRC_DIRS))
MOCKS_OBJS = $(call src_to_o,$(MOCKS_SRC))
STUFF_TO_CLEAN += $(MOCKS_OBJS)
ALL_SRC = $(SRC) $(TEST_SRC) $(MOCKS_SRC)
# If we're using VPATH
ifeq ($(CPPUTEST_USE_VPATH), Y)
# gather all the source directories and add them
VPATH += $(sort $(dir $(ALL_SRC)))
# Add the component name to the objs dir path, to differentiate between same-name objects
CPPUTEST_OBJS_DIR := $(addsuffix /$(COMPONENT_NAME),$(CPPUTEST_OBJS_DIR))
endif
#Test coverage with gcov
GCOV_OUTPUT = gcov_output.txt
GCOV_REPORT = gcov_report.txt
GCOV_ERROR = gcov_error.txt
GCOV_GCDA_FILES = $(call src_to_gcda, $(ALL_SRC))
GCOV_GCNO_FILES = $(call src_to_gcno, $(ALL_SRC))
TEST_OUTPUT = $(TEST_TARGET).txt
STUFF_TO_CLEAN += \
$(GCOV_OUTPUT)\
$(GCOV_REPORT)\
$(GCOV_REPORT).html\
$(GCOV_ERROR)\
$(GCOV_GCDA_FILES)\
$(GCOV_GCNO_FILES)\
$(TEST_OUTPUT)
#The gcda files for gcov need to be deleted before each run
#To avoid annoying messages.
GCOV_CLEAN = $(SILENCE)rm -f $(GCOV_GCDA_FILES) $(GCOV_OUTPUT) $(GCOV_REPORT) $(GCOV_ERROR)
RUN_TEST_TARGET = $(SILENCE) $(GCOV_CLEAN) ; echo "Running $(TEST_TARGET)"; ./$(TEST_TARGET) $(CPPUTEST_EXE_FLAGS) -ojunit
ifeq ($(CPPUTEST_USE_GCOV), Y)
ifeq ($(COMPILER_NAME),$(CLANG_STR))
LD_LIBRARIES += --coverage
else
LD_LIBRARIES += -lgcov
endif
endif
INCLUDES_DIRS_EXPANDED = $(call get_dirs_from_dirspec, $(INCLUDE_DIRS))
INCLUDES += $(foreach dir, $(INCLUDES_DIRS_EXPANDED), -I$(dir))
MOCK_DIRS_EXPANDED = $(call get_dirs_from_dirspec, $(MOCKS_SRC_DIRS))
INCLUDES += $(foreach dir, $(MOCK_DIRS_EXPANDED), -I$(dir))
CPPUTEST_CPPFLAGS += $(INCLUDES) $(CPPUTESTFLAGS)
DEP_FILES = $(call src_to_d, $(ALL_SRC))
STUFF_TO_CLEAN += $(DEP_FILES) $(PRODUCTION_CODE_START) $(PRODUCTION_CODE_END)
STUFF_TO_CLEAN += $(STDLIB_CODE_START) $(MAP_FILE) cpputest_*.xml junit_run_output
# We'll use the CPPUTEST_CFLAGS etc so that you can override AND add to the CppUTest flags
CFLAGS = $(CPPUTEST_CFLAGS) $(CPPUTEST_ADDITIONAL_CFLAGS)
CPPFLAGS = $(CPPUTEST_CPPFLAGS) $(CPPUTEST_ADDITIONAL_CPPFLAGS)
CXXFLAGS = $(CPPUTEST_CXXFLAGS) $(CPPUTEST_ADDITIONAL_CXXFLAGS)
LDFLAGS = $(CPPUTEST_LDFLAGS) $(CPPUTEST_ADDITIONAL_LDFLAGS)
# Don't consider creating the archive a warning condition that does STDERR output
ARFLAGS := $(ARFLAGS)c
DEP_FLAGS=-MMD -MP
# Some macros for programs to be overridden. For some reason, these are not in Make defaults
RANLIB = ranlib
# Targets
.PHONY: all
all: start $(TEST_TARGET)
$(RUN_TEST_TARGET)
.PHONY: start
start: $(TEST_TARGET)
$(SILENCE)START_TIME=$(call time)
.PHONY: all_no_tests
all_no_tests: $(TEST_TARGET)
.PHONY: flags
flags:
@echo
@echo "OS ${UNAME_OS}"
@echo "Compile C and C++ source with CPPFLAGS:"
@$(call debug_print_list,$(CPPFLAGS))
@echo "Compile C++ source with CXXFLAGS:"
@$(call debug_print_list,$(CXXFLAGS))
@echo "Compile C source with CFLAGS:"
@$(call debug_print_list,$(CFLAGS))
@echo "Link with LDFLAGS:"
@$(call debug_print_list,$(LDFLAGS))
@echo "Link with LD_LIBRARIES:"
@$(call debug_print_list,$(LD_LIBRARIES))
@echo "Create libraries with ARFLAGS:"
@$(call debug_print_list,$(ARFLAGS))
TEST_DEPS = $(TEST_OBJS) $(MOCKS_OBJS) $(PRODUCTION_CODE_START) $(TARGET_LIB) $(USER_LIBS) $(PRODUCTION_CODE_END) $(CPPUTEST_LIB) $(STDLIB_CODE_START)
test-deps: $(TEST_DEPS)
$(TEST_TARGET): $(TEST_DEPS)
@echo Linking $@
$(SILENCE)$(CXX) -o $@ $^ $(LD_LIBRARIES) $(LDFLAGS)
$(TARGET_LIB): $(OBJ)
@echo Building archive $@
$(SILENCE)mkdir -p $(dir $@)
$(SILENCE)$(AR) $(ARFLAGS) $@ $^
$(SILENCE)$(RANLIB) $@
test: $(TEST_TARGET)
$(RUN_TEST_TARGET) | tee $(TEST_OUTPUT)
vtest: $(TEST_TARGET)
$(RUN_TEST_TARGET) -v | tee $(TEST_OUTPUT)
$(CPPUTEST_OBJS_DIR)/%.o: %.cc
@echo compiling $(notdir $<)
$(SILENCE)mkdir -p $(dir $@)
$(SILENCE)$(COMPILE.cpp) $(DEP_FLAGS) $(OUTPUT_OPTION) $<
$(CPPUTEST_OBJS_DIR)/%.o: %.cpp
@echo compiling $(notdir $<)
$(SILENCE)mkdir -p $(dir $@)
$(SILENCE)$(COMPILE.cpp) $(DEP_FLAGS) $(OUTPUT_OPTION) $<
$(CPPUTEST_OBJS_DIR)/%.o: %.c
@echo compiling $(notdir $<)
$(SILENCE)mkdir -p $(dir $@)
$(SILENCE)$(COMPILE.c) $(DEP_FLAGS) $(OUTPUT_OPTION) $<
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP_FILES)
endif
.PHONY: clean
clean:
@echo Making clean
$(SILENCE)$(RM) $(STUFF_TO_CLEAN)
$(SILENCE)rm -rf gcov objs #$(CPPUTEST_OBJS_DIR)
$(SILENCE)rm -rf $(CPPUTEST_LIB_DIR)
$(SILENCE)find . -name "*.gcno" | xargs rm -f
$(SILENCE)find . -name "*.gcda" | xargs rm -f
#realclean gets rid of all gcov, o and d files in the directory tree
#not just the ones made by this makefile
.PHONY: realclean
realclean: clean
$(SILENCE)rm -rf gcov
$(SILENCE)find . -name "*.gdcno" | xargs rm -f
$(SILENCE)find . -name "*.[do]" | xargs rm -f
gcov: test
ifeq ($(CPPUTEST_USE_VPATH), Y)
$(SILENCE)gcov --object-directory $(CPPUTEST_OBJS_DIR) $(SRC) >> $(GCOV_OUTPUT) 2>> $(GCOV_ERROR)
else
$(SILENCE)for d in $(SRC_DIRS) ; do \
gcov --object-directory $(CPPUTEST_OBJS_DIR)/$$d $$d/*.c $$d/*.cpp >> $(GCOV_OUTPUT) 2>>$(GCOV_ERROR) ; \
done
$(SILENCE)for f in $(SRC_FILES) ; do \
gcov --object-directory $(CPPUTEST_OBJS_DIR)/$$f $$f >> $(GCOV_OUTPUT) 2>>$(GCOV_ERROR) ; \
done
endif
# $(CPPUTEST_HOME)/scripts/filterGcov.sh $(GCOV_OUTPUT) $(GCOV_ERROR) $(GCOV_REPORT) $(TEST_OUTPUT)
/usr/share/cpputest/scripts/filterGcov.sh $(GCOV_OUTPUT) $(GCOV_ERROR) $(GCOV_REPORT) $(TEST_OUTPUT)
$(SILENCE)cat $(GCOV_REPORT)
$(SILENCE)mkdir -p gcov
$(SILENCE)mv *.gcov gcov
$(SILENCE)mv gcov_* gcov
@echo "See gcov directory for details"
.PHONEY: format
format:
$(CPPUTEST_HOME)/scripts/reformat.sh $(PROJECT_HOME_DIR)
.PHONEY: debug
debug:
@echo
@echo "Target Source files:"
@$(call debug_print_list,$(SRC))
@echo "Target Object files:"
@$(call debug_print_list,$(OBJ))
@echo "Test Source files:"
@$(call debug_print_list,$(TEST_SRC))
@echo "Test Object files:"
@$(call debug_print_list,$(TEST_OBJS))
@echo "Mock Source files:"
@$(call debug_print_list,$(MOCKS_SRC))
@echo "Mock Object files:"
@$(call debug_print_list,$(MOCKS_OBJS))
@echo "All Input Dependency files:"
@$(call debug_print_list,$(DEP_FILES))
@echo Stuff to clean:
@$(call debug_print_list,$(STUFF_TO_CLEAN))
@echo Includes:
@$(call debug_print_list,$(INCLUDES))
-include $(OTHER_MAKEFILE_TO_INCLUDE)

View File

@ -1,91 +0,0 @@
/*
* Copyright (c) 2016, 2018, Arm Limited and affiliates.
* 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 "CppUTest/TestHarness.h"
#include "test_cs_nvm.h"
TEST_GROUP(CS_NVM)
{
void setup() {
}
void teardown() {
}
};
TEST(CS_NVM, test_cs_nvm_operation_in_progress)
{
CHECK(test_cs_nvm_operation_in_progress() == true);
}
TEST(CS_NVM, test_cs_nvm_flush)
{
CHECK(test_cs_nvm_flush() == true);
}
TEST(CS_NVM, test_cs_nvm_write_failure_in_close)
{
CHECK(test_cs_nvm_write_failure_in_close() == true);
}
TEST(CS_NVM, test_cs_nvm_write_failure)
{
CHECK(test_cs_nvm_write_failure() == true);
}
TEST(CS_NVM, test_cs_nvm_write)
{
CHECK(test_cs_nvm_write() == true);
}
TEST(CS_NVM, test_cs_nvm_read_failure_in_close)
{
CHECK(test_cs_nvm_read_failure_in_close() == true);
}
TEST(CS_NVM, test_cs_nvm_read_failure)
{
CHECK(test_cs_nvm_read_failure() == true);
}
TEST(CS_NVM, test_cs_nvm_read)
{
CHECK(test_cs_nvm_read() == true);
}
TEST(CS_NVM, test_cs_nvm_key_delete_failure_in_close)
{
CHECK(test_cs_nvm_key_delete_failure_in_close() == true);
}
TEST(CS_NVM, test_cs_nvm_key_delete)
{
CHECK(test_cs_nvm_key_delete() == true);
}
TEST(CS_NVM, test_cs_nvm_key_create)
{
CHECK(test_cs_nvm_key_create() == true);
}
TEST(CS_NVM, test_cs_nvm_init_finalize)
{
CHECK(test_cs_nvm_init_finalize() == true);
}

View File

@ -1,28 +0,0 @@
/*
* Copyright (c) 2015, 2018, Arm Limited and affiliates.
* 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 "CppUTest/CommandLineTestRunner.h"
#include "CppUTest/TestPlugin.h"
#include "CppUTest/TestRegistry.h"
#include "CppUTestExt/MockSupportPlugin.h"
int main(int ac, char **av)
{
return CommandLineTestRunner::RunAllTests(ac, av);
}
IMPORT_TEST_GROUP(CS_NVM);

View File

@ -1,44 +0,0 @@
/*
* Copyright (c) 2016, 2018, Arm Limited and affiliates.
* 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 TEST_NS_NVM_HELPER_H
#define TEST_NS_NVM_HELPER_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
bool test_cs_nvm_init_finalize();
bool test_cs_nvm_key_create();
bool test_cs_nvm_key_delete();
bool test_cs_nvm_key_delete_failure_in_close();
bool test_cs_nvm_read();
bool test_cs_nvm_read_failure();
bool test_cs_nvm_read_failure_in_close();
bool test_cs_nvm_write();
bool test_cs_nvm_write_failure();
bool test_cs_nvm_write_failure_in_close();
bool test_cs_nvm_flush();
bool test_cs_nvm_operation_in_progress();
#ifdef __cplusplus
}
#endif
#endif // TEST_NS_NVM_HELPER_H

View File

@ -1,19 +0,0 @@
#--- Inputs ----#
CPPUTEST_HOME = /usr
CPPUTEST_USE_EXTENSIONS = Y
CPPUTEST_USE_VPATH = Y
CPPUTEST_USE_GCOV = Y
CPP_PLATFORM = gcc
INCLUDE_DIRS =\
.\
../stubs\
../../../../..\
../../../../../../../core/configuration-store/\
../../../../../../../core/flash-abstraction/\
../../../../../../nanostack-libservice/mbed-client-libservice/\
../../../../../../sal-stack-nanostack-eventloop/nanostack-event-loop/\
/usr/include\
$(CPPUTEST_HOME)/include\
CPPUTESTFLAGS = -D__thumb2__ -w
CPPUTEST_CFLAGS += -std=gnu99

View File

@ -1,43 +0,0 @@
#!/bin/bash
echo
echo Build M2M API unit tests
echo
# Remember to add new test folder to Makefile
make clean
make all
echo
echo Create results
echo
mkdir results
find ./ -name '*.xml' | xargs cp -t ./results/
echo
echo Create coverage document
echo
mkdir coverages
cd coverages
#copy the .gcda & .gcno for all test projects (no need to modify
#cp ../../../source/*.gc* .
#find ../ -name '*.gcda' | xargs cp -t .
#find ../ -name '*.gcno' | xargs cp -t .
#find . -name "test*" -type f -delete
#find . -name "*test*" -type f -delete
#find . -name "*stub*" -type f -delete
#rm -rf main.*
lcov -q -d ../. -c -o app.info
lcov -q -r app.info "/test*" -o app.info
lcov -q -r app.info "/usr*" -o app.info
genhtml --no-branch-coverage app.info
cd ..
echo
echo
echo
echo Have a nice bug hunt!
echo
echo
echo

View File

@ -1,142 +0,0 @@
/*
* Copyright (c) 2016, 2018, Arm Limited and affiliates.
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <configuration-store/configuration_store.h>
#include "configuration_store_stub.h"
configuration_store_stub_data_t cfstore_stub = {ARM_DRIVER_OK, ARM_DRIVER_OK, ARM_DRIVER_OK, ARM_DRIVER_OK, ARM_DRIVER_OK, 0, NULL, NULL, NULL};
static int32_t test_cfstore_close(ARM_CFSTORE_HANDLE hkey)
{
return cfstore_stub.close_ret_val;
}
static int32_t test_cfstore_create(const char *key_name, ARM_CFSTORE_SIZE value_len, const ARM_CFSTORE_KEYDESC *kdesc, ARM_CFSTORE_HANDLE hkey)
{
return cfstore_stub.ret_val;
}
static int32_t test_cfstore_delete(ARM_CFSTORE_HANDLE hkey)
{
return cfstore_stub.delete_ret_val;
}
static int32_t test_cfstore_find(const char *key_name_query, const ARM_CFSTORE_HANDLE previous, ARM_CFSTORE_HANDLE next)
{
return ARM_DRIVER_OK;
}
static int32_t test_cfstore_flush(void)
{
return cfstore_stub.ret_val;
}
ARM_CFSTORE_CAPABILITIES test_cfstore_get_capabilities(void)
{
static ARM_CFSTORE_CAPABILITIES cfstore_caps_g = { .asynchronous_ops = 1 };
return cfstore_caps_g;
}
static int32_t test_cfstore_get_key_name(ARM_CFSTORE_HANDLE hkey, char *key_name, uint8_t *key_name_len)
{
return ARM_DRIVER_OK;
}
static ARM_CFSTORE_STATUS test_cfstore_get_status(void)
{
ARM_CFSTORE_STATUS status;
return status;
}
static int32_t test_cfstore_get_value_len(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_SIZE *value_len)
{
return ARM_DRIVER_OK;
}
ARM_DRIVER_VERSION test_cfstore_get_version(void)
{
static const ARM_DRIVER_VERSION cfstore_driver_version_g = { .api = ARM_CFSTORE_API_VERSION, .drv = ARM_CFSTORE_DRV_VERSION };
return cfstore_driver_version_g;
}
static int32_t test_cfstore_initialise(ARM_CFSTORE_CALLBACK callback, void *client_context)
{
cfstore_stub.callback = callback;
cfstore_stub.client_context = client_context;
return cfstore_stub.ret_val;
}
static int32_t test_cfstore_open(const char *key_name, ARM_CFSTORE_FMODE flags, ARM_CFSTORE_HANDLE hkey)
{
return cfstore_stub.ret_val;
}
static int32_t test_cfstore_power_control(ARM_POWER_STATE state)
{
return ARM_DRIVER_OK;
}
static int32_t test_cfstore_read(ARM_CFSTORE_HANDLE hkey, void *data, ARM_CFSTORE_SIZE *len)
{
return cfstore_stub.read_ret_val;
}
static int32_t test_cfstore_rseek(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_OFFSET offset)
{
return ARM_DRIVER_OK;
}
static int32_t test_cfstore_uninitialise(void)
{
return cfstore_stub.ret_val;
}
static int32_t test_cfstore_write(ARM_CFSTORE_HANDLE hkey, const char *data, ARM_CFSTORE_SIZE *len)
{
return cfstore_stub.write_ret_val;
}
ARM_CFSTORE_DRIVER cfstore_driver = {
.Close = test_cfstore_close,
.Create = test_cfstore_create,
.Delete = test_cfstore_delete,
.Find = test_cfstore_find,
.Flush = test_cfstore_flush,
.GetCapabilities = test_cfstore_get_capabilities,
.GetKeyName = test_cfstore_get_key_name,
.GetStatus = test_cfstore_get_status,
.GetValueLen = test_cfstore_get_value_len,
.GetVersion = test_cfstore_get_version,
.Initialize = test_cfstore_initialise,
.Open = test_cfstore_open,
.PowerControl = test_cfstore_power_control,
.Read = test_cfstore_read,
.Rseek = test_cfstore_rseek,
.Uninitialize = test_cfstore_uninitialise,
.Write = test_cfstore_write,
};
void test_cfstore_callback_trigger()
{
cfstore_stub.callback(cfstore_stub.ret_val, cfstore_stub.cmd_code, cfstore_stub.client_context, cfstore_stub.handle);
}

View File

@ -1,46 +0,0 @@
/*
* Copyright (c) 2016, 2018, Arm Limited and affiliates.
* 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 __CONFIGURATION_STORE_STUB_H__
#define __CONFIGURATION_STORE_STUB_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "stdint.h"
typedef struct {
int32_t ret_val;
int32_t delete_ret_val;
int32_t read_ret_val;
int32_t close_ret_val;
int32_t write_ret_val;
ARM_CFSTORE_OPCODE cmd_code;
void *client_context;
ARM_CFSTORE_HANDLE handle;
ARM_CFSTORE_CALLBACK callback;
} configuration_store_stub_data_t;
extern configuration_store_stub_data_t cfstore_stub;
void test_cfstore_callback_trigger(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,217 +0,0 @@
/*
* Copyright (c) 2014-2016, 2018, Arm Limited and affiliates.
* 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 <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include "ns_trace.h"
#include "ip6string.h"
#include "common_functions.h"
#if defined(_WIN32) || defined(__unix__) || defined(__unix) || defined(unix)
#ifndef MEM_ALLOC
#define MEM_ALLOC malloc
#endif
#ifndef MEM_FREE
#define MEM_FREE free
#endif
#else
#include "nsdynmemLIB.h"
#ifndef MEM_ALLOC
#define MEM_ALLOC ns_dyn_mem_alloc
#endif
#ifndef MEM_FREE
#define MEM_FREE ns_dyn_mem_free
#endif
#endif
#define VT100_COLOR_ERROR "\x1b[31m"
#define VT100_COLOR_WARN "\x1b[33m"
#define VT100_COLOR_INFO "\x1b[39m"
#define VT100_COLOR_DEBUG "\x1b[90m"
/** default max trace line size in bytes */
#define DEFAULT_TRACE_LINE_LENGTH 1024
/** default max temporary buffer size in bytes, used in
trace_ipv6, trace_array and trace_strn */
#define DEFAULT_TRACE_TMP_LINE_LEN 128
/** default max filters (include/exclude) length in bytes */
#define DEFAULT_TRACE_FILTER_LENGTH 24
static void default_print(const char *str);
typedef struct {
/** trace configuration bits */
uint8_t trace_config;
/** exclude filters list, related group name */
char *filters_exclude;
/** include filters list, related group name */
char *filters_include;
/** Filters length */
int filters_length;
/** trace line */
char *line;
/** trace line length */
int line_length;
/** temporary data */
char *tmp_data;
/** temporary data array length */
int tmp_data_length;
/** temporary data pointer */
char *tmp_data_ptr;
/** prefix function, which can be used to put time to the trace line */
char *(*prefix_f)(size_t);
/** suffix function, which can be used to some string to the end of trace line */
char *(*suffix_f)(void);
/** print out function. Can be redirect to flash for example. */
void (*printf)(const char *);
/** print out function for TRACE_LEVEL_CMD */
void (*cmd_printf)(const char *);
} trace_s;
static trace_s m_trace = {
.filters_exclude = 0,
.filters_include = 0,
.line = 0,
.tmp_data = 0,
.prefix_f = 0,
.suffix_f = 0,
.printf = 0,
.cmd_printf = 0
};
int trace_init(void)
{
return 0;
}
void trace_free(void)
{
}
void set_trace_config(uint8_t config)
{
}
uint8_t get_trace_config(void)
{
return 0;
}
void set_trace_prefix_function(char *(*pref_f)(size_t))
{
}
void set_trace_suffix_function(char *(*suffix_f)(void))
{
}
void set_trace_print_function(void (*printf)(const char *))
{
}
void set_trace_cmdprint_function(void (*printf)(const char *))
{
}
void set_trace_exclude_filters(char *filters)
{
}
const char *get_trace_exclude_filters(void)
{
return NULL;
}
const char *get_trace_include_filters(void)
{
return NULL;
}
void set_trace_include_filters(char *filters)
{
}
static int8_t trace_skip(int8_t dlevel, const char *grp)
{
return 0;
}
static void default_print(const char *str)
{
}
void tracef(uint8_t dlevel, const char *grp, const char *fmt, ...)
{
}
const char *trace_last(void)
{
return "";
}
/* Helping functions */
#define tmp_data_left() m_trace.tmp_data_length-(m_trace.tmp_data_ptr-m_trace.tmp_data)
char *trace_ipv6(const void *addr_ptr)
{
return "";
}
char *trace_ipv6_prefix(const uint8_t *prefix, uint8_t prefix_len)
{
return "";
}
char *trace_array(const uint8_t *buf, uint16_t len)
{
return "";
}
// rest of debug print functions will be obsolete and will be overridden with new trace interface..
void debugf(const char *fmt, ...)
{
}
void debug(const char *s)
{
}
void debug_put(char c)
{
}
void debug_hex(uint8_t x)
{
}
void debug_int(int i)
{
}
void printf_array(const void *buf, uint16_t len)
{
}
void printf_ipv6_address(const void *addr_ptr)
{
}
void printf_string(const void *ptr, uint16_t len)
{
}

View File

@ -1,55 +0,0 @@
/*
* Copyright (c) 2014-2016, 2018, Arm Limited and affiliates.
* 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 "nsdynmemLIB_stub.h"
#include <stdint.h>
#include <string.h>
#include "nsdynmemLIB.h"
#include "platform/arm_hal_interrupt.h"
#include <stdlib.h>
nsdynmemlib_stub_data_t nsdynmemlib_stub;
void ns_dyn_mem_init(uint8_t *heap, uint16_t h_size, void (*passed_fptr)(heap_fail_t), mem_stat_t *info_ptr)
{
}
void *ns_dyn_mem_alloc(int16_t alloc_size)
{
if (nsdynmemlib_stub.returnCounter > 0) {
nsdynmemlib_stub.returnCounter--;
return malloc(alloc_size);
} else {
return (nsdynmemlib_stub.expectedPointer);
}
}
void *ns_dyn_mem_temporary_alloc(int16_t alloc_size)
{
if (nsdynmemlib_stub.returnCounter > 0) {
nsdynmemlib_stub.returnCounter--;
return malloc(alloc_size);
} else {
return (nsdynmemlib_stub.expectedPointer);
}
}
void ns_dyn_mem_free(void *block)
{
free(block);
}

View File

@ -1,37 +0,0 @@
/*
* Copyright (c) 2015-2016, 2018, Arm Limited and affiliates.
* 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 __NSDYNMEMLIB_STUB_H__
#define __NSDYNMEMLIB_STUB_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "stdint.h"
typedef struct {
uint8_t returnCounter;
void *expectedPointer;
} nsdynmemlib_stub_data_t;
extern nsdynmemlib_stub_data_t nsdynmemlib_stub;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,39 +0,0 @@
/*
* Copyright (c) 2016, 2018, Arm Limited and affiliates.
* 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 "eventOS_event_timer.h"
static void (*test_callback)(void *);
static void *test_args;
timeout_t *eventOS_timeout_ms(void (*callback)(void *), uint32_t ms, void *arg)
{
test_callback = callback;
test_args = arg;
return NULL;
}
void eventOS_timeout_cancel(timeout_t *t)
{
}
void test_eventOS_timeout_trigger()
{
test_callback(test_args);
}

View File

@ -1,10 +1,6 @@
{
"name": "nanostack-hal",
"config": {
"nvm_cfstore": {
"help": "Use cfstore as a NVM storage. Else RAM simulation will be used",
"value": false
},
"event_loop_thread_stack_size": {
"help": "Define event-loop thread stack size. [bytes]",
"value": 6144

View File

@ -15,14 +15,6 @@
* limitations under the License.
*/
#ifdef MBED_CONF_NANOSTACK_HAL_NVM_CFSTORE
# if MBED_CONF_NANOSTACK_HAL_NVM_CFSTORE
# define IGNORE_SIMULATED_NVM_STORAGE
# else
# undef IGNORE_SIMULATED_NVM_STORAGE
# endif
#endif
/*
* Define flag IGNORE_SIMULATED_NVM_STORAGE to ignore usage of simulated NVM and use
* platform specific NVM instead.

View File

@ -1,391 +0,0 @@
/*
* 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"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
using namespace utest::v1;
#define CFSTORE_ADD_DEL_MALLOC_SIZE 1024
static char cfstore_add_del_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE];
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;
}
/** @brief Delete an attribute after an internal realloc of the cfstore memory area
*
* This test case goes through the following steps:
* 1. Creates attribute att_1 of size x, and write some data. This causes an internal
* cfstore realloc to allocate heap memory for the attribute.
* 2. Allocates some memory on the heap. Typically, this will be immediately after the
* memory used by cfstore for the KV area. This means that if any cfstore reallocs are
* made to increase size the memory area will have to move.
* 3. Creates attribute att_2 of size y. This causes an internal cfstore realloc to move
* the KV memory area to a new location.
* 4. Delete att_1. This causes an internal realloc to shrink the area and tests that the
* internal data structures that contain pointers to different parts of the KV area
* are updated correctly.
* 5. Allocates some memory on the heap. If the heap has been corrupted, this will likely trigger
* a crash
*
* @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
*/
control_t cfstore_add_del_test_05_end(const size_t call_count)
{
char data[] = "some test data";
char filename[] = "file1";
char filename2[] = "file2";
int32_t ret = ARM_DRIVER_ERROR;
void *test_buf1 = NULL;
void *test_buf2 = NULL;
ARM_CFSTORE_DRIVER *cfstoreDriver = &cfstore_driver;
ARM_CFSTORE_KEYDESC keyDesc1;
ARM_CFSTORE_HANDLE_INIT(hkey1);
ARM_CFSTORE_KEYDESC keyDesc2;
ARM_CFSTORE_HANDLE_INIT(hkey2);
ARM_CFSTORE_SIZE count = sizeof(data);
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
(void) call_count;
/* step 1 */
memset(&keyDesc1, 0, sizeof(keyDesc1));
keyDesc1.drl = ARM_RETENTION_NVM;
keyDesc1.flags.read = true;
keyDesc1.flags.write = true;
ret = cfstoreDriver->Create(filename, 1024, &keyDesc1, hkey1);
CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create attribute 1 (ret=%d)\n", __func__, (int) ret);
TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g);
/* Write data to file */
ret = cfstoreDriver->Write(hkey1, (const char *)data, &count);
CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write to attribute 1 (ret=%d)\n", __func__, (int) ret);
TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g);
/* step 2 */
test_buf1 = malloc(CFSTORE_ADD_DEL_MALLOC_SIZE);
CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to allocate memory (test_buf1=%p)\n", __func__, test_buf1);
TEST_ASSERT_MESSAGE(test_buf1 != NULL, cfstore_add_del_utest_msg_g);
/* step 3 */
memset(&keyDesc2, 0, sizeof(keyDesc2));
keyDesc2.drl = ARM_RETENTION_NVM;
keyDesc2.flags.read = true;
keyDesc2.flags.write = true;
ret = cfstoreDriver->Create(filename2, 1024, &keyDesc2, hkey2);
CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create attribute 2 (ret=%d)\n", __func__, (int) ret);
TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g);
/* Write data to file */
count = sizeof(data);
ret = cfstoreDriver->Write(hkey2, (const char *)data, &count);
CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write to attribute 2 (ret=%d)\n", __func__, (int) ret);
TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g);
/* step 4 */
ret = cfstoreDriver->Delete(hkey1);
CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to delete to attribute 1 (ret=%d)\n", __func__, (int) ret);
TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g);
ret = cfstoreDriver->Close(hkey1);
CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to close to attribute 1 (ret=%d)\n", __func__, (int) ret);
TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g);
/* step 5 */
test_buf2 = malloc(CFSTORE_ADD_DEL_MALLOC_SIZE);
CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to allocate memory (test_buf2=%p)\n", __func__, test_buf2);
TEST_ASSERT_MESSAGE(test_buf2 != NULL, cfstore_add_del_utest_msg_g);
/* clean up */
ret = cfstoreDriver->Close(hkey2);
CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to close to attribute 2 (ret=%d)\n", __func__, (int) ret);
TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g);
free(test_buf2);
free(test_buf1);
return CaseNext;
}
/// @cond CFSTORE_DOXYGEN_DISABLE
utest::v1::status_t greentea_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(300, "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),
Case("ADD_DEL_test_05_start", cfstore_utest_default_start),
Case("ADD_DEL_test_05_end", cfstore_add_del_test_05_end),
};
/* Declare your test specification with a custom setup handler */
Specification specification(greentea_setup, cases);
int main()
{
return !Harness::run(specification);
}
/// @endcond

View File

@ -1,241 +0,0 @@
/*
* 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"
#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];
/* 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 hkey1
* - 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

View File

@ -1,835 +0,0 @@
/*
* 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 "mbed_stats.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"
#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
#define CFSTORE_CREATE_MALLOC_SIZE 1024
static char cfstore_create_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE];
/// @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, double the value blob size.
* - check all the cfstore entries can be read correctly and their
* data agrees with the data supplied upon creation.
* - shrink the mid-entry value blob size to be ~half 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 Support function for test cases 05
*
* Create enough KV's to consume the whole of available memory
*/
int32_t cfstore_create_test_05_core(const size_t call_count)
{
int32_t ret = ARM_DRIVER_ERROR;
uint32_t i = 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__);
/* Initialize() */
cfstore_utest_default_start(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));
if(ret == ARM_CFSTORE_DRIVER_ERROR_OUT_OF_MEMORY){
CFSTORE_ERRLOG("Out of memory on %d-th KV.\n", (int) i);
break;
}
/* revert CFSTORE_LOG for more trace */
CFSTORE_DBGLOG("Successfully stored %d-th KV.\n", (int) i);
}
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 ret;
}
/**
* @brief Test case to check cfstore recovers from out of memory
* errors without leaking memory
*
* This test case does the following:
* 1. Start loop.
* 2. Initializes CFSTORE.
* 3. Creates as many KVs as required to run out of memory. The number of bytes B
* allocated before running out of memory is recorded.
* 4. For loop i, check that B_i = B_i-1 for i>0 i.e. that no memory has been leaked
* 5. Uninitialize(), which should clean up any cfstore internal state including
* freeing the internal memeory area.
* 6. Repeat from step 1 N times.
*/
control_t cfstore_create_test_05(const size_t call_count)
{
uint32_t i = 0;
int32_t ret = ARM_DRIVER_ERROR;
const uint32_t max_loops = 50;
mbed_stats_heap_t stats_before;
mbed_stats_heap_t stats_after;
mbed_stats_heap_get(&stats_before);
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
for(i = 0; i < max_loops; i++) {
ret = cfstore_create_test_05_core(call_count);
CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: cfstore_create_test_05_core() failed (ret = %d.\n", __func__, (int) ret);
TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g);
mbed_stats_heap_get(&stats_after);
if(i > 1) {
CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: memory leak: stored %d bytes on loop %d, but %d bytes on loop %d .\n", __func__, (int) stats_after.current_size, (int) i, (int) stats_before.current_size, (int) i-1);
TEST_ASSERT_MESSAGE(stats_after.current_size == stats_before.current_size, cfstore_create_utest_msg_g);
TEST_ASSERT(stats_after.alloc_fail_cnt > stats_before.alloc_fail_cnt);
}
stats_before = stats_after;
}
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;
}
/** @brief Test case to change the value blob size of pre-existing
* key in a way that causes the memory area to realloc-ed,
*
* The test is a modified version of cfstore_create_test_01_end which
* - creates KVs,
* - mallocs a memory object on the heap
* - increases the size of one of the existing KVs, causing the
* internal memory area to be realloc-ed.
*
* In detail, the test does the following:
* 1. creates a cfstore with ~10 entries. This causes the configuration
* store to realloc() heap memory for KV storage.
* 2. mallocs a memory object on heap.
* 3. for a mid-cfstore entry, double the value blob size. This will cause the
* cfstore memory area to be realloced.
* 4. check all the cfstore entries can be read correctly and their
* data agrees with the data supplied upon creation.
* 5. shrink the mid-entry value blob size to be ~half 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_07_end(const size_t call_count)
{
int32_t ret = ARM_DRIVER_ERROR;
void *test_buf1 = NULL;
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));
/* step 1 */
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);
/* step 2 */
test_buf1 = malloc(CFSTORE_CREATE_MALLOC_SIZE);
CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to allocate memory (test_buf1=%p)\n", __func__, test_buf1);
TEST_ASSERT_MESSAGE(test_buf1 != NULL, cfstore_create_utest_msg_g);
/* step 3. 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);
/* step 4. 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);
/* Step 5. 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++;
}
free(test_buf1);
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;
}
/// @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),
#if defined(MBED_HEAP_STATS_ENABLED) && MBED_HEAP_STATS_ENABLED && !defined(__ICCARM__)
Case("CREATE_test_05", cfstore_create_test_05),
#endif
Case("CREATE_test_06_start", cfstore_utest_default_start),
Case("CREATE_test_06_end", cfstore_create_test_06_end),
Case("CREATE_test_07_start", cfstore_utest_default_start),
Case("CREATE_test_07_end", cfstore_create_test_07_end),
};
/* Declare your test specification with a custom setup handler */
Specification specification(greentea_setup, cases);
int main()
{
return !Harness::run(specification);
}
/// @endcond

View File

@ -1,83 +0,0 @@
/*
* 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"
#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

View File

@ -1,256 +0,0 @@
/*
* 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"
#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

View File

@ -1,326 +0,0 @@
/*
* 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"
#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 == 1){
/* This is a sync mode only test. If this test is not built for sync mode, then skip testing return true
* This means the test will conveniently pass when run in CI as part of async mode testing */
CFSTORE_EX1_LOG("*** Skipping test as binary built for flash journal async mode, and this test is sync-only%s", "\n");
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

View File

@ -1,205 +0,0 @@
/*
* 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"
#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 == 1){
/* This is a sync mode only test. If this test is not built for sync mode, then skip testing return true
* This means the test will conveniently pass when run in CI as part of async mode testing */
CFSTORE_LOG("*** Skipping test as binary built for flash journal async mode, and this test is sync-only%s", "\n");
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

View File

@ -1,330 +0,0 @@
/*
* 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_MTD_K64F;
const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_MTD_K64F;
ret = FlashJournal_initialize(&jrnl, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, NULL);
CFSTORE_EX5_TEST_ASSERT_MSG(ret >= JOURNAL_STATUS_OK, "%s:Error: FlashJournal_initialize() failed (ret=%d)\r\n", __func__, (int) ret);
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){
/* 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

View File

@ -1,537 +0,0 @@
/*
* 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"
#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];
/* 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 == 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;
}
/**
* @brief test case to check Find() with previous NULL pointer works
*
* @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
*/
control_t cfstore_find_test_07_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);
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(true)
{
ret = drv->Find(key_name_query, NULL, next);
if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND) {
/* no more attributes found matching search criteria.*/
break;
}
CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Find() failed(ret=%d).\n", __func__, (int) ret);
TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_find_utest_msg_g);
len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
ret = drv->GetKeyName(next, key_name, &len);
CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to get key name for next (ret=%d).\n", __func__, (int) ret);
TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_find_utest_msg_g);
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);
/* delete the KV so it wont be found when queried is repeated*/
ret = drv->Delete(next);
CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Delete() on next handled failed(ret=%d).\n", __func__, (int) ret);
TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_find_utest_msg_g);
ret = drv->Close(next);
CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Close() on next handled failed(ret=%d).\n", __func__, (int) ret);
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: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),
Case("FIND_test_07_start", cfstore_utest_default_start),
Case("FIND_test_07_end", cfstore_find_test_07_end),
};
/* Declare your test specification with a custom setup handler */
Specification specification(greentea_setup, cases);
int main()
{
return !Harness::run(specification);
}
/// @endcond

View File

@ -1,237 +0,0 @@
/*
* 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"
#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];
/// @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

View File

@ -1,688 +0,0 @@
/*
* 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 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
using namespace utest::v1;
/* 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_MTD_K64F;
/* 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_MTD_K64F;
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

View File

@ -1,103 +0,0 @@
/*
* 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"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
using namespace utest::v1;
/**
* @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

View File

@ -1,629 +0,0 @@
/*
* 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"
#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"
#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];
#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();
ARM_CFSTORE_CAPABILITIES caps;
const ARM_CFSTORE_DRIVER* drv = &cfstore_driver;
CFSTORE_FENTRYLOG("%s:entered: \r\n", __func__);
memset(&caps, 0, sizeof(caps));
caps = drv->GetCapabilities();
if(caps.asynchronous_ops == false){
/* This is a async 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 sync mode, and this test is async-only%s", "\n");
return CaseNext;
}
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

View File

@ -1,270 +0,0 @@
/*
* 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 <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
/*
* 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

View File

@ -1,867 +0,0 @@
/*
* 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"
#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];
/// @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;
}
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 == 1){
/* This is a sync mode only test. If this test is not built for sync mode, then skip testing return true
* This means the test will conveniently pass when run in CI as part of async mode testing */
CFSTORE_LOG("*** Skipping test as binary built for flash journal async mode, and this test is sync-only%s", "\n");
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

View File

@ -1,153 +0,0 @@
/*
* 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"
#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 == 1){
/* This is a sync mode only test. If this test is not built for sync mode, then skip testing return true
* This means the test will conveniently pass when run in CI as part of async mode testing */
CFSTORE_LOG("*** Skipping test as binary built for flash journal async mode, and this test is sync-only%s", "\n");
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

View File

@ -1,327 +0,0 @@
/*
* 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"
#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];
/* 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 == 1, cfstore_misc_utest_msg_g);
ret = drv->Initialize(cfstore_utest_default_callback, NULL);
CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to initialize CFSTORE (ret=%d)\n", __func__, (int) ret);
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 == 0, cfstore_misc_utest_msg_g);
CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: GetStatus() reported operation in progress.\r\n", __func__);
TEST_ASSERT_MESSAGE(status.in_progress == 0, cfstore_misc_utest_msg_g);
ret = drv->Uninitialize();
CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);
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

View File

@ -1,633 +0,0 @@
/*
* 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"
#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];
/// @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

View File

@ -1,180 +0,0 @@
/*
* 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"
#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];
/* 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

View File

@ -1,185 +0,0 @@
/*
* 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"
#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];
/*
* 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

View File

@ -1,8 +0,0 @@
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

View File

@ -1,63 +0,0 @@
###########################################################################
#
# 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)
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

View File

@ -1,103 +0,0 @@
# 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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 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

View File

@ -1,13 +0,0 @@
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.

View File

@ -1,31 +0,0 @@
/*
* 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.
*/

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +0,0 @@
/*
* 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.
*/

View File

@ -1,881 +0,0 @@
/*
* 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() */
#include "mbed_toolchain.h" /* required for MBED_DEPRECATED_SINCE */
#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
/// @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 || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)))
/** @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)
#elif 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)
#elif 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.
} 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;
MBED_DEPRECATED_SINCE("mbed-os-5.5", "CFSTORE replace by FATFileSystem.")
extern ARM_CFSTORE_DRIVER cfstore_driver;
#ifdef __cplusplus
}
#endif
#endif /* __CONFIGURATION_STORE_H */

View File

@ -1,444 +0,0 @@
# 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

View File

@ -1,461 +0,0 @@
# 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.

View File

@ -1,17 +0,0 @@
# 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
![CFSTORE_UML_HLD_01](doc/design/pics/configuration_store_hld_api_summary.jpg)
The above UML diagram shows the low level design of the CFSTORE API.

View File

@ -1,32 +0,0 @@
# 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>
```

View File

@ -1,434 +0,0 @@
# 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

View File

@ -1,34 +0,0 @@
# 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.

View File

@ -1,74 +0,0 @@
# 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.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 289 KiB

View File

@ -1,363 +0,0 @@
<?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=&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=&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; ///&lt; protection against internal software attacks using ACLs.
uint8_t rollback_protection : 1; ///&lt; roll-back protection.
uint8_t tamper_proof : 1; ///&lt; tamper-proof memory (will be deleted on tamper-attempts using board level or chip level sensors).
uint8_t internal_flash : 1; ///&lt; Internal flash.
uint8_t reserved : 4;
/**
* Encode support for hardening against various classes of attacks.
*/
struct ARM_STOR_HARDENING
{
uint8_t device_software : 1; ///&lt; device software (malware running on the device).
uint8_t board_level_attacks : 1; ///&lt; board level attacks (debug probes, copy protection fuses.)
uint8_t chip_level_attacks : 1; ///&lt; chip level attacks (tamper-protection).
uint8_t side_channel_attacks : 1; ///&lt; side channel attacks.
uint8_t reserved : 4;
} hardening_against; ///&lt; 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=&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=&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>&lt;&lt;uses&gt;&gt;</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>&lt;&lt;uses&gt;&gt;</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>&lt;&lt;uses&gt;&gt;</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=&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=&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=&lt;-</panel_attributes>
<additional_attributes>640.0;10.0;10.0;90.0</additional_attributes>
</element>
</diagram>

View File

@ -1,68 +0,0 @@
# 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

View File

@ -1,10 +0,0 @@
{
"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
}
}
}

View File

@ -1,60 +0,0 @@
/** @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_MBED_OS_VERSION
* 3 => mbedosV3
* 4 => morpheus
*/
/* default values */
#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)
*
* */
#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
#if defined STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS
#define CFSTORE_STORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS
#endif
#endif /*__CFSTORE_CONFIG_H*/

View File

@ -1,120 +0,0 @@
/** @file cfstore_debug.h
*
* component debug header file.
*/
#ifndef __CFSTORE_DEBUG
#define __CFSTORE_DEBUG
#include <stdint.h>
#include <assert.h>
#include <stdio.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*/

View File

@ -1,326 +0,0 @@
/*
* 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 */

View File

@ -1,40 +0,0 @@
/*-
* 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_ */

View File

@ -1,65 +0,0 @@
/** @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_ */

View File

@ -1,89 +0,0 @@
/*
* 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.
*
*/
// This file is deprecated so deprecation warnings when building it are silenced
#if defined ( __CC_ARM )
#pragma diag_suppress 1361 // Deprecated declaration
#elif defined ( __GNUC__ )
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#include <stdint.h>
#include <Driver_Common.h>
#include "storage_volume_manager.h"
#include "cfstore_config.h"
#include "cfstore_debug.h"
#include "cfstore_svm.h"
/** @file cfstore_svm.cpp
*
* This module is provides a C wrapper to the C++ storage-volume-manager.h API,
* so it can be called by the C-HAL implementation configuration_store.c
*/
#ifndef CFSTORE_SVM_VOL_01_START_OFFSET
#define CFSTORE_SVM_VOL_01_START_OFFSET 0x80000UL
#endif
#ifndef CFSTORE_SVM_VOL_01_SIZE
#define CFSTORE_SVM_VOL_01_SIZE 0x80000UL
#endif
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_MTD_K64F;
static ARM_DRIVER_STORAGE *cfstore_svm_storage_drv = &ARM_Driver_Storage_MTD_K64F;
/* the storage volume manager instance used to generate virtual mtd descriptors */
StorageVolumeManager volumeManager;
/* used only for the initialization of the volume-manager. */
static void cfstore_svm_volume_manager_initialize_callback(int32_t status)
{
CFSTORE_FENTRYLOG("%s: with status %d" , __func__, (int) status);
}
static void cfstore_svm_journal_mtc_callback(int32_t status, ARM_STORAGE_OPERATION operation)
{
CFSTORE_FENTRYLOG("%s: operation %d with status %d" , __func__, (int) operation, (int) status);
}
int32_t cfstore_svm_init(struct _ARM_DRIVER_STORAGE *storage_mtd)
{
int32_t ret = ARM_DRIVER_OK;
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
ret = volumeManager.initialize(cfstore_svm_storage_drv, cfstore_svm_volume_manager_initialize_callback);
if(ret < ARM_DRIVER_OK) {
CFSTORE_ERRLOG("%s:debug: volume-manager::initialize() failed for storage_mtd=%p (ret=%d)", __func__, storage_mtd, (int) ret);
return ret;
}
ret = volumeManager.addVolume_C(CFSTORE_SVM_VOL_01_START_OFFSET, CFSTORE_SVM_VOL_01_SIZE, storage_mtd);
if(ret < ARM_DRIVER_OK) {
CFSTORE_ERRLOG("%s:debug: volume-manager::addVolume_C() failed for storage_mtd=%p (ret=%d)", __func__, storage_mtd, (int) ret);
return ret;
}
ret = storage_mtd->Initialize(cfstore_svm_journal_mtc_callback);
if(ret < ARM_DRIVER_OK) {
CFSTORE_ERRLOG("%s:debug: storage_mtd->initialize() failed for storage_mtd=%p (ret=%d)", __func__, storage_mtd, (int) ret);
return ret;
}
return ret;
}
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */

View File

@ -1,41 +0,0 @@
/*
* mbed Microcontroller Library
* Copyright (c) 2006-2016 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/** @file cfstore_svm.h
*
* This is the interface file to configuration store storage volume manager.
*/
#ifndef __CFSTORE_SVM_H_
#define __CFSTORE_SVM_H_
#include <Driver_Storage.h>
#ifdef __cplusplus
extern "C" {
#endif
int32_t cfstore_svm_init(struct _ARM_DRIVER_STORAGE *mtd);
#ifdef __cplusplus
}
#endif
#endif /*__CFSTORE_SVM_H_ */

View File

@ -1,744 +0,0 @@
/* @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.
*/
// This file is deprecated so deprecation warnings when building it are silenced
#if defined ( __CC_ARM )
#pragma diag_suppress 1361 // Deprecated declaration
#elif defined ( __GNUC__ )
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#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_MTD_K64F;
const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_MTD_K64F;
ret = FlashJournal_initialize(&jrnl, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, NULL);
if(ret < JOURNAL_STATUS_OK){
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;
}
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;
}

View File

@ -1,86 +0,0 @@
/** @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 */

View File

@ -1,76 +0,0 @@
/** @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 */

View File

@ -1,30 +0,0 @@
/* 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.
*
*/

View File

@ -1,220 +0,0 @@
/**********************************************************************
*
* Filename: flash_journal_crc.c
*
* Description: Slow and fast implementations of the CRC standards.
*
* Notes: The parameters for each supported CRC standard are
* defined in the header file crc.h. The implementations
* here should stand up to further additions to that list.
*
*
* Copyright (c) 2000 by Michael Barr. This software is placed into
* the public domain and may be used for any purpose. However, this
* notice must not be changed or removed and no warranty is either
* expressed or implied by its publication or distribution.
**********************************************************************/
#include "flash-journal-strategy-sequential/flash_journal_crc.h"
#define FALSE 0
#define TRUE !FALSE
#define CRC_NAME "CRC-32"
#define POLYNOMIAL 0x04C11DB7
#define INITIAL_REMAINDER 0xFFFFFFFF
#define FINAL_XOR_VALUE 0xFFFFFFFF
#define REFLECT_DATA TRUE
#define REFLECT_REMAINDER TRUE
#define CHECK_VALUE 0xCBF43926
/*
* Derive parameters from the standard-specific parameters in crc.h.
*/
#define WIDTH (8 * sizeof(flash_journal_crc32_t))
/* U postfix required to suppress the following warning with TOOLCHAIN_ARM:
* #61-D: integer operation result is out of range
*/
#define TOPBIT 0x80000000U
#if (REFLECT_DATA == TRUE)
#undef REFLECT_DATA
#define REFLECT_DATA(X) ((unsigned char) reflect((X), 8))
#else
#undef REFLECT_DATA
#define REFLECT_DATA(X) (X)
#endif
#if (REFLECT_REMAINDER == TRUE)
#undef REFLECT_REMAINDER
#define REFLECT_REMAINDER(X) ((flash_journal_crc32_t) reflect((X), WIDTH))
#else
#undef REFLECT_REMAINDER
#define REFLECT_REMAINDER(X) (X)
#endif
/*********************************************************************
*
* Function: reflect()
*
* Description: Reorder the bits of a binary sequence, by reflecting
* them about the middle position.
*
* Notes: No checking is done that nBits <= 32.
*
* Returns: The reflection of the original data.
*
*********************************************************************/
static uint32_t
reflect(uint32_t data, unsigned char nBits)
{
uint32_t reflection = 0x00000000;
unsigned char bit;
/*
* Reflect the data about the center bit.
*/
for (bit = 0; bit < nBits; ++bit)
{
/*
* If the LSB bit is set, set the reflection of it.
*/
if (data & 0x01)
{
reflection |= (1 << ((nBits - 1) - bit));
}
data = (data >> 1);
}
return (reflection);
} /* reflect() */
static flash_journal_crc32_t crcTable[256];
static flash_journal_crc32_t crcEngineRemainder = INITIAL_REMAINDER;
/*********************************************************************
*
* Function: flashJournalCrcInit()
*
* Description: Populate the partial CRC lookup table.
*
* Notes: This function must be rerun any time the CRC standard
* is changed. If desired, it can be run "offline" and
* the table results stored in an embedded system's ROM.
*
* Returns: None defined.
*
*********************************************************************/
void
flashJournalCrcInit(void)
{
flash_journal_crc32_t remainder;
int dividend;
unsigned char bit;
/*
* Compute the remainder of each possible dividend.
*/
for (dividend = 0; dividend < 256; ++dividend)
{
/*
* Start with the dividend followed by zeros.
*/
remainder = dividend << (WIDTH - 8);
/*
* Perform modulo-2 division, a bit at a time.
*/
for (bit = 8; bit > 0; --bit)
{
/*
* Try to divide the current data bit.
*/
if (remainder & TOPBIT)
{
remainder = (remainder << 1) ^ POLYNOMIAL;
}
else
{
remainder = (remainder << 1);
}
}
/*
* Store the result into the table.
*/
crcTable[dividend] = remainder;
}
} /* flashJournalCrcInit() */
/*********************************************************************
*
* Function: flashJournalCrcReset()
*
* Description: Resets internal state before calling crcCummulative().
*
* Notes: See the notes to crcCummulative().
*
* Returns: None defined.
*
*********************************************************************/
void
flashJournalCrcReset(void)
{
static unsigned initCalled = 0;
if (!initCalled) {
flashJournalCrcInit();
initCalled = 1;
}
crcEngineRemainder = INITIAL_REMAINDER;
} /* flashJournalCrcReset() */
/*********************************************************************
*
* Function: crcCummulative()
*
* Description: Compute the CRC of a group of messages.
*
* Notes:
* This function is intended to be used in the following way:
* - crcReset() is called first to reset internal state before the first
* fragment of a new message is processed with crcCummulative().
* - crcCummulative() called successfully appending additional message
* fragments to those previously supplied (in order), and returning
* the current crc for the message payload so far.
*
* Returns: The CRC of the message.
*
*********************************************************************/
flash_journal_crc32_t
flashJournalCrcCummulative(unsigned char const message[], int nBytes)
{
unsigned char data;
int byte;
/*
* Divide the message by the polynomial, a byte at a time.
*/
for (byte = 0; byte < nBytes; ++byte)
{
data = REFLECT_DATA(message[byte]) ^ (crcEngineRemainder >> (WIDTH - 8));
crcEngineRemainder = crcTable[data] ^ (crcEngineRemainder << 8);
}
/*
* The final remainder is the CRC.
*/
return (REFLECT_REMAINDER(crcEngineRemainder) ^ FINAL_XOR_VALUE);
} /* crcCummulative() */

View File

@ -1,34 +0,0 @@
/**********************************************************************
*
* Filename: flash_journal_crc.h.h
*
* Description: A header file describing the various CRC standards.
*
* Notes:
*
*
* Copyright (c) 2000 by Michael Barr. This software is placed into
* the public domain and may be used for any purpose. However, this
* notice must not be changed or removed and no warranty is either
* expressed or implied by its publication or distribution.
**********************************************************************/
#ifndef _flash_journal_crc_h
#define _flash_journal_crc_h
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef uint32_t flash_journal_crc32_t;
void flashJournalCrcReset(void);
flash_journal_crc32_t flashJournalCrcCummulative(unsigned char const message[], int nBytes);
#ifdef __cplusplus
}
#endif
#endif /* _flash_journal_crc_h */

View File

@ -1,175 +0,0 @@
/*
* Copyright (c) 2006-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __FLASH_JOURNAL_PRIVATE_H__
#define __FLASH_JOURNAL_PRIVATE_H__
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include "flash-journal/flash_journal.h"
static inline uint32_t roundUp_uint32(uint32_t N, uint32_t BOUNDARY) {
return ((((N) + (BOUNDARY) - 1) / (BOUNDARY)) * (BOUNDARY));
}
static inline uint32_t roundDown_uint32(uint32_t N, uint32_t BOUNDARY) {
return (((N) / (BOUNDARY)) * (BOUNDARY));
}
#define LCM_OF_ALL_ERASE_UNITS 4096 /* Assume an LCM of erase_units for now. This will be generalized later. */
static const uint32_t SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER = 0xFFFFFFFFUL;
static const uint32_t SEQUENTIAL_FLASH_JOURNAL_MAGIC = 0xCE02102AUL;
static const uint32_t SEQUENTIAL_FLASH_JOURNAL_VERSION = 1;
static const uint32_t SEQUENTIAL_FLASH_JOURNAL_HEADER_MAGIC = 0xCEA00AEEUL;
static const uint32_t SEQUENTIAL_FLASH_JOURNAL_HEADER_VERSION = 1;
typedef enum {
SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED,
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 Journal. The actual header would be an
* extension of this generic header, and would depend on the implementation
* strategy. Initialization algorithms can expect to find this generic header at
* the start of every Journal.
*/
typedef struct _SequentialFlashJournalHeader {
FlashJournalHeader_t genericHeader; /** Generic meta-data placed at the head of a Journal; common to all journal types. */
uint32_t magic; /** Sequential journal header specific magic code. */
uint32_t version; /** Revision number for this sequential journal header. */
uint32_t numSlots; /** Maximum number of logged blobs; i.e. maximum number of versions of the journaled payload. */
uint32_t sizeofSlot; /** Slot size. Each slot holds a header, blob-payload, and a tail. */
} SequentialFlashJournalHeader_t;
/**
* Meta-data placed at the head of a sequential-log entry.
*/
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 {
uint32_t sizeofBlob; /**< the size of the payload in this blob. */
uint32_t magic;
uint32_t sequenceNumber;
uint32_t crc32; /**< This field contains the CRC of the header, body (only including logged data),
* and the tail. The 'CRC32' field is assumed to hold 0x0 for the purpose of
* computing the CRC */
} SequentialFlashJournalLogTail_t;
#define SEQUENTIAL_JOURNAL_VALID_TAIL(TAIL_PTR) ((TAIL_PTR)->magic == SEQUENTIAL_FLASH_JOURNAL_MAGIC)
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 firstSlotOffset; /** Offset from the start of the journal header to the actual logged journal. */
uint32_t numSlots; /** Maximum number of logged blobs; i.e. maximum number of versions of the journaled payload. */
uint32_t sizeofSlot; /**< size of the log stride. */
uint32_t nextSequenceNumber; /**< the next valid sequence number to be used when logging the next blob. */
uint32_t currentBlobIndex; /**< index of the most recently written blob. */
SequentialFlashJournalState_t state; /**< state of the journal. SEQUENTIAL_JOURNAL_STATE_INITIALIZED being the default. */
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;
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 mtdEraseOffset;
};
struct {
uint64_t mtdOffset; /**< the current Storage offset at which data will be written. */
uint64_t mtdTailOffset; /**< Storage offset at which the SequentialFlashJournalLogTail_t will be logged for this log-entry. */
const uint8_t *dataBeingLogged; /**< temporary pointer aimed at the next data to be logged. */
size_t amountLeftToLog;
union {
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 mtdOffset; /**< the current Storage offset from which data is being read. */
uint8_t *dataBeingRead; /**< temporary pointer aimed at the next data to be read-into. */
size_t amountLeftToRead;
size_t logicalOffset; /**< the logical offset within the blob at which the next read will occur. */
} 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];
#define SLOT_ADDRESS(JOURNAL, INDEX) ((JOURNAL)->mtdStartOffset + (JOURNAL)->firstSlotOffset + ((INDEX) * (JOURNAL)->sizeofSlot))
#ifdef __cplusplus
}
#endif // __cplusplus
#endif /* __FLASH_JOURNAL_PRIVATE_H__ */

View File

@ -1,157 +0,0 @@
/*
* Copyright (c) 2006-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __FLASH_JOURNAL_STRATEGY_SEQUENTIAL_H__
#define __FLASH_JOURNAL_STRATEGY_SEQUENTIAL_H__
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include "flash-journal/flash_journal.h"
/**
* Create/format a sequential flash journal at a given offset within a storage
* device and with a given slot-cardinality.
*
* This function must be called *once* for each incarnation of a sequential
* journal.
*
* @param[in] mtd
* The underlying Storage driver.
*
* @param[in] numSlots
* Number of slots in the sequential journal. Each slot holds a header, blob-payload, and a tail.
*
* @param[in] callback
* Caller-defined callback to be invoked upon command completion
* in case the storage device executes operations asynchronously.
* Use a NULL pointer when no callback signals are required.
*
* @note: this is an asynchronous operation, but it can finish
* synchronously if the underlying MTD supports that.
*
* @return
* The function executes in the following ways:
* - When the operation is asynchronous, the function only starts the
* initialization and control returns to the caller with an
* JOURNAL_STATUS_OK before the actual completion of the operation (or with
* an appropriate error code in case of failure). When the operation is
* completed the command callback is invoked with 1 passed in as the
* 'status' parameter of the callback. In case of errors, the completion
* callback is invoked with an error status.
* - When the operation is executed by the journal in a blocking (i.e.
* synchronous) manner, control returns to the caller only upon the actual
* completion of the operation or the discovery of a failure condition. In
* this case, the function returns 1 to signal successful synchronous
* completion or an appropriate error code, and no further
* invocation of the completion callback should be expected at a later time.
*
* Here's a code snippet to suggest how this API might be used by callers:
* \code
* ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code
* int32_t returnValue = flashJournalStrategySequential_format(MTD, numSlots, callbackHandler);
* if (returnValue < JOURNAL_STATUS_OK) {
* // handle error
* } else if (returnValue == JOURNAL_STATUS_OK) {
* ASSERT(MTD->GetCapabilities().asynchronous_ops == 1);
* // handle early return from asynchronous execution
* } else {
* ASSERT(returnValue == 1);
* // handle synchronous completion
* }
* \endcode
*
* +-------------------------------+ ^
* | | |
* | Journal Header | |
* | starts with generic header | |
* | followed by specific header | |
* | | | multiple of program_unit
* +-------------------------------+ | and erase-boundary
* +-------------------------------+ |
* | | |
* | padding to allow alignment | |
* | | |
* +-------------------------------+ v
* +-------------------------------+
* | +---------------------------+ | ^
* | | slot header | | |
* | | aligned with program_unit| | |
* | +---------------------------+ | | slot 0
* | | | aligned with LCM of all erase boundaries
* | | |
* | | |
* | | |
* | BLOB0 | |
* | | |
* | | |
* | +---------------------------+ | |
* | | slot tail | | |
* | | aligned with program_unit| | |
* | +---------------------------+ | |
* +-------------------------------+ v
* +-------------------------------+
* | +---------------------------+ | ^
* | | slot header | | |
* | | aligned with program_unit| | |
* | +---------------------------+ | | slot 1
* | | | aligned with LCM of all erase boundaries
* | BLOB1 | |
* | | |
* . . .
* . . .
*
* . . .
* . BLOB(N-1) . .
* | | |
* | +---------------------------+ | | slot 'N - 1'
* | | slot tail | | | aligned with LCM of all erase boundaries
* | | aligned with program_unit| | |
* | +---------------------------+ | |
* +-------------------------------+ v
*/
int32_t flashJournalStrategySequential_format(ARM_DRIVER_STORAGE *mtd,
uint32_t numSlots,
FlashJournal_Callback_t callback);
int32_t flashJournalStrategySequential_initialize(FlashJournal_t *journal,
ARM_DRIVER_STORAGE *mtd,
const FlashJournal_Ops_t *ops,
FlashJournal_Callback_t callback);
FlashJournal_Status_t flashJournalStrategySequential_getInfo(FlashJournal_t *journal, FlashJournal_Info_t *info);
int32_t flashJournalStrategySequential_read(FlashJournal_t *journal, void *blob, size_t n);
int32_t flashJournalStrategySequential_readFrom(FlashJournal_t *journal, size_t offset, void *blob, size_t n);
int32_t flashJournalStrategySequential_log(FlashJournal_t *journal, const void *blob, size_t n);
int32_t flashJournalStrategySequential_commit(FlashJournal_t *journal);
int32_t flashJournalStrategySequential_reset(FlashJournal_t *journal);
static const FlashJournal_Ops_t FLASH_JOURNAL_STRATEGY_SEQUENTIAL = {
flashJournalStrategySequential_initialize,
flashJournalStrategySequential_getInfo,
flashJournalStrategySequential_read,
flashJournalStrategySequential_readFrom,
flashJournalStrategySequential_log,
flashJournalStrategySequential_commit,
flashJournalStrategySequential_reset
};
#ifdef __cplusplus
}
#endif // __cplusplus
#endif /* __FLASH_JOURNAL_STRATEGY_SEQUENTIAL_H__ */

View File

@ -1,477 +0,0 @@
/*
* Copyright (c) 2006-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "flash-journal-strategy-sequential/flash_journal_crc.h"
#include "flash-journal-strategy-sequential/flash_journal_private.h"
#include "flash-journal-strategy-sequential/flash_journal_strategy_sequential.h"
#include "support_funcs.h"
#include <string.h>
#include <stdio.h>
SequentialFlashJournal_t *activeJournal;
/*
* forward declarations of static-inline helper functions.
*/
static inline int32_t mtdGetTotalCapacity(ARM_DRIVER_STORAGE *mtd, uint64_t *capacityP);
static inline int32_t flashJournalStrategySequential_format_sanityChecks(ARM_DRIVER_STORAGE *mtd, uint32_t numSlots);
static inline int32_t flashJournalStrategySequential_read_sanityChecks(SequentialFlashJournal_t *journal, const void *blob, size_t sizeofBlob);
static inline int32_t flashJournalStrategySequential_log_sanityChecks(SequentialFlashJournal_t *journal, const void *blob, size_t sizeofBlob);
static inline int32_t flashJournalStrategySequential_commit_sanityChecks(SequentialFlashJournal_t *journal);
int32_t flashJournalStrategySequential_format(ARM_DRIVER_STORAGE *mtd,
uint32_t numSlots,
FlashJournal_Callback_t callback)
{
int32_t rc;
if ((rc = flashJournalStrategySequential_format_sanityChecks(mtd, numSlots)) != JOURNAL_STATUS_OK) {
return rc;
}
ARM_STORAGE_INFO mtdInfo;
if (mtd->GetInfo(&mtdInfo) < ARM_DRIVER_OK) {
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
uint64_t mtdAddr;
if (mtdGetStartAddr(mtd, &mtdAddr) < JOURNAL_STATUS_OK) {
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
formatInfoSingleton.mtd = mtd;
formatInfoSingleton.mtdAddr = mtdAddr;
formatInfoSingleton.callback = callback;
formatInfoSingleton.mtdProgramUnit = mtdInfo.program_unit;
if ((rc = setupSequentialJournalHeader(&formatInfoSingleton.header, mtd, mtdInfo.total_storage, numSlots)) != JOURNAL_STATUS_OK) {
return rc;
}
/* initialize MTD */
rc = mtd->Initialize(formatHandler);
if (rc < ARM_DRIVER_OK) {
return JOURNAL_STATUS_STORAGE_API_ERROR;
} else if (rc == ARM_DRIVER_OK) {
return JOURNAL_STATUS_OK; /* An asynchronous operation is pending; it will result in a completion callback
* where the rest of processing will take place. */
}
if (rc != 1) {
return JOURNAL_STATUS_STORAGE_API_ERROR; /* synchronous completion is expected to return 1 */
}
/* progress the rest of the create state-machine */
return flashJournalStrategySequential_format_progress(ARM_DRIVER_OK, ARM_STORAGE_OPERATION_INITIALIZE);
}
/**
* Validate a header at the start of the MTD.
*
* @param [in/out] headerP
* Caller-allocated header which gets filled in during validation.
* @return JOURNAL_STATUS_OK if the header is sane. As a side-effect, the memory
* pointed to by 'headerP' is initialized with the header.
*/
int32_t readAndVerifyJournalHeader(SequentialFlashJournal_t *journal, SequentialFlashJournalHeader_t *headerP)
{
if (headerP == NULL) {
return JOURNAL_STATUS_PARAMETER;
}
int32_t rc = journal->mtd->ReadData(journal->mtdStartOffset, headerP, sizeof(SequentialFlashJournalHeader_t));
if (rc < ARM_DRIVER_OK) {
return JOURNAL_STATUS_STORAGE_IO_ERROR;
} else if (rc == ARM_DRIVER_OK) {
ARM_STORAGE_CAPABILITIES mtdCaps = journal->mtd->GetCapabilities();
if (!mtdCaps.asynchronous_ops) {
return JOURNAL_STATUS_ERROR; /* asynchronous_ops must be set if MTD returns ARM_DRIVER_OK. */
}
return JOURNAL_STATUS_ERROR; /* TODO: handle init with pending asynchronous activity. */
}
if ((headerP->genericHeader.magic != FLASH_JOURNAL_HEADER_MAGIC) ||
(headerP->genericHeader.version != FLASH_JOURNAL_HEADER_VERSION) ||
(headerP->genericHeader.sizeofHeader != sizeof(SequentialFlashJournalHeader_t)) ||
(headerP->magic != SEQUENTIAL_FLASH_JOURNAL_HEADER_MAGIC) ||
(headerP->version != SEQUENTIAL_FLASH_JOURNAL_HEADER_VERSION)) {
return JOURNAL_STATUS_NOT_FORMATTED;
}
uint32_t expectedCRC = headerP->genericHeader.checksum;
headerP->genericHeader.checksum = 0;
flashJournalCrcReset();
uint32_t computedCRC = flashJournalCrcCummulative((const unsigned char *)&headerP->genericHeader, sizeof(SequentialFlashJournalLogHead_t));
if (computedCRC != expectedCRC) {
//printf("readAndVerifyJournalHeader: checksum mismatch during header verification: expected = %u, computed = %u\n", (unsigned int) expectedCRC, (unsigned int) computedCRC);
return JOURNAL_STATUS_METADATA_ERROR;
}
return JOURNAL_STATUS_OK;
}
int32_t flashJournalStrategySequential_initialize(FlashJournal_t *_journal,
ARM_DRIVER_STORAGE *mtd,
const FlashJournal_Ops_t *ops,
FlashJournal_Callback_t callback)
{
int32_t rc;
/* initialize MTD */
rc = mtd->Initialize(mtdHandler);
if (rc < ARM_DRIVER_OK) {
memset(_journal, 0, sizeof(FlashJournal_t));
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
if (rc == ARM_DRIVER_OK) {
ARM_STORAGE_CAPABILITIES mtdCaps = mtd->GetCapabilities();
if (!mtdCaps.asynchronous_ops) {
return JOURNAL_STATUS_ERROR; /* asynchronous_ops must be set if MTD returns ARM_DRIVER_OK. */
}
return JOURNAL_STATUS_ERROR; /* TODO: handle init with pending asynchronous activity. */
}
SequentialFlashJournal_t *journal;
activeJournal = journal = (SequentialFlashJournal_t *)_journal;
journal->state = SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED;
journal->mtd = mtd;
/* Setup start address within MTD. */
if ((rc = mtdGetStartAddr(journal->mtd, &journal->mtdStartOffset)) != JOURNAL_STATUS_OK) {
return rc;
}
/* fetch MTD's total capacity */
uint64_t mtdCapacity;
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;
}
SequentialFlashJournalHeader_t journalHeader;
if ((rc = readAndVerifyJournalHeader(journal, &journalHeader)) != JOURNAL_STATUS_OK) {
return rc;
}
/* initialize the journal structure */
memcpy(&journal->ops, ops, sizeof(FlashJournal_Ops_t));
journal->mtdCapabilities = mtd->GetCapabilities(); /* fetch MTD's capabilities */
journal->firstSlotOffset = journalHeader.genericHeader.journalOffset;
journal->numSlots = journalHeader.numSlots;
journal->sizeofSlot = journalHeader.sizeofSlot;
/* effective capacity */
journal->info.capacity = journal->sizeofSlot
- roundUp_uint32(sizeof(SequentialFlashJournalLogHead_t), mtdInfo.program_unit)
- roundUp_uint32(sizeof(SequentialFlashJournalLogTail_t), mtdInfo.program_unit);
journal->info.program_unit = mtdInfo.program_unit;
journal->callback = callback;
journal->prevCommand = FLASH_JOURNAL_OPCODE_INITIALIZE;
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;
if (journal->prevCommand != FLASH_JOURNAL_OPCODE_READ_BLOB) {
journal->read.logicalOffset = 0;
}
int32_t rc;
if ((rc = flashJournalStrategySequential_read_sanityChecks(journal, blob, sizeofBlob)) != JOURNAL_STATUS_OK) {
return rc;
}
journal->read.blob = blob;
journal->read.sizeofBlob = sizeofBlob;
if (journal->read.logicalOffset == 0) {
{ /* Establish the sanity of this slot before proceeding with the read. */
uint32_t headSequenceNumber;
SequentialFlashJournalLogTail_t tail;
if (slotIsSane(journal,
SLOT_ADDRESS(journal, journal->currentBlobIndex),
&headSequenceNumber,
&tail) != 1) {
/* TODO: rollback to an older slot. */
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
}
journal->read.mtdOffset = SLOT_ADDRESS(journal, journal->currentBlobIndex) + sizeof(SequentialFlashJournalLogHead_t);
} else {
/* journal->read.offset is already set from the previous read execution */
// printf("flashJournalStrategySequential_read: continuing read of %lu from offset %lu\n", sizeofBlob, (uint32_t)journal->read.offset);
}
journal->read.dataBeingRead = blob;
journal->read.amountLeftToRead = ((journal->info.sizeofJournaledBlob - journal->read.logicalOffset) < sizeofBlob) ?
(journal->info.sizeofJournaledBlob - journal->read.logicalOffset) : sizeofBlob;
// printf("amount left to read %u\n", journal->read.amountLeftToRead);
journal->state = SEQUENTIAL_JOURNAL_STATE_READING;
journal->prevCommand = FLASH_JOURNAL_OPCODE_READ_BLOB;
return flashJournalStrategySequential_read_progress();
}
int32_t flashJournalStrategySequential_readFrom(FlashJournal_t *_journal, size_t offset, void *blob, size_t sizeofBlob)
{
SequentialFlashJournal_t *journal;
activeJournal = journal = (SequentialFlashJournal_t *)_journal;
journal->read.logicalOffset = offset;
int32_t rc;
if ((rc = flashJournalStrategySequential_read_sanityChecks(journal, blob, sizeofBlob)) != JOURNAL_STATUS_OK) {
return rc;
}
journal->read.blob = blob;
journal->read.sizeofBlob = sizeofBlob;
journal->read.mtdOffset = SLOT_ADDRESS(journal, journal->currentBlobIndex) + sizeof(SequentialFlashJournalLogHead_t) + offset;
journal->read.dataBeingRead = blob;
journal->read.amountLeftToRead = ((journal->info.sizeofJournaledBlob - journal->read.logicalOffset) < sizeofBlob) ?
(journal->info.sizeofJournaledBlob - journal->read.logicalOffset) : sizeofBlob;
// printf("amount left to read %u\n", journal->read.amountLeftToRead);
journal->state = SEQUENTIAL_JOURNAL_STATE_READING;
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) {
/*
* This is the first log in the sequence. We have to begin by identifying a new slot and erasing it.
*/
/* choose the next slot */
uint32_t logBlobIndex = journal->currentBlobIndex + 1;
if (logBlobIndex == journal->numSlots) {
logBlobIndex = 0;
}
/* setup an erase for the slot */
journal->log.mtdEraseOffset = SLOT_ADDRESS(journal, logBlobIndex);
journal->state = SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE; /* start with erasing the log region */
journal->prevCommand = FLASH_JOURNAL_OPCODE_LOG_BLOB;
} else {
/* This is a continuation of an ongoing logging sequence. */
journal->log.dataBeingLogged = blob;
journal->log.amountLeftToLog = size;
}
/* progress the state machine for log() */
return flashJournalStrategySequential_log_progress();
}
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) {
/* the tail has already been setup during previous calls to log(); we can now include it in the crc32. */
journal->log.tail.crc32 = flashJournalCrcCummulative((const unsigned char *)&journal->log.tail, sizeof(SequentialFlashJournalLogTail_t));
flashJournalCrcReset();
journal->log.mtdOffset = journal->log.mtdTailOffset;
journal->log.dataBeingLogged = (const uint8_t *)&journal->log.tail;
journal->log.amountLeftToLog = sizeof(SequentialFlashJournalLogTail_t);
journal->state = SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL;
} else {
uint32_t logBlobIndex = journal->currentBlobIndex + 1;
if (logBlobIndex == journal->numSlots) {
logBlobIndex = 0;
}
journal->log.mtdEraseOffset = SLOT_ADDRESS(journal, logBlobIndex);
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();
}
int32_t mtdGetTotalCapacity(ARM_DRIVER_STORAGE *mtd, uint64_t *capacityP)
{
/* fetch MTD's INFO */
ARM_STORAGE_INFO mtdInfo;
int32_t rc = mtd->GetInfo(&mtdInfo);
if (rc != ARM_DRIVER_OK) {
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
*capacityP = mtdInfo.total_storage;
return JOURNAL_STATUS_OK;
}
int32_t flashJournalStrategySequential_format_sanityChecks(ARM_DRIVER_STORAGE *mtd, uint32_t numSlots)
{
/*
* basic parameter checking
*/
if ((mtd == NULL) || (numSlots == 0)) {
return JOURNAL_STATUS_PARAMETER;
}
ARM_STORAGE_INFO mtdInfo;
if (mtd->GetInfo(&mtdInfo) < ARM_DRIVER_OK) {
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
if (mtdInfo.total_storage == 0) {
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
uint64_t mtdAddr;
if (mtdGetStartAddr(mtd, &mtdAddr) < JOURNAL_STATUS_OK) {
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
if (mtd->GetBlock(mtdAddr, NULL) < ARM_DRIVER_OK) { /* check validity of journal's start address */
return JOURNAL_STATUS_PARAMETER;
}
if (mtd->GetBlock(mtdAddr + mtdInfo.total_storage - 1, NULL) < ARM_DRIVER_OK) { /* check validity of the journal's end address */
return JOURNAL_STATUS_PARAMETER;
}
if ((mtdAddr % mtdInfo.program_unit) != 0) { /* ensure that the journal starts at a programmable unit */
return JOURNAL_STATUS_PARAMETER;
}
if ((mtdAddr % LCM_OF_ALL_ERASE_UNITS) != 0) { /* ensure that the journal starts and ends at an erase-boundary */
return JOURNAL_STATUS_PARAMETER;
}
return JOURNAL_STATUS_OK;
}
int32_t flashJournalStrategySequential_read_sanityChecks(SequentialFlashJournal_t *journal, const void *blob, size_t sizeofBlob)
{
if ((journal == NULL) || (blob == NULL) || (sizeofBlob == 0)) {
return JOURNAL_STATUS_PARAMETER;
}
if ((journal->state == SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED) || (journal->state == SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS)) {
return JOURNAL_STATUS_NOT_INITIALIZED;
}
if (journal->state != SEQUENTIAL_JOURNAL_STATE_INITIALIZED) {
return JOURNAL_STATUS_ERROR; /* journal is in an un-expected state. */
}
// printf("read sanity checks: logicalOffset = %lu, sizeofJournaledBlob = %lu\n", (uint32_t)journal->read.logicalOffset, (uint32_t)journal->info.sizeofJournaledBlob);
if ((journal->info.sizeofJournaledBlob == 0) || (journal->read.logicalOffset >= journal->info.sizeofJournaledBlob)) {
journal->read.logicalOffset = 0;
return JOURNAL_STATUS_EMPTY;
}
return JOURNAL_STATUS_OK;
}
int32_t flashJournalStrategySequential_log_sanityChecks(SequentialFlashJournal_t *journal, const void *blob, size_t sizeofBlob)
{
if ((journal == NULL) || (blob == NULL) || (sizeofBlob == 0)) {
return JOURNAL_STATUS_PARAMETER;
}
if ((journal->state == SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED) || (journal->state == SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS)) {
return JOURNAL_STATUS_NOT_INITIALIZED;
}
if ((journal->state != SEQUENTIAL_JOURNAL_STATE_INITIALIZED) && (journal->state != SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY)) {
return JOURNAL_STATUS_ERROR; /* journal is in an un-expected state. */
}
if (journal->state == SEQUENTIAL_JOURNAL_STATE_INITIALIZED) {
if (sizeofBlob > journal->info.capacity) {
return JOURNAL_STATUS_BOUNDED_CAPACITY; /* adding this log chunk would cause us to exceed capacity (write past the tail). */
}
} else if (journal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY) {
if (journal->log.mtdOffset + sizeofBlob > journal->log.mtdTailOffset) {
return JOURNAL_STATUS_BOUNDED_CAPACITY; /* adding this log chunk would cause us to exceed capacity (write past the tail). */
}
}
/* ensure that the request is at least as large as the minimum program unit */
if (sizeofBlob < journal->info.program_unit) {
return JOURNAL_STATUS_SMALL_LOG_REQUEST;
}
return JOURNAL_STATUS_OK;
}
int32_t flashJournalStrategySequential_commit_sanityChecks(SequentialFlashJournal_t *journal)
{
if (journal == NULL) {
return JOURNAL_STATUS_PARAMETER;
}
if (journal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY) {
if (journal->prevCommand != FLASH_JOURNAL_OPCODE_LOG_BLOB) {
return JOURNAL_STATUS_ERROR;
}
if ((journal->log.mtdOffset == ARM_STORAGE_INVALID_OFFSET) ||
(journal->log.mtdTailOffset == ARM_STORAGE_INVALID_OFFSET) ||
(journal->log.mtdTailOffset < journal->log.mtdOffset) ||
(journal->log.tail.sizeofBlob == 0) ||
(journal->log.tail.sizeofBlob > journal->info.capacity)) {
return JOURNAL_STATUS_ERROR; /* journal is in an un-expected state. */
}
}
return JOURNAL_STATUS_OK;
}

View File

@ -1,727 +0,0 @@
/*
* Copyright (c) 2006-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "flash-journal-strategy-sequential/flash_journal_crc.h"
#include "support_funcs.h"
#include <string.h>
#include <stdio.h>
#include <inttypes.h>
struct FormatInfo_t formatInfoSingleton;
int32_t mtdGetStartAddr(ARM_DRIVER_STORAGE *mtd, uint64_t *startAddrP)
{
ARM_STORAGE_BLOCK mtdBlock;
if ((mtd->GetNextBlock(NULL, &mtdBlock)) != ARM_DRIVER_OK) {
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
if (!ARM_STORAGE_VALID_BLOCK(&mtdBlock)) {
return JOURNAL_STATUS_ERROR;
}
*startAddrP = mtdBlock.addr;
return JOURNAL_STATUS_OK;
}
/**
* Check the sanity of a given slot
* @param journal
* @param slotOffset
* @param [out] headSequenceNumberP
* sequence number of the slot as read from the header.
* @param [out] tailP
* the tail of the slot
* @return 1 if the slot is valid; i.e. if head and tail match, and if CRC32 agrees.
*/
int32_t slotIsSane(SequentialFlashJournal_t *journal,
uint64_t slotOffset,
uint32_t *headSequenceNumberP,
SequentialFlashJournalLogTail_t *tailP)
{
int32_t rc;
ARM_DRIVER_STORAGE *mtd = journal->mtd;
SequentialFlashJournalLogHead_t head;
/* TODO: add support for asynchronous read */
if (((rc = mtd->ReadData(slotOffset, &head, sizeof(SequentialFlashJournalLogHead_t))) < ARM_DRIVER_OK) ||
(rc != sizeof(SequentialFlashJournalLogHead_t))) {
if ((rc == ARM_DRIVER_OK) && (journal->mtdCapabilities.asynchronous_ops)) {
return JOURNAL_STATUS_UNSUPPORTED;
}
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
/* compute the CRC32 of the header */
flashJournalCrcReset();
flashJournalCrcCummulative((const unsigned char *)&head, sizeof(SequentialFlashJournalLogHead_t));
// printf("head->version: %lu\n", journal->initScan.head.version);
// printf("head->magic: %lx\n", journal->initScan.head.magic);
// printf("head->sequenceNumber: %lu\n", journal->initScan.head.sequenceNumber);
// printf("head->reserved: %lu\n", journal->initScan.head.reserved);
if (SEQUENTIAL_JOURNAL_VALID_HEAD(&head)) {
*headSequenceNumberP = head.sequenceNumber;
// printf("found valid header with sequenceNumber %" PRIu32 "\n", *headSequenceNumberP);
uint64_t tailoffset = slotOffset
- ((slotOffset - SLOT_ADDRESS(journal, 0)) % journal->sizeofSlot)
+ journal->sizeofSlot
- sizeof(SequentialFlashJournalLogTail_t);
// printf("hoping to read a tail at offset %lu\n", (uint32_t)tailoffset);
/* TODO: add support for asynchronous read */
if (((rc = mtd->ReadData(tailoffset, tailP, sizeof(SequentialFlashJournalLogTail_t))) < ARM_DRIVER_OK) ||
(rc != sizeof(SequentialFlashJournalLogTail_t))) {
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
if (SEQUENTIAL_JOURNAL_VALID_TAIL(tailP) && (tailP->sequenceNumber == *headSequenceNumberP)) {
// printf("found valid tail\n");
/* iterate over the body of the slot computing CRC */
#define CRC_CHUNK_SIZE 64
uint8_t crcBuffer[CRC_CHUNK_SIZE];
uint64_t bodyIndex = 0;
uint64_t bodyOffset = slotOffset + sizeof(SequentialFlashJournalLogHead_t);
while (bodyIndex < tailP->sizeofBlob) {
size_t sizeofReadOperation;
if ((tailP->sizeofBlob - bodyIndex) > CRC_CHUNK_SIZE) {
sizeofReadOperation = CRC_CHUNK_SIZE;
} else {
sizeofReadOperation = (tailP->sizeofBlob - bodyIndex);
}
/* TODO: add support for asynchronous read */
rc = mtd->ReadData(bodyOffset + bodyIndex, crcBuffer, sizeofReadOperation);
if (rc != (int32_t)sizeofReadOperation) {
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
bodyIndex += sizeofReadOperation;
flashJournalCrcCummulative(crcBuffer, sizeofReadOperation);
}
/* compute CRC32 over the tail */
/* extract existing CRC32 from the tail. The CRC32 field in the tail needs to contain 0 before CRC32 can be computed over it. */
uint32_t expectedCRC32 = tailP->crc32;
tailP->crc32 = 0;
uint32_t crc32 = flashJournalCrcCummulative((const unsigned char *)tailP, sizeof(SequentialFlashJournalLogTail_t));
flashJournalCrcReset();
// printf("expectedCRC32: 0x%x, computedCRC32: 0x%x\n", expectedCRC32, crc32);
if (crc32 == expectedCRC32) {
return 1;
}
}
}
return JOURNAL_STATUS_ERROR;
}
int32_t setupSequentialJournalHeader(SequentialFlashJournalHeader_t *headerP, ARM_DRIVER_STORAGE *mtd, uint64_t totalSize, uint32_t numSlots)
{
ARM_STORAGE_INFO mtdInfo;
if (mtd->GetInfo(&mtdInfo) < ARM_DRIVER_OK) {
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
headerP->genericHeader.magic = FLASH_JOURNAL_HEADER_MAGIC;
headerP->genericHeader.version = FLASH_JOURNAL_HEADER_VERSION;
headerP->genericHeader.sizeofHeader = sizeof(SequentialFlashJournalHeader_t);
/* Determine 'journalOffset'.
* Constraint: journal header should start and terminate at an erase-boundary
* (so that slot-0 can be erased independently), and also a program-unit boundary.
*/
headerP->genericHeader.journalOffset = roundUp_uint32(headerP->genericHeader.sizeofHeader, LCM_OF_ALL_ERASE_UNITS);
if ((headerP->genericHeader.journalOffset % mtdInfo.program_unit) != 0) {
//printf("setupSequentialJournalHeader: journalOffset is not a multiple of MTD's program_unit\r\n");
return JOURNAL_STATUS_PARAMETER;
}
headerP->magic = SEQUENTIAL_FLASH_JOURNAL_HEADER_MAGIC;
headerP->version = SEQUENTIAL_FLASH_JOURNAL_HEADER_VERSION;
headerP->numSlots = numSlots;
/* Determine 'sizeofSlot'.
* Constraint: slot-size should be a multiple of the erase-units of all involved storage blocks.
*/
uint64_t spaceAvailableForSlots = totalSize - headerP->genericHeader.journalOffset;
headerP->sizeofSlot = roundDown_uint32(spaceAvailableForSlots / numSlots, LCM_OF_ALL_ERASE_UNITS);
if (headerP->sizeofSlot == 0) {
//printf("setupSequentialJournalHeader: not enough space to create %" PRIu32 " slots\r\n", numSlots);
return JOURNAL_STATUS_PARAMETER;
}
headerP->genericHeader.totalSize = headerP->genericHeader.journalOffset + (headerP->sizeofSlot * numSlots);
//printf("setupSequentialJournalHeader: header size = %" PRIu32 ", journalOffset = %" PRIu32 ", sizeofSlot = %" PRIu32 ", totalSize = %lu\n", headerP->genericHeader.sizeofHeader, headerP->genericHeader.journalOffset, headerP->sizeofSlot, (uint32_t)headerP->genericHeader.totalSize);
/* compute checksum over the entire header */
headerP->genericHeader.checksum = 0;
flashJournalCrcReset();
headerP->genericHeader.checksum = flashJournalCrcCummulative((const unsigned char *)&headerP->genericHeader, sizeof(SequentialFlashJournalLogHead_t));
return JOURNAL_STATUS_OK;
}
int32_t discoverLatestLoggedBlob(SequentialFlashJournal_t *journal)
{
/* reset top level journal metadata prior to scanning headers. */
journal->nextSequenceNumber = SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER; /* we are currently unaware of previously written blobs */
journal->currentBlobIndex = journal->numSlots;
journal->info.sizeofJournaledBlob = 0;
/* begin header-scan from the first block of the MTD */
journal->initScan.currentOffset = SLOT_ADDRESS(journal, 0);
journal->state = SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS;
// printf("discoverLatestLoggedBlob: start of init scan\n");
for (unsigned blobIndex = 0;
blobIndex < journal->numSlots;
blobIndex++, journal->initScan.currentOffset += journal->sizeofSlot) {
// printf("discoverLatestLoggedBlob: blob index %u\n", blobIndex);
/* TODO: it is possible that the header structure spans multiple blocks, needing multiple reads. */
if (slotIsSane(journal,
journal->initScan.currentOffset,
&journal->initScan.headSequenceNumber,
&journal->initScan.tail) == 1) {
// printf("found valid blob with sequence number %lu\n", journal->initScan.headSequenceNumber);
uint32_t nextSequenceNumber = journal->initScan.headSequenceNumber + 1;
if (nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) {
nextSequenceNumber = 0;
}
/* Have we found the best of the slots seen so far? */
if ((journal->nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) ||
/* We take advantage of properties of unsigned arithmetic in the following
* expression.
*
* We want to calculate if (nextSequenceNumber > journal->nextSequenceNumber),
* instead we use the expression ((nextSequenceNumber - journal->nextSequenceNumber) > 0)
* to take wraparounds into account.
*/
((int32_t)(nextSequenceNumber - journal->nextSequenceNumber) > 0)) {
journal->currentBlobIndex = blobIndex;
journal->nextSequenceNumber = nextSequenceNumber;
journal->info.sizeofJournaledBlob = journal->initScan.tail.sizeofBlob;
// printf("discoverLatestLoggedBlob: index %lu, sizeofBlob: %lu, nextSequenceNumber: %lu\n",
// journal->currentBlobIndex, (uint32_t)journal->info.sizeofJournaledBlob, journal->nextSequenceNumber);
}
}
}
// printf("discoverLatestLoggedBlob: finished init scan\n");
/* Handle the case where our scan hasn't yielded any results. */
if (journal->nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) {
// printf("discoverLatestLoggedBlob: initializing to defaults\n");
journal->currentBlobIndex = (uint32_t)-1; /* to be incremented to 0 during the first attempt to log(). */
journal->nextSequenceNumber = 0;
}
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
return JOURNAL_STATUS_OK;
}
/**
* Progress the state machine for the 'format' operation. This method can also be called from an interrupt handler.
* @return < JOURNAL_STATUS_OK for error
* = JOURNAL_STATUS_OK to signal pending asynchronous activity
* > JOURNAL_STATUS_OK for completion
*/
int32_t flashJournalStrategySequential_format_progress(int32_t status, ARM_STORAGE_OPERATION operationWhichJustFinshed)
{
int32_t rc;
size_t sizeofWrite = roundUp_uint32(formatInfoSingleton.header.genericHeader.sizeofHeader, formatInfoSingleton.mtdProgramUnit);
size_t sizeofErase = roundUp_uint32(formatInfoSingleton.header.genericHeader.sizeofHeader, LCM_OF_ALL_ERASE_UNITS);
switch (operationWhichJustFinshed) {
case ARM_STORAGE_OPERATION_INITIALIZE:
if (status != ARM_DRIVER_OK) {
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
// printf("erasing %u bytes from offset %u\n", roundUp_uint32(header.genericHeader.sizeofHeader, mtdInfo.program_unit), mtdAddr);
rc = (formatInfoSingleton.mtd)->Erase(formatInfoSingleton.mtdAddr, sizeofErase);
if (rc < ARM_DRIVER_OK) {
if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
} else {
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
} else if (rc == ARM_DRIVER_OK) {
return JOURNAL_STATUS_OK; /* An asynchronous operation is pending; it will result in a completion callback
* where the rest of processing will take place. */
}
/* handle synchronous completion of programData */
status = rc;
/* intentional fall-through */
case ARM_STORAGE_OPERATION_ERASE:
if (status != (int32_t)sizeofErase) {
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
// printf("calling ProgramData at address %u for %u bytes\n",
// formatInfoSingleton.mtdAddr, roundUp_uint32(formatInfoSingleton.header.genericHeader.sizeofHeader, formatInfoSingleton.mtdProgramUnit));
rc = (formatInfoSingleton.mtd)->ProgramData(formatInfoSingleton.mtdAddr, &(formatInfoSingleton.header), sizeofWrite);
if (rc < ARM_DRIVER_OK) {
if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
} else {
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
} else if (rc == ARM_DRIVER_OK) {
return JOURNAL_STATUS_OK; /* An asynchronous operation is pending; it will result in a completion callback
* where the rest of processing will take place. */
}
/* handle synchronous completion of programData */
status = rc;
/* intentional fall-through */
case ARM_STORAGE_OPERATION_PROGRAM_DATA:
if (status != (int32_t)sizeofWrite) {
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
return 1; /* acknowledge the completion of create */
default:
return JOURNAL_STATUS_STORAGE_API_ERROR; /* we don't expect to be here */
}
}
int32_t flashJournalStrategySequential_reset_progress(void)
{
int32_t rc;
SequentialFlashJournal_t *journal = activeJournal;
if ((rc = journal->mtd->Erase(SLOT_ADDRESS(journal, 0), journal->numSlots * journal->sizeofSlot)) < ARM_DRIVER_OK) {
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
} else {
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
}
if ((journal->mtdCapabilities.asynchronous_ops) && (rc == ARM_DRIVER_OK)) {
//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.mtdOffset, &storageBlock)) != ARM_DRIVER_OK)) {
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
uint64_t storageBlockAvailableCapacity = storageBlock.size - (journal->read.mtdOffset - 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.mtdOffset = 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.mtdOffset);
rc = journal->mtd->ReadData(journal->read.mtdOffset, journal->read.dataBeingRead, xfer);
if (rc < ARM_DRIVER_OK) {
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
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.mtdOffset += rc;
journal->read.amountLeftToRead -= rc;
journal->read.dataBeingRead += rc;
journal->read.logicalOffset += rc;
}
}
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
return (journal->read.dataBeingRead - journal->read.blob);
}
/**
* Progress the state machine for the 'log' operation. This method can also be called from an interrupt handler.
* @return < JOURNAL_STATUS_OK for error
* = JOURNAL_STATUS_OK to signal pending asynchronous activity
* > JOURNAL_STATUS_OK for completion
*/
int32_t flashJournalStrategySequential_log_progress(void)
{
SequentialFlashJournal_t *journal = activeJournal;
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 == journal->numSlots) {
blobIndexBeingLogged = 0;
}
while (true) {
int32_t rc;
if (journal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE) {
uint64_t amountLeftToErase = SLOT_ADDRESS(journal, blobIndexBeingLogged + 1) - journal->log.mtdEraseOffset;
// printf("journal state: erasing; offset %lu [size %lu]\n",
// (uint32_t)journal->log.eraseOffset, (uint32_t)amountLeftToErase);
while (amountLeftToErase) {
if ((rc = journal->mtd->Erase(journal->log.mtdEraseOffset, amountLeftToErase)) < ARM_DRIVER_OK) {
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
} else {
return JOURNAL_STATUS_ERROR;
}
}
if ((journal->mtdCapabilities.asynchronous_ops) && (rc == ARM_DRIVER_OK)) {
return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */
} else {
/* synchronous completion. */
journal->log.mtdEraseOffset += 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.mtdOffset, &storageBlock)) != ARM_DRIVER_OK) {
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
if ((journal->log.mtdOffset - storageBlock.addr) % journal->info.program_unit) {
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
return JOURNAL_STATUS_ERROR; /* Program offset doesn't align with info.program_unit. This would result in an IO error if attempted. */
}
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.mtdOffset);
rc = journal->mtd->ProgramData(journal->log.mtdOffset, journal->log.dataBeingLogged, xfer);
if (rc < ARM_DRIVER_OK) {
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
} else {
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
}
if ((journal->mtdCapabilities.asynchronous_ops) && (rc == ARM_DRIVER_OK)) {
return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */
} else {
/* synchronous completion. 'rc' contains the actual number of bytes transferred. */
journal->log.mtdOffset += 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.mtdOffset = SLOT_ADDRESS(journal, blobIndexBeingLogged);
journal->log.head.version = SEQUENTIAL_FLASH_JOURNAL_VERSION;
journal->log.head.magic = SEQUENTIAL_FLASH_JOURNAL_MAGIC;
journal->log.head.sequenceNumber = journal->nextSequenceNumber;
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: /* we've finished writing the head */
/* compute CRC32 on the header */
flashJournalCrcReset();
flashJournalCrcCummulative((const unsigned char *)&journal->log.head, sizeof(SequentialFlashJournalLogHead_t));
/* switch to writing the body */
/* Prepare for the tail to be written out at a later time.
* This will only be done once Commit() is called. */
journal->log.mtdTailOffset = SLOT_ADDRESS(journal, blobIndexBeingLogged + 1) - sizeof(SequentialFlashJournalLogTail_t);
journal->log.tail.magic = SEQUENTIAL_FLASH_JOURNAL_MAGIC;
journal->log.tail.sequenceNumber = journal->nextSequenceNumber;
journal->log.tail.sizeofBlob = 0; /* we'll update this as we complete our writes. */
journal->log.tail.crc32 = 0;
if (journal->prevCommand == FLASH_JOURNAL_OPCODE_COMMIT) {
/* This branch is taken only when commit() is called without any preceding log() operations. */
journal->log.tail.crc32 = flashJournalCrcCummulative((const unsigned char *)&journal->log.tail, sizeof(SequentialFlashJournalLogTail_t));
flashJournalCrcReset();
journal->state = SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL;
journal->log.dataBeingLogged = (const uint8_t *)&journal->log.tail;
journal->log.amountLeftToLog = sizeof(SequentialFlashJournalLogTail_t);
journal->log.mtdOffset = journal->log.mtdTailOffset;
// printf("newstate: program TAIL at offset %lu\r\n", (uint32_t)journal->log.mtdOffset);
} else {
journal->state = SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY;
journal->log.dataBeingLogged = journal->log.blob;
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 {
uint32_t amountOfDataLogged = (journal->log.dataBeingLogged - journal->log.blob);
flashJournalCrcCummulative(journal->log.blob, amountOfDataLogged); /* compute CRC32 on logged data */
return amountOfDataLogged;
}
case SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL:
// printf("crc32 of slot: 0x%x\n", journal->log.tail.crc32);
journal->info.sizeofJournaledBlob = journal->log.tail.sizeofBlob;
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state to allow further operations */
++journal->currentBlobIndex;
if (journal->currentBlobIndex == journal->numSlots) {
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 formatHandler(int32_t status, ARM_STORAGE_OPERATION operation)
{
if (status < ARM_DRIVER_OK) {
if (formatInfoSingleton.callback) {
formatInfoSingleton.callback(status, FLASH_JOURNAL_OPCODE_FORMAT);
}
return;
}
int32_t rc = flashJournalStrategySequential_format_progress(status, operation);
if (rc != JOURNAL_STATUS_OK) {
if (formatInfoSingleton.callback) {
formatInfoSingleton.callback(rc, FLASH_JOURNAL_OPCODE_FORMAT);
}
}
}
void mtdHandler(int32_t status, ARM_STORAGE_OPERATION operation)
{
int32_t rc;
if (status < ARM_DRIVER_OK) {
/* Map integrity failures reported by the Storage driver appropriately. */
if (status == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
status = JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
} else {
status = JOURNAL_STATUS_STORAGE_IO_ERROR;
}
// printf("journal mtdHandler: received error status %ld\n", status);
switch (activeJournal->state) {
case SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED:
case SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS:
if (activeJournal->callback) {
activeJournal->callback(status, FLASH_JOURNAL_OPCODE_INITIALIZE);
}
break;
case SEQUENTIAL_JOURNAL_STATE_RESETING:
activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
if (activeJournal->callback) {
activeJournal->callback(status, 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(status, 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(status, 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.mtdEraseOffset += 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("journal mtdHandler: PROGRAM_DATA: received status of %ld\n", status);
rc = status;
activeJournal->log.mtdOffset += 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;
}
}

View File

@ -1,78 +0,0 @@
/*
* Copyright (c) 2006-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __FLASH_JOURNAL_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"
/* The following singleton captures the state of the format machine. Format is
* handled differently because it executes even before a journal exists (or a
* Journal_t can be initialized. */
extern struct FormatInfo_t {
ARM_DRIVER_STORAGE *mtd;
SequentialFlashJournalHeader_t header;
FlashJournal_Callback_t callback;
uint64_t mtdAddr;
uint32_t mtdProgramUnit;
} formatInfoSingleton;
extern SequentialFlashJournal_t *activeJournal;
/**
* Check the sanity of a given slot
* @param journal
* @param slotOffset
* @param [out] headSequenceNumberP
* sequence number of the slot as read from the header.
* @param [out] tailP
* the tail of the slot
* @return 1 if the slot is valid; i.e. if head and tail match, and if CRC32 agrees.
*/
int32_t slotIsSane(SequentialFlashJournal_t *journal,
uint64_t slotOffset,
uint32_t *headSequenceNumberP,
SequentialFlashJournalLogTail_t *tailP);
int32_t mtdGetStartAddr(ARM_DRIVER_STORAGE *mtd, uint64_t *startAddrP);
int32_t setupSequentialJournalHeader(SequentialFlashJournalHeader_t *headerP, ARM_DRIVER_STORAGE *mtd, uint64_t totalSize, uint32_t numSlots);
int32_t discoverLatestLoggedBlob(SequentialFlashJournal_t *journal);
/**
* Progress the state machine for the 'format' operation. This method can also be called from an interrupt handler.
* @return < JOURNAL_STATUS_OK for error
* = JOURNAL_STATUS_OK to signal pending asynchronous activity
* > JOURNAL_STATUS_OK for completion
*/
int32_t flashJournalStrategySequential_format_progress(int32_t status, ARM_STORAGE_OPERATION operationWhichJustFinshed);
/**
* Progress the state machine for the 'log' operation. This method can also be called from an interrupt handler.
* @return < JOURNAL_STATUS_OK for error
* = JOURNAL_STATUS_OK to signal pending asynchronous activity
* > JOURNAL_STATUS_OK for completion
*/
int32_t flashJournalStrategySequential_log_progress(void);
int32_t flashJournalStrategySequential_reset_progress(void);
int32_t flashJournalStrategySequential_read_progress(void);
void mtdHandler(int32_t status, ARM_STORAGE_OPERATION operation);
void formatHandler(int32_t status, ARM_STORAGE_OPERATION operation);
#endif /*__FLASH_JOURNAL_SEQUENTIAL_STRATEGY_SUPPORT_FUNCTIONS_H__*/

View File

@ -1,755 +0,0 @@
/*
* Copyright (c) 2006-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __FLASH_JOURNAL_H__
#define __FLASH_JOURNAL_H__
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include "storage_abstraction/Driver_Storage.h"
#include "mbed_toolchain.h" /* required for MBED_DEPRECATED_SINCE */
/**
* 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.
JOURNAL_STATUS_NOT_FORMATTED = -12, ///< need to call xxx_format() before using the journal.
JOURNAL_STATUS_METADATA_ERROR = -13, ///< sanity checks for the journal metadata failed.
JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE = -14, ///< validation or run-time errors arising from the badkend media.
} FlashJournal_Status_t;
/**
* 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_FORMAT,
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;
static const uint32_t FLASH_JOURNAL_HEADER_MAGIC = 0xA00AEE1DUL;
static const uint32_t FLASH_JOURNAL_HEADER_VERSION = 1;
/**
* Meta-data placed at the head of a Journal. The actual header would be an
* extension of this generic header, and would depend on the implementation
* strategy. Initialization algorithms can expect to find this generic header at
* the start of every Journal.
*/
typedef struct _FlashJournalHeader {
uint32_t magic; /** Journal-header specific magic code */
uint32_t version; /** Revision number for this generic journal header. */
uint64_t totalSize; /** Total space (in bytes) occupied by the journal, including the header.
* Both 'mtdOffset' and 'mtdOffset + totalSize' should
* lie on erase boundaries. */
uint32_t sizeofHeader; /** The size of the journal header; this is expected to be larger than this generic header. */
uint32_t journalOffset; /** Offset from the start of the journal header to the actual logged journal. */
uint32_t checksum; /** CRC32 over the entire flash-journal-header, including the implementation
* specific extension (i.e. over 'sizeofHeader' bytes). The value of the
* field is taken to be 0 for the purpose of computing the checksum. */
} FlashJournalHeader_t;
/**
* This is the type of the command completion callback handler for the
* asynchronous flash-journal APIs: initialize(), read(), log(), commit() and
* 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. */
struct FlashJournal_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 160
/**
* This is the set of operations offered by the flash-journal abstraction. A set
* of implementations for these operations defines a logging strategy.
*/
typedef struct FlashJournal_Ops_t {
/**
* \brief Initialize the flash journal. Refer to @ref FlashJournal_initialize.
*/
int32_t (*initialize)(struct FlashJournal_t *journal,
ARM_DRIVER_STORAGE *mtd,
const struct FlashJournal_Ops_t *ops,
FlashJournal_Callback_t callback);
/**
* \brief fetch journal metadata. Refer to @ref FlashJournal_getInfo.
*/
FlashJournal_Status_t (*getInfo) (struct FlashJournal_t *journal, FlashJournal_Info_t *info);
/**
* @brief Read from the most recently logged blob. Refer to @ref FlashJournal_read.
*/
int32_t (*read) (struct FlashJournal_t *journal, void *buffer, size_t size);
/**
* @brief Read from the most recently logged blob from a particular offset. Refer to @ref FlashJournal_readFrom.
*/
int32_t (*readFrom) (struct FlashJournal_t *journal, size_t offset, void *buffer, size_t size);
/**
* @brief Start logging a new blob or append to the one currently being logged. Refer to @ref FlashJournal_log.
*/
int32_t (*log) (struct FlashJournal_t *journal, const void *blob, size_t size);
/**
* @brief commit a blob accumulated through a non-empty sequence of
* previously successful log() operations. Refer to @ref FlashJournal_commit.
*/
int32_t (*commit) (struct FlashJournal_t *journal);
/**
* @brief Reset the journal. This has the effect of erasing all valid blobs.
* Refer to @ref FlashJournal_reset.
*/
int32_t (*reset) (struct 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
* 1 passed in as the 'status' parameter of the
* callback. In case of errors, the completion callback is invoked with
* an error status.
* - When the operation is executed by the journal in a blocking (i.e.
* synchronous) manner, control returns to the caller only upon the actual
* completion of the operation or the discovery of a failure condition. In
* this case, the function returns 1 to signal successful synchronous
* completion or an appropriate error code, and no further
* invocation of the completion callback should be expected at a later time.
*
* @note The user must call an appropriate xxx_format() to format underlying
* storage before initializing it for use. If Initialize() is called on
* unformatted storage, an error value of JOURNAL_STATUS_NOT_FORMATTED will be
* returned.
*
* Here's a code snippet to suggest how this API might be used by callers:
* \code
* ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code
* 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
*/
MBED_DEPRECATED_SINCE("mbed-os-5.5", "FlashJournal is deprecated. "
"Use a BlockDevice or filesystem instead")
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
*/
MBED_DEPRECATED_SINCE("mbed-os-5.5", "FlashJournal is deprecated. "
"Use a BlockDevice or filesystem instead")
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
*/
MBED_DEPRECATED_SINCE("mbed-os-5.5", "FlashJournal is deprecated. "
"Use a BlockDevice or filesystem instead")
static inline int32_t FlashJournal_read(FlashJournal_t *journal, void *blob, size_t n)
{
return journal->ops.read(journal, blob, n);
}
/**
* @brief Read from the most recently logged blob at a given offset. A front-end
* for @ref FlashJournal_Ops_t::readFrom().
*
* @details Read off a chunk of the logged blob from a given offset. The journal
* maintains a read-pointer internally to allow reads to continue where the
* previous one left off. This call effectively sets the read-counter before
* fetching data. Subsequent reads continue sequentially from where the
* readFrom() left off.
*
* @note: If the given offset stands at (or is beyond) the end of the previously
* logged blob, readFrom() returns the error JOURNAL_STATUS_EMPTY (or passes
* that value as the status of a completion callback) and resets the read-
* pointer to allow re-reading the blob from the start.
*
* @param [in] journal
* A previously initialized journal.
*
* @param [in] offset
* The logical offset (within the blob) at which to read data from.
*
* @param [out] buffer
* The destination of the read operation. The memory is owned
* by the caller and should remain valid for the lifetime
* of this operation.
*
* @param [in] size
* The maximum amount of data which can be read in this
* operation. The memory pointed to by 'buffer' should be as
* large as this amount.
*
* @return
* The function executes in the following ways:
* - When the operation is asynchronous--i.e. when the underlying MTD's
* ARM_STOR_CAPABILITIES::asynchronous_ops is set to 1--and the operation
* executed by the journal in a non-blocking (i.e. asynchronous) manner,
* control returns to the caller with JOURNAL_STATUS_OK before the actual
* completion of the operation (or with an appropriate error code in case of
* failure). When the operation completes, the command callback is
* invoked with the number of successfully transferred bytes passed in as
* the 'status' parameter of the callback. If any error is encountered
* after the launch of an asynchronous operation, the completion callback
* is invoked with an error status.
* - When the operation is executed by the journal in a blocking (i.e.
* synchronous) manner, control returns to the caller only upon the
* actual completion of the operation, or the discovery of a failure
* condition. In synchronous mode, the function returns the number
* of data items read or an appropriate error code.
*
* @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops
* is set then this operation may execute asynchronously. In the case of
* asynchronous operation, the invocation returns early (with
* JOURNAL_STATUS_OK) and results in a completion callback later.
*
* @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops
* is set, the journal is not required to operate asynchronously. A Read
* operation can be finished synchronously in spite of
* ARM_STORAGE_CAPABILITIES::asynchronous_ops being set, returning the
* number of data items read to indicate successful completion, or an
* appropriate error code. In this case no further invocation of a
* completion callback should be expected at a later time.
*
* Here's a code snippet to suggest how this API might be used by callers:
* \code
* ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code
* int32_t returnValue = FlashJournal_readFrom(&journal, offset, buffer, size);
* if (returnValue < JOURNAL_STATUS_OK) {
* // handle error
* } else if (returnValue == JOURNAL_STATUS_OK) {
* ASSERT(MTD->GetCapabilities().asynchronous_ops == 1);
* // handle early return from asynchronous execution
* } else {
* ASSERT(returnValue == size);
* // handle synchronous completion
* }
* \endcode
*/
MBED_DEPRECATED_SINCE("mbed-os-5.5", "FlashJournal is deprecated. "
"Use a BlockDevice or filesystem instead")
static inline int32_t FlashJournal_readFrom(struct FlashJournal_t *journal, size_t offset, void *blob, size_t n)
{
return journal->ops.readFrom(journal, offset, blob, n);
}
/**
* @brief Start logging a new blob or append to the one currently being logged.
* A front-end for @ref FlashJournal_Ops_t::log().
*
* @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
*/
MBED_DEPRECATED_SINCE("mbed-os-5.5", "FlashJournal is deprecated. "
"Use a BlockDevice or filesystem instead")
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.
*/
MBED_DEPRECATED_SINCE("mbed-os-5.5", "FlashJournal is deprecated. "
"Use a BlockDevice or filesystem instead")
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
*/
MBED_DEPRECATED_SINCE("mbed-os-5.5", "FlashJournal is deprecated. "
"Use a BlockDevice or filesystem instead")
static inline int32_t FlashJournal_reset(FlashJournal_t *journal)
{
return journal->ops.reset(journal);
}
#ifdef __cplusplus
}
#endif // __cplusplus
#endif /* __FLASH_JOURNAL_H__ */

View File

@ -1,259 +0,0 @@
/*
* Copyright (c) 2006-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// This file is deprecated so deprecation warnings when building it are silenced
#if defined ( __CC_ARM )
#pragma diag_suppress 1361 // Deprecated declaration
#elif defined ( __GNUC__ )
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#include "storage-volume-manager/storage_volume_manager.h"
#include <string.h>
#include <inttypes.h>
/* redefine tr_debug() to a printf() equivalent to emit trace */
#define tr_debug(...)
void StorageVolume::setup(uint64_t _addr, uint64_t _size, StorageVolumeManager *_volumeManager)
{
volumeOffset = _addr;
volumeSize = _size;
volumeManager = _volumeManager;
allocated = true;
}
ARM_DRIVER_VERSION StorageVolume::GetVersion(void)
{
ARM_DRIVER_VERSION bad_ver = {0, 0};
if (!allocated) {
return bad_ver;
}
return volumeManager->getStorage()->GetVersion();
}
ARM_STORAGE_CAPABILITIES StorageVolume::GetCapabilities(void)
{
ARM_STORAGE_CAPABILITIES bad_cap;
if (!allocated) {
memset(&bad_cap, 0, sizeof(ARM_STORAGE_CAPABILITIES));
return bad_cap;
}
return volumeManager->getStorage()->GetCapabilities();
}
int32_t StorageVolume::Initialize(ARM_Storage_Callback_t _callback)
{
if (!allocated) {
return STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED;
}
callback = _callback; /* nothing else to do since we've already initialized the storage */
return 1; /* synchronous completion. */
}
int32_t StorageVolume::Uninitialize(void)
{
if (!allocated) {
return STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED;
}
return 1; /* synchronous completion. */
}
int32_t StorageVolume::PowerControl(ARM_POWER_STATE state)
{
tr_debug("called powerControl(%u)", state);
if (!allocated) {
return STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED;
}
if (volumeManager->activeVolume != NULL) {
return ARM_DRIVER_ERROR_BUSY;
}
volumeManager->activeVolume = this;
int32_t rc = volumeManager->getStorage()->PowerControl(state);
if (rc != ARM_DRIVER_OK) {
volumeManager->activeVolume = NULL; /* we're certain that there is no more pending asynch. activity */
}
return rc;
}
int32_t StorageVolume::ReadData(uint64_t addr, void *data, uint32_t size)
{
tr_debug("called ReadData(%" PRIu32 ", %" PRIu32 ")", (uint32_t)addr, size);
if (!allocated) {
return STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED;
}
if (volumeManager->activeVolume != NULL) {
return ARM_DRIVER_ERROR_BUSY;
}
if ((size > volumeSize) || ((addr + size) > volumeSize)) {
return ARM_DRIVER_ERROR_PARAMETER;
}
volumeManager->activeVolume = this;
int32_t rc = volumeManager->getStorage()->ReadData(volumeOffset + addr, data, size);
if (rc != ARM_DRIVER_OK) {
volumeManager->activeVolume = NULL; /* we're certain that there is no more pending asynch. activity */
}
return rc;
}
int32_t StorageVolume::ProgramData(uint64_t addr, const void *data, uint32_t size)
{
tr_debug("called ProgramData(%" PRIu32 ", %" PRIu32 ")", (uint32_t)addr, size);
if (!allocated) {
return STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED;
}
if (volumeManager->activeVolume != NULL) {
return ARM_DRIVER_ERROR_BUSY;
}
if ((size > volumeSize) || ((addr + size) > volumeSize)) {
return ARM_DRIVER_ERROR_PARAMETER;
}
volumeManager->activeVolume = this;
int32_t rc = volumeManager->getStorage()->ProgramData(volumeOffset + addr, data, size);
if (rc != ARM_DRIVER_OK) {
volumeManager->activeVolume = NULL; /* we're certain that there is no more pending asynch. activity */
}
return rc;
}
int32_t StorageVolume::Erase(uint64_t addr, uint32_t size)
{
tr_debug("called erase(%" PRIu32 ", %" PRIu32 ")", (uint32_t)addr, size);
if (!allocated) {
return STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED;
}
if (volumeManager->activeVolume != NULL) {
return ARM_DRIVER_ERROR_BUSY;
}
if ((size > volumeSize) || ((addr + size) > volumeSize)) {
return ARM_DRIVER_ERROR_PARAMETER;
}
volumeManager->activeVolume = this;
int32_t rc = volumeManager->getStorage()->Erase(volumeOffset + addr, size);
if (rc != ARM_DRIVER_OK) {
volumeManager->activeVolume = NULL; /* we're certain that there is no more pending asynch. activity */
}
return rc;
}
int32_t StorageVolume::EraseAll(void)
{
tr_debug("called eraseAll");
if (!allocated) {
return STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED;
}
if (volumeManager->activeVolume != NULL) {
return ARM_DRIVER_ERROR_BUSY;
}
int32_t rc;
/* Allow EraseAll() only if the volume spans the entire storage. */
{
ARM_STORAGE_INFO info;
rc = volumeManager->getStorage()->GetInfo(&info);
if (rc != ARM_DRIVER_OK) {
return ARM_DRIVER_ERROR;
}
if ((volumeOffset != 0) || (volumeSize != info.total_storage)) {
return ARM_DRIVER_ERROR_UNSUPPORTED;
}
}
volumeManager->activeVolume = this;
rc = volumeManager->getStorage()->EraseAll();
if (rc != ARM_DRIVER_OK) {
volumeManager->activeVolume = NULL; /* we're certain that there is no more pending asynch. activity */
}
return rc;
}
ARM_STORAGE_STATUS StorageVolume::GetStatus(void)
{
const uint32_t busy = ((volumeManager->activeVolume != NULL) ? (uint32_t)1 : (uint32_t)0);
ARM_STORAGE_STATUS status = {0, 0};
status.busy = busy;
return status;
}
int32_t StorageVolume::GetInfo(ARM_STORAGE_INFO *infoP)
{
int32_t rc;
rc = volumeManager->getStorage()->GetInfo(infoP);
if (rc != ARM_DRIVER_OK) {
return ARM_DRIVER_ERROR;
}
infoP->total_storage = volumeSize;
return ARM_DRIVER_OK;
}
uint32_t StorageVolume::ResolveAddress(uint64_t addr) {
return (uint32_t)(volumeOffset + addr);
}
int32_t StorageVolume::GetNextBlock(const ARM_STORAGE_BLOCK* prevP, ARM_STORAGE_BLOCK *nextP)
{
int32_t rc;
ARM_STORAGE_BLOCK tmpBlock;
do {
/* iterate forward */
rc = volumeManager->getStorage()->GetNextBlock(prevP, &tmpBlock);
if (rc != ARM_DRIVER_OK) {
return rc;
}
/* Stop iteration if we have progressed past the boundary of this volume. */
if (tmpBlock.addr >= (volumeOffset + volumeSize)) {
return ARM_DRIVER_ERROR;
}
} while (!this->overlapsWithBlock(&tmpBlock));
if (nextP) {
memcpy(nextP, &tmpBlock, sizeof(ARM_STORAGE_BLOCK));
transformBlockToVolume(nextP);
}
return ARM_DRIVER_OK;
}
int32_t StorageVolume::GetBlock(uint64_t addr, ARM_STORAGE_BLOCK *blockP)
{
ARM_STORAGE_BLOCK tmpBlock;
int32_t rc = volumeManager->getStorage()->GetBlock(ResolveAddress(addr), &tmpBlock);
if (rc != ARM_DRIVER_OK) {
return rc;
}
if (!this->overlapsWithBlock(&tmpBlock)) {
return ARM_DRIVER_ERROR;
}
if (blockP) {
memcpy(blockP, &tmpBlock, sizeof(ARM_STORAGE_BLOCK));
transformBlockToVolume(blockP);
}
return ARM_DRIVER_OK;
}

Some files were not shown because too many files have changed in this diff Show More