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
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 }
Generated on Tue Jul 12 2022 18:31:59 by 1.7.2