Skip to content

Commit

Permalink
Release 0.4.4
Browse files Browse the repository at this point in the history
=============

This is a minor release.

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

* Add a new helper API: Gap::updateAdvertisingPayload(). This helps update a
  particular AD field in the advertisement payload.

* Deprecate GattClient::onDataWrite() in favour of onDataWritten().

* fix #64. clearScanResponse() should work properly now.

* fix #60: if scanning parameters are changed while scanning is active, their
  new values are propagated to the underlying stack right-away.

* Introducing an initial implementation for Google's Eddystone beacon service.
  See https://github.com/google/eddystone.

* Updated module.json because URL of the host repo has changed to
  "[email protected]:ARMmbed/ble.git".

Bugfixes
~~~~~~~~

none.
  • Loading branch information
Rohit Grover committed Aug 7, 2015
2 parents 9532157 + 00e7677 commit 1725337
Show file tree
Hide file tree
Showing 10 changed files with 698 additions and 29 deletions.
88 changes: 75 additions & 13 deletions ble/Gap.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,16 +127,10 @@ class Gap {
};

static const uint16_t UNIT_1_25_MS = 1250; /**< Number of microseconds in 1.25 milliseconds. */
static const uint16_t UNIT_0_625_MS = 625; /**< Number of microseconds in 0.625 milliseconds. */
static uint16_t MSEC_TO_GAP_DURATION_UNITS(uint32_t durationInMillis) {
return (durationInMillis * 1000) / UNIT_1_25_MS;
}
static uint16_t MSEC_TO_ADVERTISEMENT_DURATION_UNITS(uint32_t durationInMillis) {
return (durationInMillis * 1000) / UNIT_0_625_MS;
}
static uint16_t ADVERTISEMENT_DURATION_UNITS_TO_MS(uint16_t gapUnits) {
return (gapUnits * UNIT_0_625_MS) / 1000;
}


typedef void (*TimeoutEventCallback_t)(TimeoutSource_t source);
typedef void (*ConnectionEventCallback_t)(const ConnectionCallbackParams_t *params);
Expand Down Expand Up @@ -416,6 +410,7 @@ class Gap {
protected:
/* Override the following in the underlying adaptation layer to provide the functionality of scanning. */
virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams) {
(void)scanningParams;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porter(s): override this API if this capability is supported. */
}

Expand Down Expand Up @@ -470,7 +465,7 @@ class Gap {
} else if (interval < getMinAdvertisingInterval()) {
interval = getMinAdvertisingInterval();
}
_advParams.setInterval(MSEC_TO_ADVERTISEMENT_DURATION_UNITS(interval));
_advParams.setInterval(GapAdvertisingParams::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(interval));
}

/**
Expand Down Expand Up @@ -550,8 +545,8 @@ class Gap {
* small.
*
* @param app
* The max transmit power to be used by the controller. This is
* only a hint.
* The max transmit power to be used by the controller (in dBm).
* This is only a hint.
*/
ble_error_t accumulateAdvertisingPayloadTxPower(int8_t power) {
ble_error_t rc;
Expand Down Expand Up @@ -585,6 +580,33 @@ class Gap {
return setAdvertisingData();
}

/**
* 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.
*
* @param[in] type The ADV type field which describes the variable length data.
* @param[in] data data bytes.
* @param[in] len length of data.
*
* @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; else an appropriate error.
*/
ble_error_t updateAdvertisingPayload(GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len) {
if (type == GapAdvertisingData::COMPLETE_LOCAL_NAME) {
setDeviceName(data);
}

ble_error_t rc;
if ((rc = _advPayload.updateData(type, data, len)) != BLE_ERROR_NONE) {
return rc;
}

return setAdvertisingData();
}

/**
* Setup a particular, user-constructed advertisement payload for the
* underlying stack. It would be uncommon for this API to be used directly;
Expand Down Expand Up @@ -704,9 +726,22 @@ class Gap {
*
* Once the scanning parameters have been configured, scanning can be
* enabled by using startScan().
*
* If scanning is already active, the updated value of scanWindow will be
* propagated to the underlying BLE stack.
*/
ble_error_t setScanWindow(uint16_t window) {
return _scanningParams.setWindow(window);
ble_error_t rc;
if ((rc = _scanningParams.setWindow(window)) != BLE_ERROR_NONE) {
return rc;
}

/* If scanning is already active, propagate the new setting to the stack. */
if (scanningActive) {
return startRadioScan(_scanningParams);
}

return BLE_ERROR_NONE;
}

/**
Expand All @@ -716,9 +751,22 @@ class Gap {
*
* Once the scanning parameters have been configured, scanning can be
* enabled by using startScan().
*
* If scanning is already active, the updated value of scanTimeout will be
* propagated to the underlying BLE stack.
*/
ble_error_t setScanTimeout(uint16_t timeout) {
return _scanningParams.setTimeout(timeout);
ble_error_t rc;
if ((rc = _scanningParams.setTimeout(timeout)) != BLE_ERROR_NONE) {
return rc;
}

/* If scanning is already active, propagate the new settings to the stack. */
if (scanningActive) {
return startRadioScan(_scanningParams);
}

return BLE_ERROR_NONE;
}

/**
Expand All @@ -729,9 +777,19 @@ class Gap {
*
* Once the scanning parameters have been configured, scanning can be
* enabled by using startScan().
*
* If scanning is already in progress, then active-scanning will be enabled
* for the underlying BLE stack.
*/
void setActiveScanning(bool activeScanning) {
ble_error_t setActiveScanning(bool activeScanning) {
_scanningParams.setActiveScanning(activeScanning);

/* If scanning is already active, propagate the new settings to the stack. */
if (scanningActive) {
return startRadioScan(_scanningParams);
}

return BLE_ERROR_NONE;
}

/**
Expand All @@ -747,6 +805,7 @@ class Gap {
ble_error_t err = BLE_ERROR_NONE;
if (callback) {
if ((err = startRadioScan(_scanningParams)) == BLE_ERROR_NONE) {
scanningActive = true;
onAdvertisementReport.attach(callback);
}
}
Expand All @@ -762,6 +821,7 @@ class Gap {
ble_error_t err = BLE_ERROR_NONE;
if (object && callbackMember) {
if ((err = startRadioScan(_scanningParams)) == BLE_ERROR_NONE) {
scanningActive = true;
onAdvertisementReport.attach(object, callbackMember);
}
}
Expand Down Expand Up @@ -894,6 +954,7 @@ class Gap {
_scanningParams(),
_scanResponse(),
state(),
scanningActive(false),
timeoutCallback(NULL),
connectionCallback(NULL),
disconnectionCallback(NULL),
Expand Down Expand Up @@ -957,6 +1018,7 @@ class Gap {
GapAdvertisingData _scanResponse;

GapState_t state;
bool scanningActive;

protected:
TimeoutEventCallback_t timeoutCallback;
Expand Down
45 changes: 43 additions & 2 deletions ble/GapAdvertisingData.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ class GapAdvertisingData
* advertising buffer to overflow, else BLE_ERROR_NONE.
*/
ble_error_t addData(DataType advDataType, const uint8_t *payload, uint8_t len)
{
{
/* ToDo: Check if an AD type already exists and if the existing */
/* value is exclusive or not (flags, etc.) */

Expand All @@ -233,6 +233,47 @@ class GapAdvertisingData
return BLE_ERROR_NONE;
}

/**
* 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.
*
* @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.
*/
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;
}

byteIndex += (currentADV->len + 1); /* advance by len+1; '+1' is needed to span the len field itself. */
}

return BLE_ERROR_UNSPECIFIED;
}

