S Classen / nrf51-sdk

Fork of nrf51-sdk by Nordic Semiconductor

Committer:
sclassen
Date:
Fri Aug 12 23:43:43 2016 +0000
Revision:
46:7f3d63792fc3
Parent:
38:2b762c52e657
- bug 272: increase sensitivity of tap for exiting low power mode; - updated BLE_API, nRF51822, and mbed libraries

Who changed what in which revision?

UserRevisionLine numberNew contents of line
vcoubard 38:2b762c52e657 1 /*
vcoubard 38:2b762c52e657 2 * Copyright (c) Nordic Semiconductor ASA
vcoubard 38:2b762c52e657 3 * All rights reserved.
vcoubard 38:2b762c52e657 4 *
vcoubard 38:2b762c52e657 5 * Redistribution and use in source and binary forms, with or without modification,
vcoubard 38:2b762c52e657 6 * are permitted provided that the following conditions are met:
vcoubard 38:2b762c52e657 7 *
vcoubard 38:2b762c52e657 8 * 1. Redistributions of source code must retain the above copyright notice, this
vcoubard 38:2b762c52e657 9 * list of conditions and the following disclaimer.
vcoubard 38:2b762c52e657 10 *
vcoubard 38:2b762c52e657 11 * 2. Redistributions in binary form must reproduce the above copyright notice, this
vcoubard 38:2b762c52e657 12 * list of conditions and the following disclaimer in the documentation and/or
vcoubard 38:2b762c52e657 13 * other materials provided with the distribution.
vcoubard 38:2b762c52e657 14 *
vcoubard 38:2b762c52e657 15 * 3. Neither the name of Nordic Semiconductor ASA nor the names of other
vcoubard 38:2b762c52e657 16 * contributors to this software may be used to endorse or promote products
vcoubard 38:2b762c52e657 17 * derived from this software without specific prior written permission.
vcoubard 38:2b762c52e657 18 *
vcoubard 38:2b762c52e657 19 *
vcoubard 38:2b762c52e657 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
vcoubard 38:2b762c52e657 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
vcoubard 38:2b762c52e657 22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
vcoubard 38:2b762c52e657 23 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
vcoubard 38:2b762c52e657 24 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
vcoubard 38:2b762c52e657 25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
vcoubard 38:2b762c52e657 26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
vcoubard 38:2b762c52e657 27 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
vcoubard 38:2b762c52e657 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
vcoubard 38:2b762c52e657 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
vcoubard 38:2b762c52e657 30 *
vcoubard 38:2b762c52e657 31 */
vcoubard 38:2b762c52e657 32
vcoubard 38:2b762c52e657 33 #include "fstorage.h"
vcoubard 38:2b762c52e657 34 #include <stdio.h>
vcoubard 38:2b762c52e657 35 #include <string.h>
vcoubard 38:2b762c52e657 36 #include <stdbool.h>
vcoubard 38:2b762c52e657 37 #include "fstorage_config.h"
vcoubard 38:2b762c52e657 38 #include "nrf_error.h"
vcoubard 38:2b762c52e657 39 #include "nrf_soc.h"
vcoubard 38:2b762c52e657 40
vcoubard 38:2b762c52e657 41
vcoubard 38:2b762c52e657 42 #define FS_FLAG_INIT (1 << 0) /**< fstorage has been initialized. */
vcoubard 38:2b762c52e657 43 #define FS_FLAG_PROCESSING (1 << 1) /**< fstorage is executing queued flash operations. */
vcoubard 38:2b762c52e657 44 #define FS_FLAG_FLASH_REQ_PENDING (1 << 2) /**< fstorage is waiting for a flash operation initiated by another module to complete. */
vcoubard 38:2b762c52e657 45
vcoubard 38:2b762c52e657 46
vcoubard 38:2b762c52e657 47 /**@brief Macro invocation that registers section fs_data.
vcoubard 38:2b762c52e657 48 *
vcoubard 38:2b762c52e657 49 * @details Required for compilation.
vcoubard 38:2b762c52e657 50 */
vcoubard 38:2b762c52e657 51 NRF_SECTION_VARS_REGISTER_SECTION(fs_data);
vcoubard 38:2b762c52e657 52
vcoubard 38:2b762c52e657 53
vcoubard 38:2b762c52e657 54 /**@brief Macro invocation that declares symbols used to find the beginning and end of the section fs_data.
vcoubard 38:2b762c52e657 55 *
vcoubard 38:2b762c52e657 56 * @details Required for compilation.
vcoubard 38:2b762c52e657 57 */
vcoubard 38:2b762c52e657 58 NRF_SECTION_VARS_REGISTER_SYMBOLS(fs_config_t, fs_data);
vcoubard 38:2b762c52e657 59
vcoubard 38:2b762c52e657 60
vcoubard 38:2b762c52e657 61 /**@defgroup Section vars helper macros.
vcoubard 38:2b762c52e657 62 *
vcoubard 38:2b762c52e657 63 * @details Macros used to manipulate registered section variables.
vcoubard 38:2b762c52e657 64 */
vcoubard 38:2b762c52e657 65 /**@brief Get section variable with fstorage configuration by index. */
vcoubard 38:2b762c52e657 66 #define FS_SECTION_VARS_GET(i) NRF_SECTION_VARS_GET(i, fs_config_t, fs_data)
vcoubard 38:2b762c52e657 67 /**@brief Get the number of registered section variables. */
vcoubard 38:2b762c52e657 68 #define FS_SECTION_VARS_COUNT NRF_SECTION_VARS_COUNT(fs_config_t, fs_data)
vcoubard 38:2b762c52e657 69 /**@brief Get the start address of the registered section variables. */
vcoubard 38:2b762c52e657 70 #define FS_SECTION_VARS_START_ADDR NRF_SECTION_VARS_START_ADDR(fs_data)
vcoubard 38:2b762c52e657 71 /**@brief Get the end address of the registered section variables. */
vcoubard 38:2b762c52e657 72 #define FS_SECTION_VARS_END_ADDR NRF_SECTION_VARS_END_ADDR(fs_data)
vcoubard 38:2b762c52e657 73
vcoubard 38:2b762c52e657 74 /** @} */
vcoubard 38:2b762c52e657 75
vcoubard 38:2b762c52e657 76
vcoubard 38:2b762c52e657 77 /**@brief The command queue element.
vcoubard 38:2b762c52e657 78 *
vcoubard 38:2b762c52e657 79 * @details Encapsulate details of a command requested to this module.
vcoubard 38:2b762c52e657 80 */
vcoubard 38:2b762c52e657 81 typedef struct
vcoubard 38:2b762c52e657 82 {
vcoubard 38:2b762c52e657 83 fs_config_t const * p_config; /**< The configuration of the user who requested the operation. */
vcoubard 38:2b762c52e657 84 uint8_t op_code; /**< Operation code. */
vcoubard 38:2b762c52e657 85 uint32_t const * p_src; /**< Pointer to the data to be written to flash. The data must be kept in memory until the operation has finished. */
vcoubard 38:2b762c52e657 86 uint32_t const * p_addr; /**< Destination of the data in flash. */
vcoubard 38:2b762c52e657 87 fs_length_t length_words; /**< Length of the operation */
vcoubard 38:2b762c52e657 88 fs_length_t offset; /**< Offset of the operation if operation is done in chunks */
vcoubard 38:2b762c52e657 89 } fs_cmd_t;
vcoubard 38:2b762c52e657 90
vcoubard 38:2b762c52e657 91
vcoubard 38:2b762c52e657 92 /**@brief Structure that defines the command queue
vcoubard 38:2b762c52e657 93 *
vcoubard 38:2b762c52e657 94 * @details This queue holds flash operations requested to the module.
vcoubard 38:2b762c52e657 95 * The data to be written must be kept in memory until the write operation is completed,
vcoubard 38:2b762c52e657 96 * i.e., a callback indicating completion is received by the application.
vcoubard 38:2b762c52e657 97 */
vcoubard 38:2b762c52e657 98 typedef struct
vcoubard 38:2b762c52e657 99 {
vcoubard 38:2b762c52e657 100 uint8_t rp; /**< The current element being processed. */
vcoubard 38:2b762c52e657 101 uint8_t count; /**< Number of elements in the queue. */
vcoubard 38:2b762c52e657 102 fs_cmd_t cmd[FS_CMD_QUEUE_SIZE]; /**< Array to maintain flash access operation details. */
vcoubard 38:2b762c52e657 103 } fs_cmd_queue_t;
vcoubard 38:2b762c52e657 104
vcoubard 38:2b762c52e657 105
vcoubard 38:2b762c52e657 106 static uint8_t m_flags; /**< FStorage status flags. */
vcoubard 38:2b762c52e657 107 static fs_cmd_queue_t m_cmd_queue; /**< Flash operation request queue. */
vcoubard 38:2b762c52e657 108 static uint16_t m_retry_count = 0; /**< Number of times a single flash operation was retried. */
vcoubard 38:2b762c52e657 109
vcoubard 38:2b762c52e657 110
vcoubard 38:2b762c52e657 111 // Function prototypes
vcoubard 38:2b762c52e657 112 static ret_code_t queue_process(void);
vcoubard 38:2b762c52e657 113 static ret_code_t queue_process_impl(void);
vcoubard 38:2b762c52e657 114 static void app_notify(uint32_t result, fs_cmd_t const * p_cmd);
vcoubard 38:2b762c52e657 115
vcoubard 38:2b762c52e657 116
vcoubard 38:2b762c52e657 117 /**@brief Macro to check that the configuration is non-NULL and within
vcoubard 38:2b762c52e657 118 * valid section variable memory bounds.
vcoubard 38:2b762c52e657 119 *
vcoubard 38:2b762c52e657 120 * @param[in] config Configuration to check.
vcoubard 38:2b762c52e657 121 */
vcoubard 38:2b762c52e657 122 #define FS_CHECK_CONFIG(config) \
vcoubard 38:2b762c52e657 123 ((FS_SECTION_VARS_START_ADDR < config) && (config < FS_SECTION_VARS_END_ADDR))
vcoubard 38:2b762c52e657 124
vcoubard 38:2b762c52e657 125
vcoubard 38:2b762c52e657 126 /**@brief Function to check that the configuration is non-NULL and within
vcoubard 38:2b762c52e657 127 * valid section variable memory bounds.
vcoubard 38:2b762c52e657 128 *
vcoubard 38:2b762c52e657 129 * @param[in] config Configuration to check.
vcoubard 38:2b762c52e657 130 */
vcoubard 38:2b762c52e657 131 static bool check_config(fs_config_t const * const config)
vcoubard 38:2b762c52e657 132 {
vcoubard 38:2b762c52e657 133 if (config == NULL)
vcoubard 38:2b762c52e657 134 {
vcoubard 38:2b762c52e657 135 return false;
vcoubard 38:2b762c52e657 136 }
vcoubard 38:2b762c52e657 137
vcoubard 38:2b762c52e657 138 if ((FS_SECTION_VARS_START_ADDR <= (uint32_t)config) && ((uint32_t)config < FS_SECTION_VARS_END_ADDR))
vcoubard 38:2b762c52e657 139 {
vcoubard 38:2b762c52e657 140 return true;
vcoubard 38:2b762c52e657 141 }
vcoubard 38:2b762c52e657 142 else
vcoubard 38:2b762c52e657 143 {
vcoubard 38:2b762c52e657 144 return false;
vcoubard 38:2b762c52e657 145 }
vcoubard 38:2b762c52e657 146 }
vcoubard 38:2b762c52e657 147
vcoubard 38:2b762c52e657 148
vcoubard 38:2b762c52e657 149 /**@brief Function to initialize the queue. */
vcoubard 38:2b762c52e657 150 static void queue_init(void)
vcoubard 38:2b762c52e657 151 {
vcoubard 38:2b762c52e657 152 memset(&m_cmd_queue, 0, sizeof(fs_cmd_queue_t));
vcoubard 38:2b762c52e657 153 }
vcoubard 38:2b762c52e657 154
vcoubard 38:2b762c52e657 155
vcoubard 38:2b762c52e657 156 /**@brief Function to reset a queue item to its default values.
vcoubard 38:2b762c52e657 157 *
vcoubard 38:2b762c52e657 158 * @param index Index of the queue element.
vcoubard 38:2b762c52e657 159 */
vcoubard 38:2b762c52e657 160 static void cmd_reset(uint32_t index)
vcoubard 38:2b762c52e657 161 {
vcoubard 38:2b762c52e657 162 memset(&m_cmd_queue.cmd[index], 0, sizeof(fs_cmd_t));
vcoubard 38:2b762c52e657 163 }
vcoubard 38:2b762c52e657 164
vcoubard 38:2b762c52e657 165
vcoubard 38:2b762c52e657 166 /**@brief Function to enqueue flash access command
vcoubard 38:2b762c52e657 167 *
vcoubard 38:2b762c52e657 168 * @param[in] config Registered configuration.
vcoubard 38:2b762c52e657 169 * @param[in] op_code Operation code.
vcoubard 38:2b762c52e657 170 * @param[in] address Destination of the data.
vcoubard 38:2b762c52e657 171 * @param[in] p_src Source of data or NULL if n/a.
vcoubard 38:2b762c52e657 172 * @param[in] length Length of the data, in 4 byte words.
vcoubard 38:2b762c52e657 173 *
vcoubard 38:2b762c52e657 174 * @retval NRF_SUCCESS Success. Command enqueued.
vcoubard 38:2b762c52e657 175 * @retval NRF_ERROR_NO_MEM Error. Queue is full.
vcoubard 38:2b762c52e657 176 * @retval Any error returned by the SoftDevice flash API.
vcoubard 38:2b762c52e657 177 */
vcoubard 38:2b762c52e657 178 static ret_code_t cmd_enqueue(fs_config_t const * p_config,
vcoubard 38:2b762c52e657 179 uint8_t op_code,
vcoubard 38:2b762c52e657 180 uint32_t const * p_addr,
vcoubard 38:2b762c52e657 181 uint32_t const * p_src,
vcoubard 38:2b762c52e657 182 fs_length_t length_words)
vcoubard 38:2b762c52e657 183 {
vcoubard 38:2b762c52e657 184 fs_cmd_t * p_cmd;
vcoubard 38:2b762c52e657 185 uint8_t write_pos;
vcoubard 38:2b762c52e657 186
vcoubard 38:2b762c52e657 187 if (m_cmd_queue.count == FS_CMD_QUEUE_SIZE - 1)
vcoubard 38:2b762c52e657 188 {
vcoubard 38:2b762c52e657 189 return NRF_ERROR_NO_MEM;
vcoubard 38:2b762c52e657 190 }
vcoubard 38:2b762c52e657 191
vcoubard 38:2b762c52e657 192 write_pos = (m_cmd_queue.rp + m_cmd_queue.count) % FS_CMD_QUEUE_SIZE;
vcoubard 38:2b762c52e657 193
vcoubard 38:2b762c52e657 194 p_cmd = &m_cmd_queue.cmd[write_pos];
vcoubard 38:2b762c52e657 195
vcoubard 38:2b762c52e657 196 p_cmd->p_config = p_config;
vcoubard 38:2b762c52e657 197 p_cmd->op_code = op_code;
vcoubard 38:2b762c52e657 198 p_cmd->p_src = p_src;
vcoubard 38:2b762c52e657 199 p_cmd->p_addr = p_addr;
vcoubard 38:2b762c52e657 200 p_cmd->length_words = length_words;
vcoubard 38:2b762c52e657 201
vcoubard 38:2b762c52e657 202 m_cmd_queue.count++;
vcoubard 38:2b762c52e657 203
vcoubard 38:2b762c52e657 204 return queue_process();
vcoubard 38:2b762c52e657 205 }
vcoubard 38:2b762c52e657 206
vcoubard 38:2b762c52e657 207
vcoubard 38:2b762c52e657 208 /**@brief Function to consume queue item and notify the return value of the operation.
vcoubard 38:2b762c52e657 209 *
vcoubard 38:2b762c52e657 210 * @details This function will report the result and remove the command from the queue after
vcoubard 38:2b762c52e657 211 * notification.
vcoubard 38:2b762c52e657 212 */
vcoubard 38:2b762c52e657 213 static void cmd_consume(uint32_t result, const fs_cmd_t * p_cmd)
vcoubard 38:2b762c52e657 214 {
vcoubard 38:2b762c52e657 215 // Consume the current item on the queue.
vcoubard 38:2b762c52e657 216 uint8_t rp = m_cmd_queue.rp;
vcoubard 38:2b762c52e657 217
vcoubard 38:2b762c52e657 218 m_cmd_queue.count--;
vcoubard 38:2b762c52e657 219 if (m_cmd_queue.count == 0)
vcoubard 38:2b762c52e657 220 {
vcoubard 38:2b762c52e657 221 // There are no elements left. Stop processing the queue.
vcoubard 38:2b762c52e657 222 m_flags &= ~FS_FLAG_PROCESSING;
vcoubard 38:2b762c52e657 223 }
vcoubard 38:2b762c52e657 224
vcoubard 38:2b762c52e657 225 if (++(m_cmd_queue.rp) == FS_CMD_QUEUE_SIZE)
vcoubard 38:2b762c52e657 226 {
vcoubard 38:2b762c52e657 227 m_cmd_queue.rp = 0;
vcoubard 38:2b762c52e657 228 }
vcoubard 38:2b762c52e657 229
vcoubard 38:2b762c52e657 230 // Notify upon successful operation.
vcoubard 38:2b762c52e657 231 app_notify(result, p_cmd);
vcoubard 38:2b762c52e657 232
vcoubard 38:2b762c52e657 233 // Reset the queue element.
vcoubard 38:2b762c52e657 234 cmd_reset(rp);
vcoubard 38:2b762c52e657 235 }
vcoubard 38:2b762c52e657 236
vcoubard 38:2b762c52e657 237
vcoubard 38:2b762c52e657 238 /**@brief Function to store data to flash.
vcoubard 38:2b762c52e657 239 *
vcoubard 38:2b762c52e657 240 * @param[in] p_cmd The queue element associated with the operation.
vcoubard 38:2b762c52e657 241 *
vcoubard 38:2b762c52e657 242 * @retval NRF_SUCCESS Success. The request was sent to the SoftDevice.
vcoubard 38:2b762c52e657 243 * @retval Any error returned by the SoftDevice flash API.
vcoubard 38:2b762c52e657 244 */
vcoubard 38:2b762c52e657 245 static __INLINE uint32_t store_execute(fs_cmd_t const * const p_cmd)
vcoubard 38:2b762c52e657 246 {
vcoubard 38:2b762c52e657 247 // Write in chunks if write-size is larger than FS_MAX_WRITE_SIZE.
vcoubard 38:2b762c52e657 248 fs_length_t const length = ((p_cmd->length_words - p_cmd->offset) < FS_MAX_WRITE_SIZE_WORDS) ?
vcoubard 38:2b762c52e657 249 (p_cmd->length_words - p_cmd->offset) : FS_MAX_WRITE_SIZE_WORDS;
vcoubard 38:2b762c52e657 250
vcoubard 38:2b762c52e657 251 return sd_flash_write((uint32_t*)p_cmd->p_addr + p_cmd->offset /* destination */,
vcoubard 38:2b762c52e657 252 (uint32_t*)p_cmd->p_src + p_cmd->offset /* source */,
vcoubard 38:2b762c52e657 253 length);
vcoubard 38:2b762c52e657 254 }
vcoubard 38:2b762c52e657 255
vcoubard 38:2b762c52e657 256
vcoubard 38:2b762c52e657 257 /**@brief Function to erase a page.
vcoubard 38:2b762c52e657 258 *
vcoubard 38:2b762c52e657 259 * @param[in] p_cmd The queue element associated with the operation.
vcoubard 38:2b762c52e657 260 *
vcoubard 38:2b762c52e657 261 * @retval NRF_SUCCESS Success. The request was sent to the SoftDevice.
vcoubard 38:2b762c52e657 262 * @retval Any error returned by the SoftDevice flash API.
vcoubard 38:2b762c52e657 263 */
vcoubard 38:2b762c52e657 264 static __INLINE uint32_t erase_execute(fs_cmd_t const * const p_cmd)
vcoubard 38:2b762c52e657 265 {
vcoubard 38:2b762c52e657 266 // Erase the page.
vcoubard 38:2b762c52e657 267 return sd_flash_page_erase((uint32_t)(p_cmd->p_addr + p_cmd->offset) / FS_PAGE_SIZE);
vcoubard 38:2b762c52e657 268 }
vcoubard 38:2b762c52e657 269
vcoubard 38:2b762c52e657 270
vcoubard 38:2b762c52e657 271 /**@brief Function to process the current element in the queue and return the result.
vcoubard 38:2b762c52e657 272 *
vcoubard 38:2b762c52e657 273 * @retval NRF_SUCCESS Success.
vcoubard 38:2b762c52e657 274 * @retval NRF_ERROR_FORBIDDEN Error. Undefined command.
vcoubard 38:2b762c52e657 275 * @retval Any error returned by the SoftDevice flash API.
vcoubard 38:2b762c52e657 276 */
vcoubard 38:2b762c52e657 277 static uint32_t queue_process_impl(void)
vcoubard 38:2b762c52e657 278 {
vcoubard 38:2b762c52e657 279 uint32_t ret;
vcoubard 38:2b762c52e657 280
vcoubard 38:2b762c52e657 281 fs_cmd_t const * const p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
vcoubard 38:2b762c52e657 282
vcoubard 38:2b762c52e657 283 switch (p_cmd->op_code)
vcoubard 38:2b762c52e657 284 {
vcoubard 38:2b762c52e657 285 case FS_OP_STORE:
vcoubard 38:2b762c52e657 286 ret = store_execute(p_cmd);
vcoubard 38:2b762c52e657 287 break;
vcoubard 38:2b762c52e657 288
vcoubard 38:2b762c52e657 289 case FS_OP_ERASE:
vcoubard 38:2b762c52e657 290 ret = erase_execute(p_cmd);
vcoubard 38:2b762c52e657 291 break;
vcoubard 38:2b762c52e657 292
vcoubard 38:2b762c52e657 293 case FS_OP_NONE:
vcoubard 38:2b762c52e657 294 ret = NRF_SUCCESS;
vcoubard 38:2b762c52e657 295 break;
vcoubard 38:2b762c52e657 296
vcoubard 38:2b762c52e657 297 default:
vcoubard 38:2b762c52e657 298 ret = NRF_ERROR_FORBIDDEN;
vcoubard 38:2b762c52e657 299 break;
vcoubard 38:2b762c52e657 300 }
vcoubard 38:2b762c52e657 301
vcoubard 38:2b762c52e657 302 return ret;
vcoubard 38:2b762c52e657 303 }
vcoubard 38:2b762c52e657 304
vcoubard 38:2b762c52e657 305
vcoubard 38:2b762c52e657 306 /**@brief Starts processing the queue if there are no pending flash operations
vcoubard 38:2b762c52e657 307 * for which we are awaiting a callback.
vcoubard 38:2b762c52e657 308 */
vcoubard 38:2b762c52e657 309 static ret_code_t queue_process(void)
vcoubard 38:2b762c52e657 310 {
vcoubard 38:2b762c52e657 311 ret_code_t ret = NRF_SUCCESS;
vcoubard 38:2b762c52e657 312
vcoubard 38:2b762c52e657 313 /** If the queue is not being processed, and there are still
vcoubard 38:2b762c52e657 314 * some elements in it, then start processing. */
vcoubard 38:2b762c52e657 315 if ( !(m_flags & FS_FLAG_PROCESSING) &&
vcoubard 38:2b762c52e657 316 (m_cmd_queue.count > 0))
vcoubard 38:2b762c52e657 317 {
vcoubard 38:2b762c52e657 318 m_flags |= FS_FLAG_PROCESSING;
vcoubard 38:2b762c52e657 319
vcoubard 38:2b762c52e657 320 ret = queue_process_impl();
vcoubard 38:2b762c52e657 321
vcoubard 38:2b762c52e657 322 /** There is ongoing flash-operation which was not
vcoubard 38:2b762c52e657 323 * initiated by fstorage. */
vcoubard 38:2b762c52e657 324 if (ret == NRF_ERROR_BUSY)
vcoubard 38:2b762c52e657 325 {
vcoubard 38:2b762c52e657 326 // Wait for a system callback.
vcoubard 38:2b762c52e657 327 m_flags |= FS_FLAG_FLASH_REQ_PENDING;
vcoubard 38:2b762c52e657 328
vcoubard 38:2b762c52e657 329 // Stop processing the queue.
vcoubard 38:2b762c52e657 330 m_flags &= ~FS_FLAG_PROCESSING;
vcoubard 38:2b762c52e657 331
vcoubard 38:2b762c52e657 332 ret = NRF_SUCCESS;
vcoubard 38:2b762c52e657 333 }
vcoubard 38:2b762c52e657 334 else if (ret != NRF_SUCCESS)
vcoubard 38:2b762c52e657 335 {
vcoubard 38:2b762c52e657 336 // Another error has occurred.
vcoubard 38:2b762c52e657 337 app_notify(ret, &m_cmd_queue.cmd[m_cmd_queue.rp]);
vcoubard 38:2b762c52e657 338 }
vcoubard 38:2b762c52e657 339 }
vcoubard 38:2b762c52e657 340
vcoubard 38:2b762c52e657 341 // If we are already processing the queue, return immediately.
vcoubard 38:2b762c52e657 342 return ret;
vcoubard 38:2b762c52e657 343 }
vcoubard 38:2b762c52e657 344
vcoubard 38:2b762c52e657 345
vcoubard 38:2b762c52e657 346 /**@brief Flash operation success callback handler.
vcoubard 38:2b762c52e657 347 *
vcoubard 38:2b762c52e657 348 * @details This function updates read/write pointers.
vcoubard 38:2b762c52e657 349 * This function resets retry count.
vcoubard 38:2b762c52e657 350 */
vcoubard 38:2b762c52e657 351 static __INLINE void on_operation_success(void)
vcoubard 38:2b762c52e657 352 {
vcoubard 38:2b762c52e657 353 fs_cmd_t * const p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
vcoubard 38:2b762c52e657 354
vcoubard 38:2b762c52e657 355 m_retry_count = 0;
vcoubard 38:2b762c52e657 356
vcoubard 38:2b762c52e657 357 switch (p_cmd->op_code)
vcoubard 38:2b762c52e657 358 {
vcoubard 38:2b762c52e657 359 case FS_OP_STORE:
vcoubard 38:2b762c52e657 360 // Update the offset on successful write.
vcoubard 38:2b762c52e657 361 p_cmd->offset += FS_MAX_WRITE_SIZE_WORDS;
vcoubard 38:2b762c52e657 362 break;
vcoubard 38:2b762c52e657 363
vcoubard 38:2b762c52e657 364 case FS_OP_ERASE:
vcoubard 38:2b762c52e657 365 // Update the offset to correspond to the page that has been erased.
vcoubard 38:2b762c52e657 366 p_cmd->offset += FS_PAGE_SIZE_WORDS;
vcoubard 38:2b762c52e657 367 break;
vcoubard 38:2b762c52e657 368 }
vcoubard 38:2b762c52e657 369
vcoubard 38:2b762c52e657 370 // If offset is equal to or larger than length, then the operation has finished.
vcoubard 38:2b762c52e657 371 if (p_cmd->offset >= p_cmd->length_words)
vcoubard 38:2b762c52e657 372 {
vcoubard 38:2b762c52e657 373 cmd_consume(NRF_SUCCESS, p_cmd);
vcoubard 38:2b762c52e657 374 }
vcoubard 38:2b762c52e657 375
vcoubard 38:2b762c52e657 376 queue_process();
vcoubard 38:2b762c52e657 377 }
vcoubard 38:2b762c52e657 378
vcoubard 38:2b762c52e657 379
vcoubard 38:2b762c52e657 380 /**@brief Flash operation failure callback handler.
vcoubard 38:2b762c52e657 381 *
vcoubard 38:2b762c52e657 382 * @details Function to keep track of retries and notify failures.
vcoubard 38:2b762c52e657 383 */
vcoubard 38:2b762c52e657 384 static __INLINE void on_operation_failure(uint32_t sys_evt)
vcoubard 38:2b762c52e657 385 {
vcoubard 38:2b762c52e657 386 const fs_cmd_t * p_cmd;
vcoubard 38:2b762c52e657 387
vcoubard 38:2b762c52e657 388 if (++m_retry_count > FS_CMD_MAX_RETRIES)
vcoubard 38:2b762c52e657 389 {
vcoubard 38:2b762c52e657 390 p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
vcoubard 38:2b762c52e657 391 cmd_consume(NRF_ERROR_TIMEOUT, p_cmd);
vcoubard 38:2b762c52e657 392 }
vcoubard 38:2b762c52e657 393
vcoubard 38:2b762c52e657 394 queue_process();
vcoubard 38:2b762c52e657 395 }
vcoubard 38:2b762c52e657 396
vcoubard 38:2b762c52e657 397
vcoubard 38:2b762c52e657 398 /**@brief Function to notify users.
vcoubard 38:2b762c52e657 399 *
vcoubard 38:2b762c52e657 400 * @param[in] result Result of the flash operation.
vcoubard 38:2b762c52e657 401 * @param[in] p_cmd The command associated with the callback.
vcoubard 38:2b762c52e657 402 */
vcoubard 38:2b762c52e657 403 static void app_notify(uint32_t result, fs_cmd_t const * const p_cmd)
vcoubard 38:2b762c52e657 404 {
vcoubard 38:2b762c52e657 405 p_cmd->p_config->cb(p_cmd->op_code, result, p_cmd->p_addr, p_cmd->length_words);
vcoubard 38:2b762c52e657 406 }
vcoubard 38:2b762c52e657 407
vcoubard 38:2b762c52e657 408
vcoubard 38:2b762c52e657 409 ret_code_t fs_init(void)
vcoubard 38:2b762c52e657 410 {
vcoubard 38:2b762c52e657 411 uint16_t lowest_index = 0;
vcoubard 38:2b762c52e657 412 uint16_t lowest_order = 0xFFFF;
vcoubard 38:2b762c52e657 413 uint32_t * current_end = (uint32_t*)FS_PAGE_END_ADDR;
vcoubard 38:2b762c52e657 414 uint32_t num_left = FS_SECTION_VARS_COUNT;
vcoubard 38:2b762c52e657 415
vcoubard 38:2b762c52e657 416 queue_init();
vcoubard 38:2b762c52e657 417
vcoubard 38:2b762c52e657 418 /** Assign pages to registered users, beginning with the ones with the lowest
vcoubard 38:2b762c52e657 419 * order, which will be assigned pages with the lowest memory address. */
vcoubard 38:2b762c52e657 420 do
vcoubard 38:2b762c52e657 421 {
vcoubard 38:2b762c52e657 422 fs_config_t * p_config;
vcoubard 38:2b762c52e657 423 for (uint16_t i = 0; i < FS_SECTION_VARS_COUNT; i++)
vcoubard 38:2b762c52e657 424 {
vcoubard 38:2b762c52e657 425 p_config = FS_SECTION_VARS_GET(i);
vcoubard 38:2b762c52e657 426
vcoubard 38:2b762c52e657 427 // Skip the ones which have the end-address already set.
vcoubard 38:2b762c52e657 428 if (p_config->p_end_addr != NULL)
vcoubard 38:2b762c52e657 429 continue;
vcoubard 38:2b762c52e657 430
vcoubard 38:2b762c52e657 431 if (p_config->page_order < lowest_order)
vcoubard 38:2b762c52e657 432 {
vcoubard 38:2b762c52e657 433 lowest_order = p_config->page_order;
vcoubard 38:2b762c52e657 434 lowest_index = i;
vcoubard 38:2b762c52e657 435 }
vcoubard 38:2b762c52e657 436 }
vcoubard 38:2b762c52e657 437
vcoubard 38:2b762c52e657 438 p_config = FS_SECTION_VARS_GET(lowest_index);
vcoubard 38:2b762c52e657 439
vcoubard 38:2b762c52e657 440 p_config->p_end_addr = current_end;
vcoubard 38:2b762c52e657 441 p_config->p_start_addr = p_config->p_end_addr - (p_config->num_pages * FS_PAGE_SIZE_WORDS);
vcoubard 38:2b762c52e657 442
vcoubard 38:2b762c52e657 443 current_end = p_config->p_start_addr;
vcoubard 38:2b762c52e657 444 lowest_order = 0xFFFF;
vcoubard 38:2b762c52e657 445
vcoubard 38:2b762c52e657 446 } while ( --num_left > 0 );
vcoubard 38:2b762c52e657 447
vcoubard 38:2b762c52e657 448 m_flags |= FS_FLAG_INIT;
vcoubard 38:2b762c52e657 449
vcoubard 38:2b762c52e657 450 return NRF_SUCCESS;
vcoubard 38:2b762c52e657 451 }
vcoubard 38:2b762c52e657 452
vcoubard 38:2b762c52e657 453
vcoubard 38:2b762c52e657 454 ret_code_t fs_store(fs_config_t const * p_config,
vcoubard 38:2b762c52e657 455 uint32_t const * p_addr,
vcoubard 38:2b762c52e657 456 uint32_t const * const p_data,
vcoubard 38:2b762c52e657 457 fs_length_t length_words)
vcoubard 38:2b762c52e657 458 {
vcoubard 38:2b762c52e657 459 if ((m_flags & FS_FLAG_INIT) == 0)
vcoubard 38:2b762c52e657 460 {
vcoubard 38:2b762c52e657 461 return NRF_ERROR_INVALID_STATE;
vcoubard 38:2b762c52e657 462 }
vcoubard 38:2b762c52e657 463
vcoubard 38:2b762c52e657 464 if (!check_config(p_config))
vcoubard 38:2b762c52e657 465 {
vcoubard 38:2b762c52e657 466 return NRF_ERROR_FORBIDDEN;
vcoubard 38:2b762c52e657 467 }
vcoubard 38:2b762c52e657 468
vcoubard 38:2b762c52e657 469 if (!is_word_aligned(p_addr))
vcoubard 38:2b762c52e657 470 {
vcoubard 38:2b762c52e657 471 return NRF_ERROR_INVALID_ADDR;
vcoubard 38:2b762c52e657 472 }
vcoubard 38:2b762c52e657 473
vcoubard 38:2b762c52e657 474 // Check that the erase operation is on pages owned by this user (configuration).
vcoubard 38:2b762c52e657 475 if ((p_addr < p_config->p_start_addr) || ((p_addr + length_words) > p_config->p_end_addr))
vcoubard 38:2b762c52e657 476 {
vcoubard 38:2b762c52e657 477 return NRF_ERROR_INVALID_ADDR;
vcoubard 38:2b762c52e657 478 }
vcoubard 38:2b762c52e657 479
vcoubard 38:2b762c52e657 480 return cmd_enqueue(p_config, FS_OP_STORE, p_addr, p_data, length_words);
vcoubard 38:2b762c52e657 481 }
vcoubard 38:2b762c52e657 482
vcoubard 38:2b762c52e657 483
vcoubard 38:2b762c52e657 484 ret_code_t fs_erase(fs_config_t const * p_config,
vcoubard 38:2b762c52e657 485 uint32_t * const p_addr,
vcoubard 38:2b762c52e657 486 fs_length_t const length_words)
vcoubard 38:2b762c52e657 487 {
vcoubard 38:2b762c52e657 488 if ((m_flags & FS_FLAG_INIT) == 0)
vcoubard 38:2b762c52e657 489 {
vcoubard 38:2b762c52e657 490 return NRF_ERROR_INVALID_STATE;
vcoubard 38:2b762c52e657 491 }
vcoubard 38:2b762c52e657 492
vcoubard 38:2b762c52e657 493 if (!check_config(p_config))
vcoubard 38:2b762c52e657 494 {
vcoubard 38:2b762c52e657 495 return NRF_ERROR_FORBIDDEN;
vcoubard 38:2b762c52e657 496 }
vcoubard 38:2b762c52e657 497
vcoubard 38:2b762c52e657 498 /** Check that the address is aligned on a page boundary and the length to erase
vcoubard 38:2b762c52e657 499 * is a multiple of the page size. */
vcoubard 38:2b762c52e657 500 if (((uint32_t)p_addr & (FS_PAGE_SIZE - 1)) ||
vcoubard 38:2b762c52e657 501 (length_words & (FS_PAGE_SIZE_WORDS - 1)))
vcoubard 38:2b762c52e657 502 {
vcoubard 38:2b762c52e657 503 return NRF_ERROR_INVALID_ADDR;
vcoubard 38:2b762c52e657 504 }
vcoubard 38:2b762c52e657 505
vcoubard 38:2b762c52e657 506 // Check that the erase operation is on pages owned by this user (configuration).
vcoubard 38:2b762c52e657 507 if ((p_addr < p_config->p_start_addr) || ((p_addr + length_words) > p_config->p_end_addr))
vcoubard 38:2b762c52e657 508 {
vcoubard 38:2b762c52e657 509 return NRF_ERROR_INVALID_ADDR;
vcoubard 38:2b762c52e657 510 }
vcoubard 38:2b762c52e657 511
vcoubard 38:2b762c52e657 512 return cmd_enqueue(p_config, FS_OP_ERASE, p_addr, NULL, length_words);
vcoubard 38:2b762c52e657 513 }
vcoubard 38:2b762c52e657 514
vcoubard 38:2b762c52e657 515
vcoubard 38:2b762c52e657 516 /**@brief Function to handle system events from the SoftDevice.
vcoubard 38:2b762c52e657 517 *
vcoubard 38:2b762c52e657 518 * @details This function should be dispatched system events if any of the modules used by
vcoubard 38:2b762c52e657 519 * the application rely on FStorage. Examples include @ref Peer Manager and
vcoubard 38:2b762c52e657 520 * @ref Flash Data Storage.
vcoubard 38:2b762c52e657 521 *
vcoubard 38:2b762c52e657 522 * @param[in] sys_evt System Event received.
vcoubard 38:2b762c52e657 523 */
vcoubard 38:2b762c52e657 524 void fs_sys_event_handler(uint32_t sys_evt)
vcoubard 38:2b762c52e657 525 {
vcoubard 38:2b762c52e657 526 if (m_flags & FS_FLAG_PROCESSING)
vcoubard 38:2b762c52e657 527 {
vcoubard 38:2b762c52e657 528 /** A flash operation was initiated by this module.
vcoubard 38:2b762c52e657 529 * Handle its result. */
vcoubard 38:2b762c52e657 530 switch (sys_evt)
vcoubard 38:2b762c52e657 531 {
vcoubard 38:2b762c52e657 532 case NRF_EVT_FLASH_OPERATION_SUCCESS:
vcoubard 38:2b762c52e657 533 on_operation_success();
vcoubard 38:2b762c52e657 534 break;
vcoubard 38:2b762c52e657 535
vcoubard 38:2b762c52e657 536 case NRF_EVT_FLASH_OPERATION_ERROR:
vcoubard 38:2b762c52e657 537 on_operation_failure(sys_evt);
vcoubard 38:2b762c52e657 538 break;
vcoubard 38:2b762c52e657 539 }
vcoubard 38:2b762c52e657 540 }
vcoubard 38:2b762c52e657 541 else if ((m_flags & FS_FLAG_FLASH_REQ_PENDING))
vcoubard 38:2b762c52e657 542 {
vcoubard 38:2b762c52e657 543 /** A flash operation was initiated outside this module.
vcoubard 38:2b762c52e657 544 * We have now receveid a callback which indicates it has
vcoubard 38:2b762c52e657 545 * finished. Clear the FS_FLAG_FLASH_REQ_PENDING flag. */
vcoubard 38:2b762c52e657 546 m_flags &= ~FS_FLAG_FLASH_REQ_PENDING;
vcoubard 38:2b762c52e657 547
vcoubard 38:2b762c52e657 548 // Resume processing the queue, if necessary.
vcoubard 38:2b762c52e657 549 queue_process();
vcoubard 38:2b762c52e657 550 }
vcoubard 38:2b762c52e657 551 }
vcoubard 38:2b762c52e657 552
vcoubard 38:2b762c52e657 553
vcoubard 38:2b762c52e657 554 // Just for testing out section vars (across many compilers).
vcoubard 38:2b762c52e657 555 void fs_debug_print()
vcoubard 38:2b762c52e657 556 {
vcoubard 38:2b762c52e657 557 printf("fs start address: 0x%08lx\r\n", (unsigned long)FS_SECTION_VARS_START_ADDR);
vcoubard 38:2b762c52e657 558 printf("fs end address: 0x%08lx\r\n", (unsigned long)FS_SECTION_VARS_END_ADDR);
vcoubard 38:2b762c52e657 559 printf("Num items: 0x%08lx\r\n", (unsigned long)FS_SECTION_VARS_COUNT);
vcoubard 38:2b762c52e657 560 printf("===== ITEMS %lu =====\r\n", (unsigned long)FS_SECTION_VARS_COUNT);
vcoubard 38:2b762c52e657 561
vcoubard 38:2b762c52e657 562 for(int i = 0; i < FS_SECTION_VARS_COUNT; i++)
vcoubard 38:2b762c52e657 563 {
vcoubard 38:2b762c52e657 564 fs_config_t* config = FS_SECTION_VARS_GET(i);
vcoubard 38:2b762c52e657 565 printf( "Address: 0x%08lx, CB: 0x%08lx\r\n",
vcoubard 38:2b762c52e657 566 (unsigned long)config, (unsigned long)config->cb );
vcoubard 38:2b762c52e657 567 }
vcoubard 38:2b762c52e657 568 printf("\r\n");
vcoubard 38:2b762c52e657 569 }