This example demonstrates using the GattClient API to control BLE client devices. The canonical source for this example lives at https://github.com/ARMmbed/mbed-os-example-ble/tree/master/BLE_LEDBlinker

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-2015 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 #include "ble/DiscoveredCharacteristic.h"
00021 #include "ble/DiscoveredService.h"
00022 #include "ble/gap/Gap.h"
00023 #include "ble/gap/AdvertisingDataParser.h"
00024 #include "LEDService.h"
00025 #include "pretty_printer.h"
00026 
00027 const static char PEER_NAME[] = "LED";
00028 const static char DEVICE_NAME[] = "LED";
00029 
00030 static EventQueue event_queue(/* event count */ 10 * EVENTS_EVENT_SIZE);
00031 
00032 static DiscoveredCharacteristic led_characteristic;
00033 static bool trigger_led_characteristic = false;
00034 
00035 void service_discovery(const DiscoveredService *service) {
00036     if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) {
00037         printf("S UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle());
00038     } else {
00039         printf("S UUID-");
00040         const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID();
00041         for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
00042             printf("%02x", longUUIDBytes[i]);
00043         }
00044         printf(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle());
00045     }
00046 }
00047 
00048 void update_led_characteristic(void) {
00049     if (!BLE::Instance().gattClient().isServiceDiscoveryActive()) {
00050         led_characteristic.read();
00051     }
00052 }
00053 
00054 void characteristic_discovery(const DiscoveredCharacteristic *characteristicP) {
00055     printf("  C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getUUID().getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast());
00056     if (characteristicP->getUUID().getShortUUID() == 0xa001) { /* !ALERT! Alter this filter to suit your device. */
00057         led_characteristic        = *characteristicP;
00058         trigger_led_characteristic = true;
00059     }
00060 }
00061 
00062 void discovery_termination(Gap::Handle_t connectionHandle) {
00063     printf("terminated SD for handle %u\r\n", connectionHandle);
00064     if (trigger_led_characteristic) {
00065         trigger_led_characteristic = false;
00066         event_queue.call(update_led_characteristic);
00067     }
00068 }
00069 
00070 void trigger_toggled_write(const GattReadCallbackParams *response) {
00071     if (response->handle == led_characteristic.getValueHandle()) {
00072         printf("trigger_toggled_write: handle %u, offset %u, len %u\r\n", response->handle, response->offset, response->len);
00073         for (unsigned index = 0; index < response->len; index++) {
00074             printf("%c[%02x]", response->data[index], response->data[index]);
00075         }
00076         printf("\r\n");
00077 
00078         uint8_t toggledValue = response->data[0] ^ 0x1;
00079         led_characteristic.write(1, &toggledValue);
00080     }
00081 }
00082 
00083 void trigger_read(const GattWriteCallbackParams *response) {
00084     if (response->handle == led_characteristic.getValueHandle()) {
00085         led_characteristic.read();
00086     }
00087 }
00088 
00089 class LEDBlinkerDemo : ble::Gap::EventHandler {
00090 public:
00091     LEDBlinkerDemo(BLE &ble, events::EventQueue &event_queue) :
00092         _ble(ble),
00093         _event_queue(event_queue),
00094         _alive_led(LED1, 1),
00095         _actuated_led(LED2, 0),
00096         _is_connecting(false),
00097         _led_uuid(LEDService::LED_SERVICE_UUID),
00098         _led_service(NULL),
00099         _adv_data_builder(_adv_buffer) { }
00100 
00101     ~LEDBlinkerDemo() { }
00102 
00103     void start() {
00104         _ble.gap().setEventHandler(this);
00105 
00106         _ble.init(this, &LEDBlinkerDemo::on_init_complete);
00107 
00108         _event_queue.call_every(500, this, &LEDBlinkerDemo::blink);
00109 
00110         _event_queue.dispatch_forever();
00111     }
00112 
00113     void start_advertising() {
00114         /* Create advertising parameters and payload */
00115 
00116         ble::AdvertisingParameters adv_parameters(
00117             ble::advertising_type_t::CONNECTABLE_UNDIRECTED,
00118             ble::adv_interval_t(ble::millisecond_t(1000))
00119         );
00120 
00121         _adv_data_builder.setFlags();
00122         _adv_data_builder.setLocalServiceList(mbed::make_Span(&_led_uuid, 1));
00123         _adv_data_builder.setName(DEVICE_NAME);
00124 
00125         /* Setup advertising */
00126 
00127         ble_error_t error = _ble.gap().setAdvertisingParameters(
00128             ble::LEGACY_ADVERTISING_HANDLE,
00129             adv_parameters
00130         );
00131 
00132         if (error) {
00133             printf("_ble.gap().setAdvertisingParameters() failed\r\n");
00134             return;
00135         }
00136 
00137         error = _ble.gap().setAdvertisingPayload(
00138             ble::LEGACY_ADVERTISING_HANDLE,
00139             _adv_data_builder.getAdvertisingData()
00140         );
00141 
00142         if (error) {
00143             printf("_ble.gap().setAdvertisingPayload() failed\r\n");
00144             return;
00145         }
00146 
00147         /* Start advertising */
00148 
00149         error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
00150 
00151         if (error) {
00152             printf("_ble.gap().startAdvertising() failed\r\n");
00153             return;
00154         }
00155     }
00156 
00157 private:
00158     /** Callback triggered when the ble initialization process has finished */
00159     void on_init_complete(BLE::InitializationCompleteCallbackContext *params) {
00160         if (params->error != BLE_ERROR_NONE) {
00161             printf("Ble initialization failed.");
00162             return;
00163         }
00164 
00165         print_mac_address();
00166 
00167         _ble.gattClient().onDataRead(trigger_toggled_write);
00168         _ble.gattClient().onDataWritten(trigger_read);
00169 
00170         _led_service = new LEDService(_ble, false);
00171         _ble.gattServer().onDataWritten(this, &LEDBlinkerDemo::on_data_written);
00172 
00173         ble::ScanParameters scan_params;
00174         _ble.gap().setScanParameters(scan_params);
00175         _ble.gap().startScan();
00176     }
00177 
00178     void blink() {
00179         _alive_led = !_alive_led;
00180     }
00181 
00182 private:
00183     /* Event handler */
00184 
00185     void onDisconnectionComplete(const ble::DisconnectionCompleteEvent&) {
00186         _ble.gap().startScan();
00187         _is_connecting = false;
00188     }
00189 
00190     void onConnectionComplete(const ble::ConnectionCompleteEvent& event) {
00191         printf("onConnectionComplete\r\n");
00192         if (event.getOwnRole() == ble::connection_role_t::CENTRAL) {
00193             _ble.gattClient().onServiceDiscoveryTermination(discovery_termination);
00194             _ble.gattClient().launchServiceDiscovery(
00195                 event.getConnectionHandle(),
00196                 service_discovery,
00197                 characteristic_discovery,
00198                 0xa000,
00199                 0xa001
00200             );
00201             printf("Connected as Central, start advertising\r\n");
00202             start_advertising();
00203         } else if (event.getOwnRole() == ble::connection_role_t::PERIPHERAL) {
00204             printf("Connected as Peripheral\r\n");
00205         } else {
00206             _ble.gap().startScan();
00207         }
00208         _is_connecting = false;
00209     }
00210 
00211     void onAdvertisingReport(const ble::AdvertisingReportEvent &event) {
00212         /* don't bother with analysing scan result if we're already connecting */
00213         if (_is_connecting) {
00214             return;
00215         }
00216 
00217         ble::AdvertisingDataParser adv_data(event.getPayload());
00218 
00219         /* parse the advertising payload, looking for a discoverable device */
00220         while (adv_data.hasNext()) {
00221             ble::AdvertisingDataParser::element_t field = adv_data.next();
00222 
00223             /* connect to a discoverable device */
00224             if (field.type == ble::adv_data_type_t::COMPLETE_LOCAL_NAME &&
00225                 field.value.size() == strlen(PEER_NAME) &&
00226                 (memcmp(field.value.data(), PEER_NAME, field.value.size()) == 0)) {
00227 
00228                 printf("Adv from: ");
00229                 print_address(event.getPeerAddress().data());
00230                 printf(" rssi: %d, scan response: %u, connectable: %u\r\n",
00231                        event.getRssi(), event.getType().scan_response(), event.getType().connectable());
00232 
00233                 ble_error_t error = _ble.gap().stopScan();
00234 
00235                 if (error) {
00236                     print_error(error, "Error caused by Gap::stopScan");
00237                     return;
00238                 }
00239 
00240                 const ble::ConnectionParameters connection_params;
00241 
00242                 error = _ble.gap().connect(
00243                     event.getPeerAddressType(),
00244                     event.getPeerAddress(),
00245                     connection_params
00246                 );
00247 
00248                 if (error) {
00249                     _ble.gap().startScan();
00250                     return;
00251                 }
00252 
00253                 /* we may have already scan events waiting
00254                  * to be processed so we need to remember
00255                  * that we are already connecting and ignore them */
00256                 _is_connecting = true;
00257 
00258                 return;
00259             }
00260         }
00261     }
00262 
00263      /**
00264      * This callback allows the LEDService to receive updates to the ledState Characteristic.
00265      *
00266      * @param[in] params Information about the characterisitc being updated.
00267      */
00268     void on_data_written(const GattWriteCallbackParams *params) {
00269         printf("led_service getValueHandle() %x\r\n", _led_service->getValueHandle());
00270         printf("on_data_written, handle:%x len:%d\r\n", params->handle, params->len);
00271         if ((params->handle == _led_service->getValueHandle()) && (params->len == 1)) {
00272             _actuated_led = *(params->data);
00273         }
00274     }
00275 
00276 private:
00277     BLE &_ble;
00278     events::EventQueue &_event_queue;
00279     DigitalOut _alive_led;
00280     DigitalOut _actuated_led;
00281     bool _is_connecting;
00282 
00283     UUID _led_uuid;
00284     LEDService *_led_service;
00285 
00286     uint8_t _adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE];
00287     ble::AdvertisingDataBuilder _adv_data_builder;
00288 };
00289 
00290 
00291 /** Schedule processing of events from the BLE middleware in the event queue. */
00292 void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) {
00293     event_queue.call(Callback<void()>(&context->ble, &BLE::processEvents));
00294 }
00295 
00296 int main()
00297 {
00298     BLE &ble = BLE::Instance();
00299     ble.onEventsToProcess(schedule_ble_events);
00300 
00301     LEDBlinkerDemo demo(ble, event_queue);
00302     demo.start();
00303 
00304     return 0;
00305 }