BLE GAP Button example
This example is a fork of the following mbed-os example:
https://developer.mbed.org/teams/mbed-os-examples/code/mbed-os-example-ble-GAPButton/
Please read the documentation in this page.
Diff: source/main.cpp
- Revision:
- 1:7f4e41bacb3c
- Parent:
- 0:8f898b781de2
- Child:
- 2:e532bbe3fd8e
--- a/source/main.cpp Tue Jul 26 14:42:20 2016 +0100 +++ b/source/main.cpp Thu Jul 28 23:14:40 2016 +0100 @@ -1,198 +1,198 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <mbed-events/events.h> -#include <mbed.h> -#include "ble/BLE.h" - -DigitalOut led1(LED1, 1); -InterruptIn button(BUTTON1); -uint8_t cnt; - -// Change your device name below -const char DEVICE_NAME[] = "GAPButton"; - -/* We can arbiturarily choose the GAPButton service UUID to be 0xAA00 - * as long as it does not overlap with the UUIDs defined here: - * https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx */ -#define GAPButtonUUID 0xAA00 -const uint16_t uuid16_list[] = {GAPButtonUUID}; - -static EventQueue eventQueue( - /* event count */ 16 * /* event size */ 32 -); - -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 faillure"); - break; - } - printf("\r\n"); -} - -void updatePayload(void) -{ - // Update the count in the SERVICE_DATA field of the advertising payload - uint8_t service_data[3]; - service_data[0] = GAPButtonUUID & 0xff; - service_data[1] = GAPButtonUUID >> 8; - service_data[2] = cnt; // Put the button click count in the third byte - ble_error_t err = BLE::Instance().gap().updateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, (uint8_t *)service_data, sizeof(service_data)); - if (err != BLE_ERROR_NONE) { - print_error(err, "Updating payload failed"); - } -} - -void buttonPressedCallback(void) -{ - ++cnt; - - // Calling BLE api in interrupt context may cause race conditions - // Using mbed-events to schedule calls to BLE api for safety - eventQueue.post(updatePayload); -} - -void blinkCallback(void) -{ - led1 = !led1; -} - -void bleInitComplete(BLE::InitializationCompleteCallbackContext *context) -{ - BLE& ble = context->ble; - ble_error_t err = context->error; - - if (err != BLE_ERROR_NONE) { - print_error(err, "BLE initialisation failed"); - return; - } - - // Set up the advertising flags. Note: not all combination of flags are valid - // BREDR_NOT_SUPPORTED: Device does not support Basic Rate or Enchanced Data Rate, It is Low Energy only. - // LE_GENERAL_DISCOVERABLE: Peripheral device is discoverable at any moment - err = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); - if (err != BLE_ERROR_NONE) { - print_error(err, "Setting GAP flags failed"); - return; - } - - // Put the device name in the advertising payload - err = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); - if (err != BLE_ERROR_NONE) { - print_error(err, "Setting device name failed"); - return; - } - - err = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); - if (err != BLE_ERROR_NONE) { - print_error(err, "Setting service UUID failed"); - return; - } - - // The Service Data data type consists of a service UUID with the data associated with that service. - // We will encode the number of button clicks in the Service Data field - // First two bytes of SERVICE_DATA field should contain the UUID of the service - uint8_t service_data[3]; - service_data[0] = GAPButtonUUID & 0xff; - service_data[1] = GAPButtonUUID >> 8; - service_data[2] = cnt; // Put the button click count in the third byte - err = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, (uint8_t *)service_data, sizeof(service_data)); - if (err != BLE_ERROR_NONE) { - print_error(err, "Setting service data failed"); - return; - } - - // It is not connectable as we are just boardcasting - ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED); - - // Send out the advertising payload every 1000ms - ble.gap().setAdvertisingInterval(1000); - - err = ble.gap().startAdvertising(); - if (err != BLE_ERROR_NONE) { - print_error(err, "Sart advertising failed"); - return; - } -} - -void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) { - BLE &ble = BLE::Instance(); - eventQueue.post(Callback<void()>(&ble, &BLE::processEvents)); -} - -int main() -{ - cnt = 0; - - BLE &ble = BLE::Instance(); - ble.onEventsToProcess(scheduleBleEventsProcessing); - ble_error_t err = ble.init(bleInitComplete); - if (err != BLE_ERROR_NONE) { - print_error(err, "BLE initialisation failed"); - return 0; - } - - // Blink LED every 500 ms to indicate system aliveness - eventQueue.post_every(blinkCallback, 500); - - // Register function to be called when button is released - button.rise(buttonPressedCallback); - - while (true) { - eventQueue.dispatch(); - } - - return 0; -} +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <mbed-events/events.h> +#include <mbed.h> +#include "ble/BLE.h" + +DigitalOut led1(LED1, 1); +InterruptIn button(BUTTON1); +uint8_t cnt; + +// Change your device name below +const char DEVICE_NAME[] = "GAPButton"; + +/* We can arbiturarily choose the GAPButton service UUID to be 0xAA00 + * as long as it does not overlap with the UUIDs defined here: + * https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx */ +#define GAPButtonUUID 0xAA00 +const uint16_t uuid16_list[] = {GAPButtonUUID}; + +static EventQueue eventQueue( + /* event count */ 16 * /* event size */ 32 +); + +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 faillure"); + break; + } + printf("\r\n"); +} + +void updatePayload(void) +{ + // Update the count in the SERVICE_DATA field of the advertising payload + uint8_t service_data[3]; + service_data[0] = GAPButtonUUID & 0xff; + service_data[1] = GAPButtonUUID >> 8; + service_data[2] = cnt; // Put the button click count in the third byte + ble_error_t err = BLE::Instance().gap().updateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, (uint8_t *)service_data, sizeof(service_data)); + if (err != BLE_ERROR_NONE) { + print_error(err, "Updating payload failed"); + } +} + +void buttonPressedCallback(void) +{ + ++cnt; + + // Calling BLE api in interrupt context may cause race conditions + // Using mbed-events to schedule calls to BLE api for safety + eventQueue.post(updatePayload); +} + +void blinkCallback(void) +{ + led1 = !led1; +} + +void bleInitComplete(BLE::InitializationCompleteCallbackContext *context) +{ + BLE& ble = context->ble; + ble_error_t err = context->error; + + if (err != BLE_ERROR_NONE) { + print_error(err, "BLE initialisation failed"); + return; + } + + // Set up the advertising flags. Note: not all combination of flags are valid + // BREDR_NOT_SUPPORTED: Device does not support Basic Rate or Enchanced Data Rate, It is Low Energy only. + // LE_GENERAL_DISCOVERABLE: Peripheral device is discoverable at any moment + err = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); + if (err != BLE_ERROR_NONE) { + print_error(err, "Setting GAP flags failed"); + return; + } + + // Put the device name in the advertising payload + err = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); + if (err != BLE_ERROR_NONE) { + print_error(err, "Setting device name failed"); + return; + } + + err = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); + if (err != BLE_ERROR_NONE) { + print_error(err, "Setting service UUID failed"); + return; + } + + // The Service Data data type consists of a service UUID with the data associated with that service. + // We will encode the number of button clicks in the Service Data field + // First two bytes of SERVICE_DATA field should contain the UUID of the service + uint8_t service_data[3]; + service_data[0] = GAPButtonUUID & 0xff; + service_data[1] = GAPButtonUUID >> 8; + service_data[2] = cnt; // Put the button click count in the third byte + err = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, (uint8_t *)service_data, sizeof(service_data)); + if (err != BLE_ERROR_NONE) { + print_error(err, "Setting service data failed"); + return; + } + + // It is not connectable as we are just boardcasting + ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED); + + // Send out the advertising payload every 1000ms + ble.gap().setAdvertisingInterval(1000); + + err = ble.gap().startAdvertising(); + if (err != BLE_ERROR_NONE) { + print_error(err, "Sart advertising failed"); + return; + } +} + +void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) { + BLE &ble = BLE::Instance(); + eventQueue.post(Callback<void()>(&ble, &BLE::processEvents)); +} + +int main() +{ + cnt = 0; + + BLE &ble = BLE::Instance(); + ble.onEventsToProcess(scheduleBleEventsProcessing); + ble_error_t err = ble.init(bleInitComplete); + if (err != BLE_ERROR_NONE) { + print_error(err, "BLE initialisation failed"); + return 0; + } + + // Blink LED every 500 ms to indicate system aliveness + eventQueue.post_every(500, blinkCallback); + + // Register function to be called when button is released + button.rise(buttonPressedCallback); + + while (true) { + eventQueue.dispatch(); + } + + return 0; +}