Nordic nrf51 sdk sources. Mirrored from https://github.com/ARMmbed/nrf51-sdk.
Revision 39:7dafb381465b, committed 2016-04-07
- Comitter:
- vcoubard
- Date:
- Thu Apr 07 17:38:13 2016 +0100
- Parent:
- 38:2b762c52e657
- Child:
- 40:5f862d7e2d0a
- Commit message:
- Synchronized with git rev c4ecce56
Author: Andres Amaya Garcia
Fix typo in id_manager.h @note
Changed in this revision
--- a/README.md Thu Apr 07 17:38:12 2016 +0100 +++ b/README.md Thu Apr 07 17:38:13 2016 +0100 @@ -3,7 +3,6 @@ ## Changes made to Nordic files The files are kept the same as much as possible to the Nordic SDK. Modifications are made in order to integrate with mbed. - - ble/common/ble_conn_state.c: Preprocessor tests regarding S110, S120 or S130 macro should be replace by TARGET_MCU_NRF51_XXK_SXXX tests ## Porting new versions of Nordic SDK A list of files currently requierd by mbed is maintained in [script/required_files.txt](https://github.com/ARMmbed/nrf51-sdk/blob/master/script/required_files.txt). [A python script](https://github.com/ARMmbed/nrf51-sdk/blob/master/script/pick_nrf51_files.py) is written to help porting from nordic sdk releases. **required_files.txt** is parsed to find a list of filenames. The script searches for these filenames in the sdk folder, and copy then into the yotta module mirroring the folder structure in the sdk. **extraIncludes** is automatically added to module.json to allow direct inclusion of noridc headers with just the filename.
--- a/source/nordic_sdk/components/ble/common/ble_conn_state.c Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,413 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "ble_conn_state.h" -#include <stdbool.h> -#include <stdint.h> -#include <string.h> -#include "ble.h" -#include "sdk_mapped_flags.h" -#include "app_error.h" - - -#if defined(__CC_ARM) - #pragma push - #pragma anon_unions -#elif defined(__ICCARM__) - #pragma language=extended -#elif defined(__GNUC__) - /* anonymous unions are enabled by default */ -#endif - - -#define BLE_CONN_STATE_N_DEFAULT_FLAGS 5 /**< The number of flags kept for each connection, excluding user flags. */ -#define BLE_CONN_STATE_N_FLAGS (BLE_CONN_STATE_N_DEFAULT_FLAGS + BLE_CONN_STATE_N_USER_FLAGS) /**< The number of flags kept for each connection, including user flags. */ - - -/**@brief Structure containing all the flag collections maintained by the Connection State module. - */ -typedef struct -{ - sdk_mapped_flags_t valid_flags; /**< Flags indicating which connection handles are valid. */ - sdk_mapped_flags_t connected_flags; /**< Flags indicating which connections are connected, since disconnected connection handles will not immediately be invalidated. */ - sdk_mapped_flags_t central_flags; /**< Flags indicating in which connections the local device is the central. */ - sdk_mapped_flags_t encrypted_flags; /**< Flags indicating which connections are encrypted. */ - sdk_mapped_flags_t mitm_protected_flags; /**< Flags indicating which connections have encryption with protection from man-in-the-middle attacks. */ - sdk_mapped_flags_t user_flags[BLE_CONN_STATE_N_USER_FLAGS]; /**< Flags that can be reserved by the user. The flags will be cleared when a connection is invalidated, otherwise, the user is wholly responsible for the flag states. */ -} ble_conn_state_flag_collections_t; - - -/**@brief Structure containing the internal state of the Connection State module. - */ -typedef struct -{ - uint16_t acquired_flags; /**< Bitmap for keeping track of which user flags have been acquired. */ - uint16_t valid_conn_handles[SDK_MAPPED_FLAGS_N_KEYS]; /**< List of connection handles used as keys for the sdk_mapped_flags module. */ - union - { - ble_conn_state_flag_collections_t flags; /**< Flag collections kept by the Connection State module. */ - sdk_mapped_flags_t flag_array[BLE_CONN_STATE_N_FLAGS]; /**< Flag collections as array to allow use of @ref sdk_mapped_flags_bulk_update_by_key() when setting all flags. */ - }; -} ble_conn_state_t; - - -#if defined(__CC_ARM) - #pragma pop -#elif defined(__ICCARM__) - /* leave anonymous unions enabled */ -#elif defined(__GNUC__) - /* anonymous unions are enabled by default */ -#endif - - -static ble_conn_state_t m_bcs = {0}; /**< Instantiation of the internal state. */ - - -/**@brief Function for resetting all internal memory to the values it had at initialization. - */ -void bcs_internal_state_reset(void) -{ - memset( &m_bcs, 0, sizeof(ble_conn_state_t) ); -} - - -/**@brief Function for activating a connection record. - * - * @param p_record The record to activate. - * @param conn_handle The connection handle to copy into the record. - * @param role The role of the connection. - * - * @return whether the record was activated successfully. - */ -static bool record_activate(uint16_t conn_handle) -{ - uint16_t available_index = sdk_mapped_flags_first_key_index_get(~m_bcs.flags.valid_flags); - - if (available_index != SDK_MAPPED_FLAGS_INVALID_INDEX) - { - m_bcs.valid_conn_handles[available_index] = conn_handle; - sdk_mapped_flags_update_by_key(m_bcs.valid_conn_handles, - &m_bcs.flags.connected_flags, - conn_handle, - 1); - sdk_mapped_flags_update_by_key(m_bcs.valid_conn_handles, - &m_bcs.flags.valid_flags, - conn_handle, - 1); - - return true; - } - - return false; -} - - -/**@brief Function for marking a connection record as invalid and resetting the values. - * - * @param p_record The record to invalidate. - */ -static void record_invalidate(uint16_t conn_handle) -{ - sdk_mapped_flags_bulk_update_by_key(m_bcs.valid_conn_handles, - m_bcs.flag_array, - BLE_CONN_STATE_N_FLAGS, - conn_handle, - 0); -} - - -/**@brief Function for marking a connection as disconnected. See @ref BLE_CONN_STATUS_DISCONNECTED. - * - * @param p_record The record of the connection to set as disconnected. - */ -static void record_set_disconnected(uint16_t conn_handle) -{ - sdk_mapped_flags_update_by_key(m_bcs.valid_conn_handles, - &m_bcs.flags.connected_flags, - conn_handle, - 0); -} - - -/**@brief Function for invalidating records with a @ref BLE_CONN_STATUS_DISCONNECTED - * connection status - */ -static void record_purge_disconnected() -{ - sdk_mapped_flags_key_list_t disconnected_list; - - disconnected_list = sdk_mapped_flags_key_list_get( - m_bcs.valid_conn_handles, - (~m_bcs.flags.connected_flags) & (m_bcs.flags.valid_flags)); - - for (int i = 0; i < disconnected_list.len; i++) - { - record_invalidate(disconnected_list.flag_keys[i]); - } -} - - -/**@brief Function for checking if a user flag has been acquired. - * - * @param[in] flag_id Which flag to check. - * - * @return Whether the flag has been acquired. - */ -static bool user_flag_is_acquired(ble_conn_state_user_flag_id_t flag_id) -{ - return ((m_bcs.acquired_flags & (1 << flag_id)) != 0); -} - - -/**@brief Function for marking a user flag as acquired. - * - * @param[in] flag_id Which flag to mark. - */ -static void user_flag_acquire(ble_conn_state_user_flag_id_t flag_id) -{ - m_bcs.acquired_flags |= (1 << flag_id); -} - - -void ble_conn_state_init(void) -{ - bcs_internal_state_reset(); -} - - -void ble_conn_state_on_ble_evt(ble_evt_t * p_ble_evt) -{ - switch (p_ble_evt->header.evt_id) - { - case BLE_GAP_EVT_CONNECTED: - record_purge_disconnected(); - - if ( !record_activate(p_ble_evt->evt.gap_evt.conn_handle) ) - { - // No more records available. Should not happen. - APP_ERROR_HANDLER(NRF_ERROR_NO_MEM); - } - else - { -#if defined(TARGET_MCU_NRF51_16K_S110) || defined(TARGET_MCU_NRF51_32K_S110) - bool is_central = false; -#elif defined(TARGET_MCU_NRF51_16K_S120) || defined(TARGET_MCU_NRF51_32K_S120) - bool is_central = true; -#else - bool is_central = - (p_ble_evt->evt.gap_evt.params.connected.role == BLE_GAP_ROLE_CENTRAL); -#endif - - sdk_mapped_flags_update_by_key(m_bcs.valid_conn_handles, - &m_bcs.flags.central_flags, - p_ble_evt->evt.gap_evt.conn_handle, - is_central); - } - - break; - - case BLE_GAP_EVT_DISCONNECTED: - record_set_disconnected(p_ble_evt->evt.gap_evt.conn_handle); - break; - - case BLE_GAP_EVT_CONN_SEC_UPDATE: - sdk_mapped_flags_update_by_key( - m_bcs.valid_conn_handles, - &m_bcs.flags.encrypted_flags, - p_ble_evt->evt.gap_evt.conn_handle, - (p_ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec.sec_mode.lv > 1)); - sdk_mapped_flags_update_by_key( - m_bcs.valid_conn_handles, - &m_bcs.flags.mitm_protected_flags, - p_ble_evt->evt.gap_evt.conn_handle, - (p_ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec.sec_mode.lv > 2)); - break; - } -} - - -bool ble_conn_state_valid(uint16_t conn_handle) -{ - return sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles, - m_bcs.flags.valid_flags, - conn_handle); -} - - -uint8_t ble_conn_state_role(uint16_t conn_handle) -{ - uint8_t role = BLE_GAP_ROLE_INVALID; - - if ( sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles, m_bcs.flags.valid_flags, conn_handle) ) - { - bool central = sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles, - m_bcs.flags.central_flags, - conn_handle); - - role = central ? BLE_GAP_ROLE_CENTRAL : BLE_GAP_ROLE_PERIPH; - } - - return role; -} - - -ble_conn_state_status_t ble_conn_state_status(uint16_t conn_handle) -{ - ble_conn_state_status_t conn_status = BLE_CONN_STATUS_INVALID; - bool valid = sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles, - m_bcs.flags.valid_flags, - conn_handle); - - if (valid) - { - bool connected = sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles, - m_bcs.flags.connected_flags, - conn_handle); - - conn_status = connected ? BLE_CONN_STATUS_CONNECTED : BLE_CONN_STATUS_DISCONNECTED; - } - - return conn_status; -} - - -bool ble_conn_state_encrypted(uint16_t conn_handle) -{ - return sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles, - m_bcs.flags.encrypted_flags, - conn_handle); -} - - -bool ble_conn_state_mitm_protected(uint16_t conn_handle) -{ - return sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles, - m_bcs.flags.mitm_protected_flags, - conn_handle); -} - - -uint32_t ble_conn_state_n_connections(void) -{ - return sdk_mapped_flags_n_flags_set(m_bcs.flags.connected_flags); -} - - -uint32_t ble_conn_state_n_centrals(void) -{ - return sdk_mapped_flags_n_flags_set((m_bcs.flags.central_flags) & (m_bcs.flags.connected_flags)); -} - - -uint32_t ble_conn_state_n_peripherals(void) -{ - return sdk_mapped_flags_n_flags_set((~m_bcs.flags.central_flags) & (m_bcs.flags.connected_flags)); -} - - -sdk_mapped_flags_key_list_t ble_conn_state_conn_handles(void) -{ - return sdk_mapped_flags_key_list_get(m_bcs.valid_conn_handles, m_bcs.flags.valid_flags); -} - - -sdk_mapped_flags_key_list_t ble_conn_state_central_handles(void) -{ - return sdk_mapped_flags_key_list_get(m_bcs.valid_conn_handles, - (m_bcs.flags.central_flags) & (m_bcs.flags.connected_flags)); -} - - -sdk_mapped_flags_key_list_t ble_conn_state_periph_handles(void) -{ - return sdk_mapped_flags_key_list_get(m_bcs.valid_conn_handles, - (~m_bcs.flags.central_flags) & (m_bcs.flags.connected_flags)); -} - - -ble_conn_state_user_flag_id_t ble_conn_state_user_flag_acquire(void) -{ - for (ble_conn_state_user_flag_id_t i = BLE_CONN_STATE_USER_FLAG0; - i < BLE_CONN_STATE_N_USER_FLAGS; - i++) - { - if ( !user_flag_is_acquired(i) ) - { - user_flag_acquire(i); - return i; - } - } - - return BLE_CONN_STATE_USER_FLAG_INVALID; -} - - -bool ble_conn_state_user_flag_get(uint16_t conn_handle, ble_conn_state_user_flag_id_t flag_id) -{ - if (user_flag_is_acquired(flag_id)) - { - return sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles, - m_bcs.flags.user_flags[flag_id], - conn_handle); - } - else - { - return false; - } -} - - -void ble_conn_state_user_flag_set(uint16_t conn_handle, - ble_conn_state_user_flag_id_t flag_id, - bool value) -{ - if (user_flag_is_acquired(flag_id)) - { - sdk_mapped_flags_update_by_key(m_bcs.valid_conn_handles, - &m_bcs.flags.user_flags[flag_id], - conn_handle, - value); - } -} - - -sdk_mapped_flags_t ble_conn_state_user_flag_collection(ble_conn_state_user_flag_id_t flag_id) -{ - if ( user_flag_is_acquired(flag_id) ) - { - return m_bcs.flags.user_flags[flag_id]; - } - else - { - return 0; - } -}
--- a/source/nordic_sdk/components/ble/peer_manager/id_manager.h Thu Apr 07 17:38:12 2016 +0100 +++ b/source/nordic_sdk/components/ble/peer_manager/id_manager.h Thu Apr 07 17:38:13 2016 +0100 @@ -229,6 +229,38 @@ */ bool im_address_resolve(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk); +/**@brief Function for calculating the ah() hash function described in Bluetooth core specification + * 4.2 section 3.H.2.2.2. + * + * @detail BLE uses a hash function to calculate the first half of a resolvable address + * from the second half of the address and an irk. This function will use the ECB + * periferal to hash these data acording to the Bluetooth core specification. + * + * @note The ECB expect little endian input and output. + * This function expect big endian and will reverse the data as necessary. + * + * @param[in] p_k The key used in the hash function. + * For address resolution this is should be the irk. + * The array must have a length of 16. + * @param[in] p_r The rand used in the hash function. For generating a new address + * this would be a random number. For resolving a resolvable address + * this would be the last half of the address being resolved. + * The array must have a length of 3. + * @param[out] p_local_hash The result of the hash operation. For address resolution this + * will match the first half of the address being resolved if and only + * if the irk used in the hash function is the same one used to generate + * the address. + * The array must have a length of 16. + * + * @note ====IMPORTANT==== + * This is a special modification to the original nRF51 SDK required by the mbed BLE API + * to be able to generate BLE private resolvable addresses. This function is used by + * the BLE API implementation for nRF5xSecurityManager::getAddressFromBondTable() in the + * ble-nrf51822 yotta module. + * ================= + */ +void ah(uint8_t const * p_k, uint8_t const * p_r, uint8_t * p_local_hash); + /** @} */ #endif /* PEER_ID_MANAGER_H__ */ \ No newline at end of file
--- a/source/nordic_sdk/components/ble/peer_manager/peer_data.c Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,165 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - - -#include "peer_data.h" - -#include <stdint.h> -#include <string.h> -#include "peer_manager_types.h" -#include "fds.h" - - - -void peer_data_parts_get(pm_peer_data_const_t const * p_peer_data, fds_record_chunk_t * p_chunks, uint16_t * p_n_chunks) -{ - if (p_n_chunks == NULL) - { - } - else if ((p_peer_data == NULL) || (p_chunks == NULL)) - { - *p_n_chunks = 0; - } - else - { - switch (p_peer_data->data_type) - { - case PM_PEER_DATA_ID_BONDING: - p_chunks[0].p_data = p_peer_data->data.p_bonding_data; - p_chunks[0].length_words = p_peer_data->length_words; - *p_n_chunks = 1; - break; - case PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING: - p_chunks[0].p_data = p_peer_data->data.p_service_changed_pending; - p_chunks[0].length_words = p_peer_data->length_words; - *p_n_chunks = 1; - break; - case PM_PEER_DATA_ID_GATT_LOCAL: - p_chunks[0].p_data = p_peer_data->data.p_local_gatt_db; - p_chunks[0].length_words = PM_N_WORDS(PM_LOCAL_DB_LEN_OVERHEAD_BYTES); - p_chunks[1].p_data = p_peer_data->data.p_local_gatt_db->p_data; - p_chunks[1].length_words = p_peer_data->length_words - p_chunks[0].length_words; - *p_n_chunks = 2; - break; - case PM_PEER_DATA_ID_GATT_REMOTE: - p_chunks[0].p_data = p_peer_data->data.p_remote_gatt_db; - p_chunks[0].length_words = PM_N_WORDS(PM_REMOTE_DB_LEN_OVERHEAD_BYTES); - p_chunks[1].p_data = p_peer_data->data.p_remote_gatt_db->p_data; - p_chunks[1].length_words = p_peer_data->length_words - p_chunks[0].length_words; - *p_n_chunks = 2; - break; - case PM_PEER_DATA_ID_APPLICATION: - p_chunks[0].p_data = p_peer_data->data.p_application_data; - p_chunks[0].length_words = p_peer_data->length_words; - *p_n_chunks = 1; - break; - default: - *p_n_chunks = 0; - break; - } - } -} - - -ret_code_t peer_data_deserialize(pm_peer_data_flash_t const * p_in_data, pm_peer_data_t * p_out_data) -{ - if ((p_in_data == NULL) || (p_out_data == NULL)) - { - return NRF_ERROR_NULL; - } - else - { - if (p_out_data->length_words < p_in_data->length_words) - { - p_out_data->length_words = p_in_data->length_words; - return NRF_ERROR_NO_MEM; - } - p_out_data->length_words = p_in_data->length_words; - p_out_data->data_type = p_in_data->data_type; - - switch (p_in_data->data_type) - { - case PM_PEER_DATA_ID_BONDING: - *p_out_data->data.p_bonding_data = *p_in_data->data.p_bonding_data; - break; - case PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING: - *p_out_data->data.p_service_changed_pending = *p_in_data->data.p_service_changed_pending; - break; - case PM_PEER_DATA_ID_GATT_LOCAL: - if (p_out_data->data.p_local_gatt_db->p_data == NULL) - { - return NRF_ERROR_NULL; - } - if (p_out_data->data.p_local_gatt_db->len < p_in_data->data.p_local_gatt_db->len) - { - p_out_data->data.p_local_gatt_db->len = p_in_data->data.p_local_gatt_db->len; - return NRF_ERROR_NO_MEM; - } - else - { - p_out_data->data.p_local_gatt_db->flags = p_in_data->data.p_local_gatt_db->flags; - p_out_data->data.p_local_gatt_db->len = p_in_data->data.p_local_gatt_db->len; - memcpy(p_out_data->data.p_local_gatt_db->p_data, - p_in_data->data.p_local_gatt_db->p_data, - p_in_data->data.p_local_gatt_db->len); - } - break; - case PM_PEER_DATA_ID_GATT_REMOTE: - if (p_out_data->data.p_remote_gatt_db->p_data == NULL) - { - return NRF_ERROR_NULL; - } - if (p_out_data->data.p_remote_gatt_db->service_count < p_in_data->data.p_remote_gatt_db->service_count) - { - p_out_data->data.p_remote_gatt_db->service_count = p_in_data->data.p_remote_gatt_db->service_count; - return NRF_ERROR_NO_MEM; - } - else - { - p_out_data->data.p_remote_gatt_db->service_count = p_in_data->data.p_remote_gatt_db->service_count; - memcpy(p_out_data->data.p_remote_gatt_db->p_data, - p_in_data->data.p_remote_gatt_db->p_data, - p_in_data->data.p_remote_gatt_db->service_count * sizeof(ble_gatt_db_srv_t)); - } - break; - case PM_PEER_DATA_ID_APPLICATION: - memcpy(p_out_data->data.p_application_data, - p_in_data->data.p_application_data, - p_in_data->length_words * 4); - break; - default: - break; - } - } - return NRF_SUCCESS; -} -
--- a/source/nordic_sdk/components/ble/peer_manager/peer_data.h Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - - -#ifndef PEER_DATA_H__ -#define PEER_DATA_H__ - -#include <stdint.h> -#include "peer_manager_types.h" -#include "fds.h" - - -/** - * @defgroup peer_data Peer Data - * @ingroup peer_manager - * @{ - * @brief An internal module of @ref peer_manager. This module defines the structure of the data - * that is managed by the @ref peer_manager. It also provides functions for parsing the data. - */ - - -/**@brief Function for enumerating the separate (non-contiguous) parts of the peer data. - * - * @param[in] p_peer_data The peer data to enumerate. - * @param[out] p_chunks The resulting chunks. This must be an array of at least 2 elements. - * @param[out] p_n_chunks The number of chunks. If this is 0, something went wrong. - */ -void peer_data_parts_get(pm_peer_data_const_t const * p_peer_data, fds_record_chunk_t * p_chunks, uint16_t * p_n_chunks); - - -/**@brief Function for converting @ref pm_peer_data_flash_t into @ref pm_peer_data_t. - * - * @param[in] p_in_data The source data. - * @param[out] p_out_data The target data structure. - * - * @retval NRF_SUCCESS Successful conversion. - * @retval NRF_ERROR_NULL A parameter was NULL. - * @retval NRF_ERROR_NO_MEM A buffer was not large enough. - */ -ret_code_t peer_data_deserialize(pm_peer_data_flash_t const * p_in_data, pm_peer_data_t * p_out_data); - -/** @} */ - -#endif /* PEER_DATA_H__ */ \ No newline at end of file
--- a/source/nordic_sdk/components/ble/peer_manager/peer_data_storage.c Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,687 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - - -#include "peer_data_storage.h" - -#include <stdint.h> -#include <string.h> -#include "sdk_errors.h" -#include "peer_manager_types.h" -#include "peer_id.h" -#include "peer_data.h" -#include "fds.h" - -#define MAX_REGISTRANTS 6 /**< The number of user that can register with the module. */ - -#define MODULE_INITIALIZED (m_pds.n_registrants > 0) /**< Expression which is true when the module is initialized. */ - -/**@brief Macro for verifying that the module is initialized. It will cause the function to return - * @ref NRF_ERROR_INVALID_STATE if not. - */ -#define VERIFY_MODULE_INITIALIZED() \ -do \ -{ \ - if (!MODULE_INITIALIZED) \ - { \ - return NRF_ERROR_INVALID_STATE; \ - } \ -} while(0) - - -/**@brief Macro for verifying that the module is initialized. It will cause the function to return - * if not. - */ -#define VERIFY_MODULE_INITIALIZED_VOID() \ -do \ -{ \ - if (!MODULE_INITIALIZED) \ - { \ - return; \ - } \ -} while(0) - - -/**@brief Macro for verifying that the param is not NULL. It will cause the function to return - * if not. - * - * @param[in] param The variable to check if is NULL. - */ -#define VERIFY_PARAM_NOT_NULL(param) \ -do \ -{ \ - if (param == NULL) \ - { \ - return NRF_ERROR_NULL; \ - } \ -} while(0) - - -/**@brief Macro for verifying that param is not zero. It will cause the function to return - * if not. - * - * @param[in] param The variable to check if is zero. - */ -#define VERIFY_PARAM_NOT_ZERO(param) \ -do \ -{ \ - if (param == 0) \ - { \ - return NRF_ERROR_NULL; \ - } \ -} while(0) - - -/**@brief Macro for verifying that the peer id is within a valid range - * - * @param[in] id The peer data id to check. - */ -#define VERIFY_PEER_ID_IN_RANGE(id) \ -do \ -{ \ - if ((id >= PM_PEER_ID_N_AVAILABLE_IDS)) \ - { \ - return NRF_ERROR_INVALID_PARAM; \ - } \ -} while (0) - - -/**@brief Macro for verifying that the peer data id is withing a valid range - * - * @param[in] id The peer data id to check. - */ -#define VERIFY_PEER_DATA_ID_IN_RANGE(id) \ -do \ -{ \ - if (!PM_PEER_DATA_ID_IS_VALID(id)) \ - { \ - return NRF_ERROR_INVALID_PARAM; \ - } \ -} while (0) - - -#define PEER_IDS_INITIALIZE() \ -do \ -{ \ - if (!m_pds.peer_ids_initialized) \ - { \ - peer_ids_init(); \ - } \ -} while (0) - - -typedef struct -{ - bool peer_ids_initialized; - pds_evt_handler_t evt_handlers[MAX_REGISTRANTS]; - uint8_t n_registrants; -} pds_t; - -static pds_t m_pds = {.n_registrants = 0}; - -static void internal_state_reset(pds_t * p_pds) -{ - memset(p_pds, 0, sizeof(pds_t)); -} - -/**@brief Function for dispatching outbound events to all registered event handlers. - * - * @param[in] p_event The event to dispatch. - */ -static void pds_evt_send(pds_evt_t * p_event) -{ - for (int i = 0; i < m_pds.n_registrants; i++) - { - m_pds.evt_handlers[i](p_event); - } -} - -/**@brief Function to convert peer id to instance id - * - * @param[in] peer_id Peer id to convert to instance id - * - * @return Value as instance id - */ -static fds_instance_id_t convert_peer_id_to_instance_id(pm_peer_id_t peer_id) -{ - return (fds_instance_id_t)(peer_id + peer_id_to_instance_id); -} - -/**@brief Function to convert peer data id to type id - * - * @param[in] peer_data_id Peer data id to convert to type_id - * - * @return Value as type id - */ -static fds_type_id_t convert_peer_data_id_to_type_id(pm_peer_data_id_t peer_data_id) -{ - return (fds_type_id_t)peer_data_id + (fds_type_id_t)peer_data_id_to_type_id; -} - - -/**@brief Function to convert peer data id to type id - * - * @param[in] peer_data_id Peer data id to convert to type_id - * - * @return Value as type id - */ -static pm_peer_id_t convert_instance_id_to_peer_id(fds_instance_id_t instance_id) -{ - return (pm_peer_id_t)(instance_id + instance_id_to_peer_id); -} - - -/**@brief Function to type id to peer data id - * - * @param[in] type_id Type id to convert to peer data id - * - * @return Value as peer data id - */ -static pm_peer_data_id_t convert_type_id_to_peer_data_id(fds_type_id_t type_id) -{ - return (pm_peer_data_id_t)(type_id + instance_id_to_peer_id); -} - - -static ret_code_t find_fds_item(pm_peer_id_t peer_id, - pm_peer_data_id_t data_id, - fds_record_desc_t * const p_desc) -{ - fds_find_token_t find_tok; - - VERIFY_PEER_ID_IN_RANGE(peer_id); - VERIFY_PEER_DATA_ID_IN_RANGE(data_id); - // pp_record verified outside - - fds_type_id_t type_id = convert_peer_data_id_to_type_id(data_id); - fds_instance_id_t instance_id = convert_peer_id_to_instance_id(peer_id); - - return fds_find(type_id, instance_id, p_desc, &find_tok); -} - - -static void peer_ids_init() -{ - fds_record_t record; - fds_record_desc_t record_desc; - fds_find_token_t find_tok; - fds_type_id_t const type_id = convert_peer_data_id_to_type_id(PM_PEER_DATA_ID_BONDING); - pm_peer_id_t peer_id; - - if (!m_pds.peer_ids_initialized) - { - while(fds_find_by_type(type_id, &record_desc, &find_tok) == NRF_SUCCESS) - { - fds_open(&record_desc, &record); - fds_close(&record_desc); - peer_id = convert_instance_id_to_peer_id(record.header.ic.instance); - peer_id_allocate(peer_id); - } - - m_pds.peer_ids_initialized = true; - } -} - -//uint32_t size_pad_to_mult_of_four(uint32_t unpadded_size) -//{ -// return (unpadded_size + 3) & 3; -//} - -static void fds_evt_handler(ret_code_t result, - fds_cmd_id_t cmd, - fds_record_id_t record_id, - fds_record_key_t record_key - /*fds_record_t const * const p_record*/) -{ - pds_evt_t evt; - switch(cmd) - { - case FDS_CMD_INIT: - - break; - - case FDS_CMD_UPDATE: - case FDS_CMD_WRITE: - evt.peer_id = convert_instance_id_to_peer_id(record_key.instance); - evt.evt_id = (result == NRF_SUCCESS) ? PDS_EVT_STORED : PDS_EVT_ERROR_STORE; - evt.data_id = convert_type_id_to_peer_data_id(record_key.type); - evt.store_token = record_id; - pds_evt_send(&evt); - break; - - case FDS_CMD_CLEAR: - evt.peer_id = convert_instance_id_to_peer_id(record_key.instance); - evt.evt_id = (result == NRF_SUCCESS) ? PDS_EVT_CLEARED : PDS_EVT_ERROR_CLEAR; - evt.data_id = convert_type_id_to_peer_data_id(record_key.type); - evt.store_token = record_id; - pds_evt_send(&evt); - break; - - case FDS_CMD_CLEAR_INST: - { - if ((record_key.type == FDS_TYPE_ID_INVALID) && - (record_key.instance != FDS_TYPE_ID_INVALID)) - { - pm_peer_id_t peer_id = convert_instance_id_to_peer_id(record_key.instance); - - evt.peer_id = peer_id; - evt.data_id = PM_PEER_DATA_ID_INVALID; - if (result == NRF_SUCCESS) - { - evt.evt_id = PDS_EVT_PEER_ID_CLEAR; - peer_id_free(peer_id); - } - else - { - evt.evt_id = PDS_EVT_ERROR_PEER_ID_CLEAR; - } - } - else - { - // TODO: Not supported yet (clear many without clearing peer_id) - } - - pds_evt_send(&evt); - } - break; - - case FDS_CMD_GC: - evt.peer_id = convert_instance_id_to_peer_id(record_key.instance); - evt.evt_id = PDS_EVT_COMPRESSED; - evt.data_id = convert_type_id_to_peer_data_id(record_key.type); - evt.store_token = record_id; - pds_evt_send(&evt); - break; - - default: - - break; - } -} - - -ret_code_t pds_register(pds_evt_handler_t evt_handler) -{ - if (m_pds.n_registrants >= MAX_REGISTRANTS) - { - return NRF_ERROR_NO_MEM; - } - - VERIFY_PARAM_NOT_NULL(evt_handler); - - if (!MODULE_INITIALIZED) - { - ret_code_t retval; - internal_state_reset(&m_pds); - peer_id_init(); - - fds_cb_t cb = fds_evt_handler; - retval = fds_register(cb); - if(retval != NRF_SUCCESS) - { - return retval; - } - - retval = fds_init(); - if(retval != NRF_SUCCESS) - { - return retval; - } - } - - m_pds.evt_handlers[m_pds.n_registrants] = evt_handler; - m_pds.n_registrants += 1; - - return NRF_SUCCESS; - -} - - -ret_code_t pds_peer_data_read_ptr_get(pm_peer_id_t peer_id, - pm_peer_data_id_t data_id, - pm_peer_data_flash_t * p_data, - pm_store_token_t * p_token) -{ - ret_code_t retval; - - fds_record_t record; - fds_record_desc_t record_desc; - - VERIFY_MODULE_INITIALIZED(); - VERIFY_PEER_ID_IN_RANGE(peer_id); - VERIFY_PEER_DATA_ID_IN_RANGE(data_id); - - retval = find_fds_item(peer_id, data_id, &record_desc); - if (retval != NRF_SUCCESS) - { - return retval; - } - - // Shouldn't fail, unless record is cleared. - fds_open(&record_desc, &record); - // No need to keep it open, since we are not reading. - fds_close(&record_desc); - - //NRF_LOG_PRINTF("Found item with peer_id: %d, data_id: %d, Address: %p\r\n", record.p_data); - - if (p_data != NULL) - { - p_data->data_type = data_id; - p_data->length_words = record.header.tl.length_words; - - p_data->data.p_application_data = (uint8_t const*)record.p_data; - } - - if (p_token != NULL) - { - *p_token = (uint32_t)record.header.id; - } - - return retval; -} - - -ret_code_t pds_peer_data_lock(pm_store_token_t store_token) -{ - VERIFY_MODULE_INITIALIZED(); - VERIFY_PARAM_NOT_ZERO(store_token); - - // TODO: Not implemented yet in fds - - return NRF_SUCCESS; -} - - -ret_code_t pds_peer_data_verify(pm_store_token_t store_token) -{ - VERIFY_MODULE_INITIALIZED(); - VERIFY_PARAM_NOT_ZERO(store_token); - - // TODO: Not implemented yet in fds - - return NRF_SUCCESS; -} - - -ret_code_t pds_peer_data_read(pm_peer_id_t peer_id, - pm_peer_data_id_t data_id, - pm_peer_data_t * p_data, - fds_length_t * p_len_words) -{ - VERIFY_PEER_ID_IN_RANGE(peer_id); - VERIFY_PEER_DATA_ID_IN_RANGE(data_id); - VERIFY_PARAM_NOT_NULL(p_len_words); - VERIFY_PARAM_NOT_NULL(p_data); - - ret_code_t err_code; - pm_peer_data_flash_t peer_data_flash; - - err_code = pds_peer_data_read_ptr_get(peer_id, data_id, &peer_data_flash, NULL); - - if (err_code != NRF_SUCCESS) - { - return err_code; - } - - if ((*p_len_words) == 0) - { - (*p_len_words) = peer_data_flash.length_words; - return NRF_SUCCESS; - } - else if ((*p_len_words) < peer_data_flash.length_words) - { - return NRF_ERROR_NO_MEM; - } - - VERIFY_PARAM_NOT_NULL(p_data->data.p_application_data); - - err_code = peer_data_deserialize(&peer_data_flash, p_data); - - return err_code; -} - - -ret_code_t pds_peer_data_write_prepare(pm_peer_data_const_t const * p_peer_data, - pm_prepare_token_t * p_prepare_token) -{ - ret_code_t retval; - - VERIFY_MODULE_INITIALIZED(); - VERIFY_PARAM_NOT_NULL(p_peer_data); - VERIFY_PARAM_NOT_NULL(p_prepare_token); - VERIFY_PEER_DATA_ID_IN_RANGE(p_peer_data->data_type); - - retval = fds_reserve((fds_write_token_t*)p_prepare_token, p_peer_data->length_words); - return retval; -} - - -ret_code_t pds_peer_data_write_prepare_cancel(pm_prepare_token_t prepare_token) -{ - ret_code_t retval; - - VERIFY_MODULE_INITIALIZED(); - VERIFY_PARAM_NOT_ZERO(prepare_token); - - retval = fds_reserve_cancel((fds_write_token_t*)&prepare_token); - return retval; -} - - -ret_code_t pds_peer_data_write_prepared(pm_peer_id_t peer_id, - pm_peer_data_const_t const * p_peer_data, - pm_prepare_token_t prepare_token, - pm_store_token_t * p_store_token) -{ - ret_code_t retval; - fds_record_desc_t record_desc; - fds_record_key_t record_key; - fds_record_chunk_t chunks[2]; - uint16_t n_chunks; - - VERIFY_MODULE_INITIALIZED(); - //VERIFY_PARAM_NOT_ZERO(prepare_token); - VERIFY_PARAM_NOT_NULL(p_peer_data); - VERIFY_PEER_ID_IN_RANGE(peer_id); - VERIFY_PEER_DATA_ID_IN_RANGE(p_peer_data->data_type); - - // Fill in the keys. - record_key.type = convert_peer_data_id_to_type_id(p_peer_data->data_type); - record_key.instance = convert_peer_id_to_instance_id(peer_id); - - // Create chunks. - peer_data_parts_get(p_peer_data, chunks, &n_chunks); - - retval = fds_write_reserved((fds_write_token_t*)&prepare_token, &record_desc, - record_key, n_chunks, chunks); - - if ((retval == NRF_SUCCESS) && (p_store_token != NULL)) - { - fds_record_id_from_desc(&record_desc, (fds_record_id_t*)p_store_token); - } - - return retval; -} - - -ret_code_t pds_peer_data_write(pm_peer_id_t peer_id, - pm_peer_data_const_t const * p_peer_data, - pm_store_token_t * p_store_token) -{ - ret_code_t retval; - fds_record_desc_t record_desc; - fds_record_key_t record_key; - fds_record_chunk_t chunks[2]; - uint16_t n_chunks; - - VERIFY_MODULE_INITIALIZED(); - VERIFY_PEER_ID_IN_RANGE(peer_id); - VERIFY_PEER_DATA_ID_IN_RANGE(p_peer_data->data_type); - - // Fill in the keys. - record_key.type = convert_peer_data_id_to_type_id(p_peer_data->data_type); - record_key.instance = convert_peer_id_to_instance_id(peer_id); - - // Create chunks - peer_data_parts_get(p_peer_data, chunks, &n_chunks); - - // Request write - retval = fds_write(&record_desc, record_key, n_chunks, chunks); - - if ((retval == NRF_SUCCESS) && (p_store_token != NULL)) - { - fds_record_id_from_desc(&record_desc, (fds_record_id_t*)p_store_token); - } - - return retval; -} - - -ret_code_t pds_peer_data_update(pm_peer_id_t peer_id, - pm_peer_data_const_t const * p_peer_data, - pm_store_token_t old_token, - pm_store_token_t * p_store_token) -{ - ret_code_t retval; - fds_record_desc_t record_desc; - fds_record_key_t record_key; - fds_record_chunk_t chunks[2]; - uint16_t n_chunks; - - VERIFY_MODULE_INITIALIZED(); - VERIFY_PEER_DATA_ID_IN_RANGE(p_peer_data->data_type); - VERIFY_PARAM_NOT_NULL(p_peer_data); - - record_key.type = convert_peer_data_id_to_type_id(p_peer_data->data_type); - record_key.instance = convert_peer_id_to_instance_id(peer_id); - - // Create chunks - peer_data_parts_get(p_peer_data, chunks, &n_chunks); - - fds_descriptor_from_rec_id(&record_desc, (fds_record_id_t)old_token); - - retval = fds_update(&record_desc, record_key, n_chunks, chunks); - - if ((retval == NRF_SUCCESS) && (p_store_token != NULL)) - { - fds_record_id_from_desc(&record_desc, (fds_record_id_t*)p_store_token); - } - - return retval; -} - -ret_code_t pds_peer_data_clear(pm_peer_id_t peer_id, pm_peer_data_id_t data_id) -{ - ret_code_t retval; - fds_type_id_t type_id; - fds_instance_id_t instance_id; - fds_record_desc_t record_desc; - fds_find_token_t find_tok; - - VERIFY_MODULE_INITIALIZED(); - VERIFY_PEER_ID_IN_RANGE(peer_id); - VERIFY_PEER_DATA_ID_IN_RANGE(data_id); - - type_id = convert_peer_data_id_to_type_id(data_id); - instance_id = convert_peer_id_to_instance_id(peer_id); - - retval = fds_find(type_id, instance_id, &record_desc, &find_tok); - if(retval != NRF_SUCCESS) - { - return retval; - } - - retval = fds_clear(&record_desc); - return retval; -} - - -pm_peer_id_t pds_peer_id_allocate(void) -{ - if (!MODULE_INITIALIZED) - { - return PM_PEER_ID_INVALID; - } - PEER_IDS_INITIALIZE(); - return peer_id_allocate(PM_PEER_ID_INVALID); -} - - -ret_code_t pds_peer_id_free(pm_peer_id_t peer_id) -{ - ret_code_t retval; - fds_instance_id_t instance_id; - - VERIFY_MODULE_INITIALIZED(); - VERIFY_PEER_ID_IN_RANGE(peer_id); - PEER_IDS_INITIALIZE(); - - instance_id = convert_peer_id_to_instance_id(peer_id); - - retval = fds_clear_by_instance(instance_id); - return retval; -} - - -bool pds_peer_id_is_allocated(pm_peer_id_t peer_id) -{ - if (!MODULE_INITIALIZED) - { - return false; - } - PEER_IDS_INITIALIZE(); - - return peer_id_is_allocated(peer_id); -} - - -pm_peer_id_t pds_next_peer_id_get(pm_peer_id_t prev_peer_id) -{ - if (!MODULE_INITIALIZED) - { - return PM_PEER_ID_INVALID; - } - PEER_IDS_INITIALIZE(); - - return peer_id_next_id_get(prev_peer_id); -} - - -uint32_t pds_n_peers(void) -{ - if (!MODULE_INITIALIZED) - { - return 0; - } - PEER_IDS_INITIALIZE(); - return peer_id_n_ids(); -}
--- a/source/nordic_sdk/components/ble/peer_manager/peer_data_storage.h Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,370 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - - -#ifndef PEER_DATA_STORAGE_H__ -#define PEER_DATA_STORAGE_H__ - - -#include "stdint.h" -#include "sdk_errors.h" -#include "ble_gap.h" -#include "peer_manager_types.h" -#include "fds.h" - - -/** - * @defgroup peer_data_storage Peer Data Storage - * @ingroup peer_manager - * @{ - * @brief An internal module of @ref peer_manager. This module provides a Peer Manager-specific API - * to the persistent storage. - */ - -#define PDS_PREPARE_TOKEN_INVALID 0 -#define PDS_STORE_TOKEN_INVALID 0 - - -typedef enum -{ - peer_id_to_instance_id = 16384, - instance_id_to_peer_id = -peer_id_to_instance_id, - peer_data_id_to_type_id = 32768, - type_id_to_peer_data_id = -peer_data_id_to_type_id, -} pds_convert_t; - - -/**@brief The types of events that can come from the peer_data_storage module. - */ -typedef enum -{ - PDS_EVT_STORED, /**< The specified data has been successfully stored. */ - PDS_EVT_CLEARED, /**< The specified data has been successfully cleared. */ - PDS_EVT_PEER_ID_CLEAR, /**< The peer id has been successfully cleared. */ - PDS_EVT_ERROR_STORE, /**< The specified data could not be stored. */ - PDS_EVT_ERROR_CLEAR, /**< The specified data could not be cleared. */ - PDS_EVT_ERROR_PEER_ID_CLEAR, /**< The peer id has been successfully cleared. */ - PDS_EVT_COMPRESSED, /**< A compress procedure has finished successfully. */ -} pds_evt_id_t; - - -/**@brief Events that can come from the peer_data_storage module. - */ -typedef struct -{ - pds_evt_id_t evt_id; /**< The type of event. */ - pm_peer_id_t peer_id; /**< The peer the event pertains to. */ - pm_peer_data_id_t data_id; /**< The data the event pertains to. */ - pm_store_token_t store_token; -} pds_evt_t; - - -/**@brief Event handler for events from the peer_data_storage module. - * - * @param[in] event The event that has happened. - * @param[in] peer_id The id of the peer the event pertains to. - * @param[in] flags The data the event pertains to. - */ -typedef void (*pds_evt_handler_t)(pds_evt_t const * p_event); - - -/**@brief Function for registering for events from the peer database. - * - * @note This function will initialize the module if it is not already initialized. - * - * @param[in] evt_handler Event handler to register. - * - * @retval NRF_SUCCESS Registration successful. - * @retval NRF_ERROR_NO_MEM No more event handlers can be registered. - * @retval NRF_ERROR_NULL evt_handler was NULL. - * @retval NRF_ERROR_INVALID_PARAM Unexpected return code from @ref pm_buffer_init. - * @retval NRF_ERROR_INVALID_STATE FDS has not been initalized. - */ -ret_code_t pds_register(pds_evt_handler_t evt_handler); - - -#if 0 -/**@brief Function for initializing Peer Data storage and registering a - * callback for its events. - * - * @param[in] evt_handler Event handler to register. - * - * @retval NRF_SUCCESS Registration successful. - * @retval NRF_ERROR_NO_MEM No more event handlers can be registered. - * @retval NRF_ERROR_NULL evt_handler was NULL. - * @retval NRF_ERROR_INVALID_STATE FDS has not completed initialization. - */ -ret_code_t pds_init(pds_evt_handler_t evt_handler); -#endif - -/**@brief Function for retrieving a direct pointer to peer data in persistent storage. - * - * @param[in] peer_id The id of the peer whose data to read. - * @param[in] data_id Which data to get. - * @param[out] p_data The peer data pointer. - * @param[out] p_token Token that can be used to lock data in flash and check data validity. - * - * @retval NRF_SUCCESS The pointer was successfully retrieved. - * @retval NRF_ERROR_INVALID_PARAM Invalid data_id. - * @retval NRF_ERROR_NULL p_data was NULL. - * @retval NRF_ERROR_NOT_FOUND The requested data was not found in persistent storage. - * @retval NRF_ERROR_INVALID_STATE Module is not initialized. - */ -ret_code_t pds_peer_data_read_ptr_get(pm_peer_id_t peer_id, - pm_peer_data_id_t data_id, - pm_peer_data_flash_t * p_data, - pm_store_token_t * p_token); - -/**@brief Function to lock the flash data (to defer compression from invalidating data) - * - * @param[in] store_token The token representing the item to lock - * - */ -ret_code_t pds_peer_data_lock(pm_store_token_t store_token); - - -/**@brief Function to verify flash data integrity - * - * @param[in] store_token The token representing the item to lock - * - * @retval NRF_SUCCESS The data integrity is valid. - * @retval NRF_ERROR_NULL The token is invalid. - * @retval NRF_ERROR_INVALID_DATA The data integrity is not valid. - * @retval NRF_ERROR_INVALID_STATE Module is not initialized. - */ -ret_code_t pds_peer_data_verify(pm_store_token_t store_token); - - -/**@brief Function for retrieving peer data from persistent storage by making a copy - * - * @param[in] peer_id The id of the peer whose data to read. - * @param[in] data_id Which piece of data to read. - * @param[out] p_data Pointer to the peer data. - * @param[in,out] p_len_words Length available to copy to (in words). - * If set to NULL, then no copy will be made and the - * length will be reflected in p_len_words after the call returns. - * - * @retval NRF_SUCCESS The read was successful. - * @retval NRF_ERROR_INVALID_PARAM Invalid data_id. - * @retval NRF_ERROR_NULL data contained a NULL pointer. - * @retval NRF_ERROR_NOT_FOUND The requested data was not found in persistent storage. - * @retval NRF_ERROR_NO_MEM The length of stored data too large to copy out - * @retval NRF_ERROR_INVALID_STATE Module is not initialized. - */ -ret_code_t pds_peer_data_read(pm_peer_id_t peer_id, - pm_peer_data_id_t data_id, - pm_peer_data_t * p_data, - fds_length_t * p_len_words); - - -/**@brief Function for preparing persistent storage for a write. - * - * @details If this call succeeds, space is reserved in persistent storage, so the write will fit. - * - * @note If space has already been prepared for this peer_id/data_id pair, no new space will be - * reserved, unless the previous reservation had too small size. - * - * @param[in] p_peer_data Data to prepare for. The data needs not be ready, but length and type - * values must. - * @param[out] p_prepare_token A token identifying the prepared memory area. - * - * @retval NRF_SUCCESS The call was successful. - * @retval NRF_ERROR_INVALID_PARAM Invalid data ID. - * @retval NRF_ERROR_INVALID_LENGTH Data length above the maximum allowed. - * @retval NRF_ERROR_NO_MEM No space available in persistent storage. - * @retval NRF_ERROR_INVALID_STATE Module is not initialized. - */ -ret_code_t pds_peer_data_write_prepare(pm_peer_data_const_t const * p_peer_data, - pm_prepare_token_t * p_prepare_token); - - -/**@brief Function for undoing a previous call to @ref pds_peer_data_write_prepare. - * - * @param[in] prepare_token A token identifying the prepared memory area to cancel. - * - * @retval NRF_SUCCESS The call was successful. - * @retval NRF_ERROR_NOT_FOUND Invalid peer ID and/or prepare token. - * @retval NRF_ERROR_INVALID_STATE Module is not initialized. - */ -ret_code_t pds_peer_data_write_prepare_cancel(pm_prepare_token_t prepare_token); - - -/**@brief Function for writing prepared (reserved) peer data to persistent storage. - * - * @details Writing happens asynchronously. Expect a @ref PDS_EVT_STORED or @ref PDS_EVT_ERROR_STORE - * event. - * - * @param[in] peer_id The id of the peer the data pertains to. - * @param[in] p_peer_data The peer data. - * @param[in] prepare_token A token identifying the prepared memory area to write into. If - * the prepare token is invalid, e.g. PDS_PREPARE_TOKEN_INVALID, the - * prepare/write sequence will happen atomically. - * @param[out] p_store_token A token identifying this particular store operation. The token can be - * used to identify events pertaining to this operation. - * - * @retval NRF_SUCCESS The write was initiated successfully. - * @retval NRF_ERROR_INVALID_PARAM Invalid data ID or store_flags. - * @retval NRF_ERROR_INVALID_LENGTH Length of data longer than in prepare call. - * @retval NRF_ERROR_NULL data contained a NULL pointer. - * @retval NRF_ERROR_NO_MEM No space available in persistent storage. This can only happen - * if p_prepare_token is NULL. - * @retval NRF_ERROR_BUSY FDS or underlying modules are busy and can't take any - * more requests - * @retval NRF_ERROR_INVALID_STATE Module is not initialized. - */ -ret_code_t pds_peer_data_write_prepared(pm_peer_id_t peer_id, - pm_peer_data_const_t const * p_peer_data, - pm_prepare_token_t prepare_token, - pm_store_token_t * p_store_token); - - -/**@brief Function for writing peer data to persistent storage. - * - * @details Writing happens asynchronously. Expect a @ref PDS_EVT_STORED or @ref PDS_EVT_ERROR_STORE - * event. - * - * @param[in] peer_id The id of the peer the data pertains to. - * @param[in] p_peer_data The peer data. - * @param[out] p_store_token A token identifying this particular store operation. The token can be - * used to identify events pertaining to this operation. - * - * @retval NRF_SUCCESS The write was initiated successfully. - * @retval NRF_ERROR_INVALID_PARAM Invalid data ID or store_flags. - * @retval NRF_ERROR_NULL Data contained a NULL pointer. - * @retval NRF_ERROR_NO_MEM No space available in persistent storage. This can only happen - * if p_prepare_token is NULL. - * @retval NRF_ERROR_BUSY FDS or underlying modules are busy and can't take any - * more requests - * @retval NRF_ERROR_INVALID_STATE Module is not initialized. - */ -ret_code_t pds_peer_data_write(pm_peer_id_t peer_id, - pm_peer_data_const_t const * p_peer_data, - pm_store_token_t * p_store_token); - - -/**@brief Function for updating currently stored peer data to a new version - * - * @details Updating happens asynchronously. - * Expect a @ref PDS_EVT_STORED or @ref PDS_EVT_ERROR_STORE for the store token - * and a @ref PDS_EVT_ERROR_CLEAR or @ref PDS_EVT_ERROR_CLEAR for the old token - * - * @param[in] peer_id The peer which the data is associated to. - * @param[in] peer_data New data. - * @param[in] old_token Store token for the old data. - * @param[out] p_store_token Store token for the new data. - * - * @retval NRF_SUCESS The update was initiated successfully - * @retval NRF_ERROR_NOT_FOUND The old store token was invalid. - * @retval NRF_ERROR_NULL Data contained a NULL pointer. - * @retval NRF_ERROR_NO_MEM No space available in persistent storage. - * @retval NRF_ERROR_BUSY FDS or underlying modules are busy and can't take any - * more requests - * @retval NRF_ERROR_INVALID_STATE Module is not initialized. - */ -ret_code_t pds_peer_data_update(pm_peer_id_t peer_id, - pm_peer_data_const_t const * peer_data, - pm_store_token_t old_token, - pm_store_token_t * p_store_token); - - -/**@brief Function for clearing peer data from persistent storage. - * - * @details Clearing happens asynchronously. Expect a @ref PDS_EVT_CLEARED or @ref PDS_EVT_ERROR_CLEAR - * event. - * - * @param[in] peer_id The id of the peer the data pertains to. - * @param[in] data_id Which data to clear. - * - * @retval NRF_SUCCESS The clear was initiated successfully. - * @retval NRF_ERROR_INVALID_PARAM Data ID or was invalid. - * @retval NRF_ERROR_NOT_FOUND Nothing to clear for this peer ID. - * @retval NRF_ERROR_INVALID_STATE Module is not initialized. - */ -ret_code_t pds_peer_data_clear(pm_peer_id_t peer_id, pm_peer_data_id_t data_id); - - -/**@brief Function for claiming an unused peer ID. - * - * @return The first unused peer ID. - * @retval PM_PEER_ID_INVALID If no peer ID is available or module is not initialized. - */ -pm_peer_id_t pds_peer_id_allocate(void); - - -/**@brief Function for freeing a peer ID and clearing all data associated with it in persistent - * storage. - * - * @param[in] peer_id Peer ID to free. - * - * @retval NRF_SUCCESS The clear was initiated successfully - * @retval NRF_ERROR_BUSY Another peer_id clear was already requested or fds queue full - */ -ret_code_t pds_peer_id_free(pm_peer_id_t peer_id); - - -/**@brief Function for finding out whether a peer ID is in use. - * - * @param[in] peer_id The peer ID to inquire about. - * - * @retval true peer_id is in use. - * @retval false peer_id is free, or the module is not initialized. - */ -bool pds_peer_id_is_allocated(pm_peer_id_t peer_id); - - -/**@brief Function for getting the next peer ID in the sequence of all used peer IDs. Can be - * used to loop through all used peer IDs. - * - * @note @ref PM_PEER_ID_INVALID is considered to be before the first and after the last ordinary - * peer ID. - * - * @param[in] prev_peer_id The previous peer ID. - * - * @return The next peer ID. - * @return The first ordinary peer ID if prev_peer_id was @ref PM_PEER_ID_INVALID. - * @retval PM_PEER_ID_INVALID if prev_peer_id was the last ordinary peer ID or the module - * is not initialized. - */ -pm_peer_id_t pds_next_peer_id_get(pm_peer_id_t prev_peer_id); - - -/**@brief Function for querying the number of valid peer IDs available. I.E the number of peers - * in persistent storage. - * - * @return The number of valid peer IDs, or 0 if module is not initialized. - */ -uint32_t pds_n_peers(void); - - -/** @} */ - -#endif /* PEER_DATA_STORAGE_H__ */ \ No newline at end of file
--- a/source/nordic_sdk/components/ble/peer_manager/peer_database.c Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,767 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - - -#include "peer_database.h" - -#include <string.h> -#include "peer_manager_types.h" -#include "peer_data_storage.h" -#include "pm_buffer.h" - - -#define MAX_REGISTRANTS 6 /**< The number of user that can register with the module. */ - -#define MODULE_INITIALIZED (m_pdb.n_registrants > 0) /**< Expression which is true when the module is initialized. */ - -#define N_WRITE_BUFFERS 8 /**< The number of write buffers available. */ -#define N_WRITE_BUFFER_RECORDS (N_WRITE_BUFFERS) /**< The number of write buffer records. */ - -/**@brief Macro for verifying that the module is initialized. It will cause the function to return - * @ref NRF_ERROR_INVALID_STATE if not. - */ -#define VERIFY_MODULE_INITIALIZED() \ -do \ -{ \ - if (!MODULE_INITIALIZED) \ - { \ - return NRF_ERROR_INVALID_STATE; \ - } \ -} while(0) - - -/**@brief Macro for verifying that the module is initialized. It will cause the function to return - * if not. - */ -#define VERIFY_MODULE_INITIALIZED_VOID()\ -do \ -{ \ - if (!MODULE_INITIALIZED) \ - { \ - return; \ - } \ -} while(0) - - -/**@brief Macro for verifying that the module is initialized. It will cause the function to return - * if not. - * - * @param[in] param The variable to check if is NULL. - */ -#define VERIFY_PARAM_NOT_NULL(param) \ -do \ -{ \ - if (param == NULL) \ - { \ - return NRF_ERROR_NULL; \ - } \ -} while(0) - - -typedef struct -{ - pm_peer_id_t peer_id; - pm_peer_data_id_t data_id; - uint8_t buffer_block_id; - uint8_t store_busy : 1; - uint8_t store_flash_full : 1; - uint8_t store_requested : 1; - uint32_t n_bufs; - pm_prepare_token_t prepare_token; - pm_store_token_t store_token; -} pdb_buffer_record_t; - -typedef struct -{ - pdb_evt_handler_t evt_handlers[MAX_REGISTRANTS]; - uint8_t n_registrants; - pm_buffer_t write_buffer; - pdb_buffer_record_t write_buffer_records[N_WRITE_BUFFER_RECORDS]; - uint32_t n_writes; -} pdb_t; - -static pdb_t m_pdb = {.n_registrants = 0}; - - -/**@brief Function for invalidating a record of a write buffer allocation. - * - * @param[in] p_record The record to invalidate. - */ -static void write_buffer_record_invalidate(pdb_buffer_record_t * p_record) -{ - p_record->peer_id = PM_PEER_ID_INVALID; - p_record->data_id = PM_PEER_DATA_ID_INVALID; - p_record->buffer_block_id = BUFFER_INVALID_ID; - p_record->store_busy = false; - p_record->store_flash_full = false; - p_record->store_requested = false; - p_record->n_bufs = 0; - p_record->prepare_token = PDS_PREPARE_TOKEN_INVALID; - p_record->store_token = PDS_STORE_TOKEN_INVALID; -} - - -/**@brief Function for finding a record of a write buffer allocation. - * - * @param[in] peer_id The peer ID in the record. - * @param[in] data_id The data ID in the record. - * - * @return A pointer to the matching record, or NULL if none was found. - */ -static pdb_buffer_record_t * write_buffer_record_find(pm_peer_id_t peer_id, - pm_peer_data_id_t data_id) -{ - for (int i = 0; i < N_WRITE_BUFFER_RECORDS; i++) - { - if ((m_pdb.write_buffer_records[i].peer_id == peer_id) - && (m_pdb.write_buffer_records[i].data_id == data_id)) - { - return &m_pdb.write_buffer_records[i]; - } - } - return NULL; -} - - -/**@brief Function for finding an available record for write buffer allocation. - * - * @return A pointer to the available record, or NULL if none was found. - */ -static pdb_buffer_record_t * write_buffer_record_find_unused(void) -{ - return write_buffer_record_find(PM_PEER_ID_INVALID, PM_PEER_DATA_ID_INVALID); -} - - -/**@brief Function for gracefully deactivating a write buffer record. - * - * @details This function will first release any buffers, then invalidate the record. - * - * @param[inout] p_write_buffer_record The record to release. - * - * @return A pointer to the matching record, or NULL if none was found. - */ -static void write_buffer_record_release(pdb_buffer_record_t * p_write_buffer_record) -{ - for (int i = 0; i < p_write_buffer_record->n_bufs; i++) - { - pm_buffer_release(&m_pdb.write_buffer, p_write_buffer_record->buffer_block_id + i); - } - - write_buffer_record_invalidate(p_write_buffer_record); -} - - -static void write_buffer_record_get(pdb_buffer_record_t ** pp_write_buffer_record, pm_peer_id_t peer_id, pm_peer_data_id_t data_id) -{ - if (pp_write_buffer_record == NULL) - { - return; - } - *pp_write_buffer_record = write_buffer_record_find_unused(); - if (*pp_write_buffer_record == NULL) - { - // This also means the buffer is full. - return; - } - (*pp_write_buffer_record)->peer_id = peer_id; - (*pp_write_buffer_record)->data_id = data_id; -} - - -/**@brief Function for dispatching outbound events to all registered event handlers. - * - * @param[in] p_event The event to dispatch. - */ -static void pdb_evt_send(pdb_evt_t * p_event) -{ - for (int i = 0; i < m_pdb.n_registrants; i++) - { - m_pdb.evt_handlers[i](p_event); - } -} - - -/**@brief Function for resetting the internal state of the Peer Database module. - * - * @param[out] p_event The event to dispatch. - */ -static void internal_state_reset(pdb_t * pdb) -{ - memset(pdb, 0, sizeof(pdb_t)); - for (int i = 0; i < N_WRITE_BUFFER_RECORDS; i++) - { - write_buffer_record_invalidate(&pdb->write_buffer_records[i]); - } -} - - -/**@brief Function for handling events from the Peer Data Storage module. - * - * @param[in] p_event The event to handle. - */ -static void pds_evt_handler(pds_evt_t const * p_event) -{ - ret_code_t err_code; - pdb_buffer_record_t * p_write_buffer_record; - bool retry_flash_full = false; - pdb_evt_t event = - { - .peer_id = p_event->peer_id, - .data_id = p_event->data_id, - }; - - p_write_buffer_record = write_buffer_record_find(p_event->peer_id, p_event->data_id); - - switch (p_event->evt_id) - { - case PDS_EVT_STORED: - if ( (p_write_buffer_record != NULL) - //&& (p_write_buffer_record->store_token == p_event->store_token) - && (p_write_buffer_record->store_requested)) - { - write_buffer_record_release(p_write_buffer_record); - event.evt_id = PDB_EVT_WRITE_BUF_STORED; - pdb_evt_send(&event); - } - else - { - event.evt_id = PDB_EVT_RAW_STORED; - pdb_evt_send(&event); - } - break; - case PDS_EVT_ERROR_STORE: - if ( (p_write_buffer_record != NULL) - && (p_write_buffer_record->store_token == p_event->store_token) - && (p_write_buffer_record->store_requested)) - { - // Retry if internal buffer. - m_pdb.n_writes++; - p_write_buffer_record->store_requested = false; - p_write_buffer_record->store_busy = true; - } - else - { - event.evt_id = PDB_EVT_RAW_STORE_FAILED; - pdb_evt_send(&event); - } - break; - case PDS_EVT_CLEARED: - event.evt_id = PDB_EVT_CLEARED; - pdb_evt_send(&event); - break; - case PDS_EVT_ERROR_CLEAR: - event.evt_id = PDB_EVT_CLEAR_FAILED; - pdb_evt_send(&event); - break; - case PDS_EVT_COMPRESSED: - retry_flash_full = true; - event.evt_id = PDB_EVT_COMPRESSED; - pdb_evt_send(&event); - break; - default: - break; - } - - if (m_pdb.n_writes > 0) - { - for (int i = 0; i < N_WRITE_BUFFER_RECORDS; i++) - { - if ((m_pdb.write_buffer_records[i].store_busy) - || (m_pdb.write_buffer_records[i].store_flash_full && retry_flash_full)) - { - err_code = pdb_write_buf_store(m_pdb.write_buffer_records[i].peer_id, - m_pdb.write_buffer_records[i].data_id); - if (err_code != NRF_SUCCESS) - { - event.peer_id = m_pdb.write_buffer_records[i].peer_id; - event.data_id = m_pdb.write_buffer_records[i].data_id; - if (err_code == NRF_ERROR_NO_MEM) - { - event.evt_id = PDB_EVT_ERROR_NO_MEM; - } - else - { - event.evt_id = PDB_EVT_ERROR_UNEXPECTED; - } - - pdb_evt_send(&event); - break; - } - } - } - } -} - - -ret_code_t pdb_register(pdb_evt_handler_t evt_handler) -{ - if (m_pdb.n_registrants >= MAX_REGISTRANTS) - { - return NRF_ERROR_NO_MEM; - } - - VERIFY_PARAM_NOT_NULL(evt_handler); - - if (!MODULE_INITIALIZED) - { - ret_code_t err_code; - - internal_state_reset(&m_pdb); - err_code = pds_register(pds_evt_handler); - if (err_code != NRF_SUCCESS) - { - return err_code; - } - PM_BUFFER_INIT(&m_pdb.write_buffer, N_WRITE_BUFFERS, PDB_WRITE_BUF_SIZE, err_code); - if (err_code != NRF_SUCCESS) - { - return err_code; - } - } - - m_pdb.evt_handlers[m_pdb.n_registrants] = evt_handler; - m_pdb.n_registrants += 1; - - return NRF_SUCCESS; -} - - -pm_peer_id_t pdb_peer_allocate(void) -{ - if (!MODULE_INITIALIZED) - { - return PM_PEER_ID_INVALID; - } - - return pds_peer_id_allocate(); -} - - -ret_code_t pdb_peer_free(pm_peer_id_t peer_id) -{ - VERIFY_MODULE_INITIALIZED(); - - return pds_peer_id_free(peer_id); -} - - -ret_code_t pdb_read_buf_get(pm_peer_id_t peer_id, - pm_peer_data_id_t data_id, - pm_peer_data_flash_t * p_peer_data, - pm_store_token_t * p_token) -{ - VERIFY_MODULE_INITIALIZED(); - - return pds_peer_data_read_ptr_get(peer_id, data_id, p_peer_data, p_token); -} - - -static void peer_data_point_to_buffer(pm_peer_data_t * p_peer_data, pm_peer_data_id_t data_id, uint8_t * p_buffer_memory, uint16_t n_bufs) -{ - uint16_t n_bytes = n_bufs * PDB_WRITE_BUF_SIZE; - p_peer_data->data_type = data_id; - - switch(p_peer_data->data_type) - { - case PM_PEER_DATA_ID_BONDING: - p_peer_data->data.p_bonding_data = (pm_peer_data_bonding_t *)p_buffer_memory; - p_peer_data->length_words = PM_BONDING_DATA_N_WORDS(); - break; - case PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING: - p_peer_data->data.p_service_changed_pending = (bool *)p_buffer_memory; - p_peer_data->length_words = PM_SC_STATE_N_WORDS(); - break; - case PM_PEER_DATA_ID_GATT_LOCAL: - p_peer_data->data.p_local_gatt_db = (pm_peer_data_local_gatt_db_t *)p_buffer_memory; - p_peer_data->length_words = PM_LOCAL_DB_N_WORDS(n_bytes); - break; - case PM_PEER_DATA_ID_GATT_REMOTE: - p_peer_data->data.p_remote_gatt_db = (pm_peer_data_remote_gatt_db_t *)p_buffer_memory; - p_peer_data->length_words = PM_REMOTE_DB_N_WORDS(n_bytes / sizeof(ble_gatt_db_srv_t)); - break; - case PM_PEER_DATA_ID_APPLICATION: - p_peer_data->data.p_application_data = p_buffer_memory; - p_peer_data->length_words = PM_N_WORDS(n_bytes); - break; - default: - p_peer_data->length_words = 0; - break; - } -} - - -static void peer_data_const_point_to_buffer(pm_peer_data_const_t * p_peer_data, pm_peer_data_id_t data_id, uint8_t * p_buffer_memory, uint32_t n_bufs) -{ - peer_data_point_to_buffer((pm_peer_data_t*)p_peer_data, data_id, p_buffer_memory, n_bufs); -} - - -ret_code_t pdb_write_buf_get(pm_peer_id_t peer_id, - pm_peer_data_id_t data_id, - uint32_t n_bufs, - pm_peer_data_t * p_peer_data) -{ - VERIFY_MODULE_INITIALIZED(); - VERIFY_PARAM_NOT_NULL(p_peer_data); - if ( !PM_PEER_DATA_ID_IS_VALID(data_id) - || (n_bufs == 0) - || (n_bufs > N_WRITE_BUFFERS) - || !pds_peer_id_is_allocated(peer_id)) - { - return NRF_ERROR_INVALID_PARAM; - } - - pdb_buffer_record_t * write_buffer_record; - uint8_t * p_buffer_memory; - - write_buffer_record = write_buffer_record_find(peer_id, data_id); - - if ((write_buffer_record != NULL) && (write_buffer_record->n_bufs < n_bufs)) - { - // @TODO: Copy? - // Existing buffer is too small. - for (uint8_t i = 0; i < write_buffer_record->n_bufs; i++) - { - pm_buffer_release(&m_pdb.write_buffer, write_buffer_record->buffer_block_id + i); - } - write_buffer_record_invalidate(write_buffer_record); - write_buffer_record = NULL; - } - else if ((write_buffer_record != NULL) && write_buffer_record->n_bufs > n_bufs) - { - // Release excess blocks. - for (uint8_t i = n_bufs; i < write_buffer_record->n_bufs; i++) - { - pm_buffer_release(&m_pdb.write_buffer, write_buffer_record->buffer_block_id + i); - } - } - - if (write_buffer_record == NULL) - { - write_buffer_record_get(&write_buffer_record, peer_id, data_id); - if (write_buffer_record == NULL) - { - return NRF_ERROR_BUSY; - } - } - - if (write_buffer_record->buffer_block_id == BUFFER_INVALID_ID) - { - write_buffer_record->buffer_block_id = pm_buffer_block_acquire(&m_pdb.write_buffer, n_bufs); - - if (write_buffer_record->buffer_block_id == BUFFER_INVALID_ID) - { - write_buffer_record_invalidate(write_buffer_record); - return NRF_ERROR_BUSY; - } - } - - write_buffer_record->n_bufs = n_bufs; - - p_buffer_memory = pm_buffer_ptr_get(&m_pdb.write_buffer, write_buffer_record->buffer_block_id); - - if (p_buffer_memory == NULL) - { - return NRF_ERROR_INTERNAL; - } - - peer_data_point_to_buffer(p_peer_data, data_id, p_buffer_memory, n_bufs); - switch(data_id) - { - case PM_PEER_DATA_ID_BONDING: - /* No action needed. */ - break; - case PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING: - /* No action needed. */ - break; - case PM_PEER_DATA_ID_GATT_LOCAL: - { - uint32_t size_offset = sizeof(pm_peer_data_local_gatt_db_t); - p_peer_data->data.p_local_gatt_db->p_data = &p_buffer_memory[size_offset]; - p_peer_data->data.p_local_gatt_db->len = (PDB_WRITE_BUF_SIZE*n_bufs)-size_offset; - } - break; - case PM_PEER_DATA_ID_GATT_REMOTE: - { - uint32_t size_offset = sizeof(pm_peer_data_remote_gatt_db_t); - p_peer_data->data.p_remote_gatt_db->p_data = (ble_gatt_db_srv_t*)&(p_buffer_memory[size_offset]); - p_peer_data->data.p_remote_gatt_db->service_count - = ((PDB_WRITE_BUF_SIZE*n_bufs)-size_offset)/sizeof(ble_gatt_db_srv_t); - } - break; - case PM_PEER_DATA_ID_APPLICATION: - { - p_peer_data->data.p_application_data = p_buffer_memory; - } - break; - default: - // Invalid data_id. This should have been picked up earlier. - return NRF_ERROR_INTERNAL; - } - - return NRF_SUCCESS; -} - - -ret_code_t pdb_write_buf_release(pm_peer_id_t peer_id, pm_peer_data_id_t data_id) -{ - VERIFY_MODULE_INITIALIZED(); - - ret_code_t err_code = NRF_SUCCESS; - pdb_buffer_record_t * p_write_buffer_record; - p_write_buffer_record = write_buffer_record_find(peer_id, data_id); - - if (p_write_buffer_record == NULL) - { - return NRF_ERROR_NOT_FOUND; - } - - if (p_write_buffer_record->prepare_token != PDS_PREPARE_TOKEN_INVALID) - { - err_code = pds_peer_data_write_prepare_cancel(p_write_buffer_record->prepare_token); - if (err_code != NRF_SUCCESS) - { - err_code = NRF_ERROR_INTERNAL; - } - } - - write_buffer_record_release(p_write_buffer_record); - - return err_code; -} - - -ret_code_t pdb_write_buf_store_prepare(pm_peer_id_t peer_id, pm_peer_data_id_t data_id) -{ - VERIFY_MODULE_INITIALIZED(); - - ret_code_t err_code = NRF_SUCCESS; - pdb_buffer_record_t * p_write_buffer_record; - p_write_buffer_record = write_buffer_record_find(peer_id, data_id); - - if (p_write_buffer_record == NULL) - { - return NRF_ERROR_NOT_FOUND; - } - - if (p_write_buffer_record->prepare_token == PDS_PREPARE_TOKEN_INVALID) - { - uint8_t * p_buffer_memory = pm_buffer_ptr_get(&m_pdb.write_buffer, p_write_buffer_record->buffer_block_id); - pm_peer_data_const_t peer_data = {.data_type = data_id}; - - if (p_buffer_memory == NULL) - { - return NRF_ERROR_INTERNAL; - } - - peer_data_const_point_to_buffer(&peer_data, data_id, p_buffer_memory, p_write_buffer_record->n_bufs); - - err_code = pds_peer_data_write_prepare(&peer_data, &p_write_buffer_record->prepare_token); - if (err_code == NRF_ERROR_INVALID_LENGTH) - { - return NRF_ERROR_INTERNAL; - } - } - - return err_code; -} - - -static ret_code_t write_or_update(pm_peer_id_t peer_id, - pm_peer_data_id_t data_id, - pm_peer_data_const_t * p_peer_data, - pm_store_token_t * p_store_token, - pm_prepare_token_t prepare_token) -{ - pm_peer_data_flash_t old_peer_data; - pm_store_token_t old_store_token; - ret_code_t err_code = pds_peer_data_read_ptr_get(peer_id, data_id, &old_peer_data, &old_store_token); - - if (err_code == NRF_SUCCESS) - { - pds_peer_data_write_prepare_cancel(prepare_token); - err_code = pds_peer_data_update(peer_id, p_peer_data, old_store_token, p_store_token); - } - else if (err_code == NRF_ERROR_NOT_FOUND) - { - if (prepare_token == PDS_PREPARE_TOKEN_INVALID) - { - err_code = pds_peer_data_write(peer_id, p_peer_data, p_store_token); - } - else - { - err_code = pds_peer_data_write_prepared(peer_id, p_peer_data, prepare_token, p_store_token); - } - } - return err_code; -} - - -ret_code_t pdb_write_buf_store(pm_peer_id_t peer_id, - pm_peer_data_id_t data_id) -{ - VERIFY_MODULE_INITIALIZED(); - - ret_code_t err_code = NRF_SUCCESS; - pdb_buffer_record_t * p_write_buffer_record; - uint8_t * p_buffer_memory; - pm_peer_data_const_t peer_data = {.data_type = data_id}; - - - p_write_buffer_record = write_buffer_record_find(peer_id, data_id); - - if (p_write_buffer_record == NULL) - { - return NRF_ERROR_NOT_FOUND; - } - - if (p_write_buffer_record->store_requested) - { - return NRF_SUCCESS; - } - - p_buffer_memory = pm_buffer_ptr_get(&m_pdb.write_buffer, p_write_buffer_record->buffer_block_id); - - if (p_buffer_memory == NULL) - { - return NRF_ERROR_INTERNAL; - } - - peer_data_const_point_to_buffer(&peer_data, data_id, p_buffer_memory, p_write_buffer_record->n_bufs); - - switch (data_id) - { - case PM_PEER_DATA_ID_BONDING: - peer_data.length_words = PM_BONDING_DATA_N_WORDS(); - break; - case PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING: - peer_data.length_words = PM_SC_STATE_N_WORDS(); - break; - case PM_PEER_DATA_ID_GATT_LOCAL: - peer_data.length_words = PM_LOCAL_DB_N_WORDS(peer_data.data.p_local_gatt_db->len); - break; - case PM_PEER_DATA_ID_GATT_REMOTE: - peer_data.length_words = PM_REMOTE_DB_N_WORDS(peer_data.data.p_remote_gatt_db->service_count); - break; - case PM_PEER_DATA_ID_APPLICATION: - peer_data.length_words = PM_N_WORDS(p_write_buffer_record->n_bufs * PDB_WRITE_BUF_SIZE); - break; - default: - return NRF_ERROR_INVALID_PARAM; - } - - err_code = write_or_update(peer_id, data_id, &peer_data, &p_write_buffer_record->store_token, p_write_buffer_record->prepare_token); - - if (p_write_buffer_record->store_busy && p_write_buffer_record->store_flash_full) - { - m_pdb.n_writes--; - } - - if (err_code == NRF_SUCCESS) - { - p_write_buffer_record->store_requested = true; - p_write_buffer_record->store_busy = false; - p_write_buffer_record->store_flash_full = false; - } - else - { - if (err_code == NRF_ERROR_BUSY) - { - m_pdb.n_writes++; - p_write_buffer_record->store_busy = true; - p_write_buffer_record->store_flash_full = false; - err_code = NRF_SUCCESS; - } - else if (err_code == NRF_ERROR_NO_MEM) - { - m_pdb.n_writes++; - p_write_buffer_record->store_busy = false; - p_write_buffer_record->store_flash_full = true; - } - else if ((err_code != NRF_ERROR_NO_MEM) && (err_code != NRF_ERROR_INVALID_PARAM)) - { - err_code = NRF_ERROR_INTERNAL; - } - } - - return err_code; -} - - -ret_code_t pdb_clear(pm_peer_id_t peer_id, pm_peer_data_id_t data_id) -{ - VERIFY_MODULE_INITIALIZED(); - - return pds_peer_data_clear(peer_id, data_id); -} - - -uint32_t pdb_n_peers(void) -{ - if (!MODULE_INITIALIZED) - { - return 0; - } - - return pds_n_peers(); -} - - -pm_peer_id_t pdb_next_peer_id_get(pm_peer_id_t prev_peer_id) -{ - if (!MODULE_INITIALIZED) - { - return PM_PEER_ID_INVALID; - } - - return pds_next_peer_id_get(prev_peer_id); -} - - -ret_code_t pdb_raw_read(pm_peer_id_t peer_id, - pm_peer_data_id_t data_id, - pm_peer_data_t * p_peer_data) -{ - VERIFY_MODULE_INITIALIZED(); - return pds_peer_data_read(peer_id, data_id, p_peer_data, &p_peer_data->length_words); -} - - -ret_code_t pdb_raw_store(pm_peer_id_t peer_id, - pm_peer_data_const_t * p_peer_data, - pm_store_token_t * p_store_token) -{ - VERIFY_MODULE_INITIALIZED(); - - return write_or_update(peer_id, p_peer_data->data_type, p_peer_data, p_store_token, PDS_PREPARE_TOKEN_INVALID); -}
--- a/source/nordic_sdk/components/ble/peer_manager/peer_id.c Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,130 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - - -#include "peer_id.h" - -#include <stdint.h> -#include <string.h> -#include "sdk_errors.h" -#include "peer_manager_types.h" -#include "pm_mutex.h" - - -typedef struct -{ - uint8_t peer_ids[MUTEX_STORAGE_SIZE(PM_PEER_ID_N_AVAILABLE_IDS)]; /*< bitmap. */ -} pi_t; - - -static pi_t m_pi = {.peer_ids = {0}}; - - -static void internal_state_reset(pi_t * p_pi) -{ - memset(p_pi, 0, sizeof(pi_t)); -} - - -void peer_id_init(void) -{ - internal_state_reset(&m_pi); - pm_mutex_init(m_pi.peer_ids, PM_PEER_ID_N_AVAILABLE_IDS); -} - - -pm_peer_id_t peer_id_allocate(pm_peer_id_t peer_id) -{ - pm_peer_id_t allocated_peer_id = PM_PEER_ID_INVALID; - if (peer_id == PM_PEER_ID_INVALID) - { - allocated_peer_id = pm_mutex_lock_first_available(m_pi.peer_ids, PM_PEER_ID_N_AVAILABLE_IDS); - if (allocated_peer_id == PM_PEER_ID_N_AVAILABLE_IDS) - { - allocated_peer_id = PM_PEER_ID_INVALID; - } - } - else if (peer_id < PM_PEER_ID_N_AVAILABLE_IDS) - { - bool lock_success = pm_mutex_lock(m_pi.peer_ids, peer_id); - allocated_peer_id = lock_success ? peer_id : PM_PEER_ID_INVALID; - } - return allocated_peer_id; -} - - -void peer_id_free(pm_peer_id_t peer_id) -{ - if (peer_id < PM_PEER_ID_N_AVAILABLE_IDS) - { - pm_mutex_unlock(m_pi.peer_ids, peer_id); - } -} - - -bool peer_id_is_allocated(pm_peer_id_t peer_id) -{ - if (peer_id < PM_PEER_ID_N_AVAILABLE_IDS) - { - return pm_mutex_lock_status_get(m_pi.peer_ids, peer_id); - } - return false; -} - - -pm_peer_id_t peer_id_next_id_get(pm_peer_id_t prev_peer_id) -{ - pm_peer_id_t i = (prev_peer_id == PM_PEER_ID_INVALID) ? 0 : (prev_peer_id + 1); - for (; i < PM_PEER_ID_N_AVAILABLE_IDS; i++) - { - if (pm_mutex_lock_status_get(m_pi.peer_ids, i)) - { - return i; - } - } - - return PM_PEER_ID_INVALID; -} - - -uint32_t peer_id_n_ids(void) -{ - uint32_t n_ids = 0; - - for (pm_peer_id_t i = 0; i < PM_PEER_ID_N_AVAILABLE_IDS; i++) - { - n_ids += pm_mutex_lock_status_get(m_pi.peer_ids, i); - } - - return n_ids; -} -
--- a/source/nordic_sdk/components/ble/peer_manager/peer_id.h Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - - -#ifndef PEER_ID_H__ -#define PEER_ID_H__ - - -#include "stdint.h" -#include "sdk_errors.h" -#include "ble_gap.h" -#include "peer_manager_types.h" - - -/** - * @defgroup peer_id Peer IDs - * @ingroup peer_manager - * @{ - * @brief An internal module of @ref peer_manager. This module keeps track of which peer IDs are in - * use and which are free. - */ - - -/**@brief Function for initializing the module. - */ -void peer_id_init(void); - - -/**@brief Function for claiming an unused peer ID. - * - * @param peer_id The peer ID to allocate. If this is @ref PM_PEER_ID_INVALID, the first available - * will be allocated. - * - * @return The allocated peer ID. - * @retval PM_PEER_ID_INVALID If no peer ID could be allocated or module is not initialized. - */ -pm_peer_id_t peer_id_allocate(pm_peer_id_t peer_id); - - -/**@brief Function for freeing a peer ID and clearing all data associated with it in persistent - * storage. - * - * @param[in] peer_id Peer ID to free. - */ -void peer_id_free(pm_peer_id_t peer_id); - - -/**@brief Function for finding out whether a peer ID is in use. - * - * @param[in] peer_id The peer ID to inquire about. - * - * @retval true peer_id is in use. - * @retval false peer_id is free, or the module is not initialized. - */ -bool peer_id_is_allocated(pm_peer_id_t peer_id); - - -/**@brief Function for getting the next peer ID in the sequence of all used peer IDs. Can be - * used to loop through all used peer IDs. - * - * @note @ref PM_PEER_ID_INVALID is considered to be before the first and after the last ordinary - * peer ID. - * - * @param[in] prev_peer_id The previous peer ID. - * - * @return The next peer ID. - * @return The first used peer ID if prev_peer_id was @ref PM_PEER_ID_INVALID. - * @retval PM_PEER_ID_INVALID if prev_peer_id was the last ordinary peer ID or the module is - * not initialized. - */ -pm_peer_id_t peer_id_next_id_get(pm_peer_id_t prev_peer_id); - - -/**@brief Function for querying the number of valid peer IDs available. I.E the number of peers - * in persistent storage. - * - * @return The number of valid peer IDs, or 0 if module is not initialized. - */ -uint32_t peer_id_n_ids(void); - -/** @} */ - -#endif /* PEER_ID_H__ */ \ No newline at end of file
--- a/source/nordic_sdk/components/ble/peer_manager/pm_buffer.c Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,142 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - - -#include "pm_buffer.h" - -#include <stdbool.h> -#include <string.h> -#include "nrf_error.h" -#include "pm_mutex.h" - - -#define BUFFER_IS_VALID(p_buffer) ((p_buffer != NULL) \ - && (p_buffer->p_memory != NULL) \ - && (p_buffer->p_mutex != NULL)) - - - -ret_code_t pm_buffer_init(pm_buffer_t * p_buffer, - uint8_t * p_buffer_memory, - uint32_t buffer_memory_size, - uint8_t * p_mutex_memory, - uint32_t mutex_memory_size, - uint32_t n_blocks, - uint32_t block_size) -{ - if ( (p_buffer != NULL) - && (p_buffer_memory != NULL) - && (p_mutex_memory != NULL) - && (buffer_memory_size >= (n_blocks*block_size)) - && (mutex_memory_size >= MUTEX_STORAGE_SIZE(n_blocks)) - && (n_blocks != 0) - && (block_size != 0)) - { - p_buffer->p_memory = p_buffer_memory; - p_buffer->p_mutex = p_mutex_memory; - p_buffer->n_blocks = n_blocks; - p_buffer->block_size = block_size; - pm_mutex_init(p_buffer->p_mutex, n_blocks); - - return NRF_SUCCESS; - } - else - { - return NRF_ERROR_INVALID_PARAM; - } -} - - -uint8_t pm_buffer_block_acquire(pm_buffer_t * p_buffer, uint32_t n_blocks) -{ - if (!BUFFER_IS_VALID(p_buffer)) - { - return ( BUFFER_INVALID_ID ); - } - - uint8_t first_locked_mutex = BUFFER_INVALID_ID; - - for (uint8_t i = 0; i < p_buffer->n_blocks; i++) - { - if (pm_mutex_lock(p_buffer->p_mutex, i)) - { - if (first_locked_mutex == BUFFER_INVALID_ID) - { - first_locked_mutex = i; - } - if ((i - first_locked_mutex + 1) == n_blocks) - { - return first_locked_mutex; - } - } - else if (first_locked_mutex != BUFFER_INVALID_ID) - { - for (uint8_t j = first_locked_mutex; j < i; j++) - { - pm_buffer_release(p_buffer, j); - } - first_locked_mutex = BUFFER_INVALID_ID; - } - } - - return ( BUFFER_INVALID_ID ); -} - - -uint8_t * pm_buffer_ptr_get(pm_buffer_t * p_buffer, uint8_t id) -{ - if (!BUFFER_IS_VALID(p_buffer)) - { - return ( NULL ); - } - - if ( (id != BUFFER_INVALID_ID) - && pm_mutex_lock_status_get(p_buffer->p_mutex, id) ) - { - return ( &p_buffer->p_memory[id*p_buffer->block_size] ); - } - else - { - return ( NULL ); - } -} - - -void pm_buffer_release(pm_buffer_t * p_buffer, uint8_t id) -{ - if ( BUFFER_IS_VALID(p_buffer) - && (id != BUFFER_INVALID_ID) - && pm_mutex_lock_status_get(p_buffer->p_mutex, id)) - { - pm_mutex_unlock(p_buffer->p_mutex, id); - } -} \ No newline at end of file
--- a/source/nordic_sdk/components/ble/peer_manager/pm_buffer.h Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,133 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - - -#ifndef BUFFER_H__ -#define BUFFER_H__ - -#include <stdint.h> -#include "sdk_errors.h" -#include "pm_mutex.h" - - -/** - * @defgroup pm_buffer Buffer - * @ingroup peer_manager - * @{ - * @brief An internal module of @ref peer_manager. This module provides a simple buffer. - */ - - -#define BUFFER_INVALID_ID 0xFF - -#define PM_BUFFER_INIT(p_buffer, n_blocks, block_size, err_code) \ -do \ -{ \ - static uint8_t buffer_memory[(n_blocks) * (block_size)]; \ - static uint8_t mutex_memory[MUTEX_STORAGE_SIZE(n_blocks)]; \ - err_code = pm_buffer_init((p_buffer), \ - buffer_memory, \ - (n_blocks) * (block_size), \ - mutex_memory, \ - MUTEX_STORAGE_SIZE(n_blocks), \ - (n_blocks), \ - (block_size)); \ -} while(0) - - -typedef struct -{ - uint8_t * p_memory; /**< The storage for all buffer entries. The size of the buffer must be n_blocks*block_size. */ - uint8_t * p_mutex; /**< A mutex group with one mutex for each buffer entry. */ - uint32_t n_blocks; /**< The number of allocatable blocks in the buffer. */ - uint32_t block_size; /**< The size of each block in the buffer. */ -} pm_buffer_t; - -/**@brief Function for initializing a buffer instance. - * - * @param[out] p_buffer The buffer instance to initialize. - * @param[in] p_buffer_memory The memory this buffer will use. - * @param[in] buffer_memory_size The size of p_buffer_memory. This must be at least - * n_blocks*block_size. - * @param[in] p_mutex_memory The memory for the mutexes. This must be at least - * @ref MUTEX_STORAGE_SIZE(n_blocks). - * @param[in] mutex_memory_size The size of p_mutex_memory. - * @param[in] n_blocks The number of blocks in the buffer. - * @param[in] block_size The size of each block. - * - * @retval NRF_SUCCESS Successfully initialized buffer instance. - * @retval NRF_ERROR_INVALID_PARAM A parameter was 0 or NULL or a size was too small. - */ -ret_code_t pm_buffer_init(pm_buffer_t * p_buffer, - uint8_t * p_buffer_memory, - uint32_t buffer_memory_size, - uint8_t * p_mutex_memory, - uint32_t mutex_memory_size, - uint32_t n_blocks, - uint32_t block_size); - - -/**@brief Function for acquiring a buffer block in a buffer. - * - * @param[in] p_buffer The buffer instance acquire from. - * @param[in] n_blocks The number of contiguous blocks to acquire. - * - * @return The id of the acquired block, if successful. - * @retval BUFFER_INVALID_ID If unsuccessful. - */ -uint8_t pm_buffer_block_acquire(pm_buffer_t * p_buffer, uint32_t n_blocks); - - -/**@brief Function for getting a pointer to a specific buffer block. - * - * @param[in] p_buffer The buffer instance get from. - * @param[in] id The id of the buffer to get the pointer for. - * - * @return A pointer to the buffer for the specified id, if the id is valid. - * @retval NULL If the id is invalid. - */ -uint8_t * pm_buffer_ptr_get(pm_buffer_t * p_buffer, uint8_t id); - - -/**@brief Function for releasing a buffer block. - * - * @param[in] p_buffer The buffer instance containing the block to release. - * @param[in] id The id of the block to release. - */ -void pm_buffer_release(pm_buffer_t * p_buffer, uint8_t id); - - -#endif // BUFFER_H__ - -/** - * @} - */ \ No newline at end of file
--- a/source/nordic_sdk/components/ble/peer_manager/pm_mutex.c Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,135 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - - -#include "pm_mutex.h" - -#include <stdbool.h> -#include <string.h> -#include "nrf_error.h" -#include "app_util_platform.h" - - - -/**@brief Locks the mutex defined by the mask. - * - * @param p_mutex pointer to the mutex storage. - * @param mutex_mask the mask identifying the mutex position. - * - * @retval true if the mutex could be locked. - * @retval false if the mutex was already locked. - */ -static bool lock_by_mask(uint8_t * p_mutex, uint8_t mutex_mask) -{ - bool success = false; - - if ( (*p_mutex & mutex_mask) == 0 ) - { - CRITICAL_REGION_ENTER(); - if ( (*p_mutex & mutex_mask) == 0 ) - { - *p_mutex |= mutex_mask; - - success = true; - } - CRITICAL_REGION_EXIT(); - } - - return ( success ); -} - - -void pm_mutex_init(uint8_t * p_mutex, uint16_t mutex_size) -{ - if (p_mutex != NULL) - { - memset(&p_mutex[0], 0, MUTEX_STORAGE_SIZE(mutex_size)); - } -} - - -bool pm_mutex_lock(uint8_t * p_mutex, uint16_t mutex_id) -{ - if (p_mutex != NULL) - { - return ( lock_by_mask(&(p_mutex[mutex_id >> 3]), (1 << (mutex_id & 0x07))) ); - } - else - { - return false; - } -} - - -void pm_mutex_unlock(uint8_t * p_mutex, uint16_t mutex_id) -{ - uint8_t mutex_base = mutex_id >> 3; - uint8_t mutex_mask = (1 << (mutex_id & 0x07)); - - if ((p_mutex != NULL) - && (p_mutex[mutex_base] & mutex_mask)) - { - CRITICAL_REGION_ENTER(); - p_mutex[mutex_base] &= ~mutex_mask; - CRITICAL_REGION_EXIT(); - } -} - - -uint16_t pm_mutex_lock_first_available(uint8_t * p_mutex, uint16_t mutex_size) -{ - if (p_mutex != NULL) - { - for ( uint16_t i = 0; i < mutex_size; i++ ) - { - if ( lock_by_mask(&(p_mutex[i >> 3]), 1 << (i & 0x07)) ) - { - return ( i ); - } - } - } - - return ( mutex_size ); -} - - -bool pm_mutex_lock_status_get(uint8_t * p_mutex, uint16_t mutex_id) -{ - if (p_mutex != NULL) - { - return ( (p_mutex[mutex_id >> 3] & (1 << (mutex_id & 0x07))) ); - } - else - { - return true; - } -} \ No newline at end of file
--- a/source/nordic_sdk/components/ble/peer_manager/pm_mutex.h Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,108 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - - - -#ifndef MUTEX_H__ -#define MUTEX_H__ - - -#include <stdint.h> -#include <stdbool.h> - -/** - * @defgroup pm_mutex Mutex - * @ingroup peer_manager - * @{ - * @brief An internal module of @ref peer_manager. This module provides thread-safe mutexes. - */ - - -/**@brief Defines the storage size of a specified mutex group. - * - * @param number_of_mutexes the number of mutexes in the group. - */ -#define MUTEX_STORAGE_SIZE(number_of_mutexes) ((7 + (number_of_mutexes)) >> 3) - - -/**@brief Initializes a mutex group. - * - * @param[in] p_mutex Pointer to the mutex group. See @ref MUTEX_STORAGE_SIZE(). - * @param[in] mutex_size The size of the mutex group in number of mutexes. - */ -void pm_mutex_init(uint8_t * p_mutex, uint16_t mutex_size); - - -/**@brief Locks the mutex specified by the bit id. - * - * @param[inout] p_mutex Pointer to the mutex group. - * @param[in] mutex_bit_id The bit id of the mutex. - * - * @retval true if it was possible to lock the mutex. - * @retval false otherwise. - */ -bool pm_mutex_lock(uint8_t * p_mutex, uint16_t mutex_bit_id); - - -/**@brief Locks the first unlocked mutex within the mutex group. - * - * @param[in, out] p_mutex Pointer to the mutex group. - * @param[in] mutex_size The size of the mutex group. - * - * @return The first unlocked mutex id in the group. - * @retval group-size if there was no unlocked mutex available. - */ -uint16_t pm_mutex_lock_first_available(uint8_t * p_mutex, uint16_t mutex_size); - - -/**@brief Unlocks the mutex specified by the bit id. - * - * @param[in, out] p_mutex Pointer to the mutex group. - * @param[in] mutex_bit_id The bit id of the mutex. - */ -void pm_mutex_unlock(uint8_t * p_mutex, uint16_t mutex_bit_id); - - -/**@brief Gets the locking status of the specified mutex. - * - * @param[in, out] p_mutex Pointer to the mutex group. - * @param[in] mutex_bit_id The bit id of the mutex. - * - * @retval true if the mutex was locked. - * @retval false otherwise. - */ -bool pm_mutex_lock_status_get(uint8_t * p_mutex, uint16_t mutex_bit_id); - - -#endif // MUTEX_H__ - -/** @} */ \ No newline at end of file
--- a/source/nordic_sdk/components/libraries/experimental_section_vars/section_vars.h Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,323 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef SECTION_VARS_H__ -#define SECTION_VARS_H__ - -#include "app_util.h" - -#if defined __ICC_ARM__ - -// turn on language extensions for iar -#pragma language=extended - -#endif - -/** - * @defgroup section_vars Section variables - * @ingroup app_common - * @{ - * @brief Section variables. - */ - -/**@brief Macro to delay macro expression of pragma - * - */ -#define NRF_PRAGMA(x) _Pragma(#x) - - -/**@brief Macro to register section by name in code - * - * @param[in] section_name Name of the section to register - **/ -#if defined __CC_ARM - -// Not required by this compiler -#define NRF_SECTION_VARS_REGISTER_SECTION(section_name) - -#elif defined __GNUC__ - -// Not required by this compiler -#define NRF_SECTION_VARS_REGISTER_SECTION(section_name) - -#elif defined __ICCARM__ - -#define NRF_SECTION_VARS_REGISTER_SECTION(section_name) NRF_PRAGMA(section = ## #section_name ) - -#else - -#error TODO - -#endif - -/*lint -save -e27 */ - -/**@brief Macro for accessing start of a named data section by symbol - * - * @details The symbol that this macro resolves to is used to access the section - * by start address. - * - * @param[in] section_name Name of the section - */ -#if defined __CC_ARM - -#define NRF_SECTION_VARS_START_SYMBOL(section_name) section_name ## $$Base - -#elif defined __GNUC__ - -#define NRF_SECTION_VARS_START_SYMBOL(section_name) __start_ ## section_name - -#elif defined __ICCARM__ - -#define NRF_SECTION_VARS_START_SYMBOL(section_name) __section_begin(#section_name) - -#else - -#error TODO - -#endif - - -/**@brief Macro for accessing end of a named data section by symbol - * - * @details The symbol that this macro resolves to is used to access the section - * by end address. - * - * @param[in] section_name Name of the section - */ -#if defined __CC_ARM - -#define NRF_SECTION_VARS_END_SYMBOL(section_name) section_name ## $$Limit - -#elif defined __GNUC__ - -#define NRF_SECTION_VARS_END_SYMBOL(section_name) __stop_ ## section_name - -#elif defined __ICCARM__ - -#define NRF_SECTION_VARS_END_SYMBOL(section_name) __section_end(#section_name) - -#endif - -/*lint -restore */ - - -/**@brief Macro for accessing Length of a named section - * - * @details This macro is used to get the size of a named section. - * - * @param[in] section_name Name of the section - */ - -#if defined __CC_ARM - -#define NRF_SECTION_VARS_LENGTH(section_name) \ - ((uint32_t)&NRF_SECTION_VARS_END_SYMBOL(section_name) - (uint32_t)&NRF_SECTION_VARS_START_SYMBOL(section_name)) - -#elif defined __GNUC__ - - #define NRF_SECTION_VARS_LENGTH(section_name) \ - ((uint32_t)&NRF_SECTION_VARS_END_SYMBOL(section_name) - (uint32_t)&NRF_SECTION_VARS_START_SYMBOL(section_name)) - -#elif defined __ICCARM__ - - #define NRF_SECTION_VARS_LENGTH(section_name) \ - ((uint32_t)NRF_SECTION_VARS_END_SYMBOL(section_name) - (uint32_t)NRF_SECTION_VARS_START_SYMBOL(section_name)) - -#else - -#error TODO - -#endif - - -/**@brief Macro for accessing the start address of a named section - * - * param[in] section_name Name of the section to get the start address from - */ -#if defined __CC_ARM - -#define NRF_SECTION_VARS_START_ADDR(section_name) (uint32_t)&NRF_SECTION_VARS_START_SYMBOL(section_name) - -#elif defined __GNUC__ - -#define NRF_SECTION_VARS_START_ADDR(section_name) (uint32_t)&NRF_SECTION_VARS_START_SYMBOL(section_name) - -#elif defined __ICCARM__ - -#define NRF_SECTION_VARS_START_ADDR(section_name) (uint32_t)iar_ ## section_name ## _start - -#else - -#error TODO - -#endif - - -/*@brief Macro for accessing the end address of a named section - * - * @param[in] section_name Name of the section to get end address from - */ -#if defined __CC_ARM - -#define NRF_SECTION_VARS_END_ADDR(section_name) (uint32_t)&NRF_SECTION_VARS_END_SYMBOL(section_name) - -#elif defined __GNUC__ - -#define NRF_SECTION_VARS_END_ADDR(section_name) (uint32_t)&NRF_SECTION_VARS_END_SYMBOL(section_name) - -#elif defined __ICCARM__ - -#define NRF_SECTION_VARS_END_ADDR(section_name) (uint32_t)iar_ ## section_name ## _end - -#else - -#error TODO - -#endif - - -/**@brief Macro for declaring symbols for named sections - * - * @note These external declarations of section specific symbols are required for the linker in GCC and Keil (not IAR) - * - * @param[in] type_name Name of the type stored in the section - * @param[in] section_name Name of the section - */ -#if defined __CC_ARM - -#define NRF_SECTION_VARS_REGISTER_SYMBOLS(type_name, section_name) \ - extern type_name* NRF_SECTION_VARS_START_SYMBOL(section_name); \ - extern void* NRF_SECTION_VARS_END_SYMBOL(section_name) - -#elif defined __GNUC__ - -#define NRF_SECTION_VARS_REGISTER_SYMBOLS(type_name, section_name) \ - extern type_name* NRF_SECTION_VARS_START_SYMBOL(section_name); \ - extern void* NRF_SECTION_VARS_END_SYMBOL(section_name) - -#elif defined __ICCARM__ - -// No symbol registration required for IAR -#define NRF_SECTION_VARS_REGISTER_SYMBOLS(type_name, section_name) \ - extern void* iar_ ## section_name ## _start = __section_begin(#section_name); \ - extern void* iar_ ## section_name ## _end = __section_end(#section_name) - -#else - -#error TODO - -#endif - - -/**@brief Macro to add symbols to a named section - * - * @details The symbols are placed in a named section. All calls to this macro - * will result in symbols being placed in a contiguous manner in the named section. - * This macro ensures that the symbol is not removed because of optimization level. - * - * @warning There is no guarantee for ordering of placement. If ordering is required - * - * @warning The symbols added in the named section must be word aligned to - * ensure that compilers do not pad the section during symbol placement. - * - * @param[in] section_name Name of the section - * @param[in] type_def Datatype of the symbol to place in the given section - */ -#if defined __CC_ARM - -#define NRF_SECTION_VARS_ADD(section_name, type_def) \ - static type_def __attribute__((section( #section_name ))) __attribute__((used)) - -#elif defined __GNUC__ - -#define NRF_SECTION_VARS_ADD(section_name, type_def) \ - static type_def __attribute__ ((section( #section_name ))) __attribute__ ((used)) - -#elif defined __ICCARM__ - -#define NRF_SECTION_VARS_ADD(section_name, type_def) \ - __root type_def @ #section_name - -#else - -#error TODO - -#endif - - -/**@brief Macro to get symbol from named section - * - * @warning The stored symbol can only be resolved using this macro if the - * type of the data is word aligned. The operation of acquiring - * the stored symbol relies on sizeof of the stored type, no - * padding can exist in the named section in between individual - * stored items or this macro will fail. - * - * @param[in] i Index of item in section - * @param[in] type_name Type name of item in section - * @param[in] section_name Name of the section - */ - -#if defined __CC_ARM - -#define NRF_SECTION_VARS_GET(i, type_name, section_name) \ - (type_name*)(NRF_SECTION_VARS_START_ADDR(section_name) + i * sizeof(type_name)) - -#elif defined __GNUC__ - -#define NRF_SECTION_VARS_GET(i, type_name, section_name) \ - (type_name*)(NRF_SECTION_VARS_START_ADDR(section_name) + i * sizeof(type_name)) - -#elif defined __ICCARM__ - -#define NRF_SECTION_VARS_GET(i, type_name, section_name) \ - (type_name*)iar_ ## section_name ## _start + (i * sizeof(type_name)) - -#else - -#error TODO - -#endif - - -/**@brief Macro to get number of items in named section - * - * @param[in] type_name Type name of item in section - * @param[in] section_name Name of the section - */ -#define NRF_SECTION_VARS_COUNT(type_name, section_name) \ - NRF_SECTION_VARS_LENGTH(section_name) / sizeof(type_name) - -/** @} */ - -#endif // SECTION_VARS_H__ \ No newline at end of file
--- a/source/nordic_sdk/components/libraries/fds/fds.c Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2089 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "fds.h" -#include <stdint.h> -#include <string.h> -#include <stdbool.h> -#include "fds_config.h" -#include "fds_types_internal.h" -#include "fstorage.h" -#include "nrf_error.h" -#include "app_util.h" - - -/** Our fstorage configuration. - * The other fields will be assigned automatically during compilation. */ -FS_SECTION_VARS_ADD(fs_config_t fs_config) = { .cb = fs_callback, .num_pages = FDS_MAX_PAGES }; - -static uint32_t const fds_page_tag_swap[] = {FDS_PAGE_TAG_WORD_0_SWAP, FDS_PAGE_TAG_WORD_1, - FDS_PAGE_TAG_WORD_2, FDS_PAGE_TAG_WORD_3}; - -static uint32_t const fds_page_tag_valid[] = {FDS_PAGE_TAG_WORD_0_VALID, FDS_PAGE_TAG_WORD_1, - FDS_PAGE_TAG_WORD_2, FDS_PAGE_TAG_WORD_3}; - -static uint32_t const fds_page_tag_gc = FDS_PAGE_TAG_WORD_3_GC; - -static fds_tl_t const m_fds_tl_invalid = { .type = FDS_TYPE_ID_INVALID, - .length_words = 0xFFFF }; - -/**@brief Internal status flags. */ -static uint8_t volatile m_flags; - -static uint8_t m_users; -static fds_cb_t m_cb_table[FDS_MAX_USERS]; - -/**@brief The last record ID. Setup page by page_scan() during pages_init(). */ -static fds_record_id_t m_last_rec_id; - -/**@brief The internal queues. */ -static fds_cmd_queue_t m_cmd_queue; -static fds_chunk_queue_t m_chunk_queue; - -/**@brief Holds the state of pages. Setup by fds_init(). */ -static fds_page_t m_pages[FDS_MAX_PAGES]; -static bool m_swap_page_avail = false; - -static fds_gc_data_t m_gc; -static uint16_t m_gc_runs; - -static uint8_t volatile m_counter; - - -static void app_notify(ret_code_t result, - fds_cmd_id_t cmd, - fds_record_id_t record_id, - fds_record_key_t record_key) -{ - for (uint8_t user = 0; user < FDS_MAX_USERS; user++) - { - if (m_cb_table[user] != NULL) - { - m_cb_table[user](result, cmd, record_id, record_key); - } - } -} - - -static void atomic_counter_inc() -{ - CRITICAL_SECTION_ENTER(); - m_counter++; - CRITICAL_SECTION_EXIT(); -} - - -static void atomic_counter_dec() -{ - CRITICAL_SECTION_ENTER(); - m_counter--; - CRITICAL_SECTION_EXIT(); -} - - -static bool atomic_counter_is_zero() -{ - bool ret; - CRITICAL_SECTION_ENTER(); - ret = (m_counter == 0); - CRITICAL_SECTION_EXIT(); - return ret; -} - - -static void flag_set(fds_flags_t flag) -{ - CRITICAL_SECTION_ENTER(); - m_flags |= flag; - CRITICAL_SECTION_EXIT(); -} - - -static void flag_clear(fds_flags_t flag) -{ - CRITICAL_SECTION_ENTER(); - m_flags &= ~(flag); - CRITICAL_SECTION_EXIT(); -} - - -static bool flag_is_set(fds_flags_t flag) -{ - bool ret; - CRITICAL_SECTION_ENTER(); - ret = (m_flags & flag); - CRITICAL_SECTION_EXIT(); - return ret; -} - - -/**@brief Function to check if a header has valid information. */ -static __INLINE bool header_is_valid(fds_header_t const * const p_header) -{ - return ((p_header->tl.type != FDS_TYPE_ID_INVALID) && - (p_header->ic.instance != FDS_INSTANCE_ID_INVALID)); -} - - -static bool address_within_page_bounds(uint32_t const * const p_addr) -{ - return (p_addr >= fs_config.p_start_addr) && - (p_addr <= fs_config.p_end_addr) && - (is_word_aligned(p_addr)); -} - - -/**@brief Internal function to identify the page type. */ -static fds_page_type_t page_identify(uint16_t page_number) -{ - uint32_t const * const p_page_addr = m_pages[page_number].start_addr; - - uint32_t const word0 = *(p_page_addr); - uint32_t const word1 = *(p_page_addr + 1); - uint32_t const word2 = *(p_page_addr + 2); - uint32_t const word3 = *(p_page_addr + 3); - - if (word1 != FDS_PAGE_TAG_WORD_1) - { - return FDS_PAGE_UNDEFINED; - } - - if (word2 != FDS_PAGE_TAG_WORD_2) - { - return FDS_PAGE_UNDEFINED; - } - - if (word3 == FDS_PAGE_TAG_WORD_3) - { - if (word0 == FDS_PAGE_TAG_WORD_0_SWAP) - { - return FDS_PAGE_SWAP; - } - - if (word0 == FDS_PAGE_TAG_WORD_0_VALID) - { - return FDS_PAGE_VALID; - } - } - else if (word3 == FDS_PAGE_TAG_WORD_3_GC) - { - if (word0 == FDS_PAGE_TAG_WORD_0_SWAP || word0 == FDS_PAGE_TAG_WORD_0_VALID) - { - return FDS_PAGE_GC; - } - } - - return FDS_PAGE_UNDEFINED; -} - - -static uint16_t page_by_addr(uint32_t const * const p_addr) -{ - if (p_addr == NULL) - { - return 0; - } - - // Compute the BYTES offset from the beginning of the first page. - uint32_t const byte_offset = (uint32_t)p_addr - (uint32_t)m_pages[0].start_addr; - -// See nrf.h. -#if defined (NRF51) - return byte_offset >> 10; // Divide by page size (1024). -#elif defined (NRF52) - return byte_offset >> 12; // Divide by page size (4096). -#else - #error "Device family must be defined. See nrf.h." -#endif -} - - -// NOTE: depends on m_pages.write_offset to function. -static bool page_has_space(uint16_t page, fds_length_t length_words) -{ - if (page >= FDS_MAX_PAGES) - { - return false; - } - - CRITICAL_SECTION_ENTER(); - length_words += m_pages[page].write_offset; - length_words += m_pages[page].words_reserved; - CRITICAL_SECTION_EXIT(); - - return (length_words < FS_PAGE_SIZE_WORDS); -} - - -/**@brief This function scans a page to determine how many words have - * been written to it. This information is used to set the page - * write offset during initialization (mount). Additionally, this - * function will update the last known record ID as it proceeds. - */ -static void page_scan(uint16_t page, uint16_t volatile * words_written) -{ - uint32_t const * p_addr = (m_pages[page].start_addr + FDS_PAGE_TAG_SIZE); - - *words_written = FDS_PAGE_TAG_SIZE; - - // A corrupt TL might cause problems. - while ((p_addr < m_pages[page].start_addr + FS_PAGE_SIZE_WORDS) && - (*p_addr != FDS_ERASED_WORD)) - { - fds_header_t const * const p_header = (fds_header_t*)p_addr; - - /** Note: DO NOT check for the validity of the header using - * header_is_valid() here. If an header has an invalid type (0x0000) - * or a missing instance (0xFFFF) then we WANT to skip it. - */ - - // Update the last known record id. - if (p_header->id > m_last_rec_id) - { - m_last_rec_id = p_header->id; - } - - // Jump to the next record. - p_addr += (FDS_HEADER_SIZE + p_header->tl.length_words); - *words_written += (FDS_HEADER_SIZE + p_header->tl.length_words); - } -} - - -static bool page_is_empty(uint16_t page) -{ - uint32_t const * const p_addr = m_pages[page].start_addr; - - for (uint16_t i = 0; i < FS_PAGE_SIZE_WORDS; i++) - { - if (*(p_addr + i) != FDS_ERASED_WORD) - { - return false; - } - } - - return true; -} - - -static ret_code_t page_id_from_virtual_id(uint16_t vpage_id, uint16_t * p_page_id) -{ - for (uint16_t i = 0; i < FDS_MAX_PAGES; i++) - { - if (m_pages[i].vpage_id == vpage_id) - { - *p_page_id = i; - return NRF_SUCCESS; - } - } - - return NRF_ERROR_NOT_FOUND; -} - - -static ret_code_t page_from_virtual_id(uint16_t vpage_id, fds_page_t ** p_page) -{ - for (uint16_t i = 0; i < FDS_MAX_PAGES; i++) - { - if (m_pages[i].vpage_id == vpage_id) - { - *p_page = &m_pages[i]; - return NRF_SUCCESS; - } - } - - return NRF_ERROR_NOT_FOUND; -} - - -static uint32_t record_id_new() -{ - return ++m_last_rec_id; -} - - -/**@brief Tags a page as swap, i.e., reserved for GC. */ -static ret_code_t page_tag_write_swap(uint16_t page) -{ - return fs_store(&fs_config, - m_pages[page].start_addr, - (uint32_t const *)&fds_page_tag_swap, - FDS_PAGE_TAG_SIZE); -} - - -/**@brief Tags a page as valid, i.e, ready for storage. */ -static ret_code_t page_tag_write_valid(uint16_t page) -{ - return fs_store(&fs_config, - m_pages[page].start_addr, - (uint32_t const *)&fds_page_tag_valid, - FDS_PAGE_TAG_SIZE); -} - - -/**@brief Tags a valid page as being garbage collected. */ -static ret_code_t page_tag_write_gc(uint16_t page) -{ - return fs_store(&fs_config, - m_pages[page].start_addr + 3, - (uint32_t const *)&fds_page_tag_gc, - 1 /*Words*/); -} - - -/**@brief Given a page and a record, finds the next valid record. */ -static ret_code_t scan_next_valid(uint16_t page, uint32_t const ** p_record) -{ - uint32_t const * p_next_rec = (*p_record); - - if (p_next_rec == NULL) - { - // This if the first invocation on this page, start from the beginning. - p_next_rec = m_pages[page].start_addr + FDS_PAGE_TAG_SIZE; - } - else - { - // Jump to the next record. - p_next_rec += (FDS_HEADER_SIZE + ((fds_header_t*)(*p_record))->tl.length_words); - } - - // Scan until we find a valid record or until the end of the page. - - /** README: We might seek until the write_offset is reached, but it might not - * known at this point. */ - while ((p_next_rec < (m_pages[page].start_addr + FS_PAGE_SIZE_WORDS)) && - (*p_next_rec != FDS_ERASED_WORD)) // Did we jump to an erased word? - { - fds_header_t const * const p_header = (fds_header_t*)p_next_rec; - - if (header_is_valid(p_header)) - { - // Bingo! - *p_record = p_next_rec; - return NRF_SUCCESS; - } - else - { - // The item is not valid, jump to the next. - p_next_rec += (FDS_HEADER_SIZE + (p_header->tl.length_words)); - } - } - - return NRF_ERROR_NOT_FOUND; -} - - -static ret_code_t seek_record(fds_record_desc_t * const p_desc) -{ - uint32_t const * p_record; - uint16_t page; - bool seek_all_pages = false; - - if ((p_desc->ptr_magic == FDS_MAGIC_HWORD) && - (p_desc->gc_magic == m_gc_runs)) - { - // No need to seek the file. - return NRF_SUCCESS; - } - - /** The pointer in the descriptor is not initialized, or GC - * has been run since the last time it was retrieved. - * We must seek the record again. */ - - // Obtain the physical page ID. - if (page_id_from_virtual_id(p_desc->vpage_id, &page) != NRF_SUCCESS) - { - page = 0; - seek_all_pages = true; - } - - do { - // Let's find the address from where we should start seeking the record. - p_record = m_pages[page].start_addr + FDS_PAGE_TAG_SIZE; - - /** Seek for a record with matching ID. - * We might get away with seeking to the page write offset, if it is known. */ - - while ((p_record < (m_pages[page].start_addr + FS_PAGE_SIZE_WORDS)) && - (*p_record != FDS_ERASED_WORD)) - { - fds_header_t const * const p_header = (fds_header_t*)p_record; - - if ((p_header->id != p_desc->record_id) || - (!header_is_valid(p_header))) - { - // ID doesnt't match or the record has been cleared. Jump to the next record. - p_record += FDS_HEADER_SIZE + p_header->tl.length_words; - } - else - { - // Update the pointer in the descriptor. - p_desc->p_rec = p_record; - p_desc->ptr_magic = FDS_MAGIC_HWORD; - p_desc->gc_magic = m_gc_runs; - - return NRF_SUCCESS; - } - } - } while (seek_all_pages ? page++ < FDS_MAX_PAGES : 0); - - return NRF_ERROR_NOT_FOUND; -} - - -static ret_code_t find_record(fds_type_id_t const * const p_type, - fds_instance_id_t const * const p_inst, - fds_record_desc_t * const p_desc, - fds_find_token_t * const p_token) -{ - if (!flag_is_set(FDS_FLAG_INITIALIZED)) - { - return NRF_ERROR_INVALID_STATE; - } - - // Here we distinguish between the first invocation and the and the others. - if ((p_token->magic != FDS_MAGIC_WORD) || - !address_within_page_bounds(p_token->p_addr)) // Is the address is really okay? - { - // Initialize the token. - p_token->magic = FDS_MAGIC_WORD; - p_token->vpage_id = 0; - p_token->p_addr = NULL; - } - else - { - // Look past the last record address. - p_token->p_addr += (FDS_HEADER_SIZE + ((fds_header_t*)p_token->p_addr)->tl.length_words); - } - - // Begin (or resume) searching for a record. - for (; p_token->vpage_id < FDS_MAX_PAGES; p_token->vpage_id++) - { - uint16_t page = 0; - - // Obtain the physical page ID. - page_id_from_virtual_id(p_token->vpage_id, &page); - - if (m_pages[page].page_type != FDS_PAGE_VALID) - { - // Skip this page. - continue; - } - - if (p_token->p_addr == NULL) - { - // If it's the first time the function is run, initialize the pointer. - p_token->p_addr = m_pages[page].start_addr + FDS_PAGE_TAG_SIZE; - } - - // Seek a valid record on this page, starting from the address stored in the token. - while ((p_token->p_addr < (m_pages[page].start_addr + FS_PAGE_SIZE_WORDS)) && - (*p_token->p_addr != FDS_ERASED_WORD)) // Did we jump to an erased word? - { - fds_header_t const * const p_header = (fds_header_t*)p_token->p_addr; - - if (header_is_valid(p_header)) - { - // A valid record was found, check its header for a match. - bool item_match = false; - - if (p_type != NULL) - { - if (p_header->tl.type == *p_type) - { - item_match = true; - } - } - - if (p_inst != NULL) - { - if (p_header->ic.instance == *p_inst) - { - item_match = (p_type == NULL) ? true : item_match && true; - } - else - { - item_match = false; - } - } - - if (item_match) - { - // We found the record! Update the descriptor. - p_desc->vpage_id = m_pages[page].vpage_id; - p_desc->record_id = p_header->id; - - p_desc->p_rec = p_token->p_addr; - p_desc->ptr_magic = FDS_MAGIC_HWORD; - p_desc->gc_magic = m_gc_runs; - - return NRF_SUCCESS; - } - } - // Jump to the next record. - p_token->p_addr += (FDS_HEADER_SIZE + (p_header->tl.length_words)); - } - - /** We have seeked an entire page. Set the address in the token to NULL - * so that it will be set again on the next iteration. */ - p_token->p_addr = NULL; - } - - /** If we couldn't find the record, zero the token structure - * so that it can be reused. */ - p_token->magic = 0x00; - - return NRF_ERROR_NOT_FOUND; -} - - -static void gc_init() -{ - // Set which pages to GC. - for (uint16_t i = 0; i < FDS_MAX_PAGES; i++) - { - m_gc.do_gc_page[i] = (m_pages[i].page_type == FDS_PAGE_VALID); - } -} - - -static void gc_reset() -{ - m_gc.state = BEGIN; - m_gc.cur_page = 0; - m_gc.p_scan_addr = NULL; -} - - -static void gc_set_state(fds_gc_state_t new_state) -{ - m_gc.state = new_state; -} - - -static ret_code_t gc_get_next_page(uint16_t * const next_page) -{ - for (uint16_t i = 0; i < FDS_MAX_PAGES; i++) - { - if (m_gc.do_gc_page[i]) - { - uint16_t records_open; - - CRITICAL_SECTION_ENTER(); - records_open = m_pages[i].records_open; - CRITICAL_SECTION_EXIT(); - - // Do not attempt to GC this page anymore. - m_gc.do_gc_page[i] = false; - - // Only GC pages with no open records. - if (records_open == 0) - { - *next_page = i; - return NRF_SUCCESS; - } - } - } - - return NRF_ERROR_NOT_FOUND; -} - - -static ret_code_t gc_page() -{ - ret_code_t ret; - - ret = gc_get_next_page(&m_gc.cur_page); - - // No pages left to GC. GC has terminated. Reset GC data. - if (ret != NRF_SUCCESS) - { - gc_reset(); - - return COMMAND_COMPLETED; - } - - // Prepare to GC the page. - gc_set_state(GC_PAGE); - - // Flag the page as being garbage collected. - ret = page_tag_write_gc(m_gc.cur_page); - - if (ret != NRF_SUCCESS) - { - return ret; - } - - return COMMAND_EXECUTING; -} - - -static ret_code_t gc_copy_record() -{ - ret_code_t fs_ret; - - // We have found a record to copy. - fds_record_t const * const p_record = (fds_record_t*)m_gc.p_scan_addr; - - gc_set_state(COPY_RECORD); - - // Copy the item to swap. - fs_ret = fs_store(&fs_config, - m_pages[m_gc.swap_page].start_addr + m_pages[m_gc.swap_page].write_offset, - (uint32_t*)p_record, - FDS_HEADER_SIZE + p_record->header.tl.length_words); - - if (fs_ret != NRF_SUCCESS) - { - // Oops :( - // This is an error. Can we recover? - } - - // Remember to update the swap page write offset. - m_pages[m_gc.swap_page].write_offset += (FDS_HEADER_SIZE + p_record->header.tl.length_words); - - return COMMAND_EXECUTING; -} - - -static ret_code_t gc_ready_swap_page() -{ - ret_code_t fs_ret; - - /** A page has been scanned through. All valid records found were copied to swap. - * The swap page can now be flagged as a valid page. */ - gc_set_state(READY_SWAP); - - fs_ret = page_tag_write_valid(m_gc.swap_page); - if (fs_ret != NRF_SUCCESS) - { - return fs_ret; - } - - /** Do not update the page type in the internal page structure (m_pages) - * right away. (why?) */ - return COMMAND_EXECUTING; -} - - -static ret_code_t gc_seek_record() -{ - // Let's find a valid record which has not been copied yet. - if (scan_next_valid(m_gc.cur_page, &m_gc.p_scan_addr) == NRF_SUCCESS) - { - /** The record is guaranteed to fit in the destination page, - * so we don't need to check its size. */ - return gc_copy_record(); - } - else - { - /** No more (uncopied) records left on this page. - * The swap page can now be marked as a valid page. */ - return gc_ready_swap_page(); - } -} - - -static ret_code_t gc_new_swap_page() -{ - ret_code_t fs_ret; - uint16_t vpage_id; - - gc_set_state(NEW_SWAP); - - // Save the swap page virtual page ID. - vpage_id = m_pages[m_gc.swap_page].vpage_id; - - /** The swap page has been marked as valid in Flash. We copy the GC'ed page - * write_offset and virtual page ID. */ - m_pages[m_gc.swap_page].page_type = FDS_PAGE_VALID; - m_pages[m_gc.swap_page].vpage_id = m_pages[m_gc.cur_page].vpage_id; - m_pages[m_gc.swap_page].words_reserved = m_pages[m_gc.cur_page].words_reserved; - - // The new swap page is now the page we just GC. - m_gc.swap_page = m_gc.cur_page; - - // Update the write_offset, words_reserved and vpage_id fields for the new swap page. - m_pages[m_gc.swap_page].page_type = FDS_PAGE_SWAP; - m_pages[m_gc.swap_page].vpage_id = vpage_id; - m_pages[m_gc.swap_page].write_offset = FDS_PAGE_TAG_SIZE; - m_pages[m_gc.swap_page].words_reserved = 0; - - /** Finally, erase the new swap page. Remember we still have to flag this - * new page as swap, but we'll wait the callback for this operation to do so. */ - fs_ret = fs_erase(&fs_config, - (uint32_t*)m_pages[m_gc.swap_page].start_addr, - FS_PAGE_SIZE_WORDS); - - if (fs_ret != NRF_SUCCESS) - { - return fs_ret; - } - - return COMMAND_EXECUTING; -} - - -static ret_code_t gc_new_swap_page_init() -{ - ret_code_t fs_ret; - - gc_set_state(INIT_SWAP); - - fs_ret = page_tag_write_swap(m_gc.swap_page); - if (fs_ret != NRF_SUCCESS) - { - return fs_ret; - } - - return COMMAND_EXECUTING; -} - - -static ret_code_t gc_execute(uint32_t result) -{ - // TODO: Handle resuming GC. - - ret_code_t ret; - - if (result != NRF_SUCCESS) - { - // An operation failed. Report to the application. - return result; - } - - switch (m_gc.state) - { - case BEGIN: - { - // Increment the number of times the GC has been run. - m_gc_runs++; - // Sets up a list of pages to GC. - gc_init(); - // Go ! - ret = gc_page(); - } break; - - case GC_PAGE: - /** A page has been successfully flagged as being GC. - * Look for valid records to copy. */ - ret = gc_seek_record(); - break; - - case COPY_RECORD: - /** A record has been copied to swap. - * Look for more records to copy. */ - ret = gc_seek_record(); - break; - - case READY_SWAP: - /** The swap page has been flagged as 'valid' (ready). - * Let's prepare a new swap page. */ - ret = gc_new_swap_page(); - break; - - case NEW_SWAP: - // A new swap page has been prepared. Let's flag it as swap. - ret = gc_new_swap_page_init(); - break; - - case INIT_SWAP: - /** The swap was flagged as swap in flash. Let's compress another page. - * Be sure to update the address where to scan from. */ - m_gc.p_scan_addr = NULL; - ret = gc_page(); - break; - - default: - // Should really not happen. - ret = NRF_ERROR_INTERNAL; - break; - } - - return ret; -} - - -/**@brief Function for initializing the command queue. */ -static void queues_init(void) -{ - memset(&m_cmd_queue, 0, sizeof(fds_cmd_queue_t)); - memset(&m_chunk_queue, 0, sizeof(fds_chunk_queue_t)); -} - - -void cmd_queue_next(fds_cmd_t ** pp_cmd) -{ - if (*pp_cmd != &m_cmd_queue.cmd[FDS_CMD_QUEUE_SIZE - 1]) - { - (*pp_cmd)++; - return; - } - - *pp_cmd = &m_cmd_queue.cmd[0]; -} - - -void chunk_queue_next(fds_record_chunk_t ** pp_chunk) -{ - if ((*pp_chunk) != &m_chunk_queue.chunk[FDS_CHUNK_QUEUE_SIZE - 1]) - { - (*pp_chunk)++; - return; - } - - *pp_chunk = &m_chunk_queue.chunk[0]; -} - - -/**@brief Advances one position in the command queue. Returns true if the queue is not empty. */ -static bool cmd_queue_advance(void) -{ - // Reset the current element. - memset(&m_cmd_queue.cmd[m_cmd_queue.rp], 0, sizeof(fds_cmd_t)); - - CRITICAL_SECTION_ENTER(); - if (m_cmd_queue.count != 0) - { - // Advance in the queue, wrapping around if necessary. - m_cmd_queue.rp = (m_cmd_queue.rp + 1) % FDS_CMD_QUEUE_SIZE; - m_cmd_queue.count--; - } - CRITICAL_SECTION_EXIT(); - - return m_cmd_queue.count != 0; -} - - -/**@brief Returns the current chunk, and advances to the next in the queue. */ -static bool chunk_queue_get_and_advance(fds_record_chunk_t ** pp_chunk) -{ - bool chunk_popped = false; - - CRITICAL_SECTION_ENTER(); - if (m_chunk_queue.count != 0) - { - // Point to the current chunk and advance the queue. - *pp_chunk = &m_chunk_queue.chunk[m_chunk_queue.rp]; - - m_chunk_queue.rp = (m_chunk_queue.rp + 1) % FDS_CHUNK_QUEUE_SIZE; - m_chunk_queue.count--; - - chunk_popped = true; - } - CRITICAL_SECTION_EXIT(); - - return chunk_popped; -} - - -static bool chunk_queue_skip(uint8_t num_op) -{ - bool chunk_skipped = false; - - CRITICAL_SECTION_ENTER(); - if (num_op <= m_chunk_queue.count) - { - m_chunk_queue.count -= num_op; - chunk_skipped = true; - } - CRITICAL_SECTION_EXIT(); - - return chunk_skipped; -} - - -/**@brief Reserves resources on both queues. */ -static ret_code_t queue_reserve(uint8_t num_cmd, - uint8_t num_chunks, - fds_cmd_t ** pp_cmd, - fds_record_chunk_t ** pp_chunk) -{ - uint8_t cmd_index; - uint8_t chunk_index; - - // This is really just being safe. - if (pp_cmd == NULL || ((pp_chunk == NULL) && (num_chunks != 0))) - { - return NRF_ERROR_NULL; - } - - if (num_cmd == 0) - { - return NRF_ERROR_INVALID_DATA; - } - - CRITICAL_SECTION_ENTER(); - - // Ensure there is enough space in the queues. - if ((m_cmd_queue.count > FDS_CMD_QUEUE_SIZE - num_cmd) || - (m_chunk_queue.count > FDS_CHUNK_QUEUE_SIZE - num_chunks)) - { - CRITICAL_SECTION_EXIT(); - return NRF_ERROR_BUSY; - } - - // Find the write position in the commands queue. - cmd_index = m_cmd_queue.count; - cmd_index += m_cmd_queue.rp; - cmd_index = cmd_index % FDS_CMD_QUEUE_SIZE; - - *pp_cmd = &m_cmd_queue.cmd[cmd_index]; - m_cmd_queue.count += num_cmd; - - /* If no operations are associated with the command, such as is the case - * for initialization and compression, pp_chunk can be NULL. */ - if (num_chunks != 0) - { - chunk_index = m_chunk_queue.count; - chunk_index += m_chunk_queue.rp; - chunk_index = chunk_index % FDS_CHUNK_QUEUE_SIZE; - - *pp_chunk = &m_chunk_queue.chunk[chunk_index]; - m_chunk_queue.count += num_chunks; - } - - CRITICAL_SECTION_EXIT(); - - return NRF_SUCCESS; -} - - -/**@brief Cancel the reservation on resources on queues. */ -static void queue_reserve_cancel(uint8_t num_cmd, uint8_t num_chunks) -{ - CRITICAL_SECTION_ENTER(); - m_cmd_queue.count -= num_cmd; - m_chunk_queue.count -= num_chunks; - CRITICAL_SECTION_EXIT(); -} - - -static void pages_init(uint16_t * const p_pages_avail, - bool * const p_write_page_tag, - bool * const p_resume_comp) -{ - *p_pages_avail = 0; - *p_write_page_tag = false; - *p_resume_comp = false; - - /** Scan pages and setup page data. - * This function does NOT perform write operations in flash. */ - for (uint16_t i = 0; i < FDS_MAX_PAGES; i++) - { - // Initialize page data. Note that start_addr must be set BEFORE invoking page_identify(). - m_pages[i].start_addr = fs_config.p_start_addr + (i * FS_PAGE_SIZE_WORDS); - m_pages[i].write_offset = FDS_PAGE_TAG_SIZE; - m_pages[i].vpage_id = i; - m_pages[i].records_open = 0; - m_pages[i].words_reserved = 0; - - m_pages[i].page_type = page_identify(i); - - switch (m_pages[i].page_type) - { - case FDS_PAGE_UNDEFINED: - { - if (page_is_empty(i)) - { - /* We have found an erased page, which can be initialized. - * This will require a write in flash. */ - m_pages[i].page_type = FDS_PAGE_ERASED; - *p_write_page_tag = true; - } - } break; - - case FDS_PAGE_VALID: - { - /** If a page is valid, we update its write offset. - * Additionally, page_scan will update the last known record ID. */ - page_scan(i, &m_pages[i].write_offset); - (*p_pages_avail)++; - } break; - - case FDS_PAGE_SWAP: - { - m_gc.swap_page = i; - m_swap_page_avail = true; - } break; - - case FDS_PAGE_GC: - { - /** There is an ongoing garbage collection. - * We should resume the operation, which we don't yet. */ - m_gc.cur_page = i; - m_gc.state = GC_PAGE; - *p_resume_comp = true; - } break; - - default: - break; - } - } -} - - -// NOTE: Adds FDS_HEADER_SIZE automatically. -static ret_code_t write_space_reserve(uint16_t length_words, uint16_t * vpage_id) -{ - bool space_reserved = false; - uint16_t total_len_words = length_words + FDS_HEADER_SIZE; - - if (total_len_words >= FS_PAGE_SIZE_WORDS - FDS_PAGE_TAG_SIZE) - { - return NRF_ERROR_INVALID_LENGTH; - } - - for (uint16_t page = 0; page < FDS_MAX_PAGES; page++) - { - if ((m_pages[page].page_type == FDS_PAGE_VALID) && - (page_has_space(page, total_len_words))) - { - space_reserved = true; - *vpage_id = m_pages[page].vpage_id; - - CRITICAL_SECTION_ENTER(); - m_pages[page].words_reserved += total_len_words; - CRITICAL_SECTION_EXIT(); - - break; - } - } - - return space_reserved ? NRF_SUCCESS : NRF_ERROR_NO_MEM; -} - - -static bool chunk_is_aligned(fds_record_chunk_t const * const p_chunk, uint8_t num_parts) -{ - for (uint8_t i = 0; i < num_parts; i++) - { - if (!is_word_aligned(p_chunk[i].p_data)) - { - return false; - } - } - - return true; -} - - -static ret_code_t init_execute(uint32_t result, uint32_t const * p_page_addr) -{ - uint16_t cur_page; - bool page_tag_written = false; - - if (result != NRF_SUCCESS) - { - // Oops. Error. - return result; - } - - // Here we just distinguish between the first invocation and the others. - cur_page = p_page_addr == NULL ? 0 : page_by_addr(p_page_addr) + 1; - - if (cur_page == FDS_MAX_PAGES) - { - // We have finished. We'd need to set some flags. - flag_set(FDS_FLAG_INITIALIZED); - flag_clear(FDS_FLAG_INITIALIZING); - - return COMMAND_COMPLETED; - } - - while (cur_page < FDS_MAX_PAGES && !page_tag_written) - { - if (m_pages[cur_page].page_type == FDS_PAGE_ERASED) - { - page_tag_written = true; - - if (m_swap_page_avail) - { - if (page_tag_write_valid(cur_page) != NRF_SUCCESS) - { - // Oops. Error. - } - // Update the page type. - m_pages[cur_page].page_type = FDS_PAGE_VALID; - } - else - { - if (page_tag_write_swap(cur_page) != NRF_SUCCESS) - { - // Oops. Error. - } - // Update the page type. - m_pages[cur_page].page_type = FDS_PAGE_SWAP; - - /** Update compression data. We set this information in init_pages - * if it is available, otherwise, we should set it here. */ - m_swap_page_avail = true; - m_gc.swap_page = cur_page; - } - } - - cur_page++; - } - - if (!page_tag_written) - { - if (m_swap_page_avail) - { - return COMMAND_COMPLETED; - } - else - { - // There is no empty space to use as swap. - // Notify user that no compression is available? - } - } - - return COMMAND_EXECUTING; -} - - -/**@brief Function to execute write and update commands. - * - */ -static ret_code_t store_execute(uint32_t result, fds_cmd_t * const p_cmd) -{ - ret_code_t fs_ret; - fds_record_chunk_t * p_chunk = NULL; - fds_page_t * p_page = NULL; - uint32_t * p_write_addr; - - // Using virtual page IDs allows other operations to be queued even if GC has been requested. - page_from_virtual_id(p_cmd->vpage_id, &p_page); - - if (result != NRF_SUCCESS) - { - // The previous operation has failed, update the page data. - p_page->write_offset += (FDS_HEADER_SIZE + (p_cmd->chunk_offset - FDS_WRITE_OFFSET_DATA)); - p_page->words_reserved -= (FDS_HEADER_SIZE + (p_cmd->chunk_offset - FDS_WRITE_OFFSET_DATA)); - - return result; - } - - // Compute the write address (just syntatic sugar). - p_write_addr = (uint32_t*)(p_page->start_addr + p_page->write_offset); - - // Execute the operation. - switch (p_cmd->op_code) - { - case FDS_OP_WRITE_TL: - { - fs_ret = fs_store(&fs_config, - p_write_addr + FDS_WRITE_OFFSET_TL, - (uint32_t*)&p_cmd->record_header.tl, - FDS_HEADER_SIZE_TL /*Words*/); - - // Set the next operation to be executed. - p_cmd->op_code = FDS_OP_WRITE_ID; - - } break; - - case FDS_OP_WRITE_ID: - { - fs_ret = fs_store(&fs_config, - p_write_addr + FDS_WRITE_OFFSET_ID, - (uint32_t*)&p_cmd->record_header.id, - FDS_HEADER_SIZE_ID /*Words*/); - - p_cmd->op_code = FDS_OP_WRITE_CHUNK; - - } break; - - case FDS_OP_WRITE_CHUNK: - { - // Decrement the number of chunks left to write. - p_cmd->num_chunks--; - - // Retrieve the chunk to be written. - chunk_queue_get_and_advance(&p_chunk); - - fs_ret = fs_store(&fs_config, - p_write_addr + p_cmd->chunk_offset, - p_chunk->p_data, - p_chunk->length_words); - - // Accumulate the offset. - p_cmd->chunk_offset += p_chunk->length_words; - - if (p_cmd->num_chunks == 0) - { - /** We have written all the record chunks; we'll write - * IC last as a mean to 'validate' the record. */ - p_cmd->op_code = FDS_OP_WRITE_IC; - } - - } break; - - case FDS_OP_WRITE_IC: - { - fs_ret = fs_store(&fs_config, - p_write_addr + FDS_WRITE_OFFSET_IC, - (uint32_t*)&p_cmd->record_header.ic, - FDS_HEADER_SIZE_IC /*Words*/); - - // This is the final operation. - p_cmd->op_code = FDS_OP_DONE; - - } break; - - case FDS_OP_DONE: - { - // We have successfully written down the IC. The command has completed successfully. - p_page->write_offset += (FDS_HEADER_SIZE + (p_cmd->chunk_offset - FDS_WRITE_OFFSET_DATA)); - p_page->words_reserved -= (FDS_HEADER_SIZE + (p_cmd->chunk_offset - FDS_WRITE_OFFSET_DATA)); - - return COMMAND_COMPLETED; - - }; - - default: - fs_ret = NRF_ERROR_INTERNAL; - break; - } - - // If fs_store did not succeed, the command has failed. - if (fs_ret != NRF_SUCCESS) - { - /** We're not going to receive a callback from fstorage - * so we update the page data right away. */ - p_page->write_offset += (FDS_HEADER_SIZE + (p_cmd->chunk_offset - FDS_WRITE_OFFSET_DATA)); - p_page->words_reserved -= (FDS_HEADER_SIZE + (p_cmd->chunk_offset - FDS_WRITE_OFFSET_DATA)); - - // We should propagate the error from fstorage. - return fs_ret; - } - - // An operation has successfully been executed. Wait for the callback. - return COMMAND_EXECUTING; -} - - -static ret_code_t clear_execute(ret_code_t result, fds_cmd_t * const p_cmd) -{ - ret_code_t ret; - fds_record_desc_t desc; - - // This must persist across calls. - static fds_find_token_t tok; - - if (result != NRF_SUCCESS) - { - // A previous operation has failed. Propagate the error. - return result; - } - - switch (p_cmd->op_code) - { - case FDS_OP_CLEAR_TL: - { - // We were provided a descriptor for the record. - desc.vpage_id = p_cmd->vpage_id; - desc.record_id = p_cmd->record_header.id; - - /** Unfortunately, we always seek the record in this case, - * because we don't buffer an entire record descriptor in the - * fds_cmd_t structure. Keep in mind though, that we will - * seek one page at most. */ - if (seek_record(&desc) != NRF_SUCCESS) - { - // The record never existed, or it is already cleared. - ret = NRF_ERROR_NOT_FOUND; - } - else - { - // Copy the record key, so that it may be returned in the callback. - p_cmd->record_header.tl.type = ((fds_header_t*)desc.p_rec)->tl.type; - p_cmd->record_header.ic.instance = ((fds_header_t*)desc.p_rec)->ic.instance; - - ret = fs_store(&fs_config, - desc.p_rec, - (uint32_t*)&m_fds_tl_invalid, - FDS_HEADER_SIZE_TL); - } - - p_cmd->op_code = FDS_OP_DONE; - - } break; - - case FDS_OP_CLEAR_INSTANCE: - { - if (find_record(NULL, &p_cmd->record_header.ic.instance, - &desc, &tok) != NRF_SUCCESS) - { - // No more records to be found. - p_cmd->op_code = FDS_OP_DONE; - - // Zero the token, so that we may reuse it. - memset(&tok, 0, sizeof(fds_find_token_t)); - - /** We won't receive a callback, since no flash operation - * was initiated. The command has finished. */ - ret = COMMAND_COMPLETED; - } - else - { - ret = fs_store(&fs_config, - desc.p_rec, - (uint32_t*)&m_fds_tl_invalid, - FDS_HEADER_SIZE_TL); - } - } break; - - case FDS_OP_DONE: - { - /** The last operation completed successfully. - * The command has finished. Return. */ - ret = COMMAND_COMPLETED; - } break; - - default: - ret = NRF_ERROR_INVALID_DATA; - break; - } - - // Await for the operation result. - return ret; -} - - -static ret_code_t cmd_queue_process(void) -{ - ret_code_t ret; - fds_cmd_t * const p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; - - switch (p_cmd->id) - { - case FDS_CMD_INIT: - ret = init_execute(NRF_SUCCESS, NULL); - break; - - case FDS_CMD_WRITE: - case FDS_CMD_UPDATE: - ret = store_execute(NRF_SUCCESS, p_cmd); - break; - - case FDS_CMD_CLEAR: - case FDS_CMD_CLEAR_INST: - ret = clear_execute(NRF_SUCCESS, p_cmd); - break; - - case FDS_CMD_GC: - ret = gc_execute(NRF_SUCCESS); - break; - - default: - ret = NRF_ERROR_FORBIDDEN; - break; - } - - if ((ret == COMMAND_EXECUTING) || (ret == COMMAND_COMPLETED)) - { - return NRF_SUCCESS; - } - - // This is an error. - return ret; -} - - -static ret_code_t cmd_queue_process_start(void) -{ - bool start_processing = false; - - if (!flag_is_set(FDS_FLAG_PROCESSING)) - { - flag_set(FDS_FLAG_PROCESSING); - start_processing = true; - } - - if (!start_processing) - { - // We are awaiting a callback, so there is no need to manually start queue processing. - return NRF_SUCCESS; - } - - return cmd_queue_process(); -} - - -static void fs_callback(uint8_t op_code, - uint32_t result, - uint32_t const * p_data, - fs_length_t length) -{ - ret_code_t ret; - fds_cmd_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; - fds_record_key_t record_key; - - switch (p_cmd->id) - { - case FDS_CMD_INIT: - ret = init_execute(result, p_data); - break; - - case FDS_CMD_WRITE: - case FDS_CMD_UPDATE: - ret = store_execute(result, p_cmd); - break; - - case FDS_CMD_CLEAR: - case FDS_CMD_CLEAR_INST: - ret = clear_execute(result, p_cmd); - break; - - case FDS_CMD_GC: - ret = gc_execute(result); - break; - - default: - // Should not happen. - ret = NRF_ERROR_INTERNAL; - break; - } - - if (ret == COMMAND_EXECUTING /*=NRF_SUCCESS*/) - { - /** The current command is still being processed. - * The command queue does not need to advance. */ - return; - } - - // Initialize the fds_record_key_t structure needed for the callback. - record_key.type = p_cmd->record_header.tl.type; - record_key.instance = p_cmd->record_header.ic.instance; - - // The command has either completed or an operation (and thus the command) has failed. - if (ret == COMMAND_COMPLETED) - { - // The command has completed successfully. Notify the application. - app_notify(NRF_SUCCESS, p_cmd->id, p_cmd->record_header.id, record_key); - } - else - { - /** An operation has failed. This is fatal for the execution of a command. - * Skip other operations associated with the current command. - * Notify the user of the failure. */ - chunk_queue_skip(p_cmd->num_chunks); - app_notify(ret /*=result*/, p_cmd->id, p_cmd->record_header.id, record_key); - } - - // Advance the command queue, and if there is still something in the queue, process it. - if (cmd_queue_advance()) - { - /** Only process the queue if there are no pending commands being queued, since they - * will begin to process the queue on their own. Be sure to clear - * the flag FDS_FLAG_PROCESSING though ! */ - if (atomic_counter_is_zero()) - { - cmd_queue_process(); - } - else - { - flag_clear(FDS_FLAG_PROCESSING); - } - } - else - { - /** No more elements in the queue. Clear the FDS_FLAG_PROCESSING flag, - * so that new commands can start the queue processing. */ - flag_clear(FDS_FLAG_PROCESSING); - } -} - - -ret_code_t fds_init() -{ - ret_code_t fs_ret; - fds_cmd_t * p_cmd; - uint16_t pages_avail; - bool write_page_tag; - bool resume_compression; - - fds_record_key_t const dummy_key = {.type = FDS_TYPE_ID_INVALID, - .instance = FDS_INSTANCE_ID_INVALID}; - - if (flag_is_set(FDS_FLAG_INITIALIZED)) - { - // Notify immediately. - app_notify(NRF_SUCCESS, FDS_CMD_INIT, 0 /*unused*/, dummy_key /*unused*/); - return NRF_SUCCESS; - } - - if (flag_is_set(FDS_FLAG_INITIALIZING)) - { - return NRF_ERROR_INVALID_STATE; - } - - fs_ret = fs_init(); - if (fs_ret != NRF_SUCCESS) - { - // fs_init() failed, propagate the error. - return fs_ret; - } - - queues_init(); - - /** Initialize the last known record to zero. - * Its value will be updated by page_scan() called in pages_init(). */ - m_last_rec_id = 0; - - // Initialize the page table containing all info on pages (address, type etc). - pages_init(&pages_avail, &write_page_tag, &resume_compression); - - if (pages_avail == 0 && !write_page_tag) - { - return NRF_ERROR_NO_MEM; - } - - /** This flag means fds_init() has been called. However, - * the module is NOT yet initialized. */ - flag_set(FDS_FLAG_INITIALIZING); - - if (resume_compression) - { - return NRF_SUCCESS; - } - - if (write_page_tag) - { - if (queue_reserve(FDS_CMD_QUEUE_SIZE_INIT, 0, &p_cmd, NULL) != NRF_SUCCESS) - { - // Should never happen. - return NRF_ERROR_BUSY; - } - - // Initialize the command in the queue. - p_cmd->id = FDS_CMD_INIT; - - return cmd_queue_process_start(); - } - else - { - /* No flash operation is necessary for initialization. - * We can notify the application immediately. */ - flag_set (FDS_FLAG_INITIALIZED); - flag_clear(FDS_FLAG_INITIALIZING); - app_notify(NRF_SUCCESS, FDS_CMD_INIT, 0 /*unused*/, dummy_key /*unused*/); - } - - return NRF_SUCCESS; -} - - -ret_code_t fds_open(fds_record_desc_t * const p_desc, - fds_record_t * const p_record) -{ - uint16_t page; - - if (p_desc == NULL || p_record == NULL) - { - return NRF_ERROR_NULL; - } - - if (page_id_from_virtual_id(p_desc->vpage_id, &page) != NRF_SUCCESS) - { - // Should not happen. - return NRF_ERROR_INVALID_DATA; - } - - // Seek the record if necessary. - if (seek_record(p_desc) == NRF_SUCCESS) - { - if (header_is_valid((fds_header_t*)p_desc->p_rec)) - { - CRITICAL_SECTION_ENTER(); - m_pages[page].records_open++; - CRITICAL_SECTION_EXIT(); - - p_record->header = *((fds_header_t*)p_desc->p_rec); - p_record->p_data = (p_desc->p_rec + FDS_HEADER_SIZE); - - return NRF_SUCCESS; - } - } - - /** The record could not be found. - * It either never existed or it has been cleared. */ - return NRF_ERROR_NOT_FOUND; -} - - -ret_code_t fds_close(fds_record_desc_t const * const p_desc) -{ - uint16_t page; - - if (p_desc == NULL) - { - return NRF_ERROR_NULL; - } - - if (page_id_from_virtual_id(p_desc->vpage_id, &page) != NRF_SUCCESS) - { - return NRF_ERROR_INVALID_DATA; - } - - CRITICAL_SECTION_ENTER(); - m_pages[page].records_open--; - CRITICAL_SECTION_EXIT(); - - return NRF_SUCCESS; -} - - -static ret_code_t write_enqueue(fds_record_desc_t * const p_desc, - fds_record_key_t key, - uint8_t num_chunks, - fds_record_chunk_t chunks[], - fds_write_token_t const * const p_tok, - bool do_update) -{ - ret_code_t ret; - fds_cmd_t * p_cmd; - fds_record_chunk_t * p_chunk = NULL; - uint16_t vpage_id; - uint16_t length_words = 0; - uint8_t cmd_queue_elems; - - if (!flag_is_set(FDS_FLAG_INITIALIZED)) - { - return NRF_ERROR_INVALID_STATE; - } - - if ((key.type == FDS_TYPE_ID_INVALID) || - (key.instance == FDS_INSTANCE_ID_INVALID)) - { - return NRF_ERROR_INVALID_DATA; - } - - if (!chunk_is_aligned(chunks, num_chunks)) - { - return NRF_ERROR_INVALID_ADDR; - } - - cmd_queue_elems = do_update ? FDS_CMD_QUEUE_SIZE_UPDATE : FDS_CMD_QUEUE_SIZE_WRITE; - - // Reserve space on both queues, and obtain pointers to the first elements reserved. - ret = queue_reserve(cmd_queue_elems, - num_chunks, - &p_cmd, - &p_chunk); - - if (ret != NRF_SUCCESS) - { - return ret; - } - - // No space was previously reserved for this operation. - if (p_tok == NULL) - { - // Compute the total length of the record. - for (uint8_t i = 0; i < num_chunks; i++) - { - length_words += chunks[i].length_words; - } - - /** Find a page where we can write the data. Reserve the space necessary - * to write the metadata as well. */ - ret = write_space_reserve(length_words, &vpage_id); - if (ret != NRF_SUCCESS) - { - // If there is no space available, cancel the queue reservation. - queue_reserve_cancel(cmd_queue_elems, num_chunks); - return ret; - } - } - else - { - length_words = p_tok->length_words; - vpage_id = p_tok->vpage_id; - } - - // Initialize the command. - p_cmd->id = do_update ? FDS_CMD_UPDATE : FDS_CMD_WRITE; - p_cmd->op_code = FDS_OP_WRITE_TL; - p_cmd->num_chunks = num_chunks; - p_cmd->chunk_offset = FDS_WRITE_OFFSET_DATA; - p_cmd->vpage_id = vpage_id; - - // Fill in the header information. - p_cmd->record_header.id = record_id_new(); - p_cmd->record_header.tl.type = key.type; - p_cmd->record_header.tl.length_words = length_words; - p_cmd->record_header.ic.instance = key.instance; - p_cmd->record_header.ic.checksum = 0; - - // Buffer the record chunks in the queue. - for (uint8_t i = 0; i < num_chunks; i++) - { - p_chunk->p_data = chunks[i].p_data; - p_chunk->length_words = chunks[i].length_words; - chunk_queue_next(&p_chunk); - } - - if (do_update) - { - // Clear - cmd_queue_next(&p_cmd); - p_cmd->id = FDS_CMD_CLEAR; - p_cmd->op_code = FDS_OP_CLEAR_TL; - - p_cmd->vpage_id = p_desc->vpage_id; - p_cmd->record_header.id = p_desc->record_id; - } - - // Initialize the record descriptor, if provided. - if (p_desc != NULL) - { - p_desc->vpage_id = vpage_id; - // Don't invoke record_id_new() again. - p_desc->record_id = p_cmd->record_header.id; - } - - return cmd_queue_process_start(); -} - - -ret_code_t fds_reserve(fds_write_token_t * const p_tok, uint16_t length_words) -{ - uint16_t vpage_id; - - if (!flag_is_set(FDS_FLAG_INITIALIZED)) - { - return NRF_ERROR_INVALID_STATE; - } - - if (p_tok == NULL) - { - return NRF_ERROR_NULL; - } - - // Reserve space on the page. write_space_reserve() accounts for the header. - if (write_space_reserve(length_words, &vpage_id) == NRF_SUCCESS) - { - p_tok->vpage_id = vpage_id; - p_tok->length_words = length_words; - - return NRF_SUCCESS; - } - - return NRF_ERROR_NO_MEM; -} - - -ret_code_t fds_reserve_cancel(fds_write_token_t * const p_tok) -{ - fds_page_t * p_page; - - if (!flag_is_set(FDS_FLAG_INITIALIZED)) - { - return NRF_ERROR_INVALID_STATE; - } - - if (p_tok == NULL) - { - return NRF_ERROR_NULL; - } - - if (page_from_virtual_id(p_tok->vpage_id, &p_page) != NRF_SUCCESS) - { - // Could not find the virtual page. This shouldn't happen. - return NRF_ERROR_INVALID_DATA; - } - - if ((p_page->words_reserved - p_tok->length_words) < 0) - { - /** We are trying to cancel a reservation for more words than how many are - * currently reserved on the page. This is shouldn't happen. */ - return NRF_ERROR_INVALID_DATA; - } - - // Free the space which had been reserved. - p_page->words_reserved -= p_tok->length_words; - - // Clean the token. - p_tok->vpage_id = 0; - p_tok->length_words = 0; - - return NRF_SUCCESS; -} - - -ret_code_t fds_write(fds_record_desc_t * const p_desc, - fds_record_key_t key, - uint8_t num_chunks, - fds_record_chunk_t chunks[]) -{ - ret_code_t ret; - atomic_counter_inc(); - ret = write_enqueue(p_desc, key, num_chunks, chunks, NULL, false /*not an update*/); - atomic_counter_dec(); - return ret; -} - - -ret_code_t fds_write_reserved(fds_write_token_t const * const p_tok, - fds_record_desc_t * const p_desc, - fds_record_key_t key, - uint8_t num_chunks, - fds_record_chunk_t chunks[]) -{ - ret_code_t ret; - atomic_counter_inc(); - ret = write_enqueue(p_desc, key, num_chunks, chunks, p_tok, false /*not an update*/); - atomic_counter_dec(); - return ret; -} - - -static ret_code_t clear_enqueue(fds_record_desc_t * const p_desc) -{ - ret_code_t ret; - fds_cmd_t * p_cmd; - - if (!flag_is_set(FDS_FLAG_INITIALIZED)) - { - return NRF_ERROR_INVALID_STATE; - } - - if (p_desc == NULL) - { - return NRF_ERROR_NULL; - } - - ret = queue_reserve(FDS_CMD_QUEUE_SIZE_CLEAR, 0, &p_cmd, NULL); - - if (ret != NRF_SUCCESS) - { - return ret; - } - - // Initialize the command. - p_cmd->id = FDS_CMD_CLEAR; - p_cmd->op_code = FDS_OP_CLEAR_TL; - - p_cmd->record_header.id = p_desc->record_id; - p_cmd->vpage_id = p_desc->vpage_id; - - return cmd_queue_process_start(); -} - - -ret_code_t fds_clear(fds_record_desc_t * const p_desc) -{ - ret_code_t ret; - atomic_counter_inc(); - ret = clear_enqueue(p_desc); - atomic_counter_dec(); - return ret; -} - - -static ret_code_t clear_by_instance_enqueue(fds_instance_id_t instance) -{ - ret_code_t ret; - fds_cmd_t * p_cmd; - - if (!flag_is_set(FDS_FLAG_INITIALIZED)) - { - return NRF_ERROR_INVALID_STATE; - } - - ret = queue_reserve(FDS_CMD_QUEUE_SIZE_CLEAR, 0, &p_cmd, NULL); - - if (ret != NRF_SUCCESS) - { - return ret; - } - - p_cmd->id = FDS_CMD_CLEAR_INST; - p_cmd->op_code = FDS_OP_CLEAR_INSTANCE; - - p_cmd->record_header.ic.instance = instance; - - return cmd_queue_process_start(); -} - -ret_code_t fds_clear_by_instance(fds_instance_id_t instance) -{ - ret_code_t ret; - atomic_counter_inc(); - ret = clear_by_instance_enqueue(instance); - atomic_counter_dec(); - return ret; -} - - -ret_code_t fds_update(fds_record_desc_t * const p_desc, - fds_record_key_t key, - uint8_t num_chunks, - fds_record_chunk_t chunks[]) -{ - ret_code_t ret; - atomic_counter_inc(); - ret = write_enqueue(p_desc, key, num_chunks, chunks, NULL, true /*update*/); - atomic_counter_dec(); - return ret; -} - - -static ret_code_t gc_enqueue() -{ - ret_code_t ret; - fds_cmd_t * p_cmd; - - if (!flag_is_set(FDS_FLAG_INITIALIZED)) - { - return NRF_ERROR_INVALID_STATE; - } - - ret = queue_reserve(FDS_CMD_QUEUE_SIZE_GC, 0, &p_cmd, NULL); - if (ret != NRF_SUCCESS) - { - return ret; - } - - p_cmd->id = FDS_CMD_GC; - - // Set compression parameters. - m_gc.state = BEGIN; - - return cmd_queue_process_start(); -} - - -ret_code_t fds_gc() -{ - ret_code_t ret; - atomic_counter_inc(); - ret = gc_enqueue(); - atomic_counter_dec(); - return ret; -} - - -ret_code_t fds_find(fds_type_id_t type, - fds_instance_id_t instance, - fds_record_desc_t * const p_desc, - fds_find_token_t * const p_token) -{ - if (p_desc == NULL || p_token == NULL) - { - return NRF_ERROR_NULL; - } - - return find_record(&type, &instance, p_desc, p_token); -} - - -ret_code_t fds_find_by_type(fds_type_id_t type, - fds_record_desc_t * const p_desc, - fds_find_token_t * const p_token) -{ - if (p_desc == NULL || p_token == NULL) - { - return NRF_ERROR_NULL; - } - - return find_record(&type, NULL, p_desc, p_token); -} - - -ret_code_t fds_find_by_instance(fds_instance_id_t instance, - fds_record_desc_t * const p_desc, - fds_find_token_t * const p_token) -{ - if (p_desc == NULL || p_token == NULL) - { - return NRF_ERROR_NULL; - } - - return find_record(NULL, &instance, p_desc, p_token); -} - - -ret_code_t fds_register(fds_cb_t cb) -{ - if (m_users == FDS_MAX_USERS) - { - return NRF_ERROR_NO_MEM; - } - - m_cb_table[m_users] = cb; - m_users++; - - return NRF_SUCCESS; -} - - -bool fds_descriptor_match(fds_record_desc_t const * const p_desc1, - fds_record_desc_t const * const p_desc2) -{ - if ((p_desc1 == NULL) || (p_desc2 == NULL)) - { - return false; - } - - return (p_desc1->record_id == p_desc2->record_id); -} - - -ret_code_t fds_descriptor_from_rec_id(fds_record_desc_t * const p_desc, - fds_record_id_t record_id) -{ - if (p_desc == NULL) - { - return NRF_ERROR_NULL; - } - - p_desc->record_id = record_id; - p_desc->vpage_id = FDS_VPAGE_ID_UNKNOWN; - - return NRF_SUCCESS; -} - -ret_code_t fds_record_id_from_desc(fds_record_desc_t const * const p_desc, - fds_record_id_t * const p_record_id) -{ - if (p_desc == NULL || p_record_id == NULL) - { - return NRF_ERROR_NULL; - } - - *p_record_id = p_desc->record_id; - - return NRF_SUCCESS; -}
--- a/source/nordic_sdk/components/libraries/fds/fds.h Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,566 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef FDS_H__ -#define FDS_H__ - -/** - * @defgroup flash_data_storage Flash Data Storage - * @ingroup app_common - * @{ - * @brief Flash Data Storage (FDS). - * - * @details Flash Data Storage (FDS) is a minimalistic filesystem for the on-chip flash. - * It can be used to manipulate @e records, which consist of a piece of data, made up - * of one or more chunks, and an associated key pair. - */ - -#include <stdint.h> -#include <stdbool.h> -#include "sdk_errors.h" - - -/**@brief */ -#define SIZEOF_WORDS(val) (sizeof(val) / 4) - -/**@brief Reserved type key used to flag cleared records. - * May not be used as a record key by the application. */ -#define FDS_TYPE_ID_INVALID (0x0000) -/**@brief Reserved instance key used to check for missing or corrupted metadata. - * May not be used as a record key by the application. */ -#define FDS_INSTANCE_ID_INVALID (0xFFFF) - - -typedef uint32_t fds_record_id_t; -typedef uint16_t fds_type_id_t; -typedef uint16_t fds_length_t; -typedef uint16_t fds_instance_id_t; -typedef uint16_t fds_checksum_t; - - -/**@brief A piece of a record metadata, keeping information about one of its keys (type) and its - * lenght, expressed in 4 byte words. */ -typedef struct -{ - fds_type_id_t type; /**< The record type ID. */ - fds_length_t length_words; /**< Length of the record's data, in 4 byte words. */ -} fds_tl_t; - - -/**@brief A piece of a record metadata, keeping information about one of its keys (instance) and - * its checksum. */ -typedef struct -{ - fds_instance_id_t instance; /**< The record instance ID. */ - fds_checksum_t checksum; /**< Checksum of the entire record, including the metadata. */ -} fds_ic_t; - - -/**@brief The record metadata. */ -typedef struct -{ - fds_tl_t tl; /**< See @ref fds_tl_t. */ - fds_ic_t ic; /**< See @ref fds_ic_t. */ - fds_record_id_t id; /**< The unique record ID (32 bits). */ -} fds_header_t; - - -typedef fds_header_t fds_record_header_t; - -/**@brief The record descriptor structure, used to manipulate a record. - * @note This structure is meant to be opaque to the user, who does not need to access - * any of its fields. - * @note This structure does not need special initialization. - * @warning Do not reuse the same descriptor for different records. If you do, be sure to set - * its fields to zero. */ -typedef struct -{ - uint32_t record_id; /**< The unique record ID. */ - uint32_t const * p_rec; /**< The last known record address in flash. */ - uint16_t vpage_id; /**< The virtual page ID in which the record is stored. */ - uint16_t gc_magic; /**< Number of times the GC algorithm has been run. */ - uint16_t ptr_magic; /**< Used to verify the validity of p_rec. */ -} fds_record_desc_t; - - -/**@brief The record key, used to lookup records. - * @note The uniqueness of either field is not enforced by the system. */ -typedef struct -{ - uint16_t type; - uint16_t instance; -} fds_record_key_t; - - -/**@brief Structure used for reading a record back from flash memory. */ -typedef struct -{ - // TODO: the header should be a pointer. - fds_header_t header; /**< The record header (metadata), as stored in flash. */ - uint32_t const * p_data; /**< The record data. */ -} fds_record_t; - - -/**@brief A record chunk, containing a piece of data to be stored in a record. - * - * @note p_data must be aligned on a (4 bytes) word boundary. - */ -typedef struct -{ - void const * p_data; /**< Pointer to the data to store. Must be word aligned. */ - fds_length_t length_words; /**< Length of data pointed by p_data, in 4 byte words. */ -} fds_record_chunk_t; - - -/**@brief A token to a reserved space in flash, created by @ref fds_reserve. - * Use @ref fds_write_reserved to write the record in the reserved space, - * or @ref fds_reserve_cancel to cancel the reservation. - */ -typedef struct -{ - uint16_t vpage_id; /**< The virtual ID of the page where space was reserved. */ - fds_length_t length_words; /**< The amount of space reserved, in 4 byte words. */ -} fds_write_token_t; - - -/**@brief A token to keep information about the progress of @ref fds_find, @ref fds_find_by_type - * and @ref fds_find_by_instance operations. - * @note This structure is meant to be opaque to the user, who does not need to access any of its - * fields. - * @note The token does not need special initialization. - * @warning Do not reuse the same token to search for different records. If you do, be sure to set - * its fields to zero. */ -typedef struct -{ - uint32_t const * p_addr; - uint32_t magic; - uint16_t vpage_id; -} fds_find_token_t; - - -typedef enum -{ - FDS_CMD_NONE, /**< No command. */ - FDS_CMD_INIT, /**< Module initialization commnad. Used in @ref fds_init */ - FDS_CMD_WRITE, /**< Write command. Used in @ref fds_write and @ref fds_write_reserved. */ - FDS_CMD_UPDATE, /**< Update command. Used in @ref fds_update. */ - FDS_CMD_CLEAR, /**< Clear record command. Used in @ref fds_clear and @ref fds_update. */ - FDS_CMD_CLEAR_INST, /**< Clear instance command. Used in @ref fds_clear_by_instance. */ - FDS_CMD_GC /**< Garbage collection. Used in @ref fds_gc. */ -} fds_cmd_id_t; - - -/**@brief Flash data storage callback function. - * - * @param result Result of the command. - * @param cmd The command associated with the callback. - * @param record_id The unique ID of the record associated with the callback. - * @param record_key The key pair of the record associated with the callback. - */ -typedef void (*fds_cb_t)(ret_code_t result, - fds_cmd_id_t cmd, - fds_record_id_t record_id, - fds_record_key_t record_key); - - -/**@brief Function to register a callback for the module events. - * @details The maximum amount of callback which can be registered can be configured by - * changing the FDS_MAX_USERS macro in fds_config.h. - * - * @param[in] cb The callback function. - * - * - * @retval NRF_SUCCESS Success. - * @retval NRF_ERROR_NO_MEM Error. Maximum number of registered callbacks reached. - */ -ret_code_t fds_register(fds_cb_t cb); - - -/**@brief Function to initialize the module. - * - * @details This function initializes the module and installs the filesystem, if it is not - * installed yet. - * - * @note This function is asynchronous. Completion is reported with a callback through the - * registered event handler. To be able to receive such callback, be sure to call - * @ref fds_register before calling @ref fds_init. - * - * @retval NRF_SUCCESS Success. The command was queued. - * @retval NRF_ERROR_INVALID_STATE Error. The module is currently undergoing initialization. - * @retval NRF_ERROR_NO_MEM Error. Insufficient space to install the filesystem, or - * insufficient resources to perform the installation. - */ -ret_code_t fds_init(void); - - -/**@brief Function to write a record to flash. - * - * @details This function can be used to write a record to flash. A record data consists of - * multiple chunks and is supplied to the function as an array of fds_record_chunk_t - * structures. The maximum lenght of a record data may not exceed the size of one flash - * page minus FDS_HEADER_SIZE words. - * - * @note This function is asynchronous, therefore, completion is reported with a callback - * through the registered event handler. - * - * @note The record data must be aligned on a 4 byte boundary, and because it is not buffered - * internally, it must be kept in memory by the application until the callback for the - * command has been received, i.e., the command completed. - * - * @param[out] p_desc The record descriptor. It may be NULL. - * @param[in] key The record key pair. - * @param[in] num_chunks The number of elements in the chunks array. - * @param[in] chunks An array of chunks making up the record data. - * - * @retval NRF_SUCCESS Success. The command was queued. - * @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized. - * @retval NRF_ERROR_INVALID_DATA Error. The key contains an invalid type or instance. - * @retval NRF_ERROR_INVALID_ADDR Error. The record data is not aligned on a 4 byte boundary. - * @retval NRF_ERROR_INVALID_LENGTH Error. The record length exceeds the maximum lenght. - * @retval NRF_ERROR_BUSY Error. Insufficient internal resources to queue the operation. - * @retval NRF_ERROR_NO_MEM Error. No flash space available to store the record. - */ -ret_code_t fds_write(fds_record_desc_t * const p_desc, - fds_record_key_t key, - uint8_t num_chunks, - fds_record_chunk_t chunks[]); - - -/**@brief Function to reserve space for a record. - * - * @details This function can be used to reserve flash space to store a record, which can be - * later written down using @ref fds_write_reserved. It is possible to cancel a - * reservation by using @ref fds_reserve_cancel. - * - * @param[out] p_tok A token which can be used to write a record in the reserved space - * using @ref fds_write_reserved. - * @param[in] length_words The lenght of the record data, in 4 byte words. - * - * @retval NRF_SUCCESS Success. Flash space was successfully reserved. - * @retval NRF_ERROR_NULL Error. p_tok is NULL. - * @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized. - * @retval NRF_ERROR_NO_MEM Error. Insufficient space. - */ -ret_code_t fds_reserve(fds_write_token_t * const p_tok, uint16_t length_words); - - -/**@brief Function to cancel a space reservation. - * - * @param[in] p_tok The token produced by @ref fds_reserve, identifying the reservation to cancel. - * - * @retval NRF_SUCCESS Success. The reservation was canceled. - * @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized. - * @retval NRF_ERROR_NULL Error. p_tok is NULL. - * @retval NRF_ERROR_INVALID_DATA Error. p_tok contains invalid data. - */ -ret_code_t fds_reserve_cancel(fds_write_token_t * const p_tok); - - -/**@brief Function to write a record to flash, the space for which has been previously reserved - * using @ref fds_reserve. - * - * @details This function behaves similarly to @ref fds_write, with the exception that it never - * fails with NRF_ERROR_NO_MEM. - * - * @note This function is asynchronous, therefore, completion is reported with a callback - * through the registered event handler. - * - * @note The record data must be aligned on a 4 byte boundary, and because it is not buffered - * internally, it must be kept in memory by the application until the callback for the - * command has been received, i.e., the command completed. - * - * @param[in] p_tok The token return by @ref fds_reserve. - * @param[out] p_desc The record descriptor. It may be NULL. - * @param[in] key The record key pair. - * @param[in] num_chunks The number of elements in the chunks array. - * @param[in] chunks An array of chunks making up the record data. - * - * @retval NRF_SUCCESS Success. The command was queued. - * @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized. - * @retval NRF_ERROR_INVALID_DATA Error. The key contains an invalid type or instance. - * @retval NRF_ERROR_INVALID_ADDR Error. The record data is not aligned on a 4 byte boundary. - * @retval NRF_ERROR_INVALID_LENGTH Error. The record length exceeds the maximum lenght. - * @retval NRF_ERROR_BUSY Error. Insufficient internal resources to queue the operation. - */ -ret_code_t fds_write_reserved(fds_write_token_t const * const p_tok, - fds_record_desc_t * const p_desc, - fds_record_key_t key, - uint8_t num_chunks, - fds_record_chunk_t chunks[]); - - -/**@brief Function to clear a record. - * - * @details Clearing a record has the effect of preventing the system from retrieving the record - * descriptor using the @ref fds_find, @ref fds_find_by_type and @ref fds_find_by_instance - * functions. Additionally, @ref fds_open calls shall fail when supplied a descritpor for - * a record which has been cleared. Clearing a record does not free the space it occupies - * in flash. The reclaim flash space used by cleared records, use @ref fds_gc. - * - * @note This function is asynchronous, therefore, completion is reported with a callback - * through the registered event handler. - * - * @param[in] p_desc The descriptor of the record to clear. - * - * @retval NRF_SUCCESS Success. The command was queued. - * @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized. - * @retval NRF_ERROR_NULL Error. p_desc is NULL. - * @retval NRF_ERROR_BUSY Error. Insufficient internal resources to queue the operation. - */ -ret_code_t fds_clear(fds_record_desc_t * const p_desc); - - -/**@brief Function to clear all records with a given instance. - * - * @details Clearing a record has the effect of preventing the system from retrieving the record - * descriptor using the @ref fds_find, @ref fds_find_by_type and @ref fds_find_by_instance - * functions. Additionally, @ref fds_open calls shall fail when supplied a descritpor for - * a record which has been cleared. Clearing a record does not free the space it occupies - * in flash. The reclaim flash space used by cleared records, use @ref fds_gc. - * - * @note This function is asynchronous, therefore, completion is reported with a callback - * through the registered event handler. Only one callback will be issued. The record - * instance ID in the key parameter of the callback will contain the instance ID passed as - * parameter to this function. The record ID parameter will be zero, and the type ID equal - * to FDS_TYPE_ID_INVALID. - * - * @param[in] instance The instance ID of the records to clear. - * - * @retval NRF_SUCCESS Success. The command was queued. - * @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized. - * @retval NRF_ERROR_NULL Error. p_desc is NULL. - * @retval NRF_ERROR_BUSY Error. Insufficient internal resources to queue the operation. - */ -ret_code_t fds_clear_by_instance(fds_instance_id_t instance); - - -/**@brief Function to update an existing record. - * - * @details Updating a record writes a new record with the given key and data in flash, and then - * clears the old record. - * - * @note This function is asynchronous, therefore, completion is reported with a callback - * through the registered event handler. Two callbacks will be issued, one to signal that - * the updated record has been written down, and another to signal that the old one has been - * cleared. - * - * @note The record data must be aligned on a 4 byte boundary, and because it is not buffered - * internally, it must be kept in memory by the application until the callback for the - * command has been received, i.e., the command completed. - * - * @param[in, out] p_desc The descriptor of the record to update. The descriptor of the updated - * record, after the function has returned with NRF_SUCCESS. - * @param[in] key The record new key pair. - * @param[in] num_chunks The number of elements in the chunks array. - * @param[in] chunks An array of chunks making up the record new data. - * - * @retval NRF_SUCCESS Success. The command was queued. - * @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized. - * @retval NRF_ERROR_INVALID_DATA Error. The key contains an invalid type or instance. - * @retval NRF_ERROR_INVALID_ADDR Error. The record data is not aligned on a 4 byte boundary. - * @retval NRF_ERROR_INVALID_LENGTH Error. The record length exceeds the maximum lenght. - * @retval NRF_ERROR_BUSY Error. Insufficient internal resources to queue the operation. - * @retval NRF_ERROR_NO_MEM Error. No flash space available to store the record. - */ -ret_code_t fds_update(fds_record_desc_t * const p_desc, - fds_record_key_t key, - uint8_t num_chunks, - fds_record_chunk_t chunks[]); - - -/**@brief Function to search for records with a given key pair. - * - * @details Because types are not unique, to search for the next record with the given key call - * the function again and supply the same fds_find_token_t structure to resume searching - * from the last record found. - * - * @param[in] type The record type ID. - * @param[in] instance The record instance ID. - * @param[out] p_desc The descriptor of the record found. - * @param[out] p_token A token containing information about the progress of the operation. - * - * @retval NRF_SUCCESS Success. A record was found. - * @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized. - * @retval NRF_ERROR_NULL Error. Either p_desc or p_token are NULL. - * @retval NRF_ERROR_NOT_FOUND Error. No record with the given key pair was found. - */ -ret_code_t fds_find(fds_type_id_t type, - fds_instance_id_t instance, - fds_record_desc_t * const p_desc, - fds_find_token_t * const p_token); - - -/**@brief Function to search for records with a given type. - * - * @details Because types are not unique, to search for the next record with the given key call - * the function again and supply the same fds_find_token_t structure to resume searching - * from the last record found. - * - * @param[in] type The type ID in the record key. - * @param[out] p_desc The descriptor of the record found. - * @param[out] p_token A token containing information about the progress of the operation. - * - * @retval NRF_SUCCESS Success. A record was found. - * @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized. - * @retval NRF_ERROR_NULL Error. Either p_desc or p_token are NULL. - * @retval NRF_ERROR_NOT_FOUND Error. No record with the given type was found. - */ - ret_code_t fds_find_by_type(fds_type_id_t type, - fds_record_desc_t * const p_desc, - fds_find_token_t * const p_token); - - -/**@brief Function to search for records with a given instance. - * - * @details Because types are not unique, to search for the next record with the given key call - * the function again and supply the same fds_find_token_t structure to resume searching - * from the last record found. - * - * @param[in] instance The instance ID in the record key. - * @param[out] p_desc The descriptor of the record found. - * @param[out] p_token A token containing information about the progress of the operation. - * - * @retval NRF_SUCCESS Success. A record was found. - * @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized. - * @retval NRF_ERROR_NULL Error. Either p_desc or p_token are NULL. - * @retval NRF_ERROR_NOT_FOUND Error. No record with the given instance was found. - */ -ret_code_t fds_find_by_instance(fds_instance_id_t instance, - fds_record_desc_t * const p_desc, - fds_find_token_t * const p_token); - - -/**@brief Function to open a record for reading. - * - * @details Function to read a record which has been written to flash. This function initializes - * a fds_record_t structure which can be used to access the record data as well as - * its associated metadata. The pointers provided in the fds_record_t structure are - * pointers to flash memory. Opening a record with @ref fds_open prevents the garbage - * collection to run on the flash page in which record is stored, therefore the contents - * of the memory pointed by the fds_record_t p_data field is guaranteed to remain - * unmodified, as long as the record is kept open. - * - * @note When you are done reading a record, close it using @ref fds_close so that successive - * garbage collections can reclaim space on the page where the record is stored, if necessary. - * - * @param[in] p_desc The descriptor of the record to open. - * @param[out] p_record The record data and metadata, as stored in flash. - * - * @retval NRF_SUCCESS Success. The record was opened. - * @retval NRF_ERROR_NOT_FOUND Error. The record was not found. It may have been cleared, or it - * may have not been written yet. - * @retval NRF_ERROR_INVALID_DATA Error. The descriptor contains invalid data. - * @retval NRF_ERROR_NULL Error. Either p_desc or p_record are NULL. - */ -ret_code_t fds_open(fds_record_desc_t * const p_desc, - fds_record_t * const p_record); - - -/**@brief Function to close a record, after its contents have been read. - * - * @details Closing a record allows garbage collection to be run on the page in which the - * record being closed is stored (if no other records remain open on that page). - * - * @note Closing a record, does NOT invalidate its descriptor, which can be safely supplied to - * all functions which accept a descriptor as a parameter. - * - * @param[in] p_desc The descriptor of the record to close. - * - * @retval NRF_SUCCESS Success. The record was closed. - * @retval NRF_ERROR_NULL Error. p_desc is NULL. - * @retval NRF_ERROR_INVALID_DATA Error. The descriptor contains invalid data. - */ -ret_code_t fds_close(fds_record_desc_t const * const p_desc); - - -/**@brief Function to perform a garbage collection. - * - * @details Garbage collection reclaims the flash space occupied by records which have been cleared - * using @ref fds_clear. - * - * @note This function is asynchronous, therefore, completion is reported with a callback - * through the registered event handler. - */ -ret_code_t fds_gc(void); - - -/**@brief Function to compare two record descriptors. - * - * @param[in] p_desc_one First descriptor. - * @param[in] p_desc_two Second descriptor. - * - * @retval true If the descriptors identify the same record. - * @retval false Otherwise. - */ -bool fds_descriptor_match(fds_record_desc_t const * const p_desc_one, - fds_record_desc_t const * const p_desc_two); - - -/**@brief Function to obtain a descriptor from a record ID. - * - * @details This function can be used to reconstruct a descriptor from a record ID, such as the - * one passed to the callback function. - * - * @warning This function does not check if a record with the given record ID exists or not. If a - * non-existing record ID is supplied, the resulting descriptor will cause other functions - * to fail when used as parameter. - * - * @param[out] p_desc The descriptor of the record with given record ID. - * @param[in] record_id The record ID for which to provide a descriptor. - * - * @retval NRF_SUCCESS Success. - * @retval NRF_ERROR_NULL Error. p_desc is NULL. - */ -ret_code_t fds_descriptor_from_rec_id(fds_record_desc_t * const p_desc, - fds_record_id_t record_id); - -/**@brief Function to obtain a record ID from a record descriptor. - * - * @details This function can be used to extract a record ID from a descriptor. It may be used - * in the callback function to determine which record the callback is associated to, if - * you have its descriptor. - * - * @warning This function does not check the record descriptor sanity. If the descriptor is - * uninitialized, or has been tampered with, the resulting record ID may be invalid. - * - * @param[in] p_desc The descriptor from which to extract the record ID. - * @param[out] p_record_id The record ID contained in the given descriptor. - * - * @retval NRF_SUCCESS Success. - * @retval NRF_ERROR_NULL Error. Either p_desc is NULL or p_record_id is NULL. - */ -ret_code_t fds_record_id_from_desc(fds_record_desc_t const * const p_desc, - fds_record_id_t * const p_record_id); - -/** @} */ - -#endif // FDS_H__ \ No newline at end of file
--- a/source/nordic_sdk/components/libraries/fds/fds_config.h Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef FDS_CONFIG_H__ -#define FDS_CONFIG_H__ - - /** - * @file fds_config.h - * - * @addtogroup flash_data_storage - * @{ - */ - -/**@brief Configures the size of the internal queue. */ -#define FDS_CMD_QUEUE_SIZE (8) -/**@brief Determines how many @ref fds_record_chunk_t structures can be buffered at any time. */ -#define FDS_CHUNK_QUEUE_SIZE (8) - -/**@brief Configures the number of physical flash pages to use. Out of the total, one is reserved - * for garbage collection, hence, two pages is the minimum: one for the application data - * and one for the system. */ -#define FDS_MAX_PAGES (2) -/**@brief Configures the maximum number of callbacks which can be registred. */ -#define FDS_MAX_USERS (10) - -/** Page tag definitions. */ -#define FDS_PAGE_TAG_WORD_0_SWAP (0xA5A5A5A5) -#define FDS_PAGE_TAG_WORD_0_VALID (0xA4A4A4A4) -#define FDS_PAGE_TAG_WORD_1 (0xAABBCCDD) -#define FDS_PAGE_TAG_WORD_2 (0xAABB01DD) /**< Includes version. */ -#define FDS_PAGE_TAG_WORD_3 (0x1CEB00DA) -#define FDS_PAGE_TAG_WORD_3_GC (0x1CEB00D8) - -/** @} */ - -#endif // FDS_CONFIG_H__ \ No newline at end of file
--- a/source/nordic_sdk/components/libraries/fds/fds_types_internal.h Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,178 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef FDS_TYPES_INTERNAL__ -#define FDS_TYPES_INTERNAL__ - -#include "fds.h" -#include <stdint.h> -#include <stdbool.h> -#include "nrf_soc.h" - - -#define COMMAND_EXECUTING (NRF_SUCCESS) -#define COMMAND_COMPLETED (0x1234) -//#define COMMAND_FAILED (0x1236) - -#define FDS_MAGIC_HWORD (0xF11E) -#define FDS_MAGIC_WORD (0x15ABE11A) -#define FDS_ERASED_WORD (0xFFFFFFFF) - -#define FDS_PAGE_TAG_SIZE (4) /**< Page tag size, in 4 byte words. */ - -#define FDS_VPAGE_ID_UNKNOWN (0xFFFF) - -#define FDS_WRITE_OFFSET_TL (0) /**< Offset of TL from the record base address, in 4 byte words. */ -#define FDS_WRITE_OFFSET_IC (1) /**< Offset of IC from the record base address, in 4 byte words. */ -#define FDS_WRITE_OFFSET_ID (2) /**< Offset of ID from the record base address, in 4 byte words. */ -#define FDS_WRITE_OFFSET_DATA (3) /**< Offset of the data (chunks) from the record base address, in 4 byte words. */ - -#define FDS_HEADER_SIZE_TL (1) /**< Size of the TL part of the header, in 4 byte words. */ -#define FDS_HEADER_SIZE_ID (1) /**< Size of the IC part of the header, in 4 byte words. */ -#define FDS_HEADER_SIZE_IC (1) /**< Size of the IC part of the header, in 4 byte words. */ -#define FDS_HEADER_SIZE (3) /**< Size of the whole header, in 4 byte words. */ - -#define FDS_CMD_QUEUE_SIZE_INIT (1) -#define FDS_CMD_QUEUE_SIZE_WRITE (1) -#define FDS_CMD_QUEUE_SIZE_CLEAR (1) -#define FDS_CMD_QUEUE_SIZE_UPDATE (2) -#define FDS_CMD_QUEUE_SIZE_GC (1) - - -static uint8_t m_nested_critical; - -/** Macros to enable and disable application interrupts. */ -#define CRITICAL_SECTION_ENTER() //sd_nvic_critical_region_enter(&m_nested_critical) -#define CRITICAL_SECTION_EXIT() //sd_nvic_critical_region_exit ( m_nested_critical) - -/**@brief Page types. */ -typedef enum -{ - FDS_PAGE_UNDEFINED, /**< Undefined page type. */ - FDS_PAGE_ERASED, /**< Page is erased. */ - FDS_PAGE_VALID, /**< Page is ready for storage. */ - FDS_PAGE_SWAP, /**< Page is reserved for GC. */ - FDS_PAGE_GC /**< Page is being garbage collected. */ -} fds_page_type_t; - - -typedef enum -{ - FDS_OP_NONE = 0x00, /**< No operation. */ - FDS_OP_WRITE_TL, /**< Write the type and length. */ - FDS_OP_WRITE_ID, /**< Write the record ID. */ - FDS_OP_WRITE_CHUNK, /**< Write the record value. */ - FDS_OP_WRITE_IC, /**< Write the instance and checksum. */ - FDS_OP_CLEAR_TL, - FDS_OP_CLEAR_INSTANCE, - FDS_OP_DONE, -} fds_opcode_t; - - -typedef enum -{ - FDS_FLAG_INITIALIZING = (1 << 0), /**< TODO: Not really needed atm? */ - FDS_FLAG_INITIALIZED = (1 << 1), /**< Flag indicating that flash data storage has been initialized. */ - FDS_FLAG_PROCESSING = (1 << 2), /**< Flag indicating that queue is being processed. */ - FDS_FLAG_CAN_GC = (1 << 3), /**< Flag indicating that fds can regain data by performing garbage collection. */ -} fds_flags_t; - - -typedef struct -{ - uint32_t const * start_addr; - uint16_t vpage_id; /**< The page logical ID. */ - uint16_t volatile write_offset; /**< The page write offset, in 4 bytes words. */ - uint16_t volatile words_reserved; /**< The amount of words reserved by fds_write_reserve() on this page. */ - uint16_t volatile records_open; - fds_page_type_t page_type : 4; /**< The page type. */ -} fds_page_t; - - -typedef struct -{ - fds_cmd_id_t id : 4; /**< The ID of the command. */ - fds_opcode_t op_code : 4; - uint8_t num_chunks; /**< Number of operations this command has left in the operation queue. */ - uint16_t chunk_offset; /**< Offset used for writing the record value(s), in 4 byte words. */ - uint16_t vpage_id; /**< The virtual page ID where we reserved the flash space for this command. */ - fds_record_header_t record_header; -} fds_cmd_t; - - -/**@brief Defines command queue, an element is free if the op_code field is not invalid. - * - * @details Defines commands enqueued for flash access. At any point in time, this queue has one or - * more flash access operations pending if the count field is not zero. When the queue is - * not empty, the rp (read pointer) field points to the flash access command in progress - * or, if none is in progress, the command to be requested next. The queue implements a - * simple first in first out algorithm. Data addresses are assumed to be resident. - */ -typedef struct -{ - fds_cmd_t cmd[FDS_CMD_QUEUE_SIZE]; /**< Array to maintain flash access operation details. */ - uint8_t volatile rp; /**< The index of the command being executed. */ - uint8_t volatile count; /**< Number of elements in the queue. */ -} fds_cmd_queue_t; - - -typedef struct -{ - fds_record_chunk_t chunk[FDS_CHUNK_QUEUE_SIZE]; - uint8_t volatile rp; - uint8_t volatile count; -} fds_chunk_queue_t; - - -typedef enum -{ - NONE, - BEGIN, - RESUME, - GC_PAGE, - COPY_RECORD, - READY_SWAP, - NEW_SWAP, - INIT_SWAP -} fds_gc_state_t; - - -typedef struct -{ - uint16_t cur_page; - uint16_t swap_page; - uint32_t const * p_scan_addr; - fds_gc_state_t state; - bool do_gc_page[FDS_MAX_PAGES]; -} fds_gc_data_t; - -#endif // FDS_TYPES_INTERNAL__ \ No newline at end of file
--- a/source/nordic_sdk/components/libraries/fstorage/fstorage.c Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,569 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "fstorage.h" -#include <stdio.h> -#include <string.h> -#include <stdbool.h> -#include "fstorage_config.h" -#include "nrf_error.h" -#include "nrf_soc.h" - - -#define FS_FLAG_INIT (1 << 0) /**< fstorage has been initialized. */ -#define FS_FLAG_PROCESSING (1 << 1) /**< fstorage is executing queued flash operations. */ -#define FS_FLAG_FLASH_REQ_PENDING (1 << 2) /**< fstorage is waiting for a flash operation initiated by another module to complete. */ - - -/**@brief Macro invocation that registers section fs_data. - * - * @details Required for compilation. - */ -NRF_SECTION_VARS_REGISTER_SECTION(fs_data); - - -/**@brief Macro invocation that declares symbols used to find the beginning and end of the section fs_data. - * - * @details Required for compilation. - */ -NRF_SECTION_VARS_REGISTER_SYMBOLS(fs_config_t, fs_data); - - -/**@defgroup Section vars helper macros. - * - * @details Macros used to manipulate registered section variables. - */ - /**@brief Get section variable with fstorage configuration by index. */ -#define FS_SECTION_VARS_GET(i) NRF_SECTION_VARS_GET(i, fs_config_t, fs_data) - /**@brief Get the number of registered section variables. */ -#define FS_SECTION_VARS_COUNT NRF_SECTION_VARS_COUNT(fs_config_t, fs_data) - /**@brief Get the start address of the registered section variables. */ -#define FS_SECTION_VARS_START_ADDR NRF_SECTION_VARS_START_ADDR(fs_data) - /**@brief Get the end address of the registered section variables. */ -#define FS_SECTION_VARS_END_ADDR NRF_SECTION_VARS_END_ADDR(fs_data) - -/** @} */ - - -/**@brief The command queue element. - * - * @details Encapsulate details of a command requested to this module. - */ -typedef struct -{ - fs_config_t const * p_config; /**< The configuration of the user who requested the operation. */ - uint8_t op_code; /**< Operation code. */ - 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. */ - uint32_t const * p_addr; /**< Destination of the data in flash. */ - fs_length_t length_words; /**< Length of the operation */ - fs_length_t offset; /**< Offset of the operation if operation is done in chunks */ -} fs_cmd_t; - - -/**@brief Structure that defines the command queue - * - * @details This queue holds flash operations requested to the module. - * The data to be written must be kept in memory until the write operation is completed, - * i.e., a callback indicating completion is received by the application. - */ -typedef struct -{ - uint8_t rp; /**< The current element being processed. */ - uint8_t count; /**< Number of elements in the queue. */ - fs_cmd_t cmd[FS_CMD_QUEUE_SIZE]; /**< Array to maintain flash access operation details. */ -} fs_cmd_queue_t; - - -static uint8_t m_flags; /**< FStorage status flags. */ -static fs_cmd_queue_t m_cmd_queue; /**< Flash operation request queue. */ -static uint16_t m_retry_count = 0; /**< Number of times a single flash operation was retried. */ - - -// Function prototypes -static ret_code_t queue_process(void); -static ret_code_t queue_process_impl(void); -static void app_notify(uint32_t result, fs_cmd_t const * p_cmd); - - -/**@brief Macro to check that the configuration is non-NULL and within -* valid section variable memory bounds. - * - * @param[in] config Configuration to check. - */ -#define FS_CHECK_CONFIG(config) \ - ((FS_SECTION_VARS_START_ADDR < config) && (config < FS_SECTION_VARS_END_ADDR)) - - -/**@brief Function to check that the configuration is non-NULL and within -* valid section variable memory bounds. - * - * @param[in] config Configuration to check. - */ -static bool check_config(fs_config_t const * const config) -{ - if (config == NULL) - { - return false; - } - - if ((FS_SECTION_VARS_START_ADDR <= (uint32_t)config) && ((uint32_t)config < FS_SECTION_VARS_END_ADDR)) - { - return true; - } - else - { - return false; - } -} - - -/**@brief Function to initialize the queue. */ -static void queue_init(void) -{ - memset(&m_cmd_queue, 0, sizeof(fs_cmd_queue_t)); -} - - -/**@brief Function to reset a queue item to its default values. - * - * @param index Index of the queue element. - */ -static void cmd_reset(uint32_t index) -{ - memset(&m_cmd_queue.cmd[index], 0, sizeof(fs_cmd_t)); -} - - -/**@brief Function to enqueue flash access command - * - * @param[in] config Registered configuration. - * @param[in] op_code Operation code. - * @param[in] address Destination of the data. - * @param[in] p_src Source of data or NULL if n/a. - * @param[in] length Length of the data, in 4 byte words. - * - * @retval NRF_SUCCESS Success. Command enqueued. - * @retval NRF_ERROR_NO_MEM Error. Queue is full. - * @retval Any error returned by the SoftDevice flash API. - */ -static ret_code_t cmd_enqueue(fs_config_t const * p_config, - uint8_t op_code, - uint32_t const * p_addr, - uint32_t const * p_src, - fs_length_t length_words) -{ - fs_cmd_t * p_cmd; - uint8_t write_pos; - - if (m_cmd_queue.count == FS_CMD_QUEUE_SIZE - 1) - { - return NRF_ERROR_NO_MEM; - } - - write_pos = (m_cmd_queue.rp + m_cmd_queue.count) % FS_CMD_QUEUE_SIZE; - - p_cmd = &m_cmd_queue.cmd[write_pos]; - - p_cmd->p_config = p_config; - p_cmd->op_code = op_code; - p_cmd->p_src = p_src; - p_cmd->p_addr = p_addr; - p_cmd->length_words = length_words; - - m_cmd_queue.count++; - - return queue_process(); -} - - -/**@brief Function to consume queue item and notify the return value of the operation. - * - * @details This function will report the result and remove the command from the queue after - * notification. - */ -static void cmd_consume(uint32_t result, const fs_cmd_t * p_cmd) -{ - // Consume the current item on the queue. - uint8_t rp = m_cmd_queue.rp; - - m_cmd_queue.count--; - if (m_cmd_queue.count == 0) - { - // There are no elements left. Stop processing the queue. - m_flags &= ~FS_FLAG_PROCESSING; - } - - if (++(m_cmd_queue.rp) == FS_CMD_QUEUE_SIZE) - { - m_cmd_queue.rp = 0; - } - - // Notify upon successful operation. - app_notify(result, p_cmd); - - // Reset the queue element. - cmd_reset(rp); -} - - -/**@brief Function to store data to flash. - * - * @param[in] p_cmd The queue element associated with the operation. - * - * @retval NRF_SUCCESS Success. The request was sent to the SoftDevice. - * @retval Any error returned by the SoftDevice flash API. - */ -static __INLINE uint32_t store_execute(fs_cmd_t const * const p_cmd) -{ - // Write in chunks if write-size is larger than FS_MAX_WRITE_SIZE. - fs_length_t const length = ((p_cmd->length_words - p_cmd->offset) < FS_MAX_WRITE_SIZE_WORDS) ? - (p_cmd->length_words - p_cmd->offset) : FS_MAX_WRITE_SIZE_WORDS; - - return sd_flash_write((uint32_t*)p_cmd->p_addr + p_cmd->offset /* destination */, - (uint32_t*)p_cmd->p_src + p_cmd->offset /* source */, - length); -} - - -/**@brief Function to erase a page. - * - * @param[in] p_cmd The queue element associated with the operation. - * - * @retval NRF_SUCCESS Success. The request was sent to the SoftDevice. - * @retval Any error returned by the SoftDevice flash API. - */ -static __INLINE uint32_t erase_execute(fs_cmd_t const * const p_cmd) -{ - // Erase the page. - return sd_flash_page_erase((uint32_t)(p_cmd->p_addr + p_cmd->offset) / FS_PAGE_SIZE); -} - - -/**@brief Function to process the current element in the queue and return the result. - * - * @retval NRF_SUCCESS Success. - * @retval NRF_ERROR_FORBIDDEN Error. Undefined command. - * @retval Any error returned by the SoftDevice flash API. - */ -static uint32_t queue_process_impl(void) -{ - uint32_t ret; - - fs_cmd_t const * const p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; - - switch (p_cmd->op_code) - { - case FS_OP_STORE: - ret = store_execute(p_cmd); - break; - - case FS_OP_ERASE: - ret = erase_execute(p_cmd); - break; - - case FS_OP_NONE: - ret = NRF_SUCCESS; - break; - - default: - ret = NRF_ERROR_FORBIDDEN; - break; - } - - return ret; -} - - -/**@brief Starts processing the queue if there are no pending flash operations - * for which we are awaiting a callback. - */ -static ret_code_t queue_process(void) -{ - ret_code_t ret = NRF_SUCCESS; - - /** If the queue is not being processed, and there are still - * some elements in it, then start processing. */ - if ( !(m_flags & FS_FLAG_PROCESSING) && - (m_cmd_queue.count > 0)) - { - m_flags |= FS_FLAG_PROCESSING; - - ret = queue_process_impl(); - - /** There is ongoing flash-operation which was not - * initiated by fstorage. */ - if (ret == NRF_ERROR_BUSY) - { - // Wait for a system callback. - m_flags |= FS_FLAG_FLASH_REQ_PENDING; - - // Stop processing the queue. - m_flags &= ~FS_FLAG_PROCESSING; - - ret = NRF_SUCCESS; - } - else if (ret != NRF_SUCCESS) - { - // Another error has occurred. - app_notify(ret, &m_cmd_queue.cmd[m_cmd_queue.rp]); - } - } - - // If we are already processing the queue, return immediately. - return ret; -} - - -/**@brief Flash operation success callback handler. - * - * @details This function updates read/write pointers. - * This function resets retry count. - */ -static __INLINE void on_operation_success(void) -{ - fs_cmd_t * const p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; - - m_retry_count = 0; - - switch (p_cmd->op_code) - { - case FS_OP_STORE: - // Update the offset on successful write. - p_cmd->offset += FS_MAX_WRITE_SIZE_WORDS; - break; - - case FS_OP_ERASE: - // Update the offset to correspond to the page that has been erased. - p_cmd->offset += FS_PAGE_SIZE_WORDS; - break; - } - - // If offset is equal to or larger than length, then the operation has finished. - if (p_cmd->offset >= p_cmd->length_words) - { - cmd_consume(NRF_SUCCESS, p_cmd); - } - - queue_process(); -} - - -/**@brief Flash operation failure callback handler. - * - * @details Function to keep track of retries and notify failures. - */ -static __INLINE void on_operation_failure(uint32_t sys_evt) -{ - const fs_cmd_t * p_cmd; - - if (++m_retry_count > FS_CMD_MAX_RETRIES) - { - p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; - cmd_consume(NRF_ERROR_TIMEOUT, p_cmd); - } - - queue_process(); -} - - -/**@brief Function to notify users. - * - * @param[in] result Result of the flash operation. - * @param[in] p_cmd The command associated with the callback. - */ -static void app_notify(uint32_t result, fs_cmd_t const * const p_cmd) -{ - p_cmd->p_config->cb(p_cmd->op_code, result, p_cmd->p_addr, p_cmd->length_words); -} - - -ret_code_t fs_init(void) -{ - uint16_t lowest_index = 0; - uint16_t lowest_order = 0xFFFF; - uint32_t * current_end = (uint32_t*)FS_PAGE_END_ADDR; - uint32_t num_left = FS_SECTION_VARS_COUNT; - - queue_init(); - - /** Assign pages to registered users, beginning with the ones with the lowest - * order, which will be assigned pages with the lowest memory address. */ - do - { - fs_config_t * p_config; - for (uint16_t i = 0; i < FS_SECTION_VARS_COUNT; i++) - { - p_config = FS_SECTION_VARS_GET(i); - - // Skip the ones which have the end-address already set. - if (p_config->p_end_addr != NULL) - continue; - - if (p_config->page_order < lowest_order) - { - lowest_order = p_config->page_order; - lowest_index = i; - } - } - - p_config = FS_SECTION_VARS_GET(lowest_index); - - p_config->p_end_addr = current_end; - p_config->p_start_addr = p_config->p_end_addr - (p_config->num_pages * FS_PAGE_SIZE_WORDS); - - current_end = p_config->p_start_addr; - lowest_order = 0xFFFF; - - } while ( --num_left > 0 ); - - m_flags |= FS_FLAG_INIT; - - return NRF_SUCCESS; -} - - -ret_code_t fs_store(fs_config_t const * p_config, - uint32_t const * p_addr, - uint32_t const * const p_data, - fs_length_t length_words) -{ - if ((m_flags & FS_FLAG_INIT) == 0) - { - return NRF_ERROR_INVALID_STATE; - } - - if (!check_config(p_config)) - { - return NRF_ERROR_FORBIDDEN; - } - - if (!is_word_aligned(p_addr)) - { - return NRF_ERROR_INVALID_ADDR; - } - - // Check that the erase operation is on pages owned by this user (configuration). - if ((p_addr < p_config->p_start_addr) || ((p_addr + length_words) > p_config->p_end_addr)) - { - return NRF_ERROR_INVALID_ADDR; - } - - return cmd_enqueue(p_config, FS_OP_STORE, p_addr, p_data, length_words); -} - - -ret_code_t fs_erase(fs_config_t const * p_config, - uint32_t * const p_addr, - fs_length_t const length_words) -{ - if ((m_flags & FS_FLAG_INIT) == 0) - { - return NRF_ERROR_INVALID_STATE; - } - - if (!check_config(p_config)) - { - return NRF_ERROR_FORBIDDEN; - } - - /** Check that the address is aligned on a page boundary and the length to erase - * is a multiple of the page size. */ - if (((uint32_t)p_addr & (FS_PAGE_SIZE - 1)) || - (length_words & (FS_PAGE_SIZE_WORDS - 1))) - { - return NRF_ERROR_INVALID_ADDR; - } - - // Check that the erase operation is on pages owned by this user (configuration). - if ((p_addr < p_config->p_start_addr) || ((p_addr + length_words) > p_config->p_end_addr)) - { - return NRF_ERROR_INVALID_ADDR; - } - - return cmd_enqueue(p_config, FS_OP_ERASE, p_addr, NULL, length_words); -} - - -/**@brief Function to handle system events from the SoftDevice. - * - * @details This function should be dispatched system events if any of the modules used by - * the application rely on FStorage. Examples include @ref Peer Manager and - * @ref Flash Data Storage. - * - * @param[in] sys_evt System Event received. - */ -void fs_sys_event_handler(uint32_t sys_evt) -{ - if (m_flags & FS_FLAG_PROCESSING) - { - /** A flash operation was initiated by this module. - * Handle its result. */ - switch (sys_evt) - { - case NRF_EVT_FLASH_OPERATION_SUCCESS: - on_operation_success(); - break; - - case NRF_EVT_FLASH_OPERATION_ERROR: - on_operation_failure(sys_evt); - break; - } - } - else if ((m_flags & FS_FLAG_FLASH_REQ_PENDING)) - { - /** A flash operation was initiated outside this module. - * We have now receveid a callback which indicates it has - * finished. Clear the FS_FLAG_FLASH_REQ_PENDING flag. */ - m_flags &= ~FS_FLAG_FLASH_REQ_PENDING; - - // Resume processing the queue, if necessary. - queue_process(); - } -} - - -// Just for testing out section vars (across many compilers). -void fs_debug_print() -{ - printf("fs start address: 0x%08lx\r\n", (unsigned long)FS_SECTION_VARS_START_ADDR); - printf("fs end address: 0x%08lx\r\n", (unsigned long)FS_SECTION_VARS_END_ADDR); - printf("Num items: 0x%08lx\r\n", (unsigned long)FS_SECTION_VARS_COUNT); - printf("===== ITEMS %lu =====\r\n", (unsigned long)FS_SECTION_VARS_COUNT); - - for(int i = 0; i < FS_SECTION_VARS_COUNT; i++) - { - fs_config_t* config = FS_SECTION_VARS_GET(i); - printf( "Address: 0x%08lx, CB: 0x%08lx\r\n", - (unsigned long)config, (unsigned long)config->cb ); - } - printf("\r\n"); -} \ No newline at end of file
--- a/source/nordic_sdk/components/libraries/fstorage/fstorage.h Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,176 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - - -#ifndef FS_H__ -#define FS_H__ - - /** @file - * - * @defgroup fstorage FStorage - * @{ - * @ingroup app_common - * @brief Module which provides low level functionality to store data to flash. - * - */ - - -#include <stdint.h> -#include "section_vars.h" -#include "fstorage_config.h" -#include "sdk_errors.h" - - -typedef uint16_t fs_length_t; - - -typedef enum -{ - FS_OP_NONE = 0, - FS_OP_STORE = 1, - FS_OP_ERASE = 2 -} fs_oper_t; - - -/**@brief Callback for flash operations. - * - * @param[in] op_code Flash access operation code. - * @param[in] result Result of the operation. - * @param[in] data Pointer to resulting data (or NULL if not in use). - * @param[in] length_words Length of data in words. - */ -typedef void (*fs_cb_t)(uint8_t op_code, - uint32_t result, - uint32_t const * p_data, - fs_length_t length_words); - - -/**@brief Function prototype for a callback handler. - * - * @details This function is expected to be implemented by the module that - * registers for fstorage usage. Its usage is described - * in the function pointer type fs_cb_t. - * - * @param[in] op_code Flash operation code. - * @param[in] result Result of the flash operation. - * @param[in] p_data Pointer to the resulting data (or NULL if not in use). - * @param[in] length_words Length of data in words. - */ -static void fs_callback(uint8_t op_code, - uint32_t result, - uint32_t const * p_data, - fs_length_t length_words); - - -/**@brief Flash storage config variable. - * - * @details The fstorage module will update the start_addr and end_address according to - * ordering rules and the number of pages requested by the fstorage module user. - */ -typedef struct -{ - const fs_cb_t cb; /**< Callback to run when flash operation has completed. */ - const uint8_t num_pages; /**< The number of pages to reserve for flash storage. */ - const uint8_t page_order; /**< The order used to allocate pages. */ - uint32_t * p_start_addr; /**< Pointer to the start address of the allocated flash storage. Set by running @ref fs_init. */ - uint32_t * p_end_addr; /**< Pointer to the end address of the allcoated flash storage. Set by running @ref fs_init. */ -} fs_config_t; - - -/**@brief Macro for registering of flash storage configuration variable. - * - * @details This macro is expected to be invoked in the code unit that that require - * flash storage. Invoking this places the registered configuration variable - * in a section named "fs_data" that the fstorage module uses during initialization - * and regular operation. - */ -#define FS_SECTION_VARS_ADD(type_def) NRF_SECTION_VARS_ADD(fs_data, type_def) - - -/**@brief Function to initialize FStorage. - * - * @details This function allocates flash data pages according to the - * number requested in the config variable. The data used to initialize. - * the fstorage is section placed variables in the data section "fs_data". - */ -ret_code_t fs_init(void); - - -/**@brief Function to store data in flash. - * - * @warning The data to be written to flash has to be kept in memory until the operation has - * terminated, i.e., a callback is received. - * - * @param[in] p_config Const pointer to configiguration of module user that requests a store operation. - * @param[in] p_addr Write address of store operation. - * @param[in] p_data Pointer to the data to store. - * @param[in] length_words Length of the data to store. - * - * @retval NRF_SUCCESS Success. Command queued. - * @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized. - * @retval NRF_ERROR_INVALID_ADDR Error. Data is unaligned or invalid configuration. - * @retval Any error returned by the SoftDevice flash API. - */ -ret_code_t fs_store(fs_config_t const * p_config, - uint32_t const * p_addr, - uint32_t const * const p_data, - fs_length_t length_words); - - -/** Function to erase a page in flash. - * - * @note The erase address must be aligned on a page boundary. The length in words must be - * equivalent to the page size. - * - * @param[in] p_config Pointer to the configuration of the user that requests the operation. - * @param[in] p_addr Address of page to erase (the same as first word in the page). - * @param[in] length_words Length (in 4 byte words) of the area to erase. - * - * @retval NRF_SUCCESS Success. Command queued. - * @retval NRF_ERROR_INVALID_STATE Error. The module is not initialized. - * @retval NRF_ERROR_INVALID_ADDR Error. Data is unaligned or invalid configuration. - * @retval Any error returned by the SoftDevice flash API. - */ -ret_code_t fs_erase(fs_config_t const * p_config, - uint32_t * const p_addr, - fs_length_t length_words); - - -/**@brief Function to call to handle events from the SoftDevice - * - * @param sys_evt System event from the SoftDevice - */ -void fs_sys_event_handler(uint32_t sys_evt); - -/** @} */ - -#endif // FS_H__ \ No newline at end of file
--- a/source/nordic_sdk/components/libraries/fstorage/fstorage_config.h Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef FS_CONFIG_H__ -#define FS_CONFIG_H__ - -#include <stdint.h> -#include "nrf.h" - -/** - * @defgroup fstorage_config FStorage configuration - * @ingroup fstorage - * @{ - * @brief FStorage configuration. - */ - - -/**@brief Macro for max number of operations in the fs cmd queue. - */ -#define FS_CMD_QUEUE_SIZE (8) - - -/**@brief Macro for max number of retries for a flash command before it notifies as failed. - */ -#define FS_CMD_MAX_RETRIES (3) - - -/**@brief Macro for the content of a flash address that has not been written to. - */ -#define FS_EMPTY_MASK (0xFFFFFFFF) - - -/**@brief Macro for flash page size according to chip family - */ -#if defined (NRF51) - #define FS_PAGE_SIZE (1024) -#elif defined (NRF52) - #define FS_PAGE_SIZE (4096) -#else - #error "Device family must be defined. See nrf.h." -#endif - - -/*@brief Macro for flash page size according to chip family -*/ -#define FS_PAGE_SIZE_WORDS (FS_PAGE_SIZE/4) - - -/**@brief Static inline function that provides last page address - * - * @note If there is a bootloader present the bootloader address read from UICR - * will act as the page beyond the end of the available flash storage - */ -static __INLINE uint32_t fs_flash_page_end_addr() -{ - uint32_t const bootloader_addr = NRF_UICR->NRFFW[0]; - return ((bootloader_addr != FS_EMPTY_MASK) ? - bootloader_addr : NRF_FICR->CODESIZE * FS_PAGE_SIZE); -} - - -/**@brief Macro for last page address - * - * @note If there is a bootloader present the bootloader address read from UICR - * will act as the page beyond the end of the available flash storage - */ -#define FS_PAGE_END_ADDR fs_flash_page_end_addr() - - -/**@brief Macro to describe the write - * - */ -#if defined (NRF51) - #define FS_MAX_WRITE_SIZE_WORDS (256) -#elif defined (NRF52) - #define FS_MAX_WRITE_SIZE_WORDS (1024) -#else - #error "Device family must be defined. see nrf.h" -#endif - -/** @} */ - -#endif // FS_CONFIG_H__
--- a/source/nordic_sdk/components/libraries/fstorage/fstorage_nosd.c Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */
--- a/source/nordic_sdk/components/libraries/util/sdk_mapped_flags.c Thu Apr 07 17:38:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,181 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of other - * contributors to this software may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "sdk_mapped_flags.h" -#include <stdint.h> -#include <stdbool.h> -#include <stddef.h> -#include "compiler_abstraction.h" - - -/**@brief Function for setting the state of a flag to true. - * - * @note This function does not check whether the index is valid. - * - * @param[in] p_flags The collection of flags to modify. - * @param[in] index The index of the flag to modify. - */ -static __INLINE void sdk_mapped_flags_set_by_index(sdk_mapped_flags_t * p_flags, uint16_t index) -{ - *p_flags |= (1U << index); -} - - -/**@brief Function for setting the state of a flag to false. - * - * @note This function does not check whether the index is valid. - * - * @param[in] p_flags The collection of flags to modify. - * @param[in] index The index of the flag to modify. - */ -static __INLINE void sdk_mapped_flags_clear_by_index(sdk_mapped_flags_t * p_flags, uint16_t index) -{ - *p_flags &= ~(1U << index); -} - - -/**@brief Function for getting the state of a flag. - * - * @note This function does not check whether the index is valid. - * - * @param[in] p_flags The collection of flags to read. - * @param[in] index The index of the flag to get. - */ -static __INLINE bool sdk_mapped_flags_get_by_index(sdk_mapped_flags_t flags, uint16_t index) -{ - return ((flags & (1 << index)) != 0); -} - - - -uint16_t sdk_mapped_flags_first_key_index_get(sdk_mapped_flags_t flags) -{ - for (uint16_t i = 0; i < SDK_MAPPED_FLAGS_N_KEYS; i++) - { - if (sdk_mapped_flags_get_by_index(flags, i)) - { - return i; - } - } - return SDK_MAPPED_FLAGS_INVALID_INDEX; -} - - -void sdk_mapped_flags_update_by_key(uint16_t * p_keys, - sdk_mapped_flags_t * p_flags, - uint16_t key, - bool value) -{ - sdk_mapped_flags_bulk_update_by_key(p_keys, p_flags, 1, key, value); -} - - -void sdk_mapped_flags_bulk_update_by_key(uint16_t * p_keys, - sdk_mapped_flags_t * p_flags, - uint32_t n_flag_collections, - uint16_t key, - bool value) -{ - if ((p_keys != NULL) && (p_flags != NULL) && (n_flag_collections > 0)) - { - for (int i = 0; i < SDK_MAPPED_FLAGS_N_KEYS; i++) - { - if (p_keys[i] == key) - { - for (int j = 0; j < n_flag_collections; j++) - { - if (value) - { - sdk_mapped_flags_set_by_index(&p_flags[j], i); - } - else - { - sdk_mapped_flags_clear_by_index(&p_flags[j], i); - } - } - return; - } - } - } -} - - -bool sdk_mapped_flags_get_by_key(uint16_t * p_keys, sdk_mapped_flags_t flags, uint16_t key) -{ - if (p_keys != NULL) - { - for (int i = 0; i < SDK_MAPPED_FLAGS_N_KEYS; i++) - { - if (p_keys[i] == key) - { - return sdk_mapped_flags_get_by_index(flags, i); - } - } - } - return false; -} - - -sdk_mapped_flags_key_list_t sdk_mapped_flags_key_list_get(uint16_t * p_keys, - sdk_mapped_flags_t flags) -{ - sdk_mapped_flags_key_list_t key_list; - key_list.len = 0; - - if (p_keys != NULL) - { - for (int i = 0; i < SDK_MAPPED_FLAGS_N_KEYS; i++) - { - if (sdk_mapped_flags_get_by_index(flags, i)) - { - key_list.flag_keys[key_list.len++] = p_keys[i]; - } - } - } - - return key_list; -} - - -uint32_t sdk_mapped_flags_n_flags_set(sdk_mapped_flags_t flags) -{ - uint32_t n_flags_set = 0; - - for (int i = 0; i < SDK_MAPPED_FLAGS_N_KEYS; i++) - { - if (sdk_mapped_flags_get_by_index(flags, i)) - { - n_flags_set += 1; - } - } - return n_flags_set; -} \ No newline at end of file