/ 11111

Fork of nRF51822 by Nordic Semiconductor

Committer:
rgrover1
Date:
Thu Jul 02 09:08:44 2015 +0100
Revision:
362:6fa0d4d555f6
Parent:
361:d2405f5a4853
Child:
370:295f76db798e
Synchronized with git rev 2716309c
Author: Rohit Grover
Release 0.4.0
=============

This is a major release which introduces the GATT Client functionality. It
aligns with release 0.4.0 of BLE_API.

Enhancements
~~~~~~~~~~~~

* Introduce GattClient. This includes functionality for service-discovery,
connections, and attribute-reads and writes. You'll find a demo program for
LEDBlinker on the mbed.org Bluetooth team page to use the new APIs. Some of
the GATT client functionality hasn't been implemented yet, but the APIs have
been added.

* We've added an implementation for the abstract base class for
SecurityManager. All security related APIs have been moved into that.

* There has been a major cleanup of APIs under BLE. APIs have now been
categorized as belonging to Gap, GattServer, GattClient, or SecurityManager.
There are accessors to get references for Gap, GattServer, GattClient, and
SecurityManager. A former call to ble.setAddress(...) is now expected to be
achieved with ble.gap().setAddress(...).

* We've cleaned up our APIs, and this has resulted in dropping some APIs like
BLE::reset().

* We've also dropped GattServer::initializeGattDatabase(). THis was added at
some point to support controllers where a commit point was needed to
indicate when the application had finished constructing the GATT database.
This API would get called internally before Gap::startAdvertising(). We now
expect the underlying port to do the equivalent of initializeGattDatabase()
implicitly upon Gap::startAdvertising().

* We've added a version of Gap::disconnect() which takes a connection handle.
The previous API (which did not take a connection handle) has been
deprecated; it will still work for situations where there's only a single
active connection. We hold on to that API to allow existing code to migrate
to the new API.

Bugfixes
~~~~~~~~

