Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

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-2019, 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/ns_address_internal.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     }
00119     int path_len = strlen(thread_nvm_store_get_root_path());
00120     if (path_len == 0 || path_len > MAX_ROOT_PATH_LEN) {
00121         return 0;
00122     }
00123     return 1;
00124 }
00125 
00126 int thread_nvm_store_mleid_rloc_map_write(thread_nvm_mleid_rloc_map *mleid_rloc_map)
00127 {
00128     char lc_data_path[LEADER_INFO_STRING_LEN];
00129     if (!root_path_valid()) {
00130         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00131     }
00132     thread_nvm_store_create_path(lc_data_path, LEADER_INFO_FILE);
00133     tr_debug("writing to store rloc mapping info");
00134     return thread_nvm_store_write(lc_data_path, mleid_rloc_map, sizeof(thread_nvm_mleid_rloc_map), LEADER_INFO_DATA_VERSION);
00135 }
00136 
00137 int thread_nvm_store_mleid_rloc_map_read(thread_nvm_mleid_rloc_map *mleid_rloc_map)
00138 {
00139     char lc_data_path[LEADER_INFO_STRING_LEN];
00140     uint32_t version;
00141     if (NULL == mleid_rloc_map) {
00142         return THREAD_NVM_FILE_PARAMETER_INVALID;
00143     }
00144     if (!root_path_valid()) {
00145         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00146     }
00147     thread_nvm_store_create_path(lc_data_path, LEADER_INFO_FILE);
00148 
00149     int ret = thread_nvm_store_read(lc_data_path, mleid_rloc_map, sizeof(thread_nvm_mleid_rloc_map), &version);
00150 
00151     if (THREAD_NVM_FILE_SUCCESS != ret) {
00152         tr_info("Leader data map read failed");
00153         thread_nvm_store_mleid_rloc_map_remove();
00154         return ret;
00155     }
00156 
00157     if (LEADER_INFO_DATA_VERSION != version) {
00158         tr_info("Leader data map version mismatch %"PRIu32, version);
00159         thread_nvm_store_mleid_rloc_map_remove();
00160         return THREAD_NVM_FILE_VERSION_WRONG;
00161     }
00162 
00163     return ret;
00164 }
00165 
00166 int thread_nvm_store_mleid_rloc_map_remove(void)
00167 {
00168     int status;
00169     tr_info("thread_nvm_store_leader_info_remove");
00170 
00171     if (!ns_file_system_get_root_path()) {
00172         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00173     }
00174 
00175     char lc_data_path[LEADER_INFO_STRING_LEN];
00176     thread_nvm_store_create_path(lc_data_path, LEADER_INFO_FILE);
00177     status = remove(lc_data_path);
00178     if (status != 0) {
00179         return THREAD_NVM_FILE_REMOVE_ERROR;
00180     }
00181     return THREAD_NVM_FILE_SUCCESS;
00182 }
00183 
00184 int thread_nvm_store_device_configuration_write(uint8_t *mac_ptr, uint8_t *mleid_ptr)
00185 {
00186     thread_nvm_device_conf_t d_c;
00187     if (!root_path_valid()) {
00188         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00189     }
00190     memcpy(d_c.mac, mac_ptr, sizeof(d_c.mac));
00191     memcpy(d_c.mle_id, mleid_ptr, sizeof(d_c.mle_id));
00192     char device_conf_path[DEVICE_CONF_STRING_LEN];
00193     thread_nvm_store_create_path(device_conf_path, DEVICE_CONF_FILE);
00194     return thread_nvm_store_write(device_conf_path, &d_c, sizeof(thread_nvm_device_conf_t), DEVICE_CONF_VERSION);
00195 }
00196 
00197 int thread_nvm_store_device_configuration_read(uint8_t *mac_ptr, uint8_t *mleid_ptr)
00198 {
00199     int ret = THREAD_NVM_FILE_READ_ERROR;
00200     if (!root_path_valid()) {
00201         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00202     }
00203     char device_conf_path[DEVICE_CONF_STRING_LEN];
00204     thread_nvm_store_create_path(device_conf_path, DEVICE_CONF_FILE);
00205     uint32_t version;
00206     thread_nvm_device_conf_t d_c;
00207 
00208     ret = thread_nvm_store_read(device_conf_path, &d_c, sizeof(thread_nvm_device_conf_t), &version);
00209     if (THREAD_NVM_FILE_SUCCESS == ret) {
00210         if (THREAD_NVM_FILE_SUCCESS == ret && DEVICE_CONF_VERSION != version) {
00211             tr_info("fast data version mismatch %"PRIu32, version);
00212             ret = THREAD_NVM_FILE_VERSION_WRONG;
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     int status = remove(ac_data_path);
00296     if (status != 0) {
00297         return THREAD_NVM_FILE_REMOVE_ERROR;
00298     }
00299     return THREAD_NVM_FILE_SUCCESS;
00300 }
00301 
00302 int thread_nvm_store_pending_configuration_remove(void)
00303 {
00304     if (!root_path_valid()) {
00305         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00306     }
00307     char ac_data_path[PENDING_CONF_STRING_LEN];
00308     thread_nvm_store_create_path(ac_data_path, THREAD_NVM_PENDING_CONF_FILE);
00309     int status = remove(ac_data_path);
00310     if (status != 0) {
00311         return THREAD_NVM_FILE_REMOVE_ERROR;
00312     }
00313     return THREAD_NVM_FILE_SUCCESS;
00314 }
00315 
00316 
00317 int thread_nvm_store_seq_counter_write(uint32_t network_seq_counter)
00318 {
00319     int ret = THREAD_NVM_FILE_SUCCESS;
00320     if (cached_fast_data.seq_counter != network_seq_counter) {
00321         ret = thread_nvm_store_all_counters_store(cached_fast_data.mac_frame_counter, cached_fast_data.mle_frame_counter, network_seq_counter);
00322         cached_fast_data.seq_counter = network_seq_counter;
00323     }
00324     return ret;
00325 }
00326 
00327 int thread_nvm_store_fast_data_check_and_write(uint32_t mac_frame_counter, uint32_t mle_frame_counter, uint32_t network_seq_counter)
00328 {
00329     int ret = THREAD_NVM_FILE_SUCCESS;
00330     if (((int)(mac_frame_counter - cached_fast_data.mac_frame_counter) > MAC_FRAME_COUNTER_LIMIT) ||
00331             ((int)(mle_frame_counter - cached_fast_data.mle_frame_counter) > MLE_FRAME_COUNTER_LIMIT) ||
00332             cached_fast_data.seq_counter != network_seq_counter) {
00333         ret = thread_nvm_store_all_counters_store(mac_frame_counter, mle_frame_counter, network_seq_counter);
00334         cached_fast_data.mac_frame_counter = mac_frame_counter;
00335         cached_fast_data.mle_frame_counter = mle_frame_counter;
00336         cached_fast_data.seq_counter = network_seq_counter;
00337     }
00338     return ret;
00339 }
00340 
00341 int thread_nvm_store_fast_data_write_all(uint32_t mac_frame_counter, uint32_t mle_frame_counter, uint32_t network_seq_counter)
00342 {
00343     int ret;
00344     ret = thread_nvm_store_all_counters_store(mac_frame_counter, mle_frame_counter, network_seq_counter);
00345     cached_fast_data.mac_frame_counter = mac_frame_counter;
00346     cached_fast_data.mle_frame_counter = mle_frame_counter;
00347     cached_fast_data.seq_counter = network_seq_counter;
00348     return ret;
00349 }
00350 
00351 int thread_nvm_store_frame_counters_check_and_write(uint32_t mac_frame_counter, uint32_t mle_frame_counter)
00352 {
00353     int ret = THREAD_NVM_FILE_SUCCESS;
00354     if (((int)(mac_frame_counter - cached_fast_data.mac_frame_counter) > MAC_FRAME_COUNTER_LIMIT) ||
00355             ((int)(mle_frame_counter - cached_fast_data.mle_frame_counter) > MLE_FRAME_COUNTER_LIMIT)) {
00356         ret = thread_nvm_store_all_counters_store(mac_frame_counter, mle_frame_counter, cached_fast_data.seq_counter);
00357         cached_fast_data.mac_frame_counter = mac_frame_counter;
00358         cached_fast_data.mle_frame_counter = mle_frame_counter;
00359     }
00360     return ret;
00361 }
00362 
00363 static int thread_nvm_store_all_counters_store(uint32_t mac_frame_counter, uint32_t mle_frame_counter, uint32_t network_seq_counter)
00364 {
00365     thread_nvm_fast_data_t fast_data;
00366     fast_data.mac_frame_counter = mac_frame_counter;
00367     fast_data.mle_frame_counter = mle_frame_counter;
00368     fast_data.seq_counter = network_seq_counter;
00369     if (root_path_valid()) {
00370         return thread_nvm_store_fast_data_save(&fast_data);
00371     } else {
00372         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00373     }
00374 }
00375 
00376 int thread_nvm_store_fast_data_write(thread_nvm_fast_data_t *fast_data)
00377 {
00378     cached_fast_data.mac_frame_counter = fast_data->mac_frame_counter;
00379     cached_fast_data.mle_frame_counter = fast_data->mle_frame_counter;
00380     cached_fast_data.seq_counter = fast_data->seq_counter;
00381 
00382     if (root_path_valid()) {
00383         return thread_nvm_store_fast_data_save(fast_data);
00384     } else {
00385         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00386     }
00387 }
00388 
00389 static void thread_nvm_store_create_path(char *fast_data_path, const char *file_name)
00390 {
00391     strcpy(fast_data_path, thread_nvm_store_get_root_path());
00392     strcat(fast_data_path, file_name);
00393 }
00394 
00395 int thread_nvm_store_fast_data_read(thread_nvm_fast_data_t *fast_data)
00396 {
00397     int ret = THREAD_NVM_FILE_SUCCESS;
00398 
00399     if (root_path_valid()) {
00400         char fast_data_path[FAST_DATA_STRING_LEN];
00401         thread_nvm_store_create_path(fast_data_path, FAST_DATA_FILE);
00402         uint32_t version;
00403         ret = thread_nvm_store_read(fast_data_path, fast_data, sizeof(thread_nvm_fast_data_t), &version);
00404         if (THREAD_NVM_FILE_SUCCESS == ret && FAST_DATA_VERSION != version) {
00405             tr_info("fast data version mismatch %"PRIu32, version);
00406             return THREAD_NVM_FILE_VERSION_WRONG;
00407         }
00408     } else {
00409         fast_data->mac_frame_counter = cached_fast_data.mac_frame_counter;
00410         fast_data->mle_frame_counter = cached_fast_data.mle_frame_counter;
00411         fast_data->seq_counter = cached_fast_data.seq_counter;
00412     }
00413     return ret;
00414 }
00415 
00416 static int thread_nvm_store_fast_data_save(thread_nvm_fast_data_t *fast_data_to_set)
00417 {
00418     char fast_data_path[FAST_DATA_STRING_LEN];
00419     thread_nvm_store_create_path(fast_data_path, FAST_DATA_FILE);
00420     return thread_nvm_store_write(fast_data_path, fast_data_to_set, sizeof(thread_nvm_fast_data_t), FAST_DATA_VERSION);
00421 }
00422 
00423 static int thread_nvm_store_write(const char *file_name, void *data, uint32_t data_size, uint32_t version)
00424 {
00425     FILE *fp = fopen(file_name, "w");
00426     if (fp == NULL) {
00427         tr_error("NVM open error: %s", file_name);
00428         return THREAD_NVM_FILE_CANNOT_OPEN;
00429     }
00430 
00431     size_t n_bytes = fwrite(&version, 1, sizeof(uint32_t), fp);
00432     if (n_bytes != sizeof(uint32_t)) {
00433         tr_warning("NVM version write error");
00434         fclose(fp);
00435         return THREAD_NVM_FILE_WRITE_ERROR;
00436     }
00437 
00438     n_bytes = fwrite(data, 1, data_size, fp);
00439     fclose(fp);
00440     if (n_bytes != data_size) {
00441         tr_error("NVM write error %s", file_name);
00442         return THREAD_NVM_FILE_WRITE_ERROR;
00443     } else {
00444         return THREAD_NVM_FILE_SUCCESS;
00445     }
00446 }
00447 
00448 // returns 0 when ok
00449 static int thread_nvm_store_read(const char *file_name, void *data, uint32_t data_size, uint32_t *version)
00450 {
00451     FILE *fp = fopen(file_name, "r");
00452     if (fp == NULL) {
00453         tr_warning("File not found: %s", file_name);
00454         return THREAD_NVM_FILE_CANNOT_OPEN;
00455     }
00456 
00457     size_t n_bytes = fread(version, 1, sizeof(uint32_t), fp);
00458     if (n_bytes != sizeof(uint32_t)) {
00459         tr_warning("NVM version read error %s", file_name);
00460         fclose(fp);
00461         return THREAD_NVM_FILE_READ_ERROR;
00462     }
00463 
00464     n_bytes = fread(data, 1, data_size, fp);
00465     fclose(fp);
00466     if (n_bytes != data_size) {
00467         tr_error("NVM read error %s", file_name);
00468         return THREAD_NVM_FILE_READ_ERROR;
00469     } else {
00470         return THREAD_NVM_FILE_SUCCESS; // return how many bytes was written.
00471     }
00472 }
00473 
00474 int thread_nvm_store_link_info_read(void)
00475 {
00476     nvm_link_info_t nvm_link_info_tmp;
00477     int status;
00478 
00479     if (!ns_file_system_get_root_path()) {
00480         if (!memcmp(cached_link_info.nvm_link_info.mac, ADDR_UNSPECIFIED, 8) &&
00481                 cached_link_info.nvm_link_info.short_addr == LINK_INFO_SHORT_ADDR_NOT_SET) {
00482             tr_info("link info not cached");
00483             return THREAD_NVM_FILE_READ_ERROR;
00484         }
00485     }
00486     cached_link_info.loaded = true;
00487     char link_info_path[LINK_INFO_STRING_LEN];
00488     strcpy(link_info_path, thread_nvm_store_get_root_path());
00489     strcat(link_info_path, LINK_INFO_FILE);
00490 
00491     uint32_t version = 0;
00492     status = thread_nvm_store_read(link_info_path, &nvm_link_info_tmp, sizeof(nvm_link_info_t), &version);
00493 
00494     if (status != THREAD_NVM_FILE_SUCCESS) {
00495         if (!memcmp(cached_link_info.nvm_link_info.mac, ADDR_UNSPECIFIED, 8) &&
00496                 cached_link_info.nvm_link_info.short_addr == LINK_INFO_SHORT_ADDR_NOT_SET) {
00497             tr_info("link info not cached and read error %d", status);
00498             cached_link_info.loaded = false;
00499             return THREAD_NVM_FILE_READ_ERROR;
00500         }
00501         return status;
00502     } else if (ACTIVE_CONF_DATA_VERSION != version) {
00503         tr_info("link info version mismatch %"PRIu32, version);
00504         return THREAD_NVM_FILE_VERSION_WRONG;
00505     }
00506     memcpy(cached_link_info.nvm_link_info.mac, nvm_link_info_tmp.mac, 8);
00507     cached_link_info.nvm_link_info.short_addr = nvm_link_info_tmp.short_addr;
00508     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);
00509     return THREAD_NVM_FILE_SUCCESS;
00510 }
00511 
00512 int thread_nvm_store_link_info_get(uint8_t *parent_mac64, uint16_t *my_short_address)
00513 {
00514     if (!memcmp(cached_link_info.nvm_link_info.mac, ADDR_UNSPECIFIED, 8) &&
00515             cached_link_info.nvm_link_info.short_addr == LINK_INFO_SHORT_ADDR_NOT_SET) {
00516         tr_info("thread_nvm_store_link_info_get addr zeros");
00517         return THREAD_NVM_FILE_READ_ERROR;
00518     }
00519 
00520     if (!cached_link_info.loaded) {
00521         return THREAD_NVM_FILE_READ_ERROR;
00522     }
00523     // read data from cache if cached data is available
00524     if (parent_mac64) {
00525         memcpy(parent_mac64, cached_link_info.nvm_link_info.mac, 8);
00526     }
00527     if (my_short_address) {
00528         *my_short_address = cached_link_info.nvm_link_info.short_addr;
00529     }
00530     return THREAD_NVM_FILE_SUCCESS;
00531 }
00532 
00533 int thread_nvm_store_link_info_clear(void)
00534 {
00535     int status;
00536     tr_info("thread_nvm_store_link_info_clear");
00537     memset(cached_link_info.nvm_link_info.mac, 0, 8);
00538     cached_link_info.nvm_link_info.short_addr = LINK_INFO_SHORT_ADDR_NOT_SET;
00539 
00540     cached_link_info.loaded = false;
00541 
00542     if (!ns_file_system_get_root_path()) {
00543         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00544     }
00545 
00546     char link_info_path[LINK_INFO_STRING_LEN];
00547     strcpy(link_info_path, thread_nvm_store_get_root_path());
00548     strcat(link_info_path, LINK_INFO_FILE);
00549 
00550     status = remove(link_info_path);
00551 
00552     if (status != 0) {
00553         return THREAD_NVM_FILE_REMOVE_ERROR;
00554     }
00555 
00556     return THREAD_NVM_FILE_SUCCESS;
00557 }
00558 
00559 int thread_nvm_store_link_info_write(uint8_t *parent_mac, uint16_t short_addr)
00560 {
00561     //tr_info("write mac: %s parent short addr: %"PRIu16, trace_array(parent_mac, 8), short_addr);
00562     if (parent_mac) {
00563         memcpy(cached_link_info.nvm_link_info.mac, parent_mac, 8);
00564     } else {
00565         memset(cached_link_info.nvm_link_info.mac, 0, 8);
00566         tr_info("setting to zero");
00567     }
00568     // when router parent is zeros, but my short address is the actual routing address.
00569     cached_link_info.nvm_link_info.short_addr = short_addr;
00570 
00571     if (cached_link_info.write_delay == LINK_INFO_WRITE_DONE) {
00572         cached_link_info.write_delay = LINK_INFO_WRITE_DELAY; // delay writing some seconds
00573     }
00574 
00575     if (!ns_file_system_get_root_path()) {
00576         return THREAD_NVM_FILE_ROOT_PATH_INVALID;
00577     }
00578 
00579     return THREAD_NVM_FILE_SUCCESS;
00580 }
00581 
00582 static void thread_nvm_store_link_info_delayed_write(uint32_t seconds)
00583 {
00584     if (cached_link_info.write_delay == LINK_INFO_WRITE_DONE) {
00585         return;
00586     } else if (cached_link_info.write_delay > seconds) {
00587         cached_link_info.write_delay -= seconds;
00588         return;
00589     }
00590     cached_link_info.write_delay = LINK_INFO_WRITE_DONE;
00591 
00592     if (!ns_file_system_get_root_path()) {
00593         return;
00594     }
00595 
00596     char link_info_path[LINK_INFO_STRING_LEN];
00597     strcpy(link_info_path, thread_nvm_store_get_root_path());
00598     strcat(link_info_path, LINK_INFO_FILE);
00599     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);
00600     thread_nvm_store_write(link_info_path, &cached_link_info.nvm_link_info, sizeof(nvm_link_info_t), LINK_INFO_DATA_VERSION);
00601 }
00602 
00603 void thread_nvm_store_seconds_timer(uint32_t seconds)
00604 {
00605     thread_nvm_store_link_info_delayed_write(seconds);
00606 }