-
-
Save pan-/585af73a8fd0ff236b9897c0432d4ef0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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