/**
* Helper function to add APPEARANCE data to the advertising payload
*
Expand Down Expand Up @@ -287,7 +328,7 @@ class GapAdvertisingData
* Returns a pointer to the the current payload
*/
const uint8_t *getPayload(void) const {
return (_payloadLen > 0) ? _payload : NULL;
return _payload;
}

/**
Expand Down
10 changes: 9 additions & 1 deletion ble/GapAdvertisingParams.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,16 @@ class GapAdvertisingParams {
}
}

static const uint16_t UNIT_0_625_MS = 625; /**< Number of microseconds in 0.625 milliseconds. */
static uint16_t MSEC_TO_ADVERTISEMENT_DURATION_UNITS(uint32_t durationInMillis) {
return (durationInMillis * 1000) / UNIT_0_625_MS;
}
static uint16_t ADVERTISEMENT_DURATION_UNITS_TO_MS(uint16_t gapUnits) {
return (gapUnits * UNIT_0_625_MS) / 1000;
}

AdvertisingType_t getAdvertisingType(void) const {return _advType; }
uint16_t getInterval(void) const {return _interval;}
uint16_t getInterval(void) const {return ADVERTISEMENT_DURATION_UNITS_TO_MS(_interval);}
uint16_t getTimeout(void) const {return _timeout; }

void setAdvertisingType(AdvertisingType_t newAdvType) {_advType = newAdvType; }
Expand Down
5 changes: 5 additions & 0 deletions ble/GapScanningParams.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ class GapScanningParams {
uint16_t timeout = 0,
bool activeScanning = false);

static const uint16_t UNIT_0_625_MS = 625; /**< Number of microseconds in 0.625 milliseconds. */
static uint16_t MSEC_TO_SCAN_DURATION_UNITS(uint32_t durationInMillis) {
return (durationInMillis * 1000) / UNIT_0_625_MS;
}

ble_error_t setInterval(uint16_t newIntervalInMS);

ble_error_t setWindow(uint16_t newWindowInMS);
Expand Down
13 changes: 12 additions & 1 deletion ble/GattClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,10 +251,21 @@ class GattClient {
* Setup a callback for write response events.
* @Note: write commands (issued using writeWoResponse) don't generate a response.
*/
void onDataWrite(WriteCallback_t callback) {
void onDataWritten(WriteCallback_t callback) {
onDataWriteCallback = callback;
}

/**
* Setup a callback for write response events.
* @Note: write commands (issued using writeWoResponse) don't generate a response.
*
* @note: This API is now *deprecated* and will be dropped in the future.
* Please use onDataWritten() instead.
*/
void onDataWrite(WriteCallback_t callback) {
onDataWritten(callback);
}

/**
* Setup callback for when serviceDiscovery terminates.
*/
Expand Down
2 changes: 1 addition & 1 deletion ble/services/DeviceInformationService.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class DeviceInformationService {
(softwareRevision != NULL) ? strlen(softwareRevision) : 0, /* maxLength */
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ)
{
static bool serviceAdded = false; /* We should only ever need to add the heart rate service once. */
static bool serviceAdded = false; /* We should only ever need to add the information service once. */
if (serviceAdded) {
return;
}
Expand Down
Loading

0 comments on commit 1725337

Please sign in to comment.