move components to SDK dir

This commit is contained in:
Shuanglei Tao
2025-03-03 09:06:26 +08:00
parent 20d1297e57
commit f4f4c9e60d
1021 changed files with 58 additions and 35059 deletions

View File

@@ -0,0 +1,199 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 ES_H__
#define ES_H__
#include <stdint.h>
#include "app_util_platform.h"
/**
* @file
*
* @defgroup eddystone_types Frame types and data formats
* @brief Definitions specific to Eddystone frame types and data formats.
* @ingroup eddystone
* @{
*/
/** @brief Swap 2 bytes.
*/
#define BYTES_SWAP_16BIT(x) (x << 8 | x >> 8)
/** @brief Reverse 4 bytes.
*/
#define BYTES_REVERSE_32BIT(x) \
((x << 24 | ((x << 8) & 0x00FF0000)) | (((x >> 8) & 0x0000FF00) | x >> 24))
/** @brief Check if the error code is equal to NRF_SUCCESS. If it is not, return the error code.
*/
#define RETURN_IF_ERROR(PARAM) \
if ((PARAM) != NRF_SUCCESS) \
{ \
return (PARAM); \
}
#define ES_UUID 0xFEAA //!< UUID for Eddystone beacons according to specification.
#define ES_UID_FRAME_TYPE 0x00 //!< UID frame type (fixed at 0x00).
#define ES_UID_RFU 0x00, 0x00 //!< Reserved for future use according to specification.
#define ES_URL_FRAME_TYPE 0x10 //!< URL frame type (fixed at 0x10).
#define ES_URL_SCHEME 0x00 //!< URL prefix scheme according to specification (0x00 = "http://www").
#define ES_TLM_FRAME_TYPE 0x20 //!< TLM frame type (fixed at 0x20).
#define ES_EID_FRAME_TYPE 0x30 //!< EID frame type (fixed at 0x30).
#define ES_FRAME_TYPE_LENGTH (1) //!< Length of a frame type field.
#define ES_UID_LENGTH (20) //!< Length of a UID frame.
#define ES_UID_NAMESPACE_LENGTH (10) //!< Length of a UID frame namespace field.
#define ES_UID_INSTANCE_LENGTH (6) //!< Length of a UID frame instance field.
#define ES_UID_RFU_LENGTH (2) //!< Length of a UID frame RFU field.
#define ES_URL_LENGTH (20) //!< Length of a URL frame.
#define ES_URL_URL_SCHEME_LENGTH (1) //!< Length of a URL frame URL scheme field.
#define ES_URL_ENCODED_URL_LENGTH (17) //!< Maximum length of a URL frame encoded URL field.
#define ES_TLM_LENGTH (14) //!< Length of a TLM frame.
#define ES_TLM_VBATT_LENGTH (2) //!< Length of a TLM frame VBATT field.
#define ES_TLM_TEMP_LENGTH (2) //!< Length of a TLM frame TEMP field.
#define ES_TLM_ADV_CNT_LENGTH (4) //!< Length of a TLM frame ADV count field.
#define ES_TLM_SEC_CNT_LENGTH (4) //!< Length of a TLM frame seconds field.
#define ES_EID_LENGTH (10) //!< Length of an EID frame.
#define ES_EID_ID_LENGTH (8) //!< Length of an EID frame ephemeral ID field.
#define ES_EID_GATTS_READ_LENGTH (14)
#define ES_EID_GATTS_READ_FRAME_TYPE_IDX (0)
#define ES_EID_GATTS_READ_EXPONENT_IDX (1)
#define ES_EID_GATTS_READ_CLCK_VALUE_IDX (2)
#define ES_EID_GATTS_READ_EID_IDX (6)
#define ES_ETLM_LENGTH (18) //!< Length of an eTLM frame.
#define ES_ETLM_ECRYPTED_LENGTH (ES_TLM_VBATT_LENGTH + \
ES_TLM_TEMP_LENGTH + \
ES_TLM_ADV_CNT_LENGTH + \
ES_TLM_SEC_CNT_LENGTH) //!< Length of an eTLM frame encrypted TLM field.
#define ES_ETLM_RFU (0x00) //!< eTLM frame RFU field value.
#define ES_SPEC_VERSION_BYTE (0x00) //!< eTLM frame specification version field value.
/** @brief Eddystone frame type values. These values are advertised as frame types. */
typedef enum
{
ES_FRAME_TYPE_UID = ES_UID_FRAME_TYPE, /**< UID frame type. */
ES_FRAME_TYPE_URL = ES_URL_FRAME_TYPE, /**< URL frame type. */
ES_FRAME_TYPE_TLM = ES_TLM_FRAME_TYPE, /**< TLM frame type. */
ES_FRAME_TYPE_EID = ES_EID_FRAME_TYPE /**< EID frame type. */
} es_frame_type_t;
/** @brief TLM version values. */
typedef enum
{
ES_TLM_VERSION_TLM = 0x00, /**< TLM. */
ES_TLM_VERSION_ETLM = 0x01 /**< Encrypted TLM (eTLM). */
} es_tlm_version_t;
/** @brief UID frame data representation.
* @note This is a packed structure. Therefore, you should not change it.
*/
typedef PACKED_STRUCT
{
es_frame_type_t frame_type; //!< Frame type (see @ref es_frame_type_t).
int8_t ranging_data; //!< Calibrated TX power at 0 m.
int8_t namespace[ES_UID_NAMESPACE_LENGTH]; //!< UID namespace.
int8_t instance[ES_UID_INSTANCE_LENGTH]; //!< UID instance.
int8_t rfu[ES_UID_RFU_LENGTH]; //!< RFU.
} es_uid_frame_t;
/** @brief URL frame data representation.
* @note This is a packed structure. Therefore, you should not change it.
*/
typedef PACKED_STRUCT
{
es_frame_type_t frame_type; //!< Frame type (see @ref es_frame_type_t).
int8_t ranging_data; //!< Calibrated TX power at 0 m.
uint8_t url_scheme; //!< URL scheme.
uint8_t encoded_url[ES_URL_ENCODED_URL_LENGTH]; //!< Encoded URL (variable length).
} es_url_frame_t;
/** @brief TLM frame data representation.
* @note This is a packed structure. Therefore, you should not change it.
*/
typedef PACKED_STRUCT
{
es_frame_type_t frame_type; //!< Frame type (see @ref es_frame_type_t).
es_tlm_version_t version; //!< TLM version (see @ref es_tlm_version_t).
int8_t vbatt[ES_TLM_VBATT_LENGTH]; //!< Battery voltage (in 1 mV units).
int8_t temp[ES_TLM_TEMP_LENGTH]; //!< Beacon temperature.
int8_t adv_cnt[ES_TLM_ADV_CNT_LENGTH]; //!< Advertising PDU count.
int8_t sec_cnt[ES_TLM_SEC_CNT_LENGTH]; //!< Time since power-on or reboot.
} es_tlm_frame_t;
/** @brief EID frame data representation.
* @note This is a packed structure. Therefore, you should not change it.
*/
typedef PACKED_STRUCT
{
es_frame_type_t frame_type; //!< Frame type (see @ref es_frame_type_t).
int8_t ranging_data; //!< Calibrated TX power at 0 m.
int8_t eid[ES_EID_ID_LENGTH]; //!< 8-byte ephemeral identifier.
} es_eid_frame_t;
/** @brief eTLM frame data representation.
* @note This is a packed structure. Therefore, you should not change it.
*/
typedef PACKED_STRUCT
{
es_frame_type_t frame_type; //!< Frame type (see @ref es_frame_type_t).
es_tlm_version_t version; //!< TLM version (see @ref es_tlm_version_t).
int8_t encrypted_tlm[ES_ETLM_ECRYPTED_LENGTH]; //!< Encrypted TLM data.
int16_t random_salt; //!< Salt
int16_t msg_integrity_check; //!< Message integrity check.
} es_etlm_frame_t;
/**
* @}
*/
#endif // ES_H__

View File

@@ -0,0 +1,309 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 "es_adv.h"
#include "app_error.h"
#include "es_adv_frame.h"
#include "es_adv_timing.h"
#include "es_tlm.h"
#include "es_slot.h"
static es_adv_evt_handler_t m_adv_evt_handler; //!< Eddystone advertisement event handler.
static bool m_is_connected = false; //!< Is the Eddystone beacon in a connected state.
static bool m_remain_connectable = false; //!< Should the Eddystone beacon remain connectable.
static uint8_t m_ecs_uuid_type = 0; //!< UUID type of the Eddystone Configuration Service.
static uint16_t m_adv_interval = APP_CFG_NON_CONN_ADV_INTERVAL_MS; //!< Current advertisement interval.
/**@brief Function for invoking registered callback.
*
* @param[in] evt Event to issue to callback.
*/
static void invoke_callback(es_adv_evt_t evt)
{
if (m_adv_evt_handler != NULL)
{
m_adv_evt_handler(evt);
}
}
/**@brief Starting advertising.
* @param[in] p_adv_params Advertisement parameters to use.
*/
static void adv_start(ble_gap_adv_params_t * p_adv_params)
{
ret_code_t err_code = NRF_SUCCESS;
es_tlm_adv_cnt_inc();
err_code = sd_ble_gap_adv_start(p_adv_params);
if (err_code != NRF_ERROR_BUSY && err_code != NRF_SUCCESS)
{
APP_ERROR_CHECK(err_code);
}
}
/**@brief Given state of Eddystone beacon, get advertisement parameters. */
static void get_adv_params(ble_gap_adv_params_t * p_adv_params,
bool non_connectable,
bool remain_connectable)
{
// Initialize advertising parameters (used when starting advertising).
memset(p_adv_params, 0, sizeof(ble_gap_adv_params_t));
// Non-connectable
p_adv_params->type =
non_connectable ? BLE_GAP_ADV_TYPE_ADV_NONCONN_IND : BLE_GAP_ADV_TYPE_ADV_IND;
p_adv_params->p_peer_addr = NULL; // Undirected advertisement.
p_adv_params->fp = BLE_GAP_ADV_FP_ANY;
p_adv_params->interval = non_connectable ? BLE_GAP_ADV_INTERVAL_MAX : 1000;
p_adv_params->timeout = non_connectable
? APP_CFG_NON_CONN_ADV_TIMEOUT
: (remain_connectable ? 0 : APP_CFG_CONNECTABLE_ADV_TIMEOUT);
}
/**@brief Update advertisement data and start connectable advertisements. */
static void connectable_adv_start(void)
{
ble_gap_adv_params_t connectable_adv_params;
ble_advdata_t scrsp_data;
ble_uuid_t scrp_uuids[] = {{BLE_UUID_ESCS_SERVICE, m_ecs_uuid_type}};
memset(&scrsp_data, 0, sizeof(scrsp_data));
scrsp_data.name_type = BLE_ADVDATA_FULL_NAME;
scrsp_data.include_appearance = false;
scrsp_data.uuids_complete.uuid_cnt = sizeof(scrp_uuids) / sizeof(scrp_uuids[0]);
scrsp_data.uuids_complete.p_uuids = scrp_uuids;
// As the data to be written does not depend on the slot_no, we can safely send
es_adv_frame_fill_connectable_adv_data(&scrsp_data);
get_adv_params(&connectable_adv_params, false, m_remain_connectable);
adv_start(&connectable_adv_params);
invoke_callback(ES_ADV_EVT_CONNECTABLE_ADV_STARTED);
}
static void adv_stop(void)
{
ret_code_t err_code;
err_code = sd_ble_gap_adv_stop();
if (err_code != NRF_ERROR_INVALID_STATE)
{
APP_ERROR_CHECK(err_code);
}
es_adv_timing_stop();
}
static void adv_restart(void)
{
if (!m_remain_connectable)
{
es_adv_start_non_connctable_adv();
}
else
{
connectable_adv_start();
}
}
/**@brief Function handling events from @ref es_adv_timing.c.
*
* @param[in] p_evt Advertisement timing event.
*/
static void adv_timing_callback(const es_adv_timing_evt_t * p_evt)
{
ret_code_t err_code;
ble_gap_adv_params_t non_connectable_adv_params;
const es_slot_reg_t * p_reg = es_slot_get_registry();
// As new advertisement data will be loaded, stop advertising.
err_code = sd_ble_gap_adv_stop();
if (err_code != NRF_ERROR_INVALID_STATE)
{
APP_ERROR_CHECK(err_code);
}
// If a non-eTLM frame is to be advertised.
if (p_evt->evt_id == ES_ADV_TIMING_EVT_ADV_SLOT)
{
err_code = sd_ble_gap_tx_power_set(p_reg->slots[p_evt->slot_no].radio_tx_pwr);
APP_ERROR_CHECK(err_code);
es_adv_frame_fill_non_connectable_adv_data(p_evt->slot_no, false);
}
// If an eTLM frame is to be advertised
else if (p_evt->evt_id == ES_ADV_TIMING_EVT_ADV_ETLM)
{
err_code = sd_ble_gap_tx_power_set(p_reg->slots[p_reg->tlm_slot].radio_tx_pwr);
APP_ERROR_CHECK(err_code);
es_adv_frame_fill_non_connectable_adv_data(p_evt->slot_no, true);
}
invoke_callback(ES_ADV_EVT_NON_CONN_ADV);
get_adv_params(&non_connectable_adv_params, true, m_remain_connectable);
adv_start(&non_connectable_adv_params);
}
void es_adv_start_connectable_adv(void)
{
if (!m_is_connected)
{
adv_stop();
connectable_adv_start();
}
}
void es_adv_start_non_connctable_adv(void)
{
es_adv_timing_start(m_adv_interval);
}
void es_adv_remain_connectable_set(bool remain_connectable)
{
m_remain_connectable = remain_connectable;
}
bool es_adv_remain_connectable_get(void)
{
return m_remain_connectable;
}
void es_adv_on_ble_evt(ble_evt_t * p_ble_evt)
{
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
m_is_connected = true;
// The beacon must provide these advertisements for the client to see updated values
// during the connection.
es_adv_start_non_connctable_adv();
break;
case BLE_GAP_EVT_DISCONNECTED:
m_is_connected = false;
// Stop all advertising to give some time for writing to flash.
adv_stop();
adv_restart();
break;
case BLE_GAP_EVT_TIMEOUT:
if (p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_ADVERTISING &&
!m_is_connected)
{
adv_restart();
}
break;
default:
break;
}
}
void es_adv_interval_set(nrf_ble_escs_adv_interval_t interval)
{
const es_slot_reg_t * p_reg = es_slot_get_registry();
uint16_t min_valid_adv_interval;
bool eTLM_required = (p_reg->num_configured_eid_slots > 0) && (p_reg->tlm_configured);
min_valid_adv_interval = eTLM_required ? \
p_reg->num_configured_slots * (APP_CONFIG_ADV_FRAME_SPACING_MS_MIN + \
APP_CONFIG_ADV_FRAME_ETLM_SPACING_MS) \
: \
p_reg->num_configured_slots * APP_CONFIG_ADV_FRAME_SPACING_MS_MIN;
m_adv_interval = (interval > min_valid_adv_interval) ? interval : min_valid_adv_interval;
#ifdef APP_CONFIG_ADV_INTERVAL_MS_MAX
if (m_adv_interval > APP_CONFIG_ADV_INTERVAL_MS_MAX)
{
m_adv_interval = APP_CONFIG_ADV_INTERVAL_MS_MAX;
}
#endif // APP_CONFIG_ADV_INTERVAL_MS_MAX
}
nrf_ble_escs_adv_interval_t es_adv_interval_get(void)
{
return m_adv_interval;
}
void es_adv_init(uint8_t ecs_uuid_type,
es_adv_evt_handler_t adv_event_handler,
nrf_ble_escs_adv_interval_t adv_interval,
bool remain_connectable)
{
m_ecs_uuid_type = ecs_uuid_type;
m_adv_evt_handler = adv_event_handler;
m_is_connected = false;
m_remain_connectable = remain_connectable;
m_adv_interval = adv_interval;
es_tlm_init();
es_adv_timing_init(adv_timing_callback);
}
void es_adv_timers_init(void)
{
es_adv_timing_timers_init();
}

View File

@@ -0,0 +1,127 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 ES_ADV_H__
#define ES_ADV_H__
#include "nrf_ble_escs.h"
/**
* @file
* @defgroup eddystone_adv Eddystone advertising module
* @brief Types and functions for handling advertising in Eddystone beacons.
* @ingroup eddystone
* @{
*/
/** @brief Eddystone Advertiser events. */
typedef enum
{
ES_ADV_EVT_NON_CONN_ADV,
ES_ADV_EVT_CONNECTABLE_ADV_STARTED,
} es_adv_evt_t;
/** @brief Eddystone Advertiser event handler. */
typedef void (*es_adv_evt_handler_t)(es_adv_evt_t evt);
/** @brief Function for initializing the module.
*
* @param[in] ecs_uuid_type ECS UUID type used for advertising the Eddystone Configuration Service UUID.
* @param[in] adv_event_handler Eddystone advertiser event handler.
* @param[in] adv_interval Advertisement interval to use.
* @param[in] remain_connectable Flag that specifies if advertisements should remain connectable.
*/
void es_adv_init(uint8_t ecs_uuid_type,
es_adv_evt_handler_t adv_event_handler,
nrf_ble_escs_adv_interval_t adv_interval,
bool remain_connectable);
/** @brief Function for passing BLE events to this module.
*
* @param[in] p_ble_evt Pointer to the BLE evt.
*/
void es_adv_on_ble_evt(ble_evt_t * p_ble_evt);
/** @brief Function for starting the advertisements.
*/
void es_adv_start_non_connctable_adv(void);
/** @brief Function for specifying if the beacon should remain connectable.
*
* @param[in] remain_connectable Value to be set.
*/
void es_adv_remain_connectable_set(bool remain_connectable);
/** @brief Function for starting connectable advertisements.
*/
void es_adv_start_connectable_adv(void);
/** @brief Function for setting the base advertisement interval for non-connectable advertisements.
*
* The minimum allowed advertisement interval is calculated based on the configured minimum advertisement
* frame spacings and the number of configured slots. If eTLM slots are configured a separate minimum
* advertisement frame spacing is used for those. If @p interval is outside of range, the closest valid value
* is set.
*
* @param interval The new advertisement interval.
*/
void es_adv_interval_set(nrf_ble_escs_adv_interval_t interval);
/** @brief Function for getting a pointer to the current advertisement interval.
*
* @retval Pointer to the current advertisement interval.
*/
nrf_ble_escs_adv_interval_t es_adv_interval_get(void);
/** @brief Function for getting the value of the 'remain_connectable' field.
*
* @retval Value of 'remain_connectable'.
*/
bool es_adv_remain_connectable_get(void);
/** @brief Function for initializing the Eddystone advertisement timers.
*/
void es_adv_timers_init(void);
/**
* @}
*/
#endif // ES_ADV_H__

View File

@@ -0,0 +1,107 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 "es_adv_frame.h"
#include "es_slot.h"
/**@brief Function for setting advertisement data, using 'ble_advdata_set'.
*
* @param[in] p_scrsp_data Scan response data.
* @param[in] p_es_data_array Eddystone service data array.
*/
static void fill_adv_data(ble_advdata_t * p_scrsp_data, uint8_array_t * p_es_data_array)
{
ble_advdata_t adv_data;
ret_code_t err_code;
ble_uuid_t adv_uuids[] = {{ES_UUID, BLE_UUID_TYPE_BLE}};
uint8_array_t es_data_array = {0};
ble_advdata_service_data_t service_data; // Structure to hold Service Data.
service_data.service_uuid = APP_ES_UUID; // Eddystone UUID to allow discoverability on iOS devices.
service_data.data = (p_es_data_array != NULL) ? *p_es_data_array : es_data_array;
// Build and set advertising data.
memset(&adv_data, 0, sizeof(ble_advdata_t));
adv_data.name_type = BLE_ADVDATA_NO_NAME;
adv_data.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
adv_data.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]);
adv_data.uuids_complete.p_uuids = adv_uuids;
adv_data.p_service_data_array = &service_data;
adv_data.service_data_count = (p_es_data_array != NULL) ? 1 : 0;
err_code = ble_advdata_set(&adv_data, p_scrsp_data);
APP_ERROR_CHECK(err_code);
}
void es_adv_frame_fill_connectable_adv_data(ble_advdata_t * p_scrsp_data)
{
fill_adv_data(p_scrsp_data, NULL);
}
void es_adv_frame_fill_non_connectable_adv_data(uint8_t slot_no, bool etlm)
{
uint8_array_t es_data_array = {0};
const es_slot_reg_t * p_reg = es_slot_get_registry();
if (etlm)
{
es_slot_etlm_update(slot_no);
// If eTLM, the incoming slot_no points to the corresponding EID slot, update to point to TLM slot.
slot_no = p_reg->tlm_slot;
}
// If TLM, update the TLM data.
else if (p_reg->slots[slot_no].adv_frame.type == ES_FRAME_TYPE_TLM)
{
es_slot_tlm_update();
}
es_data_array.p_data = (uint8_t *)&p_reg->slots[slot_no].adv_frame.frame;
es_data_array.size = p_reg->slots[slot_no].adv_frame.length;
fill_adv_data(NULL, &es_data_array);
}

View File

@@ -0,0 +1,72 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 ES_ADV_FRAME_H__
#define ES_ADV_FRAME_H__
#include <stdint.h>
#include "ble_advdata.h"
/**
* @file
* @addtogroup eddystone_adv
* @{
*/
/**@brief Function for setting up connectable advertisement data using @ref
* ble_advdata_set.
*
* @param[in] p_scrsp_data Pointer to the scan response data.
*/
void es_adv_frame_fill_connectable_adv_data(ble_advdata_t * p_scrsp_data);
/**@brief Function for setting up non-connectable advertisement data using @ref
* ble_advdata_set.
*
* @param[in] slot_no Slot to fill in data for.
* @param[in] etlm Flag that specifies if Eddystone-TLM is required.
*/
void es_adv_frame_fill_non_connectable_adv_data(uint8_t slot_no, bool etlm);
/**
* @}
*/
#endif // ES_ADV_FRAME_H__

View File

@@ -0,0 +1,221 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 "app_timer.h"
#include "es_adv_timing.h"
#include "es_adv_timing_resolver.h"
#include "es_slot.h"
APP_TIMER_DEF(m_es_adv_interval_timer); //!< Timer for advertising the set of slots.
APP_TIMER_DEF(m_es_slot_timer); //!< Timer for advertising individual slots.
static nrf_ble_escs_adv_interval_t m_current_adv_interval; //!< Current advertisement interval.
static es_adv_timing_callback_t m_timing_mgr_callback; //!< Registered callback.
static es_adv_timing_resolver_result_t m_adv_timing_result; //!< Current advertising timing result.
static bool m_non_conn_adv_active; //!< Is the beacon advertising non-conn advertisements?
/**@brief Function for invoking registered callback.
*
* @param[in] p_evt Event to issue to callback.
*/
static void invoke_callback(const es_adv_timing_evt_t * p_evt)
{
if (m_timing_mgr_callback != NULL && m_non_conn_adv_active)
{
m_timing_mgr_callback(p_evt);
}
}
#if APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO > 1
static bool frame_to_adv_is_tlm(const es_adv_timing_evt_t * p_evt)
{
const es_slot_reg_t * p_reg = es_slot_get_registry();
return (p_reg->tlm_configured &&
(p_evt->slot_no == p_reg->tlm_slot || p_evt->evt_id == ES_ADV_TIMING_EVT_ADV_ETLM));
}
static bool tlm_should_be_advertised(uint32_t adv_event_cnt)
{
return (adv_event_cnt % APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO) == 0;
}
#endif // APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO > 1
/**@brief Timeout handler for the advertisement slot timer. */
static void adv_slot_timeout(void * p_context)
{
ret_code_t err_code;
uint32_t active_slot_index = (uint32_t)p_context;
es_adv_timing_evt_t evt;
evt.slot_no = m_adv_timing_result.timing_results[active_slot_index].slot_no;
evt.evt_id = m_adv_timing_result.timing_results[active_slot_index].is_etlm
? ES_ADV_TIMING_EVT_ADV_ETLM
: ES_ADV_TIMING_EVT_ADV_SLOT;
// Trigger an event for the next slot if this slot is not the last to be advertised in this event.
// Note: since we check 'm_adv_timing_result.len_timing_results > 1' we can safely cast the result of
// the subtraction to a uint32.
if (m_non_conn_adv_active && \
m_adv_timing_result.len_timing_results > 1 && \
active_slot_index < (uint32_t)(m_adv_timing_result.len_timing_results - 1))
{
err_code = app_timer_start( m_es_slot_timer,
APP_TIMER_TICKS(m_adv_timing_result.timing_results[active_slot_index].delay_ms,
APP_TIMER_PRESCALER),
(void*)(active_slot_index + 1));
APP_ERROR_CHECK(err_code);
}
#if APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO > 1
static uint32_t adv_event_cnt = 0;
if (active_slot_index == 0)
{
adv_event_cnt++;
}
if (frame_to_adv_is_tlm(&evt) && !tlm_should_be_advertised(adv_event_cnt))
{
return;
}
#endif // APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO > 1
invoke_callback(&evt);
}
/**@brief Timeout handler for the advertisement interval timer. */
static void adv_interval_timeout(void * p_context)
{
if (es_slot_get_registry()->num_configured_slots > 0)
{
// Trigger slot timeout for advertising the first slot.
// Note: The slot number is not the index in the slot registry, it is the index of the active slots.
adv_slot_timeout(NULL);
}
if(m_non_conn_adv_active)
{
uint32_t err_code = app_timer_start(m_es_adv_interval_timer,
APP_TIMER_TICKS(m_current_adv_interval, APP_TIMER_PRESCALER),
NULL);
APP_ERROR_CHECK(err_code);
}
}
void es_adv_timing_timers_init(void)
{
ret_code_t err_code;
err_code = app_timer_create(&m_es_adv_interval_timer,
APP_TIMER_MODE_SINGLE_SHOT,
adv_interval_timeout);
APP_ERROR_CHECK(err_code);
err_code = app_timer_create(&m_es_slot_timer,
APP_TIMER_MODE_SINGLE_SHOT,
adv_slot_timeout);
APP_ERROR_CHECK(err_code);
}
/**@brief Function for finding and setting advertisement timing configuration. */
static void adv_timing_set(void)
{
ret_code_t err_code;
const es_slot_reg_t * p_reg = es_slot_get_registry();
es_adv_timing_resolver_input_t resolver_input = {
.adv_interval = m_current_adv_interval,
.p_result = &m_adv_timing_result,
.num_slots_configured = p_reg->num_configured_slots,
.p_slots_configured = p_reg->slots_configured,
.num_eid_slots_configured = p_reg->num_configured_eid_slots,
.p_eid_slots_configured = p_reg->eid_slots_configured,
.tlm_configured = p_reg->tlm_configured,
.tlm_slot = p_reg->tlm_slot};
err_code = es_adv_timing_resolve(&resolver_input);
APP_ERROR_CHECK(err_code);
}
void es_adv_timing_start(uint16_t adv_interval)
{
ret_code_t err_code;
const es_slot_reg_t * p_reg = es_slot_get_registry();
m_non_conn_adv_active = true;
if (p_reg->num_configured_slots > 0)
{
m_current_adv_interval = adv_interval;
err_code = app_timer_start(m_es_adv_interval_timer,
APP_TIMER_TICKS(m_current_adv_interval, APP_TIMER_PRESCALER),
NULL);
APP_ERROR_CHECK(err_code);
adv_timing_set();
}
}
void es_adv_timing_stop(void)
{
m_non_conn_adv_active = false; // Stops timers from being re-fired.
}
void es_adv_timing_init(es_adv_timing_callback_t p_handler)
{
m_non_conn_adv_active = false;
m_timing_mgr_callback = p_handler;
memset(&m_adv_timing_result, 0, sizeof(m_adv_timing_result));
}

View File

@@ -0,0 +1,98 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 ES_ADV_TIMING_H__
#define ES_ADV_TIMING_H__
#include <stdint.h>
/**
* @file
* @defgroup eddystone_adv_timing Timing
* @brief Events and functions for advertisement timing.
* @ingroup eddystone_adv
* @{
*/
/**@brief Eddystone advertisement timing event types. */
typedef enum
{
ES_ADV_TIMING_EVT_ADV_SLOT, //!< Advertising non-eTLM slot.
ES_ADV_TIMING_EVT_ADV_ETLM //!< Advertising eTLM slot.
} es_adv_timing_evt_id_t;
/**@brief Eddystone advertisement timing event. */
typedef struct
{
es_adv_timing_evt_id_t evt_id; //!< Event type ID.
uint8_t slot_no; /**< @brief Slot number.
* @details For non-eTLM events: The slot number to advertise.
*
* For eTLM events: The slot number of the corresponding EID slot. */
} es_adv_timing_evt_t;
/**@brief Eddystone advertisement timing event callback.
*
* @param[in] p_evt Pointer to the Eddystone advertisement timing event.
*/
typedef void (*es_adv_timing_callback_t)(const es_adv_timing_evt_t * p_evt);
/**@brief Function for starting Eddystone advertisement timing event generation. */
void es_adv_timing_start(uint16_t adv_interval);
/**@brief Function for stopping Eddystone advertisement timing event generation. */
void es_adv_timing_stop(void);
/**@brief Function for initializing the Eddystone advertisement timers.
*/
void es_adv_timing_timers_init(void);
/**@brief Function for initializing the Eddystone advertisement timing module.
*
* @param[in] handler Eddystone advertisement timing event handler to register.
*/
void es_adv_timing_init(es_adv_timing_callback_t handler);
/**
* @}
*/
#endif // ES_ADV_TIMING_H__

View File

@@ -0,0 +1,145 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 "es_adv_timing_resolver.h"
#include "sdk_macros.h"
/**@brief Function for finding delay to use after each non-eTLM advertisement.
*
* @param[in] adv_interval Configured advertisement interval.
* @param[in] num_slots_configured Number of configured slots.
* @param[in] eTLM_required Is there an eTLM slot.
*/
static uint16_t get_adv_delay(uint16_t adv_interval,
uint8_t num_slots_configured,
bool eTLM_required)
{
// If eTLM is required, don't count this when calculating delay.
return adv_interval / (num_slots_configured - (eTLM_required ? 1 : 0));
}
/**@brief Function for checking if given slot_no is an EID slot.
*
* @param[in] slot_no Slot number to check.
* @param[in] p_eid_slots_configured Pointer to list of configured EID slots.
* @param[in] num_eid_slots_configured Number of EID slots configured.
*/
static bool is_eid(uint8_t slot_no, const uint8_t * p_eid_slots_configured, uint8_t num_eid_slots_configured)
{
for (uint32_t i = 0; i < num_eid_slots_configured; ++i)
{
if (slot_no == p_eid_slots_configured[i])
{
return true;
}
}
return false;
}
ret_code_t es_adv_timing_resolve(es_adv_timing_resolver_input_t * p_input)
{
VERIFY_PARAM_NOT_NULL(p_input);
uint8_t result_index = 0;
bool eTLM_required = p_input->tlm_configured && p_input->num_eid_slots_configured > 0;
uint16_t base_delay;
if (p_input->num_slots_configured == 0)
{
return NRF_ERROR_INVALID_PARAM;
}
base_delay = get_adv_delay(p_input->adv_interval, p_input->num_slots_configured, eTLM_required);
for (uint32_t i = 0; i < p_input->num_slots_configured; ++i)
{
uint8_t slot_no = p_input->p_slots_configured[i];
if (!(eTLM_required && slot_no == p_input->tlm_slot))
{
es_adv_timing_resolver_adv_timing_t * p_current_result = &p_input->p_result->timing_results[result_index];
p_current_result->slot_no = slot_no;
p_current_result->is_etlm = false;
// If an eTLM is to be advertised for this frame, this value will be changed.
p_current_result->delay_ms = base_delay;
result_index++;
if (eTLM_required &&
is_eid(slot_no, p_input->p_eid_slots_configured, p_input->num_eid_slots_configured))
{
es_adv_timing_resolver_adv_timing_t * p_eTLM_timing_result =
&p_input->p_result->timing_results[result_index];
p_current_result->delay_ms = APP_CONFIG_ADV_FRAME_ETLM_SPACING_MS; // Update delay from EID to eTLM frame.
p_eTLM_timing_result->slot_no = slot_no; // Point to EID slot-no, as this will be
// used for finding the correct EIK.
p_eTLM_timing_result->is_etlm = true; // Configure as eTLM frame.
if (base_delay > APP_CONFIG_ADV_FRAME_ETLM_SPACING_MS)
{
p_eTLM_timing_result->delay_ms =
base_delay -
APP_CONFIG_ADV_FRAME_ETLM_SPACING_MS; // Set delay of eTLM frame.
}
else
{
p_eTLM_timing_result->delay_ms = APP_CONFIG_ADV_FRAME_SPACING_MS_MIN;
}
result_index++;
}
}
}
p_input->p_result->len_timing_results = result_index; // Note: index has been increased to equal length of result.
if(p_input->p_result->len_timing_results > 0)
{
p_input->p_result->timing_results[p_input->p_result->len_timing_results - 1].delay_ms = 0; // Last Slot does not need delay.
}
return NRF_SUCCESS;
}

View File

@@ -0,0 +1,97 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 ES_ADV_TIMING_RESOLVER_H__
#define ES_ADV_TIMING_RESOLVER_H__
#include <stdbool.h>
#include <stdint.h>
#include "es_app_config.h"
/**
* @file
* @addtogroup eddystone_adv_timing
* @{
*/
/** @brief Timing parameters for a single slot. */
typedef struct
{
bool is_etlm; //!< Flag that specifies if the slot is an eTLM.
uint8_t slot_no; /**< @brief Slot number. @details
* For non-eTLM slots: The slot number of the given frame.
*
* For eTLM slots: The slot number of the corresponding EID frame. */
uint16_t delay_ms; //!< Delay from this frame to the next.
} es_adv_timing_resolver_adv_timing_t;
/**@brief Results of calculating advertisement delays. */
typedef struct
{
es_adv_timing_resolver_adv_timing_t timing_results[APP_MAX_ADV_SLOTS - APP_MAX_EID_SLOTS +
(APP_MAX_EID_SLOTS * 2)]; //!< List of timing results.
uint8_t len_timing_results; //!< Length of results.
} es_adv_timing_resolver_result_t;
/**@brief Input to the timing resolver. */
typedef struct
{
uint16_t adv_interval; //!< Global advertisement interval.
uint8_t num_slots_configured; //!< Number of configured slots.
const uint8_t * p_slots_configured; //!< Pointer to the list of configured slots.
uint8_t num_eid_slots_configured; //!< Number of configured EID slots.
const uint8_t * p_eid_slots_configured; //!< Pointer to the list of configured EID slots.
bool tlm_configured; //!< Flag that specifies if TLM slot is configured.
uint8_t tlm_slot; //!< Slot number of the TLM slot (if @p tlm_configured is true).
es_adv_timing_resolver_result_t * p_result; //!< Output result.
} es_adv_timing_resolver_input_t;
/**@brief Function for getting the input for advertisement interval calculation.
*
* @param[in,out] p_input Input to advertisement interval calculation (see @ref es_adv_timing_resolver_input_t).
* @retval NRF_SUCCESS If the operation was successful. Otherwise, an error code is returned.
*/
ret_code_t es_adv_timing_resolve(es_adv_timing_resolver_input_t * p_input);
/**
* @}
*/
#endif // ES_ADV_TIMING_RESOLVER_H__

View File

@@ -0,0 +1,67 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 ES_BATTERY_VOLTAGE_H__
#define ES_BATTERY_VOLTAGE_H__
#include <stdint.h>
/**
* @file
*
* @addtogroup eddystone_tlm
* @{
*/
/**@brief Function for initializing the battery voltage module.
*/
void es_battery_voltage_init(void);
/**@brief Function for reading the battery voltage.
*
* @param[out] p_vbatt Pointer to the battery voltage value.
*/
void es_battery_voltage_get(uint16_t * p_vbatt);
/**
* @}
*/
#endif // ES_BATTERY_VOLTAGE_H__

View File

@@ -0,0 +1,100 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 "app_error.h"
#include "es_battery_voltage.h"
#include "nrf_drv_adc.h"
static uint16_t m_batt_lvl_in_milli_volts;
#define ADC_REF_VOLTAGE_IN_MILLIVOLTS 600 // /< Reference voltage (in milli volts) used by ADC while doing conversion.
#define DIODE_FWD_VOLT_DROP_MILLIVOLTS 270 // /< Typical forward voltage drop of the diode (Part no: SD103ATW-7-F) that is connected in series with the voltage supply. This is the voltage drop when the forward current is 1mA. Source: Data sheet of 'SURFACE MOUNT SCHOTTKY BARRIER DIODE ARRAY' available at www.diodes.com.
#define ADC_RES_10BIT 1024 // /< Maximum digital value for 10-bit ADC conversion.
#define ADC_PRE_SCALING_COMPENSATION 6 // /< The ADC is configured to use VDD with 1/3 prescaling as input. And hence the result of conversion is to be multiplied by 3 to get the actual value of the battery voltage.
#define ADC_REF_VBG_VOLTAGE_IN_MILLIVOLTS 1200 // /< Value in millivolts for voltage used as reference in ADC conversion on NRF51.
#define ADC_INPUT_PRESCALER 3 // /< Input prescaler for ADC convestion on NRF51.
static nrf_adc_value_t adc_buf[1];
#define ADC_RESULT_IN_MILLI_VOLTS(ADC_VALUE) \
((((ADC_VALUE) *ADC_REF_VBG_VOLTAGE_IN_MILLIVOLTS) / ADC_RES_10BIT) * ADC_INPUT_PRESCALER)
static void adc_event_handler(nrf_drv_adc_evt_t const * p_event)
{
if (p_event->type == NRF_DRV_ADC_EVT_DONE)
{
nrf_adc_value_t adc_result;
ret_code_t err_code;
adc_result = p_event->data.done.p_buffer[0];
err_code = nrf_drv_adc_buffer_convert(p_event->data.done.p_buffer, 1);
APP_ERROR_CHECK(err_code);
m_batt_lvl_in_milli_volts =
ADC_RESULT_IN_MILLI_VOLTS(adc_result) + DIODE_FWD_VOLT_DROP_MILLIVOLTS;
}
}
void es_battery_voltage_init(void)
{
ret_code_t err_code = nrf_drv_adc_init(NULL, adc_event_handler);
APP_ERROR_CHECK(err_code);
static nrf_drv_adc_channel_t channel =
NRF_DRV_ADC_DEFAULT_CHANNEL(NRF_ADC_CONFIG_INPUT_DISABLED);
channel.config.config.input = (uint32_t)NRF_ADC_CONFIG_SCALING_SUPPLY_ONE_THIRD;
nrf_drv_adc_channel_enable(&channel);
err_code = nrf_drv_adc_buffer_convert(&adc_buf[0], 1);
APP_ERROR_CHECK(err_code);
nrf_drv_adc_sample();
}
void es_battery_voltage_get(uint16_t * p_vbatt)
{
*p_vbatt = m_batt_lvl_in_milli_volts;
if (!nrf_adc_is_busy())
{
nrf_drv_adc_sample();
}
}

View File

@@ -0,0 +1,105 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 "es_battery_voltage.h"
#include "nrf_drv_saadc.h"
#include "sdk_macros.h"
#define ADC_REF_VOLTAGE_IN_MILLIVOLTS 600 //!< Reference voltage (in milli volts) used by ADC while doing conversion.
#define DIODE_FWD_VOLT_DROP_MILLIVOLTS 270 //!< Typical forward voltage drop of the diode (Part no: SD103ATW-7-F) that is connected in series with the voltage supply. This is the voltage drop when the forward current is 1mA. Source: Data sheet of 'SURFACE MOUNT SCHOTTKY BARRIER DIODE ARRAY' available at www.diodes.com.
#define ADC_RES_10BIT 1024 //!< Maximum digital value for 10-bit ADC conversion.
#define ADC_PRE_SCALING_COMPENSATION 6 //!< The ADC is configured to use VDD with 1/3 prescaling as input. And hence the result of conversion is to be multiplied by 3 to get the actual value of the battery voltage.
#define ADC_RESULT_IN_MILLI_VOLTS(ADC_VALUE) \
((((ADC_VALUE) *ADC_REF_VOLTAGE_IN_MILLIVOLTS) / ADC_RES_10BIT) * ADC_PRE_SCALING_COMPENSATION)
static nrf_saadc_value_t adc_buf; //!< Buffer used for storing ADC value.
static uint16_t m_batt_lvl_in_milli_volts; //!< Current battery level.
/**@brief Function handling events from 'nrf_drv_saadc.c'.
*
* @param[in] p_evt SAADC event.
*/
static void saadc_event_handler(nrf_drv_saadc_evt_t const * p_evt)
{
if (p_evt->type == NRF_DRV_SAADC_EVT_DONE)
{
nrf_saadc_value_t adc_result;
adc_result = p_evt->data.done.p_buffer[0];
m_batt_lvl_in_milli_volts =
ADC_RESULT_IN_MILLI_VOLTS(adc_result) + DIODE_FWD_VOLT_DROP_MILLIVOLTS;
}
}
void es_battery_voltage_init(void)
{
ret_code_t err_code = nrf_drv_saadc_init(NULL, saadc_event_handler);
APP_ERROR_CHECK(err_code);
nrf_saadc_channel_config_t config =
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_VDD);
err_code = nrf_drv_saadc_channel_init(0, &config);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_buffer_convert(&adc_buf, 1);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_sample();
APP_ERROR_CHECK(err_code);
}
void es_battery_voltage_get(uint16_t * p_vbatt)
{
VERIFY_PARAM_NOT_NULL_VOID(p_vbatt);
*p_vbatt = m_batt_lvl_in_milli_volts;
if (!nrf_drv_saadc_is_busy())
{
ret_code_t err_code = nrf_drv_saadc_buffer_convert(&adc_buf, 1);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_sample();
APP_ERROR_CHECK(err_code);
}
}

View File

@@ -0,0 +1,350 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 <string.h>
#include "es_flash.h"
#include "es_util.h"
#include "app_scheduler.h"
#include "ble_hci.h"
#include "fds.h"
#include "nrf_nvic.h"
#define SIZE_OF_PRIV_KEY ESCS_ECDH_KEY_SIZE //!< Size of ECDH private key.
#define SIZE_OF_PUB_KEY ESCS_ECDH_KEY_SIZE //!< Size of ECDH public key.
#define SIZE_OF_LOCK_KEY ESCS_AES_KEY_SIZE //!< Size of lock key.
#define FILE_ID_ES_FLASH 0x1337 //!< File ID used for all flash access EXCEPT lock code.
#define FILE_ID_ES_FLASH_LOCK_KEY 0x1338 //!< File ID used for lock code flash access.
#define RECORD_KEY_FLAGS 0x1 //!< File record for flash flags.
#define RECORD_KEY_PRIV_KEY 0x2 //!< File record for private key.
#define RECORD_KEY_PUB_KEY 0x3 //!< File record for public key.
#define RECORD_KEY_LOCK_KEY 0x4 //!< File record for lock key.
#define RECORD_KEY_BEACON_CONFIG 0x5 //!< File record for lock key.
static uint16_t RECORD_KEY_SLOTS[5] = {0x6, 0x7, 0x8, 0x9, 0xa}; //!< File record for slots.
/**@brief Structure used for invoking flash access function. */
typedef struct
{
uint16_t record_key;
uint16_t file_id;
uint8_t * p_chunk_buf;
uint8_t * p_data;
uint16_t size_bytes;
es_flash_access_t access_type;
} flash_access_params_t;
static volatile uint32_t m_num_pending_ops; //!< Current number of outstanding FDS operations.
static volatile bool m_factory_reset; //!< Should factory reset be performed.
static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID; //!< Current connection handle.
#if APP_MAX_ADV_SLOTS > 32
#error "APP_MAX_ADV_SLOTS must be <= 32"
#endif
#define SLOT_DECL(i, _) __ALIGN(4) static uint8_t slot## i ##_buf[sizeof(es_slot_t)];
//lint -save -e123
EVAL(REPEAT(APP_MAX_ADV_SLOTS, SLOT_DECL, ~))
#define SLOT(i, _) slot## i ##_buf,
static uint8_t * slots_buf_p[APP_MAX_ADV_SLOTS] = {
EVAL(REPEAT(APP_MAX_ADV_SLOTS, SLOT, ~))
};
//lint -restore
__ALIGN(4) static uint8_t lock_key_buf[SIZE_OF_LOCK_KEY]; //!< Buffer for lock key flash access.
__ALIGN(4) static uint8_t flash_flags_buf[sizeof(es_flash_flags_t)]; //!< Buffer for flash flags flash access.
__ALIGN(4) static uint8_t beacon_config_buf[sizeof(es_flash_beacon_config_t)]; //!< Buffer for beacon config flash access.
/**@brief Function handling scheduled FDS garbage collection. */
static void fds_gc_event(void * p_event_data, uint16_t event_size)
{
ret_code_t fds_err_code;
fds_err_code = fds_gc();
if (fds_err_code != FDS_SUCCESS)
APP_ERROR_CHECK_BOOL(NRF_ERROR_INTERNAL);
m_num_pending_ops++;
}
/**@brief Function handling FDS events.
*
* @param[in] p_evt FDS event.
*/
static void fds_cb(fds_evt_t const * const p_evt)
{
ret_code_t err_code;
switch (p_evt->id)
{
case FDS_EVT_INIT:
m_num_pending_ops = 0;
break;
case FDS_EVT_DEL_FILE:
case FDS_EVT_DEL_RECORD:
// Schedule garbage collection
err_code = app_sched_event_put(NULL, 0, fds_gc_event);
APP_ERROR_CHECK(err_code);
break;
case FDS_EVT_GC:
if (m_factory_reset && m_conn_handle != BLE_CONN_HANDLE_INVALID)
{
err_code =
sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
APP_ERROR_CHECK(err_code);
}
// Fall through:
case FDS_EVT_UPDATE:
case FDS_EVT_WRITE:
if (m_num_pending_ops > 0)
{
m_num_pending_ops--;
}
break;
}
}
/**@brief Function performing flash access (read/write/clear).
*
* @param[in] p_params Flash access parameters.
*/
static ret_code_t access_flash_data(const flash_access_params_t * p_params)
{
ret_code_t err_code;
fds_record_chunk_t chunk = {.p_data = p_params->p_chunk_buf};
fds_record_t record_to_write = {.data.p_chunks = &chunk, .file_id = p_params->file_id};
fds_flash_record_t record = {0};
fds_record_desc_t desc = {0};
fds_find_token_t ft = {0};
err_code = fds_record_find_by_key(p_params->record_key, &desc, &ft);
// If its a read or clear, we can not accept errors on lookup
if (p_params->access_type == ES_FLASH_ACCESS_READ)
{
RETURN_IF_ERROR(err_code);
}
if (p_params->access_type == ES_FLASH_ACCESS_CLEAR && err_code == FDS_ERR_NOT_FOUND)
{
return NRF_SUCCESS;
}
switch (p_params->access_type)
{
case ES_FLASH_ACCESS_READ:
err_code = fds_record_open(&desc, &record);
RETURN_IF_ERROR(err_code);
memcpy(p_params->p_data, record.p_data, p_params->size_bytes);
err_code = fds_record_close(&desc);
RETURN_IF_ERROR(err_code);
break;
case ES_FLASH_ACCESS_WRITE:
// Note chunk.p_data points to p_params->p_chunk_buf
memcpy(p_params->p_chunk_buf, p_params->p_data, p_params->size_bytes);
chunk.length_words = p_params->size_bytes / 4;
if (p_params->size_bytes % 4 != 0)
{
chunk.length_words++;
}
record_to_write.key = p_params->record_key;
record_to_write.data.num_chunks = 1;
if (err_code == FDS_ERR_NOT_FOUND)
{
err_code = fds_record_write(&desc, &record_to_write);
}
else
{
err_code = fds_record_update(&desc, &record_to_write);
}
RETURN_IF_ERROR(err_code);
m_num_pending_ops++;
break;
case ES_FLASH_ACCESS_CLEAR:
err_code = fds_record_delete(&desc);
RETURN_IF_ERROR(err_code);
m_num_pending_ops++;
break;
default:
break;
}
return NRF_SUCCESS;
}
ret_code_t es_flash_access_lock_key(uint8_t * p_lock_key, es_flash_access_t access_type)
{
flash_access_params_t params = {.record_key = RECORD_KEY_LOCK_KEY,
.file_id = FILE_ID_ES_FLASH_LOCK_KEY,
.p_chunk_buf = lock_key_buf,
.p_data = (uint8_t *)p_lock_key,
.size_bytes = SIZE_OF_LOCK_KEY,
.access_type = access_type};
return access_flash_data(&params);
}
ret_code_t es_flash_access_beacon_config(es_flash_beacon_config_t * p_config,
es_flash_access_t access_type)
{
ret_code_t err_code;
flash_access_params_t params = {.record_key = RECORD_KEY_BEACON_CONFIG,
.file_id = FILE_ID_ES_FLASH,
.p_chunk_buf = beacon_config_buf,
.p_data = (uint8_t *)p_config,
.size_bytes = sizeof(es_flash_beacon_config_t),
.access_type = access_type};
err_code = access_flash_data(&params);
return err_code;
}
ret_code_t es_flash_access_slot_configs(uint8_t slot_no,
es_slot_t * p_slot,
es_flash_access_t access_type)
{
if (slot_no >= APP_MAX_ADV_SLOTS)
{
return NRF_ERROR_INVALID_PARAM;
}
flash_access_params_t params = {.record_key = RECORD_KEY_SLOTS[slot_no],
.file_id = FILE_ID_ES_FLASH,
.p_chunk_buf = slots_buf_p[slot_no],
.p_data = (uint8_t *)p_slot,
.size_bytes = sizeof(es_slot_t),
.access_type = access_type};
return access_flash_data(&params);
}
ret_code_t es_flash_access_flags(es_flash_flags_t * p_flags, es_flash_access_t access_type)
{
flash_access_params_t params = {.record_key = RECORD_KEY_FLAGS,
.file_id = FILE_ID_ES_FLASH,
.p_chunk_buf = flash_flags_buf,
.p_data = (uint8_t *)p_flags,
.size_bytes = sizeof(es_flash_flags_t),
.access_type = access_type};
return access_flash_data(&params);
}
ret_code_t es_flash_factory_reset(void)
{
// Delete everything except the lock key:
ret_code_t ret_code = fds_file_delete(FILE_ID_ES_FLASH);
if (ret_code == FDS_SUCCESS)
m_factory_reset = true;
return ret_code;
}
uint32_t es_flash_num_pending_ops(void)
{
return m_num_pending_ops;
}
void es_flash_on_ble_evt(ble_evt_t * p_evt)
{
switch (p_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
m_conn_handle = p_evt->evt.common_evt.conn_handle;
break;
case BLE_GAP_EVT_DISCONNECTED:
m_conn_handle = BLE_CONN_HANDLE_INVALID;
if (m_factory_reset)
{
(void)sd_nvic_SystemReset();
}
break;
}
}
ret_code_t es_flash_init(void)
{
ret_code_t err_code;
m_num_pending_ops = 1; // Will be set to 0 when getting FDS_EVT_INIT event
m_conn_handle = BLE_CONN_HANDLE_INVALID;
m_factory_reset = false;
err_code = fds_register(fds_cb);
RETURN_IF_ERROR(err_code);
err_code = fds_init();
RETURN_IF_ERROR(err_code);
return NRF_SUCCESS;
}

View File

@@ -0,0 +1,178 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 ES_FLASH_H__
#define ES_FLASH_H__
#include <stdbool.h>
#include <stdint.h>
#include "es_slot.h"
/**
* @file
* @defgroup eddystone_flash Flash access
* @brief Types and functions to access the flash of the Eddystone beacon.
* @ingroup eddystone
* @{
*/
#define WORD_SIZE 4
#define FLASH_ACCES_ERROR_CHECK_ALLOW_NOT_FOUND(err_code) \
if (err_code != (FDS_ERR_NOT_FOUND)) \
APP_ERROR_CHECK(err_code);
#define FLASH_OP_WAIT() \
uint32_t pending_ops = es_flash_num_pending_ops(); \
while (pending_ops != 0) \
{ \
pending_ops = es_flash_num_pending_ops(); \
}
/**@brief Beacon configuration. */
typedef struct
{
nrf_ble_escs_adv_interval_t adv_interval; //!< Advertising interval.
bool remain_connectable; //!< Flag that specifies if the beacon should remain connectable.
} es_flash_beacon_config_t;
/**@brief Structure for keeping track of which slot has a configuration that must be restored upon reboot.
* @details The size of this structure must be word aligned and match the flash block size of 32 bytes.
*/
typedef struct
{
bool slot_is_empty[APP_MAX_ADV_SLOTS]; //!< Flag that indicates whether the slot is empty.
uint8_t padding[WORD_SIZE - ((APP_MAX_ADV_SLOTS + 1) % WORD_SIZE)]; //!< Padding used to ensure word alignment.
} es_flash_flags_t;
/**@brief Flash access types.
*/
typedef enum
{
ES_FLASH_ACCESS_READ, //!< Read data.
ES_FLASH_ACCESS_WRITE, //!< Write data.
ES_FLASH_ACCESS_CLEAR //!< Clear data.
} es_flash_access_t;
/**@brief Function for accessing beacon configurations.
*
* @param[out,in] p_config Pointer to the beacon configuration buffer.
* @param[in] access_type Access type (see @ref es_flash_access_t).
* @return For possible return values, see:
* - @ref fds_record_find_by_key
* - @ref fds_record_open
* - @ref fds_record_close
* - @ref fds_record_write
* - @ref fds_record_update
* - @ref fds_record_delete
*/
ret_code_t es_flash_access_beacon_config(es_flash_beacon_config_t * p_config,
es_flash_access_t access_type);
/**@brief Function for accessing slot configuration from flash.
*
* @param[in] slot_no Slot index.
* @param[out,in] p_slot Pointer to the slot configuration buffer.
* @param[in] access_type Access type (see @ref es_flash_access_t).
* @return For possible return values, see:
* - @ref fds_record_find_by_key
* - @ref fds_record_open
* - @ref fds_record_close
* - @ref fds_record_write
* - @ref fds_record_update
* - @ref fds_record_delete
*/
ret_code_t es_flash_access_slot_configs(uint8_t slot_no,
es_slot_t * p_slot,
es_flash_access_t access_type);
/**@brief Function for accessing the beacon lock key from flash.
*
* @param[out,in] p_lock_key Pointer to the lock key buffer.
* @param[in] access_type Access type (see @ref es_flash_access_t).
* @return For possible return values, see:
* - @ref fds_record_find_by_key
* - @ref fds_record_open
* - @ref fds_record_close
* - @ref fds_record_write
* - @ref fds_record_update
* - @ref fds_record_delete
*/
ret_code_t es_flash_access_lock_key(uint8_t * p_lock_key, es_flash_access_t access_type);
/**@brief Function for accessing the flash configuration flag from flash.
*
* @param[out,in] p_flags Pointer to the flag buffer.
* @param[in] access_type Access type (see @ref es_flash_access_t).
* @return For possible return values, see:
* - @ref fds_record_find_by_key
* - @ref fds_record_open
* - @ref fds_record_close
* - @ref fds_record_write
* - @ref fds_record_update
* - @ref fds_record_delete
*/
ret_code_t es_flash_access_flags(es_flash_flags_t * p_flags, es_flash_access_t access_type);
/**@brief Function for retrieving the number of queued operations.
* @return The number of operations that are queued.
*/
uint32_t es_flash_num_pending_ops(void);
/**@brief Function for performing a factory reset.
* @return FDS return code.
*/
ret_code_t es_flash_factory_reset(void);
void es_flash_on_ble_evt(ble_evt_t * p_evt);
/**@brief Function for initializing the flash module.
*
* @return See @ref fds_init for possible return values.
*/
ret_code_t es_flash_init(void);
/**
* @}
*/
#endif // ES_FLASH_H__

View File

@@ -0,0 +1,188 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 "es_gatts.h"
#include "es_gatts_read.h"
#include "es_gatts_write.h"
#include "es_slot.h"
static nrf_ble_escs_lock_state_read_t m_lock_state;
static uint8_t m_active_slot;
/**@brief Function checking if beacon is unlocked.
*
* @param[in] p_escs Pointer to Eddystone Configuration Service.
*
* @retval true If beacon is unlocked.
* @retval false If beacon is locked.
*/
static bool is_beacon_unlocked(const nrf_ble_escs_t * p_escs)
{
return m_lock_state != NRF_BLE_ESCS_LOCK_STATE_LOCKED;
}
ret_code_t es_gatts_send_reply(nrf_ble_escs_t * p_escs,
ble_gatts_rw_authorize_reply_params_t * p_reply)
{
VERIFY_PARAM_NOT_NULL(p_escs);
VERIFY_PARAM_NOT_NULL(p_reply);
if (p_escs->conn_handle != BLE_CONN_HANDLE_INVALID)
{
return sd_ble_gatts_rw_authorize_reply(p_escs->conn_handle, p_reply);
}
return NRF_ERROR_INVALID_STATE;
}
ret_code_t es_gatts_send_op_not_permitted(nrf_ble_escs_t * p_escs, bool read)
{
ble_gatts_rw_authorize_reply_params_t reply = {0};
VERIFY_PARAM_NOT_NULL(p_escs);
if (read)
{
reply.type = BLE_GATTS_AUTHORIZE_TYPE_READ;
reply.params.read.gatt_status = BLE_GATT_STATUS_ATTERR_READ_NOT_PERMITTED;
}
else
{
reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_WRITE_NOT_PERMITTED;
}
return es_gatts_send_reply(p_escs, &reply);
}
void es_gatts_handle_write(nrf_ble_escs_t * p_escs,
uint16_t uuid,
uint16_t val_handle,
uint8_t * p_data,
uint16_t length)
{
ret_code_t err_code;
if (is_beacon_unlocked(p_escs))
{
if (uuid == BLE_UUID_ESCS_UNLOCK_CHAR)
{
err_code = es_gatts_send_op_not_permitted(p_escs, false);
APP_ERROR_CHECK(err_code);
}
else
{
err_code = es_gatts_write_handle_unlocked_write(
p_escs, uuid, val_handle, p_data, length, m_active_slot);
APP_ERROR_CHECK(err_code);
}
}
else
{
if (uuid == BLE_UUID_ESCS_UNLOCK_CHAR)
{
err_code = es_gatts_write_handle_unlock(p_escs, p_data, length, val_handle);
APP_ERROR_CHECK(err_code);
}
else
{
err_code = es_gatts_send_op_not_permitted(p_escs, false);
APP_ERROR_CHECK(err_code);
}
}
}
void es_gatts_handle_read(nrf_ble_escs_t * p_escs, uint16_t uuid, uint16_t val_handle)
{
ret_code_t err_code;
if (is_beacon_unlocked(p_escs))
{
if (uuid == BLE_UUID_ESCS_UNLOCK_CHAR)
{
err_code = es_gatts_send_op_not_permitted(p_escs, true);
APP_ERROR_CHECK(err_code);
}
else
{
err_code = es_gatts_read_handle_unlocked_read(p_escs, uuid, val_handle, m_active_slot, m_lock_state);
APP_ERROR_CHECK(err_code);
}
}
else // Beacon is locked.
{
if (uuid == BLE_UUID_ESCS_UNLOCK_CHAR)
{
err_code = es_gatts_read_handle_unlock(p_escs);
APP_ERROR_CHECK(err_code);
}
else
{
err_code = es_gatts_read_handle_locked_read(p_escs, uuid, m_lock_state);
APP_ERROR_CHECK(err_code);
}
}
}
ret_code_t es_gatts_init(nrf_ble_escs_t * p_ble_escs)
{
VERIFY_PARAM_NOT_NULL(p_ble_escs);
m_active_slot = 0;
m_lock_state = NRF_BLE_ESCS_LOCK_STATE_LOCKED;
p_ble_escs->p_active_slot = &m_active_slot;
p_ble_escs->p_lock_state = &m_lock_state;
return NRF_SUCCESS;
}

View File

@@ -0,0 +1,109 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 ES_GATTS_H__
#define ES_GATTS_H__
#include <stdint.h>
#include "nrf_ble_escs.h"
/**
* @file
* @defgroup eddystone_gatts GATTS
* @brief Functions for handling GATTS write and read requests.
* @ingroup eddystone
* @{
*/
ret_code_t es_gatts_init(nrf_ble_escs_t * p_ble_escs);
/**@brief Function for handling all write requests from the Central.
*
* @param[in] p_escs Pointer to the Eddystone Configuration Service.
* @param[in] uuid The UUID of the characteristic that is being written to.
* @param[in] val_handle Value handle field of the characteristic handle of the characteristic that is being written to.
* @param[in] p_data Pointer to the data to be written.
* @param[in] length Length of the data to be written.
*
*/
void es_gatts_handle_write(nrf_ble_escs_t * p_escs,
uint16_t uuid,
uint16_t val_handle,
uint8_t * p_data,
uint16_t length);
/**@brief Function for handling all read requests from the Central.
*
* @param[in] p_escs Pointer to the Eddystone Configuration Service.
* @param[in] uuid The UUID of the characteristic that is being read from.
* @param[in] val_handle Value handle field of the characteristic handle of the characteristic that is being read from.
*
*/
void es_gatts_handle_read(nrf_ble_escs_t * p_escs, uint16_t uuid, uint16_t val_handle);
/**@brief Function for sending an RW-authorization reply.
*
* @param[in] p_escs Pointer to the Eddystone Configuration Service.
* @param[in] p_reply Pointer to the reply to send.
*
* @retval NRF_SUCCESS If the reply was successfully issued to the SoftDevice.
* @retval NRF_ERROR_NULL If either of the pointers @p p_escs or @p p_reply is NULL.
* @retval NRF_ERROR_INVALID_STATE If the connection handle of @p p_escs is invalid.
* @return Otherwise, an error code from sd_ble_gatts_rw_authorize_reply() is returned.
*/
ret_code_t es_gatts_send_reply(nrf_ble_escs_t * p_escs, ble_gatts_rw_authorize_reply_params_t * p_reply);
/**@brief Function for sending an RW-authorization reply with status 'Operation not permitted'.
*
* @param[in] p_escs Pointer to the Eddystone Configuration Service.
* @param[in] op_is_read Flag that specifies if the operation being responded to is a 'read' operation.
If false, a 'write' operation is assumed.
*
* @retval NRF_ERROR_NULL If @p p_escs is NULL.
* @return Otherwise, the error code from es_gatts_send_reply() is returned.
*/
ret_code_t es_gatts_send_op_not_permitted(nrf_ble_escs_t * p_escs, bool op_is_read);
/**
* @}
*/
#endif // ES_GATTS_H__

View File

@@ -0,0 +1,246 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 "es_gatts_read.h"
#include "es_adv.h"
#include "es_gatts.h"
#include "es_security.h"
#include "es_slot.h"
static ret_code_t send_read_reply(nrf_ble_escs_t * p_escs, ble_gatts_rw_authorize_reply_params_t * p_reply)
{
VERIFY_PARAM_NOT_NULL(p_escs);
VERIFY_PARAM_NOT_NULL(p_reply);
p_reply->type = BLE_GATTS_AUTHORIZE_TYPE_READ;
p_reply->params.read.update = 1;
p_reply->params.read.offset = 0;
return es_gatts_send_reply(p_escs, p_reply);
}
static ret_code_t read_value(nrf_ble_escs_t * p_escs, uint8_t length, const void * p_value)
{
VERIFY_PARAM_NOT_NULL(p_escs);
VERIFY_PARAM_NOT_NULL(p_value);
ble_gatts_rw_authorize_reply_params_t reply = {0};
reply.params.read.len = length;
reply.params.read.p_data = p_value;
reply.params.read.gatt_status = BLE_GATT_STATUS_SUCCESS;
return send_read_reply(p_escs, &reply);
}
static ret_code_t read_from_gattdb(nrf_ble_escs_t * p_escs, uint16_t val_handle)
{
VERIFY_PARAM_NOT_NULL(p_escs);
ret_code_t err_code;
// Go straight to the characteristic
uint8_t value_buffer[ESCS_ADV_SLOT_CHAR_LENGTH_MAX] = {0};
ble_gatts_value_t value = {.len = sizeof(value_buffer),
.offset = 0,
.p_value = &(value_buffer[0])};
err_code = sd_ble_gatts_value_get(p_escs->conn_handle, val_handle, &value);
RETURN_IF_ERROR(err_code);
return read_value(p_escs, value.len, value.p_value);
}
static ret_code_t read_adv_slot(nrf_ble_escs_t * p_escs, uint8_t active_slot, const es_slot_reg_t * p_reg)
{
VERIFY_PARAM_NOT_NULL(p_escs);
ble_gatts_rw_authorize_reply_params_t reply = {0};
uint8_t eid_buf[14];
// If an EID slot is read, load scaler, clock value and ephemeral ID.
if (p_reg->slots[active_slot].adv_frame.type == ES_FRAME_TYPE_EID)
{
/*lint -save -e666 */
uint32_t clock_value = es_security_clock_get(active_slot);
clock_value = BYTES_REVERSE_32BIT(clock_value);
/*lint -restore */
reply.params.read.len = ES_EID_GATTS_READ_LENGTH;
// Fill EID buffer with data
eid_buf[ES_EID_GATTS_READ_FRAME_TYPE_IDX] = ES_FRAME_TYPE_EID;
eid_buf[ES_EID_GATTS_READ_EXPONENT_IDX] = es_security_scaler_get(active_slot);
memcpy(&eid_buf[ES_EID_GATTS_READ_CLCK_VALUE_IDX], &clock_value, sizeof(clock_value));
/*lint -save -e545 */
memcpy(&eid_buf[ES_EID_GATTS_READ_EID_IDX],
&p_reg->slots[active_slot].adv_frame.frame.eid.eid,
ES_EID_ID_LENGTH);
/*lint -restore */
reply.params.read.p_data = eid_buf;
}
// Otherwise, simply load the contents of the frame.
else
{
// Check if slot being read is an eTLM slot.
if ((p_reg->num_configured_eid_slots > 0) && p_reg->tlm_configured && (p_reg->tlm_slot == active_slot))
{
// Fill eTLM slot using EID key from first EID slot.
es_slot_etlm_update(p_reg->eid_slots_configured[0]);
}
reply.params.read.len = p_reg->slots[active_slot].adv_frame.length;
reply.params.read.p_data = (uint8_t *)&p_reg->slots[active_slot].adv_frame.frame;
}
reply.params.read.gatt_status = BLE_GATT_STATUS_SUCCESS;
return send_read_reply(p_escs, &reply);
}
ret_code_t es_gatts_read_handle_locked_read(nrf_ble_escs_t * p_escs, uint16_t uuid, uint8_t lock_state)
{
VERIFY_PARAM_NOT_NULL(p_escs);
if (uuid == BLE_UUID_ESCS_REMAIN_CONNECTABLE_CHAR)
{
uint8_t retval = APP_IS_REMAIN_CONNECTABLE_SUPPORTED;
return read_value(p_escs, sizeof(retval), &retval);
}
else if (uuid == BLE_UUID_ESCS_LOCK_STATE_CHAR)
{
return read_value(p_escs, sizeof(lock_state), &lock_state);
}
else
{
return es_gatts_send_op_not_permitted(p_escs, true);
}
}
ret_code_t es_gatts_read_handle_unlock(nrf_ble_escs_t * p_escs)
{
VERIFY_PARAM_NOT_NULL(p_escs);
ret_code_t err_code;
uint8_t key_buff[ESCS_AES_KEY_SIZE];
err_code = es_security_random_challenge_generate(key_buff);
RETURN_IF_ERROR(err_code);
es_security_unlock_prepare(key_buff);
return read_value(p_escs, ESCS_AES_KEY_SIZE, key_buff);
}
ret_code_t es_gatts_read_handle_unlocked_read(nrf_ble_escs_t * p_escs,
uint16_t uuid,
uint16_t val_handle,
uint8_t active_slot,
uint8_t lock_state)
{
VERIFY_PARAM_NOT_NULL(p_escs);
const es_slot_reg_t * p_reg = es_slot_get_registry();
switch (uuid)
{
case BLE_UUID_ESCS_BROADCAST_CAP_CHAR:
case BLE_UUID_ESCS_UNLOCK_CHAR:
case BLE_UUID_ESCS_PUBLIC_ECDH_KEY_CHAR:
case BLE_UUID_ESCS_ACTIVE_SLOT_CHAR:
return read_from_gattdb(p_escs, val_handle);
case BLE_UUID_ESCS_LOCK_STATE_CHAR:
return read_value(p_escs, sizeof(lock_state), &lock_state);
case BLE_UUID_ESCS_ADV_INTERVAL_CHAR:
{
nrf_ble_escs_adv_interval_t adv_interval = es_adv_interval_get();
adv_interval = BYTES_SWAP_16BIT(adv_interval);
return read_value(p_escs, sizeof(adv_interval), &adv_interval);
}
case BLE_UUID_ESCS_RADIO_TX_PWR_CHAR:
return read_value(p_escs,
sizeof(nrf_ble_escs_radio_tx_pwr_t),
&p_reg->slots[active_slot].radio_tx_pwr);
case BLE_UUID_ESCS_ADV_TX_PWR_CHAR:
return read_value(p_escs,
sizeof(nrf_ble_escs_radio_tx_pwr_t),
p_reg->slots[active_slot].adv_custom_tx_power
? (uint8_t *)(&p_reg->slots[active_slot].custom_tx_power)
: (uint8_t *)(&p_reg->slots[active_slot].radio_tx_pwr));
case BLE_UUID_ESCS_REMAIN_CONNECTABLE_CHAR:
{
uint8_t retval = APP_IS_REMAIN_CONNECTABLE_SUPPORTED;
return read_value(p_escs, sizeof(retval), &retval);
}
case BLE_UUID_ESCS_EID_ID_KEY_CHAR:
if (p_reg->slots[active_slot].configured &&
(p_reg->slots[active_slot].adv_frame.type == ES_FRAME_TYPE_EID))
{
return read_value(p_escs,
sizeof(nrf_ble_escs_eid_id_key_t),
&p_reg->slots[active_slot].encrypted_eid_id_key);
}
else
{
return es_gatts_send_op_not_permitted(p_escs, true);
}
case BLE_UUID_ESCS_RW_ADV_SLOT_CHAR:
return read_adv_slot(p_escs, active_slot, p_reg);
default:
return NRF_ERROR_INVALID_PARAM;
}
}

View File

@@ -0,0 +1,73 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 ES_GATTS_READ_H__
#define ES_GATTS_READ_H__
#include <stdint.h>
#include "nrf_ble_escs.h"
/**
* @file
* @defgroup eddystone_gatts_read GATTS read
* @brief Functions for handling GATTS read requests.
* @ingroup eddystone_gatts
* @{
*/
ret_code_t es_gatts_read_send_not_permitted(nrf_ble_escs_t * p_escs);
ret_code_t es_gatts_read_handle_unlocked_read(nrf_ble_escs_t * p_escs,
uint16_t uuid,
uint16_t val_handle,
uint8_t active_slot,
uint8_t lock_state);
ret_code_t es_gatts_read_handle_unlock(nrf_ble_escs_t * p_escs);
ret_code_t es_gatts_read_handle_locked_read(nrf_ble_escs_t * p_escs,
uint16_t uuid,
uint8_t lock_state);
/**
* @}
*/
#endif // ES_GATTS_READ_H__

View File

@@ -0,0 +1,254 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 "es_gatts_write.h"
#include "es_adv.h"
#include "es_flash.h"
#include "es_gatts.h"
#include "es_security.h"
static ret_code_t send_write_reply(nrf_ble_escs_t * p_escs, ble_gatts_rw_authorize_reply_params_t * p_reply)
{
VERIFY_PARAM_NOT_NULL(p_escs);
VERIFY_PARAM_NOT_NULL(p_reply);
p_reply->type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
p_reply->params.write.update = 1;
p_reply->params.write.offset = 0;
return es_gatts_send_reply(p_escs, p_reply);
}
/**@brief Function checking if length of event is correct, given the frame data.
*
* @param[in] p_data Written ADV Slot data.
* @param[in] length Written length.
*
* @retval true If length is valid.
* @retval false If length is not valid.
*/
static bool length_is_valid(uint8_t * p_data, uint8_t length)
{
if (length == 0 || (length == 1 && p_data[0] == 0))
{
return true;
}
else
{
switch ((es_frame_type_t)p_data[0])
{
case ES_FRAME_TYPE_UID:
return length == ESCS_UID_WRITE_LENGTH;
case ES_FRAME_TYPE_URL:
return ((length >= ESCS_URL_MIN_WRITE_LENGTH) && (length <= ESCS_URL_WRITE_LENGTH));
case ES_FRAME_TYPE_TLM:
return (length == ESCS_TLM_WRITE_LENGTH);
case ES_FRAME_TYPE_EID:
return ((length == ESCS_EID_WRITE_ECDH_LENGTH) ||
(length == ESCS_EID_WRITE_IDK_LENGTH));
default:
return false;
}
}
}
ret_code_t es_gatts_write_handle_unlocked_write(nrf_ble_escs_t * p_escs,
uint16_t uuid,
uint16_t val_handle,
uint8_t * p_data,
uint16_t length,
uint8_t active_slot)
{
VERIFY_PARAM_NOT_NULL(p_escs);
VERIFY_PARAM_NOT_NULL(p_data);
ret_code_t err_code;
ble_gatts_rw_authorize_reply_params_t reply = {0};
bool long_write = false;
reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
switch (uuid)
{
case BLE_UUID_ESCS_ACTIVE_SLOT_CHAR:
if (*p_data > APP_MAX_ADV_SLOTS - 1)
{
// Invalid Attribute Length: for an attempt to write illegal values.
// The beacon will list the total number of available slots in the
// max_supported_total_slots field in the Capabilities characteristic.
reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH;
length = 0;
}
break;
case BLE_UUID_ESCS_ADV_INTERVAL_CHAR:
es_adv_interval_set(BYTES_SWAP_16BIT(*(nrf_ble_escs_adv_interval_t *)p_data));
break;
case BLE_UUID_ESCS_RADIO_TX_PWR_CHAR:
es_slot_radio_tx_pwr_set(active_slot, *(nrf_ble_escs_radio_tx_pwr_t *)(p_data));
break;
case BLE_UUID_ESCS_ADV_TX_PWR_CHAR:
// Update slot info so that ADV data will only be read from what is written by client.
es_slot_set_adv_custom_tx_power(active_slot, *(nrf_ble_escs_radio_tx_pwr_t *)(p_data));
break;
case BLE_UUID_ESCS_LOCK_STATE_CHAR:
if (length == 1 && (*p_data == NRF_BLE_ESCS_LOCK_BYTE_LOCK ||
*p_data == NRF_BLE_ESCS_LOCK_BYTE_DISABLE_AUTO_RELOCK))
{
// Do nothing special, allow the write.
}
else if (length == ESCS_LOCK_STATE_NEW_LOCK_CODE_WRITE_LENGTH &&
*p_data == NRF_BLE_ESCS_LOCK_BYTE_LOCK)
{
// 0x00 + key[16] : transition to lock state and update the lock code.
err_code = es_security_lock_code_update((p_data) + 1);
RETURN_IF_ERROR(err_code);
// Only write the lock byte (0x00) to the characteristic, so set length to 1.
length = 1;
}
else
{
// Any invalid values locks the characteristic by default.
*p_data = NRF_BLE_ESCS_LOCK_BYTE_LOCK;
length = 1;
}
break;
case BLE_UUID_ESCS_RW_ADV_SLOT_CHAR:
if (length > 20)
{
long_write = true;
}
reply.params.write.gatt_status = length_is_valid(p_data, length)
? BLE_GATT_STATUS_SUCCESS
: BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH;
if (reply.params.write.gatt_status == BLE_GATT_STATUS_SUCCESS)
{
es_slot_on_write(active_slot, length, p_data);
es_adv_interval_set(es_adv_interval_get()); // Ensure that valid advertisement interval is used.
}
break;
case BLE_UUID_ESCS_FACTORY_RESET_CHAR:
if (*p_data == 0x0B)
{
err_code = es_flash_factory_reset();
RETURN_IF_ERROR(err_code);
}
break;
case BLE_UUID_ESCS_REMAIN_CONNECTABLE_CHAR:
#if APP_IS_REMAIN_CONNECTABLE_SUPPORTED == ESCS_FUNCT_REMAIN_CONNECTABLE_SUPPORTED_Yes
if (*p_data != 0)
{
es_adv_remain_connectable_set(true);
}
else
{
es_adv_remain_connectable_set(false);
}
#endif
break;
default:
break;
}
reply.params.write.len = length;
reply.params.write.p_data = p_data;
if (!long_write)
{
return send_write_reply(p_escs, &reply);
}
else
{
return NRF_SUCCESS;
}
}
ret_code_t es_gatts_write_handle_unlock(nrf_ble_escs_t * p_escs,
uint8_t * p_data,
uint16_t length,
uint16_t val_handle)
{
VERIFY_PARAM_NOT_NULL(p_escs);
VERIFY_PARAM_NOT_NULL(p_data);
ret_code_t err_code;
ble_gatts_rw_authorize_reply_params_t reply = {0};
ble_gatts_value_t value = {.len = length, .offset = 0, .p_value = p_data};
if (length == ESCS_AES_KEY_SIZE)
{
err_code = sd_ble_gatts_value_set(p_escs->conn_handle, val_handle, &value);
if (err_code == NRF_SUCCESS)
{
reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
es_security_unlock_verify((value.p_value));
}
else
{
reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_WRITE_NOT_PERMITTED;
}
}
reply.params.write.len = length;
reply.params.write.p_data = (const uint8_t *)value.p_value;
return send_write_reply(p_escs, &reply);
}

View File

@@ -0,0 +1,71 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 ES_GATTS_WRITE_H__
#define ES_GATTS_WRITE_H__
#include <stdint.h>
#include "nrf_ble_escs.h"
/**
* @file
* @defgroup eddystone_gatts_write GATTS write
* @brief Functions for handling GATTS write requests.
* @ingroup eddystone_gatts
* @{
*/
ret_code_t es_gatts_write_handle_unlocked_write(nrf_ble_escs_t * p_escs,
uint16_t uuid,
uint16_t val_handle,
uint8_t * p_data,
uint16_t length,
uint8_t active_slot);
ret_code_t es_gatts_write_handle_unlock(nrf_ble_escs_t * p_escs,
uint8_t * p_data,
uint16_t length,
uint16_t val_handle);
/**
* @}
*/
#endif // ES_GATTS_WRITE_H__

View File

@@ -0,0 +1,531 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 <stdbool.h>
#include <stdint.h>
#include "es_security.h"
#include "aes.h"
#include "app_timer.h"
#include "cifra_eax_aes.h"
#include "es_flash.h"
#include "es_stopwatch.h"
#include "fds.h"
#include "modes.h"
#include "occ_curve25519.h"
#include "occ_hmac_sha256.h"
#define TK_ROLLOVER 0x10000
#define NONCE_SIZE (6)
#define TAG_SIZE (2)
#define SALT_SIZE (2)
#define TLM_DATA_SIZE (ES_TLM_LENGTH - 2)
#define EIK_SIZE (ESCS_AES_KEY_SIZE)
/**@brief Timing structure. */
typedef struct
{
uint32_t time_counter;
uint8_t k_scaler;
} es_security_timing_t;
/**@brief Security slot structure. */
typedef struct
{
nrf_ecb_hal_data_t aes_ecb_ik;
nrf_ecb_hal_data_t aes_ecb_tk;
uint8_t eid[ES_EID_ID_LENGTH];
es_security_timing_t timing;
bool is_occupied;
} es_security_slot_t;
/**@brief Key pair structure. */
typedef struct
{
uint8_t private[ESCS_ECDH_KEY_SIZE];
uint8_t public[ESCS_ECDH_KEY_SIZE];
} ecdh_key_pair_t;
/**@brief ECDH structure. */
typedef struct
{
ecdh_key_pair_t ecdh_key_pair;
} es_security_ecdh_t;
static nrf_ecb_hal_data_t m_aes_ecb_lk;
static es_security_slot_t m_security_slot[APP_MAX_EID_SLOTS];
static es_security_ecdh_t m_ecdh;
static es_security_msg_cb_t m_security_callback;
static es_stopwatch_id_t m_seconds_passed_sw_id;
/**@brief Generates a EID with the Temporary Key*/
static void eid_generate(uint8_t slot_no)
{
memset(m_security_slot[slot_no].aes_ecb_tk.cleartext, 0, ESCS_AES_KEY_SIZE);
m_security_slot[slot_no].aes_ecb_tk.cleartext[11] = m_security_slot[slot_no].timing.k_scaler;
uint32_t k_bits_cleared_time =
(m_security_slot[slot_no].timing.time_counter >> m_security_slot[slot_no].timing.k_scaler)
<< m_security_slot[slot_no].timing.k_scaler;
m_security_slot[slot_no].aes_ecb_tk.cleartext[12] =
(uint8_t)((k_bits_cleared_time >> 24) & 0xff);
m_security_slot[slot_no].aes_ecb_tk.cleartext[13] =
(uint8_t)((k_bits_cleared_time >> 16) & 0xff);
m_security_slot[slot_no].aes_ecb_tk.cleartext[14] = (uint8_t)((k_bits_cleared_time >> 8) & 0xff);
m_security_slot[slot_no].aes_ecb_tk.cleartext[15] = (uint8_t)((k_bits_cleared_time) & 0xff);
AES128_ECB_encrypt(m_security_slot[slot_no].aes_ecb_tk.cleartext,
m_security_slot[slot_no].aes_ecb_tk.key,
m_security_slot[slot_no].aes_ecb_tk.ciphertext);
memcpy(m_security_slot[slot_no].eid,
m_security_slot[slot_no].aes_ecb_tk.ciphertext,
ES_EID_ID_LENGTH);
m_security_callback(slot_no, ES_SECURITY_MSG_EID);
}
/**@brief Generates a temporary key with the Identity key. */
static void temp_key_generate(uint8_t slot_no)
{
memset(m_security_slot[slot_no].aes_ecb_ik.cleartext, 0, ESCS_AES_KEY_SIZE);
m_security_slot[slot_no].aes_ecb_ik.cleartext[11] = 0xFF;
m_security_slot[slot_no].aes_ecb_ik.cleartext[14] =
(uint8_t)((m_security_slot[slot_no].timing.time_counter >> 24) & 0xff);
m_security_slot[slot_no].aes_ecb_ik.cleartext[15] =
(uint8_t)((m_security_slot[slot_no].timing.time_counter >> 16) & 0xff);
AES128_ECB_encrypt(m_security_slot[slot_no].aes_ecb_ik.cleartext,
m_security_slot[slot_no].aes_ecb_ik.key,
m_security_slot[slot_no].aes_ecb_ik.ciphertext);
memcpy(m_security_slot[slot_no].aes_ecb_tk.key,
m_security_slot[slot_no].aes_ecb_ik.ciphertext,
ESCS_AES_KEY_SIZE);
}
static void check_rollovers_and_update_eid(uint8_t slot_no)
{
if (m_security_slot[slot_no].timing.time_counter % TK_ROLLOVER == 0)
{
temp_key_generate(slot_no);
}
/*lint -save -e573 */
if ((m_security_slot[slot_no].timing.time_counter %
(2 << (m_security_slot[slot_no].timing.k_scaler - 1))) == 0)
{
eid_generate(slot_no);
}
/*lint -restore */
}
/**@brief Initialize lock code from flash. If it does not exist, copy from APP_CONFIG_LOCK_CODE.
*/
static void lock_code_init(uint8_t * p_lock_buff)
{
ret_code_t err_code;
err_code = es_flash_access_lock_key(p_lock_buff, ES_FLASH_ACCESS_READ);
FLASH_ACCES_ERROR_CHECK_ALLOW_NOT_FOUND(err_code);
// If no lock keys exist, then generate one and copy it to buffer.
if (err_code == FDS_ERR_NOT_FOUND)
{
uint8_t lock_code[16] = APP_CONFIG_LOCK_CODE;
memcpy(p_lock_buff, lock_code, sizeof(lock_code));
err_code = es_flash_access_lock_key(p_lock_buff, ES_FLASH_ACCESS_WRITE);
APP_ERROR_CHECK(err_code);
}
}
/**@brief Generates a the private/public ECDH key pair.
*
* @param[out] p_priv_buffer buffer of size 32 bytes to hold the private key.
* @param[out] p_pub_buffer buffer of size 32 bytes to hold the public key.
*/
static void es_beacon_ecdh_pair_generate(uint8_t * p_priv_buffer, uint8_t * p_pub_buffer)
{
// Generate random beacon private key.
uint8_t pool_size;
uint8_t bytes_available;
(void)sd_rand_application_pool_capacity_get(&pool_size);
(void)sd_rand_application_bytes_available_get(&bytes_available);
while (bytes_available < pool_size)
{
// wait for SD to acquire enough RNs.
(void)sd_rand_application_bytes_available_get(&bytes_available);
}
(void)sd_rand_application_vector_get(p_priv_buffer, pool_size);
if (pool_size < ESCS_ECDH_KEY_SIZE)
{
(void)sd_rand_application_bytes_available_get(&bytes_available);
while (bytes_available < (ESCS_ECDH_KEY_SIZE - pool_size))
{
// Wait for SD to acquire enough RNs.
(void)sd_rand_application_bytes_available_get(&bytes_available);
}
(void)sd_rand_application_vector_get(p_priv_buffer + pool_size,
ESCS_ECDH_KEY_SIZE - pool_size);
}
// Create beacon public 32-byte ECDH key from private 32-byte ECDH key.
occ_curve25519_scalarmult_base(p_pub_buffer, p_priv_buffer);
}
void es_security_update_time(void)
{
static uint32_t timer_persist;
uint32_t second_since_last_invocation = es_stopwatch_check(m_seconds_passed_sw_id);
if (second_since_last_invocation > 0)
{
for (uint32_t i = 0; i < APP_MAX_EID_SLOTS; ++i)
{
if (m_security_slot[i].is_occupied)
{
m_security_slot[i].timing.time_counter += second_since_last_invocation;
check_rollovers_and_update_eid(i);
}
}
// Every 24 hr, write the new EID timer to flash.
timer_persist += second_since_last_invocation;
const uint32_t TWENTY_FOUR_HOURS = 60 * 60 * 24;
if (timer_persist >= TWENTY_FOUR_HOURS)
{
for (uint32_t i = 0; i < APP_MAX_EID_SLOTS; ++i)
{
if (m_security_slot[i].is_occupied)
{
m_security_callback(i, ES_SECURITY_MSG_STORE_TIME);
}
}
timer_persist = 0;
}
}
}
void es_security_eid_slots_restore(uint8_t slot_no,
uint8_t k_scaler,
uint32_t time_counter,
const uint8_t * p_ik)
{
m_security_slot[slot_no].timing.k_scaler = k_scaler;
m_security_slot[slot_no].timing.time_counter = time_counter;
memcpy(m_security_slot[slot_no].aes_ecb_ik.key, p_ik, ESCS_AES_KEY_SIZE);
m_security_slot[slot_no].is_occupied = true;
m_security_callback(slot_no, ES_SECURITY_MSG_IK);
temp_key_generate(slot_no);
eid_generate(slot_no);
}
ret_code_t es_security_lock_code_update(uint8_t * p_ecrypted_key)
{
uint8_t temp_buff[ESCS_AES_KEY_SIZE] = {0};
AES128_ECB_decrypt(p_ecrypted_key, m_aes_ecb_lk.key, temp_buff);
memcpy(m_aes_ecb_lk.key, temp_buff, ESCS_AES_KEY_SIZE);
return es_flash_access_lock_key(m_aes_ecb_lk.key, ES_FLASH_ACCESS_WRITE);
}
void es_security_unlock_prepare(uint8_t * p_challenge)
{
memcpy(m_aes_ecb_lk.cleartext, p_challenge, ESCS_AES_KEY_SIZE);
AES128_ECB_encrypt(m_aes_ecb_lk.cleartext, m_aes_ecb_lk.key, m_aes_ecb_lk.ciphertext);
}
void es_security_unlock_verify(uint8_t * p_unlock_token)
{
if (memcmp(p_unlock_token, m_aes_ecb_lk.ciphertext, ESCS_AES_KEY_SIZE) == 0)
{
m_security_callback(0, ES_SECURITY_MSG_UNLOCKED);
}
}
ret_code_t es_security_random_challenge_generate(uint8_t * p_rand_chlg_buff)
{
return sd_rand_application_vector_get(p_rand_chlg_buff, ESCS_AES_KEY_SIZE);
}
void es_security_shared_ik_receive(uint8_t slot_no, uint8_t * p_encrypted_ik, uint8_t scaler_k)
{
m_security_slot[slot_no].is_occupied = true;
m_security_slot[slot_no].timing.k_scaler = scaler_k;
m_security_slot[slot_no].timing.time_counter = APP_CONFIG_TIMING_INIT_VALUE;
AES128_ECB_decrypt(p_encrypted_ik, m_aes_ecb_lk.key, m_security_slot[slot_no].aes_ecb_ik.key);
temp_key_generate(slot_no);
eid_generate(slot_no);
m_security_callback(slot_no, ES_SECURITY_MSG_IK);
}
void es_security_client_pub_ecdh_receive(uint8_t slot_no, uint8_t * p_pub_ecdh, uint8_t scaler_k)
{
static uint8_t attempt_counter = 0;
m_security_slot[slot_no].is_occupied = true;
m_security_slot[slot_no].timing.k_scaler = scaler_k;
m_security_slot[slot_no].timing.time_counter = APP_CONFIG_TIMING_INIT_VALUE;
uint8_t beacon_private[ESCS_ECDH_KEY_SIZE]; // Beacon private ECDH key
uint8_t beacon_public[ESCS_ECDH_KEY_SIZE]; // Beacon public ECDH key
uint8_t phone_public[ESCS_ECDH_KEY_SIZE]; // Phone public ECDH key
uint8_t shared[ESCS_ECDH_KEY_SIZE]; // Shared secret ECDH key
const uint8_t salt[1] = {0x01}; // Salt
uint8_t identity_key[ESCS_AES_KEY_SIZE]; // Identity Key
// Get public 32-byte service ECDH key from phone.
memcpy(phone_public, p_pub_ecdh, ESCS_ECDH_KEY_SIZE);
// Generate new set of keys for use with this EID slot.
es_beacon_ecdh_pair_generate(beacon_private, beacon_public);
memcpy(m_ecdh.ecdh_key_pair.private, beacon_private, ESCS_ECDH_KEY_SIZE);
memcpy(m_ecdh.ecdh_key_pair.public, beacon_public, ESCS_ECDH_KEY_SIZE);
// Generate shared 32-byte ECDH secret from beacon private service ECDH key and phone public ECDH key.
occ_curve25519_scalarmult(shared, beacon_private, phone_public);
// Generate key material using shared ECDH secret as salt and public_keys as key material. RFC 2104 HMAC-SHA256.
uint8_t digest[64];
uint8_t public_keys[64];
memcpy(public_keys, phone_public, 32);
memcpy(public_keys + 32, beacon_public, 32);
occ_hmac_sha256(digest, public_keys, 64, shared, 32);
// Zero check of the shared secret becoming zero, try generating a new key pair if so. Max attempt limit twice.
uint8_t empty_check[32] = {0};
if (memcmp(empty_check, shared, 32) == 0)
{
if (attempt_counter < 2)
{
attempt_counter++;
es_beacon_ecdh_pair_generate(beacon_private, beacon_public);
}
}
else
{
attempt_counter = 0;
}
// Generate 16-byte Identity Key from shared ECDH secret using RFC 2104 HMAC-SHA256 and salt.
uint8_t digest_salted[64];
occ_hmac_sha256(digest_salted, digest, 32, salt, 1);
memcpy(identity_key, digest_salted, ESCS_AES_KEY_SIZE);
memcpy(m_security_slot[slot_no].aes_ecb_ik.key, identity_key, ESCS_AES_KEY_SIZE);
temp_key_generate(slot_no);
eid_generate(slot_no);
m_security_callback(slot_no, ES_SECURITY_MSG_ECDH);
m_security_callback(slot_no, ES_SECURITY_MSG_IK);
}
void es_security_pub_ecdh_get(uint8_t slot_no, uint8_t * p_edch_buffer)
{
memcpy(p_edch_buffer, m_ecdh.ecdh_key_pair.public, ESCS_ECDH_KEY_SIZE);
}
uint32_t es_security_clock_get(uint8_t slot_no)
{
return m_security_slot[slot_no].timing.time_counter;
}
void es_security_eid_slot_destroy(uint8_t slot_no)
{
memset(&m_security_slot[slot_no], 0, sizeof(es_security_slot_t));
}
uint8_t es_security_scaler_get(uint8_t slot_no)
{
return m_security_slot[slot_no].timing.k_scaler;
}
void es_security_eid_get(uint8_t slot_no, uint8_t * p_eid_buffer)
{
memcpy(p_eid_buffer, m_security_slot[slot_no].eid, ES_EID_ID_LENGTH);
}
void es_security_encrypted_eid_id_key_get(uint8_t slot_no, uint8_t * p_key_buffer)
{
memcpy(m_aes_ecb_lk.cleartext, m_security_slot[slot_no].aes_ecb_ik.key, ESCS_AES_KEY_SIZE);
AES128_ECB_encrypt(m_aes_ecb_lk.cleartext, m_aes_ecb_lk.key, m_aes_ecb_lk.ciphertext);
memcpy(p_key_buffer, m_aes_ecb_lk.ciphertext, ESCS_AES_KEY_SIZE);
}
void es_security_plain_eid_id_key_get(uint8_t slot_no, uint8_t * p_key_buffer)
{
memcpy(p_key_buffer, m_security_slot[slot_no].aes_ecb_ik.key, ESCS_AES_KEY_SIZE);
}
void es_security_tlm_to_etlm(uint8_t ik_slot_no, es_tlm_frame_t * p_tlm, es_etlm_frame_t * p_etlm)
{
cf_prp prp; // Describe the block cipher to use.
uint8_t plain[TLM_DATA_SIZE] = {0}; // Plaintext tlm, without the frame byte and version.
size_t nplain = TLM_DATA_SIZE; // Length of message plaintext.
/*lint -save -e420 */
memcpy(plain, &p_tlm->vbatt[0], sizeof(plain));
const uint8_t header = 0; // Additionally authenticated data (AAD).
size_t nheader = 0; // Length of header (AAD). May be zero.
uint8_t key[EIK_SIZE] = {0}; // Encryption/decryption key: EIK.
size_t nkey = EIK_SIZE; // Length of encryption/decryption key.
memcpy(key, &m_security_slot[ik_slot_no].aes_ecb_ik.key[0], EIK_SIZE);
/*lint -restore */
uint8_t nonce[NONCE_SIZE] = {0}; // Nonce. This must not repeat for a given key.
size_t nnonce = NONCE_SIZE; // Length of nonce.First 4 bytes are beacon time base with k-bits cleared.
// Last two bits are randomly generated
// Take the current timestamp and clear the lowest K bits, use it as nonce.
uint32_t k_bits_cleared_time = (m_security_slot[ik_slot_no].timing.time_counter
>> m_security_slot[ik_slot_no].timing.k_scaler)
<< m_security_slot[ik_slot_no].timing.k_scaler;
nonce[0] = (uint8_t)((k_bits_cleared_time >> 24) & 0xff);
nonce[1] = (uint8_t)((k_bits_cleared_time >> 16) & 0xff);
nonce[2] = (uint8_t)((k_bits_cleared_time >> 8) & 0xff);
nonce[3] = (uint8_t)((k_bits_cleared_time) & 0xff);
// Generate random salt.
uint8_t salt[SALT_SIZE] = {0};
(void)sd_rand_application_vector_get(salt, SALT_SIZE);
memcpy(&nonce[4], salt, SALT_SIZE);
uint8_t cipher[ES_ETLM_ECRYPTED_LENGTH]; // Ciphertext output. nplain bytes are written.
uint8_t tag[TAG_SIZE] = {0}; // Authentication tag. ntag bytes are written.
size_t ntag = TAG_SIZE; // Length of authentication tag.
// Encryption
// --------------------------------------------------------------------------
cf_aes_context ctx;
cf_aes_init(&ctx, key, nkey);
prp.encrypt = (cf_prp_block)cf_aes_encrypt; // Encryption context
prp.decrypt = (cf_prp_block)cf_aes_decrypt; // Decryption context
prp.blocksz = ESCS_AES_KEY_SIZE;
cf_eax_encrypt(&prp,
&ctx,
plain, // Plaintext input, aka TLM
nplain, // Length of TLM
&header, // Empty
nheader, // Empty
nonce, // Nonce input
nnonce, // Length of nonce
cipher, // Encrypted output
tag, // Authentication tag output
ntag // Length of authentication tag
);
// Construct the eTLM.
// --------------------------------------------------------------------------
p_etlm->frame_type = p_tlm->frame_type;
p_etlm->version = ES_TLM_VERSION_ETLM;
memcpy(p_etlm->encrypted_tlm, cipher, ES_ETLM_ECRYPTED_LENGTH);
memcpy((uint8_t *)&p_etlm->random_salt, salt, SALT_SIZE);
memcpy((uint8_t *)&p_etlm->msg_integrity_check, tag, TAG_SIZE);
}
ret_code_t es_security_init(es_security_msg_cb_t security_callback)
{
ret_code_t err_code;
if (security_callback == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
// Get lock code from 'es_app_config.h', or fetch it from flash if exists.
lock_code_init(m_aes_ecb_lk.key);
m_security_callback = security_callback;
memset(&m_ecdh, 0, sizeof(es_security_ecdh_t));
for (uint32_t i = 0; i < APP_MAX_EID_SLOTS; ++i)
{
m_security_slot[i].timing.time_counter = APP_CONFIG_TIMING_INIT_VALUE;
}
err_code = es_stopwatch_create(&m_seconds_passed_sw_id, APP_TIMER_TICKS(1000, APP_TIMER_PRESCALER));
APP_ERROR_CHECK(err_code);
return NRF_SUCCESS;
}

View File

@@ -0,0 +1,239 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 ES_SECURITY_H__
#define ES_SECURITY_H__
#include "app_error.h"
#include "nrf_ble_escs.h"
/**
* @file
* @defgroup eddystone_security Security
* @brief Types and functions for dealing with security of Eddystone beacons.
* @ingroup eddystone
* @{
*/
/**@brief Security events.
*/
typedef enum
{
ES_SECURITY_MSG_UNLOCKED, //!< Beacon is unlocked.
ES_SECURITY_MSG_EID, //!< EID has been generated.
ES_SECURITY_MSG_IK, //!< IK has been generated.
ES_SECURITY_MSG_ECDH, //!< Public ECDH has been generated.
ES_SECURITY_MSG_STORE_TIME //!< EID slot time must be stored.
} es_security_msg_t;
/* @brief Callback for security events. */
typedef void (*es_security_msg_cb_t)(uint8_t slot_no, es_security_msg_t msg_type);
/**@brief EID configuration.
*
* @details This structure is used to preserve or restore an EID slot.
*
* @note This is a packed structure. Therefore, you should not change it.
*/
typedef PACKED_STRUCT
{
es_frame_type_t frame_type;
uint8_t k_scaler;
uint32_t time_counter;
uint8_t ik[ESCS_AES_KEY_SIZE];
} es_eid_config_t;
/**@brief Eddystone beacon lock state.
*/
typedef nrf_ble_escs_lock_state_read_t es_security_lock_state_t;
/**@brief Function for initializing the security module.
*
* @param[in] msg_cb Callback function.
*
* @return See @ref app_timer_start for possible return values.
*/
ret_code_t es_security_init(es_security_msg_cb_t msg_cb);
/**@brief Function for updating the lock code and storing it to flash.
*
* @param[in] p_encrypted_key Pointer to the new lock code.
*
* @return See @ref es_flash_access_lock_key for possible return values.
*/
ret_code_t es_security_lock_code_update(uint8_t * p_encrypted_key);
/**@brief Function for reading the challenge and encrypting it with AES_ECB.
*
* @details The result of the encryption is compared with the provided unlock token
* in @ref es_security_unlock_verify.
*
* @param[in] p_challenge Pointer to the challenge buffer.
*
* @return See @ref sd_ecb_block_encrypt for possible return values.
*/
void es_security_unlock_prepare(uint8_t * p_challenge);
/**@brief Function for unlocking the beacon.
*
* @details This function compares the result from @ref es_security_unlock_prepare to the input
* unlock token and unlocks the beacon if matching.
*
* @param[in] p_unlock_token The unlock token written by the client.
*/
void es_security_unlock_verify(uint8_t * p_unlock_token);
/**@brief Function for generating a random challenge for the unlock characteristic.
*
* @param[out] p_rand_chlg_buff Pointer to a buffer to which the random challenge is copied.
*
* @return See @ref sd_rand_application_vector_get for possible return values.
*/
ret_code_t es_security_random_challenge_generate(uint8_t * p_rand_chlg_buff);
/**@brief Function for storing the public ECDH key from the client in the beacon registration process.
*
* @details This function starts a series of cryptographic activities, including the generation of temporary keys and EIDs.
*
* @param[in] slot_no The index of the slot whose public ECDH key is retrieved.
* @param[in] p_pub_ecdh Pointer to the public ECDH.
* @param[in] scaler_k K rotation scaler.
*/
void es_security_client_pub_ecdh_receive(uint8_t slot_no, uint8_t * p_pub_ecdh, uint8_t scaler_k);
/**@brief Function for storing the shared IK from the client in the beacon registration process.
*
* @details This function starts a series of cryptographic activities, including the generation of temporary keys and EIDs.
*
* @param[in] slot_no The index of the slot whose public ECDH key is retrieved.
* @param[in] p_encrypted_ik Pointer to the received IK.
* @param[in] scaler_k K rotation scaler.
*/
void es_security_shared_ik_receive(uint8_t slot_no, uint8_t * p_encrypted_ik, uint8_t scaler_k);
/**@brief Function for copying the 32-byte ECDH key into the provided buffer.
*
* @param[in] slot_no The index of the slot whose public ECDH key is retrieved.
* @param[out] p_edch_buffer Pointer to the buffer.
*/
void es_security_pub_ecdh_get(uint8_t slot_no, uint8_t * p_edch_buffer);
/**@brief Function for returning the beacon clock value (in little endian).
*
* @param[in] slot_no The index of the slot.
*
* @return 32-bit clock value.
*/
uint32_t es_security_clock_get(uint8_t slot_no);
/**@brief Function for updating the beacon time counter.
*
* @details This function checks how much time has passed since the last
* invocation and, if required, updates the EID, the temporary key, or both.
* The function generates an @ref ES_SECURITY_MSG_STORE_TIME event
* for each active security slot every 24 hours.
*/
void es_security_update_time(void);
/**@brief Function for returning the rotation exponent scaler value.
*
* @param[in] slot_no The index of the slot.
*
* @return K rotation scaler.
*/
uint8_t es_security_scaler_get(uint8_t slot_no);
/**@brief Function for copying the 8-byte EID into the provided buffer.
*
* @param[in] slot_no The index of the slot whose EID is retrieved.
* @param[out] p_eid_buffer Pointer to the buffer.
*/
void es_security_eid_get(uint8_t slot_no, uint8_t * p_eid_buffer);
/**@brief Function for restoring an EID slot.
*
* @param[in] slot_no The index of the slot to restore.
* @param[in] k_scaler K rotation scaler.
* @param[in] time_counter EID slot time counter value (in seconds).
* @param[in] p_ik Pointer to the identity key of the specified slot.
*/
void es_security_eid_slots_restore(uint8_t slot_no,
uint8_t k_scaler,
uint32_t time_counter,
const uint8_t * p_ik);
/**@brief Function for destroying stored EID states.
*
* @details This function should be called when the slot is either overwritten as another slot or
* cleared by writing an empty byte or a single 0.
*
* @param[in] slot_no The index of the slot to destroy.
*/
void es_security_eid_slot_destroy(uint8_t slot_no);
/**@brief Function for copying the 16-byte EID ID key into the provided buffer.
*
* @param[in] slot_no The index of the EID slot whose IK is retrieved.
* @param[out] p_key_buffer Buffer for the key.
*/
void es_security_plain_eid_id_key_get(uint8_t slot_no, uint8_t * p_key_buffer);
/**@brief Function for copying the 16-byte LK encrypted EID ID key into the provided buffer.
*
* @param[in] slot_no The index of the EID slot whose encrypted IK is retrieved.
* @param[out] p_key_buffer Buffer for the key.
*/
void es_security_encrypted_eid_id_key_get(uint8_t slot_no, uint8_t * p_key_buffer);
/**@brief Function for converting a TLM frame into an eTLM frame using the EIK of the specified slot.
*
* @param[in] ik_slot_no The index of the EID slot whose IK is paired with the eTLM.
* @param[in] p_tlm Pointer to the TLM frame buffer.
* @param[out] p_etlm Pointer to the eTLM frame buffer.
*/
void es_security_tlm_to_etlm(uint8_t ik_slot_no, es_tlm_frame_t * p_tlm, es_etlm_frame_t * p_etlm);
/**
* @}
*/
#endif // ES_SECURITY_H__

View File

@@ -0,0 +1,80 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 <stdint.h>
#include <stdbool.h>
#include "app_timer.h"
#include "es_app_config.h"
#define TICKS_1_SECOND APP_TIMER_TICKS(1000, APP_TIMER_PRESCALER)
static uint32_t m_ticks_last_returned_second = 0; //!< Tick count at last second returned from 'es_security_timing_seconds_passed'.
uint32_t es_security_timing_seconds_passed(void)
{
uint32_t ticks_current = app_timer_cnt_get();
uint32_t ticks_diff;
uint32_t err_code;
err_code = app_timer_cnt_diff_compute(ticks_current, m_ticks_last_returned_second, &ticks_diff);
APP_ERROR_CHECK(err_code);
if(ticks_diff > TICKS_1_SECOND)
{
// Update 'm_ticks_last_returned_second' so it points to the last 'whole second' as it is this point we are referring to when
// returning the number of seconds passed since last invocation.
// I.E. if this function is called after 1.5 seconds and 2.0 seconds, 'm_ticks_last_returned_second' must point to 1.0 seconds
// after the first invocation in order to return '1' upon the second invocation.
uint32_t current_second_ms = (ticks_current / TICKS_1_SECOND) * 1000;
m_ticks_last_returned_second = APP_TIMER_TICKS(current_second_ms, APP_TIMER_PRESCALER);
return ticks_diff / TICKS_1_SECOND;
}
return 0;
}
void es_security_timing_init(void)
{
m_ticks_last_returned_second = 0;
}

View File

@@ -0,0 +1,68 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 ES_SECURITY_TIMING_H__
#define ES_SECURITY_TIMING_H__
#include <stdint.h>
/**
* @file
* @addtogroup eddystone_security
* @{
*/
/**@brief Function for getting the number of seconds passed since the last invocation.
* @details If the function returns zero, the 'last time called' state is not updated. If a non-zero value
* is returned, the 'last time called' state will point to the last whole second.
* @return Number of seconds passed since the last invocation.
*/
uint32_t es_security_timing_seconds_passed(void);
/**@brief Function for initializing the security timing module.
*/
void es_security_timing_init(void);
/**
* @}
*/
#endif // ES_SECURITY_TIMING_H__

View File

@@ -0,0 +1,441 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 <stdint.h>
#include <string.h>
#include "es_slot.h"
#include "es_flash.h"
#include "es_security.h"
#include "es_slot_reg.h"
#include "es_tlm.h"
#include "fds.h"
static es_slot_reg_t m_reg; //!< Slot registry.
static bool m_eid_loaded_from_flash; //!< Set to true if EID slot has been loaded from flash.
#define RANGING_DATA_INDEX (1) //!< Index of ranging data within frames that contain ranging data.
#define RANGING_DATA_LENGTH (1) //!< Length of ranging data.
/**@brief Enforce legal slot number.
*
* @param[in] p_slot Pointer to the slot number variable to check.
*/
static void slot_boundary_check(uint8_t * p_slot)
{
if (*p_slot > (APP_MAX_ADV_SLOTS - 1))
{
*p_slot = (APP_MAX_ADV_SLOTS - 1);
}
}
/**@brief Function loading slot data from flash.
*
* @param[in] slot_no Slot number to be used.
*/
static void load_slot_from_flash(uint8_t slot_no)
{
ret_code_t err_code;
err_code = es_flash_access_slot_configs(slot_no, &m_reg.slots[slot_no], ES_FLASH_ACCESS_READ);
if (err_code != FDS_ERR_NOT_FOUND)
{
APP_ERROR_CHECK(err_code);
if (m_reg.slots[slot_no].adv_frame.type == ES_FRAME_TYPE_EID)
{
m_eid_loaded_from_flash = true;
es_security_eid_slots_restore(slot_no,
m_reg.slots[slot_no].k_scaler,
m_reg.slots[slot_no].seconds,
(const uint8_t *)m_reg.slots[slot_no].ik);
}
else
{
// If a non-EID slot has been loaded, update the state of m_reg immediately.
es_slot_reg_update_slot_list_info_on_add(&m_reg, slot_no, m_reg.slots[slot_no].adv_frame.type, true);
}
}
}
/**@brief Function for setting the ranging data field to be broadcast in the frame.
*
* @param[in] slot_no The slot index.
* @param[in] tx_power The radio tx power to be calibrated to ranging data.
*/
static void set_ranging_data_for_slot(uint8_t slot_no, nrf_ble_escs_radio_tx_pwr_t tx_power)
{
int8_t ranging_data_array[ESCS_NUM_OF_SUPPORTED_TX_POWER] = APP_CONFIG_CALIBRATED_RANGING_DATA;
nrf_ble_escs_radio_tx_pwr_t supported_tx[ESCS_NUM_OF_SUPPORTED_TX_POWER] =
ESCS_SUPPORTED_TX_POWER;
int8_t ranging_data = 0;
if (m_reg.slots[slot_no].adv_custom_tx_power)
{
ranging_data = m_reg.slots[slot_no].custom_tx_power;
}
else
{
for (uint32_t i = 0; i < ESCS_NUM_OF_SUPPORTED_TX_POWER; ++i)
{
if (supported_tx[i] >= tx_power)
{
ranging_data = ranging_data_array[i];
break;
}
}
}
es_adv_frame_t * frame = &m_reg.slots[slot_no].adv_frame;
switch (frame->type)
{
case ES_FRAME_TYPE_UID:
{
es_uid_frame_t * uid = &frame->frame.uid;
uid->ranging_data = ranging_data;
break;
}
case ES_FRAME_TYPE_URL:
{
es_url_frame_t * url = &frame->frame.url;
url->ranging_data = ranging_data;
break;
}
case ES_FRAME_TYPE_EID:
{
es_eid_frame_t * eid = &frame->frame.eid;
eid->ranging_data = ranging_data;
break;
}
case ES_FRAME_TYPE_TLM:
APP_ERROR_CHECK(NRF_ERROR_INVALID_PARAM);
break;
}
}
/**@brief Function configuring a non-EID slot.
*
* @param[in] slot_no Slot number to be used.
* @param[in] length Length of write operation.
* @param[in] p_frame_data Pointer to written data.
*/
static void configure_slot(uint8_t slot_no, uint8_t length, uint8_t * p_frame_data)
{
// If a TLM slot is being configured and there already exists a TLM.
if ((es_frame_type_t)p_frame_data[0] == ES_FRAME_TYPE_TLM && m_reg.tlm_configured)
{
return; // Silently ignore any attempts to create more than one TLM slot as there is no point.
}
es_slot_reg_update_slot_list_info_on_add(&m_reg, slot_no, (es_frame_type_t)p_frame_data[0], false);
// For convenience, frame_type is stored in two places, set both.
m_reg.slots[slot_no].adv_frame.type = (es_frame_type_t)p_frame_data[0];
memcpy(&m_reg.slots[slot_no].adv_frame.frame, &m_reg.slots[slot_no].adv_frame.type, 1);
uint8_t * p_data_after_ranging_data = ((uint8_t *)(&m_reg.slots[slot_no].adv_frame.frame) +
RANGING_DATA_INDEX + RANGING_DATA_LENGTH);
switch (m_reg.slots[slot_no].adv_frame.type)
{
case ES_FRAME_TYPE_UID:
// Fall through.
case ES_FRAME_TYPE_URL:
memcpy(p_data_after_ranging_data, &p_frame_data[1], length);
set_ranging_data_for_slot(slot_no, APP_CFG_DEFAULT_RADIO_TX_POWER);
m_reg.slots[slot_no].adv_frame.length = length + 1; // + 1 for ranging data
break;
case ES_FRAME_TYPE_TLM:
es_tlm_tlm_get(&m_reg.slots[slot_no].adv_frame.frame.tlm);
m_reg.slots[slot_no].adv_frame.length = ES_TLM_LENGTH;
break;
default:
break;
}
}
/**@brief Function configuring an EID slot.
*
* @param[in] slot_no Slot number to be used.
* @param[in] length Length of write operation.
* @param[in] p_frame_data Pointer to written data.
*/
static void configure_eid_slot(uint8_t slot_no, uint8_t length, uint8_t * p_frame_data)
{
bool clear_eid_slot = false;
// Do not update slot count, as this will be done when in the callback invoked when the EID data
// is ready.
// As it takes a while to do the calculation, temporarily remove the slot being overwritten.
// The slot will be re-added in the callback invoked when the EID data is ready.
clear_eid_slot = es_slot_reg_clear_slot(&m_reg, slot_no);
if (clear_eid_slot)
{
es_security_eid_slot_destroy(slot_no);
}
if (p_frame_data[0] != ES_FRAME_TYPE_EID)
{
APP_ERROR_CHECK(NRF_ERROR_INVALID_STATE);
}
if (length == ESCS_EID_WRITE_ECDH_LENGTH)
{
es_security_client_pub_ecdh_receive(slot_no,
&p_frame_data[ESCS_EID_WRITE_PUB_KEY_INDEX],
p_frame_data[ESCS_EID_WRITE_ECDH_LENGTH -1]);
}
else if (length == ESCS_EID_WRITE_IDK_LENGTH)
{
es_security_shared_ik_receive(slot_no,
&p_frame_data[ESCS_EID_WRITE_ENC_ID_KEY_INDEX],
p_frame_data[ESCS_EID_WRITE_IDK_LENGTH - 1]);
}
else
{
// Invalid length being written.
APP_ERROR_CHECK(NRF_ERROR_INVALID_PARAM);
}
}
ret_code_t es_slot_write_to_flash(uint8_t slot_no)
{
if (m_reg.slots[slot_no].configured)
{
// If its an EID, we need to store some metadata in order to re-initialize the EID.
if (m_reg.slots[slot_no].adv_frame.type == ES_FRAME_TYPE_EID)
{
m_reg.slots[slot_no].seconds = es_security_clock_get(slot_no);
m_reg.slots[slot_no].k_scaler = es_security_scaler_get(slot_no);
es_security_plain_eid_id_key_get(slot_no, m_reg.slots[slot_no].ik);
}
return es_flash_access_slot_configs(slot_no, &m_reg.slots[slot_no], ES_FLASH_ACCESS_WRITE);
}
else
{
return es_flash_access_slot_configs(slot_no, NULL, ES_FLASH_ACCESS_CLEAR);
}
}
void es_slot_radio_tx_pwr_set(uint8_t slot_no, nrf_ble_escs_radio_tx_pwr_t radio_tx_pwr)
{
slot_boundary_check(&slot_no);
m_reg.slots[slot_no].radio_tx_pwr = radio_tx_pwr;
if (!m_reg.slots[slot_no].adv_custom_tx_power) // Only update TX power in ADV if custom TX power is not set
{
set_ranging_data_for_slot(slot_no, radio_tx_pwr);
}
}
void es_slot_set_adv_custom_tx_power(uint8_t slot_no, nrf_ble_escs_adv_tx_pwr_t tx_pwr)
{
slot_boundary_check(&slot_no);
m_reg.slots[slot_no].adv_custom_tx_power = true;
m_reg.slots[slot_no].custom_tx_power = tx_pwr;
set_ranging_data_for_slot(slot_no, tx_pwr);
}
void es_slot_on_write(uint8_t slot_no, uint8_t length, uint8_t * p_frame_data)
{
slot_boundary_check(&slot_no);
if (p_frame_data == NULL)
{
APP_ERROR_CHECK(NRF_ERROR_NULL);
}
// Cleared
if (length == 0 || (length == 1 && p_frame_data[0] == 0))
{
(void)es_slot_reg_clear_slot(&m_reg, slot_no);
}
// EID slot being configured
else if (p_frame_data[0] == ES_FRAME_TYPE_EID &&
(length == ESCS_EID_WRITE_ECDH_LENGTH || length == ESCS_EID_WRITE_IDK_LENGTH))
{
if (m_reg.slots[slot_no].configured)
(void)es_slot_reg_clear_slot(&m_reg, slot_no);
configure_eid_slot(slot_no, length, p_frame_data);
}
// Non-EID slot configured.
else
{
if (m_reg.slots[slot_no].configured)
(void)es_slot_reg_clear_slot(&m_reg, slot_no);
configure_slot(slot_no, length, p_frame_data);
}
}
void es_slot_encrypted_eid_id_key_set(uint8_t slot_no, nrf_ble_escs_eid_id_key_t * p_eid_id_key)
{
slot_boundary_check(&slot_no);
if (p_eid_id_key != NULL)
{
memcpy(&(m_reg.slots[slot_no].encrypted_eid_id_key), p_eid_id_key,
sizeof(nrf_ble_escs_eid_id_key_t));
}
}
void es_slot_eid_ready(uint8_t slot_no)
{
m_reg.slots[slot_no].adv_frame.type = ES_FRAME_TYPE_EID;
m_reg.slots[slot_no].adv_frame.length = ES_EID_LENGTH;
es_security_eid_get(slot_no, (uint8_t *)m_reg.slots[slot_no].adv_frame.frame.eid.eid);
m_reg.slots[slot_no].adv_frame.frame.eid.frame_type = ES_FRAME_TYPE_EID;
set_ranging_data_for_slot(slot_no, m_reg.slots[slot_no].radio_tx_pwr);
if (m_eid_loaded_from_flash)
{
es_slot_reg_update_slot_list_info_on_add(&m_reg, slot_no, ES_FRAME_TYPE_EID, true);
m_eid_loaded_from_flash = false;
}
else
{
es_slot_reg_update_slot_list_info_on_add(&m_reg, slot_no, ES_FRAME_TYPE_EID, false);
}
}
static bool slot_is_eid(uint8_t eid_slot_no)
{
for (uint32_t i = 0; i < m_reg.num_configured_eid_slots; ++i)
{
if (m_reg.eid_slots_configured[i] == eid_slot_no)
{
return true;
}
}
return false;
}
void es_slot_tlm_update(void)
{
if (m_reg.tlm_configured)
{
es_tlm_tlm_get(&m_reg.slots[m_reg.tlm_slot].adv_frame.frame.tlm);
}
}
void es_slot_etlm_update(uint8_t eid_slot_no)
{
es_tlm_frame_t tlm;
es_etlm_frame_t etlm;
// Ignore the request if eTLM is not required or slot no does not correspond to an EID slot.
if (!es_slot_reg_etlm_required(&m_reg) || !slot_is_eid(eid_slot_no))
{
return;
}
es_tlm_tlm_get(&tlm);
es_security_tlm_to_etlm(eid_slot_no, &tlm, &etlm);
memcpy(&m_reg.slots[m_reg.tlm_slot].adv_frame.frame.etlm, &etlm, sizeof(es_etlm_frame_t));
m_reg.slots[m_reg.tlm_slot].adv_frame.length = sizeof(es_etlm_frame_t);
}
const es_slot_reg_t * es_slot_get_registry(void)
{
return (const es_slot_reg_t *)&m_reg;
}
void es_slots_init(const es_slot_t * p_default_slot)
{
ret_code_t err_code;
es_flash_flags_t flash_flags = {{0}};
es_slot_reg_init(&m_reg);
m_eid_loaded_from_flash = false;
// Read the flash flags to see if there are any previously stored slot configs
err_code = es_flash_access_flags(&flash_flags, ES_FLASH_ACCESS_READ);
if (err_code == FDS_ERR_NOT_FOUND)
{
// Factory reset or initial boot, load default data
memcpy(&m_reg.slots[0], p_default_slot, sizeof(*p_default_slot));
es_slot_reg_update_slot_list_info_on_add(&m_reg, 0, p_default_slot->adv_frame.type, true);
}
else
{
APP_ERROR_CHECK(err_code);
for (uint32_t i = 0; i < APP_MAX_ADV_SLOTS; ++i)
{
if (!flash_flags.slot_is_empty[i])
{
load_slot_from_flash(i);
}
}
}
}

View File

@@ -0,0 +1,203 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 ES_SLOT_H__
#define ES_SLOT_H__
#include <stdint.h>
#include "es_app_config.h"
#include "nrf_ble_escs.h"
/**
* @file
* @defgroup eddystone_slot Slots
* @brief Types and functions for handling Eddystone slots.
* @ingroup eddystone
* @{
*/
/**@brief Advertisable frame types that can be passed in to the advertising
* data during non-connectable slot advertising. */
typedef struct
{
union
{
es_uid_frame_t uid; //!< UID frame.
es_url_frame_t url; //!< URL frame.
es_tlm_frame_t tlm; //!< TLM frame.
es_eid_frame_t eid; //!< EID frame.
es_etlm_frame_t etlm; //!< eTLM frame.
} frame;
es_frame_type_t type; //!< Type defined twice for convenience (because the other one is inside a union).
uint8_t length;
}es_adv_frame_t;
/**@brief Slot. */
typedef struct
{
uint8_t slot_no; //!< Identifier for the slot, indexed at 0.
nrf_ble_escs_radio_tx_pwr_t radio_tx_pwr; //!< Radio TX power (in dB).
nrf_ble_escs_eid_id_key_t encrypted_eid_id_key; //!< EID key for the slot.
es_adv_frame_t adv_frame; //!< Frame structure to be passed in for advertising data.
bool adv_custom_tx_power; //!< Flag that specifies if the client has written to the 'Advertised TX Power' field of this slot.
nrf_ble_escs_radio_tx_pwr_t custom_tx_power; //!< Custom TX power to advertise (only if @ref adv_custom_tx_power is true).
bool configured; //!< Is this slot configured and active.
uint8_t k_scaler;
uint32_t seconds;
uint8_t ik[ESCS_AES_KEY_SIZE];
} es_slot_t;
/**@brief Slot registry. */
typedef struct
{
es_slot_t slots[APP_MAX_ADV_SLOTS];
uint8_t num_configured_slots;
uint8_t num_configured_eid_slots;
uint8_t slots_configured[APP_MAX_ADV_SLOTS];
uint8_t eid_slots_configured[APP_MAX_EID_SLOTS];
uint8_t tlm_slot;
bool tlm_configured;
uint8_t scaler_k;
uint8_t enc_key[ESCS_AES_KEY_SIZE];
} es_slot_reg_t;
/**@brief Function for initializing the Eddystone slots with default values.
*
* @details This function synchronizes all slots with the initial values.
*
* @param[in] p_default_slot Pointer to the default parameters for a slot.
*/
void es_slots_init(const es_slot_t * p_default_slot);
/**@brief Function for setting the advertising interval of the specified slot.
*
* For compatibility with the Eddystone specifications, @p p_adv_interval must point to
* a 16-bit big endian value (coming from the characteristic write request),
* which is then converted to a little endian value inside the function before
* it is written into the variable in the slot.
*
* @parameternoteslot
* @parameternoteadv
*
* @param[in] slot_no The index of the slot.
* @param[in,out] p_adv_interval Pointer to the advertisement interval (in ms) to set.
* @param[in] global Flag that should be set if the beacon does not support variable advertising intervals.
*/
void es_slot_adv_interval_set(uint8_t slot_no,
nrf_ble_escs_adv_interval_t * p_adv_interval,
bool global);
/**@brief Function for setting the TX power of the specified slot.
*
* @parameternoteslot
* @parameternotetxpower
*
* @param[in] slot_no The index of the slot.
* @param[in,out] radio_tx_pwr TX power value to set.
*/
void es_slot_radio_tx_pwr_set(uint8_t slot_no, nrf_ble_escs_radio_tx_pwr_t radio_tx_pwr);
/**@brief Function for setting the R/W ADV of the specified slot.
*
* @parameternoteslot
*
* @param[in] slot_no The index of the slot.
* @param[in,out] length The length of the data written or read.
* @param[in,out] p_frame_data Pointer to the data.
*
*/
void es_slot_on_write(uint8_t slot_no, uint8_t length, uint8_t * p_frame_data);
/**@brief Function for writing the slot's configuration to flash.
*
* @param[in] slot_no The index of the slot.
*/
ret_code_t es_slot_write_to_flash(uint8_t slot_no);
/**@brief Function for setting the slot's encrypted EID Identity Key to be displayed in the EID Identity Key characteristic.
*
* @parameternoteslot
*
* @param[in] slot_no The index of the slot.
* @param[in,out] p_eid_id_key Pointer to a @ref nrf_ble_escs_eid_id_key_t structure from where the key will be written.
*/
void es_slot_encrypted_eid_id_key_set(uint8_t slot_no, nrf_ble_escs_eid_id_key_t * p_eid_id_key);
/**@brief Function for marking an EID slot as ready for populating.
*
* @details Call this function when an EID has been generated and the advertisement frame can be populated with the EID.
*
* @param[in] slot_no The index of the slot.
*/
void es_slot_eid_ready(uint8_t slot_no);
/**@brief Function for updating the TLM slot with updated data. */
void es_slot_tlm_update(void);
/**@brief Function for updating the TLM slot with eTLM data.
*
* @details This function uses the EID identity key from the given EID slot number to update the TLM slot.
*
* @param[in] eid_slot_no EID slot to get EID identity key from.
*/
void es_slot_etlm_update(uint8_t eid_slot_no);
/**@brief Function for getting a pointer to the slot registry.
*
* @return A pointer to the slot registry.
*/
const es_slot_reg_t * es_slot_get_registry(void);
/**@brief Function for setting a custom advertisement TX power for a given slot.
*
* @parameternoteslot
* @parameternotetxpower
*
* @param[in] slot_no The index of the slot.
* @param[in] tx_pwr Advertised TX power to be set.
*/
void es_slot_set_adv_custom_tx_power(uint8_t slot_no, nrf_ble_escs_adv_tx_pwr_t tx_pwr);
/**
* @}
*/
#endif // ES_SLOT_H__

View File

@@ -0,0 +1,182 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 "es_slot_reg.h"
#define ES_SLOT_NOT_CONFIGURED 0xab /** Value set in configured lists to indicate not configured slot. */
/**@brief Function updating 'tlm_configured' property of slot registry when slot is being cleared.
*
* @param[in] p_reg Pointer to slot registry.
* @param[in] slot_no Slot number to be used.
*/
static void update_tlm_configured_on_clearing(es_slot_reg_t * p_reg, uint8_t slot_no)
{
if (p_reg->tlm_configured && slot_no == p_reg->tlm_slot)
{
p_reg->tlm_configured = false;
}
}
/**@brief Function updating 'num_configured_slots' and 'slots_configured' properties of slot registry when slot is being cleared.
*
* @param[in] p_configured Pointer to list of configured slots.
* @param[in] p_num_configured_slots Pointer to number of configured slots.
* @param[in] slot_no Slot number to clear.
*/
static void configured_slots_on_clear_update(uint8_t * p_configured, uint8_t * p_num_configured_slots, uint8_t slot_no)
{
uint8_t index_of_last_configured_slot = *p_num_configured_slots - 1;
for (uint32_t i = 0; i < APP_MAX_ADV_SLOTS; ++i)
{
if (p_configured[i] == slot_no)
{
// Copy all values 'to the right' of the cleared slot one step to the left.
if (i < index_of_last_configured_slot)
{
for (uint32_t j = i; j < index_of_last_configured_slot; ++j)
{
p_configured[j] = p_configured[j + 1];
}
// Write ES_SLOT_NOT_CONFIGURED to all rightmost not configured indexes.
memset(&p_configured[index_of_last_configured_slot],
ES_SLOT_NOT_CONFIGURED,
APP_MAX_ADV_SLOTS - index_of_last_configured_slot);
}
else
{
// There are no values 'to the right', simply overwrite with ES_SLOT_NOT_CONFIGURED
p_configured[i] = ES_SLOT_NOT_CONFIGURED;
}
*p_num_configured_slots -= 1;
return;
}
}
}
bool es_slot_reg_etlm_required(const es_slot_reg_t * p_reg)
{
return (p_reg->num_configured_eid_slots > 0 && p_reg->tlm_configured);
}
bool es_slot_reg_clear_slot(es_slot_reg_t * p_reg, uint8_t slot_no)
{
bool eid_has_been_cleared = false;
if (p_reg->slots[slot_no].configured)
{
update_tlm_configured_on_clearing(p_reg, slot_no);
configured_slots_on_clear_update(p_reg->slots_configured,
&p_reg->num_configured_slots,
slot_no);
if (p_reg->slots[slot_no].adv_frame.type == ES_FRAME_TYPE_EID)
{
configured_slots_on_clear_update(p_reg->eid_slots_configured,
&p_reg->num_configured_eid_slots,
slot_no);
eid_has_been_cleared = true;
}
p_reg->slots[slot_no].configured = false;
}
memset(&p_reg->slots[slot_no], 0, sizeof(p_reg->slots[slot_no]));
return eid_has_been_cleared;
}
void es_slot_reg_update_slot_list_info_on_add(es_slot_reg_t * p_reg,
uint8_t slot_no,
es_frame_type_t frame_type,
bool init)
{
if (frame_type == ES_FRAME_TYPE_TLM)
{
p_reg->tlm_configured = true;
p_reg->tlm_slot = slot_no;
}
if (!p_reg->slots[slot_no].configured || init)
{
p_reg->slots[slot_no].configured = true;
// Note, we use 'num_configured_slots' before incrementing it, so it is pointing to the correct index.
p_reg->slots_configured[p_reg->num_configured_slots] = slot_no;
p_reg->num_configured_slots++;
if (frame_type == ES_FRAME_TYPE_EID)
{
p_reg->eid_slots_configured[p_reg->num_configured_eid_slots] = slot_no;
p_reg->num_configured_eid_slots++;
}
}
// If an already configured slot has changed from anything TO an EID slot.
else if (frame_type == ES_FRAME_TYPE_EID &&
p_reg->slots[slot_no].adv_frame.type != ES_FRAME_TYPE_EID)
{
p_reg->eid_slots_configured[p_reg->num_configured_eid_slots] = slot_no;
p_reg->num_configured_eid_slots++;
}
}
void es_slot_reg_init(es_slot_reg_t * p_reg)
{
p_reg->tlm_configured = false;
memset(p_reg->slots_configured, ES_SLOT_NOT_CONFIGURED, APP_MAX_ADV_SLOTS);
memset(p_reg->eid_slots_configured, ES_SLOT_NOT_CONFIGURED, APP_MAX_EID_SLOTS);
p_reg->num_configured_eid_slots = 0;
p_reg->num_configured_slots = 0;
}

View File

@@ -0,0 +1,91 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 ES_SLOT_REG_H__
#define ES_SLOT_REG_H__
#include <stdint.h>
#include "es_slot.h"
/**
* @file
* @addtogroup eddystone_slot
* @{
*/
/** @brief Function for checking if an eTLM frame is required.
*
* @param[in] p_reg Pointer to the slot registry.
*
* @retval true If an eTLM frame is required.
* @retval false Otherwise.
*/
bool es_slot_reg_etlm_required(const es_slot_reg_t * p_reg);
/** @brief Function for clearing a slot.
*
* @param[in] p_reg Pointer to the slot registry.
* @param[in] slot_no The slot number to clear.
*
* @retval true If an EID slot was cleared.
*/
bool es_slot_reg_clear_slot(es_slot_reg_t * p_reg, uint8_t slot_no);
/** @brief Function for updating the state of the slot registry after adding a slot.
*
* @param[in] p_reg Pointer to the slot registry.
* @param[in] slot_no The slot number that was added.
* @param[in] frame_type The frame type that was added.
* @param[in] init Information if the data is loaded during initialization. Set this
* parameter to false if the call is a result of a write to the Eddystone Configuration Service.
*/
void es_slot_reg_update_slot_list_info_on_add(es_slot_reg_t * p_reg, uint8_t slot_no, es_frame_type_t frame_type, bool init);
/** @brief Function for initializing the slot registry.
*
* @param[in] p_reg Pointer to the slot registry to initialize.
*/
void es_slot_reg_init(es_slot_reg_t * p_reg);
/**
* @}
*/
#endif // ES_SLOT_REG_H__

View File

@@ -0,0 +1,106 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "es_stopwatch.h"
#include "sdk_macros.h"
#include "app_timer.h"
#include "es_app_config.h"
static uint32_t m_ticks_last_returned[ES_STOPWATCH_MAX_USERS];
static uint32_t m_ids_ticks_wrap[ES_STOPWATCH_MAX_USERS];
static uint8_t m_nof_ids = 0;
static bool m_initialized = false;
uint32_t es_stopwatch_check(es_stopwatch_id_t id)
{
uint32_t ticks_current = app_timer_cnt_get();
uint32_t ticks_diff;
if (m_ids_ticks_wrap[id] == 0)
{
APP_ERROR_CHECK(NRF_ERROR_INVALID_STATE);
}
(void) app_timer_cnt_diff_compute(ticks_current, m_ticks_last_returned[id], &ticks_diff);
if (ticks_diff >= m_ids_ticks_wrap[id])
{
m_ticks_last_returned[id] = (ticks_current / m_ids_ticks_wrap[id]) * m_ids_ticks_wrap[id];
return ticks_diff / m_ids_ticks_wrap[id];
}
return 0;
}
ret_code_t es_stopwatch_create(es_stopwatch_id_t * p_sw_id, uint32_t ticks_wrap)
{
VERIFY_PARAM_NOT_NULL(p_sw_id);
if (m_nof_ids == ES_STOPWATCH_MAX_USERS)
{
return NRF_ERROR_INVALID_STATE;
}
if (!m_initialized)
{
return NRF_ERROR_MODULE_NOT_INITIALZED;
}
*p_sw_id = m_nof_ids;
m_ids_ticks_wrap[m_nof_ids] = ticks_wrap;
m_nof_ids++;
return NRF_SUCCESS;
}
void es_stopwatch_init(void)
{
m_nof_ids = 0;
memset(m_ticks_last_returned, 0, sizeof(m_ticks_last_returned));
memset(m_ids_ticks_wrap, 0, sizeof(m_ids_ticks_wrap));
m_initialized = true;
}

View File

@@ -0,0 +1,71 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 ES_SECURITY_TIMING_H__
#define ES_SECURITY_TIMING_H__
#include <stdint.h>
#include "app_error.h"
/**
* @file
* @addtogroup eddystone_security
* @{
*/
typedef uint8_t es_stopwatch_id_t;
/**@brief Function for getting the number of seconds passed since the last invocation.
* @details If the function returns zero, the 'last time called' state is not updated. If a non-zero value
* is returned, the 'last time called' state will point to the last whole second.
* @return Number of seconds passed since the last invocation.
*/
uint32_t es_stopwatch_check(es_stopwatch_id_t id);
ret_code_t es_stopwatch_create(es_stopwatch_id_t * p_sw_id, uint32_t ticks_wrap);
/**@brief Function for initializing the security timing module.
*/
void es_stopwatch_init(void);
/**
* @}
*/
#endif // ES_SECURITY_TIMING_H__

View File

@@ -0,0 +1,141 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 <string.h>
#include "app_timer.h"
#include "es_tlm.h"
#include "es_app_config.h"
#include "es_battery_voltage.h"
#include "es_stopwatch.h"
#include "nrf_soc.h"
#define TICKS_100_MS APP_TIMER_TICKS(100, APP_TIMER_PRESCALER) //!< Tick count for 100ms.
static es_tlm_frame_t m_tlm;
static uint32_t m_le_adv_cnt;
static es_stopwatch_id_t m_time_sec_sw_id;
static es_stopwatch_id_t m_tlm_refresh_sw_id;
/**@brief Function for updating the ADV_SEC field of TLM*/
static void update_time(void)
{
static uint32_t time_total_100_ms = 0;
uint32_t be_time_100_ms; // Big endian version of 0.1 second counter.
time_total_100_ms += es_stopwatch_check(m_time_sec_sw_id);
be_time_100_ms = BYTES_REVERSE_32BIT(time_total_100_ms);
memcpy(m_tlm.sec_cnt, &be_time_100_ms, ES_TLM_SEC_CNT_LENGTH);
}
/**@brief Function for updating the TEMP field of TLM*/
static void update_temp(void)
{
int32_t temp; // variable to hold temp reading
(void)sd_temp_get(&temp); // get new temperature
int16_t temp_new = (int16_t) temp; // convert from int32_t to int16_t
m_tlm.temp[0] = (uint8_t)((temp_new >> 2) & 0xFFUL); // Right-shift by two to remove decimal part
m_tlm.temp[1] = (uint8_t)((temp_new << 6) & 0xFFUL); // Left-shift 6 to get fractional part with 0.25 degrees C resolution
}
/**@brief Function for updating the VBATT field of TLM*/
static void update_vbatt(void)
{
uint16_t vbatt; // Variable to hold voltage reading
es_battery_voltage_get(&vbatt); // Get new battery voltage
m_tlm.vbatt[0] = (uint8_t)(vbatt >> 8);
m_tlm.vbatt[1] = (uint8_t)vbatt;
}
static void update_adv_cnt(void)
{
uint32_t be_adv_cnt = BYTES_REVERSE_32BIT(m_le_adv_cnt);
memcpy(m_tlm.adv_cnt, (uint8_t *)(&be_adv_cnt), ES_TLM_ADV_CNT_LENGTH);
}
void es_tlm_tlm_get(es_tlm_frame_t * p_tlm_frame)
{
// Note that frame type and TLM version fields are set in initialization.
update_time();
update_adv_cnt();
if (es_stopwatch_check(m_tlm_refresh_sw_id) > 0)
{
update_temp();
update_vbatt();
}
memcpy(p_tlm_frame, &m_tlm, sizeof(es_tlm_frame_t));
}
void es_tlm_adv_cnt_inc(void)
{
m_le_adv_cnt++;
}
void es_tlm_init(void)
{
ret_code_t err_code;
memset(&m_tlm, 0, sizeof(m_tlm));
m_tlm.frame_type = ES_FRAME_TYPE_TLM;
m_tlm.version = ES_TLM_VERSION_TLM;
m_le_adv_cnt = 0;
update_time();
update_vbatt();
update_temp();
err_code = es_stopwatch_create(&m_time_sec_sw_id, APP_TIMER_TICKS(100, APP_TIMER_PRESCALER));
APP_ERROR_CHECK(err_code);
err_code = es_stopwatch_create(
&m_tlm_refresh_sw_id,
APP_TIMER_TICKS(APP_CONFIG_TLM_TEMP_VBATT_UPDATE_INTERVAL_SECONDS * 1000,
APP_TIMER_PRESCALER));
APP_ERROR_CHECK(err_code);
}

View File

@@ -0,0 +1,76 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 ES_TLM_H__
#define ES_TLM_H__
#include "es.h"
/**
* @file
* @defgroup eddystone_tlm TLM
* @brief Functions for the Eddystone telemetry (TLM) manager.
* @ingroup eddystone_adv
* @{
*/
/**@brief Function for initializing the TLM manager.
*
* @return See @ref app_timer_start for possible return values.
*/
void es_tlm_init(void);
/**@brief Function for getting the current TLM.
*
* @param[in] p_tlm_frame Pointer to the TLM frame to which the frame is retrieved.
*/
void es_tlm_tlm_get(es_tlm_frame_t * p_tlm_frame);
/**@brief Function for incrementing the ADV_CNT field of the TLM frame.
*
* @details This function should be called every time a frame is advertised.
*
*/
void es_tlm_adv_cnt_inc(void);
/**
* @}
*/
#endif // ES_TLM_H__

View File

@@ -0,0 +1,137 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
// See https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms
#ifndef ES_UTIL_H__
#define ES_UTIL_H__
#define BOOL(x) COMPL(NOT(x))
#define IF(c) IIF(BOOL(c))
#define CHECK_N(x, n, ...) n
#define CHECK(...) CHECK_N(__VA_ARGS__, 0,)
#define PROBE(x) x, 1,
#define EAT(...)
#define EXPAND(...) __VA_ARGS__
#define WHEN(c) IF(c)(EXPAND, EAT)
#define NOT(x) CHECK(PRIMITIVE_CAT(NOT_, x))
#define NOT_0 PROBE(~)
#define COMPL(b) PRIMITIVE_CAT(COMPL_, b)
#define COMPL_0 1
#define COMPL_1 0
#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
#define IIF(c) PRIMITIVE_CAT(IIF_, c)
#define IIF_0(t, ...) __VA_ARGS__
#define IIF_1(t, ...) t
#define DEC(x) PRIMITIVE_CAT(DEC_, x)
#define DEC_0 0
#define DEC_1 0
#define DEC_2 1
#define DEC_3 2
#define DEC_4 3
#define DEC_5 4
#define DEC_6 5
#define DEC_7 6
#define DEC_8 7
#define DEC_9 8
#define DEC_10 9
#define DEC_11 10
#define DEC_12 11
#define DEC_13 12
#define DEC_14 13
#define DEC_15 14
#define DEC_16 15
#define DEC_17 16
#define DEC_18 17
#define DEC_19 18
#define DEC_20 19
#define DEC_21 20
#define DEC_22 21
#define DEC_23 22
#define DEC_24 23
#define DEC_25 24
#define DEC_26 25
#define DEC_27 26
#define DEC_28 27
#define DEC_29 28
#define DEC_30 29
#define DEC_31 30
#define DEC_32 31
#define EMPTY()
#define DEFER(id) id EMPTY()
#define OBSTRUCT(...) __VA_ARGS__ DEFER(EMPTY)()
#define EXPAND(...) __VA_ARGS__
#define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
#define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
#define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
#define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
#define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__)))
#define EVAL5(...) __VA_ARGS__
#define REPEAT(count, macro, ...) \
WHEN(count) \
( \
OBSTRUCT(REPEAT_INDIRECT) () \
( \
DEC(count), macro, __VA_ARGS__ \
) \
OBSTRUCT(macro) \
( \
DEC(count), __VA_ARGS__ \
) \
)
#define REPEAT_INDIRECT() REPEAT
/**
* @}
*/
#endif // ES_UTIL_H__

View File

@@ -0,0 +1,429 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 <string.h>
#include "nrf_ble_es.h"
#include "app_error.h"
#include "fds.h"
#include "es_adv.h"
#include "es_battery_voltage.h"
#include "es_flash.h"
#include "es_gatts.h"
#include "es_security.h"
#include "es_slot.h"
#include "es_stopwatch.h"
#include "escs_defs.h"
static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID; //!< Connection handle.
static nrf_ble_escs_t m_ble_ecs; //!< Struct identifying the Eddystone Config Service.
static nrf_ble_es_evt_handler_t m_evt_handler; //!< Event handler.
/**@brief Function for invoking registered callback.
*
* @param[in] evt Event to issue to callback.
*/
static void handle_evt(nrf_ble_es_evt_t evt)
{
if (m_evt_handler != NULL)
{
m_evt_handler(evt);
}
}
/**@brief Function resetting MAC address. Will resume advertisement. */
static void new_address_set(void)
{
ret_code_t err_code;
uint8_t bytes_available;
ble_gap_addr_t new_address;
new_address.addr_type = BLE_GAP_ADDR_TYPE_PUBLIC;
// Randomize the MAC address on every EID generation
(void)sd_rand_application_bytes_available_get(&bytes_available);
while (bytes_available < BLE_GAP_ADDR_LEN)
{
// wait for SD to acquire enough RNs
(void)sd_rand_application_bytes_available_get(&bytes_available);
}
(void)sd_rand_application_vector_get(new_address.addr, BLE_GAP_ADDR_LEN);
// Stop advertising to ensure that it is possible to change the address.
(void)sd_ble_gap_adv_stop();
do
{
#if NRF_SD_BLE_API_VERSION >= 3
err_code = sd_ble_gap_addr_set(&new_address);
#else
err_code = sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &new_address);
#endif // NRF_SD_BLE_API_VERSION
}while(err_code == NRF_ERROR_INVALID_STATE);
APP_ERROR_CHECK(err_code);
if(es_adv_remain_connectable_get())
{
es_adv_start_connectable_adv();
}
else
{
es_adv_start_non_connctable_adv();
}
}
/**@brief Function updating MAC address if required.
*
* @param[in] demand_new_mac If 'true', mac address will be updated on next invocation when not connected.
* If 'false', simply check if we have an outstanding demand for new MAC and update if not connected.
*/
static void check_and_update_mac_address(bool demand_new_mac)
{
static bool reset_mac_address = false;
if (demand_new_mac)
{
reset_mac_address = true;
}
// Not possible to update MAC address while in a connection
if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
{
return;
}
else if (reset_mac_address)
{
reset_mac_address = false;
new_address_set();
}
}
/**@brief Function to lock the beacon (change lock state characteristic to LOCKED)
*/
static void lock_beacon(void)
{
*(m_ble_ecs.p_lock_state) = NRF_BLE_ESCS_LOCK_STATE_LOCKED;
}
/**@brief Function for handling BLE event from the SoftDevice.
*
* @param[in] p_ble_evt Pointer to BLE event.
*/
static void on_ble_evt(ble_evt_t * p_ble_evt)
{
ret_code_t err_code;
es_flash_flags_t flash_flag = {{0}};
const es_slot_reg_t * p_reg = es_slot_get_registry();
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
m_conn_handle = p_ble_evt->evt.common_evt.conn_handle;
*(m_ble_ecs.p_active_slot) = 0;
break;
case BLE_GAP_EVT_DISCONNECTED:
m_conn_handle = BLE_CONN_HANDLE_INVALID;
for (uint32_t i = 0; i < APP_MAX_ADV_SLOTS; ++i)
{
err_code = es_slot_write_to_flash(i);
APP_ERROR_CHECK(err_code);
flash_flag.slot_is_empty[i] = !p_reg->slots[i].configured;
}
err_code = es_flash_access_flags(&flash_flag, ES_FLASH_ACCESS_WRITE);
APP_ERROR_CHECK(err_code);
es_flash_beacon_config_t beacon_config;
beacon_config.adv_interval = es_adv_interval_get();
beacon_config.remain_connectable = es_adv_remain_connectable_get();
err_code = es_flash_access_beacon_config(&beacon_config, ES_FLASH_ACCESS_WRITE);
APP_ERROR_CHECK(err_code);
if (*m_ble_ecs.p_lock_state == NRF_BLE_ESCS_LOCK_STATE_UNLOCKED)
{
lock_beacon();
}
check_and_update_mac_address(false);
break;
default:
// No implementation needed.
break;
}
}
/**@brief Callback function to receive messages from the security module
*
* @details Need to be passed in during es_security_init(). The security
* module will callback anytime a particular security process is completed
*
* @params[in] slot_no Index of the slot
* @params[in] msg_type Message type corersponding to different security components
*/
static void nrf_ble_escs_security_cb(uint8_t slot_no, es_security_msg_t msg_type)
{
nrf_ble_escs_eid_id_key_t encrypted_id_key;
nrf_ble_escs_public_ecdh_key_t pub_ecdh_key;
ret_code_t err_code;
static ble_gatts_value_t value;
switch (msg_type)
{
case ES_SECURITY_MSG_UNLOCKED:
*(m_ble_ecs.p_lock_state) = NRF_BLE_ESCS_LOCK_STATE_UNLOCKED;
break;
case ES_SECURITY_MSG_EID:
es_slot_eid_ready(slot_no);
#ifdef MAC_RANDOMIZED
check_and_update_mac_address(true);
#endif // MAC_RANDOMIZED
break;
case ES_SECURITY_MSG_IK:
es_security_encrypted_eid_id_key_get(slot_no, (uint8_t *)encrypted_id_key.key);
// Set the EID ID key in the slot so it can be exposed in the characteristic
es_slot_encrypted_eid_id_key_set(slot_no, &encrypted_id_key);
break;
case ES_SECURITY_MSG_ECDH:
es_security_pub_ecdh_get(slot_no, (uint8_t *)pub_ecdh_key.key);
// Set the characteristic to the ECDH key value
value.len = sizeof(nrf_ble_escs_public_ecdh_key_t);
value.offset = 0;
value.p_value = (uint8_t *)pub_ecdh_key.key;
if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
{
err_code = sd_ble_gatts_value_set(m_ble_ecs.conn_handle,
m_ble_ecs.pub_ecdh_key_handles.value_handle,
&value);
if (err_code != NRF_SUCCESS)
{
APP_ERROR_CHECK(err_code);
}
}
break;
case ES_SECURITY_MSG_STORE_TIME:
// Every 24 hours any EID slots time is stored to flash to allow for power lock_state_handles
// recovery. Only time needs to be stored, but just store the entire slot anyway for API simplicity.
err_code = es_slot_write_to_flash(slot_no);
APP_ERROR_CHECK(err_code);
break;
default:
APP_ERROR_CHECK(NRF_ERROR_INVALID_PARAM); // Should never happen
break;
}
}
/**@brief Function for handling advertisement events from 'es_adv'.
*
* @param[in] evt Advertisement event to handle.
*/
static void adv_evt_handler(es_adv_evt_t evt)
{
switch (evt)
{
case ES_ADV_EVT_NON_CONN_ADV:
handle_evt(NRF_BLE_ES_EVT_ADVERTISEMENT_SENT);
es_security_update_time();
break;
case ES_ADV_EVT_CONNECTABLE_ADV_STARTED:
handle_evt(NRF_BLE_ES_EVT_CONNECTABLE_ADV_STARTED);
break;
}
}
/**@brief Initialize the ECS with initial values for the characteristics and other necessary modules */
static void ble_escs_init(void)
{
ret_code_t err_code;
nrf_ble_escs_init_t ecs_init;
nrf_ble_escs_init_params_t init_params;
int8_t tx_powers[ESCS_NUM_OF_SUPPORTED_TX_POWER] = ESCS_SUPPORTED_TX_POWER;
/*Init the broadcast capabilities characteristic*/
memset(&init_params.broadcast_cap, 0, sizeof(init_params.broadcast_cap));
init_params.broadcast_cap.vers_byte = ES_SPEC_VERSION_BYTE;
init_params.broadcast_cap.max_supp_total_slots = APP_MAX_ADV_SLOTS;
init_params.broadcast_cap.max_supp_eid_slots = APP_MAX_EID_SLOTS;
init_params.broadcast_cap.cap_bitfield = ( (APP_IS_VARIABLE_ADV_SUPPORTED << ESCS_BROADCAST_VAR_ADV_SUPPORTED_Pos)
| (APP_IS_VARIABLE_TX_POWER_SUPPORTED << ESCS_BROADCAST_VAR_TX_POWER_SUPPORTED_Pos))
& (ESCS_BROADCAST_VAR_RFU_MASK);
init_params.broadcast_cap.supp_frame_types = ( (APP_IS_URL_SUPPORTED << ESCS_FRAME_TYPE_URL_SUPPORTED_Pos)
| (APP_IS_UID_SUPPORTED << ESCS_FRAME_TYPE_UID_SUPPORTED_Pos)
| (APP_IS_TLM_SUPPORTED << ESCS_FRAME_TYPE_TLM_SUPPORTED_Pos)
| (APP_IS_EID_SUPPORTED << ESCS_FRAME_TYPE_EID_SUPPORTED_Pos))
& (ESCS_FRAME_TYPE_RFU_MASK);
memcpy(init_params.broadcast_cap.supp_radio_tx_power, tx_powers, ESCS_NUM_OF_SUPPORTED_TX_POWER);
init_params.adv_interval = APP_CFG_NON_CONN_ADV_INTERVAL_MS;
init_params.adv_tx_pwr = APP_CFG_DEFAULT_RADIO_TX_POWER;
init_params.radio_tx_pwr = 0x00;
init_params.factory_reset = 0;
init_params.remain_connectable.r_is_non_connectable_supported = APP_IS_REMAIN_CONNECTABLE_SUPPORTED;
// Initialize evt handlers and the service
memset(&ecs_init, 0, sizeof(ecs_init));
ecs_init.write_evt_handler = es_gatts_handle_write;
ecs_init.read_evt_handler = es_gatts_handle_read;
ecs_init.p_init_vals = &(init_params);
err_code = nrf_ble_escs_init(&m_ble_ecs, &ecs_init);
APP_ERROR_CHECK(err_code);
}
/**@brief Function for initializing 'es_adv' module. */
static void adv_init(void)
{
ret_code_t err_code;
es_flash_beacon_config_t beacon_config;
err_code = es_flash_access_beacon_config(&beacon_config, ES_FLASH_ACCESS_READ);
if (err_code == FDS_ERR_NOT_FOUND)
{
beacon_config.adv_interval = APP_CFG_NON_CONN_ADV_INTERVAL_MS;
beacon_config.remain_connectable = false;
}
else
{
APP_ERROR_CHECK(err_code);
}
es_adv_init(m_ble_ecs.uuid_type,
adv_evt_handler,
beacon_config.adv_interval,
beacon_config.remain_connectable);
}
/**@brief Function for initializing es_slots module. */
static void adv_slots_init(void)
{
uint8_t default_frame_data[DEFAULT_FRAME_LENGTH] = DEFAULT_FRAME_DATA;
es_slot_t default_adv_slot = {.slot_no = 0,
.radio_tx_pwr = 0,
.adv_frame.type = DEFAULT_FRAME_TYPE,
.adv_frame.length = DEFAULT_FRAME_LENGTH,
.adv_custom_tx_power = false,
.configured = true};
memcpy(&default_adv_slot.adv_frame.frame, default_frame_data, DEFAULT_FRAME_LENGTH);
es_slots_init(&default_adv_slot);
}
void nrf_ble_es_on_ble_evt(ble_evt_t * p_ble_evt)
{
ret_code_t err_code;
es_adv_on_ble_evt(p_ble_evt);
err_code = nrf_ble_escs_on_ble_evt(&m_ble_ecs, p_ble_evt);
APP_ERROR_CHECK(err_code);
on_ble_evt(p_ble_evt);
es_flash_on_ble_evt(p_ble_evt);
}
void nrf_ble_es_on_start_connectable_advertising(void)
{
es_adv_start_connectable_adv();
}
void nrf_ble_es_init(nrf_ble_es_evt_handler_t evt_handler)
{
ret_code_t err_code;
m_evt_handler = evt_handler;
m_conn_handle = BLE_CONN_HANDLE_INVALID;
es_stopwatch_init();
err_code = es_gatts_init(&m_ble_ecs);
APP_ERROR_CHECK(err_code);
err_code = es_flash_init();
APP_ERROR_CHECK(err_code);
while (es_flash_num_pending_ops() > 0)
{
; // Busy wait while initialization of FDS module completes
}
err_code = es_security_init(nrf_ble_escs_security_cb);
APP_ERROR_CHECK(err_code);
es_adv_timers_init();
ble_escs_init();
adv_slots_init();
es_battery_voltage_init();
adv_init();
es_adv_start_non_connctable_adv();
}

