@ -202,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 updateFieldPayload ( 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, either add to field or replace
return updateFieldPayload ( advDataType , payload , len , field ) ;
} else {
// field doesn't exists, return an error
return BLE_ERROR_UNSPECIFIED ;
}
return BLE_ERROR_UNSPECIFIED ;
}
/**
@ -475,6 +389,85 @@ 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 .
* Returns BLE_ERROR_NONE on success .
*/
ble_error_t updateFieldPayload ( 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 : {
// 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 ;
}
}
return result ;
}
uint8_t _payload [ GAP_ADVERTISING_DATA_MAX_PAYLOAD ] ;
uint8_t _payloadLen ;
uint16_t _appearance ;