BLE GAP Button example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include <events/mbed_events.h>
00018 #include <mbed.h>
00019 #include "ble/BLE.h"
00020 
00021 DigitalOut  led1(LED1, 1);
00022 InterruptIn button(BLE_BUTTON_PIN_NAME);
00023 uint8_t cnt;
00024 
00025 // Change your device name below
00026 const char DEVICE_NAME[] = "GAPButton";
00027 
00028 /* We can arbiturarily choose the GAPButton service UUID to be 0xAA00
00029  * as long as it does not overlap with the UUIDs defined here:
00030  * https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx */
00031 #define GAPButtonUUID 0xAA00
00032 const uint16_t uuid16_list[] = {GAPButtonUUID};
00033 
00034 static EventQueue eventQueue(/* event count */ 16 * EVENTS_EVENT_SIZE);
00035 
00036 void print_error(ble_error_t error, const char* msg)
00037 {
00038     printf("%s: ", msg);
00039     switch(error) {
00040         case BLE_ERROR_NONE:
00041             printf("BLE_ERROR_NONE: No error");
00042             break;
00043         case BLE_ERROR_BUFFER_OVERFLOW:
00044             printf("BLE_ERROR_BUFFER_OVERFLOW: The requested action would cause a buffer overflow and has been aborted");
00045             break;
00046         case BLE_ERROR_NOT_IMPLEMENTED:
00047             printf("BLE_ERROR_NOT_IMPLEMENTED: Requested a feature that isn't yet implement or isn't supported by the target HW");
00048             break;
00049         case BLE_ERROR_PARAM_OUT_OF_RANGE:
00050             printf("BLE_ERROR_PARAM_OUT_OF_RANGE: One of the supplied parameters is outside the valid range");
00051             break;
00052         case BLE_ERROR_INVALID_PARAM:
00053             printf("BLE_ERROR_INVALID_PARAM: One of the supplied parameters is invalid");
00054             break;
00055         case BLE_STACK_BUSY:
00056             printf("BLE_STACK_BUSY: The stack is busy");
00057             break;
00058         case BLE_ERROR_INVALID_STATE:
00059             printf("BLE_ERROR_INVALID_STATE: Invalid state");
00060             break;
00061         case BLE_ERROR_NO_MEM:
00062             printf("BLE_ERROR_NO_MEM: Out of Memory");
00063             break;
00064         case BLE_ERROR_OPERATION_NOT_PERMITTED:
00065             printf("BLE_ERROR_OPERATION_NOT_PERMITTED");
00066             break;
00067         case BLE_ERROR_INITIALIZATION_INCOMPLETE:
00068             printf("BLE_ERROR_INITIALIZATION_INCOMPLETE");
00069             break;
00070         case BLE_ERROR_ALREADY_INITIALIZED:
00071             printf("BLE_ERROR_ALREADY_INITIALIZED");
00072             break;
00073         case BLE_ERROR_UNSPECIFIED:
00074             printf("BLE_ERROR_UNSPECIFIED: Unknown error");
00075             break;
00076         case BLE_ERROR_INTERNAL_STACK_FAILURE:
00077             printf("BLE_ERROR_INTERNAL_STACK_FAILURE: internal stack faillure");
00078             break;
00079     }
00080     printf("\r\n");
00081 }
00082 
00083 void updatePayload(void)
00084 {
00085     // Update the count in the SERVICE_DATA field of the advertising payload
00086     uint8_t service_data[3];
00087     service_data[0] = GAPButtonUUID & 0xff;
00088     service_data[1] = GAPButtonUUID >> 8;
00089     service_data[2] = cnt; // Put the button click count in the third byte
00090     ble_error_t err = BLE::Instance().gap().updateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, (uint8_t *)service_data, sizeof(service_data));
00091     if (err != BLE_ERROR_NONE) {
00092         print_error(err, "Updating payload failed");
00093     }
00094 }
00095 
00096 void buttonPressedCallback(void)
00097 {
00098     ++cnt;
00099 
00100     // Calling BLE api in interrupt context may cause race conditions
00101     // Using mbed-events to schedule calls to BLE api for safety
00102     eventQueue.call(updatePayload);
00103 }
00104 
00105 void blinkCallback(void)
00106 {
00107     led1 = !led1;
00108 }
00109 
00110 void bleInitComplete(BLE::InitializationCompleteCallbackContext *context)
00111 {
00112     BLE&        ble = context->ble;
00113     ble_error_t err = context->error;
00114 
00115     if (err != BLE_ERROR_NONE) {
00116         print_error(err, "BLE initialisation failed");
00117         return;
00118     }
00119 
00120     // Set up the advertising flags. Note: not all combination of flags are valid
00121     // BREDR_NOT_SUPPORTED: Device does not support Basic Rate or Enchanced Data Rate, It is Low Energy only.
00122     // LE_GENERAL_DISCOVERABLE: Peripheral device is discoverable at any moment
00123     err = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
00124     if (err != BLE_ERROR_NONE) {
00125         print_error(err, "Setting GAP flags failed");
00126         return;
00127     }
00128 
00129     // Put the device name in the advertising payload
00130     err = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
00131     if (err != BLE_ERROR_NONE) {
00132         print_error(err, "Setting device name failed");
00133         return;
00134     }
00135 
00136     err = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
00137     if (err != BLE_ERROR_NONE) {
00138         print_error(err, "Setting service UUID failed");
00139         return;
00140     }
00141 
00142     // The Service Data data type consists of a service UUID with the data associated with that service.
00143     // We will encode the number of button clicks in the Service Data field
00144     // First two bytes of SERVICE_DATA field should contain the UUID of the service
00145     uint8_t service_data[3];
00146     service_data[0] = GAPButtonUUID & 0xff;
00147     service_data[1] = GAPButtonUUID >> 8;
00148     service_data[2] = cnt; // Put the button click count in the third byte
00149     err = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, (uint8_t *)service_data, sizeof(service_data));
00150     if (err != BLE_ERROR_NONE) {
00151         print_error(err, "Setting service data failed");
00152         return;
00153     }
00154 
00155     // It is not connectable as we are just boardcasting
00156     ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED);
00157 
00158     // Send out the advertising payload every 1000ms
00159     ble.gap().setAdvertisingInterval(1000);
00160 
00161     err = ble.gap().startAdvertising();
00162     if (err != BLE_ERROR_NONE) {
00163         print_error(err, "Sart advertising failed");
00164         return;
00165     }
00166 }
00167 
00168 void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
00169     BLE &ble = BLE::Instance();
00170     eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
00171 }
00172 
00173 int main()
00174 {
00175     cnt = 0;
00176 
00177     BLE &ble = BLE::Instance();
00178     ble.onEventsToProcess(scheduleBleEventsProcessing);
00179     ble_error_t err = ble.init(bleInitComplete);
00180     if (err != BLE_ERROR_NONE) {
00181         print_error(err, "BLE initialisation failed");
00182         return 0;
00183     }
00184 
00185     // Blink LED every 500 ms to indicate system aliveness
00186     eventQueue.call_every(500, blinkCallback);
00187 
00188     // Register function to be called when button is released
00189     button.rise(buttonPressedCallback);
00190 
00191     eventQueue.dispatch_forever();
00192 
00193     return 0;
00194 }