Knight KE / Mbed OS Game_Master
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ns_nvm_helper.c Source File

ns_nvm_helper.c

00001 // ----------------------------------------------------------------------------
00002 // Copyright 2016-2017 ARM Ltd.
00003 //
00004 // SPDX-License-Identifier: Apache-2.0
00005 //
00006 // Licensed under the Apache License, Version 2.0 (the "License");
00007 // you may not use this file except in compliance with the License.
00008 // You may obtain a copy of the License at
00009 //
00010 //     http://www.apache.org/licenses/LICENSE-2.0
00011 //
00012 // Unless required by applicable law or agreed to in writing, software
00013 // distributed under the License is distributed on an "AS IS" BASIS,
00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 // See the License for the specific language governing permissions and
00016 // limitations under the License.
00017 // ----------------------------------------------------------------------------
00018 
00019 #include <string.h>
00020 #include <ns_types.h>
00021 #include <nsdynmemLIB.h>
00022 #include "ns_list.h"
00023 #include "platform/arm_hal_nvm.h"
00024 #include "ns_nvm_helper.h"
00025 
00026 #define TRACE_GROUP "nnvm"
00027 
00028 /* NVM operations */
00029 #define NS_NVM_NONE         0x00
00030 #define NS_NVM_INIT         0x01
00031 #define NS_NVM_KEY_CREATE   0x02
00032 #define NS_NVM_KEY_READ     0x03
00033 #define NS_NVM_KEY_WRITE    0x04
00034 #define NS_NVM_FLUSH        0x05
00035 #define NS_NVM_KEY_DELETE   0x06
00036 
00037 typedef struct {
00038     ns_nvm_callback *callback;
00039     const char *client_key_name;
00040     void *client_context;
00041     int operation;
00042     uint8_t *buffer;
00043     uint16_t *buffer_len;
00044     void *original_request;
00045     ns_list_link_t link;
00046 } ns_nvm_request_t;
00047 
00048 static bool ns_nvm_initialized = false;
00049 static bool ns_nvm_operation_in_progress = false;
00050 
00051 static ns_nvm_request_t *ns_nvm_create_request(ns_nvm_callback *callback, void *context, const char *key_name, uint8_t *buf, uint16_t *buf_len, uint8_t operation);
00052 static int ns_nvm_operation_start(ns_nvm_request_t *request);
00053 static int ns_nvm_operation_continue(ns_nvm_request_t *request, bool free_request);
00054 static void ns_nvm_operation_end(ns_nvm_request_t *ns_nvm_request_ptr, int client_retval);
00055 
00056 static NS_LIST_DEFINE(ns_nvm_request_list, ns_nvm_request_t, link);
00057 
00058 /*
00059  * Callback from platform NVM adaptation
00060  */
00061 void ns_nvm_callback_func(platform_nvm_status status, void *args)
00062 {
00063     ns_nvm_request_t *ns_nvm_request_ptr = (ns_nvm_request_t*)args;
00064     int client_retval = NS_NVM_OK;
00065 
00066     if (status == PLATFORM_NVM_ERROR) {
00067         client_retval = NS_NVM_ERROR;
00068     } else if (status == PLATFORM_NVM_KEY_NOT_FOUND) {
00069         client_retval = NS_NVM_DATA_NOT_FOUND;
00070     }
00071 
00072     switch(ns_nvm_request_ptr->operation) {
00073         case NS_NVM_INIT:
00074             ns_nvm_operation_continue(ns_nvm_request_ptr->original_request, true);
00075             ns_dyn_mem_free(ns_nvm_request_ptr);
00076             break;
00077         case NS_NVM_FLUSH:
00078         case NS_NVM_KEY_READ:
00079             ns_nvm_operation_end(ns_nvm_request_ptr, client_retval);
00080             break;
00081         case NS_NVM_KEY_CREATE:
00082             if (status == PLATFORM_NVM_OK) {
00083                 ns_nvm_request_ptr->operation = NS_NVM_KEY_WRITE;
00084                 platform_nvm_write(ns_nvm_callback_func, ns_nvm_request_ptr->client_key_name, ns_nvm_request_ptr->buffer, ns_nvm_request_ptr->buffer_len, ns_nvm_request_ptr);
00085             } else {
00086                 ns_nvm_operation_end(ns_nvm_request_ptr, client_retval);
00087             }
00088             break;
00089         case NS_NVM_KEY_DELETE:
00090         case NS_NVM_KEY_WRITE:
00091             if (status == PLATFORM_NVM_OK) {
00092                 // write ok, flush the changes
00093                 ns_nvm_request_ptr->operation = NS_NVM_FLUSH;
00094                 platform_nvm_flush(ns_nvm_callback_func, ns_nvm_request_ptr);
00095             } else {
00096                 // write failed, inform client
00097                 ns_nvm_operation_end(ns_nvm_request_ptr, client_retval);
00098             }
00099             break;
00100     }
00101 }
00102 
00103 int ns_nvm_key_delete(ns_nvm_callback *callback, const char *key_name, void *context)
00104 {
00105     if (!callback || !key_name) {
00106         return NS_NVM_ERROR;
00107     }
00108     ns_nvm_request_t *ns_nvm_request_ptr = ns_nvm_create_request(callback, context, key_name, NULL, NULL, NS_NVM_KEY_DELETE);
00109     return ns_nvm_operation_start(ns_nvm_request_ptr);
00110 }
00111 
00112 int ns_nvm_data_read(ns_nvm_callback *callback, const char *key_name, uint8_t *buf, uint16_t *buf_len, void *context)
00113 {
00114     if (!callback || !key_name || !buf || !buf_len) {
00115         return NS_NVM_ERROR;
00116     }
00117     ns_nvm_request_t *ns_nvm_request_ptr = ns_nvm_create_request(callback, context, key_name, buf, buf_len, NS_NVM_KEY_READ);
00118     return ns_nvm_operation_start(ns_nvm_request_ptr);
00119 }
00120 
00121 int ns_nvm_data_write(ns_nvm_callback *callback, const char *key_name, uint8_t *buf, uint16_t *buf_len, void *context)
00122 {
00123     if (!callback || !key_name || !buf || !buf_len) {
00124         return NS_NVM_ERROR;
00125     }
00126     ns_nvm_request_t *ns_nvm_request_ptr = ns_nvm_create_request(callback, context, key_name, buf, buf_len, NS_NVM_KEY_WRITE);
00127     return ns_nvm_operation_start(ns_nvm_request_ptr);
00128 }
00129 
00130 static int ns_nvm_operation_start(ns_nvm_request_t *nvm_request)
00131 {
00132     int ret = NS_NVM_OK;
00133     platform_nvm_status pnvm_status;
00134 
00135     if (!nvm_request) {
00136         return NS_NVM_MEMORY;
00137     }
00138     if (ns_nvm_initialized == true) {
00139         // NVM already initialized, continue directly
00140         if (!ns_nvm_operation_in_progress) {
00141             ret = ns_nvm_operation_continue(nvm_request, true);
00142         } else {
00143             // add request to list and handle when existing calls has been handled.
00144             ns_list_add_to_end(&ns_nvm_request_list, nvm_request);
00145         }
00146     } else {
00147         ns_nvm_request_t *ns_nvm_request_ptr = ns_nvm_create_request(NULL, NULL, NULL, NULL, NULL, NS_NVM_INIT);
00148         if (!ns_nvm_request_ptr) {
00149             ns_dyn_mem_free(nvm_request);
00150             ns_dyn_mem_free(ns_nvm_request_ptr);
00151             return NS_NVM_MEMORY;
00152         }
00153         ns_nvm_request_ptr->original_request = nvm_request;
00154         pnvm_status = platform_nvm_init(ns_nvm_callback_func, ns_nvm_request_ptr);
00155         if (pnvm_status != PLATFORM_NVM_OK) {
00156             ns_dyn_mem_free(nvm_request);
00157             ns_dyn_mem_free(ns_nvm_request_ptr);
00158             return NS_NVM_ERROR;
00159         }
00160         ns_list_init(&ns_nvm_request_list);
00161         ns_nvm_initialized = true;
00162         ns_nvm_operation_in_progress = true;
00163     }
00164     return ret;
00165 }
00166 
00167 static ns_nvm_request_t *ns_nvm_create_request(ns_nvm_callback *callback, void *context, const char *key_name, uint8_t *buf, uint16_t *buf_len, uint8_t operation)
00168 {
00169     ns_nvm_request_t *ns_nvm_request_ptr = ns_dyn_mem_temporary_alloc(sizeof(ns_nvm_request_t));
00170     if (!ns_nvm_request_ptr) {
00171         return NULL;
00172     }
00173     ns_nvm_request_ptr->client_context = context;
00174     ns_nvm_request_ptr->callback = callback;
00175     ns_nvm_request_ptr->client_key_name = key_name;
00176     ns_nvm_request_ptr->operation = operation;
00177     ns_nvm_request_ptr->buffer = buf;
00178     ns_nvm_request_ptr->buffer_len = buf_len;
00179 
00180     return ns_nvm_request_ptr;
00181 }
00182 
00183 static int ns_nvm_operation_continue(ns_nvm_request_t *request, bool free_request)
00184 {
00185     platform_nvm_status ret = PLATFORM_NVM_OK;
00186 
00187     ns_nvm_operation_in_progress = true;
00188     switch(request->operation) {
00189         case NS_NVM_KEY_WRITE:
00190             request->operation = NS_NVM_KEY_CREATE;
00191             ret = platform_nvm_key_create(ns_nvm_callback_func, request->client_key_name, *request->buffer_len, 0, request);
00192             break;
00193         case NS_NVM_KEY_READ:
00194             ret = platform_nvm_read(ns_nvm_callback_func, request->client_key_name, request->buffer, request->buffer_len, request);
00195             break;
00196         case NS_NVM_KEY_DELETE:
00197             ret = platform_nvm_key_delete(ns_nvm_callback_func, request->client_key_name, request);
00198             break;
00199     }
00200 
00201     if (ret != PLATFORM_NVM_OK) {
00202         if (free_request == true) {
00203             // free request if requested
00204             ns_dyn_mem_free(request);
00205         }
00206         ns_nvm_operation_in_progress = false;
00207         return NS_NVM_ERROR;
00208     }
00209 
00210     return NS_NVM_OK;
00211 }
00212 
00213 static void ns_nvm_operation_end(ns_nvm_request_t *ns_nvm_request_ptr, int client_retval)
00214 {
00215     ns_nvm_request_ptr->callback(client_retval, ns_nvm_request_ptr->client_context);
00216     ns_dyn_mem_free(ns_nvm_request_ptr);
00217     ns_nvm_operation_in_progress = false;
00218 
00219     ns_list_foreach_safe(ns_nvm_request_t, pending_req, &ns_nvm_request_list) {
00220         // there are pending requests to be processed
00221         ns_list_remove(&ns_nvm_request_list, pending_req);
00222         int ret = ns_nvm_operation_continue(pending_req, false);
00223         if (ret != NS_NVM_OK) {
00224             ns_nvm_operation_end(pending_req, ret);
00225         } else {
00226             break;
00227         }
00228     }
00229 }