Skip to content

Instantly share code, notes, and snippets.

@pan-
Created June 25, 2018 16:16
Show Gist options
  • Save pan-/585af73a8fd0ff236b9897c0432d4ef0 to your computer and use it in GitHub Desktop.
Save pan-/585af73a8fd0ff236b9897c0432d4ef0 to your computer and use it in GitHub Desktop.
#include <events/mbed_events.h>
#include <mbed.h>
#include "ble/BLE.h"
#include "ble/DiscoveredCharacteristic.h"
#include "ble/DiscoveredService.h"
#define UUID_HRM_SERVICE 0x180d
#define UUID_HRM_CHARACTERISTIC 0x2a37
#define UUID_HRM_DESCRIPTOR 0x2902
DigitalOut alivenessLED(LED1, 1);
static DiscoveredCharacteristic hrmCharacteristic;
static const char PEER_NAME[] = "RBL-BLE";
uint16_t _discovered_UUID = 0x0000;
GattAttribute::Handle_t _CCCD_handle(0);
uint8_t reed_state;
void discoveryTerminationCallback(Gap::Handle_t connectionHandle);
void look_for_Descriptors();
void stop();
void onUpdatesCallback(const GattHVXCallbackParams *updates);
void serviceDiscoveryCallback(const DiscoveredService *service);
void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP);
void characteristicDescriptorDiscoveryCallback(
const CharacteristicDescriptorDiscovery::DiscoveryCallbackParams_t *charParams
);
void descriptorDiscoveryTerminationCallback(
const CharacteristicDescriptorDiscovery::TerminationCallbackParams_t *termParams
);
void write_cccd();
static bool flag_connected = false;
static bool flag_hrm_char_found = false;
static EventQueue eventQueue(/* event count */ 16 * EVENTS_EVENT_SIZE);
void periodicCallback(void) {
if(flag_connected){
alivenessLED = !alivenessLED; /* Do blinky on LED1 while we're waiting for BLE events */
}
}
void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) {
// parse the advertising payload, looking for data type COMPLETE_LOCAL_NAME
// The advertising payload is a collection of key/value records where
// byte 0: length of the record excluding this byte
// byte 1: The key, it is the type of the data
// byte [2..N] The value. N is equal to byte0 - 1
uint32_t err_code;
for (uint8_t i = 0; i < params->advertisingDataLen; ++i) {
const uint8_t record_length = params->advertisingData[i];
if (record_length == 0) {
continue;
}
const uint8_t type = params->advertisingData[i + 1];
const uint8_t* value = params->advertisingData + i + 2;
const uint8_t value_length = record_length - 1;
if(type == GapAdvertisingData::COMPLETE_LOCAL_NAME) {
if ((value_length == sizeof(PEER_NAME)) && (memcmp(value, PEER_NAME, value_length) == 0)) {
printf(
"adv peerAddr[%02x %02x %02x %02x %02x %02x] rssi %d, isScanResponse %u, AdvertisementType %u\r\n",
params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2], //peerAddr: BLE address of the device that has advertised the packet.
params->peerAddr[1], params->peerAddr[0], params->rssi, params->isScanResponse, params->type
);
err_code = BLE::Instance().gap().connect(params->peerAddr, Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL);
if(err_code == BLE_ERROR_NOT_IMPLEMENTED){
printf("BLE_ERROR_NOT_IMPLEMENTED\r\n");
}else if(err_code == 0){
wait_ms(100);
printf("success\r\n");
}
break;
}
}
i += record_length;
}
}
void connectionCallback(const Gap::ConnectionCallbackParams_t *params) {
flag_connected = true;
printf("connected to Peer, connection handle is: %d\r\n", params->handle);
if (params->role == Gap::CENTRAL) {
GattClient& client = BLE::Instance().gattClient();
client.onServiceDiscoveryTermination(discoveryTerminationCallback);
client.launchServiceDiscovery(
params->handle,
serviceDiscoveryCallback,
characteristicDiscoveryCallback
);
}
}
void serviceDiscoveryCallback(const DiscoveredService *service) {
printf("Service Discovery Callback\r\n");
if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) {
printf(
"Service UUID-%x attrs[%u %u]\r\n",
service->getUUID().getShortUUID(),
service->getStartHandle(),
service->getEndHandle()
);
} else {
printf("Service UUID-");
const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID();
for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
printf("%02x", longUUIDBytes[i]);
}
printf(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle());
}
}
void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP) {
printf(" \r\n");
printf("Characteristic Discovery Callback\r\n");
printf(
"Char UUID[%x] valueAttr_Handle[%u] broadcast[%x] notification[%u] readable[%u]\r\n",
characteristicP->getUUID().getShortUUID(),
characteristicP->getValueHandle(),
(uint8_t)characteristicP->getProperties().broadcast(),
(uint8_t)characteristicP->getProperties().notify(),
(uint8_t)characteristicP->getProperties().read()
);
/* !ALERT! Alter this filter to suit your device. */
if (characteristicP->getUUID().getShortUUID() == UUID_HRM_CHARACTERISTIC ) {
hrmCharacteristic = *characteristicP;
flag_hrm_char_found = true; //flag true so look_for_Descriptors gets invoked
}
}
void discoveryTerminationCallback(Gap::Handle_t connectionHandle) {
printf("terminated Service Discovery for handle %u\r\n", connectionHandle);
//printf("trigger update\n");
if(flag_hrm_char_found == true && hrmCharacteristic.getProperties().notify()){
printf("hrm Char found with notifications enabled\r\n");
eventQueue.call(look_for_Descriptors);
}else if(flag_hrm_char_found == true && !hrmCharacteristic.getProperties().notify()){
printf("hrm Char found with notifications disabled\r\n");
}
}
void look_for_Descriptors(){
printf(" \n");
BLE &ble = BLE::Instance();
printf(
"start looking for Descriptors of characteristic %d, range [%d, %d] now\r\n",
hrmCharacteristic.getValueHandle(),
hrmCharacteristic.getValueHandle() + 1,
hrmCharacteristic.getLastHandle()
);
ble.gattClient().discoverCharacteristicDescriptors(
hrmCharacteristic,
characteristicDescriptorDiscoveryCallback,
descriptorDiscoveryTerminationCallback
);
}
void characteristicDescriptorDiscoveryCallback(
const CharacteristicDescriptorDiscovery::DiscoveryCallbackParams_t *charParams
) {
printf("descriptor found with:\n");
printf("connection_handle[%u] UUID[%X] attribute_Handle[%u]\r\n",
charParams->descriptor.getConnectionHandle(),
charParams->descriptor.getUUID().getShortUUID(),
charParams->descriptor.getAttributeHandle()
);
// no reason to pursue the descriptor discovery at this point
// request to terminate it then get notified in the termination callback
if (charParams->descriptor.getUUID().getLen() != UUID::LENGTH_OF_LONG_UUID &&
charParams->descriptor.getUUID().getShortUUID() == BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG
) {
_discovered_UUID = charParams->descriptor.getUUID().getShortUUID();
_CCCD_handle = charParams->descriptor.getAttributeHandle();
GattClient& client = BLE::Instance().gattClient();
client.terminateCharacteristicDescriptorDiscovery(hrmCharacteristic);
printf("CCCD found; explicit termination of descriptors discovery\r\n");
}
}
void descriptorDiscoveryTerminationCallback(
const CharacteristicDescriptorDiscovery::TerminationCallbackParams_t *termParams
) {
if (termParams->error_code || _discovered_UUID != BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG) {
printf("no cccd found\r\n");
return;
}
printf("descriptorDiscovery terminated without errors\r\n");
printf("cccd with handle [%u] found!\r\n", _CCCD_handle);
eventQueue.call(write_cccd);
}
void write_cccd() {
// cccd are 16 bit bit long; indication flag is on bit 2
uint16_t cccd_value = BLE_HVX_NOTIFICATION;
GattClient& client = BLE::Instance().gattClient();
ble_error_t err = client.write(
GattClient::GATT_OP_WRITE_REQ,
hrmCharacteristic.getConnectionHandle(),
_CCCD_handle,
sizeof(cccd_value),
(uint8_t*) &cccd_value
);
if(err == 0){
printf("cccd update sent successful\r\n");
client.onHVX(onUpdatesCallback);
}else{
printf("error updating: error_code [%u]\n", err);
}
}
void onDataWrittenCallback(const GattWriteCallbackParams* params) {
printf(
"Attribute written by client: connection = %d, handle = %d, status = %d, error code = %d\r\n",
params->connHandle,
params->handle,
params->status,
params->error_code
);
}
void onUpdatesCallback(const GattHVXCallbackParams *updates){
printf("update received: handle %u\r\n", updates->handle);
if (updates->handle == hrmCharacteristic.getValueHandle()) {
const uint8_t *p_data = updates->data;
printf(
"updates received: connHandle: %u, attrHandle: %u, Type: %x, Data: ",
updates->connHandle,
updates->handle,
updates->type
);
for (unsigned index = 0; index < updates->len; index++) {
printf("%02x ", updates->data[index]);
}
printf("\r\n");
}
}
void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *) {
flag_connected = false;
printf("disconnected\r\n");
stop(); //detach hvx callback handler and reset flags
/* Start scanning and try to connect again */
BLE::Instance().gap().startScan(advertisementCallback);
}
void onBleInitError(BLE &ble, ble_error_t error)
{
/* Initialization error handling should go here */
printf(" \r\n");
printf("ble init error\r\n");
printf(" \r\n");
}
void printMacAddress()
{
/* Print out device MAC address to the console*/
Gap::AddressType_t addr_type;
Gap::Address_t address;
BLE::Instance().gap().getAddress(&addr_type, address);
printf("DEVICE MAC ADDRESS: ");
for (int i = 5; i >= 1; i--){
printf("%02x:", address[i]);
}
printf("%02x\r\n", address[0]);
}
void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
{
BLE& ble = params->ble;
ble_error_t error = params->error;
if (error != BLE_ERROR_NONE) {
/* In case of error, forward the error handling to onBleInitError */
onBleInitError(ble, error);
return;
}
/* Ensure that it is the default instance of BLE */
if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
return;
}
ble.gap().onDisconnection(disconnectionCallback);
ble.gap().onConnection(connectionCallback);
ble.gattClient().onDataWritten(onDataWrittenCallback);
//ble.gattClient().onDataWrite(triggerRead);
// scan interval: 400ms and scan window: 400ms.
// Every 400ms the device will scan for 400ms
// This means that the device will scan continuously.
ble.gap().setScanParams(400, 400);
ble.gap().startScan(advertisementCallback);
printMacAddress();
}
void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
BLE &ble = BLE::Instance();
eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
}
void stop(){
printf("stop\r\n");
BLE &ble = BLE::Instance();
ble.gattClient().onHVX().detach(onUpdatesCallback);
flag_hrm_char_found = false;
}
int main()
{
eventQueue.call_every(500, periodicCallback); //Calls an event on the queue periodically
BLE &ble = BLE::Instance();
ble.onEventsToProcess(scheduleBleEventsProcessing);
ble.init(bleInitComplete);
eventQueue.dispatch_forever();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment