takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

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-2018, 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 200
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 int thread_nvm_store_fast_data_write_all(uint32_t mac_frame_counter, uint32_t mle_frame_counter, uint32_t network_seq_counter)
00334 {
00335     int ret;
00336     ret = thread_nvm_store_all_counters_store(mac_frame_counter, mle_frame_counter, network_seq_counter);
00337     cached_fast_data.mac_frame_counter = mac_frame_counter;
00338     cached_fast_data.mle_frame_counter = mle_frame_counter;
00339     cached_fast_data.seq_counter=network_seq_counter;
00340     return ret;
00341 }
00342 
00343 int thread_nvm_store_frame_counters_check_and_write(uint32_t mac_frame_counter, uint32_t mle_frame_counter)
00344 {
00345     int ret = THREAD_NVM_FILE_SUCCESS;
00346     if( ((int)(mac_frame_counter - cached_fast_data.mac_frame_counter) > MAC_FRAME_COUNTER_LIMIT) ||
00347         ((int)(mle_frame_counter - cached_fast_data.mle_frame_counter) > MLE_FRAME_COUNTER_LIMIT)) {
00348             ret = thread_nvm_store_all_counters_store(mac_frame_counter, mle_frame_counter, cached_fast_data.seq_counter);
00349             cached_fast_data.mac_frame_counter = mac_frame_counter;
00350             cached_fast_data.mle_frame_counter = mle_frame_counter;
00351     }
00352     return ret;
00353 }
00354 
00355 static int thread_nvm_store_all_counters_store(uint32_t mac_frame_counter, uint32_t mle_frame_counter, uint32_t network_seq_counter)
00356 {
00357     thread_nvm_fast_data_t fast_data;
00358     fast_data.mac_frame_counter = mac_frame_counter;
00359     fast_data.mle_frame_counter = mle_frame_counter;
00360     fast_data.seq_counter = network_seq_counter;
00361     if (root_path_valid()) {
00362         return thread_nvm_store_fast_data_save(&fast_data);
00363     }
00364     else{
00365         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00366     }
00367 }
00368 
00369 int thread_nvm_store_fast_data_write(thread_nvm_fast_data_t* fast_data)
00370 {
00371     cached_fast_data.mac_frame_counter = fast_data->mac_frame_counter;
00372     cached_fast_data.mle_frame_counter = fast_data->mle_frame_counter;
00373     cached_fast_data.seq_counter = fast_data->seq_counter;
00374 
00375     if (root_path_valid()) {
00376         return thread_nvm_store_fast_data_save(fast_data);
00377     }
00378     else {
00379         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00380     }
00381 }
00382 
00383 static void thread_nvm_store_create_path(char* fast_data_path, const char* file_name)
00384 {
00385     strcpy(fast_data_path, thread_nvm_store_get_root_path());
00386     strcat(fast_data_path, file_name);
00387 }
00388 
00389 int thread_nvm_store_fast_data_read(thread_nvm_fast_data_t* fast_data)
00390 {
00391     int ret = THREAD_NVM_FILE_SUCCESS;
00392 
00393     if (root_path_valid()) {
00394         char fast_data_path[FAST_DATA_STRING_LEN];
00395         thread_nvm_store_create_path(fast_data_path, FAST_DATA_FILE);
00396         uint32_t version;
00397         ret = thread_nvm_store_read(fast_data_path, fast_data, sizeof(thread_nvm_fast_data_t), &version);
00398         if (THREAD_NVM_FILE_SUCCESS==ret && FAST_DATA_VERSION!=version) {
00399             tr_info("fast data version mismatch %"PRIu32, version);
00400             return THREAD_NVM_FILE_VERSION_WRONG;
00401         }
00402     }
00403     else {
00404         fast_data->mac_frame_counter = cached_fast_data.mac_frame_counter;
00405         fast_data->mle_frame_counter = cached_fast_data.mle_frame_counter;
00406         fast_data->seq_counter = cached_fast_data.seq_counter;
00407     }
00408     return ret;
00409 }
00410 
00411 static int thread_nvm_store_fast_data_save(thread_nvm_fast_data_t* fast_data_to_set)
00412 {
00413     char fast_data_path[FAST_DATA_STRING_LEN];
00414     thread_nvm_store_create_path(fast_data_path, FAST_DATA_FILE);
00415     return thread_nvm_store_write(fast_data_path, fast_data_to_set, sizeof(thread_nvm_fast_data_t), FAST_DATA_VERSION);
00416 }
00417 
00418 static int thread_nvm_store_write(const char *file_name, void *data, uint32_t data_size, uint32_t version)
00419 {
00420     FILE *fp = fopen(file_name, "w");
00421     if(fp == NULL) {
00422         tr_error("NVM open error: %s", file_name);
00423         return THREAD_NVM_FILE_CANNOT_OPEN;
00424     }
00425 
00426     size_t n_bytes = fwrite(&version, 1, sizeof(uint32_t), fp);
00427     if (n_bytes!=sizeof(uint32_t)) {
00428         tr_warning("NVM version write error");
00429         fclose(fp);
00430         return THREAD_NVM_FILE_WRITE_ERROR;
00431     }
00432 
00433     n_bytes = fwrite(data, 1, data_size, fp);
00434     fclose(fp);
00435     if (n_bytes!=data_size) {
00436         tr_error("NVM write error %s", file_name);
00437         return THREAD_NVM_FILE_WRITE_ERROR;
00438     }
00439     else {
00440         return THREAD_NVM_FILE_SUCCESS;
00441     }
00442 }
00443 
00444 // returns 0 when ok
00445 static int thread_nvm_store_read(const char *file_name, void *data, uint32_t data_size, uint32_t *version)
00446 {
00447     FILE *fp = fopen(file_name, "r");
00448     if(fp == NULL) {
00449         tr_warning("File not found: %s", file_name);
00450         return THREAD_NVM_FILE_CANNOT_OPEN;
00451     }
00452 
00453     size_t n_bytes = fread(version, 1, sizeof(uint32_t), fp);
00454     if (n_bytes!=sizeof(uint32_t)) {
00455         tr_warning("NVM version read error %s", file_name);
00456         fclose(fp);
00457         return THREAD_NVM_FILE_READ_ERROR;
00458     }
00459 
00460     n_bytes = fread(data, 1, data_size, fp);
00461     fclose(fp);
00462     if (n_bytes!=data_size) {
00463         tr_error("NVM read error %s", file_name);
00464         return THREAD_NVM_FILE_READ_ERROR;
00465     }
00466     else {
00467         return THREAD_NVM_FILE_SUCCESS; // return how many bytes was written.
00468     }
00469 }
00470 
00471 int thread_nvm_store_link_info_read(void)
00472 {
00473     nvm_link_info_t nvm_link_info_tmp;
00474     int status;
00475 
00476     if (!ns_file_system_get_root_path()) {
00477         if (!memcmp(cached_link_info.nvm_link_info.mac, ADDR_UNSPECIFIED, 8) &&
00478             cached_link_info.nvm_link_info.short_addr == LINK_INFO_SHORT_ADDR_NOT_SET) {
00479             tr_info("link info not cached");
00480             return THREAD_NVM_FILE_READ_ERROR;
00481         }
00482     }
00483     cached_link_info.loaded = true;
00484     char link_info_path[LINK_INFO_STRING_LEN];
00485     strcpy(link_info_path, thread_nvm_store_get_root_path());
00486     strcat(link_info_path, LINK_INFO_FILE);
00487 
00488     uint32_t version=0;
00489     status = thread_nvm_store_read(link_info_path, &nvm_link_info_tmp, sizeof(nvm_link_info_t), &version);
00490 
00491     if (status != THREAD_NVM_FILE_SUCCESS) {
00492         if (!memcmp(cached_link_info.nvm_link_info.mac, ADDR_UNSPECIFIED, 8) &&
00493             cached_link_info.nvm_link_info.short_addr == LINK_INFO_SHORT_ADDR_NOT_SET) {
00494             tr_info("link info not cached and read error %d", status);
00495             cached_link_info.loaded = false;
00496             return THREAD_NVM_FILE_READ_ERROR;
00497         }
00498         return status;
00499     }
00500     else if (ACTIVE_CONF_DATA_VERSION != version) {
00501         tr_info("link info version mismatch %"PRIu32, version);
00502         return THREAD_NVM_FILE_VERSION_WRONG;
00503     }
00504     memcpy(cached_link_info.nvm_link_info.mac, nvm_link_info_tmp.mac, 8);
00505     cached_link_info.nvm_link_info.short_addr = nvm_link_info_tmp.short_addr;
00506     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);
00507     return THREAD_NVM_FILE_SUCCESS;
00508 }
00509 
00510 int thread_nvm_store_link_info_get(uint8_t *parent_mac64, uint16_t *my_short_address)
00511 {
00512     if (!memcmp(cached_link_info.nvm_link_info.mac, ADDR_UNSPECIFIED, 8) &&
00513         cached_link_info.nvm_link_info.short_addr == LINK_INFO_SHORT_ADDR_NOT_SET) {
00514         tr_info("thread_nvm_store_link_info_get addr zeros");
00515         return THREAD_NVM_FILE_READ_ERROR;
00516     }
00517 
00518     if (!cached_link_info.loaded) {
00519         return THREAD_NVM_FILE_READ_ERROR;
00520     }
00521     // read data from cache if cached data is available
00522     if (parent_mac64) {
00523         memcpy(parent_mac64, cached_link_info.nvm_link_info.mac, 8);
00524     }
00525     if (my_short_address) {
00526         *my_short_address = cached_link_info.nvm_link_info.short_addr;
00527     }
00528     return THREAD_NVM_FILE_SUCCESS;
00529 }
00530 
00531 int thread_nvm_store_link_info_clear(void)
00532 {
00533     int status;
00534     tr_info("thread_nvm_store_link_info_clear");
00535     memset(cached_link_info.nvm_link_info.mac, 0, 8);
00536     cached_link_info.nvm_link_info.short_addr = LINK_INFO_SHORT_ADDR_NOT_SET;
00537 
00538     cached_link_info.loaded = false;
00539 
00540     if (!ns_file_system_get_root_path()) {
00541         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00542     }
00543 
00544     char link_info_path[LINK_INFO_STRING_LEN];
00545     strcpy(link_info_path, thread_nvm_store_get_root_path());
00546     strcat(link_info_path, LINK_INFO_FILE);
00547 
00548     status = remove(link_info_path);
00549 
00550     if (status != 0) {
00551       return THREAD_NVM_FILE_REMOVE_ERROR;
00552     }
00553 
00554     return THREAD_NVM_FILE_SUCCESS;
00555 }
00556 
00557 int thread_nvm_store_link_info_write(uint8_t *parent_mac, uint16_t short_addr)
00558 {
00559     //tr_info("write mac: %s parent short addr: %"PRIu16, trace_array(parent_mac, 8), short_addr);
00560     if (parent_mac) {
00561         memcpy(cached_link_info.nvm_link_info.mac, parent_mac, 8);
00562     } else {
00563         memset(cached_link_info.nvm_link_info.mac, 0, 8);
00564         tr_info("setting to zero");
00565     }
00566     // when router parent is zeros, but my short address is the actual routing address.
00567     cached_link_info.nvm_link_info.short_addr = short_addr;
00568 
00569     if (cached_link_info.write_delay == LINK_INFO_WRITE_DONE) {
00570         cached_link_info.write_delay = LINK_INFO_WRITE_DELAY; // delay writing some seconds
00571     }
00572 
00573     if (!ns_file_system_get_root_path()) {
00574         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00575     }
00576 
00577     return THREAD_NVM_FILE_SUCCESS;
00578 }
00579 
00580 static void thread_nvm_store_link_info_delayed_write(uint32_t seconds)
00581 {
00582     if (cached_link_info.write_delay == LINK_INFO_WRITE_DONE) {
00583         return;
00584     }
00585     else if (cached_link_info.write_delay > seconds) {
00586         cached_link_info.write_delay -= seconds;
00587         return;
00588     }
00589     cached_link_info.write_delay = LINK_INFO_WRITE_DONE;
00590 
00591     if (!ns_file_system_get_root_path()) {
00592         return;
00593     }
00594 
00595     char link_info_path[LINK_INFO_STRING_LEN];
00596     strcpy(link_info_path, thread_nvm_store_get_root_path());
00597     strcat(link_info_path, LINK_INFO_FILE);
00598     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);
00599     thread_nvm_store_write(link_info_path, &cached_link_info.nvm_link_info, sizeof(nvm_link_info_t), LINK_INFO_DATA_VERSION);
00600 }
00601 
00602 void thread_nvm_store_seconds_timer(uint32_t seconds)
00603 {
00604     thread_nvm_store_link_info_delayed_write(seconds);
00605 }