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

« Back to documentation index

Show/hide line numbers thread_nvm_store.c Source File

thread_nvm_store.c

00001 /*
00002  * Copyright (c) 2017, Arm Limited and affiliates.
00003  * SPDX-License-Identifier: BSD-3-Clause
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holder nor the
00014  *    names of its contributors may be used to endorse or promote products
00015  *    derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 /*
00030  * \file thread_nvm_store.c
00031  *
00032  */
00033 
00034 #include "nsconfig.h"
00035 
00036 #include <string.h>
00037 #include <stdio.h>
00038 #include "Core/include/address.h"
00039 #include "ns_file_system.h"
00040 #include "thread_config.h"
00041 #include "thread_common.h"
00042 #include "thread_nvm_store.h"
00043 #include "ns_trace.h"
00044 
00045 #define TRACE_GROUP "tnvm"
00046 const char *FAST_DATA_FILE = "f_d";
00047 #define FAST_DATA_VERSION 1
00048 #define LINK_INFO_WRITE_DELAY 2
00049 #define LINK_INFO_SHORT_ADDR_NOT_SET 0xffff
00050 #define LINK_INFO_WRITE_DONE 0xffff
00051 
00052 const char *LINK_INFO_FILE = "l_i";
00053 #define LINK_INFO_DATA_VERSION 1
00054 
00055 const char *LEADER_INFO_FILE = "ld_i";
00056 #define LEADER_INFO_DATA_VERSION 1
00057 
00058 typedef struct {
00059     uint8_t mac[8];
00060     uint16_t short_addr;
00061 } nvm_link_info_t;
00062 
00063 typedef struct {
00064     nvm_link_info_t nvm_link_info;
00065     uint16_t write_delay;
00066     bool loaded;
00067 } thread_nvm_store_link_info_t;
00068 
00069 const char *THREAD_NVM_ACTIVE_CONF_FILE = "a_c";
00070 #define ACTIVE_CONF_DATA_VERSION 1
00071 
00072 const char *DEVICE_CONF_FILE = "s_d";
00073 #define DEVICE_CONF_VERSION 1
00074 
00075 const char *THREAD_NVM_PENDING_CONF_FILE = "p_c";
00076 #define PENDING_CONF_DATA_VERSION 1
00077 
00078 static const char* thread_nvm_store_get_root_path(void);
00079 static int root_path_valid(void);
00080 static int thread_nvm_store_read(const char *file_name, void *data, uint32_t data_size, uint32_t *version);
00081 static int thread_nvm_store_write(const char *file_name, void *data, uint32_t data_size, uint32_t version);
00082 static void thread_nvm_store_create_path(char* fast_data_path, const char* file_name);
00083 static int thread_nvm_store_fast_data_save(thread_nvm_fast_data_t* fast_data_to_set);
00084 static int thread_nvm_store_all_counters_store(uint32_t mac_frame_counter, uint32_t mle_frame_counter, uint32_t seq_counter);
00085 static void thread_nvm_store_link_info_delayed_write(uint32_t seconds);
00086 
00087 #define MAX_ROOT_PATH_LEN 150
00088 
00089 #define FAST_DATA_STRING_LEN (strlen(FAST_DATA_FILE)+strlen(thread_nvm_store_get_root_path())+1)
00090 #define ACTIVE_CONF_STRING_LEN (strlen(THREAD_NVM_ACTIVE_CONF_FILE)+strlen(thread_nvm_store_get_root_path())+1)
00091 #define DEVICE_CONF_STRING_LEN (strlen(DEVICE_CONF_FILE)+strlen(thread_nvm_store_get_root_path())+1)
00092 #define PENDING_CONF_STRING_LEN (strlen(THREAD_NVM_PENDING_CONF_FILE)+strlen(thread_nvm_store_get_root_path())+1)
00093 #define LINK_INFO_STRING_LEN (strlen(LINK_INFO_FILE)+strlen(thread_nvm_store_get_root_path())+1)
00094 #define LEADER_INFO_STRING_LEN (strlen(LEADER_INFO_FILE)+strlen(thread_nvm_store_get_root_path())+1)
00095 
00096 
00097 thread_nvm_fast_data_t cached_fast_data;
00098 thread_nvm_store_link_info_t cached_link_info = {
00099     .nvm_link_info.short_addr = LINK_INFO_SHORT_ADDR_NOT_SET,
00100     .nvm_link_info.mac = {0,0,0,0,0,0,0,0},
00101     .write_delay = LINK_INFO_WRITE_DELAY,
00102     .loaded = false
00103 };
00104 
00105 static const char* thread_nvm_store_get_root_path(void)
00106 {
00107     char* path = ns_file_system_get_root_path();
00108     if (NULL==path) {
00109         return "";
00110     }
00111     return path;
00112 }
00113 
00114 static int root_path_valid(void)
00115 {
00116     if (NULL==ns_file_system_get_root_path())
00117         return 0;
00118     int path_len = strlen(thread_nvm_store_get_root_path());
00119     if(path_len==0 || path_len>MAX_ROOT_PATH_LEN) {
00120         return 0;
00121     }
00122     return 1;
00123 }
00124 
00125 int thread_nvm_store_mleid_rloc_map_write(thread_nvm_mleid_rloc_map *mleid_rloc_map)
00126 {
00127     char lc_data_path[LEADER_INFO_STRING_LEN];
00128     if (!root_path_valid()) {
00129         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00130     }
00131     thread_nvm_store_create_path(lc_data_path, LEADER_INFO_FILE);
00132     tr_debug("writing to store rloc mapping info");
00133     return thread_nvm_store_write(lc_data_path, mleid_rloc_map, sizeof(thread_nvm_mleid_rloc_map), LEADER_INFO_DATA_VERSION);
00134 }
00135 
00136 int thread_nvm_store_mleid_rloc_map_read(thread_nvm_mleid_rloc_map *mleid_rloc_map)
00137 {
00138     char lc_data_path[LEADER_INFO_STRING_LEN];
00139     uint32_t version;
00140     if (NULL==mleid_rloc_map) {
00141         return THREAD_NVM_FILE_PARAMETER_INVALID;
00142     }
00143     if (!root_path_valid()) {
00144         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00145     }
00146     thread_nvm_store_create_path(lc_data_path, LEADER_INFO_FILE);
00147 
00148     int ret = thread_nvm_store_read(lc_data_path, mleid_rloc_map, sizeof(thread_nvm_mleid_rloc_map), &version);
00149 
00150     if (THREAD_NVM_FILE_SUCCESS!=ret) {
00151         tr_info("Leader data map read failed");
00152         thread_nvm_store_mleid_rloc_map_remove();
00153         return ret;
00154     }
00155 
00156     if (LEADER_INFO_DATA_VERSION!=version) {
00157         tr_info("Leader data map version mismatch %"PRIu32, version);
00158         thread_nvm_store_mleid_rloc_map_remove();
00159         return THREAD_NVM_FILE_VERSION_WRONG;
00160     }
00161 
00162     return ret;
00163 }
00164 
00165 int thread_nvm_store_mleid_rloc_map_remove(void)
00166 {
00167     int status;
00168     tr_info("thread_nvm_store_leader_info_remove");
00169 
00170     if (!ns_file_system_get_root_path()) {
00171         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00172     }
00173 
00174     char lc_data_path[LEADER_INFO_STRING_LEN];
00175     thread_nvm_store_create_path(lc_data_path, LEADER_INFO_FILE);
00176     status = remove(lc_data_path);
00177     if (status != 0) {
00178       return THREAD_NVM_FILE_REMOVE_ERROR;
00179     }
00180     return THREAD_NVM_FILE_SUCCESS;
00181 }
00182 
00183 int thread_nvm_store_device_configuration_write(uint8_t *mac_ptr, uint8_t *mleid_ptr)
00184 {
00185    thread_nvm_device_conf_t d_c;
00186    if (!root_path_valid()) {
00187        return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00188    }
00189    memcpy(d_c.mac, mac_ptr, sizeof(d_c.mac));
00190    memcpy(d_c.mle_id, mleid_ptr, sizeof(d_c.mle_id));
00191    char device_conf_path[DEVICE_CONF_STRING_LEN];
00192    thread_nvm_store_create_path(device_conf_path, DEVICE_CONF_FILE);
00193    return thread_nvm_store_write(device_conf_path, &d_c, sizeof(thread_nvm_device_conf_t), DEVICE_CONF_VERSION);
00194 }
00195 
00196 int thread_nvm_store_device_configuration_read(uint8_t *mac_ptr, uint8_t *mleid_ptr)
00197 {
00198     int ret = THREAD_NVM_FILE_READ_ERROR;
00199     if (!root_path_valid()) {
00200         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00201     }
00202     char device_conf_path[DEVICE_CONF_STRING_LEN];
00203     thread_nvm_store_create_path(device_conf_path, DEVICE_CONF_FILE);
00204     uint32_t version;
00205     thread_nvm_device_conf_t d_c;
00206 
00207     ret = thread_nvm_store_read(device_conf_path, &d_c, sizeof(thread_nvm_device_conf_t), &version);
00208     if(THREAD_NVM_FILE_SUCCESS==ret) {
00209         if (THREAD_NVM_FILE_SUCCESS==ret && DEVICE_CONF_VERSION!=version) {
00210             tr_info("fast data version mismatch %"PRIu32, version);
00211             ret = THREAD_NVM_FILE_VERSION_WRONG;
00212         }
00213         else {
00214             memcpy(mac_ptr, d_c.mac, sizeof(d_c.mac));
00215             memcpy(mleid_ptr, d_c.mle_id, sizeof(d_c.mle_id));
00216         }
00217     }
00218     return ret;
00219 }
00220 
00221 int thread_nvm_store_pending_configuration_write(void *data, uint16_t size)
00222 {
00223     char pc_data_path[PENDING_CONF_STRING_LEN];
00224     if (NULL==data) {
00225         return THREAD_NVM_FILE_PARAMETER_INVALID;
00226     }
00227     if (!root_path_valid()) {
00228         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00229     }
00230     thread_nvm_store_create_path(pc_data_path, THREAD_NVM_PENDING_CONF_FILE);
00231     return thread_nvm_store_write(pc_data_path, data, size, PENDING_CONF_DATA_VERSION);
00232 }
00233 
00234 int thread_nvm_store_pending_configuration_read(void *data, uint16_t size)
00235 {
00236     char pc_data_path[PENDING_CONF_STRING_LEN];
00237     uint32_t version;
00238     if (NULL==data) {
00239         return THREAD_NVM_FILE_PARAMETER_INVALID;
00240     }
00241     if (!root_path_valid()) {
00242         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00243     }
00244     thread_nvm_store_create_path(pc_data_path, THREAD_NVM_PENDING_CONF_FILE);
00245 
00246     int ret = thread_nvm_store_read(pc_data_path, data, size, &version);
00247     if (THREAD_NVM_FILE_SUCCESS==ret && PENDING_CONF_DATA_VERSION!=version) {
00248         tr_info("Pending configuration version mismatch %"PRIu32, version);
00249         return THREAD_NVM_FILE_VERSION_WRONG;
00250     }
00251     return ret;
00252 }
00253 
00254 int thread_nvm_store_active_configuration_write(void *data, uint16_t data_size)
00255 {
00256     char ac_data_path[ACTIVE_CONF_STRING_LEN];
00257     if (NULL==data) {
00258         return THREAD_NVM_FILE_PARAMETER_INVALID;
00259     }
00260     if (!root_path_valid()) {
00261         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00262     }
00263 
00264     thread_nvm_store_create_path(ac_data_path, THREAD_NVM_ACTIVE_CONF_FILE);
00265     return thread_nvm_store_write(ac_data_path, data, data_size, ACTIVE_CONF_DATA_VERSION);
00266 }
00267 
00268 int thread_nvm_store_active_configuration_read(void *data, uint16_t data_size)
00269 {
00270     char ac_data_path[ACTIVE_CONF_STRING_LEN];
00271     uint32_t version;
00272     if (NULL==data) {
00273         return THREAD_NVM_FILE_PARAMETER_INVALID;
00274     }
00275     if (!root_path_valid()) {
00276         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00277     }
00278     thread_nvm_store_create_path(ac_data_path, THREAD_NVM_ACTIVE_CONF_FILE);
00279 
00280     int ret = thread_nvm_store_read(ac_data_path, data, data_size, &version);
00281     if (THREAD_NVM_FILE_SUCCESS==ret && ACTIVE_CONF_DATA_VERSION!=version) {
00282         tr_info("active configuration version mismatch %"PRIu32, version);
00283         return THREAD_NVM_FILE_VERSION_WRONG;
00284     }
00285     return ret;
00286 }
00287 
00288 int thread_nvm_store_active_configuration_remove(void)
00289 {
00290     if (!root_path_valid()) {
00291         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00292     }
00293     char ac_data_path[ACTIVE_CONF_STRING_LEN];
00294     thread_nvm_store_create_path(ac_data_path, THREAD_NVM_ACTIVE_CONF_FILE);
00295     return remove(ac_data_path);
00296 }
00297 
00298 int thread_nvm_store_pending_configuration_remove(void)
00299 {
00300     if (!root_path_valid()) {
00301         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00302     }
00303     char ac_data_path[PENDING_CONF_STRING_LEN];
00304     thread_nvm_store_create_path(ac_data_path, THREAD_NVM_PENDING_CONF_FILE);
00305     return remove(ac_data_path);
00306 }
00307 
00308 
00309 int thread_nvm_store_seq_counter_write(uint32_t network_seq_counter)
00310 {
00311     int ret = THREAD_NVM_FILE_SUCCESS;
00312     if (cached_fast_data.seq_counter!=network_seq_counter) {
00313         ret = thread_nvm_store_all_counters_store(cached_fast_data.mac_frame_counter, cached_fast_data.mle_frame_counter, network_seq_counter);
00314         cached_fast_data.seq_counter=network_seq_counter;
00315     }
00316     return ret;
00317 }
00318 
00319 int thread_nvm_store_fast_data_check_and_write(uint32_t mac_frame_counter, uint32_t mle_frame_counter, uint32_t network_seq_counter)
00320 {
00321     int ret = THREAD_NVM_FILE_SUCCESS;
00322     if( ((int)(mac_frame_counter - cached_fast_data.mac_frame_counter) > MAC_FRAME_COUNTER_LIMIT) ||
00323         ((int)(mle_frame_counter - cached_fast_data.mle_frame_counter) > MLE_FRAME_COUNTER_LIMIT) ||
00324         cached_fast_data.seq_counter!=network_seq_counter) {
00325             ret = thread_nvm_store_all_counters_store(mac_frame_counter, mle_frame_counter, network_seq_counter);
00326             cached_fast_data.mac_frame_counter = mac_frame_counter;
00327             cached_fast_data.mle_frame_counter = mle_frame_counter;
00328             cached_fast_data.seq_counter=network_seq_counter;
00329     }
00330     return ret;
00331 }
00332 
00333 
00334 int thread_nvm_store_frame_counters_check_and_write(uint32_t mac_frame_counter, uint32_t mle_frame_counter)
00335 {
00336     int ret = THREAD_NVM_FILE_SUCCESS;
00337     if( ((int)(mac_frame_counter - cached_fast_data.mac_frame_counter) > MAC_FRAME_COUNTER_LIMIT) ||
00338         ((int)(mle_frame_counter - cached_fast_data.mle_frame_counter) > MLE_FRAME_COUNTER_LIMIT)) {
00339             ret = thread_nvm_store_all_counters_store(mac_frame_counter, mle_frame_counter, cached_fast_data.seq_counter);
00340             cached_fast_data.mac_frame_counter = mac_frame_counter;
00341             cached_fast_data.mle_frame_counter = mle_frame_counter;
00342     }
00343     return ret;
00344 }
00345 
00346 static int thread_nvm_store_all_counters_store(uint32_t mac_frame_counter, uint32_t mle_frame_counter, uint32_t network_seq_counter)
00347 {
00348     thread_nvm_fast_data_t fast_data;
00349     fast_data.mac_frame_counter = mac_frame_counter;
00350     fast_data.mle_frame_counter = mle_frame_counter;
00351     fast_data.seq_counter = network_seq_counter;
00352     if (root_path_valid()) {
00353         return thread_nvm_store_fast_data_save(&fast_data);
00354     }
00355     else{
00356         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00357     }
00358 }
00359 
00360 int thread_nvm_store_fast_data_write(thread_nvm_fast_data_t* fast_data)
00361 {
00362     cached_fast_data.mac_frame_counter = fast_data->mac_frame_counter;
00363     cached_fast_data.mle_frame_counter = fast_data->mle_frame_counter;
00364     cached_fast_data.seq_counter = fast_data->seq_counter;
00365 
00366     if (root_path_valid()) {
00367         return thread_nvm_store_fast_data_save(fast_data);
00368     }
00369     else {
00370         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00371     }
00372 }
00373 
00374 static void thread_nvm_store_create_path(char* fast_data_path, const char* file_name)
00375 {
00376     strcpy(fast_data_path, thread_nvm_store_get_root_path());
00377     strcat(fast_data_path, file_name);
00378 }
00379 
00380 int thread_nvm_store_fast_data_read(thread_nvm_fast_data_t* fast_data)
00381 {
00382     int ret = THREAD_NVM_FILE_SUCCESS;
00383 
00384     if (root_path_valid()) {
00385         char fast_data_path[FAST_DATA_STRING_LEN];
00386         thread_nvm_store_create_path(fast_data_path, FAST_DATA_FILE);
00387         uint32_t version;
00388         ret = thread_nvm_store_read(fast_data_path, fast_data, sizeof(thread_nvm_fast_data_t), &version);
00389         if (THREAD_NVM_FILE_SUCCESS==ret && FAST_DATA_VERSION!=version) {
00390             tr_info("fast data version mismatch %"PRIu32, version);
00391             return THREAD_NVM_FILE_VERSION_WRONG;
00392         }
00393     }
00394     else {
00395         fast_data->mac_frame_counter = cached_fast_data.mac_frame_counter;
00396         fast_data->mle_frame_counter = cached_fast_data.mle_frame_counter;
00397         fast_data->seq_counter = cached_fast_data.seq_counter;
00398     }
00399     return ret;
00400 }
00401 
00402 static int thread_nvm_store_fast_data_save(thread_nvm_fast_data_t* fast_data_to_set)
00403 {
00404     char fast_data_path[FAST_DATA_STRING_LEN];
00405     thread_nvm_store_create_path(fast_data_path, FAST_DATA_FILE);
00406     return thread_nvm_store_write(fast_data_path, fast_data_to_set, sizeof(thread_nvm_fast_data_t), FAST_DATA_VERSION);
00407 }
00408 
00409 static int thread_nvm_store_write(const char *file_name, void *data, uint32_t data_size, uint32_t version)
00410 {
00411     FILE *fp = fopen(file_name, "w");
00412     if(fp == NULL) {
00413         tr_error("NVM open error: %s", file_name);
00414         return THREAD_NVM_FILE_CANNOT_OPEN;
00415     }
00416 
00417     size_t n_bytes = fwrite(&version, 1, sizeof(uint32_t), fp);
00418     if (n_bytes!=sizeof(uint32_t)) {
00419         tr_warning("NVM version write error");
00420         fclose(fp);
00421         return THREAD_NVM_FILE_WRITE_ERROR;
00422     }
00423 
00424     n_bytes = fwrite(data, 1, data_size, fp);
00425     fclose(fp);
00426     if (n_bytes!=data_size) {
00427         tr_error("NVM write error %s", file_name);
00428         return THREAD_NVM_FILE_WRITE_ERROR;
00429     }
00430     else {
00431         return THREAD_NVM_FILE_SUCCESS;
00432     }
00433 }
00434 
00435 // returns 0 when ok
00436 static int thread_nvm_store_read(const char *file_name, void *data, uint32_t data_size, uint32_t *version)
00437 {
00438     FILE *fp = fopen(file_name, "r");
00439     if(fp == NULL) {
00440         tr_warning("File not found: %s", file_name);
00441         return THREAD_NVM_FILE_CANNOT_OPEN;
00442     }
00443 
00444     size_t n_bytes = fread(version, 1, sizeof(uint32_t), fp);
00445     if (n_bytes!=sizeof(uint32_t)) {
00446         tr_warning("NVM version read error %s", file_name);
00447         fclose(fp);
00448         return THREAD_NVM_FILE_READ_ERROR;
00449     }
00450 
00451     n_bytes = fread(data, 1, data_size, fp);
00452     fclose(fp);
00453     if (n_bytes!=data_size) {
00454         tr_error("NVM read error %s", file_name);
00455         return THREAD_NVM_FILE_READ_ERROR;
00456     }
00457     else {
00458         return THREAD_NVM_FILE_SUCCESS; // return how many bytes was written.
00459     }
00460 }
00461 
00462 int thread_nvm_store_link_info_read(void)
00463 {
00464     nvm_link_info_t nvm_link_info_tmp;
00465     int status;
00466 
00467     if (!ns_file_system_get_root_path()) {
00468         if (!memcmp(cached_link_info.nvm_link_info.mac, ADDR_UNSPECIFIED, 8) &&
00469             cached_link_info.nvm_link_info.short_addr == LINK_INFO_SHORT_ADDR_NOT_SET) {
00470             tr_info("link info not cached");
00471             return THREAD_NVM_FILE_READ_ERROR;
00472         }
00473     }
00474     cached_link_info.loaded = true;
00475     char link_info_path[LINK_INFO_STRING_LEN];
00476     strcpy(link_info_path, thread_nvm_store_get_root_path());
00477     strcat(link_info_path, LINK_INFO_FILE);
00478 
00479     uint32_t version=0;
00480     status = thread_nvm_store_read(link_info_path, &nvm_link_info_tmp, sizeof(nvm_link_info_t), &version);
00481 
00482     if (status != THREAD_NVM_FILE_SUCCESS) {
00483         if (!memcmp(cached_link_info.nvm_link_info.mac, ADDR_UNSPECIFIED, 8) &&
00484             cached_link_info.nvm_link_info.short_addr == LINK_INFO_SHORT_ADDR_NOT_SET) {
00485             tr_info("link info not cached and read error %d", status);
00486             cached_link_info.loaded = false;
00487             return THREAD_NVM_FILE_READ_ERROR;
00488         }
00489         return status;
00490     }
00491     else if (ACTIVE_CONF_DATA_VERSION != version) {
00492         tr_info("link info version mismatch %"PRIu32, version);
00493         return THREAD_NVM_FILE_VERSION_WRONG;
00494     }
00495     memcpy(cached_link_info.nvm_link_info.mac, nvm_link_info_tmp.mac, 8);
00496     cached_link_info.nvm_link_info.short_addr = nvm_link_info_tmp.short_addr;
00497     tr_info("info read: %s parent short addr: %"PRIu16, trace_array(cached_link_info.nvm_link_info.mac, 8), cached_link_info.nvm_link_info.short_addr);
00498     return THREAD_NVM_FILE_SUCCESS;
00499 }
00500 
00501 int thread_nvm_store_link_info_get(uint8_t *parent_mac64, uint16_t *my_short_address)
00502 {
00503     if (!memcmp(cached_link_info.nvm_link_info.mac, ADDR_UNSPECIFIED, 8) &&
00504         cached_link_info.nvm_link_info.short_addr == LINK_INFO_SHORT_ADDR_NOT_SET) {
00505         tr_info("thread_nvm_store_link_info_get addr zeros");
00506         return THREAD_NVM_FILE_READ_ERROR;
00507     }
00508 
00509     if (!cached_link_info.loaded) {
00510         return THREAD_NVM_FILE_READ_ERROR;
00511     }
00512     // read data from cache if cached data is available
00513     if (parent_mac64) {
00514         memcpy(parent_mac64, cached_link_info.nvm_link_info.mac, 8);
00515     }
00516     if (my_short_address) {
00517         *my_short_address = cached_link_info.nvm_link_info.short_addr;
00518     }
00519     return THREAD_NVM_FILE_SUCCESS;
00520 }
00521 
00522 int thread_nvm_store_link_info_clear(void)
00523 {
00524     int status;
00525     tr_info("thread_nvm_store_link_info_clear");
00526     memset(cached_link_info.nvm_link_info.mac, 0, 8);
00527     cached_link_info.nvm_link_info.short_addr = LINK_INFO_SHORT_ADDR_NOT_SET;
00528 
00529     cached_link_info.loaded = false;
00530 
00531     if (!ns_file_system_get_root_path()) {
00532         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00533     }
00534 
00535     char link_info_path[LINK_INFO_STRING_LEN];
00536     strcpy(link_info_path, thread_nvm_store_get_root_path());
00537     strcat(link_info_path, LINK_INFO_FILE);
00538 
00539     status = remove(link_info_path);
00540 
00541     if (status != 0) {
00542       return THREAD_NVM_FILE_REMOVE_ERROR;
00543     }
00544 
00545     return THREAD_NVM_FILE_SUCCESS;
00546 }
00547 
00548 int thread_nvm_store_link_info_write(uint8_t *parent_mac, uint16_t short_addr)
00549 {
00550     //tr_info("write mac: %s parent short addr: %"PRIu16, trace_array(parent_mac, 8), short_addr);
00551     if (parent_mac) {
00552         memcpy(cached_link_info.nvm_link_info.mac, parent_mac, 8);
00553     } else {
00554         memset(cached_link_info.nvm_link_info.mac, 0, 8);
00555         tr_info("setting to zero");
00556     }
00557     // when router parent is zeros, but my short address is the actual routing address.
00558     cached_link_info.nvm_link_info.short_addr = short_addr;
00559 
00560     if (cached_link_info.write_delay == LINK_INFO_WRITE_DONE) {
00561         cached_link_info.write_delay = LINK_INFO_WRITE_DELAY; // delay writing some seconds
00562     }
00563 
00564     if (!ns_file_system_get_root_path()) {
00565         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00566     }
00567 
00568     return THREAD_NVM_FILE_SUCCESS;
00569 }
00570 
00571 static void thread_nvm_store_link_info_delayed_write(uint32_t seconds)
00572 {
00573     if (cached_link_info.write_delay == LINK_INFO_WRITE_DONE) {
00574         return;
00575     }
00576     else if (cached_link_info.write_delay > seconds) {
00577         cached_link_info.write_delay -= seconds;
00578         return;
00579     }
00580     cached_link_info.write_delay = LINK_INFO_WRITE_DONE;
00581 
00582     if (!ns_file_system_get_root_path()) {
00583         return;
00584     }
00585 
00586     char link_info_path[LINK_INFO_STRING_LEN];
00587     strcpy(link_info_path, thread_nvm_store_get_root_path());
00588     strcat(link_info_path, LINK_INFO_FILE);
00589     tr_info("link info write parent mac: %s parent short addr: %"PRIu16, trace_array(cached_link_info.nvm_link_info.mac, 8), cached_link_info.nvm_link_info.short_addr);
00590     thread_nvm_store_write(link_info_path, &cached_link_info.nvm_link_info, sizeof(nvm_link_info_t), LINK_INFO_DATA_VERSION);
00591 }
00592 
00593 void thread_nvm_store_seconds_timer(uint32_t seconds)
00594 {
00595     thread_nvm_store_link_info_delayed_write(seconds);
00596 }