Skip to content

Instantly share code, notes, and snippets.

@ladislas
Created November 2, 2020 10:22
Show Gist options
  • Save ladislas/a93937dbaeca08ed60f04ce704a22721 to your computer and use it in GitHub Desktop.
Save ladislas/a93937dbaeca08ed60f04ce704a22721 to your computer and use it in GitHub Desktop.
Mbed BLE Example
// Leka - LekaOS
// Copyright 2020 APF France handicap
// SPDX-License-Identifier: Apache-2.0
#include "events/mbed_events.h"
#include "ble/BLE.h"
#include "ble/Gap.h"
#include "ble/services/HeartRateService.h"
#include "pretty_printer.h"
const static char DEVICE_NAME[] = "Heartrate";
static events::EventQueue event_queue(/* event count */ 32 * EVENTS_EVENT_SIZE);
class HeartrateDemo : ble::Gap::EventHandler
{
public:
HeartrateDemo(BLE &ble, events::EventQueue &event_queue)
: _ble(ble),
_event_queue(event_queue),
// _led1(LED1, 1),
_connected(false),
_hr_uuid(GattService::UUID_HEART_RATE_SERVICE),
_hr_counter(100),
_hr_service(ble, _hr_counter, HeartRateService::LOCATION_FINGER),
_adv_data_builder(_adv_buffer)
{
}
void start()
{
_ble.gap().setEventHandler(this);
_ble.init(this, &HeartrateDemo::on_init_complete);
// _event_queue.call_every(500ms, this, &HeartrateDemo::blink);
_event_queue.call_every(1000ms, this, &HeartrateDemo::update_sensor_value);
// _event_queue.dispatch_forever();
// printf("dispatch_forever\n");
}
private:
/** Callback triggered when the ble initialization process has finished */
void on_init_complete(BLE::InitializationCompleteCallbackContext *params)
{
if (params->error != BLE_ERROR_NONE) {
printf("Ble initialization failed.");
return;
}
print_mac_address();
start_advertising();
}
void start_advertising()
{
/* Create advertising parameters and payload */
ble::AdvertisingParameters adv_parameters(ble::advertising_type_t::CONNECTABLE_UNDIRECTED,
ble::adv_interval_t(ble::millisecond_t(1000)));
_adv_data_builder.setFlags();
_adv_data_builder.setAppearance(ble::adv_data_appearance_t::GENERIC_HEART_RATE_SENSOR);
_adv_data_builder.setLocalServiceList(mbed::make_Span(&_hr_uuid, 1));
_adv_data_builder.setName(DEVICE_NAME);
/* Setup advertising */
ble_error_t error = _ble.gap().setAdvertisingParameters(ble::LEGACY_ADVERTISING_HANDLE, adv_parameters);
if (error) {
printf("_ble.gap().setAdvertisingParameters() failed\r\n");
return;
}
error =
_ble.gap().setAdvertisingPayload(ble::LEGACY_ADVERTISING_HANDLE, _adv_data_builder.getAdvertisingData());
if (error) {
printf("_ble.gap().setAdvertisingPayload() failed\r\n");
return;
}
/* Start advertising */
error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
if (error) {
printf("_ble.gap().startAdvertising() failed\r\n");
return;
}
}
void update_sensor_value()
{
if (_connected) {
// Do blocking calls or whatever is necessary for sensor polling.
// In our case, we simply update the HRM measurement.
_hr_counter++;
// 100 <= HRM bps <=175
if (_hr_counter == 175) {
_hr_counter = 100;
}
_hr_service.updateHeartRate(_hr_counter);
}
}
// void blink(void) { _led1 = !_led1; }
private:
/* Event handler */
void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &)
{
_ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
_connected = false;
}
virtual void onConnectionComplete(const ble::ConnectionCompleteEvent &event)
{
if (event.getStatus() == BLE_ERROR_NONE) {
_connected = true;
}
}
private:
BLE &_ble;
events::EventQueue &_event_queue;
// DigitalOut _led1;
bool _connected;
UUID _hr_uuid;
uint8_t _hr_counter;
HeartRateService _hr_service;
uint8_t _adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE];
ble::AdvertisingDataBuilder _adv_data_builder;
};
// Leka - LekaOS
// Copyright 2020 APF France handicap
// SPDX-License-Identifier: Apache-2.0
#include <mbed.h>
#include "LKBLE.h"
Thread thread_ble_event_queue;
void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context)
{
event_queue.call(Callback<void()>(&context->ble, &BLE::processEvents));
}
int main()
{
BLE &ble = BLE::Instance();
ble.onEventsToProcess(schedule_ble_events);
HeartrateDemo demo(ble, event_queue);
demo.start();
thread_ble_event_queue.start(callback(&event_queue, &EventQueue::dispatch_forever));
while (true) {
rtos::ThisThread::sleep_for(5s);
}
return 0;
}
// Leka - LekaOS
// Copyright 2020 APF France handicap
// SPDX-License-Identifier: Apache-2.0
#ifndef _LEKA_OS_LIB_BLE_PRETTY_PRINTER_H_
#define _LEKA_OS_LIB_BLE_PRETTY_PRINTER_H_
#include "ble/BLE.h"
inline void print_error(ble_error_t error, const char *msg)
{
printf("%s: ", msg);
switch (error) {
case BLE_ERROR_NONE:
printf("BLE_ERROR_NONE: No error");
break;
case BLE_ERROR_BUFFER_OVERFLOW:
printf(
"BLE_ERROR_BUFFER_OVERFLOW: The requested action would cause a buffer overflow and has been aborted");
break;
case BLE_ERROR_NOT_IMPLEMENTED:
printf(
"BLE_ERROR_NOT_IMPLEMENTED: Requested a feature that isn't yet implement or isn't supported by the "
"target HW");
break;
case BLE_ERROR_PARAM_OUT_OF_RANGE:
printf("BLE_ERROR_PARAM_OUT_OF_RANGE: One of the supplied parameters is outside the valid range");
break;
case BLE_ERROR_INVALID_PARAM:
printf("BLE_ERROR_INVALID_PARAM: One of the supplied parameters is invalid");
break;
case BLE_STACK_BUSY:
printf("BLE_STACK_BUSY: The stack is busy");
break;
case BLE_ERROR_INVALID_STATE:
printf("BLE_ERROR_INVALID_STATE: Invalid state");
break;
case BLE_ERROR_NO_MEM:
printf("BLE_ERROR_NO_MEM: Out of Memory");
break;
case BLE_ERROR_OPERATION_NOT_PERMITTED:
printf("BLE_ERROR_OPERATION_NOT_PERMITTED");
break;
case BLE_ERROR_INITIALIZATION_INCOMPLETE:
printf("BLE_ERROR_INITIALIZATION_INCOMPLETE");
break;
case BLE_ERROR_ALREADY_INITIALIZED:
printf("BLE_ERROR_ALREADY_INITIALIZED");
break;
case BLE_ERROR_UNSPECIFIED:
printf("BLE_ERROR_UNSPECIFIED: Unknown error");
break;
case BLE_ERROR_INTERNAL_STACK_FAILURE:
printf("BLE_ERROR_INTERNAL_STACK_FAILURE: internal stack failure");
break;
case BLE_ERROR_NOT_FOUND:
printf("BLE_ERROR_NOT_FOUND");
break;
default:
printf("Unknown error");
}
printf("\r\n");
}
/** print device address to the terminal */
inline void print_address(const ble::address_t &addr)
{
printf("%02x:%02x:%02x:%02x:%02x:%02x\r\n", addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
}
inline void print_mac_address()
{
/* Print out device MAC address to the console*/
ble::own_address_type_t addr_type;
ble::address_t address;
BLE::Instance().gap().getAddress(addr_type, address);
printf("DEVICE MAC ADDRESS: ");
print_address(address);
}
inline const char *phy_to_string(ble::phy_t phy)
{
switch (phy.value()) {
case ble::phy_t::LE_1M:
return "LE 1M";
case ble::phy_t::LE_2M:
return "LE 2M";
case ble::phy_t::LE_CODED:
return "LE coded";
default:
return "invalid PHY";
}
}
#endif // _LEKA_OS_LIB_BLE_PRETTY_PRINTER_H_
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment