Merge branch 'develop' of https://github.com/ARMmbed/ble-nrf51822 into characteristicDescriptorDiscovery
commit
7e784e0e0c
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Nordic Semiconductor ASA
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this
|
||||
* list of conditions and the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
11
LICENSE
11
LICENSE
|
@ -1,9 +1,6 @@
|
|||
Many of the files in this module have been inherited from the Nordic SDK for
|
||||
nRF51822. With the exception of the softdevice, they come with a BSD license
|
||||
offered by Nordic for use in mbed. The Nordic Softdevice License Agreement, a
|
||||
BSD-like licence for binary distributions, applies to the softdevice. Some
|
||||
This module contains softdevice which comes with The Nordic Softdevice License Agreement,
|
||||
a BSD-like licence for binary distributions, offered by Nordic for use in mbed. Some
|
||||
other files come from the mbed SDK, and are licensed under Apache-2.0. Unless
|
||||
specifically indicated otherwise in a file, files are licensed under the
|
||||
Apache 2.0 license, as can be found in: apache-2.0.txt. The BSD-like Nordic
|
||||
license can be found in BSD-3clause-Nordic.txt. The Nordic Semiconductor Softdevice
|
||||
License Agreement can be found in softdevice_nrf51822_licence_agreement.txt.
|
||||
Apache 2.0 license, as can be found in: apache-2.0.txt. The Nordic Semiconductor Softdevice
|
||||
License Agreement can be found in softdevice_nrf51822_licence_agreement.txt.
|
||||
|
|
24
module.json
24
module.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "ble-nrf51822",
|
||||
"version": "2.0.6",
|
||||
"version": "2.2.5",
|
||||
"description": "Nordic stack and drivers for the mbed BLE API.",
|
||||
"keywords": [
|
||||
"Bluetooth",
|
||||
|
@ -24,29 +24,13 @@
|
|||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"ble": "^2.0.0"
|
||||
"ble": "^2.1.11",
|
||||
"nrf51-sdk": "^1.0.0"
|
||||
},
|
||||
"extraIncludes": [
|
||||
"source/btle",
|
||||
"source/btle/custom",
|
||||
"source/common",
|
||||
"source/nordic-sdk/components",
|
||||
"source/nordic-sdk/components/libraries/util",
|
||||
"source/nordic-sdk/components/libraries/hci",
|
||||
"source/nordic-sdk/components/libraries/bootloader_dfu",
|
||||
"source/nordic-sdk/components/libraries/bootloader_dfu/hci_transport",
|
||||
"source/nordic-sdk/components/libraries/bootloader_dfu/experimental",
|
||||
"source/nordic-sdk/components/softdevice/s130/include",
|
||||
"source/nordic-sdk/components/softdevice/common/softdevice_handler",
|
||||
"source/nordic-sdk/components/drivers_nrf/hal",
|
||||
"source/nordic-sdk/components/drivers_nrf/ble_flash",
|
||||
"source/nordic-sdk/components/drivers_nrf/pstorage",
|
||||
"source/nordic-sdk/components/drivers_nrf/pstorage/config",
|
||||
"source/nordic-sdk/components/ble/ble_radio_notification",
|
||||
"source/nordic-sdk/components/ble/ble_services/ble_dfu",
|
||||
"source/nordic-sdk/components/ble/common",
|
||||
"source/nordic-sdk/components/ble/device_manager",
|
||||
"source/nordic-sdk/components/ble/device_manager/config"
|
||||
"source/common"
|
||||
],
|
||||
"targetDependencies": {}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
#include "btle.h"
|
||||
|
||||
#include "ble_stack_handler_types.h"
|
||||
#include "ble_flash.h"
|
||||
#include "ble_conn_params.h"
|
||||
|
||||
|
@ -27,15 +26,17 @@
|
|||
#include "btle_advertising.h"
|
||||
#include "custom/custom_helper.h"
|
||||
|
||||
#include "softdevice_handler.h"
|
||||
#include "pstorage.h"
|
||||
|
||||
#include "ble/GapEvents.h"
|
||||
#include "nRF5xGap.h"
|
||||
#include "nRF5xGattServer.h"
|
||||
#include "nRF5xSecurityManager.h"
|
||||
|
||||
extern "C" {
|
||||
#include "pstorage.h"
|
||||
#include "device_manager.h"
|
||||
#include "softdevice_handler.h"
|
||||
#include "ble_stack_handler_types.h"
|
||||
}
|
||||
|
||||
#include "ble_hci.h"
|
||||
#include "btle_discovery.h"
|
||||
|
|
|
@ -15,17 +15,35 @@
|
|||
*/
|
||||
|
||||
#include "btle.h"
|
||||
#include "pstorage.h"
|
||||
|
||||
#include "nRF5xGap.h"
|
||||
#include "nRF5xSecurityManager.h"
|
||||
|
||||
extern "C" {
|
||||
#include "pstorage.h"
|
||||
#include "device_manager.h"
|
||||
}
|
||||
|
||||
#include "btle_security.h"
|
||||
|
||||
static dm_application_instance_t applicationInstance;
|
||||
static ret_code_t dm_handler(dm_handle_t const *p_handle, dm_event_t const *p_event, ret_code_t event_result);
|
||||
|
||||
// default security parameters
|
||||
static ble_gap_sec_params_t securityParameters = {
|
||||
.bond = true, /**< Perform bonding. */
|
||||
.mitm = true, /**< Man In The Middle protection required. */
|
||||
.io_caps = SecurityManager::IO_CAPS_NONE, /**< IO capabilities, see @ref BLE_GAP_IO_CAPS. */
|
||||
.oob = 0, /**< Out Of Band data available. */
|
||||
.min_key_size = 16, /**< Minimum encryption key size in octets between 7 and 16. If 0 then not applicable in this instance. */
|
||||
.max_key_size = 16, /**< Maximum encryption key size in octets between min_key_size and 16. */
|
||||
.kdist_periph = {
|
||||
.enc = 1, /**< Long Term Key and Master Identification. */
|
||||
.id = 1, /**< Identity Resolving Key and Identity Address Information. */
|
||||
.sign = 1, /**< Connection Signature Resolving Key. */
|
||||
}, /**< Key distribution bitmap: keys that the peripheral device will distribute. */
|
||||
};
|
||||
|
||||
ble_error_t
|
||||
btle_initializeSecurity(bool enableBonding,
|
||||
bool requireMITM,
|
||||
|
@ -68,22 +86,15 @@ btle_initializeSecurity(bool enableBonding,
|
|||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
|
||||
// update default security parameters with function call parameters
|
||||
securityParameters.bond = enableBonding;
|
||||
securityParameters.mitm = requireMITM;
|
||||
securityParameters.io_caps = iocaps;
|
||||
|
||||
const dm_application_param_t dm_param = {
|
||||
.evt_handler = dm_handler,
|
||||
.service_type = DM_PROTOCOL_CNTXT_GATT_CLI_ID,
|
||||
.sec_param = {
|
||||
.bond = enableBonding,/**< Perform bonding. */
|
||||
.mitm = requireMITM, /**< Man In The Middle protection required. */
|
||||
.io_caps = iocaps, /**< IO capabilities, see @ref BLE_GAP_IO_CAPS. */
|
||||
.oob = 0, /**< Out Of Band data available. */
|
||||
.min_key_size = 16, /**< Minimum encryption key size in octets between 7 and 16. If 0 then not applicable in this instance. */
|
||||
.max_key_size = 16, /**< Maximum encryption key size in octets between min_key_size and 16. */
|
||||
.kdist_periph = {
|
||||
.enc = 1, /**< Long Term Key and Master Identification. */
|
||||
.id = 1, /**< Identity Resolving Key and Identity Address Information. */
|
||||
.sign = 1, /**< Connection Signature Resolving Key. */
|
||||
}, /**< Key distribution bitmap: keys that the peripheral device will distribute. */
|
||||
}
|
||||
.sec_param = securityParameters
|
||||
};
|
||||
|
||||
if ((rc = dm_register(&applicationInstance, &dm_param)) != NRF_SUCCESS) {
|
||||
|
@ -148,6 +159,48 @@ btle_getLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::LinkSecuri
|
|||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t
|
||||
btle_setLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::SecurityMode_t securityMode)
|
||||
{
|
||||
// use default and updated parameters as starting point
|
||||
// and modify structure based on security mode.
|
||||
ble_gap_sec_params_t params = securityParameters;
|
||||
|
||||
switch (securityMode) {
|
||||
case SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK:
|
||||
/**< Require no protection, open link. */
|
||||
securityParameters.bond = false;
|
||||
securityParameters.mitm = false;
|
||||
break;
|
||||
|
||||
case SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM:
|
||||
/**< Require encryption, but no MITM protection. */
|
||||
securityParameters.bond = true;
|
||||
securityParameters.mitm = false;
|
||||
break;
|
||||
|
||||
// not yet implemented security modes
|
||||
case SecurityManager::SECURITY_MODE_NO_ACCESS:
|
||||
case SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM:
|
||||
/**< Require encryption and MITM protection. */
|
||||
case SecurityManager::SECURITY_MODE_SIGNED_NO_MITM:
|
||||
/**< Require signing or encryption, but no MITM protection. */
|
||||
case SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM:
|
||||
/**< Require signing or encryption, and MITM protection. */
|
||||
default:
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// update security settings for given connection
|
||||
uint32_t result = sd_ble_gap_authenticate(connectionHandle, ¶ms);
|
||||
|
||||
if (result == NRF_SUCCESS) {
|
||||
return BLE_ERROR_NONE;
|
||||
} else {
|
||||
return BLE_ERROR_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
ret_code_t
|
||||
dm_handler(dm_handle_t const *p_handle, dm_event_t const *p_event, ret_code_t event_result)
|
||||
{
|
||||
|
|
|
@ -48,10 +48,23 @@ ble_error_t btle_initializeSecurity(bool en
|
|||
* @param[out] securityStatusP
|
||||
* security status.
|
||||
*
|
||||
* @return BLE_SUCCESS Or appropriate error code indicating reason for failure.
|
||||
* @return BLE_ERROR_NONE Or appropriate error code indicating reason for failure.
|
||||
*/
|
||||
ble_error_t btle_getLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::LinkSecurityStatus_t *securityStatusP);
|
||||
|
||||
/**
|
||||
* Set the security mode on a connection. Useful for elevating the security mode
|
||||
* once certain conditions are met, e.g., a particular service is found.
|
||||
*
|
||||
* @param[in] connectionHandle
|
||||
* Handle to identify the connection.
|
||||
* @param[in] securityMode
|
||||
* security mode.
|
||||
*
|
||||
* @return BLE_ERROR_NONE Or appropriate error code indicating reason for failure.
|
||||
*/
|
||||
ble_error_t btle_setLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::SecurityMode_t securityMode);
|
||||
|
||||
/**
|
||||
* Function for deleting all peer device context and all related bonding
|
||||
* information from the database.
|
||||
|
|
|
@ -148,9 +148,8 @@ uint8_t custom_add_uuid_base(uint8_t const *const p_uuid_base)
|
|||
ble_uuid128_t base_uuid;
|
||||
uint8_t uuid_type = 0;
|
||||
|
||||
/* Reverse the bytes since ble_uuid128_t is LSB */
|
||||
for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
|
||||
base_uuid.uuid128[i] = p_uuid_base[UUID::LENGTH_OF_LONG_UUID - 1 - i];
|
||||
base_uuid.uuid128[i] = p_uuid_base[i];
|
||||
}
|
||||
|
||||
ASSERT_INT( ERROR_NONE, sd_ble_uuid_vs_add( &base_uuid, &uuid_type ), 0);
|
||||
|
@ -168,9 +167,8 @@ error_t custom_decode_uuid_base(uint8_t const *const p_uuid_base,
|
|||
{
|
||||
UUID::LongUUIDBytes_t uuid_base_le;
|
||||
|
||||
/* Reverse the bytes since ble_uuid128_t is LSB */
|
||||
for (uint8_t i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
|
||||
uuid_base_le[i] = p_uuid_base[UUID::LENGTH_OF_LONG_UUID - 1 - i];
|
||||
uuid_base_le[i] = p_uuid_base[i];
|
||||
}
|
||||
|
||||
ASSERT_STATUS( sd_ble_uuid_decode(UUID::LENGTH_OF_LONG_UUID, uuid_base_le, p_uuid));
|
||||
|
@ -191,6 +189,8 @@ error_t custom_decode_uuid_base(uint8_t const *const p_uuid_base,
|
|||
@param[in] char_props The characteristic properties, as
|
||||
defined by ble_gatt_char_props_t
|
||||
@param[in] max_length The maximum length of this characeristic
|
||||
@param[in] has_variable_len Whether the characteristic data has
|
||||
variable length.
|
||||
@param[out] p_char_handle
|
||||
|
||||
@returns
|
||||
|
@ -202,8 +202,9 @@ error_t custom_add_in_characteristic(uint16_t service_handle,
|
|||
uint8_t properties,
|
||||
SecurityManager::SecurityMode_t requiredSecurity,
|
||||
uint8_t *p_data,
|
||||
uint16_t min_length,
|
||||
uint16_t length,
|
||||
uint16_t max_length,
|
||||
bool has_variable_len,
|
||||
const uint8_t *userDescriptionDescriptorValuePtr,
|
||||
uint16_t userDescriptionDescriptorValueLen,
|
||||
bool readAuthorization,
|
||||
|
@ -242,7 +243,8 @@ error_t custom_add_in_characteristic(uint16_t service_handle,
|
|||
attr_md.wr_auth = writeAuthorization;
|
||||
|
||||
attr_md.vloc = BLE_GATTS_VLOC_STACK;
|
||||
attr_md.vlen = (min_length == max_length) ? 0 : 1;
|
||||
/* Always set variable size */
|
||||
attr_md.vlen = has_variable_len;
|
||||
|
||||
if (char_props.read || char_props.notify || char_props.indicate) {
|
||||
switch (requiredSecurity) {
|
||||
|
@ -292,7 +294,7 @@ error_t custom_add_in_characteristic(uint16_t service_handle,
|
|||
|
||||
attr_char_value.p_uuid = p_uuid;
|
||||
attr_char_value.p_attr_md = &attr_md;
|
||||
attr_char_value.init_len = min_length;
|
||||
attr_char_value.init_len = length;
|
||||
attr_char_value.max_len = max_length;
|
||||
attr_char_value.p_value = p_data;
|
||||
|
||||
|
@ -317,23 +319,27 @@ error_t custom_add_in_characteristic(uint16_t service_handle,
|
|||
since 1 is typically used by the primary
|
||||
service).
|
||||
@param[in] max_length The maximum length of this descriptor
|
||||
@param[in] has_variable_len Whether the characteristic data has
|
||||
variable length.
|
||||
|
||||
@returns
|
||||
@retval ERROR_NONE Everything executed normally
|
||||
*/
|
||||
/**************************************************************************/
|
||||
error_t custom_add_in_descriptor(uint16_t char_handle,
|
||||
ble_uuid_t *p_uuid,
|
||||
uint8_t *p_data,
|
||||
uint16_t min_length,
|
||||
uint16_t max_length,
|
||||
uint16_t *p_desc_handle)
|
||||
ble_uuid_t *p_uuid,
|
||||
uint8_t *p_data,
|
||||
uint16_t length,
|
||||
uint16_t max_length,
|
||||
bool has_variable_len,
|
||||
uint16_t *p_desc_handle)
|
||||
{
|
||||
/* Descriptor metadata */
|
||||
ble_gatts_attr_md_t desc_md = {0};
|
||||
|
||||
desc_md.vloc = BLE_GATTS_VLOC_STACK;
|
||||
desc_md.vlen = (min_length == max_length) ? 0 : 1;
|
||||
/* Always set variable size */
|
||||
desc_md.vlen = has_variable_len;
|
||||
|
||||
/* Make it readable and writable */
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_md.read_perm);
|
||||
|
@ -343,7 +349,7 @@ error_t custom_add_in_descriptor(uint16_t char_handle,
|
|||
|
||||
attr_desc.p_uuid = p_uuid;
|
||||
attr_desc.p_attr_md = &desc_md;
|
||||
attr_desc.init_len = min_length;
|
||||
attr_desc.init_len = length;
|
||||
attr_desc.max_len = max_length;
|
||||
attr_desc.p_value = p_data;
|
||||
|
||||
|
|
|
@ -36,8 +36,9 @@ error_t custom_add_in_characteristic(uint16_t service_handle,
|
|||
uint8_t properties,
|
||||
SecurityManager::SecurityMode_t requiredSecurity,
|
||||
uint8_t *p_data,
|
||||
uint16_t min_length,
|
||||
uint16_t length,
|
||||
uint16_t max_length,
|
||||
bool has_variable_len,
|
||||
const uint8_t *userDescriptionDescriptorValuePtr,
|
||||
uint16_t userDescriptionDescriptorValueLen,
|
||||
bool readAuthorization,
|
||||
|
@ -47,8 +48,9 @@ error_t custom_add_in_characteristic(uint16_t service_handle,
|
|||
error_t custom_add_in_descriptor(uint16_t char_handle,
|
||||
ble_uuid_t *p_uuid,
|
||||
uint8_t *p_data,
|
||||
uint16_t min_length,
|
||||
uint16_t length,
|
||||
uint16_t max_length,
|
||||
bool has_variable_len,
|
||||
uint16_t *p_desc_handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -374,15 +374,30 @@ uint16_t nRF5xGap::getConnectionHandle(void)
|
|||
/**************************************************************************/
|
||||
ble_error_t nRF5xGap::setAddress(AddressType_t type, const Address_t address)
|
||||
{
|
||||
if (type > ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE) {
|
||||
uint8_t cycle_mode;
|
||||
ble_gap_addr_t dev_addr;
|
||||
|
||||
/* When using Public or Static addresses, the cycle mode must be None.
|
||||
When using Random Private addresses, the cycle mode must be Auto.
|
||||
In auto mode, the given address is ignored.
|
||||
*/
|
||||
if ((type == ADDR_TYPE_PUBLIC) || (type == ADDR_TYPE_RANDOM_STATIC))
|
||||
{
|
||||
cycle_mode = BLE_GAP_ADDR_CYCLE_MODE_NONE;
|
||||
memcpy(dev_addr.addr, address, ADDR_LEN);
|
||||
}
|
||||
else if ((type == ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE) || (type == ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE))
|
||||
{
|
||||
cycle_mode = BLE_GAP_ADDR_CYCLE_MODE_AUTO;
|
||||
// address is ignored when in auto mode
|
||||
}
|
||||
else
|
||||
{
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
ble_gap_addr_t dev_addr;
|
||||
dev_addr.addr_type = type;
|
||||
memcpy(dev_addr.addr, address, ADDR_LEN);
|
||||
|
||||
ASSERT_INT(ERROR_NONE, sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &dev_addr), BLE_ERROR_PARAM_OUT_OF_RANGE);
|
||||
ASSERT_INT(ERROR_NONE, sd_ble_gap_address_set(cycle_mode, &dev_addr), BLE_ERROR_PARAM_OUT_OF_RANGE);
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,11 @@
|
|||
#include "ble/GapScanningParams.h"
|
||||
|
||||
#include "nrf_soc.h"
|
||||
|
||||
extern "C" {
|
||||
#include "ble_radio_notification.h"
|
||||
}
|
||||
|
||||
#include "btle_security.h"
|
||||
|
||||
void radioNotificationStaticCallback(bool param);
|
||||
|
@ -109,64 +113,84 @@ public:
|
|||
#endif
|
||||
|
||||
private:
|
||||
#ifdef YOTTA_CFG_MBED_OS
|
||||
/*
|
||||
* In mbed OS, all user-facing BLE events (interrupts) are posted to the
|
||||
* MINAR scheduler to be executed as callbacks in thread mode. MINAR guards
|
||||
* its critical sections from interrupts by acquiring CriticalSectionLock,
|
||||
* which results in a call to sd_nvic_critical_region_enter(). Thus, it is
|
||||
* safe to invoke MINAR APIs from interrupt context as long as those
|
||||
* interrupts are blocked by sd_nvic_critical_region_enter().
|
||||
*
|
||||
* Radio notifications are a special case for the above. The Radio
|
||||
* Notification IRQ is handled at a very high priority--higher than the
|
||||
* level blocked by sd_nvic_critical_region_enter(). Thus Radio Notification
|
||||
* events can preempt MINAR's critical sections. Using MINAR APIs (such as
|
||||
* posting an event) directly in processRadioNotification() may result in a
|
||||
* race condition ending in a hard-fault.
|
||||
*
|
||||
* The solution is to *not* call MINAR APIs directly from the Radio
|
||||
* Notification handling; i.e. to do the bulk of RadioNotification
|
||||
* processing at a reduced priority which respects MINAR's critical
|
||||
* sections. Unfortunately, on a cortex-M0, there is no clean way to demote
|
||||
* priority for the currently executing interrupt--we wouldn't want to
|
||||
* demote the radio notification handling anyway because it is sensitive to
|
||||
* timing, and the system expects to finish this handling very quickly. The
|
||||
* workaround is to employ a Timeout to trigger
|
||||
* postRadioNotificationCallback() after a very short delay (~0 us) and post
|
||||
* the MINAR callback that context.
|
||||
*
|
||||
* !!!WARNING!!! Radio notifications are very time critical events. The
|
||||
* current solution is expected to work under the assumption that
|
||||
* postRadioNotificationCalback() will be executed BEFORE the next radio
|
||||
* notification event is generated.
|
||||
*/
|
||||
|
||||
bool radioNotificationCallbackParam; /* parameter to be passed into the Timeout-generated radio notification callback. */
|
||||
Timeout radioNotificationTimeout;
|
||||
|
||||
/*
|
||||
* A helper function to post radio notification callbacks through MINAR when using mbed OS.
|
||||
* A helper function to post radio notification callbacks with low interrupt priority.
|
||||
*/
|
||||
void postRadioNotificationCallback(void) {
|
||||
#ifdef YOTTA_CFG_MBED_OS
|
||||
/*
|
||||
* In mbed OS, all user-facing BLE events (interrupts) are posted to the
|
||||
* MINAR scheduler to be executed as callbacks in thread mode. MINAR guards
|
||||
* its critical sections from interrupts by acquiring CriticalSectionLock,
|
||||
* which results in a call to sd_nvic_critical_region_enter(). Thus, it is
|
||||
* safe to invoke MINAR APIs from interrupt context as long as those
|
||||
* interrupts are blocked by sd_nvic_critical_region_enter().
|
||||
*
|
||||
* Radio notifications are a special case for the above. The Radio
|
||||
* Notification IRQ is handled at a very high priority--higher than the
|
||||
* level blocked by sd_nvic_critical_region_enter(). Thus Radio Notification
|
||||
* events can preempt MINAR's critical sections. Using MINAR APIs (such as
|
||||
* posting an event) directly in processRadioNotification() may result in a
|
||||
* race condition ending in a hard-fault.
|
||||
*
|
||||
* The solution is to *not* call MINAR APIs directly from the Radio
|
||||
* Notification handling; i.e. to do the bulk of RadioNotification
|
||||
* processing at a reduced priority which respects MINAR's critical
|
||||
* sections. Unfortunately, on a cortex-M0, there is no clean way to demote
|
||||
* priority for the currently executing interrupt--we wouldn't want to
|
||||
* demote the radio notification handling anyway because it is sensitive to
|
||||
* timing, and the system expects to finish this handling very quickly. The
|
||||
* workaround is to employ a Timeout to trigger
|
||||
* postRadioNotificationCallback() after a very short delay (~0 us) and post
|
||||
* the MINAR callback that context.
|
||||
*
|
||||
* !!!WARNING!!! Radio notifications are very time critical events. The
|
||||
* current solution is expected to work under the assumption that
|
||||
* postRadioNotificationCalback() will be executed BEFORE the next radio
|
||||
* notification event is generated.
|
||||
*/
|
||||
minar::Scheduler::postCallback(
|
||||
mbed::util::FunctionPointer1<void, bool>(&radioNotificationCallback, &FunctionPointerWithContext<bool>::call).bind(radioNotificationCallbackParam)
|
||||
);
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* In mbed classic, all user-facing BLE events execute callbacks in interrupt
|
||||
* mode. Radio Notifications are a special case because its IRQ is handled at
|
||||
* a very high priority. Thus Radio Notification events can preempt other
|
||||
* operations that require interaction with the SoftDevice such as advertising
|
||||
* payload updates and changing the Gap state. Therefore, executing a Radio
|
||||
* Notification callback directly from processRadioNotification() may result
|
||||
* in a race condition ending in a hard-fault.
|
||||
*
|
||||
* The solution is to *not* execute the Radio Notification callback directly
|
||||
* from the Radio Notification handling; i.e. to do the bulk of the
|
||||
* Radio Notification processing at a reduced priority. Unfortunately, on a
|
||||
* cortex-M0, there is no clean way to demote priority for the currently
|
||||
* executing interrupt--we wouldn't want to demote the radio notification
|
||||
* handling anyway because it is sensitive to timing, and the system expects
|
||||
* to finish this handling very quickly. The workaround is to employ a Timeout
|
||||
* to trigger postRadioNotificationCallback() after a very short delay (~0 us)
|
||||
* and execute the callback in that context.
|
||||
*
|
||||
* !!!WARNING!!! Radio notifications are very time critical events. The
|
||||
* current solution is expected to work under the assumption that
|
||||
* postRadioNotificationCalback() will be executed BEFORE the next radio
|
||||
* notification event is generated.
|
||||
*/
|
||||
radioNotificationCallback.call(radioNotificationCallbackParam);
|
||||
#endif /* #ifdef YOTTA_CFG_MBED_OS */
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function to process radio-notification events; to be called internally.
|
||||
* @param param [description]
|
||||
*/
|
||||
void processRadioNotificationEvent(bool param) {
|
||||
#ifdef YOTTA_CFG_MBED_OS
|
||||
/* When using mbed OS the callback to the user-defined function will be posted through minar */
|
||||
radioNotificationCallbackParam = param;
|
||||
radioNotificationTimeout.attach_us(this, &nRF5xGap::postRadioNotificationCallback, 0);
|
||||
#else
|
||||
radioNotificationCallback.call(param);
|
||||
#endif
|
||||
}
|
||||
friend void radioNotificationStaticCallback(bool param); /* allow invocations of processRadioNotificationEvent() */
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ ble_error_t nRF5xGattServer::addService(GattService &service)
|
|||
|
||||
/* Skip any incompletely defined, read-only characteristics. */
|
||||
if ((p_char->getValueAttribute().getValuePtr() == NULL) &&
|
||||
(p_char->getValueAttribute().getInitialLength() == 0) &&
|
||||
(p_char->getValueAttribute().getLength() == 0) &&
|
||||
(p_char->getProperties() == GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -95,8 +95,9 @@ ble_error_t nRF5xGattServer::addService(GattService &service)
|
|||
p_char->getProperties(),
|
||||
p_char->getRequiredSecurity(),
|
||||
p_char->getValueAttribute().getValuePtr(),
|
||||
p_char->getValueAttribute().getInitialLength(),
|
||||
p_char->getValueAttribute().getLength(),
|
||||
p_char->getValueAttribute().getMaxLength(),
|
||||
p_char->getValueAttribute().hasVariableLength(),
|
||||
userDescriptionDescriptorValuePtr,
|
||||
userDescriptionDescriptorValueLen,
|
||||
p_char->isReadAuthorizationEnabled(),
|
||||
|
@ -127,8 +128,9 @@ ble_error_t nRF5xGattServer::addService(GattService &service)
|
|||
custom_add_in_descriptor(BLE_GATT_HANDLE_INVALID,
|
||||
&nordicUUID,
|
||||
p_desc->getValuePtr(),
|
||||
p_desc->getInitialLength(),
|
||||
p_desc->getLength(),
|
||||
p_desc->getMaxLength(),
|
||||
p_desc->hasVariableLength(),
|
||||
&nrfDescriptorHandles[descriptorCount]),
|
||||
BLE_ERROR_PARAM_OUT_OF_RANGE);
|
||||
|
||||
|
|
|
@ -39,6 +39,10 @@ public:
|
|||
return btle_getLinkSecurity(connectionHandle, securityStatusP);
|
||||
}
|
||||
|
||||
virtual ble_error_t setLinkSecurity(Gap::Handle_t connectionHandle, SecurityMode_t securityMode) {
|
||||
return btle_setLinkSecurity(connectionHandle, securityMode);
|
||||
}
|
||||
|
||||
virtual ble_error_t purgeAllBondingState(void) {
|
||||
return btle_purgeAllBondingState();
|
||||
}
|
||||
|
|
|
@ -285,13 +285,10 @@ nRF5xServiceDiscovery::processDiscoverUUIDResponse(const ble_gattc_evt_char_val_
|
|||
if (state == DISCOVER_SERVICE_UUIDS) {
|
||||
if ((response->count == 1) && (response->value_len == UUID::LENGTH_OF_LONG_UUID)) {
|
||||
UUID::LongUUIDBytes_t uuid;
|
||||
/* Switch longUUID bytes to MSB */
|
||||
for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
|
||||
uuid[i] = response->handle_value[0].p_value[UUID::LENGTH_OF_LONG_UUID - 1 - i];
|
||||
}
|
||||
memcpy(uuid, response->handle_value[0].p_value, UUID::LENGTH_OF_LONG_UUID);
|
||||
|
||||
unsigned serviceIndex = serviceUUIDDiscoveryQueue.dequeue();
|
||||
services[serviceIndex].setupLongUUID(uuid);
|
||||
services[serviceIndex].setupLongUUID(uuid, UUID::LSB);
|
||||
|
||||
serviceUUIDDiscoveryQueue.triggerFirst();
|
||||
} else {
|
||||
|
@ -300,13 +297,11 @@ nRF5xServiceDiscovery::processDiscoverUUIDResponse(const ble_gattc_evt_char_val_
|
|||
} else if (state == DISCOVER_CHARACTERISTIC_UUIDS) {
|
||||
if ((response->count == 1) && (response->value_len == UUID::LENGTH_OF_LONG_UUID + 1 /* props */ + 2 /* value handle */)) {
|
||||
UUID::LongUUIDBytes_t uuid;
|
||||
/* Switch longUUID bytes to MSB */
|
||||
for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
|
||||
uuid[i] = response->handle_value[0].p_value[3 + UUID::LENGTH_OF_LONG_UUID - 1 - i];
|
||||
}
|
||||
|
||||
memcpy(uuid, &(response->handle_value[0].p_value[3]), UUID::LENGTH_OF_LONG_UUID);
|
||||
|
||||
unsigned charIndex = charUUIDDiscoveryQueue.dequeue();
|
||||
characteristics[charIndex].setupLongUUID(uuid);
|
||||
characteristics[charIndex].setupLongUUID(uuid, UUID::LSB);
|
||||
|
||||
charUUIDDiscoveryQueue.triggerFirst();
|
||||
} else {
|
||||
|
|
|
@ -22,7 +22,9 @@
|
|||
#include "btle/btle.h"
|
||||
#include "nrf_delay.h"
|
||||
|
||||
extern "C" {
|
||||
#include "softdevice_handler.h"
|
||||
}
|
||||
|
||||
/**
|
||||
* The singleton which represents the nRF51822 transport for the BLE.
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Nordic Semiconductor ASA
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this
|
||||
* list of conditions and the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ble_radio_notification.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
static bool m_radio_active = false; /**< Current radio state. */
|
||||
static ble_radio_notification_evt_handler_t m_evt_handler = NULL; /**< Application event handler for handling Radio Notification events. */
|
||||
|
||||
|
||||
void SWI1_IRQHandler(void)
|
||||
{
|
||||
m_radio_active = !m_radio_active;
|
||||
if (m_evt_handler != NULL)
|
||||
{
|
||||
m_evt_handler(m_radio_active);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_radio_notification_init(nrf_app_irq_priority_t irq_priority,
|
||||
nrf_radio_notification_distance_t distance,
|
||||
ble_radio_notification_evt_handler_t evt_handler)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
m_evt_handler = evt_handler;
|
||||
|
||||
// Initialize Radio Notification software interrupt
|
||||
err_code = sd_nvic_ClearPendingIRQ(SWI1_IRQn);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
err_code = sd_nvic_SetPriority(SWI1_IRQn, irq_priority);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
err_code = sd_nvic_EnableIRQ(SWI1_IRQn);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
// Configure the event
|
||||
return sd_radio_notification_cfg_set(NRF_RADIO_NOTIFICATION_TYPE_INT_ON_BOTH, distance);
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Nordic Semiconductor ASA
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this
|
||||
* list of conditions and the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
/** @file
|
||||
*
|
||||
* @defgroup ble_radio_notification Radio Notification Event Handler
|
||||
* @{
|
||||
* @ingroup ble_sdk_lib
|
||||
* @brief Module for propagating Radio Notification events to the application.
|
||||
*/
|
||||
|
||||
#ifndef BLE_RADIO_NOTIFICATION_H__
|
||||
#define BLE_RADIO_NOTIFICATION_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "nrf_soc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Application radio notification event handler type. */
|
||||
typedef void (*ble_radio_notification_evt_handler_t) (bool radio_active);
|
||||
|
||||
/**@brief Function for initializing the Radio Notification module.
|
||||
*
|
||||
* @param[in] irq_priority Interrupt priority for the Radio Notification interrupt handler.
|
||||
* @param[in] distance The time from an Active event until the radio is activated.
|
||||
* @param[in] evt_handler Handler to be executed when a radio notification event has been
|
||||
* received.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful initialization, otherwise an error code.
|
||||
*/
|
||||
uint32_t ble_radio_notification_init(nrf_app_irq_priority_t irq_priority,
|
||||
nrf_radio_notification_distance_t distance,
|
||||
ble_radio_notification_evt_handler_t evt_handler);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BLE_RADIO_NOTIFICATION_H__
|
||||
|
||||
/** @} */
|
|
@ -1,686 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Nordic Semiconductor ASA
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this
|
||||
* list of conditions and the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ble_dfu.h"
|
||||
#include "nrf_error.h"
|
||||
#include "ble_types.h"
|
||||
#include "ble_gatts.h"
|
||||
#include "app_util.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "nordic_common.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define MAX_DFU_PKT_LEN 20 /**< Maximum length (in bytes) of the DFU Packet characteristic. */
|
||||
#define PKT_START_DFU_PARAM_LEN 2 /**< Length (in bytes) of the parameters for Packet Start DFU Request. */
|
||||
#define PKT_INIT_DFU_PARAM_LEN 2 /**< Length (in bytes) of the parameters for Packet Init DFU Request. */
|
||||
#define PKT_RCPT_NOTIF_REQ_LEN 3 /**< Length (in bytes) of the Packet Receipt Notification Request. */
|
||||
#define MAX_PKTS_RCPT_NOTIF_LEN 6 /**< Maximum length (in bytes) of the Packets Receipt Notification. */
|
||||
#define MAX_RESPONSE_LEN 7 /**< Maximum length (in bytes) of the response to a Control Point command. */
|
||||
#define MAX_NOTIF_BUFFER_LEN MAX(MAX_PKTS_RCPT_NOTIF_LEN, MAX_RESPONSE_LEN) /**< Maximum length (in bytes) of the buffer needed by DFU Service while sending notifications to peer. */
|
||||
|
||||
enum
|
||||
{
|
||||
OP_CODE_START_DFU = 1, /**< Value of the Op code field for 'Start DFU' command.*/
|
||||
OP_CODE_RECEIVE_INIT = 2, /**< Value of the Op code field for 'Initialize DFU parameters' command.*/
|
||||
OP_CODE_RECEIVE_FW = 3, /**< Value of the Op code field for 'Receive firmware image' command.*/
|
||||
OP_CODE_VALIDATE = 4, /**< Value of the Op code field for 'Validate firmware' command.*/
|
||||
OP_CODE_ACTIVATE_N_RESET = 5, /**< Value of the Op code field for 'Activate & Reset' command.*/
|
||||
OP_CODE_SYS_RESET = 6, /**< Value of the Op code field for 'Reset System' command.*/
|
||||
OP_CODE_IMAGE_SIZE_REQ = 7, /**< Value of the Op code field for 'Report received image size' command.*/
|
||||
OP_CODE_PKT_RCPT_NOTIF_REQ = 8, /**< Value of the Op code field for 'Request packet receipt notification.*/
|
||||
OP_CODE_RESPONSE = 16, /**< Value of the Op code field for 'Response.*/
|
||||
OP_CODE_PKT_RCPT_NOTIF = 17 /**< Value of the Op code field for 'Packets Receipt Notification'.*/
|
||||
};
|
||||
|
||||
static bool m_is_dfu_service_initialized = false; /**< Variable to check if the DFU service was initialized by the application.*/
|
||||
static uint8_t m_notif_buffer[MAX_NOTIF_BUFFER_LEN]; /**< Buffer used for sending notifications to peer. */
|
||||
|
||||
/**@brief Function for adding DFU Packet characteristic to the BLE Stack.
|
||||
*
|
||||
* @param[in] p_dfu DFU Service structure.
|
||||
*
|
||||
* @return NRF_SUCCESS on success. Otherwise an error code.
|
||||
*/
|
||||
static uint32_t dfu_pkt_char_add(ble_dfu_t * const p_dfu)
|
||||
{
|
||||
ble_gatts_char_md_t char_md;
|
||||
ble_gatts_attr_t attr_char_value;
|
||||
ble_uuid_t char_uuid;
|
||||
ble_gatts_attr_md_t attr_md;
|
||||
|
||||
memset(&char_md, 0, sizeof(char_md));
|
||||
|
||||
char_md.char_props.write_wo_resp = 1;
|
||||
char_md.p_char_user_desc = NULL;
|
||||
char_md.p_char_pf = NULL;
|
||||
char_md.p_user_desc_md = NULL;
|
||||
char_md.p_cccd_md = NULL;
|
||||
char_md.p_sccd_md = NULL;
|
||||
|
||||
char_uuid.type = p_dfu->uuid_type;
|
||||
char_uuid.uuid = BLE_DFU_PKT_CHAR_UUID;
|
||||
|
||||
memset(&attr_md, 0, sizeof(attr_md));
|
||||
|
||||
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm);
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
|
||||
|
||||
attr_md.vloc = BLE_GATTS_VLOC_STACK;
|
||||
attr_md.rd_auth = 0;
|
||||
attr_md.wr_auth = 0;
|
||||
attr_md.vlen = 1;
|
||||
|
||||
memset(&attr_char_value, 0, sizeof(attr_char_value));
|
||||
|
||||
attr_char_value.p_uuid = &char_uuid;
|
||||
attr_char_value.p_attr_md = &attr_md;
|
||||
attr_char_value.init_len = 0;
|
||||
attr_char_value.init_offs = 0;
|
||||
attr_char_value.max_len = MAX_DFU_PKT_LEN;
|
||||
attr_char_value.p_value = NULL;
|
||||
|
||||
return sd_ble_gatts_characteristic_add(p_dfu->service_handle,
|
||||
&char_md,
|
||||
&attr_char_value,
|
||||
&p_dfu->dfu_pkt_handles);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for adding DFU Revision characteristic to the BLE Stack.
|
||||
*
|
||||
* @param[in] p_dfu DFU Service structure.
|
||||
*
|
||||
* @return NRF_SUCCESS on success. Otherwise an error code.
|
||||
*/
|
||||
static uint32_t dfu_rev_char_add(ble_dfu_t * const p_dfu, ble_dfu_init_t const * const p_dfu_init)
|
||||
{
|
||||
ble_gatts_char_md_t char_md;
|
||||
ble_gatts_attr_t attr_char_value;
|
||||
ble_uuid_t char_uuid;
|
||||
ble_gatts_attr_md_t attr_md;
|
||||
|
||||
memset(&char_md, 0, sizeof(char_md));
|
||||
|
||||
char_md.char_props.read = 1;
|
||||
char_md.p_char_user_desc = NULL;
|
||||
char_md.p_char_pf = NULL;
|
||||
char_md.p_user_desc_md = NULL;
|
||||
char_md.p_cccd_md = NULL;
|
||||
char_md.p_sccd_md = NULL;
|
||||
|
||||
char_uuid.type = p_dfu->uuid_type;
|
||||
char_uuid.uuid = BLE_DFU_REV_CHAR_UUID;
|
||||
|
||||
memset(&attr_md, 0, sizeof(attr_md));
|
||||
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
|
||||
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
|
||||
|
||||
attr_md.vloc = BLE_GATTS_VLOC_STACK;
|
||||
attr_md.rd_auth = 0;
|
||||
attr_md.wr_auth = 0;
|
||||
attr_md.vlen = 1;
|
||||
|
||||
memset(&attr_char_value, 0, sizeof(attr_char_value));
|
||||
|
||||
attr_char_value.p_uuid = &char_uuid;
|
||||
attr_char_value.p_attr_md = &attr_md;
|
||||
attr_char_value.init_len = sizeof(uint16_t);
|
||||
attr_char_value.init_offs = 0;
|
||||
attr_char_value.max_len = sizeof(uint16_t);
|
||||
attr_char_value.p_value = (uint8_t *)&p_dfu_init->revision;
|
||||
|
||||
return sd_ble_gatts_characteristic_add(p_dfu->service_handle,
|
||||
&char_md,
|
||||
&attr_char_value,
|
||||
&p_dfu->dfu_rev_handles);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for adding DFU Control Point characteristic to the BLE Stack.
|
||||
*
|
||||
* @param[in] p_dfu DFU Service structure.
|
||||
*
|
||||
* @return NRF_SUCCESS on success. Otherwise an error code.
|
||||
*/
|
||||
static uint32_t dfu_ctrl_pt_add(ble_dfu_t * const p_dfu)
|
||||
{
|
||||
ble_gatts_char_md_t char_md;
|
||||
ble_gatts_attr_t attr_char_value;
|
||||
ble_uuid_t char_uuid;
|
||||
ble_gatts_attr_md_t attr_md;
|
||||
|
||||
memset(&char_md, 0, sizeof(char_md));
|
||||
|
||||
char_md.char_props.write = 1;
|
||||
char_md.char_props.notify = 1;
|
||||
char_md.p_char_user_desc = NULL;
|
||||
char_md.p_char_pf = NULL;
|
||||
char_md.p_user_desc_md = NULL;
|
||||
char_md.p_cccd_md = NULL;
|
||||
char_md.p_sccd_md = NULL;
|
||||
|
||||
char_uuid.type = p_dfu->uuid_type;
|
||||
char_uuid.uuid = BLE_DFU_CTRL_PT_UUID;
|
||||
|
||||
memset(&attr_md, 0, sizeof(attr_md));
|
||||
|
||||
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm);
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
|
||||
|
||||
attr_md.vloc = BLE_GATTS_VLOC_STACK;
|
||||
attr_md.rd_auth = 0;
|
||||
attr_md.wr_auth = 1;
|
||||
attr_md.vlen = 1;
|
||||
|
||||
memset(&attr_char_value, 0, sizeof(attr_char_value));
|
||||
|
||||
attr_char_value.p_uuid = &char_uuid;
|
||||
attr_char_value.p_attr_md = &attr_md;
|
||||
attr_char_value.init_len = 0;
|
||||
attr_char_value.init_offs = 0;
|
||||
attr_char_value.max_len = BLE_L2CAP_MTU_DEF;
|
||||
attr_char_value.p_value = NULL;
|
||||
|
||||
return sd_ble_gatts_characteristic_add(p_dfu->service_handle,
|
||||
&char_md,
|
||||
&attr_char_value,
|
||||
&p_dfu->dfu_ctrl_pt_handles);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the @ref BLE_GAP_EVT_CONNECTED event from the S110 SoftDevice.
|
||||
*
|
||||
* @param[in] p_dfu DFU Service Structure.
|
||||
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
|
||||
*/
|
||||
static void on_connect(ble_dfu_t * p_dfu, ble_evt_t * p_ble_evt)
|
||||
{
|
||||
p_dfu->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for checking if the CCCD of DFU Control point is configured for Notification.
|
||||
*
|
||||
* @details This function checks if the CCCD of DFU Control Point characteristic is configured
|
||||
* for Notification by the DFU Controller.
|
||||
*
|
||||
* @param[in] p_dfu DFU Service structure.
|
||||
*
|
||||
* @return True if the CCCD of DFU Control Point characteristic is configured for Notification.
|
||||
* False otherwise.
|
||||
*/
|
||||
static bool is_cccd_configured(ble_dfu_t * p_dfu)
|
||||
{
|
||||
// Check if the CCCDs are configured.
|
||||
uint8_t cccd_val_buf[BLE_CCCD_VALUE_LEN];
|
||||
ble_gatts_value_t gatts_value;
|
||||
|
||||
// Initialize value struct.
|
||||
memset(&gatts_value, 0, sizeof(gatts_value));
|
||||
|
||||
gatts_value.len = BLE_CCCD_VALUE_LEN;
|
||||
gatts_value.offset = 0;
|
||||
gatts_value.p_value = cccd_val_buf;
|
||||
|
||||
// Check the CCCD Value of DFU Control Point.
|
||||
uint32_t err_code = sd_ble_gatts_value_get(p_dfu->conn_handle,
|
||||
p_dfu->dfu_ctrl_pt_handles.cccd_handle,
|
||||
&gatts_value);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
if (p_dfu->error_handler != NULL)
|
||||
{
|
||||
p_dfu->error_handler(err_code);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return ble_srv_is_notification_enabled(cccd_val_buf);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling a Write event on the Control Point characteristic.
|
||||
*
|
||||
* @param[in] p_dfu DFU Service Structure.
|
||||
* @param[in] p_ble_write_evt Pointer to the write event received from BLE stack.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful processing of control point write. Otherwise an error code.
|
||||
*/
|
||||
static uint32_t on_ctrl_pt_write(ble_dfu_t * p_dfu, ble_gatts_evt_write_t * p_ble_write_evt)
|
||||
{
|
||||
ble_gatts_rw_authorize_reply_params_t write_authorize_reply;
|
||||
|
||||
write_authorize_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
|
||||
|
||||
if (!is_cccd_configured(p_dfu))
|
||||
{
|
||||
// Send an error response to the peer indicating that the CCCD is improperly configured.
|
||||
write_authorize_reply.params.write.gatt_status =
|
||||
BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR;
|
||||
|
||||
return (sd_ble_gatts_rw_authorize_reply(p_dfu->conn_handle, &write_authorize_reply));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
write_authorize_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
|
||||
|
||||
err_code = (sd_ble_gatts_rw_authorize_reply(p_dfu->conn_handle, &write_authorize_reply));
|
||||
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
}
|
||||
|
||||
ble_dfu_evt_t ble_dfu_evt;
|
||||
|
||||
switch (p_ble_write_evt->data[0])
|
||||
{
|
||||
case OP_CODE_START_DFU:
|
||||
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_START;
|
||||
|
||||
if (p_ble_write_evt->len < PKT_START_DFU_PARAM_LEN)
|
||||
{
|
||||
return ble_dfu_response_send(p_dfu,
|
||||
(ble_dfu_procedure_t) p_ble_write_evt->data[0],
|
||||
BLE_DFU_RESP_VAL_OPER_FAILED);
|
||||
}
|
||||
|
||||
ble_dfu_evt.evt.ble_dfu_pkt_write.len = 1;
|
||||
ble_dfu_evt.evt.ble_dfu_pkt_write.p_data = &(p_ble_write_evt->data[1]);
|
||||
|
||||
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
|
||||
break;
|
||||
|
||||
case OP_CODE_RECEIVE_INIT:
|
||||
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_RECEIVE_INIT_DATA;
|
||||
|
||||
if (p_ble_write_evt->len < PKT_INIT_DFU_PARAM_LEN)
|
||||
{
|
||||
return ble_dfu_response_send(p_dfu,
|
||||
(ble_dfu_procedure_t) p_ble_write_evt->data[0],
|
||||
BLE_DFU_RESP_VAL_OPER_FAILED);
|
||||
}
|
||||
|
||||
ble_dfu_evt.evt.ble_dfu_pkt_write.len = 1;
|
||||
ble_dfu_evt.evt.ble_dfu_pkt_write.p_data = &(p_ble_write_evt->data[1]);
|
||||
|
||||
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
|
||||
break;
|
||||
|
||||
case OP_CODE_RECEIVE_FW:
|
||||
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_RECEIVE_APP_DATA;
|
||||
|
||||
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
|
||||
break;
|
||||
|
||||
case OP_CODE_VALIDATE:
|
||||
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_VALIDATE;
|
||||
|
||||
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
|
||||
break;
|
||||
|
||||
case OP_CODE_ACTIVATE_N_RESET:
|
||||
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_ACTIVATE_N_RESET;
|
||||
|
||||
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
|
||||
break;
|
||||
|
||||
case OP_CODE_SYS_RESET:
|
||||
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_SYS_RESET;
|
||||
|
||||
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
|
||||
break;
|
||||
|
||||
case OP_CODE_PKT_RCPT_NOTIF_REQ:
|
||||
if (p_ble_write_evt->len < PKT_RCPT_NOTIF_REQ_LEN)
|
||||
{
|
||||
return (ble_dfu_response_send(p_dfu,
|
||||
BLE_DFU_PKT_RCPT_REQ_PROCEDURE,
|
||||
BLE_DFU_RESP_VAL_NOT_SUPPORTED));
|
||||
}
|
||||
|
||||
ble_dfu_evt.evt.pkt_rcpt_notif_req.num_of_pkts =
|
||||
uint16_decode(&(p_ble_write_evt->data[1]));
|
||||
|
||||
if (ble_dfu_evt.evt.pkt_rcpt_notif_req.num_of_pkts == 0)
|
||||
{
|
||||
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_PKT_RCPT_NOTIF_DISABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_PKT_RCPT_NOTIF_ENABLED;
|
||||
}
|
||||
|
||||
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
|
||||
|
||||
break;
|
||||
|
||||
case OP_CODE_IMAGE_SIZE_REQ:
|
||||
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_BYTES_RECEIVED_SEND;
|
||||
|
||||
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Unsupported op code.
|
||||
return ble_dfu_response_send(p_dfu,
|
||||
(ble_dfu_procedure_t) p_ble_write_evt->data[0],
|
||||
BLE_DFU_RESP_VAL_NOT_SUPPORTED);
|
||||
}
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST event from the S110
|
||||
* Stack.
|
||||
*
|
||||
* @param[in] p_dfu DFU Service Structure.
|
||||
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
|
||||
*/
|
||||
static void on_rw_authorize_req(ble_dfu_t * p_dfu, ble_evt_t * p_ble_evt)
|
||||
{
|
||||
ble_gatts_evt_rw_authorize_request_t * p_authorize_request;
|
||||
|
||||
p_authorize_request = &(p_ble_evt->evt.gatts_evt.params.authorize_request);
|
||||
|
||||
if (
|
||||
(p_authorize_request->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
|
||||
&&
|
||||
(p_authorize_request->request.write.handle == p_dfu->dfu_ctrl_pt_handles.value_handle)
|
||||
&&
|
||||
(p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.op != BLE_GATTS_OP_PREP_WRITE_REQ)
|
||||
&&
|
||||
(p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.op != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW)
|
||||
&&
|
||||
(p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.op != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)
|
||||
)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
err_code = on_ctrl_pt_write(p_dfu, &(p_authorize_request->request.write));
|
||||
|
||||
if (err_code != NRF_SUCCESS && p_dfu->error_handler != NULL)
|
||||
{
|
||||
p_dfu->error_handler(err_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the @ref BLE_GATTS_EVT_WRITE event from the S110 SoftDevice.
|
||||
*
|
||||
* @param[in] p_dfu DFU Service Structure.
|
||||
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
|
||||
*/
|
||||
static void on_write(ble_dfu_t * p_dfu, ble_evt_t * p_ble_evt)
|
||||
{
|
||||
if (p_ble_evt->evt.gatts_evt.params.write.handle == p_dfu->dfu_pkt_handles.value_handle)
|
||||
{
|
||||
// DFU Packet written
|
||||
|
||||
ble_dfu_evt_t ble_dfu_evt;
|
||||
|
||||
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_PACKET_WRITE;
|
||||
ble_dfu_evt.evt.ble_dfu_pkt_write.len = p_ble_evt->evt.gatts_evt.params.write.len;
|
||||
ble_dfu_evt.evt.ble_dfu_pkt_write.p_data = p_ble_evt->evt.gatts_evt.params.write.data;
|
||||
|
||||
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the BLE_GAP_EVT_DISCONNECTED event from the S110 SoftDevice.
|
||||
*
|
||||
* @param[in] p_dfu DFU Service Structure.
|
||||
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
|
||||
*/
|
||||
static void on_disconnect(ble_dfu_t * p_dfu, ble_evt_t * p_ble_evt)
|
||||
{
|
||||
p_dfu->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_dfu_init(ble_dfu_t * p_dfu, ble_dfu_init_t * p_dfu_init)
|
||||
{
|
||||
if ((p_dfu == NULL) || (p_dfu_init == NULL) || (p_dfu_init->evt_handler == NULL))
|
||||
{
|
||||
return NRF_ERROR_NULL;
|
||||
}
|
||||
|
||||
p_dfu->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
|
||||
ble_uuid_t service_uuid;
|
||||
uint32_t err_code;
|
||||
|
||||
const ble_uuid128_t base_uuid128 =
|
||||
{
|
||||
{
|
||||
0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
|
||||
0xDE, 0xEF, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00
|
||||
}
|
||||
};
|
||||
|
||||
service_uuid.uuid = BLE_DFU_SERVICE_UUID;
|
||||
|
||||
err_code = sd_ble_uuid_vs_add(&base_uuid128, &(service_uuid.type));
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
|
||||
&service_uuid,
|
||||
&(p_dfu->service_handle));
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
p_dfu->uuid_type = service_uuid.type;
|
||||
|
||||
err_code = dfu_pkt_char_add(p_dfu);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
err_code = dfu_ctrl_pt_add(p_dfu);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
err_code = dfu_rev_char_add(p_dfu, p_dfu_init);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
p_dfu->evt_handler = p_dfu_init->evt_handler;
|
||||
|
||||
if (p_dfu_init->error_handler != NULL)
|
||||
{
|
||||
p_dfu->error_handler = p_dfu_init->error_handler;
|
||||