1 /**
2 * Arduino Wrapper for BTstack
3 */
4
5 #include <Arduino.h>
6 #include <SPI.h>
7
8 #ifdef __AVR__
9 #include <avr/wdt.h>
10 #endif
11
12 #if __arm__
13 #include <Reset.h> // also provides NVIC_SystemReset
14 #endif
15
16 #include "BTstack.h"
17
18 #include "btstack_memory.h"
19 #include "hal_tick.h"
20 #include "hal_cpu.h"
21 #include "hci_cmd.h"
22 #include "btstack_util.h"
23 #include "btstack_run_loop.h"
24 #include "btstack_event.h"
25 #include "btstack_run_loop_embedded.h"
26 #include "hci_transport.h"
27 #include "hci_transport_h4.h"
28
29 #include "ad_parser.h"
30 #include "btstack_chipset_em9301.h"
31 #include "btstack_debug.h"
32 #include "gap.h"
33 #include "hci.h"
34 #include "hci_dump.h"
35 #include "hci_dump_embedded_stdout.h"
36 #include "l2cap.h"
37 #include "ble/att_db.h"
38 #include "ble/att_server.h"
39 #include "ble/att_db_util.h"
40 #include "ble/le_device_db.h"
41 #include "ble/sm.h"
42
43 // Pin 13 has an LED connected on most Arduino boards.
44 #define PIN_LED 13
45
46 // prototypes
47 extern "C" void hal_uart_dma_process(void);
48
49 enum {
50 SET_ADVERTISEMENT_PARAMS = 1 << 0,
51 SET_ADVERTISEMENT_DATA = 1 << 1,
52 SET_ADVERTISEMENT_ENABLED = 1 << 2,
53 };
54
55 typedef enum gattAction {
56 gattActionWrite,
57 gattActionSubscribe,
58 gattActionUnsubscribe,
59 gattActionServiceQuery,
60 gattActionCharacteristicQuery,
61 gattActionRead,
62 } gattAction_t;
63
64 static gattAction_t gattAction;
65
66 // btstack state
67 static int btstack_state;
68
69 static const uint8_t iBeaconAdvertisement01[] = { 0x02, 0x01 };
70 static const uint8_t iBeaconAdvertisement38[] = { 0x1a, 0xff, 0x4c, 0x00, 0x02, 0x15 };
71 static uint8_t adv_data[31];
72 static uint16_t adv_data_len = 0;
73 static int gatt_is_characteristics_query;
74
75 static uint16_t le_peripheral_todos = 0;
76 static bool have_custom_addr;
77 static bd_addr_t public_bd_addr;
78
79 static btstack_timer_source_t connection_timer;
80
81 static void (*bleAdvertismentCallback)(BLEAdvertisement * bleAdvertisement) = NULL;
82 static void (*bleDeviceConnectedCallback)(BLEStatus status, BLEDevice * device)= NULL;
83 static void (*bleDeviceDisconnectedCallback)(BLEDevice * device) = NULL;
84 static void (*gattServiceDiscoveredCallback)(BLEStatus status, BLEDevice * device, BLEService * bleService) = NULL;
85 static void (*gattCharacteristicDiscoveredCallback)(BLEStatus status, BLEDevice * device, BLECharacteristic * characteristic) = NULL;
86 static void (*gattCharacteristicNotificationCallback)(BLEDevice * device, uint16_t value_handle, uint8_t* value, uint16_t length) = NULL;
87 static void (*gattCharacteristicIndicationCallback)(BLEDevice * device, uint16_t value_handle, uint8_t* value, uint16_t length) = NULL;
88 static void (*gattCharacteristicReadCallback)(BLEStatus status, BLEDevice * device, uint8_t * value, uint16_t length) = NULL;
89 static void (*gattCharacteristicWrittenCallback)(BLEStatus status, BLEDevice * device) = NULL;
90 static void (*gattCharacteristicSubscribedCallback)(BLEStatus status, BLEDevice * device) = NULL;
91 static void (*gattCharacteristicUnsubscribedCallback)(BLEStatus status, BLEDevice * device) = NULL;
92
93
94 // retarget printf to Serial
95 #ifdef ENERGIA
putchar(int c)96 extern "C" int putchar(int c) {
97 Serial.write((uint8_t)c);
98 return c;
99 }
100 #else
101 #ifdef __AVR__
102 static FILE uartout = {0} ;
uart_putchar(char c,FILE * stream)103 static int uart_putchar (char c, FILE *stream) {
104 Serial.write(c);
105 return 0;
106 }
107 #endif
108 // added for Arduino Zero. Arduino Due already has tis own _write(..) implementation
109 // in /Users/mringwal/Library/Arduino15/packages/arduino/hardware/sam/1.6.4/cores/arduino/syscalls_sam3.c
110 #if defined(__SAMD21G18A__)
111 // #ifdef __arm__
_write(int file,char * ptr,int len)112 extern "C" int _write(int file, char *ptr, int len){
113 int i;
114 for (i = 0; i < len; i++) {
115 if (ptr[i] == '\n') {
116 Serial.write((uint8_t)'\r');
117 }
118 Serial.write((uint8_t)ptr[i]);
119 }
120 return i;
121 }
122 #endif
123 #endif
124
125 // HAL CPU Implementation
hal_cpu_disable_irqs(void)126 extern "C" void hal_cpu_disable_irqs(void){ }
hal_cpu_enable_irqs(void)127 extern "C" void hal_cpu_enable_irqs(void) { }
hal_cpu_enable_irqs_and_sleep(void)128 extern "C" void hal_cpu_enable_irqs_and_sleep(void) { }
129
130 //
packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)131 static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
132
133 hci_con_handle_t con_handle;
134
135 switch (packet_type) {
136
137 case HCI_EVENT_PACKET:
138 switch (packet[0]) {
139
140 case BTSTACK_EVENT_STATE:
141 btstack_state = packet[2];
142 // bt stack activated, get started
143 if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING){
144 le_peripheral_todos |= SET_ADVERTISEMENT_PARAMS
145 | SET_ADVERTISEMENT_DATA
146 | SET_ADVERTISEMENT_ENABLED;
147 bd_addr_t addr;
148 gap_local_bd_addr(addr);
149 printf("BTstack up and running at %s\n", bd_addr_to_str(addr));
150 }
151 break;
152
153 case HCI_EVENT_DISCONNECTION_COMPLETE:
154 if (bleDeviceDisconnectedCallback) {
155 con_handle = little_endian_read_16(packet, 3);
156 BLEDevice device(con_handle);
157 (*bleDeviceDisconnectedCallback)(&device);
158 }
159 le_peripheral_todos |= SET_ADVERTISEMENT_ENABLED;
160 break;
161
162 case GAP_EVENT_ADVERTISING_REPORT: {
163 if (bleAdvertismentCallback) {
164 BLEAdvertisement advertisement(packet);
165 (*bleAdvertismentCallback)(&advertisement);
166 }
167 break;
168 }
169
170 case HCI_EVENT_LE_META:
171 switch (packet[2]) {
172 case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
173 con_handle = little_endian_read_16(packet, 4);
174 printf("Connection complete, con_handle 0x%04x\n", con_handle);
175 btstack_run_loop_remove_timer(&connection_timer);
176 if (!bleDeviceConnectedCallback) break;
177 if (packet[3]){
178 (*bleDeviceConnectedCallback)(BLE_STATUS_CONNECTION_ERROR, NULL);
179 } else {
180 BLEDevice device(con_handle);
181 (*bleDeviceConnectedCallback)(BLE_STATUS_OK, &device);
182 }
183 break;
184 default:
185 break;
186 }
187 break;
188 }
189 }
190 }
191
extract_service(gatt_client_service_t * service,uint8_t * packet)192 static void extract_service(gatt_client_service_t * service, uint8_t * packet){
193 service->start_group_handle = little_endian_read_16(packet, 4);
194 service->end_group_handle = little_endian_read_16(packet, 6);
195 service->uuid16 = 0;
196 reverse_128(&packet[8], service->uuid128);
197 if (uuid_has_bluetooth_prefix(service->uuid128)){
198 service->uuid16 = big_endian_read_32(service->uuid128, 0);
199 }
200 }
201
extract_characteristic(gatt_client_characteristic_t * characteristic,uint8_t * packet)202 static void extract_characteristic(gatt_client_characteristic_t * characteristic, uint8_t * packet){
203 characteristic->start_handle = little_endian_read_16(packet, 4);
204 characteristic->value_handle = little_endian_read_16(packet, 6);
205 characteristic->end_handle = little_endian_read_16(packet, 8);
206 characteristic->properties = little_endian_read_16(packet, 10);
207 characteristic->uuid16 = 0;
208 reverse_128(&packet[12], characteristic->uuid128);
209 if (uuid_has_bluetooth_prefix(characteristic->uuid128)){
210 characteristic->uuid16 = big_endian_read_32(characteristic->uuid128, 0);
211 }
212 }
213
gatt_client_callback(uint8_t packet_type,uint8_t * packet,uint16_t size)214 static void gatt_client_callback(uint8_t packet_type, uint8_t * packet, uint16_t size){
215
216 // if (hci) event is not 4-byte aligned, event->handle causes crash
217 // workaround: check event type, assuming GATT event types are contagious
218 if (packet[0] < GATT_EVENT_QUERY_COMPLETE) return;
219 if (packet[0] > GATT_EVENT_MTU) return;
220
221 hci_con_handle_t con_handle = little_endian_read_16(packet, 2);
222 uint8_t status;
223 uint8_t * value;
224 uint16_t value_handle;
225 uint16_t value_length;
226
227 BLEDevice device(con_handle);
228 switch(hci_event_packet_get_type(packet)){
229 case GATT_EVENT_SERVICE_QUERY_RESULT:
230 if (gattServiceDiscoveredCallback) {
231 gatt_client_service_t service;
232 extract_service(&service, packet);
233 BLEService bleService(service);
234 (*gattServiceDiscoveredCallback)(BLE_STATUS_OK, &device, &bleService);
235 }
236 break;
237 case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT:
238 if (gattCharacteristicDiscoveredCallback){
239 gatt_client_characteristic_t characteristic;
240 extract_characteristic(&characteristic, packet);
241 BLECharacteristic bleCharacteristic(characteristic);
242 (*gattCharacteristicDiscoveredCallback)(BLE_STATUS_OK, &device, &bleCharacteristic);
243 }
244 break;
245 case GATT_EVENT_QUERY_COMPLETE:
246 status = little_endian_read_16(packet, 4);
247 switch (gattAction){
248 case gattActionWrite:
249 if (gattCharacteristicWrittenCallback) gattCharacteristicWrittenCallback(status ? BLE_STATUS_OTHER_ERROR : BLE_STATUS_OK, &device);
250 break;
251 case gattActionSubscribe:
252 if (gattCharacteristicSubscribedCallback) gattCharacteristicSubscribedCallback(status ? BLE_STATUS_OTHER_ERROR : BLE_STATUS_OK, &device);
253 break;
254 case gattActionUnsubscribe:
255 if (gattCharacteristicUnsubscribedCallback) gattCharacteristicUnsubscribedCallback(status ? BLE_STATUS_OTHER_ERROR : BLE_STATUS_OK, &device);
256 break;
257 case gattActionServiceQuery:
258 if (gattServiceDiscoveredCallback) gattServiceDiscoveredCallback(BLE_STATUS_DONE, &device, NULL);
259 break;
260 case gattActionCharacteristicQuery:
261 if (gattCharacteristicDiscoveredCallback) gattCharacteristicDiscoveredCallback(BLE_STATUS_DONE, &device, NULL);
262 break;
263 default:
264 break;
265 };
266 break;
267 case GATT_EVENT_NOTIFICATION:
268 if (gattCharacteristicNotificationCallback) {
269 value_handle = little_endian_read_16(packet, 4);
270 value_length = little_endian_read_16(packet, 6);
271 value = &packet[8];
272 (*gattCharacteristicNotificationCallback)(&device, value_handle, value, value_length);
273 }
274 break;
275 case GATT_EVENT_INDICATION:
276 if (gattCharacteristicIndicationCallback) {
277 value_handle = little_endian_read_16(packet, 4);
278 value_length = little_endian_read_16(packet, 6);
279 value = &packet[8];
280 (*gattCharacteristicIndicationCallback)(&device, value_handle, value, value_length);
281 }
282 break;
283 case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT:
284 if (gattCharacteristicReadCallback) {
285 value_handle = little_endian_read_16(packet, 4);
286 value_length = little_endian_read_16(packet, 6);
287 value = &packet[8];
288 (*gattCharacteristicReadCallback)(BLE_STATUS_OK, &device, value, value_length);
289 }
290 break;
291 default:
292 break;
293 }
294 }
295
connection_timeout_handler(btstack_timer_source_t * timer)296 static void connection_timeout_handler(btstack_timer_source_t * timer){
297 // log_info("Cancel outgoing connection");
298 gap_connect_cancel();
299 if (!bleDeviceConnectedCallback) return;
300 (*bleDeviceConnectedCallback)(BLE_STATUS_CONNECTION_TIMEOUT, NULL); // page timeout 0x04
301 }
302
303 //
304
305 /// UUID class
UUID(void)306 UUID::UUID(void){
307 memset(uuid, 0, 16);
308 }
309
UUID(const uint8_t uuid[16])310 UUID::UUID(const uint8_t uuid[16]){
311 memcpy(this->uuid, uuid, 16);
312 }
313
UUID(const char * uuidStr)314 UUID::UUID(const char * uuidStr){
315 memset(uuid, 0, 16);
316 int len = strlen(uuidStr);
317 if (len <= 4){
318 // Handle 4 Bytes HEX
319 uint16_t uuid16;
320 int result = sscanf( (char *) uuidStr, "%x", &uuid16);
321 if (result == 1){
322 uuid_add_bluetooth_prefix(uuid, uuid16);
323 }
324 return;
325 }
326
327 // quick UUID parser, ignoring dashes
328 int i = 0;
329 int data = 0;
330 int have_nibble = 0;
331 while(*uuidStr && i < 16){
332 const char c = *uuidStr++;
333 if (c == '-') continue;
334 data = data << 4 | nibble_for_char(c);
335 if (!have_nibble) {
336 have_nibble = 1;
337 continue;
338 }
339 uuid[i++] = data;
340 data = 0;
341 have_nibble = 0;
342 }
343 }
344
getUuid(void) const345 const uint8_t * UUID::getUuid(void) const {
346 return uuid;
347 }
348
349 static char uuid16_buffer[5];
getUuidString() const350 const char * UUID::getUuidString() const {
351 // TODO: fix uuid_has_bluetooth_prefix call to use const
352 if (uuid_has_bluetooth_prefix((uint8_t*)uuid)){
353 sprintf(uuid16_buffer, "%04x", (uint16_t) big_endian_read_32(uuid, 0));
354 return uuid16_buffer;
355 } else {
356 // TODO: fix uuid128_to_str
357 return uuid128_to_str((uint8_t*)uuid);
358 }
359 }
360
getUuid128String() const361 const char * UUID::getUuid128String() const {
362 return uuid128_to_str((uint8_t*)uuid);
363 }
364
matches(UUID * other) const365 bool UUID::matches(UUID *other) const {
366 return memcmp(this->uuid, other->uuid, 16) == 0;
367 }
368
369
370 // BD_ADDR class
BD_ADDR(void)371 BD_ADDR::BD_ADDR(void){
372 }
373
BD_ADDR(const char * address_string,BD_ADDR_TYPE address_type)374 BD_ADDR::BD_ADDR(const char * address_string, BD_ADDR_TYPE address_type ) : address_type(address_type) {
375 // TODO: implement
376 // log_error("BD_ADDR::BD_ADDR(const char *, BD_ADDR_TYPE) not implemented yet!");
377 }
378
BD_ADDR(const uint8_t address[6],BD_ADDR_TYPE address_type)379 BD_ADDR::BD_ADDR(const uint8_t address[6], BD_ADDR_TYPE address_type) : address_type(address_type){
380 memcpy(this->address, address, 6);
381 }
382
getAddress(void)383 const uint8_t * BD_ADDR::getAddress(void){
384 return address;
385 }
386
getAddressString(void)387 const char * BD_ADDR::getAddressString(void){
388 return bd_addr_to_str(address);
389 }
390
getAddressType(void)391 BD_ADDR_TYPE BD_ADDR::getAddressType(void){
392 return address_type;
393 }
394
395
BLEAdvertisement(uint8_t * event_packet)396 BLEAdvertisement::BLEAdvertisement(uint8_t * event_packet) :
397 advertising_event_type(event_packet[2]),
398 rssi(event_packet[10]),
399 data_length(event_packet[11]),
400 iBeacon_UUID(NULL)
401 {
402 bd_addr_t addr;
403 reverse_bd_addr(&event_packet[4], addr);
404 bd_addr = BD_ADDR(addr, (BD_ADDR_TYPE)event_packet[3]);
405 memcpy(data, &event_packet[12], LE_ADVERTISING_DATA_SIZE);
406 }
407
~BLEAdvertisement()408 BLEAdvertisement::~BLEAdvertisement(){
409 if (iBeacon_UUID) delete(iBeacon_UUID);
410 }
411
getAdvData(void)412 const uint8_t * BLEAdvertisement::getAdvData(void){
413 return data;
414 }
415
getBdAddr(void)416 BD_ADDR * BLEAdvertisement::getBdAddr(void){
417 return &bd_addr;
418 }
419
getRssi(void)420 int BLEAdvertisement::getRssi(void){
421 return rssi > 127 ? rssi - 256 : rssi;
422 }
423
424
containsService(UUID * service)425 bool BLEAdvertisement::containsService(UUID * service){
426 return ad_data_contains_uuid128(data_length, data, (uint8_t*) service->getUuid());
427 }
428
nameHasPrefix(const char * name_prefix)429 bool BLEAdvertisement::nameHasPrefix(const char * name_prefix){
430 ad_context_t context;
431 int name_prefix_len = strlen(name_prefix);
432 for (ad_iterator_init(&context, data_length, data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)){
433 uint8_t data_type = ad_iterator_get_data_type(&context);
434 uint8_t data_len = ad_iterator_get_data_len(&context);
435 uint8_t * data = ad_iterator_get_data(&context);
436 int compare_len = name_prefix_len;
437 switch(data_type){
438 case 8: // shortented local name
439 case 9: // complete local name
440 if (compare_len > data_len) compare_len = data_len;
441 if (strncmp(name_prefix, (const char*) data, compare_len) == 0) return true;
442 break;
443 default:
444 break;
445 }
446 }
447 return false;
448 };
449
isIBeacon(void)450 bool BLEAdvertisement::isIBeacon(void){
451 return ((memcmp(iBeaconAdvertisement01, data, sizeof(iBeaconAdvertisement01)) == 0)
452 && (memcmp(iBeaconAdvertisement38, &data[3], sizeof(iBeaconAdvertisement38)) == 0));
453 }
454
getIBeaconUUID(void)455 const UUID * BLEAdvertisement::getIBeaconUUID(void){
456 if (!iBeacon_UUID){
457 iBeacon_UUID = new UUID(&data[9]);
458 }
459 return iBeacon_UUID;
460 };
getIBeaconMajorID(void)461 uint16_t BLEAdvertisement::getIBeaconMajorID(void){
462 return big_endian_read_16(data, 25);
463 };
getIBecaonMinorID(void)464 uint16_t BLEAdvertisement::getIBecaonMinorID(void){
465 return big_endian_read_16(data, 27);
466 };
getiBeaconMeasuredPower(void)467 uint8_t BLEAdvertisement::getiBeaconMeasuredPower(void){
468 return data[29];
469 }
470
471
BLECharacteristic(void)472 BLECharacteristic::BLECharacteristic(void){
473 }
474
BLECharacteristic(gatt_client_characteristic_t characteristic)475 BLECharacteristic::BLECharacteristic(gatt_client_characteristic_t characteristic)
476 : characteristic(characteristic), uuid(characteristic.uuid128) {
477 }
478
getUUID(void)479 const UUID * BLECharacteristic::getUUID(void){
480 return &uuid;
481 }
482
matches(UUID * uuid)483 bool BLECharacteristic::matches(UUID * uuid){
484 return this->uuid.matches(uuid);
485 }
486
isValueHandle(uint16_t value_handle)487 bool BLECharacteristic::isValueHandle(uint16_t value_handle){
488 return characteristic.value_handle == value_handle;
489 }
490
getCharacteristic(void)491 const gatt_client_characteristic_t * BLECharacteristic::getCharacteristic(void){
492 return &characteristic;
493 }
494
495
BLEService(void)496 BLEService::BLEService(void){
497 }
498
BLEService(gatt_client_service_t service)499 BLEService::BLEService(gatt_client_service_t service)
500 : service(service), uuid(service.uuid128){
501 }
502
getUUID(void)503 const UUID * BLEService::getUUID(void){
504 return &uuid;
505 }
506
matches(UUID * uuid)507 bool BLEService::matches(UUID * uuid){
508 return this->uuid.matches(uuid);
509 }
510
getService(void)511 const gatt_client_service_t * BLEService::getService(void){
512 return &service;
513 }
514
515 // discovery of services and characteristics
BLEDevice(void)516 BLEDevice::BLEDevice(void){
517 }
BLEDevice(hci_con_handle_t handle)518 BLEDevice::BLEDevice(hci_con_handle_t handle)
519 : handle(handle){
520 }
getHandle(void)521 uint16_t BLEDevice::getHandle(void){
522 return handle;
523 }
discoverGATTServices(void)524 int BLEDevice::discoverGATTServices(void){
525 return BTstack.discoverGATTServices(this);
526 }
discoverCharacteristicsForService(BLEService * service)527 int BLEDevice::discoverCharacteristicsForService(BLEService * service){
528 return BTstack.discoverCharacteristicsForService(this, service);
529 }
readCharacteristic(BLECharacteristic * characteristic)530 int BLEDevice::readCharacteristic(BLECharacteristic * characteristic){
531 return BTstack.readCharacteristic(this, characteristic);
532 }
writeCharacteristic(BLECharacteristic * characteristic,uint8_t * data,uint16_t size)533 int BLEDevice::writeCharacteristic(BLECharacteristic * characteristic, uint8_t * data, uint16_t size){
534 return BTstack.writeCharacteristic(this, characteristic, data, size);
535 }
writeCharacteristicWithoutResponse(BLECharacteristic * characteristic,uint8_t * data,uint16_t size)536 int BLEDevice::writeCharacteristicWithoutResponse(BLECharacteristic * characteristic, uint8_t * data, uint16_t size){
537 return BTstack.writeCharacteristicWithoutResponse(this, characteristic, data, size);
538 }
subscribeForNotifications(BLECharacteristic * characteristic)539 int BLEDevice::subscribeForNotifications(BLECharacteristic * characteristic){
540 return BTstack.subscribeForNotifications(this, characteristic);
541 }
unsubscribeFromNotifications(BLECharacteristic * characteristic)542 int BLEDevice::unsubscribeFromNotifications(BLECharacteristic * characteristic){
543 return BTstack.unsubscribeFromNotifications(this, characteristic);
544 }
subscribeForIndications(BLECharacteristic * characteristic)545 int BLEDevice::subscribeForIndications(BLECharacteristic * characteristic){
546 return BTstack.subscribeForIndications(this, characteristic);
547 }
unsubscribeFromIndications(BLECharacteristic * characteristic)548 int BLEDevice::unsubscribeFromIndications(BLECharacteristic * characteristic){
549 return BTstack.unsubscribeFromIndications(this, characteristic);
550 }
551
552
553
554 static uint16_t (*gattReadCallback)(uint16_t characteristic_id, uint8_t * buffer, uint16_t buffer_size);
555 static int (*gattWriteCallback)(uint16_t characteristic_id, uint8_t *buffer, uint16_t buffer_size);
556
557 // ATT Client Read Callback for Dynamic Data
558 // - if buffer == NULL, don't copy data, just return size of value
559 // - if buffer != NULL, copy data and return number bytes copied
560 // @param offset defines start of attribute value
att_read_callback(hci_con_handle_t con_handle,uint16_t att_handle,uint16_t offset,uint8_t * buffer,uint16_t buffer_size)561 static uint16_t att_read_callback(hci_con_handle_t con_handle, uint16_t att_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
562 if (gattReadCallback){
563 return gattReadCallback(att_handle, buffer, buffer_size);
564 }
565 return 0;
566 }
567 /* LISTING_END */
568
569
570 /*
571 * @section ATT Write
572 *
573 * @text The only valid ATT write in this example is to the Client Characteristic Configuration, which configures notification
574 * and indication. If the ATT handle matches the client configuration handle, the new configuration value is stored and used
575 * in the heartbeat handler to decide if a new value should be sent. See Listing attWrite.
576 */
577
578 /* LISTING_START(attWrite): ATT Write */
att_write_callback(hci_con_handle_t con_handle,uint16_t att_handle,uint16_t transaction_mode,uint16_t offset,uint8_t * buffer,uint16_t buffer_size)579 static int att_write_callback(hci_con_handle_t con_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size){
580 if (gattWriteCallback){
581 gattWriteCallback(att_handle, buffer, buffer_size);
582 }
583 return 0;
584 }
585
586
587
BTstackManager(void)588 BTstackManager::BTstackManager(void){
589 // client_packet_handler = NULL;
590 have_custom_addr = false;
591 // reset handler
592 bleAdvertismentCallback = NULL;
593 bleDeviceConnectedCallback = NULL;
594 bleDeviceDisconnectedCallback = NULL;
595 gattServiceDiscoveredCallback = NULL;
596 gattCharacteristicDiscoveredCallback = NULL;
597 gattCharacteristicNotificationCallback = NULL;
598
599 att_db_util_init();
600
601 // disable LOG_INFO messages
602 hci_dump_enable_log_level(HCI_DUMP_LOG_LEVEL_INFO, 0);
603
604 #ifdef __AVR__
605 // configure stdout to go via Serial
606 fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE);
607 stdout = &uartout;
608 #endif
609 }
610
setBLEAdvertisementCallback(void (* callback)(BLEAdvertisement * bleAdvertisement))611 void BTstackManager::setBLEAdvertisementCallback(void (*callback)(BLEAdvertisement * bleAdvertisement)){
612 bleAdvertismentCallback = callback;
613 }
setBLEDeviceConnectedCallback(void (* callback)(BLEStatus status,BLEDevice * device))614 void BTstackManager::setBLEDeviceConnectedCallback(void (*callback)(BLEStatus status, BLEDevice * device)){
615 bleDeviceConnectedCallback = callback;
616 }
setBLEDeviceDisconnectedCallback(void (* callback)(BLEDevice * device))617 void BTstackManager::setBLEDeviceDisconnectedCallback(void (*callback)(BLEDevice * device)){
618 bleDeviceDisconnectedCallback = callback;
619 }
setGATTServiceDiscoveredCallback(void (* callback)(BLEStatus status,BLEDevice * device,BLEService * bleService))620 void BTstackManager::setGATTServiceDiscoveredCallback(void (*callback)(BLEStatus status, BLEDevice * device, BLEService * bleService)){
621 gattServiceDiscoveredCallback = callback;
622 }
setGATTCharacteristicDiscoveredCallback(void (* callback)(BLEStatus status,BLEDevice * device,BLECharacteristic * characteristic))623 void BTstackManager::setGATTCharacteristicDiscoveredCallback(void (*callback)(BLEStatus status, BLEDevice * device, BLECharacteristic * characteristic)){
624 gattCharacteristicDiscoveredCallback = callback;
625 }
setGATTCharacteristicNotificationCallback(void (* callback)(BLEDevice * device,uint16_t value_handle,uint8_t * value,uint16_t length))626 void BTstackManager::setGATTCharacteristicNotificationCallback(void (*callback)(BLEDevice * device, uint16_t value_handle, uint8_t* value, uint16_t length)){
627 gattCharacteristicNotificationCallback = callback;
628 }
setGATTCharacteristicIndicationCallback(void (* callback)(BLEDevice * device,uint16_t value_handle,uint8_t * value,uint16_t length))629 void BTstackManager::setGATTCharacteristicIndicationCallback(void (*callback)(BLEDevice * device, uint16_t value_handle, uint8_t* value, uint16_t length)){
630 gattCharacteristicIndicationCallback = callback;
631 }
setGATTCharacteristicReadCallback(void (* callback)(BLEStatus status,BLEDevice * device,uint8_t * value,uint16_t length))632 void BTstackManager::setGATTCharacteristicReadCallback(void (*callback)(BLEStatus status, BLEDevice * device, uint8_t * value, uint16_t length)){
633 gattCharacteristicReadCallback = callback;
634 }
setGATTCharacteristicWrittenCallback(void (* callback)(BLEStatus status,BLEDevice * device))635 void BTstackManager::setGATTCharacteristicWrittenCallback(void (*callback)(BLEStatus status, BLEDevice * device)){
636 gattCharacteristicWrittenCallback = callback;
637 }
setGATTCharacteristicSubscribedCallback(void (* callback)(BLEStatus status,BLEDevice * device))638 void BTstackManager::setGATTCharacteristicSubscribedCallback(void (*callback)(BLEStatus status, BLEDevice * device)){
639 gattCharacteristicSubscribedCallback = callback;
640 }
setGATTCharacteristicUnsubscribedCallback(void (* callback)(BLEStatus status,BLEDevice * device))641 void BTstackManager::setGATTCharacteristicUnsubscribedCallback(void (*callback)(BLEStatus status, BLEDevice * device)){
642 gattCharacteristicUnsubscribedCallback = callback;
643 }
644
discoverGATTServices(BLEDevice * device)645 int BTstackManager::discoverGATTServices(BLEDevice * device){
646 gattAction = gattActionServiceQuery;
647 return gatt_client_discover_primary_services(gatt_client_callback, device->getHandle());
648 }
discoverCharacteristicsForService(BLEDevice * device,BLEService * service)649 int BTstackManager::discoverCharacteristicsForService(BLEDevice * device, BLEService * service){
650 gattAction = gattActionCharacteristicQuery;
651 return gatt_client_discover_characteristics_for_service(gatt_client_callback, device->getHandle(), (gatt_client_service_t*) service->getService());
652 }
readCharacteristic(BLEDevice * device,BLECharacteristic * characteristic)653 int BTstackManager::readCharacteristic(BLEDevice * device, BLECharacteristic * characteristic){
654 return gatt_client_read_value_of_characteristic(gatt_client_callback, device->getHandle(), (gatt_client_characteristic_t*) characteristic->getCharacteristic());
655 }
writeCharacteristic(BLEDevice * device,BLECharacteristic * characteristic,uint8_t * data,uint16_t size)656 int BTstackManager::writeCharacteristic(BLEDevice * device, BLECharacteristic * characteristic, uint8_t * data, uint16_t size){
657 gattAction = gattActionWrite;
658 return gatt_client_write_value_of_characteristic(gatt_client_callback, device->getHandle(), characteristic->getCharacteristic()->value_handle,
659 size, data);
660 }
writeCharacteristicWithoutResponse(BLEDevice * device,BLECharacteristic * characteristic,uint8_t * data,uint16_t size)661 int BTstackManager::writeCharacteristicWithoutResponse(BLEDevice * device, BLECharacteristic * characteristic, uint8_t * data, uint16_t size){
662 return gatt_client_write_value_of_characteristic_without_response(device->getHandle(), characteristic->getCharacteristic()->value_handle,
663 size, data);
664 }
subscribeForNotifications(BLEDevice * device,BLECharacteristic * characteristic)665 int BTstackManager::subscribeForNotifications(BLEDevice * device, BLECharacteristic * characteristic){
666 gattAction = gattActionSubscribe;
667 return gatt_client_write_client_characteristic_configuration(gatt_client_callback, device->getHandle(), (gatt_client_characteristic_t*) characteristic->getCharacteristic(),
668 GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
669 }
subscribeForIndications(BLEDevice * device,BLECharacteristic * characteristic)670 int BTstackManager::subscribeForIndications(BLEDevice * device, BLECharacteristic * characteristic){
671 gattAction = gattActionSubscribe;
672 return gatt_client_write_client_characteristic_configuration(gatt_client_callback, device->getHandle(), (gatt_client_characteristic_t*) characteristic->getCharacteristic(),
673 GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_INDICATION);
674 }
unsubscribeFromNotifications(BLEDevice * device,BLECharacteristic * characteristic)675 int BTstackManager::unsubscribeFromNotifications(BLEDevice * device, BLECharacteristic * characteristic){
676 gattAction = gattActionUnsubscribe;
677 return gatt_client_write_client_characteristic_configuration(gatt_client_callback, device->getHandle(), (gatt_client_characteristic_t*) characteristic->getCharacteristic(),
678 GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NONE);
679 }
unsubscribeFromIndications(BLEDevice * device,BLECharacteristic * characteristic)680 int BTstackManager::unsubscribeFromIndications(BLEDevice * device, BLECharacteristic * characteristic){
681 gattAction = gattActionUnsubscribe;
682 return gatt_client_write_client_characteristic_configuration(gatt_client_callback, device->getHandle(), (gatt_client_characteristic_t*) characteristic->getCharacteristic(),
683 GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NONE);
684 }
bleConnect(BLEAdvertisement * advertisement,int timeout_ms)685 void BTstackManager::bleConnect(BLEAdvertisement * advertisement, int timeout_ms){
686 bleConnect(advertisement->getBdAddr(), timeout_ms);
687 }
bleConnect(BD_ADDR * address,int timeout_ms)688 void BTstackManager::bleConnect(BD_ADDR * address, int timeout_ms){
689 bleConnect(address->getAddressType(), address->getAddress(), timeout_ms);
690 }
bleConnect(BD_ADDR_TYPE address_type,const char * address,int timeout_ms)691 void BTstackManager::bleConnect(BD_ADDR_TYPE address_type, const char * address, int timeout_ms){
692 // TOOD: implement
693 // log_error("BTstackManager::bleConnect(BD_ADDR_TYPE address_type, const char * address, int timeout_ms) not implemented");
694 }
bleConnect(BD_ADDR_TYPE address_type,const uint8_t address[6],int timeout_ms)695 void BTstackManager::bleConnect(BD_ADDR_TYPE address_type, const uint8_t address[6], int timeout_ms){
696 gap_connect((uint8_t*)address, (bd_addr_type_t) address_type);
697 if (!timeout_ms) return;
698 btstack_run_loop_set_timer(&connection_timer, timeout_ms);
699 btstack_run_loop_set_timer_handler(&connection_timer, connection_timeout_handler);
700 btstack_run_loop_add_timer(&connection_timer);
701 }
702
bleDisconnect(BLEDevice * device)703 void BTstackManager::bleDisconnect(BLEDevice * device){
704 btstack_run_loop_remove_timer(&connection_timer);
705 gap_disconnect(device->getHandle());
706 }
707
setPublicBdAddr(bd_addr_t addr)708 void BTstackManager::setPublicBdAddr(bd_addr_t addr){
709 have_custom_addr = true;
710 memcpy(public_bd_addr, addr ,6);
711 }
712
bluetooth_hardware_error(uint8_t error)713 void bluetooth_hardware_error(uint8_t error){
714 printf("Bluetooth Hardware Error event 0x%02x. Restarting...\n\n\n", error);
715 #ifdef __AVR__
716 wdt_enable(WDTO_15MS);
717 // wait for watchdog to trigger
718 #endif
719
720 #ifdef __arm__
721 NVIC_SystemReset();
722 #endif
723 while(1);
724 }
725
726 static hci_transport_config_uart_t config = {
727 HCI_TRANSPORT_CONFIG_UART,
728 115200,
729 0, // main baudrate
730 1, // flow control
731 NULL,
732 };
733
734 static btstack_packet_callback_registration_t hci_event_callback_registration;
735
setup(void)736 void BTstackManager::setup(void){
737
738 #ifdef PIN_LED
739 pinMode(PIN_LED, OUTPUT);
740 #endif
741
742 printf("BTstackManager::setup()\n");
743
744 btstack_memory_init();
745 btstack_run_loop_init(btstack_run_loop_embedded_get_instance());
746
747 const hci_transport_t * transport = hci_transport_h4_instance(btstack_uart_block_embedded_instance());
748 hci_init(transport, (void*) &config);
749 hci_set_chipset(btstack_chipset_em9301_instance());
750
751 if (have_custom_addr){
752 hci_set_bd_addr(public_bd_addr);
753 }
754
755 hci_set_hardware_error_callback(&bluetooth_hardware_error);
756
757 // inform about BTstack state
758 hci_event_callback_registration.callback = &packet_handler;
759 hci_add_event_handler(&hci_event_callback_registration);
760
761 l2cap_init();
762
763 // setup central device db
764 le_device_db_init();
765
766 sm_init();
767
768 att_server_init(att_db_util_get_address(),att_read_callback, att_write_callback);
769
770 gatt_client_init();
771
772 // setup advertisements params
773 uint16_t adv_int_min = 0x0030;
774 uint16_t adv_int_max = 0x0030;
775 uint8_t adv_type = 0;
776 bd_addr_t null_addr;
777 memset(null_addr, 0, 6);
778 gap_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, null_addr, 0x07, 0x00);
779
780 // setup advertisements data
781 int pos = 0;
782 const uint8_t flags[] = { 0x02, 0x01, 0x02 };
783 memcpy(&adv_data[pos], flags, sizeof(flags));
784 pos += sizeof(flags);
785 char * name = "BTstack LE Shield";
786 adv_data[pos++] = strlen(name) + 1;
787 adv_data[pos++] = 0x09;
788 memcpy(&adv_data[pos], name, strlen(name));
789 pos += strlen(name);
790 adv_data_len = pos;
791 gap_advertisements_set_data(adv_data_len, adv_data);
792
793 // turn on!
794 btstack_state = 0;
795 hci_power_control(HCI_POWER_ON);
796 }
797
enablePacketLogger(void)798 void BTstackManager::enablePacketLogger(void){
799 hci_dump_init(hci_dump_embedded_stdout_get_instance());
800 }
801
enableDebugLogger()802 void BTstackManager::enableDebugLogger(){
803 // enable LOG_INFO messages
804 hci_dump_enable_log_level(HCI_DUMP_LOG_LEVEL_INFO, 1);
805 }
806
807
loop(void)808 void BTstackManager::loop(void){
809 // process data from/to Bluetooth module
810 hal_uart_dma_process();
811 // BTstack Run Loop
812 btstack_run_loop_embedded_execute_once();
813 }
814
bleStartScanning(void)815 void BTstackManager::bleStartScanning(void){
816 printf("Start scanning\n");
817 gap_start_scan();
818 }
bleStopScanning(void)819 void BTstackManager::bleStopScanning(void){
820 gap_stop_scan();
821 }
822
setGATTCharacteristicRead(uint16_t (* cb)(uint16_t characteristic_id,uint8_t * buffer,uint16_t buffer_size))823 void BTstackManager::setGATTCharacteristicRead(uint16_t (*cb)(uint16_t characteristic_id, uint8_t * buffer, uint16_t buffer_size)){
824 gattReadCallback = cb;
825 }
setGATTCharacteristicWrite(int (* cb)(uint16_t characteristic_id,uint8_t * buffer,uint16_t buffer_size))826 void BTstackManager::setGATTCharacteristicWrite(int (*cb)(uint16_t characteristic_id, uint8_t *buffer, uint16_t buffer_size)){
827 gattWriteCallback = cb;
828 }
addGATTService(UUID * uuid)829 void BTstackManager::addGATTService(UUID * uuid){
830 att_db_util_add_service_uuid128((uint8_t*)uuid->getUuid());
831 }
addGATTCharacteristic(UUID * uuid,uint16_t flags,const char * text)832 uint16_t BTstackManager::addGATTCharacteristic(UUID * uuid, uint16_t flags, const char * text){
833 return att_db_util_add_characteristic_uuid128((uint8_t*)uuid->getUuid(), flags, ATT_SECURITY_NONE, ATT_SECURITY_NONE, (uint8_t*)text, strlen(text));
834 }
addGATTCharacteristic(UUID * uuid,uint16_t flags,uint8_t * data,uint16_t data_len)835 uint16_t BTstackManager::addGATTCharacteristic(UUID * uuid, uint16_t flags, uint8_t * data, uint16_t data_len){
836 return att_db_util_add_characteristic_uuid128((uint8_t*)uuid->getUuid(), flags, ATT_SECURITY_NONE, ATT_SECURITY_NONE, data, data_len);
837 }
addGATTCharacteristicDynamic(UUID * uuid,uint16_t flags,uint16_t characteristic_id)838 uint16_t BTstackManager::addGATTCharacteristicDynamic(UUID * uuid, uint16_t flags, uint16_t characteristic_id){
839 return att_db_util_add_characteristic_uuid128((uint8_t*)uuid->getUuid(), flags | ATT_PROPERTY_DYNAMIC, ATT_SECURITY_NONE, ATT_SECURITY_NONE, NULL, 0);
840 }
setAdvData(uint16_t adv_data_len,const uint8_t * adv_data)841 void BTstackManager::setAdvData(uint16_t adv_data_len, const uint8_t * adv_data){
842 gap_advertisements_set_data(adv_data_len, (uint8_t*) adv_data);
843 }
startAdvertising()844 void BTstackManager::startAdvertising(){
845 gap_advertisements_enable(1);
846 }
stopAdvertising()847 void BTstackManager::stopAdvertising(){
848 gap_advertisements_enable(0);
849 }
iBeaconConfigure(UUID * uuid,uint16_t major_id,uint16_t minor_id,uint8_t measured_power)850 void BTstackManager::iBeaconConfigure(UUID * uuid, uint16_t major_id, uint16_t minor_id, uint8_t measured_power){
851 memcpy(adv_data, iBeaconAdvertisement01, sizeof(iBeaconAdvertisement01));
852 adv_data[2] = 0x06;
853 memcpy(&adv_data[3], iBeaconAdvertisement38, sizeof(iBeaconAdvertisement38));
854 memcpy(&adv_data[9], uuid->getUuid(), 16);
855 big_endian_store_16(adv_data, 25, major_id);
856 big_endian_store_16(adv_data, 27, minor_id);
857 adv_data[29] = measured_power;
858 adv_data_len = 30;
859 gap_advertisements_set_data(adv_data_len, adv_data);
860 }
861 // 02 01 06 1A FF 4C 00 02 15 -- F8 97 17 7B AE E8 47 67 8E CC CC 69 4F D5 FC EE -- 12 67 00 02 00 00
862 // 02 01 06 1a ff 4c 00 02 15 -- FB 0B 57 A2 82 28 44 CD 91 3A 94 A1 22 BA 12 06 -- 00 01 00 02 D1 00
863
864
865 BTstackManager BTstack;
866
867