tile_storage.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. /**
  2. * NOTICE
  3. *
  4. * Copyright 2019 Tile Inc. All Rights Reserved.
  5. * All code or other information included in the accompanying files ("Tile Source Material")
  6. * is PROPRIETARY information of Tile Inc. ("Tile") and access and use of the Tile Source Material
  7. * is subject to these terms. The Tile Source Material may only be used for demonstration purposes,
  8. * and may not be otherwise distributed or made available to others, including for commercial purposes.
  9. * Without limiting the foregoing , you understand and agree that no production use
  10. * of the Tile Source Material is allowed without a Tile ID properly obtained under a separate
  11. * agreement with Tile.
  12. * You also understand and agree that Tile may terminate the limited rights granted under these terms
  13. * at any time in its discretion.
  14. * All Tile Source Material is provided AS-IS without warranty of any kind.
  15. * Tile does not warrant that the Tile Source Material will be error-free or fit for your purposes.
  16. * Tile will not be liable for any damages resulting from your use of or inability to use
  17. * the Tile Source Material.
  18. *
  19. * Support: firmware_support@tile.com
  20. */
  21. /**
  22. * @file tile_storage.c
  23. * @brief Tile storage system
  24. */
  25. #include "sdk_common.h"
  26. #if NRF_MODULE_ENABLED(TILE_SUPPORT)
  27. #include "tile_storage.h"
  28. #include "tile_lib.h"
  29. #include "tile_config.h"
  30. #include "modules/tile_tmd_module.h"
  31. #include "crc16.h"
  32. #include "nrf_fstorage.h"
  33. #include "nrf_soc.h"
  34. #include "nrf_log.h"
  35. #include "nrf_log_ctrl.h"
  36. #include "app_error.h"
  37. #include <stdint.h>
  38. #include <stdbool.h>
  39. #include <stddef.h>
  40. #include <string.h>
  41. /*******************************************************************************
  42. * Global variables
  43. ******************************************************************************/
  44. struct tile_persist_tag tile_persist __attribute__( (section("NoInit")) );
  45. struct tile_checked_tag * const tile_checked = &tile_persist.checked.s;
  46. struct tile_unchecked_tag * const tile_unchecked = &tile_persist.unchecked.s;
  47. struct tile_env_tag tile_env;
  48. /*******************************************************************************
  49. * Local variables
  50. ******************************************************************************/
  51. static volatile bool write_in_progress = false;
  52. static volatile bool write_one_more_time = false;
  53. const uint8_t interim_tile_id[8] = INTERIM_TILE_ID;
  54. const uint8_t interim_tile_key[16] = INTERIM_AUTH_KEY;
  55. /*******************************************************************************
  56. * Forward declarations
  57. ******************************************************************************/
  58. uint16_t tile_get_adv_uuid(void);
  59. static void tile_app_on_flash_evt(nrf_fstorage_evt_t * evt);
  60. static int compare_versions(uint8_t v1, uint8_t v2);
  61. static struct tile_persist_tag * active_app_data_bank(void);
  62. /*******************************************************************************
  63. * Flash region configuration
  64. ******************************************************************************/
  65. NRF_FSTORAGE_DEF(nrf_fstorage_t app_data_bank0) = {
  66. .start_addr = APP_DATA_BANK0_ADDRESS,
  67. .end_addr = (APP_DATA_BANK0_ADDRESS + APP_DATA_NUM_PAGES * PAGE_SIZE),
  68. .evt_handler = tile_app_on_flash_evt,
  69. };
  70. NRF_FSTORAGE_DEF(nrf_fstorage_t app_data_bank1) = {
  71. .start_addr = APP_DATA_BANK1_ADDRESS,
  72. .end_addr = (APP_DATA_BANK1_ADDRESS + APP_DATA_NUM_PAGES * PAGE_SIZE),
  73. .evt_handler = tile_app_on_flash_evt,
  74. };
  75. /*******************************************************************************
  76. * Global functions
  77. ******************************************************************************/
  78. /**@brief Sleep until an event is received. */
  79. static void power_manage(void)
  80. {
  81. #ifdef SOFTDEVICE_PRESENT
  82. (void) sd_app_evt_wait();
  83. #else
  84. __WFE();
  85. #endif
  86. }
  87. void wait_for_flash_ready(nrf_fstorage_t const * p_fstorage)
  88. {
  89. /* While fstorage is busy, sleep and wait for an event. */
  90. while (nrf_fstorage_is_busy(p_fstorage))
  91. {
  92. power_manage();
  93. }
  94. }
  95. #if 0
  96. /**@brief Helper function to obtain the last address on the last page of the on-chip flash that
  97. * can be used to write user data.
  98. */
  99. static uint32_t nrf5_flash_end_addr_get()
  100. {
  101. uint32_t const bootloader_addr = NRF_UICR->NRFFW[0];
  102. uint32_t const page_sz = NRF_FICR->CODEPAGESIZE;
  103. uint32_t const code_sz = NRF_FICR->CODESIZE;
  104. return (bootloader_addr != 0xFFFFFFFF ?
  105. bootloader_addr : (code_sz * page_sz));
  106. }
  107. #endif
  108. /**@brief This function initializes two banks to be used in ping-pong manner in the Flash memory for usage by Tile Service.
  109. * Purpose of two banks is to provide a back-up in case memory storage fails at some point in time
  110. * This function checks for RAM and flash memory validity.
  111. * a) If RAM data is valid, it stores the data in the newer bank in flash.
  112. * b) If neither RAM nor flash is valid, it initializes the data to default values and stores in flash.
  113. * This should happen only at very first boot
  114. * c) If RAM data is not valid, but flash is, it gets latest data from flash, copies it to RAM, and updates newer flash bank
  115. */
  116. void tile_storage_init(void)
  117. {
  118. ret_code_t ret;
  119. ret = nrf_fstorage_init(&app_data_bank0, &nrf_fstorage_sd, NULL);
  120. APP_ERROR_CHECK(ret);
  121. ret = nrf_fstorage_init(&app_data_bank1, &nrf_fstorage_sd, NULL);
  122. APP_ERROR_CHECK(ret);
  123. /* Check if RAM is still okay. Read from flash if not. */
  124. if(PERSIST_SIGNATURE == tile_persist.signature
  125. && tile_persist.crc == crc16_compute(tile_persist.checked.d, sizeof(tile_persist.checked.d), NULL))
  126. {
  127. /* RAM checks out. No need to load from flash. */
  128. }
  129. else
  130. {
  131. // Determine current tile_persist bank
  132. struct tile_persist_tag *p = active_app_data_bank();
  133. if(NULL == p)
  134. {
  135. // Initialize to sane values
  136. memset(&tile_persist, 0, sizeof(tile_persist));
  137. tile_checked->mode = TILE_MODE_SHIPPING;
  138. tile_checked->tdt_configuration = DEFAULT_TDT_CONFIG;
  139. memcpy(tile_checked->model_number, tile_model_number, TILE_MODEL_NUMBER_LEN);
  140. memcpy(tile_checked->hardware_version, tile_hw_version, TILE_HARDWARE_VERSION_LEN);
  141. }
  142. else
  143. {
  144. memcpy(&tile_persist, p, sizeof(tile_persist));
  145. }
  146. }
  147. tile_unchecked->reset_count++;
  148. tile_store_app_data();
  149. }
  150. /**
  151. * @brief Save tile_persist to flash
  152. */
  153. void tile_store_app_data(void)
  154. {
  155. ret_code_t ret;
  156. /* Compute CRC, to ensure most up-to-date version remains in RAM */
  157. tile_persist.crc = crc16_compute(tile_persist.checked.d, sizeof(tile_persist.checked.d), NULL);
  158. if(write_in_progress)
  159. {
  160. write_one_more_time = true;
  161. return;
  162. }
  163. write_in_progress = true;
  164. write_one_more_time = false;
  165. /* Update bank and ID */
  166. tile_checked->bank = !tile_checked->bank;
  167. tile_checked->id++;
  168. tile_checked->version = CHECKED_STRUCTURE_VERSION;
  169. tile_persist.signature = PERSIST_SIGNATURE;
  170. /* Recompute CRC, to account for bank switch */
  171. tile_persist.crc = crc16_compute(tile_persist.checked.d, sizeof(tile_persist.checked.d), NULL);
  172. /* Save */
  173. if(0 == tile_checked->bank)
  174. {
  175. ret = nrf_fstorage_erase(&app_data_bank0, app_data_bank0.start_addr, APP_DATA_NUM_PAGES, NULL);
  176. APP_ERROR_CHECK(ret);
  177. ret = nrf_fstorage_write(&app_data_bank0, app_data_bank0.start_addr, &tile_persist, sizeof(tile_persist), NULL);
  178. APP_ERROR_CHECK(ret);
  179. //wait_for_flash_ready(&app_data_bank1);
  180. }
  181. else
  182. {
  183. ret = nrf_fstorage_erase(&app_data_bank1, app_data_bank1.start_addr, APP_DATA_NUM_PAGES, NULL);
  184. APP_ERROR_CHECK(ret);
  185. ret = nrf_fstorage_write(&app_data_bank1, app_data_bank1.start_addr, &tile_persist, sizeof(tile_persist), NULL);
  186. APP_ERROR_CHECK(ret);
  187. //wait_for_flash_ready(&app_data_bank1);
  188. }
  189. }
  190. /*******************************************************************************
  191. * Fstorage callbacks
  192. ******************************************************************************/
  193. /**
  194. * @brief Callback for flash activity not initiated by Tile Lib.
  195. */
  196. static void tile_app_on_flash_evt(nrf_fstorage_evt_t * evt)
  197. {
  198. if (evt->result != NRF_SUCCESS)
  199. {
  200. NRF_LOG_INFO("--> Event received: ERROR while executing an fstorage operation.");
  201. return;
  202. }
  203. if(NRF_FSTORAGE_EVT_WRITE_RESULT == evt->id)
  204. {
  205. NRF_LOG_DEBUG("Fstorage Write Event Callback\n");
  206. write_in_progress = false;
  207. if(write_one_more_time)
  208. {
  209. tile_store_app_data();
  210. }
  211. }
  212. else if (NRF_FSTORAGE_EVT_ERASE_RESULT == evt->id)
  213. {
  214. NRF_LOG_DEBUG("Fstorage Erase Event Callback\n");
  215. }
  216. }
  217. /*******************************************************************************
  218. * Local functions
  219. ******************************************************************************/
  220. /**
  221. * @brief Compare 1-byte cyclic version counters
  222. *
  223. * We will define v1 < v2 if the difference (v2 - v1) mod 0x100
  224. * is less than 0x80 (this is equivalent to having v2 - v1 come out
  225. * positive in signed, 8-bit, 2's-complement arithmetic).
  226. *
  227. * @return 1 if v1 > v2, 0 if v1 = v2, and -1 if v1 < v2
  228. */
  229. static int compare_versions(uint8_t v1, uint8_t v2)
  230. {
  231. /*
  232. * This returns (v1 > v2) - (v1 < v2), i.e.
  233. * 1 if v1 > v2, 0 if v1 = v2, and -1 if v1 < v2
  234. */
  235. return (((v2 - v1) & 0xFF) > 0x80) - (((v2 - v1) & 0xFF) < 0x80);
  236. }
  237. /**
  238. * @brief Decide which bank is active, based on the validity of the banks and their IDs
  239. *
  240. * @param[in] valid0 True if bank 0 is valid.
  241. * @param[in] valid1 True if bank 1 is valid.
  242. * @param[in] id0 ID of bank 0.
  243. * @param[in] id1 ID of bank 1.
  244. *
  245. * @return 0 if bank 0 is the active bank, 1 if bank 1 is the active bank, and
  246. * -1 if neither bank is valid.
  247. */
  248. static int active_bank(bool valid0, bool valid1, uint8_t id0, uint8_t id1)
  249. {
  250. if(valid0 && valid1)
  251. {
  252. if(compare_versions(id0, id1) >= 0)
  253. {
  254. return 0;
  255. }
  256. else
  257. {
  258. return 1;
  259. }
  260. }
  261. else if(valid0)
  262. {
  263. return 0;
  264. }
  265. else if(valid1)
  266. {
  267. return 1;
  268. }
  269. else
  270. {
  271. return -1;
  272. }
  273. }
  274. /**
  275. * @brief Find the active tile_checked bank.
  276. *
  277. * @return A pointer to the active tile_checked structure in flash, or NULL if
  278. * there is no active bank.
  279. */
  280. static struct tile_persist_tag * active_app_data_bank(void)
  281. {
  282. struct tile_persist_tag *p0 = (void*)APP_DATA_BANK0_ADDRESS;
  283. struct tile_persist_tag *p1 = (void*)APP_DATA_BANK1_ADDRESS;
  284. bool p0_valid = false;
  285. bool p1_valid = false;
  286. if(PERSIST_SIGNATURE == p0->signature
  287. && 0 == p0->checked.s.bank
  288. && p0->crc == crc16_compute(p0->checked.d, sizeof(p0->checked.d), NULL))
  289. {
  290. p0_valid = true;
  291. }
  292. if(PERSIST_SIGNATURE == p1->signature
  293. && 1 == p1->checked.s.bank
  294. && p1->crc == crc16_compute(p1->checked.d, sizeof(p1->checked.d), NULL))
  295. {
  296. p1_valid = true;
  297. }
  298. int bank = active_bank(p0_valid, p1_valid, p0->checked.s.id, p1->checked.s.id);
  299. if(bank < 0)
  300. {
  301. return NULL;
  302. }
  303. else if(0 == bank)
  304. {
  305. return p0;
  306. }
  307. else if(1 == bank)
  308. {
  309. return p1;
  310. }
  311. else
  312. {
  313. /* Assert! We don't expect any other value to be returned. */
  314. return NULL;
  315. }
  316. }
  317. #endif // NRF_MODULE_ENABLED(TILE_SUPPORT)