View File

@@ -0,0 +1,98 @@
/**
* Copyright (c) 2016 - 2017, 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 NRF_ES_H__
#define NRF_ES_H__
#include <stdint.h>
#include "ble.h"
/**
* @file
* @defgroup eddystone Eddystone library
* @ingroup app_common
* @{
*
* @brief Library for Eddystone beacons. This library is used in the @ref ble_sdk_app_es.
*
* @note The API documentation is provided for reference only. You should
* not modify this library, and you should not use any functions
* except for the main level functions defined in @c nrf_ble_es.h
* in different contexts.
*/
/** @brief Eddystone event types. */
typedef enum {
NRF_BLE_ES_EVT_ADVERTISEMENT_SENT, //!< A non-connectable Eddystone frame advertisement was sent.
NRF_BLE_ES_EVT_CONNECTABLE_ADV_STARTED, //!< Advertising in connectable mode was started.
}nrf_ble_es_evt_t;
/**@brief Eddystone event handler type. */
typedef void (*nrf_ble_es_evt_handler_t)(nrf_ble_es_evt_t evt);
/**@brief Function for handling the application's BLE stack events.
*
* @details This function handles all events from the BLE stack that are of
* interest to the Eddystone library. It must be called from the @ref
* softdevice_handler callback for all BLE events that are received from the
* SoftDevice.
*
* @param[in] p_ble_evt Event received from the BLE stack.
*/
void nrf_ble_es_on_ble_evt(ble_evt_t * p_ble_evt);
/**@brief Function for putting the beacon in connectable mode.
*
* @details This function makes the beacon advertise connectable advertisements.
* If the beacon is in a connected state, the request is ignored.
*/
void nrf_ble_es_on_start_connectable_advertising(void);
/** @brief Function for initializing the Eddystone library.
*
* @param[in] evt_handler Event handler to be called for handling BLE events.
*/
void nrf_ble_es_init(nrf_ble_es_evt_handler_t evt_handler);
/**
* @}
*/
#endif