| Flash Storage (или для краткости fstorage) это модуль для сохранения и стирания данных в постоянном хранилище, организованном в памяти FLASH микроконтроллера [1]. Этот модуль работает как обертка над SoftDevice flash API, принимая запросы на сохранение или стирание страниц с данными. Эти запросы ставятся в очередь для дальнейшей асинхронной обработки. Приложение оповещается о результатах операции через вызовы callback-функций для зарегистрированных обработчиков событий. Fstorage автоматически делит на части большие по объему данных операции записи и стирания, позволяя тем самым коду SoftDevice обрабатывать эти запросы в перерывах между операциями радиосвязи. Неудачные операции с флэш-памятью, которые не приняты или не запланированы SoftDevice, повторяются. Модуль Experimental: Flash Data Storage [2] использует внутри себя fstorage. Также fstorage может быть использован напрямую. [Регистрация использования] Модуль fstorage может использоваться разными приложениями, или разными частями приложения одновременно (но только не в нескольких потоках, т. е. не обеспечивается thread-safe функционирование). Каждый пользователь flash storage должен зарегистрироваться с модулем, чтобы запросить определенное количество страниц хранилища. Страница (page) в fstorage это физическая страница памяти FLASH микроконтроллера, размер которой зависит от модели чипа. После этого модуль дает доступ только к зарегистрированным страницам, не давая возможности обратиться к FLASH по адресам, выходящих за область зарегистрированных страниц. Все зарегистрированные пользователи используют свой собственный callback-обработчик, и принимают обновления страниц, которые они зарегистрировали для своего использования. Регистрация использования осуществляется во время компиляции через переменные секции [3]. Пользователь должен предоставить указатель на функцию, которая будет использована для обработки событий (event callbacks), количество страниц для резервирования и приоритет, и приоритет, определяющий способ назначения пространства в памяти FLASH. Эти параметры задаются фиксировано во время компиляции (compile time), и не могут быть изменены во время работы приложения (run time). Замечание: если Вы обновляете свое приложение, и хотите сохранить в целости имеющиеся в памяти FLASH данные приложения, то не должны менять приоритет или страницы FLASH, которые зарезервированы для каждого модуля. Чтобы добавить страницы для нового модуля, зарегистрируйте его с более низким приоритетом чем те приоритеты, которые уже используются. Для регистрации использования fstorage вызовите макрос FS_REGISTER_CFG, который определен в заголовке fstorage.h. Поместите в приложение код, аналогичный приведенному примеру ниже, чтобы создать переменную секции fs_config, содержащую конфигурацию для fstorage: 
#include "fstorage.h"
   FS_REGISTER_CFG(fs_config_t fs_config) =
{
   .callback  = fs_evt_handler, // Функция для обработки событий (event callbacks).
   .num_pages = NUM_PAGES,      // Количество требуемых физических страниц памяти FLASH.
   .priority  = 0xFE            // Приоритет использования FLASH.
};
 [Обработчик события] Следующий пример показывает декларацию обработчика событий (event handler) модуля fstorage: 
static void fs_evt_handler(fs_evt_t const * const evt, fs_ret_t result)
{
   if (result != FS_SUCCESS)
   {
      // Произошла ошибка.
   }
}
 [Приоритет для использования FLASH] Для каждой регистрации модуля fstorage обязательно нужно указать приоритет, с которым fstorage назначает пространство FLASH для модуля. Для приоритета возможны значения от 0 до 255, причем 255 зарезервировано для использования модулем Peer Manager [4]. Все эти сконфигурированные приоритеты должны быть уникальны. Flash storage назначает пространство FLASH с самым большим адресом памяти (сразу ниже загрузчика, если он присутствует) для модуля с самым присвоенным высоким приоритетом. Так что если, к примеру, у модуля 1 низкий приоритет, и ему нужна 1 страница, а у модуля 2 высокий приоритет, и ему нужно 2 страницы, то fstorage назначит эти 2 страницы для модуля 2 на самые старшие доступные адреса FLASH. Модуль 1 получит одну страницу сразу после этих двух страниц. [Инициализация] Следующий пример кода показывает, как инициализировать fstorage: 
fs_ret_t ret = fs_init(); if (ret != FS_SUCCESS)
{
   // Произошла ошибка.
}
 [Сохранение и стирание данных] Flash storage ставит в очередь запросы на операции с FLASH и взаимодействие с кодом SoftDevice, чтобы получить интервалы времени для обработки этих операций по порядку. Запросы на сохранение больших объемов данных делятся на несколько операций, чтобы оптимизировать взаимодействие с SoftDevice при получение желаемых слотов времени. Максимальное количество слов в одном сохранении может быть указано макросом FS_MAX_WRITE_SIZE_WORDS в заголовке fstorage_config.h. Запросы на стирание нескольких страниц делятся на операции стирания страниц по отдельности. Если SoftDevice не принял запрос, то fstorage повторяет поставленную в очередь операцию до тех пор, пока SoftDevice не примет запрос. Если SoftDevice принял запрос, но при этом столкнулся с ошибкой в планировании операции FLASH и произошел таймаут (это может произойти, к примеру, из-за высокой активности BLE), то fstorage повторит запрос некоторое предварительно сконфигурированное количество раз. Это максимальное количество повторов может быть задано макросом FS_OP_MAX_RETRIES в заголовке fstorage_config.h. Зарегистрированный пользователь оповещается об успехе или отказе операции путем вызова event callback. Следующий пример кода показывает, как сохранить данные. Предполагается, что fs_config это переменная секции, которая хранит конфигурацию fstorage: 
static uint32_t data = 0xAAAAAAAA;   fs_ret_t ret = fs_store(&fs_config, fs_config.p_start_addr, &data, 1); if (ret != FS_SUCCESS)
{
   // Произошла ошибка.
}
 Следующий пример кода показывает стирание страниц: 
#define PAGE_SIZE_WORDS 1024   // Получение адреса страницы. static uint32_t const * address_of_page(uint16_t page_num)
{
   return fs_config.p_start_addr + (page_num * PAGE_SIZE_WORDS);
}  fs_ret_t ret;   // Стирание одной страницы (страница 0).
ret = fs_erase(&fs_config, address_of_page(0), 1); if (ret != FS_SUCCESS)
{
   // Произошла ошибка.
}  // Стирание двух страниц, начиная со страницы 3.
ret = fs_erase(&fs_config, address_of_page(3), 2); if (ret != FS_SUCCESS)
{
   // Произошла ошибка.
}
 Успех или отказ каждой операции будет показан вызовами обработчика (event callbacks). Поэтому проверка кода возврата всего лишь покажет, была ли успешно вызвана функция для постановки операции в очередь, но этот код возврата ничего не будет говорить о том, выполнилась ли операция на самом деле. [Ссылки] 1. nRF5 SDK v13 Experimental Flash Storage site:nordicsemi.com.2. nRF5 SDK Flash Data Storage.
 3. nRF5 SDK Section Variables.
 4. nRF5 SDK Peer Manager.
 |