Merge branch 'develop' of https://github.com/ARMmbed/ble into descriptorDiscovery

master
Vincent Coubard 7 years ago
commit 5caca671f3

@ -196,7 +196,7 @@ public:
* directly, as it returns references to singletons.
*
* @param[in] id
* Instance-ID. This should be less than NUM_INSTANCES
* Instance-ID. This should be less than NUM_INSTANCES
* for the returned BLE singleton to be useful.
*
* @return a reference to a single object.
@ -239,7 +239,7 @@ public:
* ble.setAddress(...) should be replaced with
* ble.gap().setAddress(...).
*/
ble_error_t setAddress(Gap::AddressType_t type, const Gap::Address_t address) {
ble_error_t setAddress(BLEProtocol::AddressType_t type, const BLEProtocol::Address_t address) {
return gap().setAddress(type, address);
}
@ -252,7 +252,7 @@ public:
* ble.getAddress(...) should be replaced with
* ble.gap().getAddress(...).
*/
ble_error_t getAddress(Gap::AddressType_t *typeP, Gap::Address_t address) {
ble_error_t getAddress(BLEProtocol::AddressType_t *typeP, BLEProtocol::Address_t address) {
return gap().getAddress(typeP, address);
}
@ -752,8 +752,8 @@ public:
* ble.connect(...) should be replaced with
* ble.gap().connect(...).
*/
ble_error_t connect(const Gap::Address_t peerAddr,
Gap::AddressType_t peerAddrType = Gap::ADDR_TYPE_RANDOM_STATIC,
ble_error_t connect(const BLEProtocol::Address_t peerAddr,
BLEProtocol::AddressType_t peerAddrType = BLEProtocol::AddressType::RANDOM_STATIC,
const Gap::ConnectionParams_t *connectionParams = NULL,
const GapScanningParams *scanParams = NULL) {
return gap().connect(peerAddr, peerAddrType, connectionParams, scanParams);
@ -773,7 +773,7 @@ public:
}
/**
* This call initiates the disconnection procedure, and its completion
* This call initiates the disconnection procedure, and its completion
* is communicated to the application with an invocation of the
* onDisconnection callback.
*
@ -1407,7 +1407,7 @@ public:
/**
* Set up a callback for when the passkey needs to be displayed on a
* peripheral with DISPLAY capability. This happens when security is
* configured to prevent Man-In-The-Middle attacks, and the peers need to exchange
* configured to prevent Man-In-The-Middle attacks, and the peers need to exchange
* a passkey (or PIN) to authenticate the connection
* attempt.
*

@ -0,0 +1,49 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __BLE_PROTOCOL_H__
#define __BLE_PROTOCOL_H__
#include <stddef.h>
#include <stdint.h>
/**
* A common namespace for types and constants used everywhere in BLE API.
*/
namespace BLEProtocol {
/**< Address-type for Protocol addresses. */
struct AddressType { /* Adding a struct to encapsulate the contained enumeration
* prevents polluting the BLEProtocol namespace with the
* enumerated values. It also allows type-aliases for the
* enumeration while retaining the enumerated values. i.e.
*
* doing:
* typedef AddressType_t AliasedType_t;
* would allow the use of AliasedType_t::PUBLIC in code. */
enum Type {
PUBLIC = 0,
RANDOM_STATIC,
RANDOM_PRIVATE_RESOLVABLE,
RANDOM_PRIVATE_NON_RESOLVABLE
};
};
typedef AddressType::Type AddressType_t; /**< Alias for AddressType::Type */
static const size_t ADDR_LEN = 6; /**< Length (in octets) of the BLE MAC address. */
typedef uint8_t Address_t[ADDR_LEN]; /**< 48-bit address, in LSB format. */
};
#endif /* __BLE_PROTOCOL_H__ */

@ -17,6 +17,7 @@
#ifndef __GAP_H__
#define __GAP_H__
#include "ble/BLEProtocol.h"
#include "GapAdvertisingData.h"
#include "GapAdvertisingParams.h"
#include "GapScanningParams.h"
@ -30,19 +31,44 @@ class GapScanningParams;
class GapAdvertisingData;
class Gap {
/*
* DEPRECATION ALERT: all of the APIs in this `public` block are deprecated.
* They have been relocated to the class BLEProtocol.
*/
public:
enum AddressType_t {
ADDR_TYPE_PUBLIC = 0,
ADDR_TYPE_RANDOM_STATIC,
ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE,
ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE
/**
* Address-type for BLEProtocol addresses.
*
* @note: deprecated. Use BLEProtocol::AddressType_t instead.
*/
typedef BLEProtocol::AddressType_t AddressType_t;
/**
* Address-type for BLEProtocol addresses.
* @note: deprecated. Use BLEProtocol::AddressType_t instead.
*/
typedef BLEProtocol::AddressType_t addr_type_t;
/**
* Address-type for BLEProtocol addresses.
* @note: deprecated. Use BLEProtocol::AddressType_t instead.
*
* DEPRECATION ALERT: The following constants have been left in their
* deprecated state to transparenly support existing applications which may
* have used Gap::ADDR_TYPE_*.
*/
enum {
ADDR_TYPE_PUBLIC = BLEProtocol::AddressType::PUBLIC,
ADDR_TYPE_RANDOM_STATIC = BLEProtocol::AddressType::RANDOM_STATIC,
ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE = BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE,
ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE = BLEProtocol::AddressType::RANDOM_PRIVATE_NON_RESOLVABLE
};
typedef enum AddressType_t addr_type_t; /* @Note: Deprecated. Use AddressType_t instead. */
static const unsigned ADDR_LEN = 6;
typedef uint8_t Address_t[ADDR_LEN]; /* 48-bit address, LSB format. */
typedef Address_t address_t; /* @Note: Deprecated. Use Address_t instead. */
static const unsigned ADDR_LEN = BLEProtocol::ADDR_LEN; /**< Length (in octets) of the BLE MAC address. */
typedef BLEProtocol::Address_t Address_t; /**< 48-bit address, LSB format. @Note: Deprecated. Use BLEProtocol::Address_t instead. */
typedef BLEProtocol::Address_t address_t; /**< 48-bit address, LSB format. @Note: Deprecated. Use BLEProtocol::Address_t instead. */
public:
enum TimeoutSource_t {
TIMEOUT_SRC_ADVERTISING = 0x00, /**< Advertising timeout. */
TIMEOUT_SRC_SECURITY_REQUEST = 0x01, /**< Security request timeout. */
@ -87,31 +113,31 @@ public:
};
struct AdvertisementCallbackParams_t {
Address_t peerAddr;
int8_t rssi;
bool isScanResponse;
GapAdvertisingParams::AdvertisingType_t type;
uint8_t advertisingDataLen;
const uint8_t *advertisingData;
BLEProtocol::Address_t peerAddr;
int8_t rssi;
bool isScanResponse;
GapAdvertisingParams::AdvertisingType_t type;
uint8_t advertisingDataLen;
const uint8_t *advertisingData;
};
typedef FunctionPointerWithContext<const AdvertisementCallbackParams_t *> AdvertisementReportCallback_t;
struct ConnectionCallbackParams_t {
Handle_t handle;
Role_t role;
AddressType_t peerAddrType;
Address_t peerAddr;
AddressType_t ownAddrType;
Address_t ownAddr;
const ConnectionParams_t *connectionParams;
ConnectionCallbackParams_t(Handle_t handleIn,
Role_t roleIn,
AddressType_t peerAddrTypeIn,
const uint8_t *peerAddrIn,
AddressType_t ownAddrTypeIn,
const uint8_t *ownAddrIn,
const ConnectionParams_t *connectionParamsIn) :
Handle_t handle;
Role_t role;
BLEProtocol::AddressType_t peerAddrType;
BLEProtocol::Address_t peerAddr;
BLEProtocol::AddressType_t ownAddrType;
BLEProtocol::Address_t ownAddr;
const ConnectionParams_t *connectionParams;
ConnectionCallbackParams_t(Handle_t handleIn,
Role_t roleIn,
BLEProtocol::AddressType_t peerAddrTypeIn,
const uint8_t *peerAddrIn,
BLEProtocol::AddressType_t ownAddrTypeIn,
const uint8_t *ownAddrIn,
const ConnectionParams_t *connectionParamsIn) :
handle(handleIn),
role(roleIn),
peerAddrType(peerAddrTypeIn),
@ -151,17 +177,20 @@ public:
typedef FunctionPointerWithContext<bool> RadioNotificationEventCallback_t;
typedef FunctionPointerWithContext<const Gap *> GapShutdownCallback_t;
typedef CallChainOfFunctionPointersWithContext<const Gap *> GapShutdownCallbackChain_t;
/*
* The following functions are meant to be overridden in the platform-specific sub-class.
*/
public:
/**
* Set the BTLE MAC address and type. Please note that the address format is
* least significant byte first (LSB). Please refer to Address_t.
* least significant byte first (LSB). Please refer to BLEProtocol::Address_t.
*
* @return BLE_ERROR_NONE on success.
*/
virtual ble_error_t setAddress(AddressType_t type, const Address_t address) {
virtual ble_error_t setAddress(BLEProtocol::AddressType_t type, const BLEProtocol::Address_t address) {
/* avoid compiler warnings about unused variables */
(void)type;
(void)address;
@ -174,7 +203,7 @@ public:
*
* @return BLE_ERROR_NONE on success.
*/
virtual ble_error_t getAddress(AddressType_t *typeP, Address_t address) {
virtual ble_error_t getAddress(BLEProtocol::AddressType_t *typeP, BLEProtocol::Address_t address) {
/* Avoid compiler warnings about unused variables. */
(void)typeP;
(void)address;
@ -233,10 +262,10 @@ public:
* successfully. The connectionCallChain (if set) will be invoked upon
* a connection event.
*/
virtual ble_error_t connect(const Address_t peerAddr,
Gap::AddressType_t peerAddrType,
const ConnectionParams_t *connectionParams,
const GapScanningParams *scanParams) {
virtual ble_error_t connect(const BLEProtocol::Address_t peerAddr,
BLEProtocol::AddressType_t peerAddrType,
const ConnectionParams_t *connectionParams,
const GapScanningParams *scanParams) {
/* Avoid compiler warnings about unused variables. */
(void)peerAddr;
(void)peerAddrType;
@ -575,6 +604,16 @@ public:
* @param type The type describing the variable length data.
* @param data Data bytes.
* @param len Length of data.
*
* @return BLE_ERROR_NONE if the advertisement payload was updated based on
* matching AD type; otherwise, an appropriate error.
*
* @note When the specified AD type is INCOMPLETE_LIST_16BIT_SERVICE_IDS,
* COMPLETE_LIST_16BIT_SERVICE_IDS, INCOMPLETE_LIST_32BIT_SERVICE_IDS,
* COMPLETE_LIST_32BIT_SERVICE_IDS, INCOMPLETE_LIST_128BIT_SERVICE_IDS,
* COMPLETE_LIST_128BIT_SERVICE_IDS or LIST_128BIT_SOLICITATION_IDS the
* supplied value is appended to the values previously added to the
* payload.
*/
ble_error_t accumulateAdvertisingPayload(GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len) {
if (type == GapAdvertisingData::COMPLETE_LOCAL_NAME) {
@ -591,8 +630,7 @@ public:
/**
* Update a particular ADV field in the advertising payload (based on
* matching type and length). Note: the length of the new data must be the
* same as the old one.
* matching type).
*
* @param[in] type The ADV type field describing the variable length data.
* @param[in] data Data bytes.
@ -601,7 +639,7 @@ public:
* @note: If advertisements are enabled, then the update will take effect immediately.
*
* @return BLE_ERROR_NONE if the advertisement payload was updated based on
* a <type, len> match; otherwise, an appropriate error.
* matching AD type; otherwise, an appropriate error.
*/
ble_error_t updateAdvertisingPayload(GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len) {
if (type == GapAdvertisingData::COMPLETE_LOCAL_NAME) {
@ -983,6 +1021,80 @@ public:
radioNotificationCallback.attach(tptr, mptr);
}
/**
* Setup a callback to be invoked to notify the user application that the
* Gap instance is about to shutdown (possibly as a result of a call
* to BLE::shutdown()).
*
* @Note: It is possible to chain together multiple onShutdown callbacks
* (potentially from different modules of an application) to be notified
* before the Gap instance is shutdown.
*
* @Note: It is also possible to set up a callback into a member function of
* some object.
*
* @Note It is possible to unregister a callback using onShutdown().detach(callback)
*/
void onShutdown(const GapShutdownCallback_t& callback) {
shutdownCallChain.add(callback);
}
template <typename T>
void onShutdown(T *objPtr, void (T::*memberPtr)(void)) {
shutdownCallChain.add(objPtr, memberPtr);
}
/**
* @brief provide access to the callchain of shutdown event callbacks
* It is possible to register callbacks using onShutdown().add(callback);
* It is possible to unregister callbacks using onShutdown().detach(callback)
* @return The shutdown event callbacks chain
*/
GapShutdownCallbackChain_t& onShutdown() {
return shutdownCallChain;
}
public:
/**
* Notify all registered onShutdown callbacks that the Gap instance is
* about to be shutdown and clear all Gap state of the
* associated object.
*
* This function is meant to be overridden in the platform-specific
* sub-class. Nevertheless, the sub-class is only expected to reset its
* state and not the data held in Gap members. This shall be achieved by a
* call to Gap::reset() from the sub-class' reset() implementation.
*
* @return BLE_ERROR_NONE on success.
*
* @note: Currently a call to reset() does not reset the advertising and
* scan parameters to default values.
*/
virtual ble_error_t reset(void) {
/* Notify that the instance is about to shutdown */
shutdownCallChain.call(this);
shutdownCallChain.clear();
/* Clear Gap state */
state.advertising = 0;
state.connected = 0;
/* Clear scanning state */
scanningActive = false;
/* Clear advertising and scanning data */
_advPayload.clear();
_scanResponse.clear();
/* Clear callbacks */
timeoutCallbackChain.clear();
connectionCallChain.clear();
disconnectionCallChain.clear();
radioNotificationCallback = NULL;
onAdvertisementReport = NULL;
return BLE_ERROR_NONE;
}
protected:
Gap() :
_advParams(),
@ -1002,13 +1114,13 @@ protected:
/* Entry points for the underlying stack to report events back to the user. */
public:
void processConnectionEvent(Handle_t handle,
Role_t role,
AddressType_t peerAddrType,
const Address_t peerAddr,
AddressType_t ownAddrType,
const Address_t ownAddr,
const ConnectionParams_t *connectionParams) {
void processConnectionEvent(Handle_t handle,
Role_t role,
BLEProtocol::AddressType_t peerAddrType,
const BLEProtocol::Address_t peerAddr,
BLEProtocol::AddressType_t ownAddrType,
const BLEProtocol::Address_t ownAddr,
const ConnectionParams_t *connectionParams) {
state.connected = 1;
ConnectionCallbackParams_t callbackParams(handle, role, peerAddrType, peerAddr, ownAddrType, ownAddr, connectionParams);
connectionCallChain.call(&callbackParams);
@ -1020,12 +1132,12 @@ public:
disconnectionCallChain.call(&callbackParams);
}
void processAdvertisementReport(const Address_t peerAddr,
int8_t rssi,
bool isScanResponse,
void processAdvertisementReport(const BLEProtocol::Address_t peerAddr,
int8_t rssi,
bool isScanResponse,
GapAdvertisingParams::AdvertisingType_t type,
uint8_t advertisingDataLen,
const uint8_t *advertisingData) {
uint8_t advertisingDataLen,
const uint8_t *advertisingData) {
AdvertisementCallbackParams_t params;
memcpy(params.peerAddr, peerAddr, ADDR_LEN);
params.rssi = rssi;
@ -1058,6 +1170,9 @@ protected:
ConnectionEventCallbackChain_t connectionCallChain;
DisconnectionEventCallbackChain_t disconnectionCallChain;
private:
GapShutdownCallbackChain_t shutdownCallChain;
private:
/* Disallow copy and assignment. */
Gap(const Gap &);

@ -187,6 +187,7 @@ public:
PULSE_OXIMETER_GENERIC = 3136, /**< Generic Pulse Oximeter. */
PULSE_OXIMETER_FINGERTIP = 3137, /**< Fingertip Pulse Oximeter. */
PULSE_OXIMETER_WRIST_WORN = 3138, /**< Wrist Worn Pulse Oximeter. */
GENERIC_WEIGHT_SCALE = 3200, /**< Generic Weight Scale. */
OUTDOOR_GENERIC = 5184, /**< Generic Outdoor. */
OUTDOOR_LOCATION_DISPLAY_DEVICE = 5185, /**< Outdoor Location Display Device. */
OUTDOOR_LOCATION_AND_NAVIGATION_DISPLAY_DEVICE = 5186, /**< Outdoor Location and Navigation Display Device. */
@ -201,149 +202,63 @@ public:
/**
* Adds advertising data based on the specified AD type (see DataType).
* If the supplied AD type is already present in the advertising
* payload, then the value is updated.
*
* @param advDataType The Advertising 'DataType' to add.
* @param payload Pointer to the payload contents.
* @param len Size of the payload in bytes.
* @param[in] advDataType The Advertising 'DataType' to add.
* @param[in] payload Pointer to the payload contents.
* @param[in] len Size of the payload in bytes.
*
* @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the
* advertising buffer to overflow, else BLE_ERROR_NONE.
* @return BLE_ERROR_BUFFER_OVERFLOW if the new value causes the
* advertising buffer to overflow. BLE_ERROR_NONE is returned
* on success.
*
* @note When the specified AD type is INCOMPLETE_LIST_16BIT_SERVICE_IDS,
* COMPLETE_LIST_16BIT_SERVICE_IDS, INCOMPLETE_LIST_32BIT_SERVICE_IDS,
* COMPLETE_LIST_32BIT_SERVICE_IDS, INCOMPLETE_LIST_128BIT_SERVICE_IDS,
* COMPLETE_LIST_128BIT_SERVICE_IDS or LIST_128BIT_SOLICITATION_IDS the
* supplied value is appended to the values previously added to the
* payload.
*/
ble_error_t addData(DataType advDataType, const uint8_t *payload, uint8_t len)
ble_error_t addData(DataType_t advDataType, const uint8_t *payload, uint8_t len)
{
ble_error_t result = BLE_ERROR_BUFFER_OVERFLOW;
// find field
uint8_t* field = findField(advDataType);
// Field type already exist, either add to field or replace
if (field) {
switch(advDataType) {
// These fields will be overwritten with the new value
case FLAGS:
case SHORTENED_LOCAL_NAME:
case COMPLETE_LOCAL_NAME:
case TX_POWER_LEVEL:
case DEVICE_ID:
case SLAVE_CONNECTION_INTERVAL_RANGE:
case SERVICE_DATA:
case APPEARANCE:
case ADVERTISING_INTERVAL:
case MANUFACTURER_SPECIFIC_DATA: {
// current field length, with the type subtracted
uint8_t dataLength = field[0] - 1;
// new data has same length, do in-order replacement
if (len == dataLength) {
for (uint8_t idx = 0; idx < dataLength; idx++) {
field[2 + idx] = payload[idx];
}
} else {
// check if data fits
if ((_payloadLen - dataLength + len) <= GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
// remove old field
while ((field + dataLength + 2) < &_payload[_payloadLen]) {
*field = field[dataLength + 2];
field++;
}
// reduce length
_payloadLen -= dataLength + 2;
// add new field
result = appendField(advDataType, payload, len);
}
}
break;
}
// These fields will have the new data appended if there is sufficient space
case INCOMPLETE_LIST_16BIT_SERVICE_IDS:
case COMPLETE_LIST_16BIT_SERVICE_IDS:
case INCOMPLETE_LIST_32BIT_SERVICE_IDS:
case COMPLETE_LIST_32BIT_SERVICE_IDS:
case INCOMPLETE_LIST_128BIT_SERVICE_IDS:
case COMPLETE_LIST_128BIT_SERVICE_IDS:
case LIST_128BIT_SOLICITATION_IDS: {
// check if data fits
if ((_payloadLen + len) <= GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
// make room for new field by moving the remainder of the
// advertisement payload "to the right" starting after the
// TYPE field.
uint8_t* end = &_payload[_payloadLen];
while (&field[1] < end) {
end[len] = *end;
end--;
}
// insert new data
for (uint8_t idx = 0; idx < len; idx++) {
field[2 + idx] = payload[idx];
}
// increment lengths
field[0] += len;
_payloadLen += len;
result = BLE_ERROR_NONE;
}
break;
}
// Field exists but updating it is not supported. Abort operation.
default:
result = BLE_ERROR_NOT_IMPLEMENTED;
break;
}
// Field type already exist, either add to field or replace
return addField(advDataType, payload, len, field);
} else {
// field doesn't exists, insert new
result = appendField(advDataType, payload, len);
return appendField(advDataType, payload, len);
}
return result;
}
/**
* Update a particular ADV field in the advertising payload (based on
* matching type and length). Note: the length of the new data must be the
* same as the old one.
* matching type).
*
* @param[in] advDataType The Advertising 'DataType' to add.
* @param[in] payload Pointer to the payload contents.
* @param[in] len Size of the payload in bytes.
*
* @return BLE_ERROR_UNSPECIFIED if the specified field is not found, else
* BLE_ERROR_NONE.
* @return BLE_ERROR_UNSPECIFIED if the specified field is not found,
* BLE_ERROR_BUFFER_OVERFLOW if the new value causes the
* advertising buffer to overflow. BLE_ERROR_NONE is returned
* on success.
*/
ble_error_t updateData(DataType_t advDataType, const uint8_t *payload, uint8_t len)
{
if ((payload == NULL) || (len == 0)) {
return BLE_ERROR_INVALID_PARAM;
}
/* A local struct to describe an ADV field. This definition comes from the Bluetooth Core Spec. (v4.2) Part C, Section 11. */
struct ADVField_t {
uint8_t len; /* Describes the length (in bytes) of the following type and bytes. */
uint8_t type; /* Should have the same representation of DataType_t (above). */
uint8_t bytes[0]; /* A placeholder for variable length data. */
};
/* Iterate over the adv fields looking for the first match. */
uint8_t byteIndex = 0;
while (byteIndex < _payloadLen) {
ADVField_t *currentADV = (ADVField_t *)&_payload[byteIndex];
if ((currentADV->len == (len + 1)) && /* Incoming len only describes the payload, whereas ADV->len describes [type + payload]. */
(currentADV->type == advDataType)) {
memcpy(currentADV->bytes, payload, len);
return BLE_ERROR_NONE;
}
// find field
uint8_t* field = findField(advDataType);
byteIndex += (currentADV->len + 1); /* Advance by len+1; '+1' is needed to span the len field itself. */
if (field) {
// Field type already exist, replace field contents
return updateField(advDataType, payload, len, field);
} else {
// field doesn't exists, return an error
return BLE_ERROR_UNSPECIFIED;
}
return BLE_ERROR_UNSPECIFIED;
}
/**
@ -474,6 +389,107 @@ private:
return NULL;
}
/**
* Given the a pointer to a field in the advertising payload it replaces
* the existing data in the field with the supplied data.
*
* When the specified AD type is INCOMPLETE_LIST_16BIT_SERVICE_IDS,
* COMPLETE_LIST_16BIT_SERVICE_IDS, INCOMPLETE_LIST_32BIT_SERVICE_IDS,
* COMPLETE_LIST_32BIT_SERVICE_IDS, INCOMPLETE_LIST_128BIT_SERVICE_IDS,
* COMPLETE_LIST_128BIT_SERVICE_IDS or LIST_128BIT_SOLICITATION_IDS the
* supplied value is appended to the values previously added to the
* payload.
*
* Returns BLE_ERROR_NONE on success.
*/
ble_error_t addField(DataType_t advDataType, const uint8_t *payload, uint8_t len, uint8_t* field)
{
ble_error_t result = BLE_ERROR_BUFFER_OVERFLOW;
switch(advDataType) {
// These fields will have the new data appended if there is sufficient space
case INCOMPLETE_LIST_16BIT_SERVICE_IDS:
case COMPLETE_LIST_16BIT_SERVICE_IDS:
case INCOMPLETE_LIST_32BIT_SERVICE_IDS:
case COMPLETE_LIST_32BIT_SERVICE_IDS:
case INCOMPLETE_LIST_128BIT_SERVICE_IDS:
case COMPLETE_LIST_128BIT_SERVICE_IDS:
case LIST_128BIT_SOLICITATION_IDS: {
// check if data fits
if ((_payloadLen + len) <= GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
// make room for new field by moving the remainder of the
// advertisement payload "to the right" starting after the
// TYPE field.
uint8_t* end = &_payload[_payloadLen];
while (&field[1] < end) {
end[len] = *end;
end--;
}
// insert new data
for (uint8_t idx = 0; idx < len; idx++) {
field[2 + idx] = payload[idx];
}
// increment lengths
field[0] += len;
_payloadLen += len;
result = BLE_ERROR_NONE;
}
break;
}
// These fields will be overwritten with the new value
default: {
result = updateField(advDataType, payload, len, field);
break;
}
}
return result;
}
/**
* Given the a pointer to a field in the advertising payload it replaces
* the existing data in the field with the supplied data.
* Returns BLE_ERROR_NONE on success.
*/
ble_error_t updateField(DataType_t advDataType, const uint8_t *payload, uint8_t len, uint8_t* field)
{
ble_error_t result = BLE_ERROR_BUFFER_OVERFLOW;
uint8_t dataLength = field[0] - 1;
// new data has same length, do in-order replacement
if (len == dataLength) {
for (uint8_t idx = 0; idx < dataLength; idx++) {
field[2 + idx] = payload[idx];
}
result = BLE_ERROR_NONE;
} else {
// check if data fits
if ((_payloadLen - dataLength + len) <= GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
// remove old field
while ((field + dataLength + 2) < &_payload[_payloadLen]) {
*field = field[dataLength + 2];
field++;
}
// reduce length
_payloadLen -= dataLength + 2;
// add new field
result = appendField(advDataType, payload, len);
}
}
return result;
}
uint8_t _payload[GAP_ADVERTISING_DATA_MAX_PAYLOAD];
uint8_t _payloadLen;
uint16_t _appearance;

@ -42,6 +42,9 @@ public:
typedef FunctionPointerWithContext<const GattHVXCallbackParams*> HVXCallback_t;
typedef CallChainOfFunctionPointersWithContext<const GattHVXCallbackParams*> HVXCallbackChain_t;
typedef FunctionPointerWithContext<const GattClient *> GattClientShutdownCallback_t;
typedef CallChainOfFunctionPointersWithContext<const GattClient *> GattClientShutdownCallbackChain_t;
/*
* The following functions are meant to be overridden in the platform-specific sub-class.
*/
@ -368,6 +371,37 @@ public:
onHVXCallbackChain.add(callback);
}
/**
* Setup a callback to be invoked to notify the user application that the
* GattClient instance is about to shutdown (possibly as a result of a call
* to BLE::shutdown()).
*
* @Note: It is possible to chain together multiple onShutdown callbacks
* (potentially from different modules of an application) to be notified
* before the GattClient is shutdown.
*
* @Note: It is also possible to set up a callback into a member function of
* some object.
*
* @Note It is possible to unregister a callback using onShutdown().detach(callback)
*/
void onShutdown(const GattClientShutdownCallback_t& callback) {
shutdownCallChain.add(callback);
}
template <typename T>
void onShutdown(T *objPtr, void (T::*memberPtr)(void)) {
shutdownCallChain.add(objPtr, memberPtr);
}
/**
* @brief provide access to the callchain of shutdown event callbacks
* It is possible to register callbacks using onShutdown().add(callback);
* It is possible to unregister callbacks using onShutdown().detach(callback)
* @return The shutdown event callbacks chain
*/
GattClientShutdownCallbackChain_t& onShutdown() {
return shutdownCallChain;
}
/**
* @brief provide access to the callchain of HVX callbacks
@ -379,6 +413,32 @@ public:
return onHVXCallbackChain;
}
public:
/**
* Notify all registered onShutdown callbacks that the GattClient is
* about to be shutdown and clear all GattClient state of the
* associated object.
*
* This function is meant to be overridden in the platform-specific
* sub-class. Nevertheless, the sub-class is only expected to reset its
* state and not the data held in GattClient members. This shall be achieved
* by a call to GattClient::reset() from the sub-class' reset()
* implementation.
*
* @return BLE_ERROR_NONE on success.
*/
virtual ble_error_t reset(void) {
/* Notify that the instance is about to shutdown */
shutdownCallChain.call(this);
shutdownCallChain.clear();
onDataReadCallbackChain.clear();
onDataWriteCallbackChain.clear();
onHVXCallbackChain.clear();
return BLE_ERROR_NONE;
}
protected:
GattClient() {
/* Empty */
@ -401,9 +461,10 @@ public:
}
protected:
ReadCallbackChain_t onDataReadCallbackChain;
WriteCallbackChain_t onDataWriteCallbackChain;
HVXCallbackChain_t onHVXCallbackChain;
ReadCallbackChain_t onDataReadCallbackChain;
WriteCallbackChain_t onDataWriteCallbackChain;
HVXCallbackChain_t onHVXCallbackChain;
GattClientShutdownCallbackChain_t shutdownCallChain;
private:
/* Disallow copy and assignment. */

@ -26,17 +26,19 @@
class GattServer {
public:
/* Event callback handlers. */
typedef FunctionPointerWithContext<unsigned> DataSentCallback_t;
typedef CallChainOfFunctionPointersWithContext<unsigned> DataSentCallbackChain_t;
typedef FunctionPointerWithContext<const GattWriteCallbackParams*> DataWrittenCallback_t;
typedef CallChainOfFunctionPointersWithContext<const GattWriteCallbackParams*> DataWrittenCallbackChain_t;
typedef CallChainOfFunctionPointersWithContext<const GattWriteCallbackParams*> DataWrittenCallbackChain_t;
typedef FunctionPointerWithContext<const GattReadCallbackParams*> DataReadCallback_t;
typedef CallChainOfFunctionPointersWithContext<const GattReadCallbackParams *> DataReadCallbackChain_t;
typedef FunctionPointerWithContext<const GattServer *> GattServerShutdownCallback_t;
typedef CallChainOfFunctionPointersWithContext<const GattServer *> GattServerShutdownCallbackChain_t;
typedef FunctionPointerWithContext<GattAttribute::Handle_t> EventCallback_t;
protected:
@ -254,9 +256,9 @@ public:
}
/**
* @brief get the callback chain called when the event DATA_EVENT is triggered.
* @brief get the callback chain called when the event DATA_EVENT is triggered.
*/
DataSentCallbackChain_t& onDataSent() {
DataSentCallbackChain_t& onDataSent() {
return dataSentCallChain;
}
@ -274,7 +276,7 @@ public:
*
* @Note: It is also possible to set up a callback into a member function of
* some object.
*
*
* @Note It is possible to unregister a callback using onDataWritten().detach(callback)
*/
void onDataWritten(const DataWrittenCallback_t& callback) {dataWrittenCallChain.add(callback);}
@ -286,9 +288,9 @@ public:
/**
* @brief provide access to the callchain of data written event callbacks
* It is possible to register callbacks using onDataWritten().add(callback);
* It is possible to unregister callbacks using onDataWritten().detach(callback)
* It is possible to unregister callbacks using onDataWritten().detach(callback)
* @return The data written event callbacks chain
*/
*/
DataWrittenCallbackChain_t& onDataWritten() {
return dataWrittenCallChain;
}
@ -335,13 +337,45 @@ public:
/**
* @brief provide access to the callchain of data read event callbacks
* It is possible to register callbacks using onDataRead().add(callback);
* It is possible to unregister callbacks using onDataRead().detach(callback)
* It is possible to unregister callbacks using onDataRead().detach(callback)
* @return The data read event callbacks chain
*/
DataReadCallbackChain_t& onDataRead() {
return dataReadCallChain;
}
/**
* Setup a callback to be invoked to notify the user application that the
* GattServer instance is about to shutdown (possibly as a result of a call
* to BLE::shutdown()).
*
* @Note: It is possible to chain together multiple onShutdown callbacks
* (potentially from different modules of an application) to be notified
* before the GattServer is shutdown.
*
* @Note: It is also possible to set up a callback into a member function of
* some object.
*
* @Note It is possible to unregister a callback using onShutdown().detach(callback)
*/
void onShutdown(const GattServerShutdownCallback_t& callback) {
shutdownCallChain.add(callback);
}
template <typename T>
void onShutdown(T *objPtr, void (T::*memberPtr)(void)) {
shutdownCallChain.add(objPtr, memberPtr);
}
/**
* @brief provide access to the callchain of shutdown event callbacks
* It is possible to register callbacks using onShutdown().add(callback);
* It is possible to unregister callbacks using onShutdown().detach(callback)
* @return The shutdown event callbacks chain
*/
GattServerShutdownCallbackChain_t& onShutdown() {
return shutdownCallChain;
}
/**
* Set up a callback for when notifications or indications are enabled for a
* characteristic on the local GATT server.
@ -396,17 +430,50 @@ protected:
dataSentCallChain.call(count);
}
public:
/**
* Notify all registered onShutdown callbacks that the GattServer is
* about to be shutdown and clear all GattServer state of the
* associated object.
*
* This function is meant to be overridden in the platform-specific
* sub-class. Nevertheless, the sub-class is only expected to reset its
* state and not the data held in GattServer members. This shall be achieved
* by a call to GattServer::reset() from the sub-class' reset()
* implementation.
*
* @return BLE_ERROR_NONE on success.
*/
virtual ble_error_t reset(void) {
/* Notify that the instance is about to shutdown */
shutdownCallChain.call(this);
shutdownCallChain.clear();
serviceCount = 0;
characteristicCount = 0;
dataSentCallChain.clear();
dataWrittenCallChain.clear();
dataReadCallChain.clear();
updatesEnabledCallback = NULL;
updatesDisabledCallback = NULL;
confirmationReceivedCallback = NULL;
return BLE_ERROR_NONE;
}
protected:
uint8_t serviceCount;
uint8_t characteristicCount;
private:
DataSentCallbackChain_t dataSentCallChain;
DataWrittenCallbackChain_t dataWrittenCallChain;
DataReadCallbackChain_t dataReadCallChain;
EventCallback_t updatesEnabledCallback;
EventCallback_t updatesDisabledCallback;
EventCallback_t confirmationReceivedCallback;
DataSentCallbackChain_t dataSentCallChain;
DataWrittenCallbackChain_t dataWrittenCallChain;
DataReadCallbackChain_t dataReadCallChain;
GattServerShutdownCallbackChain_t shutdownCallChain;
EventCallback_t updatesEnabledCallback;
EventCallback_t updatesDisabledCallback;
EventCallback_t confirmationReceivedCallback;
private:
/* Disallow copy and assignment. */

@ -20,6 +20,7 @@
#include <stdint.h>
#include "Gap.h"
#include "CallChainOfFunctionPointersWithContext.h"
class SecurityManager {
public:
@ -82,6 +83,9 @@ public:
typedef void (*LinkSecuredCallback_t)(Gap::Handle_t handle, SecurityMode_t securityMode);
typedef void (*PasskeyDisplayCallback_t)(Gap::Handle_t handle, const Passkey_t passkey);
typedef FunctionPointerWithContext<const SecurityManager *> SecurityManagerShutdownCallback_t;
typedef CallChainOfFunctionPointersWithContext<const SecurityManager *> SecurityManagerShutdownCallbackChain_t;
/*
* The following functions are meant to be overridden in the platform-specific sub-class.
*/
@ -161,6 +165,38 @@ public:
/* Event callback handlers. */
public:
/**
* Setup a callback to be invoked to notify the user application that the
* SecurityManager instance is about to shutdown (possibly as a result of a call
* to BLE::shutdown()).
*
* @Note: It is possible to chain together multiple onShutdown callbacks
* (potentially from different modules of an application) to be notified
* before the SecurityManager is shutdown.
*
* @Note: It is also possible to set up a callback into a member function of
* some object.
*
* @Note It is possible to unregister a callback using onShutdown().detach(callback)
*/
void onShutdown(const SecurityManagerShutdownCallback_t& callback) {
shutdownCallChain.add(callback);
}
template <typename T>
void onShutdown(T *objPtr, void (T::*memberPtr)(void)) {
shutdownCallChain.add(objPtr, memberPtr);
}
/**
* @brief provide access to the callchain of shutdown event callbacks
* It is possible to register callbacks using onShutdown().add(callback);
* It is possible to unregister callbacks using onShutdown().detach(callback)
* @return The shutdown event callbacks chain
*/
SecurityManagerShutdownCallbackChain_t& onShutdown() {
return shutdownCallChain;
}
/**
* To indicate that a security procedure for the link has started.
*/
@ -231,12 +267,43 @@ protected:
/* empty */
}
public:
/**
* Notify all registered onShutdown callbacks that the SecurityManager is
* about to be shutdown and clear all SecurityManager state of the
* associated object.
*
* This function is meant to be overridden in the platform-specific
* sub-class. Nevertheless, the sub-class is only expected to reset its
* state and not the data held in SecurityManager members. This shall be
* achieved by a call to SecurityManager::reset() from the sub-class'
* reset() implementation.
*
* @return BLE_ERROR_NONE on success.
*/
virtual ble_error_t reset(void) {
/* Notify that the instance is about to shutdown */
shutdownCallChain.call(this);
shutdownCallChain.clear();
securitySetupInitiatedCallback = NULL;
securitySetupCompletedCallback = NULL;
linkSecuredCallback = NULL;
securityContextStoredCallback = NULL;
passkeyDisplayCallback = NULL;
return BLE_ERROR_NONE;
}
protected:
SecuritySetupInitiatedCallback_t securitySetupInitiatedCallback;
SecuritySetupCompletedCallback_t securitySetupCompletedCallback;
LinkSecuredCallback_t linkSecuredCallback;
HandleSpecificEvent_t securityContextStoredCallback;
PasskeyDisplayCallback_t passkeyDisplayCallback;
private:
SecurityManagerShutdownCallbackChain_t shutdownCallChain;
};
#endif /*__SECURITY_MANAGER_H__*/

@ -132,6 +132,27 @@ public:
*/
virtual void onTermination(TerminationCallback_t callback) = 0;
/**
* Clear all ServiceDiscovery state of the associated object.
*
* This function is meant to be overridden in the platform-specific
* sub-class. Nevertheless, the sub-class is only expected to reset its
* state and not the data held in ServiceDiscovery members. This shall be
* achieved by a call to ServiceDiscovery::reset() from the sub-class'
* reset() implementation.
*
* @return BLE_ERROR_NONE on success.
*/
virtual ble_error_t reset(void) {
connHandle = 0;
matchingServiceUUID = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN);
serviceCallback = NULL;
matchingCharacteristicUUID = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN);
characteristicCallback = NULL;
return BLE_ERROR_NONE;
}
protected:
Gap::Handle_t connHandle; /**< Connection handle as provided by the SoftDevice. */
UUID matchingServiceUUID;

@ -49,62 +49,6 @@ enum {
BLE_UUID_GAP_CHARACTERISTIC_PPCP = 0x2A04, /**< Peripheral Preferred Connection Parameters Characteristic. */
};
/*! Bluetooth appearance values.
* @note Retrieved from http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml
*/
enum {
BLE_APPEARANCE_UNKNOWN = 0, /**< Unknown. */
BLE_APPEARANCE_GENERIC_PHONE = 64, /**< Generic Phone. */
BLE_APPEARANCE_GENERIC_COMPUTER = 128, /**< Generic Computer. */
BLE_APPEARANCE_GENERIC_WATCH = 192, /**< Generic Watch. */
BLE_APPEARANCE_WATCH_SPORTS_WATCH = 193, /**< Watch: Sports Watch. */
BLE_APPEARANCE_GENERIC_CLOCK = 256, /**< Generic Clock. */
BLE_APPEARANCE_GENERIC_DISPLAY = 320, /**< Generic Display. */
BLE_APPEARANCE_GENERIC_REMOTE_CONTROL = 384, /**< Generic Remote Control. */
BLE_APPEARANCE_GENERIC_EYE_GLASSES = 448, /**< Generic Eye-glasses. */
BLE_APPEARANCE_GENERIC_TAG = 512, /**< Generic Tag. */
BLE_APPEARANCE_GENERIC_KEYRING = 576, /**< Generic Keyring. */
BLE_APPEARANCE_GENERIC_MEDIA_PLAYER = 640, /**< Generic Media Player. */
BLE_APPEARANCE_GENERIC_BARCODE_SCANNER = 704, /**< Generic Barcode Scanner. */
BLE_APPEARANCE_GENERIC_THERMOMETER = 768, /**< Generic Thermometer. */
BLE_APPEARANCE_THERMOMETER_EAR = 769, /**< Thermometer: Ear. */
BLE_APPEARANCE_GENERIC_HEART_RATE_SENSOR = 832, /**< Generic Heart Rate Sensor. */
BLE_APPEARANCE_HEART_RATE_SENSOR_HEART_RATE_BELT = 833, /**< Heart Rate Sensor: Heart Rate Belt. */
BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE = 896, /**< Generic Blood Pressure. */
BLE_APPEARANCE_BLOOD_PRESSURE_ARM = 897, /**< Blood Pressure: Arm. */
BLE_APPEARANCE_BLOOD_PRESSURE_WRIST = 898, /**< Blood Pressure: Wrist. */
BLE_APPEARANCE_GENERIC_HID = 960, /**< Human Interface Device (HID). */
BLE_APPEARANCE_HID_KEYBOARD = 961, /**< Keyboard (HID subtype). */
BLE_APPEARANCE_HID_MOUSE = 962, /**< Mouse (HID subtype). */
BLE_APPEARANCE_HID_JOYSTICK = 963, /**< Joystick (HID subtype). */
BLE_APPEARANCE_HID_GAMEPAD = 964, /**< Gamepad (HID subtype). */
BLE_APPEARANCE_HID_DIGITIZERSUBTYPE = 965, /**< Digitizer Tablet (HID subtype). */
BLE_APPEARANCE_HID_CARD_READER = 966, /**< Card Reader (HID subtype). */
BLE_APPEARANCE_HID_DIGITAL_PEN = 967, /**< Digital Pen (HID subtype). */
BLE_APPEARANCE_HID_BARCODE = 968, /**< Barcode Scanner (HID subtype). */
BLE_APPEARANCE_GENERIC_GLUCOSE_METER = 1024, /**< Generic Glucose Meter. */
BLE_APPEARANCE_GENERIC_RUNNING_WALKING_SENSOR = 1088, /**< Generic Running Walking Sensor. */
BLE_APPEARANCE_RUNNING_WALKING_SENSOR_IN_SHOE = 1089, /**< Running Walking Sensor: In-Shoe. */
BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_SHOE = 1090, /**< Running Walking Sensor: On-Shoe. */
BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_HIP = 1091, /**< Running Walking Sensor: On-Hip. */
BLE_APPEARANCE_GENERIC_CYCLING = 1152, /**< Generic Cycling. */
BLE_APPEARANCE_CYCLING_CYCLING_COMPUTER = 1153, /**< Cycling: Cycling Computer. */
BLE_APPEARANCE_CYCLING_SPEED_SENSOR = 1154, /**< Cycling: Speed Sensor. */
BLE_APPEARANCE_CYCLING_CADENCE_SENSOR = 1155, /**< Cycling: Cadence Sensor. */
BLE_APPEARANCE_CYCLING_POWER_SENSOR = 1156, /**< Cycling: Power Sensor. */
BLE_APPEARANCE_CYCLING_SPEED_CADENCE_SENSOR = 1157, /**< Cycling: Speed and Cadence Sensor. */
BLE_APPEARANCE_GENERIC_PULSE_OXIMETER = 3136, /**< Generic Pulse Oximeter. */
BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP = 3137, /**< Fingertip (Pulse Oximeter subtype). */
BLE_APPEARANCE_PULSE_OXIMETER_WRIST_WORN = 3138, /**< Wrist Worn (Pulse Oximeter subtype). */
BLE_APPEARANCE_GENERIC_WEIGHT_SCALE = 3200, /**< Generic Weight Scale. */
BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS_ACT = 5184, /**< Generic Outdoor Sports Activity. */
BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_DISP = 5185, /**< Location Display Device (Outdoor Sports Activity subtype). */
BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_DISP = 5186, /**< Location and Navigation Display Device (Outdoor Sports Activity subtype). */
BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_POD = 5187, /**< Location Pod (Outdoor Sports Activity subtype). */
BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_POD = 5188, /**< Location and Navigation Pod (Outdoor Sports Activity subtype). */
};
/*! @brief Error codes for the BLE API. */
enum ble_error_t {
BLE_ERROR_NONE = 0, /**< No error. */
@ -119,6 +63,7 @@ enum ble_error_t {
BLE_ERROR_INITIALIZATION_INCOMPLETE = 9,
BLE_ERROR_ALREADY_INITIALIZED = 10,
BLE_ERROR_UNSPECIFIED = 11, /**< Unknown error. */
BLE_ERROR_INTERNAL_STACK_FAILURE = 12, /**< The platform-specific stack failed */
};
/** @brief Default MTU size. */

@ -1,6 +1,6 @@
{
"name": "ble",
"version": "2.1.14",
"version": "2.2.2",
"description": "The BLE module offers a high level abstraction for using Bluetooth Low Energy on multiple platforms.",
"keywords": [
"Bluetooth",
@ -26,7 +26,7 @@
"x-nucleo-idb0xa1": "^2.0.0"
},
"nrf51822": {
"ble-nrf51822": "^2.1.3"
"ble-nrf51822": "^2.2.8"
},
"cordio": {
"ble-wicentric": "~0.0.4"

@ -131,7 +131,6 @@ bool BLE::hasInitialized(void) const
ble_error_t BLE::shutdown(void)
{
clearAdvertisingPayload();
if (!transport) {
error("bad handle to underlying transport");
}

@ -31,29 +31,29 @@ DiscoveredCharacteristic::read(uint16_t offset) const
return gattc->read(connHandle, valueHandle, offset);
}
struct OneShotReadCallback {
static void launch(GattClient* client, Gap::Handle_t connHandle,
GattAttribute::Handle_t handle, const GattClient::ReadCallback_t& cb) {
struct OneShotReadCallback {
static void launch(GattClient* client, Gap::Handle_t connHandle,
GattAttribute::Handle_t handle, const GattClient::ReadCallback_t& cb) {
OneShotReadCallback* oneShot = new OneShotReadCallback(client, connHandle, handle, cb);
oneShot->attach();
// delete will be made when this callback is called
}
private:
OneShotReadCallback(GattClient* client, Gap::Handle_t connHandle,
GattAttribute::Handle_t handle, const GattClient::ReadCallback_t& cb) :
OneShotReadCallback(GattClient* client, Gap::Handle_t connHandle,
GattAttribute::Handle_t handle, const GattClient::ReadCallback_t& cb) :
_client(client),
_connHandle(connHandle),
_handle(handle),
_callback(cb) { }
_handle(handle),
_callback(cb) { }
void attach() {
void attach() {
_client->onDataRead(makeFunctionPointer(this, &OneShotReadCallback::call));
}
void call(const GattReadCallbackParams* params) {
// verifiy that it is the right characteristic on the right connection
if (params->connHandle == _connHandle && params->handle == _handle) {
if (params->connHandle == _connHandle && params->handle == _handle) {
_callback(params);
_client->onDataRead().detach(makeFunctionPointer(this, &OneShotReadCallback::call));
delete this;
@ -68,7 +68,7 @@ private:
ble_error_t DiscoveredCharacteristic::read(uint16_t offset, const GattClient::ReadCallback_t& onRead) const {
ble_error_t error = read(offset);
if (error) {
if (error) {
return error;
}
@ -105,29 +105,29 @@ DiscoveredCharacteristic::writeWoResponse(uint16_t length, const uint8_t *value)
return gattc->write(GattClient::GATT_OP_WRITE_CMD, connHandle, valueHandle, length, value);
}
struct OneShotWriteCallback {
static void launch(GattClient* client, Gap::Handle_t connHandle,
GattAttribute::Handle_t handle, const GattClient::WriteCallback_t& cb) {
struct OneShotWriteCallback {
static void launch(GattClient* client, Gap::Handle_t connHandle,
GattAttribute::Handle_t handle, const GattClient::WriteCallback_t& cb) {
OneShotWriteCallback* oneShot = new OneShotWriteCallback(client, connHandle, handle, cb);
oneShot->attach();
// delete will be made when this callback is called
}
private:
OneShotWriteCallback(GattClient* client, Gap::Handle_t connHandle,
GattAttribute::Handle_t handle, const GattClient::WriteCallback_t& cb) :
OneShotWriteCallback(GattClient* client, Gap::Handle_t connHandle,
GattAttribute::Handle_t handle, const GattClient::WriteCallback_t& cb) :
_client(client),
_connHandle(connHandle),
_handle(handle),
_callback(cb) { }
_handle(handle),
_callback(cb) { }
void attach() {
void attach() {
_client->onDataWritten(makeFunctionPointer(this, &OneShotWriteCallback::call));
}
void call(const GattWriteCallbackParams* params) {
// verifiy that it is the right characteristic on the right connection
if (params->connHandle == _connHandle && params->handle == _handle) {
if (params->connHandle == _connHandle && params->handle == _handle) {
_callback(params);
_client->onDataWritten().detach(makeFunctionPointer(this, &OneShotWriteCallback::call));
delete this;
@ -142,7 +142,7 @@ private:
ble_error_t DiscoveredCharacteristic::write(uint16_t length, const uint8_t *value, const GattClient::WriteCallback_t& onRead) const {
ble_error_t error = write(length, value);
if (error) {
if (error) {
return error;
}

Loading…
Cancel
Save