Merge pull request #10258 from davidsaada/david_remove_feature_storage
Remove FEATURE_STORAGE and all underlying deprecated featurespull/10503/head
|
@ -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/
|
||||
|
|
|
@ -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/* \
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 */
|
|
@ -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)
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
*
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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.
|
|
@ -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.
|
||||
*/
|
|
@ -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.
|
||||
*/
|
|
@ -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 */
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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.
|
|
@ -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
|
||||
|
||||

|
||||
|
||||
|
||||
The above UML diagram shows the low level design of the CFSTORE API.
|
|
@ -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>
|
||||
```
|
||||
|
||||
|
||||
|
|
@ -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
|
|
@ -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.
|
||||
|
|
@ -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.
|
Before Width: | Height: | Size: 100 KiB |
Before Width: | Height: | Size: 79 KiB |
Before Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 89 KiB |
Before Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 83 KiB |
Before Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 289 KiB |
|
@ -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=<-</panel_attributes>
|
||||
<additional_attributes>10.0;120.0;660.0;10.0</additional_attributes>
|
||||
</element>
|
||||
<element>
|
||||
<id>Relation</id>
|
||||
<coordinates>
|
||||
<x>1056</x>
|
||||
<y>1072</y>
|
||||
<w>368</w>
|
||||
<h>112</h>
|
||||
</coordinates>
|
||||
<panel_attributes>lt=<-</panel_attributes>
|
||||
<additional_attributes>440.0;120.0;10.0;10.0</additional_attributes>
|
||||
</element>
|
||||
<element>
|
||||
<id>UMLClass</id>
|
||||
<coordinates>
|
||||
<x>968</x>
|
||||
<y>1168</y>
|
||||
<w>344</w>
|
||||
<h>256</h>
|
||||
</coordinates>
|
||||
<panel_attributes>ARM_STOR_SECURITY_FEATURES
|
||||
--
|
||||
uint8_t acls : 1; ///< protection against internal software attacks using ACLs.
|
||||
uint8_t rollback_protection : 1; ///< roll-back protection.
|
||||
uint8_t tamper_proof : 1; ///< tamper-proof memory (will be deleted on tamper-attempts using board level or chip level sensors).
|
||||
uint8_t internal_flash : 1; ///< Internal flash.
|
||||
uint8_t reserved : 4;
|
||||
|
||||
/**
|
||||
* Encode support for hardening against various classes of attacks.
|
||||
*/
|
||||
struct ARM_STOR_HARDENING
|
||||
{
|
||||
uint8_t device_software : 1; ///< device software (malware running on the device).
|
||||
uint8_t board_level_attacks : 1; ///< board level attacks (debug probes, copy protection fuses.)
|
||||
uint8_t chip_level_attacks : 1; ///< chip level attacks (tamper-protection).
|
||||
uint8_t side_channel_attacks : 1; ///< side channel attacks.
|
||||
uint8_t reserved : 4;
|
||||
} hardening_against; ///< hardening.
|
||||
</panel_attributes>
|
||||
<additional_attributes/>
|
||||
</element>
|
||||
<element>
|
||||
<id>Relation</id>
|
||||
<coordinates>
|
||||
<x>816</x>
|
||||
<y>1072</y>
|
||||
<w>264</w>
|
||||
<h>112</h>
|
||||
</coordinates>
|
||||
<panel_attributes>lt=<-</panel_attributes>
|
||||
<additional_attributes>10.0;120.0;310.0;10.0</additional_attributes>
|
||||
</element>
|
||||
<element>
|
||||
<id>Relation</id>
|
||||
<coordinates>
|
||||
<x>1056</x>
|
||||
<y>1072</y>
|
||||
<w>24</w>
|
||||
<h>112</h>
|
||||
</coordinates>
|
||||
<panel_attributes>lt=<-</panel_attributes>
|
||||
<additional_attributes>10.0;120.0;10.0;10.0</additional_attributes>
|
||||
</element>
|
||||
<element>
|
||||
<id>UMLActor</id>
|
||||
<coordinates>
|
||||
<x>1304</x>
|
||||
<y>0</y>
|
||||
<w>104</w>
|
||||
<h>96</h>
|
||||
</coordinates>
|
||||
<panel_attributes>Box 1
|
||||
Security Context</panel_attributes>
|
||||
<additional_attributes/>
|
||||
</element>
|
||||
<element>
|
||||
<id>UMLActor</id>
|
||||
<coordinates>
|
||||
<x>1408</x>
|
||||
<y>0</y>
|
||||
<w>104</w>
|
||||
<h>96</h>
|
||||
</coordinates>
|
||||
<panel_attributes>Box i
|
||||
Security Context</panel_attributes>
|
||||
<additional_attributes/>
|
||||
</element>
|
||||
<element>
|
||||
<id>UMLActor</id>
|
||||
<coordinates>
|
||||
<x>1504</x>
|
||||
<y>0</y>
|
||||
<w>104</w>
|
||||
<h>96</h>
|
||||
</coordinates>
|
||||
<panel_attributes>Box n
|
||||
Security Context</panel_attributes>
|
||||
<additional_attributes/>
|
||||
</element>
|
||||
<element>
|
||||
<id>UMLUseCase</id>
|
||||
<coordinates>
|
||||
<x>1376</x>
|
||||
<y>160</y>
|
||||
<w>184</w>
|
||||
<h>96</h>
|
||||
</coordinates>
|
||||
<panel_attributes>Config Store
|
||||
{key,value} storage operations
|
||||
</panel_attributes>
|
||||
<additional_attributes/>
|
||||
</element>
|
||||
<element>
|
||||
<id>Relation</id>
|
||||
<coordinates>
|
||||
<x>1360</x>
|
||||
<y>48</y>
|
||||
<w>128</w>
|
||||
<h>128</h>
|
||||
</coordinates>
|
||||
<panel_attributes><<uses>></panel_attributes>
|
||||
<additional_attributes>10.0;10.0;140.0;140.0</additional_attributes>
|
||||
</element>
|
||||
<element>
|
||||
<id>Relation</id>
|
||||
<coordinates>
|
||||
<x>1464</x>
|
||||
<y>48</y>
|
||||
<w>56</w>
|
||||
<h>128</h>
|
||||
</coordinates>
|
||||
<panel_attributes><<uses>></panel_attributes>
|
||||
<additional_attributes>10.0;10.0;10.0;140.0</additional_attributes>
|
||||
</element>
|
||||
<element>
|
||||
<id>Relation</id>
|
||||
<coordinates>
|
||||
<x>1464</x>
|
||||
<y>48</y>
|
||||
<w>120</w>
|
||||
<h>128</h>
|
||||
</coordinates>
|
||||
<panel_attributes><<uses>></panel_attributes>
|
||||
<additional_attributes>130.0;10.0;10.0;140.0</additional_attributes>
|
||||
</element>
|
||||
<element>
|
||||
<id>UMLNote</id>
|
||||
<coordinates>
|
||||
<x>224</x>
|
||||
<y>656</y>
|
||||
<w>304</w>
|
||||
<h>64</h>
|
||||
</coordinates>
|
||||
<panel_attributes>Note..
|
||||
mbed_config_store_hld
|
||||
v0.04
|
||||
20160225
|
||||
|
||||
</panel_attributes>
|
||||
<additional_attributes/>
|
||||
</element>
|
||||
<element>
|
||||
<id>UMLClass</id>
|
||||
<coordinates>
|
||||
<x>824</x>
|
||||
<y>968</y>
|
||||
<w>264</w>
|
||||
<h>112</h>
|
||||
</coordinates>
|
||||
<panel_attributes>ARM_CFSTORE_KEYDESC
|
||||
--
|
||||
/*key descriptor attributes */
|
||||
ARM_CFSTORE_ACCESS_CONTROL_LIST acl;
|
||||
ARM_STOR_DATA_RETENTION_LEVEL drl;
|
||||
ARM_STOR_SECURITY_FEATURES security;
|
||||
ARM_CFSTORE_FMODE flags;
|
||||
|
||||
|
||||
</panel_attributes>
|
||||
<additional_attributes/>
|
||||
</element>
|
||||
<element>
|
||||
<id>UMLClass</id>
|
||||
<coordinates>
|
||||
<x>904</x>
|
||||
<y>720</y>
|
||||
<w>240</w>
|
||||
<h>232</h>
|
||||
</coordinates>
|
||||
<panel_attributes>ARM_CFSTORE_OPCODE;
|
||||
--
|
||||
CFSTORE_OPCODE_CLOSE
|
||||
CFSTORE_OPCODE_CREATE
|
||||
CFSTORE_OPCODE_DELETE
|
||||
CFSTORE_OPCODE_FIND
|
||||
CFSTORE_OPCODE_FLUSH
|
||||
CFSTORE_OPCODE_GET_KEY_NAME
|
||||
CFSTORE_OPCODE_GET_STATUS
|
||||
CFSTORE_OPCODE_GET_VALUE_LEN
|
||||
CFSTORE_OPCODE_INITIALIZE
|
||||
CFSTORE_OPCODE_OPEN
|
||||
CFSTORE_OPCODE_POWER_CONTROL
|
||||
CFSTORE_OPCODE_READ
|
||||
CFSTORE_OPCODE_RSEEK
|
||||
CFSTORE_OPCODE_UNINITIALIZE
|
||||
CFSTORE_OPCODE_WRITE
|
||||
CFSTORE_OPCODE_MAX
|
||||
</panel_attributes>
|
||||
<additional_attributes/>
|
||||
</element>
|
||||
<element>
|
||||
<id>UMLClass</id>
|
||||
<coordinates>
|
||||
<x>576</x>
|
||||
<y>608</y>
|
||||
<w>808</w>
|
||||
<h>64</h>
|
||||
</coordinates>
|
||||
<panel_attributes>ARM_CFSTORE_CALLBACK
|
||||
--
|
||||
typedef void (*ARM_CFSTORE_CALLBACK)(int32_t status, ARM_CFSTORE_OPCODE cmd_code, void *client_context, ARM_CFSTORE_HANDLE handle);
|
||||
</panel_attributes>
|
||||
<additional_attributes/>
|
||||
</element>
|
||||
<element>
|
||||
<id>Relation</id>
|
||||
<coordinates>
|
||||
<x>392</x>
|
||||
<y>880</y>
|
||||
<w>576</w>
|
||||
<h>104</h>
|
||||
</coordinates>
|
||||
<panel_attributes>lt=<-</panel_attributes>
|
||||
<additional_attributes>700.0;110.0;10.0;10.0</additional_attributes>
|
||||
</element>
|
||||
<element>
|
||||
<id>Relation</id>
|
||||
<coordinates>
|
||||
<x>392</x>
|
||||
<y>664</y>
|
||||
<w>536</w>
|
||||
<h>240</h>
|
||||
</coordinates>
|
||||
<panel_attributes>lt=<-</panel_attributes>
|
||||
<additional_attributes>650.0;10.0;10.0;280.0</additional_attributes>
|
||||
</element>
|
||||
<element>
|
||||
<id>Relation</id>
|
||||
<coordinates>
|
||||
<x>392</x>
|
||||
<y>816</y>
|
||||
<w>528</w>
|
||||
<h>88</h>
|
||||
</coordinates>
|
||||
<panel_attributes>lt=<-</panel_attributes>
|
||||
<additional_attributes>640.0;10.0;10.0;90.0</additional_attributes>
|
||||
</element>
|
||||
</diagram>
|
|
@ -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
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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*/
|
|
@ -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*/
|
|
@ -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 */
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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 */
|
||||
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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.
|
||||
*
|
||||
*/
|
|
@ -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() */
|
||||
|
|
@ -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 */
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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__*/
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|