* None.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rgrover1 362:6fa0d4d555f6 1 /*
rgrover1 362:6fa0d4d555f6 2 * Copyright (c) Nordic Semiconductor ASA
rgrover1 362:6fa0d4d555f6 3 * All rights reserved.
rgrover1 362:6fa0d4d555f6 4 *
rgrover1 362:6fa0d4d555f6 5 * Redistribution and use in source and binary forms, with or without modification,
rgrover1 362:6fa0d4d555f6 6 * are permitted provided that the following conditions are met:
rgrover1 362:6fa0d4d555f6 7 *
rgrover1 362:6fa0d4d555f6 8 * 1. Redistributions of source code must retain the above copyright notice, this
rgrover1 362:6fa0d4d555f6 9 * list of conditions and the following disclaimer.
rgrover1 362:6fa0d4d555f6 10 *
rgrover1 362:6fa0d4d555f6 11 * 2. Redistributions in binary form must reproduce the above copyright notice, this
rgrover1 362:6fa0d4d555f6 12 * list of conditions and the following disclaimer in the documentation and/or
rgrover1 362:6fa0d4d555f6 13 * other materials provided with the distribution.
rgrover1 362:6fa0d4d555f6 14 *
rgrover1 362:6fa0d4d555f6 15 * 3. Neither the name of Nordic Semiconductor ASA nor the names of other
rgrover1 362:6fa0d4d555f6 16 * contributors to this software may be used to endorse or promote products
rgrover1 362:6fa0d4d555f6 17 * derived from this software without specific prior written permission.
rgrover1 362:6fa0d4d555f6 18 *
rgrover1 362:6fa0d4d555f6 19 *
rgrover1 362:6fa0d4d555f6 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
rgrover1 362:6fa0d4d555f6 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
rgrover1 362:6fa0d4d555f6 22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
rgrover1 362:6fa0d4d555f6 23 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
rgrover1 362:6fa0d4d555f6 24 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
rgrover1 362:6fa0d4d555f6 25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
rgrover1 362:6fa0d4d555f6 26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
rgrover1 362:6fa0d4d555f6 27 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
rgrover1 362:6fa0d4d555f6 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
rgrover1 362:6fa0d4d555f6 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
rgrover1 362:6fa0d4d555f6 30 *
rgrover1 362:6fa0d4d555f6 31 */
rgrover1 362:6fa0d4d555f6 32
rgrover1 362:6fa0d4d555f6 33 #include "pstorage.h"
rgrover1 362:6fa0d4d555f6 34 #include <stdlib.h>
rgrover1 362:6fa0d4d555f6 35 #include <stdint.h>
rgrover1 362:6fa0d4d555f6 36 #include <string.h>
rgrover1 362:6fa0d4d555f6 37 #include "nordic_common.h"
rgrover1 362:6fa0d4d555f6 38 #include "nrf_error.h"
rgrover1 362:6fa0d4d555f6 39 #include "nrf_assert.h"
rgrover1 362:6fa0d4d555f6 40 // #include "nrf.h"
rgrover1 362:6fa0d4d555f6 41 #include "nrf_soc.h"
rgrover1 362:6fa0d4d555f6 42 #include "app_util.h"
rgrover1 362:6fa0d4d555f6 43
rgrover1 362:6fa0d4d555f6 44 #define INVALID_OPCODE 0x00 /**< Invalid op code identifier. */
rgrover1 362:6fa0d4d555f6 45 #define SOC_MAX_WRITE_SIZE 1024 /**< Maximum write size allowed for a single call to \ref sd_flash_write as specified in the SoC API. */
rgrover1 362:6fa0d4d555f6 46 #define RAW_MODE_APP_ID (PSTORAGE_MAX_APPLICATIONS + 1) /**< Application id for raw mode. */
rgrover1 362:6fa0d4d555f6 47
rgrover1 362:6fa0d4d555f6 48 /**
rgrover1 362:6fa0d4d555f6 49 * @defgroup api_param_check API Parameters check macros.
rgrover1 362:6fa0d4d555f6 50 *
rgrover1 362:6fa0d4d555f6 51 * @details Macros that verify parameters passed to the module in the APIs. These macros
rgrover1 362:6fa0d4d555f6 52 * could be mapped to nothing in final versions of code to save execution and size.
rgrover1 362:6fa0d4d555f6 53 *
rgrover1 362:6fa0d4d555f6 54 * @{
rgrover1 362:6fa0d4d555f6 55 */
rgrover1 362:6fa0d4d555f6 56
rgrover1 362:6fa0d4d555f6 57 /**
rgrover1 362:6fa0d4d555f6 58 * @brief Check if the input pointer is NULL, if it is returns NRF_ERROR_NULL.
rgrover1 362:6fa0d4d555f6 59 */
rgrover1 362:6fa0d4d555f6 60 #define NULL_PARAM_CHECK(PARAM) \
rgrover1 362:6fa0d4d555f6 61 if ((PARAM) == NULL) \
rgrover1 362:6fa0d4d555f6 62 { \
rgrover1 362:6fa0d4d555f6 63 return NRF_ERROR_NULL; \
rgrover1 362:6fa0d4d555f6 64 }
rgrover1 362:6fa0d4d555f6 65
rgrover1 362:6fa0d4d555f6 66 /**
rgrover1 362:6fa0d4d555f6 67 * @brief Verifies the module identifier supplied by the application is within permissible
rgrover1 362:6fa0d4d555f6 68 * range.
rgrover1 362:6fa0d4d555f6 69 */
rgrover1 362:6fa0d4d555f6 70 #define MODULE_ID_RANGE_CHECK(ID) \
rgrover1 362:6fa0d4d555f6 71 if ((((ID)->module_id) >= PSTORAGE_MAX_APPLICATIONS) || \
rgrover1 362:6fa0d4d555f6 72 (m_app_table[(ID)->module_id].cb == NULL)) \
rgrover1 362:6fa0d4d555f6 73 { \
rgrover1 362:6fa0d4d555f6 74 return NRF_ERROR_INVALID_PARAM; \
rgrover1 362:6fa0d4d555f6 75 }
rgrover1 362:6fa0d4d555f6 76
rgrover1 362:6fa0d4d555f6 77 /**
rgrover1 362:6fa0d4d555f6 78 * @brief Verifies the block identifier supplied by the application is within the permissible
rgrover1 362:6fa0d4d555f6 79 * range.
rgrover1 362:6fa0d4d555f6 80 */
rgrover1 362:6fa0d4d555f6 81 #define BLOCK_ID_RANGE_CHECK(ID) \
rgrover1 362:6fa0d4d555f6 82 if (((ID)->block_id) >= (m_app_table[(ID)->module_id].base_id + \
rgrover1 362:6fa0d4d555f6 83 (m_app_table[(ID)->module_id].block_count * MODULE_BLOCK_SIZE(ID)))) \
rgrover1 362:6fa0d4d555f6 84 { \
rgrover1 362:6fa0d4d555f6 85 return NRF_ERROR_INVALID_PARAM; \
rgrover1 362:6fa0d4d555f6 86 }
rgrover1 362:6fa0d4d555f6 87
rgrover1 362:6fa0d4d555f6 88 /**
rgrover1 362:6fa0d4d555f6 89 * @brief Verifies the block size requested by the application can be supported by the module.
rgrover1 362:6fa0d4d555f6 90 */
rgrover1 362:6fa0d4d555f6 91 #define BLOCK_SIZE_CHECK(X) \
rgrover1 362:6fa0d4d555f6 92 if (((X) > PSTORAGE_MAX_BLOCK_SIZE) || ((X) < PSTORAGE_MIN_BLOCK_SIZE)) \
rgrover1 362:6fa0d4d555f6 93 { \
rgrover1 362:6fa0d4d555f6 94 return NRF_ERROR_INVALID_PARAM; \
rgrover1 362:6fa0d4d555f6 95 }
rgrover1 362:6fa0d4d555f6 96
rgrover1 362:6fa0d4d555f6 97 /**
rgrover1 362:6fa0d4d555f6 98 * @brief Verifies block size requested by Application in registration API.
rgrover1 362:6fa0d4d555f6 99 */
rgrover1 362:6fa0d4d555f6 100 #define BLOCK_COUNT_CHECK(COUNT, SIZE) \
rgrover1 362:6fa0d4d555f6 101 if (((COUNT) == 0) || \
rgrover1 362:6fa0d4d555f6 102 ((m_next_page_addr + ((COUNT) *(SIZE)) > PSTORAGE_SWAP_ADDR)) || \
rgrover1 362:6fa0d4d555f6 103 ((((COUNT) * (SIZE)) > PSTORAGE_FLASH_PAGE_SIZE) && (PSTORAGE_FLASH_PAGE_SIZE % (SIZE)))) \
rgrover1 362:6fa0d4d555f6 104 { \
rgrover1 362:6fa0d4d555f6 105 return NRF_ERROR_INVALID_PARAM; \
rgrover1 362:6fa0d4d555f6 106 }
rgrover1 362:6fa0d4d555f6 107
rgrover1 362:6fa0d4d555f6 108 /**
rgrover1 362:6fa0d4d555f6 109 * @brief Verifies size parameter provided by application in API.
rgrover1 362:6fa0d4d555f6 110 */
rgrover1 362:6fa0d4d555f6 111 #define SIZE_CHECK(ID, SIZE) \
rgrover1 362:6fa0d4d555f6 112 if(((SIZE) == 0) || ((SIZE) > MODULE_BLOCK_SIZE(ID))) \
rgrover1 362:6fa0d4d555f6 113 { \
rgrover1 362:6fa0d4d555f6 114 return NRF_ERROR_INVALID_PARAM; \
rgrover1 362:6fa0d4d555f6 115 }
rgrover1 362:6fa0d4d555f6 116
rgrover1 362:6fa0d4d555f6 117 /**
rgrover1 362:6fa0d4d555f6 118 * @brief Verifies offset parameter provided by application in API.
rgrover1 362:6fa0d4d555f6 119 */
rgrover1 362:6fa0d4d555f6 120 #define OFFSET_CHECK(ID, OFFSET, SIZE) \
rgrover1 362:6fa0d4d555f6 121 if(((SIZE) + (OFFSET)) > MODULE_BLOCK_SIZE(ID)) \
rgrover1 362:6fa0d4d555f6 122 { \
rgrover1 362:6fa0d4d555f6 123 return NRF_ERROR_INVALID_PARAM; \
rgrover1 362:6fa0d4d555f6 124 }
rgrover1 362:6fa0d4d555f6 125
rgrover1 362:6fa0d4d555f6 126 #ifdef PSTORAGE_RAW_MODE_ENABLE
rgrover1 362:6fa0d4d555f6 127
rgrover1 362:6fa0d4d555f6 128 /**
rgrover1 362:6fa0d4d555f6 129 * @brief Verifies the module identifier supplied by the application is registered for raw mode.
rgrover1 362:6fa0d4d555f6 130 */
rgrover1 362:6fa0d4d555f6 131 #define MODULE_RAW_ID_RANGE_CHECK(ID) \
rgrover1 362:6fa0d4d555f6 132 if ((PSTORAGE_MAX_APPLICATIONS+1 != ((ID)->module_id)) || \
rgrover1 362:6fa0d4d555f6 133 (m_raw_app_table.cb == NULL)) \
rgrover1 362:6fa0d4d555f6 134 { \
rgrover1 362:6fa0d4d555f6 135 return NRF_ERROR_INVALID_PARAM; \
rgrover1 362:6fa0d4d555f6 136 }
rgrover1 362:6fa0d4d555f6 137
rgrover1 362:6fa0d4d555f6 138 #endif // PSTORAGE_RAW_MODE_ENABLE
rgrover1 362:6fa0d4d555f6 139
rgrover1 362:6fa0d4d555f6 140 /**@} */
rgrover1 362:6fa0d4d555f6 141
rgrover1 362:6fa0d4d555f6 142
rgrover1 362:6fa0d4d555f6 143 /**@brief Verify module's initialization status.
rgrover1 362:6fa0d4d555f6 144 *
rgrover1 362:6fa0d4d555f6 145 * @details Verify module's initialization status. Returns NRF_ERROR_INVALID_STATE in case a
rgrover1 362:6fa0d4d555f6 146 * module API is called without initializing the module.
rgrover1 362:6fa0d4d555f6 147 */
rgrover1 362:6fa0d4d555f6 148 #define VERIFY_MODULE_INITIALIZED() \
rgrover1 362:6fa0d4d555f6 149 do \
rgrover1 362:6fa0d4d555f6 150 { \
rgrover1 362:6fa0d4d555f6 151 if (!m_module_initialized) \
rgrover1 362:6fa0d4d555f6 152 { \
rgrover1 362:6fa0d4d555f6 153 return NRF_ERROR_INVALID_STATE; \
rgrover1 362:6fa0d4d555f6 154 } \
rgrover1 362:6fa0d4d555f6 155 } while(0)
rgrover1 362:6fa0d4d555f6 156
rgrover1 362:6fa0d4d555f6 157 /**@brief Macro to fetch the block size registered for the module. */
rgrover1 362:6fa0d4d555f6 158 #define MODULE_BLOCK_SIZE(ID) (m_app_table[(ID)->module_id].block_size)
rgrover1 362:6fa0d4d555f6 159
rgrover1 362:6fa0d4d555f6 160
rgrover1 362:6fa0d4d555f6 161 /** @brief States for the Update/Clear swap backup state machine. */
rgrover1 362:6fa0d4d555f6 162 typedef enum
rgrover1 362:6fa0d4d555f6 163 {
rgrover1 362:6fa0d4d555f6 164 STATE_INIT, /**< State for indicating that swap can be used when using update/clear API. */
rgrover1 362:6fa0d4d555f6 165 STATE_DATA_TO_SWAP_WRITE, /**< State for doing backup of data page into the swap page when using update/clear API. */
rgrover1 362:6fa0d4d555f6 166 STATE_DATA_ERASE, /**< State for erasing data page when using update/clear API. */
rgrover1 362:6fa0d4d555f6 167 STATE_HEAD_RESTORE, /**< State for restoring head (beginning) of backed up data from swap to data page when using update/clear API. */
rgrover1 362:6fa0d4d555f6 168 STATE_TAIL_RESTORE, /**< State for restoring tail (end) of backed up data from swap to data page when using update/clear API. */
rgrover1 362:6fa0d4d555f6 169 STATE_NEW_BODY_WRITE, /**< State for writing body (middle) data to the data page when using update/clear API. */
rgrover1 362:6fa0d4d555f6 170 STATE_SWAP_ERASE, /**< State for erasing the swap page when using the update/clear API. */
rgrover1 362:6fa0d4d555f6 171 STATE_COMPLETE, /**< State for indicating that update/clear sequence is completed internal in the module when using the update/clear API. */
rgrover1 362:6fa0d4d555f6 172 STATE_SWAP_DIRTY /**< State for initializing the swap region on module initialization. */
rgrover1 362:6fa0d4d555f6 173 } swap_backup_state_t;
rgrover1 362:6fa0d4d555f6 174
rgrover1 362:6fa0d4d555f6 175
rgrover1 362:6fa0d4d555f6 176 /**
rgrover1 362:6fa0d4d555f6 177 * @brief Application registration information.
rgrover1 362:6fa0d4d555f6 178 *
rgrover1 362:6fa0d4d555f6 179 * @details Define application specific information that application needs to maintain to be able
rgrover1 362:6fa0d4d555f6 180 * to process requests from each one of them.
rgrover1 362:6fa0d4d555f6 181 */
rgrover1 362:6fa0d4d555f6 182 typedef struct
rgrover1 362:6fa0d4d555f6 183 {
rgrover1 362:6fa0d4d555f6 184 pstorage_ntf_cb_t cb; /**< Callback registered with the module to be notified of result of flash access. */
rgrover1 362:6fa0d4d555f6 185 pstorage_block_t base_id; /**< Base block id assigned to the module. */
rgrover1 362:6fa0d4d555f6 186 pstorage_size_t block_size; /**< Size of block for the module. */
rgrover1 362:6fa0d4d555f6 187 pstorage_size_t block_count; /**< Number of block requested by application. */
rgrover1 362:6fa0d4d555f6 188 pstorage_size_t num_of_pages; /**< Variable to remember how many pages have been allocated for this module. This information is used for clearing of block, so that application does not need to have knowledge of number of pages its using. */
rgrover1 362:6fa0d4d555f6 189 } pstorage_module_table_t;
rgrover1 362:6fa0d4d555f6 190
rgrover1 362:6fa0d4d555f6 191
rgrover1 362:6fa0d4d555f6 192 #ifdef PSTORAGE_RAW_MODE_ENABLE
rgrover1 362:6fa0d4d555f6 193 /**
rgrover1 362:6fa0d4d555f6 194 * @brief Application registration information.
rgrover1 362:6fa0d4d555f6 195 *
rgrover1 362:6fa0d4d555f6 196 * @details Define application specific information that application registered for raw mode.
rgrover1 362:6fa0d4d555f6 197 */
rgrover1 362:6fa0d4d555f6 198 typedef struct
rgrover1 362:6fa0d4d555f6 199 {
rgrover1 362:6fa0d4d555f6 200 pstorage_ntf_cb_t cb; /**< Callback registered with the module to be notified of result of flash access. */
rgrover1 362:6fa0d4d555f6 201 uint16_t num_of_pages; /**< Variable to remember how many pages have been allocated for this module. This information is used for clearing of block, so that application does not need to have knowledge of number of pages its using. */
rgrover1 362:6fa0d4d555f6 202 } pstorage_raw_module_table_t;
rgrover1 362:6fa0d4d555f6 203 #endif // PSTORAGE_RAW_MODE_ENABLE
rgrover1 362:6fa0d4d555f6 204
rgrover1 362:6fa0d4d555f6 205
rgrover1 362:6fa0d4d555f6 206 /**
rgrover1 362:6fa0d4d555f6 207 * @brief Defines command queue element.
rgrover1 362:6fa0d4d555f6 208 *
rgrover1 362:6fa0d4d555f6 209 * @details Defines command queue element. Each element encapsulates needed information to process
rgrover1 362:6fa0d4d555f6 210 * a flash access command.
rgrover1 362:6fa0d4d555f6 211 */
rgrover1 362:6fa0d4d555f6 212 typedef struct
rgrover1 362:6fa0d4d555f6 213 {
rgrover1 362:6fa0d4d555f6 214 uint8_t op_code; /**< Identifies flash access operation being queued. Element is free if op-code is INVALID_OPCODE. */
rgrover1 362:6fa0d4d555f6 215 pstorage_size_t size; /**< Identifies size in bytes requested for the operation. */
rgrover1 362:6fa0d4d555f6 216 pstorage_size_t offset; /**< Offset requested by the application for access operation. */
rgrover1 362:6fa0d4d555f6 217 pstorage_handle_t storage_addr; /**< Address/Identifier for persistent memory. */
rgrover1 362:6fa0d4d555f6 218 uint8_t * p_data_addr; /**< Address/Identifier for data memory. This is assumed to be resident memory. */
rgrover1 362:6fa0d4d555f6 219 } cmd_queue_element_t;
rgrover1 362:6fa0d4d555f6 220
rgrover1 362:6fa0d4d555f6 221
rgrover1 362:6fa0d4d555f6 222 /**
rgrover1 362:6fa0d4d555f6 223 * @brief Defines command queue, an element is free if op_code field is not invalid.
rgrover1 362:6fa0d4d555f6 224 *
rgrover1 362:6fa0d4d555f6 225 * @details Defines commands enqueued for flash access. At any point of time, this queue has one or
rgrover1 362:6fa0d4d555f6 226 * more flash access operation pending if the count field is not zero. When the queue is
rgrover1 362:6fa0d4d555f6 227 * not empty, the rp (read pointer) field points to the flash access command in progress
rgrover1 362:6fa0d4d555f6 228 * or to requested next. The queue implements a simple first in first out algorithm.
rgrover1 362:6fa0d4d555f6 229 * Data addresses are assumed to be resident.
rgrover1 362:6fa0d4d555f6 230 */
rgrover1 362:6fa0d4d555f6 231 typedef struct
rgrover1 362:6fa0d4d555f6 232 {
rgrover1 362:6fa0d4d555f6 233 uint8_t rp; /**< Read pointer, pointing to flash access that is ongoing or to be requested next. */
rgrover1 362:6fa0d4d555f6 234 uint8_t count; /**< Number of elements in the queue. */
rgrover1 362:6fa0d4d555f6 235 bool flash_access; /**< Flag to ensure an flash event received is for an request issued by the module. */
rgrover1 362:6fa0d4d555f6 236 cmd_queue_element_t cmd[PSTORAGE_CMD_QUEUE_SIZE]; /**< Array to maintain flash access operation details. */
rgrover1 362:6fa0d4d555f6 237 } cmd_queue_t;
rgrover1 362:6fa0d4d555f6 238
rgrover1 362:6fa0d4d555f6 239
rgrover1 362:6fa0d4d555f6 240 static cmd_queue_t m_cmd_queue; /**< Flash operation request queue. */
rgrover1 362:6fa0d4d555f6 241 static pstorage_size_t m_next_app_instance; /**< Points to the application module instance that can be allocated next. */
rgrover1 362:6fa0d4d555f6 242 static uint32_t m_next_page_addr; /**< Points to the flash address that can be allocated to a module next, this is needed as blocks of a module can span across flash pages. */
rgrover1 362:6fa0d4d555f6 243 static pstorage_size_t m_round_val; /**< Round value for multiple round operations. For erase operations, the round value will contain current round counter which is identical to number of pages erased. For store operations, the round value contains current round of operation * SOC_MAX_WRITE_SIZE to ensure each store to the SoC Flash API is within the SoC limit. */
rgrover1 362:6fa0d4d555f6 244 static bool m_module_initialized = false; /**< Flag for checking if module has been initialized. */
rgrover1 362:6fa0d4d555f6 245 static swap_backup_state_t m_swap_state; /**< Swap page state. */
rgrover1 362:6fa0d4d555f6 246
rgrover1 362:6fa0d4d555f6 247
rgrover1 362:6fa0d4d555f6 248 static pstorage_module_table_t m_app_table[PSTORAGE_MAX_APPLICATIONS]; /**< Registered application information table. */
rgrover1 362:6fa0d4d555f6 249
rgrover1 362:6fa0d4d555f6 250 #ifdef PSTORAGE_RAW_MODE_ENABLE
rgrover1 362:6fa0d4d555f6 251 static pstorage_raw_module_table_t m_raw_app_table; /**< Registered application information table for raw mode. */
rgrover1 362:6fa0d4d555f6 252 #endif // PSTORAGE_RAW_MODE_ENABLE
rgrover1 362:6fa0d4d555f6 253
rgrover1 362:6fa0d4d555f6 254
rgrover1 362:6fa0d4d555f6 255 /**
rgrover1 362:6fa0d4d555f6 256 * @brief Routine called to actually issue the flash access request to the SoftDevice.
rgrover1 362:6fa0d4d555f6 257 *
rgrover1 362:6fa0d4d555f6 258 * @retval NRF_SUCCESS on success, else an error code indicating reason for failure.
rgrover1 362:6fa0d4d555f6 259 */
rgrover1 362:6fa0d4d555f6 260 static uint32_t cmd_process(void);
rgrover1 362:6fa0d4d555f6 261
rgrover1 362:6fa0d4d555f6 262
rgrover1 362:6fa0d4d555f6 263 /**
rgrover1 362:6fa0d4d555f6 264 * @brief Routine to notify application of any errors.
rgrover1 362:6fa0d4d555f6 265 *
rgrover1 362:6fa0d4d555f6 266 * @param[in] result Result of event being notified.
rgrover1 362:6fa0d4d555f6 267 */
rgrover1 362:6fa0d4d555f6 268 static void app_notify(uint32_t result);
rgrover1 362:6fa0d4d555f6 269
rgrover1 362:6fa0d4d555f6 270
rgrover1 362:6fa0d4d555f6 271 /**
rgrover1 362:6fa0d4d555f6 272 * @defgroup utility_functions Utility internal functions.
rgrover1 362:6fa0d4d555f6 273 * @{
rgrover1 362:6fa0d4d555f6 274 * @details Utility functions needed for interfacing with flash through SoC APIs.
rgrover1 362:6fa0d4d555f6 275 * SoC APIs are non blocking and provide the result of flash access through an event.
rgrover1 362:6fa0d4d555f6 276 *
rgrover1 362:6fa0d4d555f6 277 * @note Only one flash access operation is permitted at a time by SoC. Hence a queue is
rgrover1 362:6fa0d4d555f6 278 * maintained by this module.
rgrover1 362:6fa0d4d555f6 279 */
rgrover1 362:6fa0d4d555f6 280
rgrover1 362:6fa0d4d555f6 281
rgrover1 362:6fa0d4d555f6 282 /**
rgrover1 362:6fa0d4d555f6 283 * @brief Initializes command queue element.
rgrover1 362:6fa0d4d555f6 284 *
rgrover1 362:6fa0d4d555f6 285 * @param[in] index Element index being initialized.
rgrover1 362:6fa0d4d555f6 286 */
rgrover1 362:6fa0d4d555f6 287 static void cmd_queue_element_init(uint32_t index)
rgrover1 362:6fa0d4d555f6 288 {
rgrover1 362:6fa0d4d555f6 289 // Internal function and checks on range of index can be avoided.
rgrover1 362:6fa0d4d555f6 290 m_cmd_queue.cmd[index].op_code = INVALID_OPCODE;
rgrover1 362:6fa0d4d555f6 291 m_cmd_queue.cmd[index].size = 0;
rgrover1 362:6fa0d4d555f6 292 m_cmd_queue.cmd[index].storage_addr.module_id = PSTORAGE_MAX_APPLICATIONS;
rgrover1 362:6fa0d4d555f6 293 m_cmd_queue.cmd[index].storage_addr.block_id = 0;
rgrover1 362:6fa0d4d555f6 294 m_cmd_queue.cmd[index].p_data_addr = NULL;
rgrover1 362:6fa0d4d555f6 295 m_cmd_queue.cmd[index].offset = 0;
rgrover1 362:6fa0d4d555f6 296 }
rgrover1 362:6fa0d4d555f6 297
rgrover1 362:6fa0d4d555f6 298
rgrover1 362:6fa0d4d555f6 299 /**
rgrover1 362:6fa0d4d555f6 300 * @brief Initializes command queue.
rgrover1 362:6fa0d4d555f6 301 */
rgrover1 362:6fa0d4d555f6 302 static void cmd_queue_init(void)
rgrover1 362:6fa0d4d555f6 303 {
rgrover1 362:6fa0d4d555f6 304 uint32_t cmd_index;
rgrover1 362:6fa0d4d555f6 305
rgrover1 362:6fa0d4d555f6 306 m_round_val = 0;
rgrover1 362:6fa0d4d555f6 307 m_swap_state = STATE_INIT;
rgrover1 362:6fa0d4d555f6 308 m_cmd_queue.rp = 0;
rgrover1 362:6fa0d4d555f6 309 m_cmd_queue.count = 0;
rgrover1 362:6fa0d4d555f6 310 m_cmd_queue.flash_access = false;
rgrover1 362:6fa0d4d555f6 311
rgrover1 362:6fa0d4d555f6 312 for (cmd_index = 0; cmd_index < PSTORAGE_CMD_QUEUE_SIZE; cmd_index++)
rgrover1 362:6fa0d4d555f6 313 {
rgrover1 362:6fa0d4d555f6 314 cmd_queue_element_init(cmd_index);
rgrover1 362:6fa0d4d555f6 315 }
rgrover1 362:6fa0d4d555f6 316 }
rgrover1 362:6fa0d4d555f6 317
rgrover1 362:6fa0d4d555f6 318
rgrover1 362:6fa0d4d555f6 319 /**
rgrover1 362:6fa0d4d555f6 320 * @brief Routine to enqueue a flash access operation.
rgrover1 362:6fa0d4d555f6 321 *
rgrover1 362:6fa0d4d555f6 322 * @param[in] opcode Identifies operation requested to be enqueued.
rgrover1 362:6fa0d4d555f6 323 * @param[in] p_storage_addr Identiifes module and flash address on which operation is requested.
rgrover1 362:6fa0d4d555f6 324 * @param[in] p_data_addr Identifies data address for flash access.
rgrover1 362:6fa0d4d555f6 325 * @param[in] size Size in bytes of data requested for the access operation.
rgrover1 362:6fa0d4d555f6 326 * @param[in] offset Offset within the flash memory block at which operation is requested.
rgrover1 362:6fa0d4d555f6 327 *
rgrover1 362:6fa0d4d555f6 328 * @retval NRF_SUCCESS on success, else an error code indicating reason for failure.
rgrover1 362:6fa0d4d555f6 329 *
rgrover1 362:6fa0d4d555f6 330 * @note All paramater check should be performed before requesting in an enqueue.
rgrover1 362:6fa0d4d555f6 331 */
rgrover1 362:6fa0d4d555f6 332 static uint32_t cmd_queue_enqueue(uint8_t opcode,
rgrover1 362:6fa0d4d555f6 333 pstorage_handle_t * p_storage_addr,
rgrover1 362:6fa0d4d555f6 334 uint8_t * p_data_addr,
rgrover1 362:6fa0d4d555f6 335 pstorage_size_t size,
rgrover1 362:6fa0d4d555f6 336 pstorage_size_t offset)
rgrover1 362:6fa0d4d555f6 337 {
rgrover1 362:6fa0d4d555f6 338 uint32_t retval;
rgrover1 362:6fa0d4d555f6 339 uint8_t write_index = 0;
rgrover1 362:6fa0d4d555f6 340
rgrover1 362:6fa0d4d555f6 341 if (m_cmd_queue.count != PSTORAGE_CMD_QUEUE_SIZE)
rgrover1 362:6fa0d4d555f6 342 {
rgrover1 362:6fa0d4d555f6 343 // Enqueue the command if it is queue is not full.
rgrover1 362:6fa0d4d555f6 344 write_index = m_cmd_queue.rp + m_cmd_queue.count;
rgrover1 362:6fa0d4d555f6 345
rgrover1 362:6fa0d4d555f6 346 if (write_index >= PSTORAGE_CMD_QUEUE_SIZE)
rgrover1 362:6fa0d4d555f6 347 {
rgrover1 362:6fa0d4d555f6 348 write_index -= PSTORAGE_CMD_QUEUE_SIZE;
rgrover1 362:6fa0d4d555f6 349 }
rgrover1 362:6fa0d4d555f6 350
rgrover1 362:6fa0d4d555f6 351 m_cmd_queue.cmd[write_index].op_code = opcode;
rgrover1 362:6fa0d4d555f6 352 m_cmd_queue.cmd[write_index].p_data_addr = p_data_addr;
rgrover1 362:6fa0d4d555f6 353 m_cmd_queue.cmd[write_index].storage_addr = (*p_storage_addr);
rgrover1 362:6fa0d4d555f6 354 m_cmd_queue.cmd[write_index].size = size;
rgrover1 362:6fa0d4d555f6 355 m_cmd_queue.cmd[write_index].offset = offset;
rgrover1 362:6fa0d4d555f6 356 retval = NRF_SUCCESS;
rgrover1 362:6fa0d4d555f6 357 if (m_cmd_queue.flash_access == false)
rgrover1 362:6fa0d4d555f6 358 {
rgrover1 362:6fa0d4d555f6 359 retval = cmd_process();
rgrover1 362:6fa0d4d555f6 360 if (retval == NRF_ERROR_BUSY)
rgrover1 362:6fa0d4d555f6 361 {
rgrover1 362:6fa0d4d555f6 362 // In case of busy error code, it is possible to attempt to access flash.
rgrover1 362:6fa0d4d555f6 363 retval = NRF_SUCCESS;
rgrover1 362:6fa0d4d555f6 364 }
rgrover1 362:6fa0d4d555f6 365 }
rgrover1 362:6fa0d4d555f6 366 m_cmd_queue.count++;
rgrover1 362:6fa0d4d555f6 367 }
rgrover1 362:6fa0d4d555f6 368 else
rgrover1 362:6fa0d4d555f6 369 {
rgrover1 362:6fa0d4d555f6 370 retval = NRF_ERROR_NO_MEM;
rgrover1 362:6fa0d4d555f6 371 }
rgrover1 362:6fa0d4d555f6 372
rgrover1 362:6fa0d4d555f6 373 return retval;
rgrover1 362:6fa0d4d555f6 374 }
rgrover1 362:6fa0d4d555f6 375
rgrover1 362:6fa0d4d555f6 376
rgrover1 362:6fa0d4d555f6 377 /**
rgrover1 362:6fa0d4d555f6 378 * @brief Dequeues a command element.
rgrover1 362:6fa0d4d555f6 379 *
rgrover1 362:6fa0d4d555f6 380 * @retval NRF_SUCCESS on success, else an error code indicating reason for failure.
rgrover1 362:6fa0d4d555f6 381 */
rgrover1 362:6fa0d4d555f6 382 static uint32_t cmd_queue_dequeue(void)
rgrover1 362:6fa0d4d555f6 383 {
rgrover1 362:6fa0d4d555f6 384 uint32_t retval;
rgrover1 362:6fa0d4d555f6 385 retval = NRF_SUCCESS;
rgrover1 362:6fa0d4d555f6 386
rgrover1 362:6fa0d4d555f6 387 // If any flash operation is enqueued, schedule.
rgrover1 362:6fa0d4d555f6 388 if (m_cmd_queue.count > 0)
rgrover1 362:6fa0d4d555f6 389 {
rgrover1 362:6fa0d4d555f6 390 retval = cmd_process();
rgrover1 362:6fa0d4d555f6 391 if (retval != NRF_SUCCESS)
rgrover1 362:6fa0d4d555f6 392 {
rgrover1 362:6fa0d4d555f6 393 // Flash could be accessed by modules other than Bond Manager, hence a busy error is
rgrover1 362:6fa0d4d555f6 394 // acceptable, but any other error needs to be indicated to the bond manager.
rgrover1 362:6fa0d4d555f6 395 if (retval == NRF_ERROR_BUSY)
rgrover1 362:6fa0d4d555f6 396 {
rgrover1 362:6fa0d4d555f6 397 // In case of busy error code, it is possible to attempt to access flash.
rgrover1 362:6fa0d4d555f6 398 retval = NRF_SUCCESS;
rgrover1 362:6fa0d4d555f6 399 }
rgrover1 362:6fa0d4d555f6 400 }
rgrover1 362:6fa0d4d555f6 401 }
rgrover1 362:6fa0d4d555f6 402 else
rgrover1 362:6fa0d4d555f6 403 {
rgrover1 362:6fa0d4d555f6 404 // No flash access request pending.
rgrover1 362:6fa0d4d555f6 405 }
rgrover1 362:6fa0d4d555f6 406
rgrover1 362:6fa0d4d555f6 407 return retval;
rgrover1 362:6fa0d4d555f6 408 }
rgrover1 362:6fa0d4d555f6 409
rgrover1 362:6fa0d4d555f6 410
rgrover1 362:6fa0d4d555f6 411 /**
rgrover1 362:6fa0d4d555f6 412 * @brief Routine to notify application of any errors.
rgrover1 362:6fa0d4d555f6 413 *
rgrover1 362:6fa0d4d555f6 414 * @param[in] result Result of event being notified.
rgrover1 362:6fa0d4d555f6 415 */
rgrover1 362:6fa0d4d555f6 416 static void app_notify(uint32_t result)
rgrover1 362:6fa0d4d555f6 417 {
rgrover1 362:6fa0d4d555f6 418 pstorage_ntf_cb_t ntf_cb;
rgrover1 362:6fa0d4d555f6 419 uint8_t op_code = m_cmd_queue.cmd[m_cmd_queue.rp].op_code;
rgrover1 362:6fa0d4d555f6 420
rgrover1 362:6fa0d4d555f6 421 #ifdef PSTORAGE_RAW_MODE_ENABLE
rgrover1 362:6fa0d4d555f6 422 if (m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr.module_id == RAW_MODE_APP_ID)
rgrover1 362:6fa0d4d555f6 423 {
rgrover1 362:6fa0d4d555f6 424 ntf_cb = m_raw_app_table.cb;
rgrover1 362:6fa0d4d555f6 425 }
rgrover1 362:6fa0d4d555f6 426 else
rgrover1 362:6fa0d4d555f6 427 #endif // PSTORAGE_RAW_MODE_ENABLE
rgrover1 362:6fa0d4d555f6 428 {
rgrover1 362:6fa0d4d555f6 429 ntf_cb = m_app_table[m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr.module_id].cb;
rgrover1 362:6fa0d4d555f6 430 }
rgrover1 362:6fa0d4d555f6 431
rgrover1 362:6fa0d4d555f6 432 // Indicate result to client.
rgrover1 362:6fa0d4d555f6 433 // For PSTORAGE_CLEAR_OP_CODE no size is returned as the size field is used only internally
rgrover1 362:6fa0d4d555f6 434 // for clients registering multiple pages.
rgrover1 362:6fa0d4d555f6 435 ntf_cb(&m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr,
rgrover1 362:6fa0d4d555f6 436 op_code,
rgrover1 362:6fa0d4d555f6 437 result,
rgrover1 362:6fa0d4d555f6 438 m_cmd_queue.cmd[m_cmd_queue.rp].p_data_addr,
rgrover1 362:6fa0d4d555f6 439 m_cmd_queue.cmd[m_cmd_queue.rp].size);
rgrover1 362:6fa0d4d555f6 440 }
rgrover1 362:6fa0d4d555f6 441
rgrover1 362:6fa0d4d555f6 442
rgrover1 362:6fa0d4d555f6 443 /**
rgrover1 362:6fa0d4d555f6 444 * @brief Handles Flash Access Result Events declared in pstorage_platform.h.
rgrover1 362:6fa0d4d555f6 445 *
rgrover1 362:6fa0d4d555f6 446 * @param[in] sys_evt System event to be handled.
rgrover1 362:6fa0d4d555f6 447 */
rgrover1 362:6fa0d4d555f6 448 void pstorage_sys_event_handler(uint32_t sys_evt)
rgrover1 362:6fa0d4d555f6 449 {
rgrover1 362:6fa0d4d555f6 450 uint32_t retval = NRF_SUCCESS;
rgrover1 362:6fa0d4d555f6 451
rgrover1 362:6fa0d4d555f6 452 // Its possible the flash access was not initiated by bond manager, hence
rgrover1 362:6fa0d4d555f6 453 // event is processed only if the event triggered was for an operation requested by the
rgrover1 362:6fa0d4d555f6 454 // bond manager.
rgrover1 362:6fa0d4d555f6 455 if (m_cmd_queue.flash_access == true)
rgrover1 362:6fa0d4d555f6 456 {
rgrover1 362:6fa0d4d555f6 457 cmd_queue_element_t * p_cmd;
rgrover1 362:6fa0d4d555f6 458
rgrover1 362:6fa0d4d555f6 459 m_cmd_queue.flash_access = false;
rgrover1 362:6fa0d4d555f6 460
rgrover1 362:6fa0d4d555f6 461 if (m_swap_state == STATE_SWAP_DIRTY)
rgrover1 362:6fa0d4d555f6 462 {
rgrover1 362:6fa0d4d555f6 463 if (sys_evt == NRF_EVT_FLASH_OPERATION_SUCCESS)
rgrover1 362:6fa0d4d555f6 464 {
rgrover1 362:6fa0d4d555f6 465 m_swap_state = STATE_INIT;
rgrover1 362:6fa0d4d555f6 466 }
rgrover1 362:6fa0d4d555f6 467 else
rgrover1 362:6fa0d4d555f6 468 {
rgrover1 362:6fa0d4d555f6 469 // If clearing the swap fails, set the application back to un-initialized, to give
rgrover1 362:6fa0d4d555f6 470 // the application a chance for a retry.
rgrover1 362:6fa0d4d555f6 471 m_module_initialized = false;
rgrover1 362:6fa0d4d555f6 472 }
rgrover1 362:6fa0d4d555f6 473
rgrover1 362:6fa0d4d555f6 474 // Schedule any queued flash access operations.
rgrover1 362:6fa0d4d555f6 475 retval = cmd_queue_dequeue();
rgrover1 362:6fa0d4d555f6 476 if (retval != NRF_SUCCESS)
rgrover1 362:6fa0d4d555f6 477 {
rgrover1 362:6fa0d4d555f6 478 app_notify(retval);
rgrover1 362:6fa0d4d555f6 479 }
rgrover1 362:6fa0d4d555f6 480 return;
rgrover1 362:6fa0d4d555f6 481 }
rgrover1 362:6fa0d4d555f6 482
rgrover1 362:6fa0d4d555f6 483 switch (sys_evt)
rgrover1 362:6fa0d4d555f6 484 {
rgrover1 362:6fa0d4d555f6 485 case NRF_EVT_FLASH_OPERATION_SUCCESS:
rgrover1 362:6fa0d4d555f6 486 {
rgrover1 362:6fa0d4d555f6 487 p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
rgrover1 362:6fa0d4d555f6 488 m_round_val++;
rgrover1 362:6fa0d4d555f6 489
rgrover1 362:6fa0d4d555f6 490 const bool store_finished =
rgrover1 362:6fa0d4d555f6 491 ((p_cmd->op_code == PSTORAGE_STORE_OP_CODE) &&
rgrover1 362:6fa0d4d555f6 492 ((m_round_val * SOC_MAX_WRITE_SIZE) >= p_cmd->size));
rgrover1 362:6fa0d4d555f6 493
rgrover1 362:6fa0d4d555f6 494 const bool update_finished =
rgrover1 362:6fa0d4d555f6 495 ((p_cmd->op_code == PSTORAGE_UPDATE_OP_CODE) &&
rgrover1 362:6fa0d4d555f6 496 (m_swap_state == STATE_COMPLETE));
rgrover1 362:6fa0d4d555f6 497
rgrover1 362:6fa0d4d555f6 498 const bool clear_block_finished =
rgrover1 362:6fa0d4d555f6 499 ((p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) &&
rgrover1 362:6fa0d4d555f6 500 (m_swap_state == STATE_COMPLETE));
rgrover1 362:6fa0d4d555f6 501
rgrover1 362:6fa0d4d555f6 502 const bool clear_all_finished =
rgrover1 362:6fa0d4d555f6 503 ((p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) &&
rgrover1 362:6fa0d4d555f6 504 ((m_round_val * SOC_MAX_WRITE_SIZE) >= p_cmd->size) &&
rgrover1 362:6fa0d4d555f6 505 (m_swap_state == STATE_INIT));
rgrover1 362:6fa0d4d555f6 506
rgrover1 362:6fa0d4d555f6 507 if (update_finished ||
rgrover1 362:6fa0d4d555f6 508 clear_block_finished ||
rgrover1 362:6fa0d4d555f6 509 clear_all_finished ||
rgrover1 362:6fa0d4d555f6 510 store_finished)
rgrover1 362:6fa0d4d555f6 511 {
rgrover1 362:6fa0d4d555f6 512 m_swap_state = STATE_INIT;
rgrover1 362:6fa0d4d555f6 513
rgrover1 362:6fa0d4d555f6 514 app_notify(retval);
rgrover1 362:6fa0d4d555f6 515
rgrover1 362:6fa0d4d555f6 516 // Initialize/free the element as it is now processed.
rgrover1 362:6fa0d4d555f6 517 cmd_queue_element_init(m_cmd_queue.rp);
rgrover1 362:6fa0d4d555f6 518 m_round_val = 0;
rgrover1 362:6fa0d4d555f6 519 m_cmd_queue.count--;
rgrover1 362:6fa0d4d555f6 520 m_cmd_queue.rp++;
rgrover1 362:6fa0d4d555f6 521
rgrover1 362:6fa0d4d555f6 522 if (m_cmd_queue.rp >= PSTORAGE_CMD_QUEUE_SIZE)
rgrover1 362:6fa0d4d555f6 523 {
rgrover1 362:6fa0d4d555f6 524 m_cmd_queue.rp -= PSTORAGE_CMD_QUEUE_SIZE;
rgrover1 362:6fa0d4d555f6 525 }
rgrover1 362:6fa0d4d555f6 526 }
rgrover1 362:6fa0d4d555f6 527 // Schedule any queued flash access operations.
rgrover1 362:6fa0d4d555f6 528 retval = cmd_queue_dequeue();
rgrover1 362:6fa0d4d555f6 529
rgrover1 362:6fa0d4d555f6 530 if (retval != NRF_SUCCESS)
rgrover1 362:6fa0d4d555f6 531 {
rgrover1 362:6fa0d4d555f6 532 app_notify(retval);
rgrover1 362:6fa0d4d555f6 533 }
rgrover1 362:6fa0d4d555f6 534 }
rgrover1 362:6fa0d4d555f6 535 break;
rgrover1 362:6fa0d4d555f6 536
rgrover1 362:6fa0d4d555f6 537 case NRF_EVT_FLASH_OPERATION_ERROR:
rgrover1 362:6fa0d4d555f6 538 app_notify(NRF_ERROR_TIMEOUT);
rgrover1 362:6fa0d4d555f6 539 break;
rgrover1 362:6fa0d4d555f6 540
rgrover1 362:6fa0d4d555f6 541 default:
rgrover1 362:6fa0d4d555f6 542 // No implementation needed.
rgrover1 362:6fa0d4d555f6 543 break;
rgrover1 362:6fa0d4d555f6 544
rgrover1 362:6fa0d4d555f6 545 }
rgrover1 362:6fa0d4d555f6 546 }
rgrover1 362:6fa0d4d555f6 547 }
rgrover1 362:6fa0d4d555f6 548
rgrover1 362:6fa0d4d555f6 549
rgrover1 362:6fa0d4d555f6 550 /** @brief Function for handling flash accesses when using swap.
rgrover1 362:6fa0d4d555f6 551 *
rgrover1 362:6fa0d4d555f6 552 * __________________________________________________________
rgrover1 362:6fa0d4d555f6 553 * | Page |
rgrover1 362:6fa0d4d555f6 554 * |________________________________________________________|
rgrover1 362:6fa0d4d555f6 555 * | head | affected body (to be updated or cleared) | tail |
rgrover1 362:6fa0d4d555f6 556 * |______|__________________________________________|______|
rgrover1 362:6fa0d4d555f6 557 *
rgrover1 362:6fa0d4d555f6 558 * @param[in] p_cmd Queue element being processed.
rgrover1 362:6fa0d4d555f6 559 * @param[in] page_number The affected page number.
rgrover1 362:6fa0d4d555f6 560 * @param[in] head_word_size Size of the head in number of words.
rgrover1 362:6fa0d4d555f6 561 * @param[in] tail_word_size Size of the tail in number of words.
rgrover1 362:6fa0d4d555f6 562 *
rgrover1 362:6fa0d4d555f6 563 * @retval NRF_SUCCESS on success, else an error code indicating reason for failure.
rgrover1 362:6fa0d4d555f6 564 */
rgrover1 362:6fa0d4d555f6 565 static uint32_t swap_state_process(cmd_queue_element_t * p_cmd,
rgrover1 362:6fa0d4d555f6 566 uint32_t page_number,
rgrover1 362:6fa0d4d555f6 567 uint32_t head_word_size,
rgrover1 362:6fa0d4d555f6 568 uint32_t tail_word_size)
rgrover1 362:6fa0d4d555f6 569 {
rgrover1 362:6fa0d4d555f6 570 uint32_t retval = NRF_ERROR_INTERNAL;
rgrover1 362:6fa0d4d555f6 571
rgrover1 362:6fa0d4d555f6 572 // Adjust entry point to state machine if needed. When we update has no head or tail its
rgrover1 362:6fa0d4d555f6 573 // no need for using the swap.
rgrover1 362:6fa0d4d555f6 574 if (m_swap_state == STATE_INIT)
rgrover1 362:6fa0d4d555f6 575 {
rgrover1 362:6fa0d4d555f6 576 if ((head_word_size == 0) && (tail_word_size == 0))
rgrover1 362:6fa0d4d555f6 577 {
rgrover1 362:6fa0d4d555f6 578 // Only skip swap usage if the new data fills a whole flash page.
rgrover1 362:6fa0d4d555f6 579 m_swap_state = STATE_DATA_ERASE;
rgrover1 362:6fa0d4d555f6 580 }
rgrover1 362:6fa0d4d555f6 581 else
rgrover1 362:6fa0d4d555f6 582 {
rgrover1 362:6fa0d4d555f6 583 // Else start backing up application data to swap.
rgrover1 362:6fa0d4d555f6 584 m_swap_state = STATE_DATA_TO_SWAP_WRITE;
rgrover1 362:6fa0d4d555f6 585 }
rgrover1 362:6fa0d4d555f6 586 }
rgrover1 362:6fa0d4d555f6 587
rgrover1 362:6fa0d4d555f6 588 switch (m_swap_state)
rgrover1 362:6fa0d4d555f6 589 {
rgrover1 362:6fa0d4d555f6 590 case STATE_DATA_TO_SWAP_WRITE:
rgrover1 362:6fa0d4d555f6 591 // Backup previous content into swap page.
rgrover1 362:6fa0d4d555f6 592 retval = sd_flash_write((uint32_t *)(PSTORAGE_SWAP_ADDR),
rgrover1 362:6fa0d4d555f6 593 (uint32_t *)(page_number * PSTORAGE_FLASH_PAGE_SIZE),
rgrover1 362:6fa0d4d555f6 594 PSTORAGE_FLASH_PAGE_SIZE / sizeof(uint32_t));
rgrover1 362:6fa0d4d555f6 595 if (retval == NRF_SUCCESS)
rgrover1 362:6fa0d4d555f6 596 {
rgrover1 362:6fa0d4d555f6 597 m_swap_state = STATE_DATA_ERASE;
rgrover1 362:6fa0d4d555f6 598 }
rgrover1 362:6fa0d4d555f6 599 break;
rgrover1 362:6fa0d4d555f6 600
rgrover1 362:6fa0d4d555f6 601 case STATE_DATA_ERASE:
rgrover1 362:6fa0d4d555f6 602 // Clear the application data page.
rgrover1 362:6fa0d4d555f6 603 retval = sd_flash_page_erase(page_number);
rgrover1 362:6fa0d4d555f6 604 if (retval == NRF_SUCCESS)
rgrover1 362:6fa0d4d555f6 605 {
rgrover1 362:6fa0d4d555f6 606 if (head_word_size == 0)
rgrover1 362:6fa0d4d555f6 607 {
rgrover1 362:6fa0d4d555f6 608 if (tail_word_size == 0)
rgrover1 362:6fa0d4d555f6 609 {
rgrover1 362:6fa0d4d555f6 610 if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE)
rgrover1 362:6fa0d4d555f6 611 {
rgrover1 362:6fa0d4d555f6 612 m_swap_state = STATE_COMPLETE;
rgrover1 362:6fa0d4d555f6 613 }
rgrover1 362:6fa0d4d555f6 614 else
rgrover1 362:6fa0d4d555f6 615 {
rgrover1 362:6fa0d4d555f6 616 m_swap_state = STATE_NEW_BODY_WRITE;
rgrover1 362:6fa0d4d555f6 617 }
rgrover1 362:6fa0d4d555f6 618 }
rgrover1 362:6fa0d4d555f6 619 else
rgrover1 362:6fa0d4d555f6 620 {
rgrover1 362:6fa0d4d555f6 621 m_swap_state = STATE_TAIL_RESTORE;
rgrover1 362:6fa0d4d555f6 622 }
rgrover1 362:6fa0d4d555f6 623 }
rgrover1 362:6fa0d4d555f6 624 else
rgrover1 362:6fa0d4d555f6 625 {
rgrover1 362:6fa0d4d555f6 626 m_swap_state = STATE_HEAD_RESTORE;
rgrover1 362:6fa0d4d555f6 627 }
rgrover1 362:6fa0d4d555f6 628 }
rgrover1 362:6fa0d4d555f6 629 break;
rgrover1 362:6fa0d4d555f6 630
rgrover1 362:6fa0d4d555f6 631 case STATE_HEAD_RESTORE:
rgrover1 362:6fa0d4d555f6 632 // Restore head from swap to application data page.
rgrover1 362:6fa0d4d555f6 633 retval = sd_flash_write((uint32_t *)(page_number * PSTORAGE_FLASH_PAGE_SIZE),
rgrover1 362:6fa0d4d555f6 634 (uint32_t *)PSTORAGE_SWAP_ADDR,
rgrover1 362:6fa0d4d555f6 635 head_word_size);
rgrover1 362:6fa0d4d555f6 636 if (retval == NRF_SUCCESS)
rgrover1 362:6fa0d4d555f6 637 {
rgrover1 362:6fa0d4d555f6 638 if (tail_word_size == 0)
rgrover1 362:6fa0d4d555f6 639 {
rgrover1 362:6fa0d4d555f6 640 if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE)
rgrover1 362:6fa0d4d555f6 641 {
rgrover1 362:6fa0d4d555f6 642 m_swap_state = STATE_SWAP_ERASE;
rgrover1 362:6fa0d4d555f6 643 }
rgrover1 362:6fa0d4d555f6 644 else
rgrover1 362:6fa0d4d555f6 645 {
rgrover1 362:6fa0d4d555f6 646 m_swap_state = STATE_NEW_BODY_WRITE;
rgrover1 362:6fa0d4d555f6 647 }
rgrover1 362:6fa0d4d555f6 648 }
rgrover1 362:6fa0d4d555f6 649 else
rgrover1 362:6fa0d4d555f6 650 {
rgrover1 362:6fa0d4d555f6 651 m_swap_state = STATE_TAIL_RESTORE;
rgrover1 362:6fa0d4d555f6 652 }
rgrover1 362:6fa0d4d555f6 653 }
rgrover1 362:6fa0d4d555f6 654 break;
rgrover1 362:6fa0d4d555f6 655
rgrover1 362:6fa0d4d555f6 656 case STATE_TAIL_RESTORE:
rgrover1 362:6fa0d4d555f6 657 // Restore tail from swap to application data page.
rgrover1 362:6fa0d4d555f6 658 retval = sd_flash_write((uint32_t *)((page_number * PSTORAGE_FLASH_PAGE_SIZE) +
rgrover1 362:6fa0d4d555f6 659 (head_word_size * sizeof(uint32_t)) +
rgrover1 362:6fa0d4d555f6 660 p_cmd->size),
rgrover1 362:6fa0d4d555f6 661 (uint32_t *)(PSTORAGE_SWAP_ADDR +
rgrover1 362:6fa0d4d555f6 662 (head_word_size * sizeof(uint32_t)) +
rgrover1 362:6fa0d4d555f6 663 p_cmd->size),
rgrover1 362:6fa0d4d555f6 664 tail_word_size);
rgrover1 362:6fa0d4d555f6 665 if (retval == NRF_SUCCESS)
rgrover1 362:6fa0d4d555f6 666 {
rgrover1 362:6fa0d4d555f6 667 if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE)
rgrover1 362:6fa0d4d555f6 668 {
rgrover1 362:6fa0d4d555f6 669 m_swap_state = STATE_SWAP_ERASE;
rgrover1 362:6fa0d4d555f6 670 }
rgrover1 362:6fa0d4d555f6 671 else
rgrover1 362:6fa0d4d555f6 672 {
rgrover1 362:6fa0d4d555f6 673 m_swap_state = STATE_NEW_BODY_WRITE;
rgrover1 362:6fa0d4d555f6 674 }
rgrover1 362:6fa0d4d555f6 675 }
rgrover1 362:6fa0d4d555f6 676 break;
rgrover1 362:6fa0d4d555f6 677
rgrover1 362:6fa0d4d555f6 678 case STATE_NEW_BODY_WRITE:
rgrover1 362:6fa0d4d555f6 679 // Write new data (body) to application data page.
rgrover1 362:6fa0d4d555f6 680 retval = sd_flash_write((uint32_t *)((page_number * PSTORAGE_FLASH_PAGE_SIZE) +
rgrover1 362:6fa0d4d555f6 681 (head_word_size * sizeof(uint32_t))),
rgrover1 362:6fa0d4d555f6 682 (uint32_t *)p_cmd->p_data_addr,
rgrover1 362:6fa0d4d555f6 683 p_cmd->size / sizeof(uint32_t));
rgrover1 362:6fa0d4d555f6 684 if (retval == NRF_SUCCESS)
rgrover1 362:6fa0d4d555f6 685 {
rgrover1 362:6fa0d4d555f6 686 if ((head_word_size == 0) && (tail_word_size == 0))
rgrover1 362:6fa0d4d555f6 687 {
rgrover1 362:6fa0d4d555f6 688 m_swap_state = STATE_COMPLETE;
rgrover1 362:6fa0d4d555f6 689 }
rgrover1 362:6fa0d4d555f6 690 else
rgrover1 362:6fa0d4d555f6 691 {
rgrover1 362:6fa0d4d555f6 692 m_swap_state = STATE_SWAP_ERASE;
rgrover1 362:6fa0d4d555f6 693 }
rgrover1 362:6fa0d4d555f6 694 }
rgrover1 362:6fa0d4d555f6 695 break;
rgrover1 362:6fa0d4d555f6 696
rgrover1 362:6fa0d4d555f6 697 case STATE_SWAP_ERASE:
rgrover1 362:6fa0d4d555f6 698 // Clear the swap page for subsequent use.
rgrover1 362:6fa0d4d555f6 699 retval = sd_flash_page_erase(PSTORAGE_SWAP_ADDR / PSTORAGE_FLASH_PAGE_SIZE);
rgrover1 362:6fa0d4d555f6 700 if (retval == NRF_SUCCESS)
rgrover1 362:6fa0d4d555f6 701 {
rgrover1 362:6fa0d4d555f6 702 m_swap_state = STATE_COMPLETE;
rgrover1 362:6fa0d4d555f6 703 }
rgrover1 362:6fa0d4d555f6 704 break;
rgrover1 362:6fa0d4d555f6 705
rgrover1 362:6fa0d4d555f6 706 default:
rgrover1 362:6fa0d4d555f6 707 break;
rgrover1 362:6fa0d4d555f6 708 }
rgrover1 362:6fa0d4d555f6 709
rgrover1 362:6fa0d4d555f6 710 return retval;
rgrover1 362:6fa0d4d555f6 711 }
rgrover1 362:6fa0d4d555f6 712
rgrover1 362:6fa0d4d555f6 713
rgrover1 362:6fa0d4d555f6 714 /**
rgrover1 362:6fa0d4d555f6 715 * @brief Routine called to actually issue the flash access request to the SoftDevice.
rgrover1 362:6fa0d4d555f6 716 *
rgrover1 362:6fa0d4d555f6 717 * @retval NRF_SUCCESS on success, else an error code indicating reason for failure.
rgrover1 362:6fa0d4d555f6 718 */
rgrover1 362:6fa0d4d555f6 719 static uint32_t cmd_process(void)
rgrover1 362:6fa0d4d555f6 720 {
rgrover1 362:6fa0d4d555f6 721 uint32_t retval;
rgrover1 362:6fa0d4d555f6 722 uint32_t storage_addr;
rgrover1 362:6fa0d4d555f6 723 cmd_queue_element_t * p_cmd;
rgrover1 362:6fa0d4d555f6 724
rgrover1 362:6fa0d4d555f6 725 retval = NRF_ERROR_FORBIDDEN;
rgrover1 362:6fa0d4d555f6 726
rgrover1 362:6fa0d4d555f6 727 p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
rgrover1 362:6fa0d4d555f6 728
rgrover1 362:6fa0d4d555f6 729 storage_addr = p_cmd->storage_addr.block_id;
rgrover1 362:6fa0d4d555f6 730
rgrover1 362:6fa0d4d555f6 731 switch (p_cmd->op_code)
rgrover1 362:6fa0d4d555f6 732 {
rgrover1 362:6fa0d4d555f6 733 case PSTORAGE_STORE_OP_CODE:
rgrover1 362:6fa0d4d555f6 734 {
rgrover1 362:6fa0d4d555f6 735 uint32_t size;
rgrover1 362:6fa0d4d555f6 736 uint32_t offset;
rgrover1 362:6fa0d4d555f6 737 uint8_t * p_data_addr = p_cmd->p_data_addr;
rgrover1 362:6fa0d4d555f6 738
rgrover1 362:6fa0d4d555f6 739 offset = (m_round_val * SOC_MAX_WRITE_SIZE);
rgrover1 362:6fa0d4d555f6 740 size = p_cmd->size - offset;
rgrover1 362:6fa0d4d555f6 741 p_data_addr += offset;
rgrover1 362:6fa0d4d555f6 742 storage_addr += (p_cmd->offset + offset);
rgrover1 362:6fa0d4d555f6 743
rgrover1 362:6fa0d4d555f6 744 if (size < SOC_MAX_WRITE_SIZE)
rgrover1 362:6fa0d4d555f6 745 {
rgrover1 362:6fa0d4d555f6 746 retval = sd_flash_write(((uint32_t *)storage_addr),
rgrover1 362:6fa0d4d555f6 747 (uint32_t *)p_data_addr,
rgrover1 362:6fa0d4d555f6 748 size / sizeof(uint32_t));
rgrover1 362:6fa0d4d555f6 749 }
rgrover1 362:6fa0d4d555f6 750 else
rgrover1 362:6fa0d4d555f6 751 {
rgrover1 362:6fa0d4d555f6 752 retval = sd_flash_write(((uint32_t *)storage_addr),
rgrover1 362:6fa0d4d555f6 753 (uint32_t *)p_data_addr,
rgrover1 362:6fa0d4d555f6 754 SOC_MAX_WRITE_SIZE / sizeof(uint32_t));
rgrover1 362:6fa0d4d555f6 755 }
rgrover1 362:6fa0d4d555f6 756 }
rgrover1 362:6fa0d4d555f6 757 break;
rgrover1 362:6fa0d4d555f6 758
rgrover1 362:6fa0d4d555f6 759 case PSTORAGE_CLEAR_OP_CODE:
rgrover1 362:6fa0d4d555f6 760 {
rgrover1 362:6fa0d4d555f6 761 // Calculate page number before clearing.
rgrover1 362:6fa0d4d555f6 762 uint32_t page_number;
rgrover1 362:6fa0d4d555f6 763
rgrover1 362:6fa0d4d555f6 764 pstorage_size_t block_size =
rgrover1 362:6fa0d4d555f6 765 m_app_table[p_cmd->storage_addr.module_id].block_size;
rgrover1 362:6fa0d4d555f6 766
rgrover1 362:6fa0d4d555f6 767 pstorage_size_t block_count =
rgrover1 362:6fa0d4d555f6 768 m_app_table[p_cmd->storage_addr.module_id].block_count;
rgrover1 362:6fa0d4d555f6 769
rgrover1 362:6fa0d4d555f6 770 pstorage_block_t base_address =
rgrover1 362:6fa0d4d555f6 771 m_app_table[p_cmd->storage_addr.module_id].base_id;
rgrover1 362:6fa0d4d555f6 772
rgrover1 362:6fa0d4d555f6 773 // If the whole module should be cleared.
rgrover1 362:6fa0d4d555f6 774 if (((base_address == storage_addr) && (block_size * block_count == p_cmd->size)) ||
rgrover1 362:6fa0d4d555f6 775 (p_cmd->storage_addr.module_id == RAW_MODE_APP_ID))
rgrover1 362:6fa0d4d555f6 776 {
rgrover1 362:6fa0d4d555f6 777 page_number = ((storage_addr / PSTORAGE_FLASH_PAGE_SIZE) + m_round_val);
rgrover1 362:6fa0d4d555f6 778
rgrover1 362:6fa0d4d555f6 779 retval = sd_flash_page_erase(page_number);
rgrover1 362:6fa0d4d555f6 780 }
rgrover1 362:6fa0d4d555f6 781 // If one block is to be erased.
rgrover1 362:6fa0d4d555f6 782 else
rgrover1 362:6fa0d4d555f6 783 {
rgrover1 362:6fa0d4d555f6 784 page_number = (storage_addr / PSTORAGE_FLASH_PAGE_SIZE);
rgrover1 362:6fa0d4d555f6 785
rgrover1 362:6fa0d4d555f6 786 uint32_t head_word_size = (
rgrover1 362:6fa0d4d555f6 787 storage_addr -
rgrover1 362:6fa0d4d555f6 788 (page_number * PSTORAGE_FLASH_PAGE_SIZE)
rgrover1 362:6fa0d4d555f6 789 ) / sizeof(uint32_t);
rgrover1 362:6fa0d4d555f6 790
rgrover1 362:6fa0d4d555f6 791 uint32_t tail_word_size = (
rgrover1 362:6fa0d4d555f6 792 ((page_number + 1) * PSTORAGE_FLASH_PAGE_SIZE) -
rgrover1 362:6fa0d4d555f6 793 (storage_addr + p_cmd->size)
rgrover1 362:6fa0d4d555f6 794 ) / sizeof(uint32_t);
rgrover1 362:6fa0d4d555f6 795
rgrover1 362:6fa0d4d555f6 796 retval = swap_state_process(p_cmd,
rgrover1 362:6fa0d4d555f6 797 page_number,
rgrover1 362:6fa0d4d555f6 798 head_word_size,
rgrover1 362:6fa0d4d555f6 799 tail_word_size);
rgrover1 362:6fa0d4d555f6 800 }
rgrover1 362:6fa0d4d555f6 801 }
rgrover1 362:6fa0d4d555f6 802 break;
rgrover1 362:6fa0d4d555f6 803
rgrover1 362:6fa0d4d555f6 804 case PSTORAGE_UPDATE_OP_CODE:
rgrover1 362:6fa0d4d555f6 805 {
rgrover1 362:6fa0d4d555f6 806 uint32_t page_number = (storage_addr / PSTORAGE_FLASH_PAGE_SIZE);
rgrover1 362:6fa0d4d555f6 807
rgrover1 362:6fa0d4d555f6 808 uint32_t head_word_size = (
rgrover1 362:6fa0d4d555f6 809 storage_addr + p_cmd->offset -
rgrover1 362:6fa0d4d555f6 810 (page_number * PSTORAGE_FLASH_PAGE_SIZE)
rgrover1 362:6fa0d4d555f6 811 ) / sizeof(uint32_t);
rgrover1 362:6fa0d4d555f6 812
rgrover1 362:6fa0d4d555f6 813 uint32_t tail_word_size = (
rgrover1 362:6fa0d4d555f6 814 ((page_number + 1) * PSTORAGE_FLASH_PAGE_SIZE) -
rgrover1 362:6fa0d4d555f6 815 (storage_addr + p_cmd->offset + p_cmd->size)
rgrover1 362:6fa0d4d555f6 816 ) / sizeof(uint32_t);
rgrover1 362:6fa0d4d555f6 817
rgrover1 362:6fa0d4d555f6 818 retval = swap_state_process(p_cmd, page_number, head_word_size, tail_word_size);
rgrover1 362:6fa0d4d555f6 819 }
rgrover1 362:6fa0d4d555f6 820 break;
rgrover1 362:6fa0d4d555f6 821
rgrover1 362:6fa0d4d555f6 822 default:
rgrover1 362:6fa0d4d555f6 823 // Should never reach here.
rgrover1 362:6fa0d4d555f6 824 break;
rgrover1 362:6fa0d4d555f6 825 }
rgrover1 362:6fa0d4d555f6 826
rgrover1 362:6fa0d4d555f6 827 if (retval == NRF_SUCCESS)
rgrover1 362:6fa0d4d555f6 828 {
rgrover1 362:6fa0d4d555f6 829 m_cmd_queue.flash_access = true;
rgrover1 362:6fa0d4d555f6 830 }
rgrover1 362:6fa0d4d555f6 831
rgrover1 362:6fa0d4d555f6 832 return retval;
rgrover1 362:6fa0d4d555f6 833 }
rgrover1 362:6fa0d4d555f6 834 /** @} */
rgrover1 362:6fa0d4d555f6 835
rgrover1 362:6fa0d4d555f6 836
rgrover1 362:6fa0d4d555f6 837 uint32_t pstorage_init(void)
rgrover1 362:6fa0d4d555f6 838 {
rgrover1 362:6fa0d4d555f6 839 uint32_t retval;
rgrover1 362:6fa0d4d555f6 840
rgrover1 362:6fa0d4d555f6 841 cmd_queue_init();
rgrover1 362:6fa0d4d555f6 842
rgrover1 362:6fa0d4d555f6 843 m_next_app_instance = 0;
rgrover1 362:6fa0d4d555f6 844 m_next_page_addr = PSTORAGE_DATA_START_ADDR;
rgrover1 362:6fa0d4d555f6 845 m_round_val = 0;
rgrover1 362:6fa0d4d555f6 846
rgrover1 362:6fa0d4d555f6 847 for (uint32_t index = 0; index < PSTORAGE_MAX_APPLICATIONS; index++)
rgrover1 362:6fa0d4d555f6 848 {
rgrover1 362:6fa0d4d555f6 849 m_app_table[index].cb = NULL;
rgrover1 362:6fa0d4d555f6 850 m_app_table[index].block_size = 0;
rgrover1 362:6fa0d4d555f6 851 m_app_table[index].num_of_pages = 0;
rgrover1 362:6fa0d4d555f6 852 m_app_table[index].block_count = 0;
rgrover1 362:6fa0d4d555f6 853 }
rgrover1 362:6fa0d4d555f6 854
rgrover1 362:6fa0d4d555f6 855 #ifdef PSTORAGE_RAW_MODE_ENABLE
rgrover1 362:6fa0d4d555f6 856 m_raw_app_table.cb = NULL;
rgrover1 362:6fa0d4d555f6 857 m_raw_app_table.num_of_pages = 0;
rgrover1 362:6fa0d4d555f6 858 m_module_initialized = true;
rgrover1 362:6fa0d4d555f6 859 m_swap_state = STATE_INIT;
rgrover1 362:6fa0d4d555f6 860
rgrover1 362:6fa0d4d555f6 861 retval = NRF_SUCCESS;
rgrover1 362:6fa0d4d555f6 862 #else
rgrover1 362:6fa0d4d555f6 863 m_swap_state = STATE_SWAP_DIRTY;
rgrover1 362:6fa0d4d555f6 864
rgrover1 362:6fa0d4d555f6 865 // Erase swap region in case it is dirty.
rgrover1 362:6fa0d4d555f6 866 retval = sd_flash_page_erase(PSTORAGE_SWAP_ADDR / PSTORAGE_FLASH_PAGE_SIZE);
rgrover1 362:6fa0d4d555f6 867 if (retval == NRF_SUCCESS)
rgrover1 362:6fa0d4d555f6 868 {
rgrover1 362:6fa0d4d555f6 869 m_cmd_queue.flash_access = true;
rgrover1 362:6fa0d4d555f6 870 m_module_initialized = true;
rgrover1 362:6fa0d4d555f6 871 }
rgrover1 362:6fa0d4d555f6 872 #endif //PSTORAGE_RAW_MODE_ENABLE
rgrover1 362:6fa0d4d555f6 873
rgrover1 362:6fa0d4d555f6 874 return retval;
rgrover1 362:6fa0d4d555f6 875 }
rgrover1 362:6fa0d4d555f6 876
rgrover1 362:6fa0d4d555f6 877
rgrover1 362:6fa0d4d555f6 878 uint32_t pstorage_register(pstorage_module_param_t * p_module_param,
rgrover1 362:6fa0d4d555f6 879 pstorage_handle_t * p_block_id)
rgrover1 362:6fa0d4d555f6 880 {
rgrover1 362:6fa0d4d555f6 881 uint16_t page_count;
rgrover1 362:6fa0d4d555f6 882 uint32_t total_size;
rgrover1 362:6fa0d4d555f6 883
rgrover1 362:6fa0d4d555f6 884 VERIFY_MODULE_INITIALIZED();
rgrover1 362:6fa0d4d555f6 885 NULL_PARAM_CHECK(p_module_param);
rgrover1 362:6fa0d4d555f6 886 NULL_PARAM_CHECK(p_block_id);
rgrover1 362:6fa0d4d555f6 887 NULL_PARAM_CHECK(p_module_param->cb);
rgrover1 362:6fa0d4d555f6 888 BLOCK_SIZE_CHECK(p_module_param->block_size);
rgrover1 362:6fa0d4d555f6 889 BLOCK_COUNT_CHECK(p_module_param->block_count, p_module_param->block_size);
rgrover1 362:6fa0d4d555f6 890
rgrover1 362:6fa0d4d555f6 891 // Block size should be a multiple of word size.
rgrover1 362:6fa0d4d555f6 892 if (!((p_module_param->block_size % sizeof(uint32_t)) == 0))
rgrover1 362:6fa0d4d555f6 893 {
rgrover1 362:6fa0d4d555f6 894 return NRF_ERROR_INVALID_PARAM;
rgrover1 362:6fa0d4d555f6 895 }
rgrover1 362:6fa0d4d555f6 896
rgrover1 362:6fa0d4d555f6 897 if (m_next_app_instance == PSTORAGE_MAX_APPLICATIONS)
rgrover1 362:6fa0d4d555f6 898 {
rgrover1 362:6fa0d4d555f6 899 return NRF_ERROR_NO_MEM;
rgrover1 362:6fa0d4d555f6 900 }
rgrover1 362:6fa0d4d555f6 901
rgrover1 362:6fa0d4d555f6 902 p_block_id->module_id = m_next_app_instance;
rgrover1 362:6fa0d4d555f6 903 p_block_id->block_id = m_next_page_addr;
rgrover1 362:6fa0d4d555f6 904
rgrover1 362:6fa0d4d555f6 905 m_app_table[m_next_app_instance].base_id = p_block_id->block_id;
rgrover1 362:6fa0d4d555f6 906 m_app_table[m_next_app_instance].cb = p_module_param->cb;
rgrover1 362:6fa0d4d555f6 907 m_app_table[m_next_app_instance].block_size = p_module_param->block_size;
rgrover1 362:6fa0d4d555f6 908 m_app_table[m_next_app_instance].block_count = p_module_param->block_count;
rgrover1 362:6fa0d4d555f6 909
rgrover1 362:6fa0d4d555f6 910 // Calculate number of flash pages allocated for the device.
rgrover1 362:6fa0d4d555f6 911 page_count = 0;
rgrover1 362:6fa0d4d555f6 912 total_size = p_module_param->block_size * p_module_param->block_count;
rgrover1 362:6fa0d4d555f6 913 do
rgrover1 362:6fa0d4d555f6 914 {
rgrover1 362:6fa0d4d555f6 915 page_count++;
rgrover1 362:6fa0d4d555f6 916 if (total_size > PSTORAGE_FLASH_PAGE_SIZE)
rgrover1 362:6fa0d4d555f6 917 {
rgrover1 362:6fa0d4d555f6 918 total_size -= PSTORAGE_FLASH_PAGE_SIZE;
rgrover1 362:6fa0d4d555f6 919 }
rgrover1 362:6fa0d4d555f6 920 else
rgrover1 362:6fa0d4d555f6 921 {
rgrover1 362:6fa0d4d555f6 922 total_size = 0;
rgrover1 362:6fa0d4d555f6 923 }
rgrover1 362:6fa0d4d555f6 924 m_next_page_addr += PSTORAGE_FLASH_PAGE_SIZE;
rgrover1 362:6fa0d4d555f6 925 }
rgrover1 362:6fa0d4d555f6 926 while (total_size >= PSTORAGE_FLASH_PAGE_SIZE);
rgrover1 362:6fa0d4d555f6 927
rgrover1 362:6fa0d4d555f6 928 m_app_table[m_next_app_instance].num_of_pages = page_count;
rgrover1 362:6fa0d4d555f6 929 m_next_app_instance++;
rgrover1 362:6fa0d4d555f6 930
rgrover1 362:6fa0d4d555f6 931 return NRF_SUCCESS;
rgrover1 362:6fa0d4d555f6 932 }
rgrover1 362:6fa0d4d555f6 933
rgrover1 362:6fa0d4d555f6 934
rgrover1 362:6fa0d4d555f6 935 uint32_t pstorage_block_identifier_get(pstorage_handle_t * p_base_id,
rgrover1 362:6fa0d4d555f6 936 pstorage_size_t block_num,
rgrover1 362:6fa0d4d555f6 937 pstorage_handle_t * p_block_id)
rgrover1 362:6fa0d4d555f6 938 {
rgrover1 362:6fa0d4d555f6 939 pstorage_handle_t temp_id;
rgrover1 362:6fa0d4d555f6 940
rgrover1 362:6fa0d4d555f6 941 VERIFY_MODULE_INITIALIZED();
rgrover1 362:6fa0d4d555f6 942 NULL_PARAM_CHECK(p_base_id);
rgrover1 362:6fa0d4d555f6 943 NULL_PARAM_CHECK(p_block_id);
rgrover1 362:6fa0d4d555f6 944 MODULE_ID_RANGE_CHECK(p_base_id);
rgrover1 362:6fa0d4d555f6 945
rgrover1 362:6fa0d4d555f6 946 temp_id = (*p_base_id);
rgrover1 362:6fa0d4d555f6 947 temp_id.block_id += (block_num * MODULE_BLOCK_SIZE(p_base_id));
rgrover1 362:6fa0d4d555f6 948
rgrover1 362:6fa0d4d555f6 949 BLOCK_ID_RANGE_CHECK(&temp_id);
rgrover1 362:6fa0d4d555f6 950
rgrover1 362:6fa0d4d555f6 951 (*p_block_id) = temp_id;
rgrover1 362:6fa0d4d555f6 952
rgrover1 362:6fa0d4d555f6 953 return NRF_SUCCESS;
rgrover1 362:6fa0d4d555f6 954 }
rgrover1 362:6fa0d4d555f6 955
rgrover1 362:6fa0d4d555f6 956
rgrover1 362:6fa0d4d555f6 957 uint32_t pstorage_store(pstorage_handle_t * p_dest,
rgrover1 362:6fa0d4d555f6 958 uint8_t * p_src,
rgrover1 362:6fa0d4d555f6 959 pstorage_size_t size,
rgrover1 362:6fa0d4d555f6 960 pstorage_size_t offset)
rgrover1 362:6fa0d4d555f6 961 {
rgrover1 362:6fa0d4d555f6 962 VERIFY_MODULE_INITIALIZED();
rgrover1 362:6fa0d4d555f6 963 NULL_PARAM_CHECK(p_src);
rgrover1 362:6fa0d4d555f6 964 NULL_PARAM_CHECK(p_dest);
rgrover1 362:6fa0d4d555f6 965 MODULE_ID_RANGE_CHECK(p_dest);
rgrover1 362:6fa0d4d555f6 966 BLOCK_ID_RANGE_CHECK(p_dest);
rgrover1 362:6fa0d4d555f6 967 SIZE_CHECK(p_dest, size);
rgrover1 362:6fa0d4d555f6 968 OFFSET_CHECK(p_dest, offset,size);
rgrover1 362:6fa0d4d555f6 969
rgrover1 362:6fa0d4d555f6 970 // Verify word alignment.
rgrover1 362:6fa0d4d555f6 971 if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset)))
rgrover1 362:6fa0d4d555f6 972 {
rgrover1 362:6fa0d4d555f6 973 return NRF_ERROR_INVALID_ADDR;
rgrover1 362:6fa0d4d555f6 974 }
rgrover1 362:6fa0d4d555f6 975
rgrover1 362:6fa0d4d555f6 976 if ((!is_word_aligned((uint32_t *)p_dest->block_id)))
rgrover1 362:6fa0d4d555f6 977 {
rgrover1 362:6fa0d4d555f6 978 return NRF_ERROR_INVALID_ADDR;
rgrover1 362:6fa0d4d555f6 979 }
rgrover1 362:6fa0d4d555f6 980
rgrover1 362:6fa0d4d555f6 981 return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset);
rgrover1 362:6fa0d4d555f6 982 }
rgrover1 362:6fa0d4d555f6 983
rgrover1 362:6fa0d4d555f6 984
rgrover1 362:6fa0d4d555f6 985 uint32_t pstorage_update(pstorage_handle_t * p_dest,
rgrover1 362:6fa0d4d555f6 986 uint8_t * p_src,
rgrover1 362:6fa0d4d555f6 987 pstorage_size_t size,
rgrover1 362:6fa0d4d555f6 988 pstorage_size_t offset)
rgrover1 362:6fa0d4d555f6 989 {
rgrover1 362:6fa0d4d555f6 990 VERIFY_MODULE_INITIALIZED();
rgrover1 362:6fa0d4d555f6 991 NULL_PARAM_CHECK(p_src);
rgrover1 362:6fa0d4d555f6 992 NULL_PARAM_CHECK(p_dest);
rgrover1 362:6fa0d4d555f6 993 MODULE_ID_RANGE_CHECK(p_dest);
rgrover1 362:6fa0d4d555f6 994 BLOCK_ID_RANGE_CHECK(p_dest);
rgrover1 362:6fa0d4d555f6 995 SIZE_CHECK(p_dest, size);
rgrover1 362:6fa0d4d555f6 996 OFFSET_CHECK(p_dest, offset, size);
rgrover1 362:6fa0d4d555f6 997
rgrover1 362:6fa0d4d555f6 998 // Verify word alignment.
rgrover1 362:6fa0d4d555f6 999 if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset)))
rgrover1 362:6fa0d4d555f6 1000 {
rgrover1 362:6fa0d4d555f6 1001 return NRF_ERROR_INVALID_ADDR;
rgrover1 362:6fa0d4d555f6 1002 }
rgrover1 362:6fa0d4d555f6 1003
rgrover1 362:6fa0d4d555f6 1004 if ((!is_word_aligned((uint32_t *)p_dest->block_id)))
rgrover1 362:6fa0d4d555f6 1005 {
rgrover1 362:6fa0d4d555f6 1006 return NRF_ERROR_INVALID_ADDR;
rgrover1 362:6fa0d4d555f6 1007 }
rgrover1 362:6fa0d4d555f6 1008
rgrover1 362:6fa0d4d555f6 1009 return cmd_queue_enqueue(PSTORAGE_UPDATE_OP_CODE, p_dest, p_src, size, offset);
rgrover1 362:6fa0d4d555f6 1010 }
rgrover1 362:6fa0d4d555f6 1011
rgrover1 362:6fa0d4d555f6 1012
rgrover1 362:6fa0d4d555f6 1013 uint32_t pstorage_load(uint8_t * p_dest,
rgrover1 362:6fa0d4d555f6 1014 pstorage_handle_t * p_src,
rgrover1 362:6fa0d4d555f6 1015 pstorage_size_t size,
rgrover1 362:6fa0d4d555f6 1016 pstorage_size_t offset)
rgrover1 362:6fa0d4d555f6 1017 {
rgrover1 362:6fa0d4d555f6 1018 VERIFY_MODULE_INITIALIZED();
rgrover1 362:6fa0d4d555f6 1019 NULL_PARAM_CHECK(p_src);
rgrover1 362:6fa0d4d555f6 1020 NULL_PARAM_CHECK(p_dest);
rgrover1 362:6fa0d4d555f6 1021 MODULE_ID_RANGE_CHECK(p_src);
rgrover1 362:6fa0d4d555f6 1022 BLOCK_ID_RANGE_CHECK(p_src);
rgrover1 362:6fa0d4d555f6 1023 SIZE_CHECK(p_src, size);
rgrover1 362:6fa0d4d555f6 1024 OFFSET_CHECK(p_src, offset, size);
rgrover1 362:6fa0d4d555f6 1025
rgrover1 362:6fa0d4d555f6 1026 // Verify word alignment.
rgrover1 362:6fa0d4d555f6 1027 if ((!is_word_aligned(p_dest)) || (!is_word_aligned((void *)(uint32_t)offset)))
rgrover1 362:6fa0d4d555f6 1028 {
rgrover1 362:6fa0d4d555f6 1029 return NRF_ERROR_INVALID_ADDR;
rgrover1 362:6fa0d4d555f6 1030 }
rgrover1 362:6fa0d4d555f6 1031
rgrover1 362:6fa0d4d555f6 1032 if ((!is_word_aligned((uint32_t *)p_src->block_id)))
rgrover1 362:6fa0d4d555f6 1033 {
rgrover1 362:6fa0d4d555f6 1034 return NRF_ERROR_INVALID_ADDR;
rgrover1 362:6fa0d4d555f6 1035 }
rgrover1 362:6fa0d4d555f6 1036
rgrover1 362:6fa0d4d555f6 1037 memcpy(p_dest, (((uint8_t *)p_src->block_id) + offset), size);
rgrover1 362:6fa0d4d555f6 1038
rgrover1 362:6fa0d4d555f6 1039 m_app_table[p_src->module_id].cb(p_src, PSTORAGE_LOAD_OP_CODE, NRF_SUCCESS, p_dest, size);
rgrover1 362:6fa0d4d555f6 1040
rgrover1 362:6fa0d4d555f6 1041 return NRF_SUCCESS;
rgrover1 362:6fa0d4d555f6 1042 }
rgrover1 362:6fa0d4d555f6 1043
rgrover1 362:6fa0d4d555f6 1044
rgrover1 362:6fa0d4d555f6 1045 uint32_t pstorage_clear(pstorage_handle_t * p_dest, pstorage_size_t size)
rgrover1 362:6fa0d4d555f6 1046 {
rgrover1 362:6fa0d4d555f6 1047 uint32_t retval;
rgrover1 362:6fa0d4d555f6 1048
rgrover1 362:6fa0d4d555f6 1049 VERIFY_MODULE_INITIALIZED();
rgrover1 362:6fa0d4d555f6 1050 NULL_PARAM_CHECK(p_dest);
rgrover1 362:6fa0d4d555f6 1051 MODULE_ID_RANGE_CHECK(p_dest);
rgrover1 362:6fa0d4d555f6 1052 BLOCK_ID_RANGE_CHECK(p_dest);
rgrover1 362:6fa0d4d555f6 1053
rgrover1 362:6fa0d4d555f6 1054 if ((!is_word_aligned((uint32_t *)p_dest->block_id)))
rgrover1 362:6fa0d4d555f6 1055 {
rgrover1 362:6fa0d4d555f6 1056 return NRF_ERROR_INVALID_ADDR;
rgrover1 362:6fa0d4d555f6 1057 }
rgrover1 362:6fa0d4d555f6 1058
rgrover1 362:6fa0d4d555f6 1059 if (
rgrover1 362:6fa0d4d555f6 1060 !(
rgrover1 362:6fa0d4d555f6 1061 ((p_dest->block_id - m_app_table[p_dest->module_id].base_id) %
rgrover1 362:6fa0d4d555f6 1062 m_app_table[p_dest->module_id].block_size) == 0
rgrover1 362:6fa0d4d555f6 1063 )
rgrover1 362:6fa0d4d555f6 1064 )
rgrover1 362:6fa0d4d555f6 1065 {
rgrover1 362:6fa0d4d555f6 1066 return NRF_ERROR_INVALID_PARAM;
rgrover1 362:6fa0d4d555f6 1067 }
rgrover1 362:6fa0d4d555f6 1068
rgrover1 362:6fa0d4d555f6 1069 retval = cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0);
rgrover1 362:6fa0d4d555f6 1070
rgrover1 362:6fa0d4d555f6 1071 return retval;
rgrover1 362:6fa0d4d555f6 1072 }
rgrover1 362:6fa0d4d555f6 1073
rgrover1 362:6fa0d4d555f6 1074
rgrover1 362:6fa0d4d555f6 1075 uint32_t pstorage_access_status_get(uint32_t * p_count)
rgrover1 362:6fa0d4d555f6 1076 {
rgrover1 362:6fa0d4d555f6 1077 VERIFY_MODULE_INITIALIZED();
rgrover1 362:6fa0d4d555f6 1078 NULL_PARAM_CHECK(p_count);
rgrover1 362:6fa0d4d555f6 1079
rgrover1 362:6fa0d4d555f6 1080 (*p_count) = m_cmd_queue.count;
rgrover1 362:6fa0d4d555f6 1081
rgrover1 362:6fa0d4d555f6 1082 return NRF_SUCCESS;
rgrover1 362:6fa0d4d555f6 1083 }
rgrover1 362:6fa0d4d555f6 1084
rgrover1 362:6fa0d4d555f6 1085 #ifdef PSTORAGE_RAW_MODE_ENABLE
rgrover1 362:6fa0d4d555f6 1086
rgrover1 362:6fa0d4d555f6 1087
rgrover1 362:6fa0d4d555f6 1088 uint32_t pstorage_raw_register(pstorage_module_param_t * p_module_param,
rgrover1 362:6fa0d4d555f6 1089 pstorage_handle_t * p_block_id)
rgrover1 362:6fa0d4d555f6 1090 {
rgrover1 362:6fa0d4d555f6 1091 VERIFY_MODULE_INITIALIZED();
rgrover1 362:6fa0d4d555f6 1092 NULL_PARAM_CHECK(p_module_param);
rgrover1 362:6fa0d4d555f6 1093 NULL_PARAM_CHECK(p_block_id);
rgrover1 362:6fa0d4d555f6 1094 NULL_PARAM_CHECK(p_module_param->cb);
rgrover1 362:6fa0d4d555f6 1095
rgrover1 362:6fa0d4d555f6 1096 if (m_raw_app_table.cb != NULL)
rgrover1 362:6fa0d4d555f6 1097 {
rgrover1 362:6fa0d4d555f6 1098 return NRF_ERROR_NO_MEM;
rgrover1 362:6fa0d4d555f6 1099 }
rgrover1 362:6fa0d4d555f6 1100
rgrover1 362:6fa0d4d555f6 1101 p_block_id->module_id = RAW_MODE_APP_ID;
rgrover1 362:6fa0d4d555f6 1102 m_raw_app_table.cb = p_module_param->cb;
rgrover1 362:6fa0d4d555f6 1103
rgrover1 362:6fa0d4d555f6 1104 return NRF_SUCCESS;
rgrover1 362:6fa0d4d555f6 1105 }
rgrover1 362:6fa0d4d555f6 1106
rgrover1 362:6fa0d4d555f6 1107
rgrover1 362:6fa0d4d555f6 1108 uint32_t pstorage_raw_store(pstorage_handle_t * p_dest,
rgrover1 362:6fa0d4d555f6 1109 uint8_t * p_src,
rgrover1 362:6fa0d4d555f6 1110 pstorage_size_t size,
rgrover1 362:6fa0d4d555f6 1111 pstorage_size_t offset)
rgrover1 362:6fa0d4d555f6 1112 {
rgrover1 362:6fa0d4d555f6 1113 VERIFY_MODULE_INITIALIZED();
rgrover1 362:6fa0d4d555f6 1114 NULL_PARAM_CHECK(p_src);
rgrover1 362:6fa0d4d555f6 1115 NULL_PARAM_CHECK(p_dest);
rgrover1 362:6fa0d4d555f6 1116 MODULE_RAW_ID_RANGE_CHECK(p_dest);
rgrover1 362:6fa0d4d555f6 1117
rgrover1 362:6fa0d4d555f6 1118 // Verify word alignment.
rgrover1 362:6fa0d4d555f6 1119 if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset)))
rgrover1 362:6fa0d4d555f6 1120 {
rgrover1 362:6fa0d4d555f6 1121 return NRF_ERROR_INVALID_ADDR;
rgrover1 362:6fa0d4d555f6 1122 }
rgrover1 362:6fa0d4d555f6 1123
rgrover1 362:6fa0d4d555f6 1124 return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset);
rgrover1 362:6fa0d4d555f6 1125 }
rgrover1 362:6fa0d4d555f6 1126
rgrover1 362:6fa0d4d555f6 1127
rgrover1 362:6fa0d4d555f6 1128 uint32_t pstorage_raw_clear(pstorage_handle_t * p_dest, pstorage_size_t size)
rgrover1 362:6fa0d4d555f6 1129 {
rgrover1 362:6fa0d4d555f6 1130 uint32_t retval;
rgrover1 362:6fa0d4d555f6 1131
rgrover1 362:6fa0d4d555f6 1132 VERIFY_MODULE_INITIALIZED();
rgrover1 362:6fa0d4d555f6 1133 NULL_PARAM_CHECK(p_dest);
rgrover1 362:6fa0d4d555f6 1134 MODULE_RAW_ID_RANGE_CHECK(p_dest);
rgrover1 362:6fa0d4d555f6 1135
rgrover1 362:6fa0d4d555f6 1136 retval = cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0);
rgrover1 362:6fa0d4d555f6 1137
rgrover1 362:6fa0d4d555f6 1138 return retval;
rgrover1 362:6fa0d4d555f6 1139 }
rgrover1 362:6fa0d4d555f6 1140
rgrover1 362:6fa0d4d555f6 1141 #endif // PSTORAGE_RAW_MODE_ENABLE