diff --git a/libraries/BLE/examples/central/led_control/led_control.ino b/libraries/BLE/examples/central/led_control/led_control.ino new file mode 100644 index 00000000..b98eef70 --- /dev/null +++ b/libraries/BLE/examples/central/led_control/led_control.ino @@ -0,0 +1,128 @@ +/* + Arduino BLE Central LED Control example + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include + +// variables for button +const int buttonPin = 2; +int oldButtonState = LOW; + +char uuid_buf[70]; + +void setup() { + Serial.begin(9600); + + // configure the button pin as input + pinMode(buttonPin, INPUT); + + // initialize the BLE hardware + BLE.begin(); + + Serial.println("BLE Central - LED control"); + + // start scanning for peripherals + BLE.startScanning(); +} + +void loop() { + // check if a peripheral has been discovered + BLEDevice peripheral = BLE.available(); + + if (peripheral) { + // discovered a peripheral, print out address, local name, and advertised service + peripheral.advertisedServiceUuid(uuid_buf); + Serial.print("Found "); + Serial.print(peripheral.address()); + Serial.print(" '"); + Serial.print(peripheral.localName()); + Serial.print("' "); + Serial.println(uuid_buf); + + // see if peripheral is advertising the LED service + if (String(uuid_buf) == String("19b10000-e8f2-537e-4f6c-d104768a1214")) { + // stop scanning + BLE.stopScanning(); + + controlLed(peripheral); + + // peripheral disconnected, start scanning again + BLE.startScanning(); + } + } +} + +void controlLed(BLEDevice peripheral) { + // connect to the peripheral + Serial.println("Connecting ..."); + + if (peripheral.connect()) { + Serial.println("Connected"); + } else { + Serial.println("Failed to connect!"); + return; + } + + // discover peripheral attributes + Serial.println("Discovering attributes ..."); + if (peripheral.discoverAttributes()) { + Serial.println("Attributes discovered"); + } else { + Serial.println("Attribute discovery failed!"); + peripheral.disconnect(); + return; + } + + // retrieve the LED characteristic + BLECharacteristic ledCharacteristic = peripheral.characteristic("19b10001-e8f2-537e-4f6c-d104768a1214"); + + if (!ledCharacteristic) { + Serial.println("Peripheral does not have LED characteristic!"); + peripheral.disconnect(); + return; + } else if (!ledCharacteristic.canWrite()) { + Serial.println("Peripheral does not have a writable LED characteristic!"); + peripheral.disconnect(); + return; + } + + while (peripheral.connected()) { + // while the peripheral is connection + + // read the button pin + int buttonState = digitalRead(buttonPin); + + if (oldButtonState != buttonState) { + // button changed + oldButtonState = buttonState; + + if (buttonState) { + Serial.println("button pressed"); + + // button is pressed, write 0x01 to turn the LED on + ledCharacteristic.writeByte(0x01); + } else { + Serial.println("button released"); + + // button is released, write 0x00 to turn the LED of + ledCharacteristic.writeByte(0x00); + } + } + } +} diff --git a/libraries/BLE/examples/central/peripheral_explorer/peripheral_explorer.ino b/libraries/BLE/examples/central/peripheral_explorer/peripheral_explorer.ino new file mode 100644 index 00000000..16eafb8c --- /dev/null +++ b/libraries/BLE/examples/central/peripheral_explorer/peripheral_explorer.ino @@ -0,0 +1,177 @@ +/* + Arduino BLE Central peripheral explorer example + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +char uuid_buf[70]; + +void setup() { + Serial.begin(9600); + + // initialize the BLE hardware + BLE.begin(); + + Serial.println("BLE Central - Peripheral Explorer"); + + // start scanning for peripherals + BLE.startScanning(); +} + +void loop() { + // check if a peripheral has been discovered + BLEDevice peripheral = BLE.available(); + + if (peripheral) { + // discovered a peripheral, print out address, local name, and advertised service + peripheral.advertisedServiceUuid(uuid_buf); + Serial.print("Found "); + Serial.print(peripheral.address()); + Serial.print(" '"); + Serial.print(peripheral.localName()); + Serial.print("' "); + Serial.println(uuid_buf); + + // see if peripheral is a SensorTag + if (peripheral.localName() == "SensorTag") { + // stop scanning + BLE.stopScanning(); + + explorerPeripheral(peripheral); + + // peripheral disconnected, we are done + while (1) { + // do nothing + } + } + } +} + +void explorerPeripheral(BLEDevice peripheral) { + // connect to the peripheral + Serial.println("Connecting ..."); + + if (peripheral.connect()) { + Serial.println("Connected"); + } else { + Serial.println("Failed to connect!"); + return; + } + + // discover peripheral attributes + Serial.println("Discovering attributes ..."); + if (peripheral.discoverAttributes()) { + Serial.println("Attributes discovered"); + } else { + Serial.println("Attribute discovery failed!"); + peripheral.disconnect(); + return; + } + + // read and print device name of peripheral + Serial.println(); + Serial.print("Device name: "); + Serial.println(peripheral.deviceName()); + + // read and print appearance of peripheral + Serial.print("Appearance: "); + Serial.println(peripheral.appearance()); + Serial.println(); + + // loop the services of the peripheral and explore each + for (int i = 0; i < peripheral.serviceCount(); i++) { + BLEService service = peripheral.service(i); + + exploreService(service); + } + + Serial.println(); + + // we are done exploring, disconnect + Serial.println("Disconnecting ..."); + peripheral.disconnect(); + Serial.println("Disconnected"); +} + +void exploreService(BLEService service) { + // print the UUID of the service + Serial.print("Service "); + Serial.println(service.uuid()); + + // loop the characteristics of the service and explore each + for (int i = 0; i < service.characteristicCount(); i++) { + BLECharacteristic characteristic = service.characteristic(i); + + exploreCharacteristic(characteristic); + } +} + +void exploreCharacteristic(BLECharacteristic characteristic) { + // print the UUID and properies of the characteristic + Serial.print("\tCharacteristic "); + Serial.print(characteristic.uuid()); + Serial.print(", properties 0x"); + Serial.print(characteristic.properties()); + + // check if the characteristic is readable + if (characteristic.canRead()) { + // read the characteristic value + characteristic.read(); + + // print out the value of the characteristic + Serial.print(", value 0x"); + printData(characteristic.value(), characteristic.valueLength()); + } + + Serial.println(); + + // loop the descriptors of the characteristic and explore each + for (int i = 0; i < characteristic.descriptorCount(); i++) { + BLEDescriptor descriptor = characteristic.descriptor(i); + + exploreDescriptor(descriptor); + } +} + +void exploreDescriptor(BLEDescriptor descriptor) { + // print the UUID of the descriptor + Serial.print("\t\tDescriptor "); + Serial.print(descriptor.uuid()); + + // read the descriptor value + descriptor.read(); + + // print out the value of the descriptor + Serial.print(", value 0x"); + printData(descriptor.value(), descriptor.valueLength()); + + Serial.println(); +} + +void printData(const unsigned char data[], int length) { + for (int i = 0; i < length; i++) { + unsigned char b = data[i]; + + if (b < 16) { + Serial.print("0"); + } + + Serial.print(b, HEX); + } +} + diff --git a/libraries/BLE/examples/central/scan/scan.ino b/libraries/BLE/examples/central/scan/scan.ino new file mode 100644 index 00000000..6b643967 --- /dev/null +++ b/libraries/BLE/examples/central/scan/scan.ino @@ -0,0 +1,72 @@ +/* + Arduino BLE Central scan example + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +char uuid_buf[70]; + +#include + +void setup() { + Serial.begin(9600); + + // initialize the BLE hardware + BLE.begin(); + + Serial.println("BLE Central scan"); + + // start scanning for peripheral + BLE.startScanning(); +} + +void loop() { + // check if a peripheral has been discovered + BLEDevice peripheral = BLE.available(); + + if (peripheral) { + // discovered a peripheral + Serial.println("Discovered a peripheral"); + Serial.println("-----------------------"); + + // print address + Serial.print("Address: "); + Serial.println(peripheral.address()); + + // print the local name, if present + if (peripheral.hasLocalName()) { + Serial.print("Local Name: "); + Serial.println(peripheral.localName()); + } + + // print the advertised service UUID's, if present + if (peripheral.hasAdvertisedServiceUuid()) { + Serial.print("Service UUID's: "); + for (int i = 0; i < peripheral.advertisedServiceUuidCount(); i++) { + peripheral.advertisedServiceUuid(i, uuid_buf); + Serial.print(String(uuid_buf) + " "); + } + Serial.println(); + } + + // print the RSSI + Serial.print("RSSI: "); + Serial.println(peripheral.rssi()); + + Serial.println(); + } +} + diff --git a/libraries/BLE/examples/central/scan_callback/scan_callback.ino b/libraries/BLE/examples/central/scan_callback/scan_callback.ino new file mode 100644 index 00000000..5dede517 --- /dev/null +++ b/libraries/BLE/examples/central/scan_callback/scan_callback.ino @@ -0,0 +1,74 @@ +/* + Arduino BLE Central scan callback example + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +char uuid_buf[70]; + +void setup() { + Serial.begin(9600); + + // initialize the BLE hardware + BLE.begin(); + + Serial.println("BLE Central scan callback"); + + // set the discovered event handle + BLE.setEventHandler(BLEDiscovered, bleCentralDiscoverHandler); + + // start scanning for peripherals with duplicates + BLE.startScanningWithDuplicates(); +} + +void loop() { + // poll the central for events + BLE.poll(); +} + +void bleCentralDiscoverHandler(BLEDevice peripheral) { + // discovered a peripheral + Serial.println("Discovered a peripheral"); + Serial.println("-----------------------"); + + // print address + Serial.print("Address: "); + Serial.println(peripheral.address()); + + // print the local name, if present + if (peripheral.hasLocalName()) { + Serial.print("Local Name: "); + Serial.println(peripheral.localName()); + } + + // print the advertised service UUID's, if present + if (peripheral.hasAdvertisedServiceUuid()) { + Serial.print("Service UUID's: "); + for (int i = 0; i < peripheral.advertisedServiceUuidCount(); i++) { + peripheral.advertisedServiceUuid(i, uuid_buf); + Serial.print(String(uuid_buf) + " "); + } + Serial.println(); + } + + // print the RSSI + Serial.print("RSSI: "); + Serial.println(peripheral.rssi()); + + Serial.println(); +} diff --git a/libraries/BLE/examples/central/sensortag_button/sensortag_button.ino b/libraries/BLE/examples/central/sensortag_button/sensortag_button.ino new file mode 100644 index 00000000..10b18125 --- /dev/null +++ b/libraries/BLE/examples/central/sensortag_button/sensortag_button.ino @@ -0,0 +1,124 @@ +/* + Arduino BLE Central SensorTag button example + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +uuid_buf[70]; + +void setup() { + Serial.begin(9600); + + // initialize the BLE hardware + BLE.begin(); + + Serial.println("BLE Central - SensorTag button"); + + // start scanning for peripheral + BLE.startScanning(); +} + +void loop() { + // check if a peripheral has been discovered + BLEDevice peripheral = BLE.available(); + + if (peripheral) { + // discovered a peripheral, print out address, local name, and advertised service + peripheral.advertisedServiceUuid(uuid_buf); + + Serial.print("Found "); + Serial.print(peripheral.address()); + Serial.print(" '"); + Serial.print(peripheral.localName()); + Serial.print("' "); + Serial.println(uuid_buf); + + // see if peripheral is a SensorTag + if (peripheral.localName() == "SensorTag") { + // stop scanning + BLE.stopScanning(); + + monitorSensorTagButtons(peripheral); + + // peripheral disconnected, start scanning again + BLE.startScanning(); + } + } +} + +void monitorSensorTagButtons(BLEDevice peripheral) { + // connect to the peripheral + Serial.println("Connecting ..."); + if (peripheral.connect()) { + Serial.println("Connected"); + } else { + Serial.println("Failed to connect!"); + return; + } + + // discover peripheral attributes + Serial.println("Discovering attributes ..."); + if (peripheral.discoverAttributes()) { + Serial.println("Attributes discovered"); + } else { + Serial.println("Attribute discovery failed!"); + peripheral.disconnect(); + return; + } + + // retrieve the simple key characteristic + BLECharacteristic simpleKeyCharacteristic = peripheral.characteristic("ffe1"); + + // subscribe to the simple key characteristic + Serial.println("Subscribing to simple key characteristic ..."); + if (!simpleKeyCharacteristic) { + Serial.println("no simple key characteristic found!"); + peripheral.disconnect(); + return; + } else if (!simpleKeyCharacteristic.canSubscribe()) { + Serial.println("simple key characteristic is not subscribable!"); + peripheral.disconnect(); + return; + } else if (!simpleKeyCharacteristic.subscribe()) { + Serial.println("subscription failed!"); + peripheral.disconnect(); + return; + } else { + Serial.println("Subscribed"); + } + + while (peripheral.connected()) { + // while the peripheral is connected + + // check if the value of the simple key characteristic has been updated + if (simpleKeyCharacteristic.valueUpdated()) { + // yes, get the value, characteristic is 1 byte so use char value + int value = simpleKeyCharacteristic.charValue(); + + if (value & 0x01) { + // first bit corresponds to the right button + Serial.println("Right button pressed"); + } + + if (value & 0x02) { + // second bit corresponds to the left button + Serial.println("Left button pressed"); + } + } + } +} diff --git a/libraries/BLE/examples/peripheral/led/led.ino b/libraries/BLE/examples/peripheral/led/led.ino new file mode 100644 index 00000000..eb708300 --- /dev/null +++ b/libraries/BLE/examples/peripheral/led/led.ino @@ -0,0 +1,84 @@ +/* + Arduino BLE Peripheral LED example + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +// LED pin +#define LED_PIN 13 + +// create service +BLEService ledService("19b10000e8f2537e4f6cd104768a1214"); + +// create switch characteristic +BLEByteCharacteristic switchCharacteristic("19b10001e8f2537e4f6cd104768a1214", BLERead | BLEWrite); + +BLEDescriptor switchDescriptor("2901", "switch"); + +void setup() { + Serial.begin(9600); + + // set LED pin to output mode + pinMode(LED_PIN, OUTPUT); + + // begin initialization + BLE.begin(); + Serial.println(BLE.address()); + + // set advertised local name and service UUID + BLE.setLocalName("LED"); + BLE.setAdvertisedServiceUuid(ledService.uuid()); + + switchCharacteristic.addDescriptor(switchDescriptor); + ledService.addCharacteristic(switchCharacteristic); + + // add service and characteristic + BLE.addService(ledService); + + BLE.startAdvertising(); + + Serial.println(F("BLE LED Peripheral")); +} + +void loop() { + BLEDevice central = BLE.central(); + + if (central) { + // central connected to peripheral + Serial.print(F("Connected to central: ")); + Serial.println(central.address()); + + while (central.connected()) { + // central still connected to peripheral + if (switchCharacteristic.written()) { + // central wrote new value to characteristic, update LED + if (switchCharacteristic.value()) { + Serial.println(F("LED on")); + digitalWrite(LED_PIN, HIGH); + } else { + Serial.println(F("LED off")); + digitalWrite(LED_PIN, LOW); + } + } + } + + // central disconnected + Serial.print(F("Disconnected from central: ")); + Serial.println(central.address()); + } +} diff --git a/libraries/BLE/examples/peripheral/led_callback/led_callback.ino b/libraries/BLE/examples/peripheral/led_callback/led_callback.ino new file mode 100644 index 00000000..f2207837 --- /dev/null +++ b/libraries/BLE/examples/peripheral/led_callback/led_callback.ino @@ -0,0 +1,90 @@ +/* + Arduino BLE Peripheral LED callback example + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// Import libraries +#include + +// LED pin +#define LED_PIN 13 + +// create service +BLEService ledService("19b10000e8f2537e4f6cd104768a1214"); + +// create switch characteristic +BLECharCharacteristic switchCharacteristic("19b10001e8f2537e4f6cd104768a1214", BLERead | BLEWrite); + +void setup() { + Serial.begin(9600); + + // set LED pin to output mode + pinMode(LED_PIN, OUTPUT); + + // begin initialization + BLE.begin(); + + // set advertised local name and service UUID + BLE.setLocalName("LED"); + BLE.setAdvertisedServiceUuid(ledService.uuid()); + + ledService.addCharacteristic(switchCharacteristic); + + // add service + BLE.addService(ledService); + + // assign event handlers for connected, disconnected to peripheral + BLE.setEventHandler(BLEConnected, bleDeviceConnectHandler); + BLE.setEventHandler(BLEDisconnected, bleDeviceDisconnectHandler); + + // assign event handlers for characteristic + switchCharacteristic.setEventHandler(BLEWritten, switchCharacteristicWritten); + + BLE.startAdvertising(); + + Serial.println(F("BLE LED Peripheral")); +} + +void loop() { + // poll peripheral + BLE.poll(); +} + +void bleDeviceConnectHandler(BLEDevice central) { + // central connected event handler + Serial.print(F("Connected event, central: ")); + Serial.println(central.address()); +} + +void bleDeviceDisconnectHandler(BLEDevice central) { + // central disconnected event handler + Serial.print(F("Disconnected event, central: ")); + Serial.println(central.address()); +} + +void switchCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) { + // central wrote new value to characteristic, update LED + Serial.print(F("Characteristic event, writen: ")); + + if (switchCharacteristic.value()) { + Serial.println(F("LED on")); + digitalWrite(LED_PIN, HIGH); + } else { + Serial.println(F("LED off")); + digitalWrite(LED_PIN, LOW); + } +} diff --git a/libraries/BLE/examples/test/central/central.ino b/libraries/BLE/examples/test/central/central.ino new file mode 100644 index 00000000..5b65b3bc --- /dev/null +++ b/libraries/BLE/examples/test/central/central.ino @@ -0,0 +1,86 @@ + +#include "ArduinoBLE.h" + +// LED pin +#define LED_PIN 13 + +void setup() { + Serial.begin(9600); + Serial.println("test---"); + + // set LED pin to output mode + pinMode(LED_PIN, OUTPUT); + + // begin initialization + BLE.begin(); + Serial.println(BLE.address()); + + BLE.startScanning("LED"); +} + +void controlLed(BLEDevice &peripheral) +{ + static bool discovered = false; + // connect to the peripheral + Serial.print("Connecting ... "); + Serial.println(peripheral.address()); + + if (peripheral.connect()) + { + Serial.print("Connected: "); + Serial.println(peripheral.address()); + } + else + { + Serial.println("Failed to connect!"); + return; + } + + peripheral.discoverAttributes(); + + BLECharacteristic ledCharacteristic = peripheral.characteristic("19b10101-e8f2-537e-4f6c-d104768a1214"); + + if (!ledCharacteristic) + { + peripheral.disconnect(); + Serial.println("Peripheral does not have LED characteristic!"); + delay(5000); + return; + } + + + unsigned char ledstate = 0; + + discovered = false; + while (peripheral.connected()) + { + if (ledstate == 1) + { + ledstate = 0; + } + else + { + ledstate = 1; + } + ledCharacteristic.write(&ledstate, sizeof(ledstate)); + delay(5000); + } + Serial.print("Disconnected"); + Serial.println(peripheral.address()); +} + +void loop() { + BLEDevice peripheral = BLE.available(); + if (peripheral) + { + Serial.println(peripheral.address()); + BLE.stopScanning(); + delay (1000); + // central connected to peripheral + controlLed(peripheral); + delay (4000); + BLE.startScanning("LED"); + } +} + + diff --git a/libraries/BLE/examples/test/notification/notification.ino b/libraries/BLE/examples/test/notification/notification.ino new file mode 100644 index 00000000..29d44f59 --- /dev/null +++ b/libraries/BLE/examples/test/notification/notification.ino @@ -0,0 +1,78 @@ + +#include "ArduinoBLE.h" + +// LED pin +#define LED_PIN 13 + +// create service +BLEService ledService("19b10100e8f2537e4f6cd104768a1214"); + +BLECharacteristic switchCharacteristic("19b10101e8f2537e4f6cd104768a1214", BLERead | BLEWrite | BLENotify, 1); + +BLEDescriptor switchDescriptor("2901", "switch"); + +void setup() { + Serial.begin(9600); + Serial.println("test---"); + + // set LED pin to output mode + pinMode(LED_PIN, OUTPUT); + + // begin initialization + BLE.begin(); + Serial.println(BLE.address()); + + // set advertised local name and service UUID + BLE.setLocalName("LED"); + BLE.setAdvertisedServiceUuid(ledService.uuid()); + + // add service and characteristic + BLE.addService(ledService); + ledService.addCharacteristic(switchCharacteristic); + switchCharacteristic.addDescriptor(switchDescriptor); + unsigned char test = 1; + switchCharacteristic.writeValue(&test,1); + BLE.startAdvertising(); +} + +void loop() { + static int i = 0; + BLEDevice central = BLE.central(); + bool temp = central; +i++; + if (temp) { + // central connected to peripheral + Serial.print(i); + Serial.print(F("Connected to central: ")); + Serial.println(central.address()); + + Serial.print(temp); + + unsigned char ledstate = 0; + + while (central.connected()) { + // central still connected to peripheral + if (switchCharacteristic.canNotify()) + { + + if (ledstate == 1) + { + ledstate = 0; + digitalWrite(LED_PIN, LOW); + } + else + { + ledstate = 1; + digitalWrite(LED_PIN, HIGH); + } + switchCharacteristic.writeValue(&ledstate, sizeof(ledstate)); + delay(5000); + } + } + + // central disconnected + Serial.print(F("Disconnected from central: ")); + Serial.println(central.address()); + } + //delay (1000); +} diff --git a/libraries/BLE/examples/test/notifycentral/notifycentral.ino b/libraries/BLE/examples/test/notifycentral/notifycentral.ino new file mode 100644 index 00000000..8f599d7b --- /dev/null +++ b/libraries/BLE/examples/test/notifycentral/notifycentral.ino @@ -0,0 +1,89 @@ + +#include "ArduinoBLE.h" + +// LED pin +#define LED_PIN 13 + +void setup() { + Serial.begin(9600); + Serial.println("test---"); + + // set LED pin to output mode + pinMode(LED_PIN, OUTPUT); + + // begin initialization + BLE.begin(); + Serial.println(BLE.address()); + + BLE.startScanning("LED"); +} + +void controlLed(BLEDevice &peripheral) +{ + static bool discovered = false; + // connect to the peripheral + Serial.print("Connecting ... "); + Serial.println(peripheral.address()); + + if (peripheral.connect()) + { + Serial.print("Connected: "); + Serial.println(peripheral.address()); + } + else + { + Serial.println("Failed to connect!"); + return; + } + + peripheral.discoverAttributes(); + + BLECharacteristic ledCharacteristic = peripheral.characteristic("19b10101-e8f2-537e-4f6c-d104768a1214"); + + if (!ledCharacteristic) + { + peripheral.disconnect(); + Serial.println("Peripheral does not have LED characteristic!"); + delay(5000); + return; + } + ledCharacteristic.subscribe(); + + + discovered = false; + while (peripheral.connected()) + { + if (ledCharacteristic.valueUpdated()) + { + char ledValue = *ledCharacteristic.value(); + + if (ledValue) { + Serial.println(F("LED on")); + digitalWrite(LED_PIN, HIGH); + } else { + Serial.println(F("LED off")); + digitalWrite(LED_PIN, LOW); + } + } + } + Serial.print("Disconnected"); + Serial.println(peripheral.address()); +} + +void loop() { + //pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); + BLEDevice peripheral = BLE.available(); + //pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); + if (peripheral) + { + Serial.println(peripheral.address()); + BLE.stopScanning(); + delay (1000); + // central connected to peripheral + controlLed(peripheral); + delay (4000); + BLE.startScanning("LED"); + } +} + + diff --git a/libraries/BLE/examples/test/test/test.ino b/libraries/BLE/examples/test/test/test.ino new file mode 100644 index 00000000..dd15eb10 --- /dev/null +++ b/libraries/BLE/examples/test/test/test.ino @@ -0,0 +1,71 @@ + +#include "ArduinoBLE.h" + +// LED pin +#define LED_PIN 13 + +// create service +BLEService ledService("19b10100e8f2537e4f6cd104768a1214"); + +BLECharacteristic switchCharacteristic("19b10101e8f2537e4f6cd104768a1214", BLERead | BLEWrite | BLENotify, 1); + +BLEDescriptor switchDescriptor("2901", "switch"); + +void setup() { + Serial.begin(9600); + Serial.println("test---"); + + // set LED pin to output mode + pinMode(LED_PIN, OUTPUT); + + // begin initialization + BLE.begin(); + Serial.println(BLE.address()); + + // set advertised local name and service UUID + BLE.setLocalName("LED"); + BLE.setAdvertisedServiceUuid(ledService.uuid()); + + // add service and characteristic + BLE.addService(ledService); + ledService.addCharacteristic(switchCharacteristic); + switchCharacteristic.addDescriptor(switchDescriptor); + unsigned char test = 1; + switchCharacteristic.writeValue(&test,1); + BLE.startAdvertising(); +} + +void loop() { + static int i = 0; + BLEDevice central = BLE.central(); + bool temp = central; +i++; + if (temp) { + // central connected to peripheral + Serial.print(i); + Serial.print(F("Connected to central: ")); + Serial.println(central.address()); + + Serial.print(temp); + + while (central.connected()) { + // central still connected to peripheral + if (switchCharacteristic.written()) { + char ledValue = *switchCharacteristic.value(); + // central wrote new value to characteristic, update LED + if (ledValue) { + Serial.println(F("LED on")); + digitalWrite(LED_PIN, HIGH); + } else { + Serial.println(F("LED off")); + digitalWrite(LED_PIN, LOW); + } + } + } + + // central disconnected + Serial.print(F("Disconnected from central: ")); + Serial.println(central.address()); + } + //delay (1000); +} diff --git a/libraries/BLE/library.properties b/libraries/BLE/library.properties new file mode 100644 index 00000000..ecdb692d --- /dev/null +++ b/libraries/BLE/library.properties @@ -0,0 +1,9 @@ +name=BLE +version=0.0 +author=Lianggao +maintainer=Lianggao +sentence=Library to manage the Bluetooth Low Energy module with Curie Core boards. +paragraph=Using this library, it is possible to use BLE features to communicate and interact with other devices like smartphones and tablets. This library enables multiple types of functionalities through a number of different classes. +category=Communication +url= +architectures=arc32 diff --git a/libraries/BLE/src/ArduinoBLE.h b/libraries/BLE/src/ArduinoBLE.h new file mode 100644 index 00000000..fc83d81b --- /dev/null +++ b/libraries/BLE/src/ArduinoBLE.h @@ -0,0 +1,47 @@ +/* + BLE API + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ARDUINO_BLE_H +#define ARDUINO_BLE_H + +#define ARDUINO_BLE_API_VERSION 10000 // version 1.0.0 + +class BLEDevice; +class BLECharacteristic; +class BLEDescriptor; +class BLEService; +class BLECharacteristicImp; +class BLEDescriptorImp; + +#include "BLECommon.h" + +#include "BLEDevice.h" +#include "BLEAttributeWithValue.h" +#include "BLECharacteristic.h" +#include "BLEDescriptor.h" +#include "BLEService.h" + +#include "BLETypedCharacteristics.h" + +#include "BLECentral.h" +#include "BLEPeripheral.h" + +extern BLEDevice BLE; + +#endif diff --git a/libraries/BLE/src/BLEAttribute.cpp b/libraries/BLE/src/BLEAttribute.cpp new file mode 100644 index 00000000..b3e3b711 --- /dev/null +++ b/libraries/BLE/src/BLEAttribute.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "ArduinoBLE.h" +#include "BLEAttribute.h" + +#include "./internal/BLEUtils.h" + + +BLEAttribute::BLEAttribute(const char* uuid, BLEAttributeType type) : + _type(type) +{ + memset(&_uuid, 0, sizeof (_uuid)); + BLEUtils::uuidString2BT(uuid, (bt_uuid_t*)&_uuid); +} + +BLEAttribute::BLEAttribute(const bt_uuid_t* uuid, BLEAttributeType type) : + _type(type) +{ + memcpy(&_uuid, uuid, sizeof (_uuid)); +} + +const bt_uuid_t *BLEAttribute::bt_uuid(void) +{ + return (bt_uuid_t *)&_uuid; +} + + +BLEAttributeType +BLEAttribute::type() const { + return this->_type; +} + +bool BLEAttribute::compareUuid(const bt_uuid_t* uuid) +{ + int cmpresult = 0; + cmpresult = bt_uuid_cmp(uuid, (const bt_uuid_t*)&_uuid); + return (cmpresult == 0); + +} + +bool BLEAttribute::compareUuid(const char* uuid) +{ + bt_uuid_128_t temp; + BLEUtils::uuidString2BT(uuid,(bt_uuid_t *)&temp); + return compareUuid((bt_uuid_t *)&temp); +} + diff --git a/libraries/BLE/src/BLEAttribute.h b/libraries/BLE/src/BLEAttribute.h new file mode 100644 index 00000000..db69cf32 --- /dev/null +++ b/libraries/BLE/src/BLEAttribute.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _BLE_ATTRIBUTE_H_INCLUDED +#define _BLE_ATTRIBUTE_H_INCLUDED + +#include "BLECommon.h" + +/// BLE attribute tyep enum +typedef enum { + BLETypeService = 0x2800, ///< the service type + BLETypeCharacteristic = 0x2803, ///< the characteristic type + BLETypeDescriptor = 0x2900 ///< the descriptor type +}BLEAttributeType; + + +class BLEAttribute { +public: + /** + * @brief Get the UUID raw data + * + * @param none + * + * @return bt_uuid_t* The pointer of UUID + * + * @note none + */ + const bt_uuid_t *bt_uuid(void); + + /** + * @brief Compare the UUID with the paramater data + * + * @param[in] data The pointer of data + * + * @param[in] uuidsize The max size of UUID + * + * @return bool true - UUID is the same with data + * false- UUID is not the same with data + * + * @note none + */ + bool compareUuid(const char* uuid); + bool compareUuid(const bt_uuid_t* uuid); + + BLEAttributeType type(void) const; + +protected: + BLEAttribute(const char* uuid, BLEAttributeType type); + BLEAttribute(const bt_uuid_t* uuid, BLEAttributeType type); +private: + bt_uuid_128_t _uuid; + + BLEAttributeType _type; + +}; + +#endif // _BLE_ATTRIBUTE_H_INCLUDED diff --git a/libraries/BLE/src/BLEAttributeWithValue.cpp b/libraries/BLE/src/BLEAttributeWithValue.cpp new file mode 100644 index 00000000..88c629f1 --- /dev/null +++ b/libraries/BLE/src/BLEAttributeWithValue.cpp @@ -0,0 +1,181 @@ +/* + BLE Attribute with value API + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "Arduino.h" +#include "BLEAttributeWithValue.h" + +BLEAttributeWithValue::BLEAttributeWithValue() +{ + +} + + // intepret the value of the attribute with the specified type +String BLEAttributeWithValue::stringValue() const +{ + const char *retTemp = (const char *)this->value(); + return retTemp; +} + +char BLEAttributeWithValue::charValue() const +{ + char ret = this->operator[](0); + return ret; +} + +unsigned char BLEAttributeWithValue::unsignedCharValue() const +{ + unsigned char ret = this->operator[](0); + return ret; +} + +byte BLEAttributeWithValue::byteValue() const +{ + return this->operator[](0); +} + +short BLEAttributeWithValue::shortValue() const +{ + short retTmp = 0; + memcpy(&retTmp, this->value(), sizeof(retTmp)); + return retTmp; +} + +unsigned short BLEAttributeWithValue::unsignedShortValue() const +{ + unsigned short retTmp = 0; + memcpy(&retTmp, this->value(), sizeof(retTmp)); + return retTmp; +} + +int BLEAttributeWithValue::intValue() const +{ + int retTmp = 0; + memcpy(&retTmp, this->value(), sizeof(retTmp)); + return retTmp; +} + +unsigned int BLEAttributeWithValue::unsignedIntValue() const +{ + unsigned int retTmp = 0; + memcpy(&retTmp, this->value(), sizeof(retTmp)); + return retTmp; +} + +long BLEAttributeWithValue::longValue() const +{ + long retTmp = 0; + memcpy(&retTmp, this->value(), sizeof(retTmp)); + return retTmp; +} + +unsigned long BLEAttributeWithValue::unsignedLongValue() const +{ + unsigned long retTmp = 0; + memcpy(&retTmp, this->value(), sizeof(retTmp)); + return retTmp; +} + +float BLEAttributeWithValue::floatValue() const +{ + float retTmp = 0; + memcpy(&retTmp, this->value(), sizeof(retTmp)); + return retTmp; +} + +double BLEAttributeWithValue::doubleValue() const +{ + double retTmp = 0; + memcpy(&retTmp, this->value(), sizeof(retTmp)); + return retTmp; +} + +// write the value of the attribute with the specified type +bool BLEAttributeWithValue::writeString(const String& s) +{ + if (s.length() > (unsigned int)this->valueSize()) + { + return false; + } + return this->writeValue((const byte*)s.c_str(), s.length()); +} + +bool BLEAttributeWithValue::writeString(const char* s) +{ + if (strlen(s) > (unsigned int)this->valueSize()) + { + return false; + } + return this->writeValue((const byte*)s, strlen(s)); +} + +bool BLEAttributeWithValue::writeChar(char c) +{ + return this->writeValue((const byte*)&c, sizeof(c)); +} + +bool BLEAttributeWithValue::writeUnsignedChar(unsigned char c) +{ + return this->writeValue((const byte*)&c, sizeof(c)); +} + +bool BLEAttributeWithValue::writeByte(byte b) +{ + return this->writeValue((const byte*)&b, sizeof(b)); +} + +bool BLEAttributeWithValue::writeShort(short s) +{ + return this->writeValue((const byte*)&s, sizeof(s)); +} + +bool BLEAttributeWithValue::writeUnsignedShort(unsigned short s) +{ + return this->writeValue((const byte*)&s, sizeof(s)); +} + +bool BLEAttributeWithValue::writeInt(int i) +{ + return this->writeValue((const byte*)&i, sizeof(i)); +} + +bool BLEAttributeWithValue::writeUnsignedInt(unsigned int i) +{ + return this->writeValue((const byte*)&i, sizeof(i)); +} + +bool BLEAttributeWithValue::writeLong(long l) +{ + return this->writeValue((const byte*)&l, sizeof(l)); +} + +bool BLEAttributeWithValue::writeUnsignedLong(unsigned int l) +{ + return this->writeValue((const byte*)&l, sizeof(l)); +} + +bool BLEAttributeWithValue::writeFloat(float f) +{ + return this->writeValue((const byte*)&f, sizeof(f)); +} + +bool BLEAttributeWithValue::writeDouble(double d) +{ + return this->writeValue((const byte*)&d, sizeof(d)); +} + + diff --git a/libraries/BLE/src/BLEAttributeWithValue.h b/libraries/BLE/src/BLEAttributeWithValue.h new file mode 100644 index 00000000..96971d56 --- /dev/null +++ b/libraries/BLE/src/BLEAttributeWithValue.h @@ -0,0 +1,63 @@ +/* + BLE Attribute with value API + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ARDUINO_BLE_ATTRIBUTE_WITH_VALUE__H +#define ARDUINO_BLE_ATTRIBUTE_WITH_VALUE__H + +class BLEAttributeWithValue +{ + public: + BLEAttributeWithValue(); + + virtual int valueSize() const = 0; // returns the length of the attribute value + virtual const byte* value() const = 0; // returns the value of the attribute array + virtual byte operator[] (int offset) const = 0; // access an attribute value at the specified offset + virtual bool writeValue(const byte value[], int length) = 0; + + // intepret the value of the attribute with the specified type + String stringValue() const; + char charValue() const; + unsigned char unsignedCharValue() const; + byte byteValue() const; + short shortValue() const; + unsigned short unsignedShortValue() const; + int intValue() const; + unsigned int unsignedIntValue() const; + long longValue() const; + unsigned long unsignedLongValue() const; + float floatValue() const; + double doubleValue() const; + + // write the value of the attribute with the specified type + bool writeString(const String& s); + bool writeString(const char* s); + bool writeChar(char c); + bool writeUnsignedChar(unsigned char c); + bool writeByte(byte b); + bool writeShort(short s); + bool writeUnsignedShort(unsigned short s); + bool writeInt(int i); + bool writeUnsignedInt(unsigned int i); + bool writeLong(long l); + bool writeUnsignedLong(unsigned int l); + bool writeFloat(float f); + bool writeDouble(double d); +}; + +#endif diff --git a/libraries/BLE/src/BLECentral.cpp b/libraries/BLE/src/BLECentral.cpp new file mode 100644 index 00000000..a751060e --- /dev/null +++ b/libraries/BLE/src/BLECentral.cpp @@ -0,0 +1,61 @@ +/* + BLE Central API (deprecated) + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "ArduinoBLE.h" + +BLECentral::BLECentral(BLEDevice& device) : + _device(&device) +{ + +} + +bool BLECentral::connected(void) +{ + return _device.connected(); +} + +const char* BLECentral::address(void) const +{ + return _device.address().c_str(); +} + +bool BLECentral::disconnect(void) +{ + return _device.disconnect(); +} + +void BLECentral::poll(void) +{ + _device.poll(); +} + +BLECentral::operator bool(void) const +{ + return _device; +} + +bool BLECentral::operator==(const BLECentral& rhs) const +{ + return (_device == rhs._device); +} + +bool BLECentral::operator!=(const BLECentral& rhs) const +{ + return (_device != rhs._device); +} \ No newline at end of file diff --git a/libraries/BLE/src/BLECentral.h b/libraries/BLE/src/BLECentral.h new file mode 100644 index 00000000..b6148e12 --- /dev/null +++ b/libraries/BLE/src/BLECentral.h @@ -0,0 +1,45 @@ +/* + BLE Central API (deprecated) + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ARDUINO_CENTRAL_H +#define ARDUINO_CENTRAL_H + +class BLECentral { + public: + bool connected(void); // is the central connected + + const char* address(void) const; // address of the Central in string form + + bool disconnect(void); // Disconnect the central if it is connected + void poll(void); // Poll the central for events + + operator bool(void) const; + bool operator==(const BLECentral& rhs) const; + bool operator!=(const BLECentral& rhs) const; +protected: + friend void bleBackCompatiblePeripheralConnectHandler(BLEDevice central); + friend void bleBackCompatiblePeripheralDisconnectHandler(BLEDevice central); + friend class BLEPeripheral; + BLECentral(BLEDevice& device); + private: + + BLEDevice _device; +}; + +#endif \ No newline at end of file diff --git a/libraries/BLE/src/BLECharacteristic.cpp b/libraries/BLE/src/BLECharacteristic.cpp new file mode 100644 index 00000000..8c0451d7 --- /dev/null +++ b/libraries/BLE/src/BLECharacteristic.cpp @@ -0,0 +1,512 @@ + +#include "ArduinoBLE.h" + +#include "./internal/BLEUtils.h" + +#include "BLECharacteristic.h" +#include "./internal/BLEProfileManager.h" + +#include "./internal/BLECharacteristicImp.h" + +BLECharacteristic::BLECharacteristic(): + _bledev(), _internal(NULL), _properties(0), + _value_size(0), _value(NULL) +{ + memset(_uuid_cstr, 0, sizeof(_uuid_cstr)); + memset(_event_handlers, 0, sizeof(_event_handlers)); +} + +BLECharacteristic::BLECharacteristic(const char* uuid, + unsigned char properties, + unsigned short valueSize): + _bledev(), _internal(NULL), _properties(properties), _value(NULL) +{ + bt_uuid_128 bt_uuid_tmp; + _value_size = valueSize > BLE_MAX_ATTR_LONGDATA_LEN ? BLE_MAX_ATTR_LONGDATA_LEN : valueSize; + BLEUtils::uuidString2BT(uuid, (bt_uuid_t *)&bt_uuid_tmp); + BLEUtils::uuidBT2String((const bt_uuid_t *)&bt_uuid_tmp, _uuid_cstr); + _bledev.setAddress(*BLEUtils::bleGetLoalAddress()); + memset(_event_handlers, 0, sizeof(_event_handlers)); +} + +BLECharacteristic::BLECharacteristic(const char* uuid, + unsigned char properties, + const char* value): + BLECharacteristic(uuid, properties, strlen(value)) +{ + _setValue((const uint8_t*)value, strlen(value)); +} + +BLECharacteristic::BLECharacteristic(BLECharacteristicImp *characteristicImp, + const BLEDevice *bleDev): + _bledev(bleDev), _internal(characteristicImp), + _value(NULL) +{ + BLEUtils::uuidBT2String(characteristicImp->bt_uuid(), _uuid_cstr); + _properties = characteristicImp->properties(); + _value_size = characteristicImp->valueSize(); + memset(_event_handlers, 0, sizeof(_event_handlers)); +} + +BLECharacteristic::BLECharacteristic(const BLECharacteristic& rhs) +{ + _value = (unsigned char*)malloc(rhs._value_size); // Sid. KW: _value should not make local here + if (_value) { + memcpy(_value, rhs._value, rhs._value_size); + _value_size = rhs._value_size; + } else { + _value_size = 0; + } + memcpy(_uuid_cstr, rhs._uuid_cstr, sizeof(_uuid_cstr)); + _properties = rhs._properties; + memcpy(_event_handlers, rhs._event_handlers, sizeof(_event_handlers)); + _internal = rhs._internal; + _bledev = BLEDevice(&rhs._bledev); +} + +BLECharacteristic& BLECharacteristic::operator= (const BLECharacteristic& rhs) +{ + if (this != &rhs) + { + if (_value) + { + free(_value); + } + _value = (unsigned char*)malloc(rhs._value_size); + if (_value) + { + memcpy(_value, rhs._value, rhs._value_size); + _value_size = rhs._value_size; + } else { + _value_size = 0; + } + memcpy(_uuid_cstr, rhs._uuid_cstr, sizeof(_uuid_cstr)); + _properties = rhs._properties; + memcpy(_event_handlers, rhs._event_handlers, sizeof(_event_handlers)); + _internal = rhs._internal; + _bledev = BLEDevice(&rhs._bledev); + } + return *this; +} + +BLECharacteristic::~BLECharacteristic() +{ + if (_value) + { + free(_value); + } +} + +const char* BLECharacteristic::uuid() const +{ + return _uuid_cstr; +} + +unsigned char BLECharacteristic::properties() const +{ + unsigned char property = 0; + BLECharacteristicImp *characteristicImp = getImplementation(); + if (NULL != characteristicImp) + { + property = characteristicImp->properties(); + } + return property; +} + +int BLECharacteristic::valueSize() const +{ + int valuesize = 0; + BLECharacteristicImp *characteristicImp = getImplementation(); + if (NULL != characteristicImp) + { + valuesize = characteristicImp->valueSize(); + } + return valuesize; +} + +const byte* BLECharacteristic::value() const +{ + const byte* value_temp = NULL; + BLECharacteristicImp *characteristicImp = _internal;//getImplementation(); + if (NULL != characteristicImp) + { + value_temp = characteristicImp->value(); + } + return value_temp; +} + +int BLECharacteristic::valueLength() const +{ + int valueLength = 0; + BLECharacteristicImp *characteristicImp = getImplementation(); + if (NULL != characteristicImp) + { + valueLength = characteristicImp->valueLength(); + } + return valueLength; +} + +BLECharacteristic::operator bool() const +{ + return (strlen(_uuid_cstr) > 3); +} + + +byte BLECharacteristic::operator[] (int offset) const +{ + byte data = 0; + BLECharacteristicImp *characteristicImp = getImplementation(); + + if (NULL != characteristicImp) + { + data = (*characteristicImp)[offset]; + } + return data; +} + +bool BLECharacteristic::setValue(const unsigned char value[], unsigned short length) +{ + return writeValue(value, (int)length); +} + +bool BLECharacteristic::writeValue(const byte value[], int length) +{ + bool retVar = false; + BLECharacteristicImp *characteristicImp = getImplementation(); + + if (NULL != characteristicImp) + { + characteristicImp->writeValue(value, length); + retVar = true; + } + return writeValue(value, length, 0); +} + +bool BLECharacteristic::writeValue(const byte value[], int length, int offset) +{ + bool retVar = false; + BLECharacteristicImp *characteristicImp = getImplementation(); + + if (NULL != characteristicImp) + { + characteristicImp->writeValue(value, length, offset); + retVar = true; + } + return retVar; +} + +bool BLECharacteristic::writeValue(const char* value) +{ + return writeValue((const byte*)value, strlen(value)); +} + +bool BLECharacteristic::broadcast() +{ + // TODO: Need more information + return false; +} + +bool BLECharacteristic::written() +{ + bool retVar = false; + BLECharacteristicImp *characteristicImp = getImplementation(); + + if (NULL != characteristicImp) + { + retVar = characteristicImp->written(); + } + return retVar; +} + +bool BLECharacteristic::subscribed() +{ + bool retVar = false; + BLECharacteristicImp *characteristicImp = getImplementation(); + + if (NULL != characteristicImp) + { + retVar = characteristicImp->subscribed(); + } + return retVar; +} + +bool BLECharacteristic::canNotify() +{ + bool retVar = false; + BLECharacteristicImp *characteristicImp = getImplementation(); + + if (NULL != characteristicImp) + { + retVar = characteristicImp->canNotify(); + } + return retVar; +} + +bool BLECharacteristic::canIndicate() +{ + bool retVar = false; + BLECharacteristicImp *characteristicImp = getImplementation(); + + if (NULL != characteristicImp) + { + retVar = characteristicImp->canIndicate(); + } + return retVar; +} + +bool BLECharacteristic::canRead() +{ + // TODO: Need more confirmation + return false; +} +bool BLECharacteristic::canWrite() +{ + // TODO: Need more confirmation + return false; +} +bool BLECharacteristic::canSubscribe() +{ + // TODO: Need more confirmation + return false; +} +bool BLECharacteristic::canUnsubscribe() +{ + // TODO: Need more confirmation + return false; +} + +bool BLECharacteristic::read() +{ + bool retVar = false; + BLECharacteristicImp *characteristicImp = getImplementation(); + + if (NULL != characteristicImp) + { + retVar = characteristicImp->read(); + } + return retVar; +} + +bool BLECharacteristic::write(const unsigned char* value, int length) +{ + bool retVar = false; + BLECharacteristicImp *characteristicImp = getImplementation(); + + if (NULL != characteristicImp) + { + retVar = characteristicImp->write(value, (uint16_t)length); + } + return retVar; +} + +bool BLECharacteristic::subscribe() +{ + bool retVar = false; + BLECharacteristicImp *characteristicImp = getImplementation(); + + if (NULL != characteristicImp) + { + retVar = characteristicImp->subscribe(); + } + return retVar; +} + +bool BLECharacteristic::unsubscribe() +{ + bool retVar = false; + BLECharacteristicImp *characteristicImp = getImplementation(); + + if (NULL != characteristicImp) + { + retVar = characteristicImp->unsubscribe(); + } + return retVar; +} + +bool BLECharacteristic::valueUpdated() +{ + bool retVar = false; + BLECharacteristicImp *characteristicImp = getImplementation(); + + if (NULL != characteristicImp) + { + retVar = characteristicImp->valueUpdated(); + } + return retVar; +} + +int BLECharacteristic::addDescriptor(BLEDescriptor& descriptor) +{ + bool retVar = false; + BLECharacteristicImp *characteristicImp = getImplementation(); + + if (NULL != characteristicImp) + { + retVar = characteristicImp->addDescriptor(descriptor); + } + return retVar; +} + +int BLECharacteristic::descriptorCount() const +{ + int count = 0; + BLECharacteristicImp *characteristicImp = getImplementation(); + + if (NULL != characteristicImp) + { + count = characteristicImp->descriptorCount(); + } + return count; +} + +bool BLECharacteristic::hasDescriptor(const char* uuid) const +{ + BLEDescriptorImp* descriptorImp = NULL; + BLECharacteristicImp *characteristicImp = getImplementation(); + + if (NULL != characteristicImp) + { + descriptorImp = characteristicImp->descrptor(uuid); + } + + return (descriptorImp != NULL); +} + +bool BLECharacteristic::hasDescriptor(const char* uuid, int index) const +{ + bool retVal = false; + BLEDescriptorImp* descriptorImp = NULL; + BLECharacteristicImp *characteristicImp = getImplementation(); + + if (NULL != characteristicImp) + { + descriptorImp = characteristicImp->descrptor(index); + if (NULL != descriptorImp) + { + retVal = descriptorImp->compareUuid(uuid); + } + } + + return retVal; +} + +BLEDescriptor BLECharacteristic::descriptor(int index) const +{ + BLEDescriptorImp* descriptorImp = NULL; + BLECharacteristicImp *characteristicImp = getImplementation(); + + if (NULL != characteristicImp) + { + descriptorImp = characteristicImp->descrptor(index); + } + + if (descriptorImp != NULL) + { + return BLEDescriptor(descriptorImp, &_bledev); + } + else + { + return BLEDescriptor(); + } +} +BLEDescriptor BLECharacteristic::descriptor(const char * uuid) const +{ + BLEDescriptorImp* descriptorImp = NULL; + BLECharacteristicImp *characteristicImp = getImplementation(); + + if (NULL != characteristicImp) + { + descriptorImp = characteristicImp->descrptor(uuid); + } + + if (descriptorImp != NULL) + { + return BLEDescriptor(descriptorImp, &_bledev); + } + else + { + return BLEDescriptor(); + } +} + +BLEDescriptor BLECharacteristic::descriptor(const char * uuid, int index) const +{ + bool retVal = false; + BLEDescriptorImp* descriptorImp = NULL; + BLECharacteristicImp *characteristicImp = getImplementation(); + + if (NULL != characteristicImp) + { + descriptorImp = characteristicImp->descrptor(index); + if (NULL != descriptorImp) + { + retVal = descriptorImp->compareUuid(uuid); + } + } + + if (descriptorImp != NULL && true == retVal) + { + return BLEDescriptor(descriptorImp, &_bledev); + } + else + { + return BLEDescriptor(); + } +} + +void BLECharacteristic::setEventHandler(BLECharacteristicEvent event, + BLECharacteristicEventHandler eventHandler) +{ + BLECharacteristicImp *characteristicImp = getImplementation(); + if (event >= BLECharacteristicEventLast) + { + return; + } + + if (NULL != characteristicImp) + { + characteristicImp->setEventHandler(event, eventHandler); + } + else + { + _event_handlers[event] = eventHandler; + } +} + + +void +BLECharacteristic::_setValue(const uint8_t value[], uint16_t length) +{ + if (length > _value_size) { + length = _value_size; + } + + if (NULL == _value) + { + // Allocate the buffer for characteristic + _value = (unsigned char*)malloc(_value_size); + } + if (NULL == _value) + { + return; + } + memcpy(_value, value, length); +} + +BLECharacteristicImp* BLECharacteristic::getImplementation() const +{ + BLECharacteristicImp* tmp = NULL; + tmp = _internal; + if (NULL == tmp) + { + tmp = BLEProfileManager::instance()->characteristic(_bledev, (const char*)_uuid_cstr); + } + return tmp; +} + +void BLECharacteristic::setBLECharacteristicImp(BLECharacteristicImp *characteristicImp) +{ + _internal = characteristicImp; +} + + diff --git a/libraries/BLE/src/BLECharacteristic.h b/libraries/BLE/src/BLECharacteristic.h new file mode 100644 index 00000000..f8a346bc --- /dev/null +++ b/libraries/BLE/src/BLECharacteristic.h @@ -0,0 +1,529 @@ +/* + BLE Characteristic API + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ARDUINO_BLE_CHARACTERISTIC_H +#define ARDUINO_BLE_CHARACTERISTIC_H + +#include "ArduinoBLE.h" + +#include "BLEDevice.h" + +enum BLECharacteristicEvent { + BLEWritten = 0, + BLESubscribed = 1, + BLEUnsubscribed = 2, + BLEValueUpdated = 3, + BLECharacteristicEventLast +}; + +enum BLEProperty { + BLEBroadcast = 0x01, + BLERead = 0x02, + BLEWriteWithoutResponse = 0x04, + BLEWrite = 0x08, + BLENotify = 0x10, + BLEIndicate = 0x20 +}; + +typedef void (*BLECharacteristicEventHandler)(BLEDevice bledev, BLECharacteristic characteristic); + +//#include "BLECharacteristicImp.h" + +class BLECharacteristic: public BLEAttributeWithValue +{ +public: + BLECharacteristic(); + /** + * @brief Create a characteristic with specified value size + * + * @param uuid The UUID of the characteristic + * + * @param properties The properties of the characteristic + * + * @param valueSize The size of the characteristic data + * + * @return none + * + * @note none + */ + BLECharacteristic(const char* uuid, + unsigned char properties, + unsigned short valueSize); + + /** + * @brief Create a characteristic with string value + * + * @param uuid The UUID of the characteristic + * + * @param properties The properties of the characteristic + * + * @param value The string of the characteristic data + * + * @return none + * + * @note The data length is string's size. Can't set a string that is longger + * than the this input + */ + BLECharacteristic(const char* uuid, + unsigned char properties, + const char* value); + + BLECharacteristic(const BLECharacteristic&); + + BLECharacteristic& operator=(const BLECharacteristic&); + + virtual ~BLECharacteristic(); + + /** + * @brief Is the characteristic valid + * + * @param none + * + * @return bool true/false + * + * @note Invalid characteristic is NULL pointer or all zero with UUID + */ + virtual operator bool() const; // + + /** + * @brief Get the characteristic's UUID string + * + * @param none + * + * @return const char* The UUID string + * + * @note none + */ + const char* uuid() const; + + /** + * @brief Get the property mask of the characteristic + * + * @param none + * + * @return unsigned char The property mask of the characteristic + * + * @note none + */ + unsigned char properties() const; + + /** + * @brief Get the maximum size of the value + * + * @param none + * + * @return int The maximum size of the value + * + * @note none + */ + int valueSize() const; + + /** + * @brief Get the value buffer + * + * @param none + * + * @return const byte* The value buffer + * + * @note none + */ + virtual const byte* value() const; + + /** + * @brief Get the current length of the value + * + * @param none + * + * @return int The current length of the value string + * + * @note TODO: How to handle if the data is RAW data? This API is danger + */ + virtual int valueLength() const; + + /** + * @brief Get a byte of the value at the specified offset + * + * @param none + * + * @return byte A byte of the value at the specified offset + * + * @note none + */ + virtual byte operator[] (int offset) const; + + /** + * Set the current value of the Characteristic + * + * @param[in] value New value to set, as a byte array. Data is stored in internal copy. + * @param[in] length Length, in bytes, of valid data in the array to write. + * Must not exceed maxLength set for this characteristic. + * + * @return bool true set value success, false on error + * @note GATT Server only + */ + bool setValue(const unsigned char value[], unsigned short length); + + /** + * @brief Write the value of the characteristic + * + * @param value The value buffer that want to write to characteristic + * + * @param length The value buffer's length + * + * @return bool true - Success, false - Failed + * + * @note none + */ + virtual bool writeValue(const byte value[], int length); + + /** + * @brief Write the value of the characteristic + * + * @param value The value buffer that want to write to characteristic + * + * @param length The value buffer's length + * + * @param offset The offset in the characteristic's data + * + * @return bool true - Success, false - Failed + * + * @note none + */ + bool writeValue(const byte value[], int length, int offset); + + /** + * @brief Write the value of the characteristic + * + * @param value The value string that want to write to characteristic + * + * @return bool true - Success, false - Failed + * + * @note none + */ + bool writeValue(const char* value); + + // peripheral mode + bool broadcast(); // broadcast the characteristic value in the advertisement data + + // GATT server + /** + * @brief Has the GATT client written a new value + * + * @param none + * + * @return bool true - Written, false - Not changed + * + * @note GATT server only. GATT client always return false. + */ + bool written(); + + /** + * @brief Is the GATT client subscribed + * + * @param none + * + * @return bool true - Subscribed, false - Not subscribed + * + * @note GATT server and client + */ + bool subscribed(); + + /** + * @brief Can a notification be sent to the GATT client + * + * @param none + * + * @return true - Yes, false - No + * + * @note GATT server only + */ + bool canNotify(); + + /** + * @brief Can a indication be sent to the GATT client + * + * @param none + * + * @return true - Yes, false - No + * + * @note GATT server only + */ + bool canIndicate(); + + // GATT + /** + * @brief Can the characteristic be read (based on properties) + * + * @param none + * + * @return true - readable, false - None + * + * @note none + */ + bool canRead(); + + /** + * @brief Can the characteristic be written (based on properties) + * + * @param none + * + * @return true - writable, false - None + * + * @note none + */ + bool canWrite(); + + /** + * @brief Can the characteristic be subscribed to (based on properties) + * + * @param none + * + * @return true - Can be subscribed, false - No + * + * @note What different with canUnsubscribe? + */ + bool canSubscribe(); + + /** + * @brief Can the characteristic be unsubscribed to (based on properties) + * + * @param none + * + * @return true - Can be unsubscribed, false - No + * + * @note none + */ + bool canUnsubscribe(); + + /** + * @brief Read the characteristic value + * + * @param none + * + * @return bool true - Success, false - Failed + * + * @note Only for GATT client. Schedule read request to the GATT server + */ + virtual bool read(); + + /** + * @brief Write the charcteristic value + * + * @param value The value buffer that want to write to characteristic + * + * @param length The value buffer's length + * + * @return bool true - Success, false - Failed + * + * @note Only for GATT client. Schedule write request to the GATT server + */ + virtual bool write(const unsigned char* value, int length); + + /** + * @brief Subscribe to the characteristic + * + * @param none + * + * @return bool true - Success, false - Failed + * + * @note Only for GATT client. Schedule CCCD to the GATT server + */ + bool subscribe(); + + /** + * @brief Unsubscribe to the characteristic + * + * @param none + * + * @return bool true - Success, false - Failed + * + * @note Only for GATT client. Schedule CCCD to the GATT server + */ + bool unsubscribe(); + + + /** + * @brief Read response or notification updated the characteristic + * + * @param none + * + * @return bool true - Written, false - Not changed + * + * @note GATT client only. GATT server always return false. + */ + bool valueUpdated(); + + /** + * @brief Add the characteristic's descriptor + * + * @param descriptor The descriptor for characteristic + * + * @return none + * + * @note none + */ + int addDescriptor(BLEDescriptor& descriptor); + + /** + * @brief Get the number of descriptors the characteristic has + * + * @param none + * + * @return int the number of descriptors the characteristic has + * + * @note none + */ + int descriptorCount() const; + + /** + * @brief Does the characteristic have a descriptor with the specified UUID + * + * @param uuid The descriptor's UUID + * + * @return bool true - Yes. false - No + * + * @note none + */ + bool hasDescriptor(const char* uuid) const; + + /** + * @brief Does the characteristic have an nth descriptor with the specified UUID + * + * @param uuid The descriptor's UUID + * + * @param index The index of descriptor + * + * @return bool true - Yes. false - No + * + * @note none + */ + bool hasDescriptor(const char* uuid, int index) const; + + /** + * @brief Get the nth descriptor of the characteristic + * + * @param index The index of descriptor + * + * @return BLEDescriptor The descriptor + * + * @note none + */ + BLEDescriptor descriptor(int index) const; + + /** + * @brief Get the descriptor with the specified UUID + * + * @param uuid The descriptor's UUID + * + * @return BLEDescriptor The descriptor + * + * @note none + */ + BLEDescriptor descriptor(const char * uuid) const; + + /** + * @brief Get the nth descriptor with the specified UUID + * + * @param uuid The descriptor's UUID + * + * @param index The index of descriptor + * + * @return BLEDescriptor The descriptor + * + * @note none + */ + BLEDescriptor descriptor(const char * uuid, int index) const; + + /** + * @brief Set an event handler (callback) + * + * @param event Characteristic event + * + * @param eventHandler The handler of characteristic + * + * @return none + * + * @note none + */ + void setEventHandler(BLECharacteristicEvent event, + BLECharacteristicEventHandler eventHandler); + +protected: + friend class BLEDevice; + friend class BLEService; + /** + * @brief Create a characteristic with specified value size + * + * @param characteristicImp The implementation of the characteristic + * + * @param bleDev The peer BLE device + * + * @return none + * + * @note none + */ + BLECharacteristic(BLECharacteristicImp *characteristicImp, + const BLEDevice *bleDev); + + /** + * @brief Create a characteristic with string value + * + * @param uuid The UUID of the characteristic + * + * @param properties The properties of the characteristic + * + * @param value The string of the characteristic data + * + * @param bleDev The peer BLE device + * + * @return none + * + * @note The data length is string's size. Can't set a string that is longger + * than the this input + */ + //BLECharacteristic(const char* uuid, + // unsigned char properties, + // const char* value, + // BLEDevice *bleDev); + + // For GATT + void setBLECharacteristicImp(BLECharacteristicImp *characteristicImp); + +private: + void _setValue(const uint8_t value[], uint16_t length); + BLECharacteristicImp *getImplementation() const; + +private: + char _uuid_cstr[37]; // The characteristic UUID + BLEDevice _bledev; // The GATT server BLE object. Only for GATT client to read/write + // NULL - GATT server + // None-NULL - GATT client + BLECharacteristicImp *_internal; // The real implementation of characteristic. +protected: + friend class BLECharacteristicImp; + unsigned char _properties; // The characteristic property + + unsigned short _value_size; // The value size + unsigned char* _value; // The value. Will delete after create the _internal + + BLECharacteristicEventHandler _event_handlers[BLECharacteristicEventLast]; // Sid. Define the arr as in BLECharacteristicImp.h +}; + +#endif + diff --git a/libraries/BLE/src/BLECommon.h b/libraries/BLE/src/BLECommon.h new file mode 100644 index 00000000..cfd90a79 --- /dev/null +++ b/libraries/BLE/src/BLECommon.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2015 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _BLE_COMMON_H_INCLUDED +#define _BLE_COMMON_H_INCLUDED + +#include "Arduino.h" +//#include "ArduinoBLE.h" + +#include "../src/services/ble_service/ble_protocol.h" + + +#include "infra/log.h" + + +#include +#include +#include +#include +//#include + +#define BLE_ADDR_LEN 6 + +#define UUID_SIZE_128 16 +#define UUID_SIZE_16 2 +#define MAX_UUID_SIZE UUID_SIZE_128 + +/* Theoretically we should be able to support attribute lengths up to 512 bytes + * but this involves splitting it across multiple packets. For simplicity, + * we will just limit this to 20 bytes for now, which will fit in a single packet + */ +#define BLE_MAX_ATTR_DATA_LEN 20 +#define BLE_MAX_ATTR_LONGDATA_LEN 512 + +/* Default device name prefix, applied only if user does not provide a name + * If a factory-configured MAC address is defined, the last 2 bytes of the + * address will be appended to the device name */ +#define BLE_DEVICE_NAME_DEFAULT_PREFIX "Arduino101" + +/* Invalid BLE Address type */ +#define BLE_DEVICE_ADDR_INVALID 0xFF + +#if 0 +/** BLE response/event status codes. */ +enum BLE_STATUS { + BLE_STATUS_SUCCESS = 0, /**< General BLE Success code */ + BLE_STATUS_PENDING, /**< Request received and execution started, response pending */ + BLE_STATUS_TIMEOUT, /**< Request timed out */ + BLE_STATUS_NOT_SUPPORTED, /**< Request/feature/parameter not supported */ + BLE_STATUS_NOT_ALLOWED, /**< Request not allowed */ + BLE_STATUS_LINK_TIMEOUT, /**< Link timeout (link loss) */ + BLE_STATUS_NOT_ENABLED, /**< BLE not enabled, @ref ble_enable */ + BLE_STATUS_ERROR, /**< Generic Error */ + BLE_STATUS_ALREADY_REGISTERED, /**< BLE service already registered */ + BLE_STATUS_WRONG_STATE, /**< Wrong state for request */ + BLE_STATUS_ERROR_PARAMETER, /**< Parameter in request is wrong */ + BLE_STATUS_NO_MEMORY, /**< System doesn't have memory */ + BLE_STATUS_GAP_BASE = 0x100, /**< GAP specific error base */ + BLE_STATUS_GATT_BASE = 0x200, /**< GATT specific Error base */ +}; +#endif + +typedef enum +{ + BLE_STATUS_SUCCESS = 0, + BLE_STATUS_FORBIDDEN, /**< The operation is forbidden. Central mode call peripheral API and vice versa */ + BLE_STATUS_PENDING, /**< Request received and execution started, response pending */ + BLE_STATUS_TIMEOUT, /**< Request timed out */ + BLE_STATUS_NOT_SUPPORTED, /**< Request/feature/parameter not supported */ + BLE_STATUS_NOT_FOUND, + BLE_STATUS_NOT_ALLOWED, /**< Request not allowed */ + BLE_STATUS_LINK_TIMEOUT, /**< Link timeout (link loss) */ + BLE_STATUS_NOT_ENABLED, /**< BLE not enabled, @ref ble_enable */ + BLE_STATUS_ERROR, /**< Generic Error */ + BLE_STATUS_ALREADY_REGISTERED, /**< BLE service already registered */ + BLE_STATUS_WRONG_STATE, /**< Wrong state for request */ + BLE_STATUS_ERROR_PARAMETER, /**< Parameter in request is wrong */ + BLE_STATUS_NO_MEMORY, /**< System doesn't have memory */ + BLE_STATUS_NO_SERVICE, /**< System doesn't have service */ +}BLE_STATUS_T; + +typedef uint16_t ble_status_t; /**< Response and event BLE service status type @ref BLE_STATUS */ + +typedef ble_status_t BleStatus; + +#define BLE_LIB_ASSERT(cond) ((cond) ? (void)0 : __assert_fail()) + +#define BLE_MAX_CONN_CFG 2 +#define BLE_MAX_ADV_BUFFER_CFG 3 + +typedef bool (*ble_advertise_handle_cb_t)(uint8_t type, const uint8_t *dataPtr, + uint8_t data_len, const bt_addr_le_t *addrPtr); + + +typedef struct ble_conn_param { + float interval_min; // millisecond 7.5 - 4000ms + float interval_max; // millisecond 7.5 - 4000ms + uint16_t latency; // 0x0000 - 0x01F4 + uint16_t timeout; // millisecond 100 - 32000ms +}ble_conn_param_t; +#ifdef __cplusplus +extern "C" { +#endif + +#include "os/os.h" + +extern void __assert_fail(void); + +/// Define the structure for app +typedef struct bt_uuid bt_uuid_t; +typedef struct bt_uuid_16 bt_uuid_16_t; +typedef struct bt_uuid_128 bt_uuid_128_t; +typedef struct bt_conn bt_conn_t; +typedef struct bt_gatt_attr bt_gatt_attr_t; +typedef struct bt_gatt_discover_params bt_gatt_discover_params_t; +typedef struct bt_le_scan_param bt_le_scan_param_t; +typedef struct bt_le_conn_param bt_le_conn_param_t; +typedef struct bt_gatt_subscribe_params bt_gatt_subscribe_params_t; +typedef struct bt_gatt_read_params bt_gatt_read_params_t; +typedef struct _bt_gatt_ccc _bt_gatt_ccc_t; +typedef struct bt_gatt_chrc bt_gatt_chrc_t; +typedef struct bt_gatt_ccc_cfg bt_gatt_ccc_cfg_t; +typedef struct bt_data bt_data_t; + +#ifdef __cplusplus +} +#endif +#endif // _BLE_COMMON_H_INCLUDED diff --git a/libraries/BLE/src/BLEDescriptor.cpp b/libraries/BLE/src/BLEDescriptor.cpp new file mode 100644 index 00000000..47556d32 --- /dev/null +++ b/libraries/BLE/src/BLEDescriptor.cpp @@ -0,0 +1,195 @@ +/* + BLE Descriptor API + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "BLEAttribute.h" +#include "BLEDescriptor.h" +#include "./internal/BLEUtils.h" +#include "./internal/BLEDescriptorImp.h" + +BLEDescriptor::BLEDescriptor(): + _properties(0), + _value_size(0), + _value(NULL) +{ + memset(_uuid_cstr, 0, sizeof (_uuid_cstr)); +} + +BLEDescriptor::BLEDescriptor(BLEDescriptorImp* descriptorImp, + const BLEDevice *bleDev): + _bledev(bleDev), + _value_size(0), + _value(NULL) +{ + _properties = descriptorImp->properties(); + memset(_uuid_cstr, 0, sizeof (_uuid_cstr)); + BLEUtils::uuidBT2String(descriptorImp->bt_uuid(), _uuid_cstr); + + _value_size = descriptorImp->valueSize(); + _value = (unsigned char*)malloc(_value_size); + memcpy(_value, descriptorImp->value(), _value_size); +} + +BLEDescriptor::BLEDescriptor(const char* uuid, + const unsigned char value[], + unsigned short valueLength): + _bledev() +{ + bt_uuid_128_t uuid_tmp; + memset(_uuid_cstr, 0, sizeof (_uuid_cstr)); + BLEUtils::uuidString2BT(uuid, (bt_uuid_t *)&uuid_tmp); + BLEUtils::uuidBT2String((const bt_uuid_t *)&uuid_tmp, _uuid_cstr); + + _bledev.setAddress(*BLEUtils::bleGetLoalAddress()); + + _value_size = valueLength > BLE_MAX_ATTR_LONGDATA_LEN ? BLE_MAX_ATTR_LONGDATA_LEN : valueLength; + _value = (unsigned char*)malloc(_value_size); + memcpy(_value, value, _value_size); +} + +BLEDescriptor::BLEDescriptor(const char* uuid, + const char* value): + BLEDescriptor(uuid, (const unsigned char*)value, strlen(value)) +{} + +BLEDescriptor::BLEDescriptor(const BLEDescriptor& rhs) +{ + _value = (unsigned char*)malloc(rhs._value_size); // Sid. KW: allocate memory for _value, not local + if (_value) { + memcpy(_value, rhs._value, rhs._value_size); + _value_size = rhs._value_size; + } else { + _value_size = 0; + } + memcpy(_uuid_cstr, rhs._uuid_cstr, sizeof(_uuid_cstr)); + _properties = rhs._properties; + _bledev = BLEDevice(&rhs._bledev); +} + +BLEDescriptor& BLEDescriptor::operator= (const BLEDescriptor& rhs) +{ + if (this != &rhs) + { + if (_value) + { + free(_value); + } + _value = (unsigned char*)malloc(rhs._value_size); + if (_value) + { + memcpy(_value, rhs._value, rhs._value_size); + _value_size = rhs._value_size; + memcpy(_uuid_cstr, rhs._uuid_cstr, sizeof(_uuid_cstr)); + _properties = rhs._properties; + _bledev = BLEDevice(&rhs._bledev); + } + } + return *this; +} + +BLEDescriptor::~BLEDescriptor() +{ + if (_value) + { + free(_value); + _value = NULL; + } +} + +const char* BLEDescriptor::uuid() const +{ + return _uuid_cstr; +} + +const byte* BLEDescriptor::value() const +{ + // TODO: Not support now + return _value; +} + +int BLEDescriptor::valueLength() const +{ + // TODO: Not support now + return _value_size; +} + +byte BLEDescriptor::operator[] (int offset) const +{ + // TODO: Not support now + return 0; +} + +BLEDescriptor::operator bool() const +{ + // TODO: Not support now + return false; +} + +bool BLEDescriptor::writeValue(const byte value[], int length) +{ + // TODO: Not support now + return false; +} + +bool BLEDescriptor::writeValue(const byte value[], int length, int offset) +{ + // TODO: Not support now + return false; +} + +bool BLEDescriptor::writeValue(const char* value) +{ + // TODO: Not support now + return false; +} + +// GATT client Write the value of the descriptor +bool BLEDescriptor::write(const byte value[], int length) +{ + // TODO: Not support now + return false; +} + +bool BLEDescriptor::write(const byte value[], int length, int offset) +{ + // TODO: Not support now + return false; +} + +bool BLEDescriptor::write(const char* value) +{ + // TODO: Not support now + return false; +} + +bool BLEDescriptor::read() +{ + // TODO: Not support now + return false; +} + +unsigned char BLEDescriptor::properties() const +{ + return _properties; +} + + +int BLEDescriptor::valueSize() const +{ + return _value_size; +} + diff --git a/libraries/BLE/src/BLEDescriptor.h b/libraries/BLE/src/BLEDescriptor.h new file mode 100644 index 00000000..faf867c0 --- /dev/null +++ b/libraries/BLE/src/BLEDescriptor.h @@ -0,0 +1,104 @@ +/* + BLE Descriptor API + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ARDUINO_BLE_DESCRIPTOR_H +#define ARDUINO_BLE_DESCRIPTOR_H + +#include "ArduinoBLE.h" + +#include "BLEDevice.h" + +class BLEDescriptor +{ + public: + BLEDescriptor(); + BLEDescriptor(const char* uuid, const unsigned char value[], unsigned short valueLength); // create a descriptor the specified uuid and value + BLEDescriptor(const char* uuid, const char* value); // create a descriptor the specified uuid and string value + + BLEDescriptor(BLEDescriptorImp* descriptorImp, const BLEDevice *bleDev); + BLEDescriptor(const BLEDescriptor&); + BLEDescriptor& operator=(const BLEDescriptor&); + + virtual ~BLEDescriptor(); + + const char* uuid() const; + + virtual const byte* value() const; // returns the value buffer + virtual int valueLength() const; // returns the current length of the value + virtual byte operator[] (int offset) const; // returns a byte of the value at the specified offset + + virtual operator bool() const; // is the descriptor valid (discovered from peripheral) + + /** + * @brief Write the value of the descriptor + * + * @param value The value buffer that want to write to descriptor + * + * @param length The value buffer's length + * + * @return bool true - Success, false - Failed + * + * @note none + */ + virtual bool writeValue(const byte value[], int length); + + /** + * @brief Write the value of the descriptor + * + * @param value The value buffer that want to write to descriptor + * + * @param length The value buffer's length + * + * @param offset The offset in the descriptor's data + * + * @return bool true - Success, false - Failed + * + * @note none + */ + bool writeValue(const byte value[], int length, int offset); + + /** + * @brief Write the value of the descriptor + * + * @param value The value string that want to write to descriptor + * + * @return bool true - Success, false - Failed + * + * @note none + */ + bool writeValue(const char* value); + + // GATT client Write the value of the descriptor + virtual bool write(const byte value[], int length); + bool write(const byte value[], int length, int offset); + bool write(const char* value); + bool read(); + unsigned char properties() const; + int valueSize() const; +private: + char _uuid_cstr[37]; // The characteristic UUID + BLEDevice _bledev; + + unsigned char _properties; // The characteristic property + + unsigned short _value_size; // The value size + unsigned char* _value; // The value. Will delete after create the _internal +}; + +#endif diff --git a/libraries/BLE/src/BLEDevice.cpp b/libraries/BLE/src/BLEDevice.cpp new file mode 100644 index 00000000..d6711585 --- /dev/null +++ b/libraries/BLE/src/BLEDevice.cpp @@ -0,0 +1,451 @@ +/* + BLE Device API + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "ArduinoBLE.h" +#include "BLEDevice.h" + +#include "./internal/BLEUtils.h" + +#include "./internal/BLEProfileManager.h" +#include "./internal/BLEDeviceManager.h" +#include "./internal/BLECharacteristicImp.h" + +BLEDevice::BLEDevice() +{ + memset(&_bt_addr, 0, sizeof(_bt_addr)); + _conn_param.interval_max = BT_GAP_INIT_CONN_INT_MAX; + _conn_param.interval_min = BT_GAP_INIT_CONN_INT_MIN; + _conn_param.latency = 0; + _conn_param.timeout = 400; +} + +/* +BLEDevice::BLEDevice(String bleaddress) +{ + BLEUtils::macAddressString2BT(bleaddress.c_str(), _bt_addr); +} + +BLEDevice::BLEDevice(const char* bleaddress) +{ + BLEUtils::macAddressString2BT(bleaddress, _bt_addr); +} + +*/ + +BLEDevice::BLEDevice(const bt_addr_le_t* bleaddress): + BLEDevice() +{ + memcpy(&_bt_addr, bleaddress, sizeof(bt_addr_le_t)); +} + +BLEDevice::BLEDevice(const BLEDevice* bledevice) +{ + memcpy(&_bt_addr, bledevice->bt_le_address(), sizeof(bt_addr_le_t)); + memcpy(&_conn_param, &bledevice->_conn_param, sizeof (ble_conn_param_t)); +} + +BLEDevice::~BLEDevice() +{ + //pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); +} + +bool BLEDevice::begin() +{ + return BLEDeviceManager::instance()->begin(this); +} + +void BLEDevice::poll() +{} + +void BLEDevice::end() +{} + +bool BLEDevice::connected() +{ + return BLEDeviceManager::instance()->connected(this); +} + +bool BLEDevice::disconnect() +{ + return BLEDeviceManager::instance()->disconnect(this); +} + +String BLEDevice::address() const +{ + return BLEUtils::macAddressBT2String(_bt_addr); +} + +void BLEDevice::setAddress(const bt_addr_le_t& addr) +{ + memcpy(&_bt_addr, &addr, sizeof(_bt_addr)); +} + +void BLEDevice::setAdvertisedServiceUuid(const char* advertisedServiceUuid) +{ + BLEDeviceManager::instance()->setAdvertisedServiceUuid(advertisedServiceUuid); +} + +void BLEDevice::setAdvertisedService(const BLEService& service) +{ + setAdvertisedServiceUuid(service.uuid()); +} + +void BLEDevice::setServiceSolicitationUuid(const char* serviceSolicitationUuid) +{ + BLEDeviceManager::instance()->setServiceSolicitationUuid(serviceSolicitationUuid); +} + +void BLEDevice::setManufacturerData(const unsigned char manufacturerData[], + unsigned char manufacturerDataLength) +{} + +void BLEDevice::setLocalName(const char *localName) +{ + BLEDeviceManager::instance()->setLocalName(localName); +} + +void BLEDevice::setAdvertisingInterval(float advertisingInterval) +{ + BLEDeviceManager::instance()->setAdvertisingInterval(advertisingInterval); +} + +void BLEDevice::setConnectionInterval(int minimumConnectionInterval, + int maximumConnectionInterval, + uint16_t latency, + uint16_t timeout) +{ + // TODO: Update the connection interval need more discussion +} + +void BLEDevice::setConnectionInterval(int minimumConnectionInterval, + int maximumConnectionInterval) +{ + // TODO: Update the connection interval need more discussion + +} + +bool BLEDevice::setTxPower(int txPower) +{ + return BLEDeviceManager::instance()->setTxPower(txPower); +} + +void BLEDevice::setConnectable(bool connectable) +{ + BLEDeviceManager::instance()->setConnectable(connectable); +} + +void BLEDevice::setDeviceName(const char* deviceName) +{ + BLEDeviceManager::instance()->setDeviceName(deviceName); +} + +void BLEDevice::setAppearance(unsigned short appearance) +{ + BLEDeviceManager::instance()->setAppearance(appearance); +} + +int BLEDevice::addService(BLEService& attribute) +{ + return BLEProfileManager::instance()->addService(*this, attribute); +} + +int BLEDevice::startAdvertising() +{ + preCheckProfile(); + return BLEDeviceManager::instance()->startAdvertising(); +} + +void BLEDevice::stopAdvertising() +{ + BLEDeviceManager::instance()->stopAdvertising(); +} + +BLEDevice BLEDevice::central() +{ + return BLEDeviceManager::instance()->central(); +} + +BLEDevice BLEDevice::peripheral() +{ + // TODO: How to get the target devices + BLEDevice temp; + return temp; +} + +BLEDevice::operator bool() const +{ + return BLEUtils::macAddressValid(_bt_addr); +} + +//BLEDevice& BLEDevice::operator=(const BLEDevice& device) +//{ +// if (*this != device) +// { +// memcpy(&(this->_bt_addr), &(device._bt_addr), sizeof (bt_addr_le_t)); +// } +// return *this; +//} + +bool BLEDevice::operator==(const BLEDevice& device) const +{ + return (memcmp(this->_bt_addr.val, device._bt_addr.val, 6) == 0); +} + +bool BLEDevice::operator!=(const BLEDevice& device) const +{ + return (memcmp(this->_bt_addr.val, device._bt_addr.val, 6) != 0); +} + + +void BLEDevice::startScanning() +{ + preCheckProfile(); + BLEDeviceManager::instance()->clearAdvertiseCritical(); + BLEDeviceManager::instance()->startScanning(); +} + +void BLEDevice::startScanning(String name) +{ + preCheckProfile(); + BLEDeviceManager::instance()->setAdvertiseCritical(name); + BLEDeviceManager::instance()->startScanning(); +} + +void BLEDevice::startScanning(BLEService& service) +{ + preCheckProfile(); + BLEDeviceManager::instance()->setAdvertiseCritical(service); + BLEDeviceManager::instance()->startScanning(); +} + +void BLEDevice::startScanningWithDuplicates() +{ + // TODO +} + +void BLEDevice::stopScanning() +{ + BLEDeviceManager::instance()->stopScanning(); +} + +BLEDevice BLEDevice::available() +{ + return BLEDeviceManager::instance()->available(); +} + +bool BLEDevice::hasLocalName() const +{ + return BLEDeviceManager::instance()->hasLocalName(this); +} + +bool BLEDevice::hasAdvertisedServiceUuid() const +{ + return BLEDeviceManager::instance()->hasAdvertisedServiceUuid(this); +} + +bool BLEDevice::hasAdvertisedServiceUuid(int index) const +{ + return BLEDeviceManager::instance()->hasAdvertisedServiceUuid(this, index); +} + +int BLEDevice::advertisedServiceUuidCount() const +{ + return BLEDeviceManager::instance()->advertisedServiceUuidCount(this); +} + +String BLEDevice::localName() const +{ + return BLEDeviceManager::instance()->localName(this); +} + +void BLEDevice::advertisedServiceUuid(char *buf) const +{ + BLEDeviceManager::instance()->advertisedServiceUuid(this, buf); +} + +void BLEDevice::advertisedServiceUuid(int index, char *buf) const +{ + BLEDeviceManager::instance()->advertisedServiceUuid(this, index, buf); +} + +int BLEDevice::rssi() const +{ + return BLEDeviceManager::instance()->rssi(this); +} + +bool BLEDevice::connect() +{ + return BLEDeviceManager::instance()->connect(*this); +} + +bool BLEDevice::discoverAttributes() +{ + return BLEProfileManager::instance()->discoverAttributes(this); +} + +String BLEDevice::deviceName() +{ + return BLEDeviceManager::instance()->deviceName(); +} + +int BLEDevice::appearance() +{ + return BLEDeviceManager::instance()->appearance(); +} + +// For GATT +int BLEDevice::serviceCount() const +{ + return BLEProfileManager::instance()->serviceCount(*this); +} + +bool BLEDevice::hasService(const char* uuid) const +{ + BLEServiceImp* serviceImp = BLEProfileManager::instance()->service(*this, uuid); + return (NULL != serviceImp); +} + +bool BLEDevice::hasService(const char* uuid, int index) const +{ + BLEServiceImp* serviceImp = BLEProfileManager::instance()->service(*this, index); + return serviceImp->compareUuid(uuid); +} + +BLEService BLEDevice::service(int index) const +{ + BLEServiceImp* serviceImp = BLEProfileManager::instance()->service(*this, index); + if (serviceImp != NULL) + { + BLEService temp(serviceImp, this); + return temp; + } + BLEService temp; + return temp; +} + +BLEService BLEDevice::service(const char * uuid) const +{ + BLEServiceImp* serviceImp = BLEProfileManager::instance()->service(*this, uuid); + if (serviceImp != NULL) + { + BLEService temp(serviceImp, this); + return temp; + } + BLEService temp; + return temp; +} + +BLEService BLEDevice::service(const char * uuid, int index) const +{ + BLEServiceImp* serviceImp = BLEProfileManager::instance()->service(*this, index); + if (serviceImp != NULL && serviceImp->compareUuid(uuid)) + { + BLEService temp(serviceImp, this); + return temp; + } + BLEService temp; + return temp; +} + +int BLEDevice::characteristicCount() const +{ + return BLEProfileManager::instance()->characteristicCount(*this); +} + +bool BLEDevice::hasCharacteristic(const char* uuid) const +{ + BLECharacteristicImp* characteristicImp = BLEProfileManager::instance()->characteristic(*this, uuid); + return (NULL != characteristicImp); +} + +bool BLEDevice::hasCharacteristic(const char* uuid, int index) const +{ + BLECharacteristicImp* characteristicImp = BLEProfileManager::instance()->characteristic(*this, uuid, index); + return (NULL != characteristicImp); +} + +BLECharacteristic BLEDevice::characteristic(int index) const +{ + BLECharacteristicImp* characteristicImp = BLEProfileManager::instance()->characteristic(*this, index); + + if (NULL == characteristicImp) + { + BLECharacteristic temp; + return temp; + } + BLECharacteristic temp(characteristicImp, this); + return temp; +} + +BLECharacteristic BLEDevice::characteristic(const char * uuid) const +{ + BLECharacteristicImp* characteristicImp = BLEProfileManager::instance()->characteristic(*this, uuid); + + if (NULL == characteristicImp) + { + BLECharacteristic temp; + return temp; + } + BLECharacteristic temp(characteristicImp, this); + return temp; +} + +BLECharacteristic BLEDevice::characteristic(const char * uuid, int index) const +{ + BLECharacteristicImp* characteristicImp = BLEProfileManager::instance()->characteristic(*this, index); + if (false == characteristicImp->compareUuid(uuid)) + { + // UUID not matching + characteristicImp = NULL; + } + + if (NULL == characteristicImp) + { + BLECharacteristic temp; + return temp; + } + BLECharacteristic temp(characteristicImp, this); + return temp; +} + +// event handler +void BLEDevice::setEventHandler(BLEDeviceEvent event, + BLEDeviceEventHandler eventHandler) +{ + BLEDeviceManager::instance()->setEventHandler(event, eventHandler); +} + +const bt_addr_le_t* BLEDevice::bt_le_address() const +{ + return &_bt_addr; +} +const bt_le_conn_param* BLEDevice::bt_conn_param() const +{ + return &_conn_param; +} + +void BLEDevice::preCheckProfile() +{ + if (false == BLEProfileManager::instance()->hasRegisterProfile() && + BLEProfileManager::instance()->serviceCount(*this) > 0) + { + BLEProfileManager::instance()->registerProfile(*this); + delay(8); + } +} + diff --git a/libraries/BLE/src/BLEDevice.h b/libraries/BLE/src/BLEDevice.h new file mode 100644 index 00000000..a96ce433 --- /dev/null +++ b/libraries/BLE/src/BLEDevice.h @@ -0,0 +1,631 @@ +/* + BLE Device API + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ARDUINO_BLE_DEVICE_H +#define ARDUINO_BLE_DEVICE_H + +#include + +enum BLEDeviceEvent { + BLEConnected = 0, // BLE device connected + BLEDisconnected = 1, // BLE device disconnected + BLEConParamUpdate = 2, // Update the connection parameter + // Connection update request in central + // Connection parameter updated in peripheral + BLEDiscovered, // The scanned BLE device + BLEDeviceLastEvent +}; + +typedef void (*BLEDeviceEventHandler)(BLEDevice device); + +class BLEDevice +{ + public: + /** + * @brief The BLE device constructure + * + * @param none + * + * @return none + * + * @note none + */ + BLEDevice(); + + /** + * @brief The BLE device constructure + * + * @param[in] bleaddress BLE device address + * + * @return none + * + * @note none + */ + BLEDevice(const bt_addr_le_t* bleaddress); + /** + * @brief The BLE device constructure + * + * @param[in] bledevice BLE device + * + * @return none + * + * @note none + */ + BLEDevice(const BLEDevice* bledevice); + + virtual ~BLEDevice(); + + + /** + * @brief Initiliaze the BLE hardware + * + * @return bool indicating success or error + * + * @note This method are for real BLE device. + * Not for peer BLE device. + */ + bool begin(); + + /** + * @brief Poll for events + * + * @param none + * + * @return none + * + * @note This method are for real BLE device. + * Not for peer BLE device. + */ + void poll(); // Do we need add the return value or + // input parameter to get the events? + // Events may inlcue: + // GAP : Connected, Disconnected, Update connetion parameter + // GATT: Discovered + + /** + * @brief Deinitiliaze the BLE hardware + * + * @param none + * + * @return none + * + * @note This method are for real BLE device. + * Not for peer BLE device. + */ + void end(); + + /** + * @brief Is the device connected with another BLE device. + * + * @param none + * + * @return bool indicating success or error + * + * @note none + */ + bool connected(); + + /** + * @brief Disconnect the connected device/s. + * + * @param none + * + * @return bool indicating success or error + * + * @note The BLE may connected multiple devices. + * This call will disconnect all conected devices. + */ + bool disconnect(); + + + /** + * @brief Get the BLE address of the BLE in string format + * + * @param none + * + * @return String The address of the BLE in string format + * + * @note none + */ + String address() const; + + /** + * @brief Set the service UUID that the BLE Peripheral Device advertises + * + * @param[in] advertisedServiceUuid 16-bit or 128-bit UUID to advertis + * (in string form) + * + * @note This method must be called before the begin method + * Only for peripheral mode. + */ + void setAdvertisedServiceUuid(const char* advertisedServiceUuid); + + /** + * @brief Set the service that the BLE Peripheral Device will advertise this UUID + * + * @param[in] service The service the will in advertise data. + * + * @note This method must be called before the begin method + * Only for peripheral mode. + */ + void setAdvertisedService(const BLEService& service); + + /** + * @brief Set the service UUID that is solicited in the BLE Peripheral + * Device advertises + * + * @param[in] advertisedServiceUuid 16-bit or 128-bit UUID to advertis + * (in string form) + * + * @note This method must be called before the begin method + * Only for peripheral mode. + */ + void setServiceSolicitationUuid(const char* serviceSolicitationUuid); + + /** + * @brief Set the manufacturer data in the BLE Peripheral Device advertises + * + * @param[in] manufacturerData The data about manufacturer will + * be set in advertisement + * @param[in] manufacturerDataLength The length of the manufacturer data + * + * @note This method must be called before the begin method + * Only for peripheral mode. + */ + void setManufacturerData(const unsigned char manufacturerData[], + unsigned char manufacturerDataLength); + + /** + * Set the local name that the BLE Peripheral Device advertises + * + * @param[in] localName local name to advertise + * + * @note This method must be called before the begin method + */ + void setLocalName(const char *localName); + + /** + * @brief Set advertising interval + * + * @param[in] advertisingInterval Advertising Interval in ms + * + * @return none + * + * @note none + */ + void setAdvertisingInterval(float advertisingInterval); + + /** + * @brief Set the connection parameters and send connection + * update request in both BLE peripheral and central + * + * @param[in] intervalmin Minimum Connection Interval (ms) + * + * @param[in] intervalmax Maximum Connection Interval (ms) + * + * @param[in] latency Connection Latency + * + * @param[in] timeout Supervision Timeout (ms) + * + * @return none + * + * @note none + */ + void setConnectionInterval(int minimumConnectionInterval, + int maximumConnectionInterval, + uint16_t latency, + uint16_t timeout); + + /** + * @brief Set the min and max connection interval and send connection + * update request in both BLE peripheral and central + * + * @param[in] intervalmin Minimum Connection Interval (ms) + * + * @param[in] intervalmax Maximum Connection Interval (ms) + * + * @return none + * + * @note none + */ + void setConnectionInterval(int minimumConnectionInterval, + int maximumConnectionInterval); + + /** + * @brief Set TX power of the radio in dBM + * + * @param[in] tx_power The antenna TX power + * + * @return boolean_t true if established connection, otherwise false + */ + bool setTxPower(int txPower); + + /** + * @brief Set advertising type as connectable/non-connectable + * + * @param[in] connectable true - The device connectable + * false - The device non-connectable + * + * @return none + * + * @note Only for peripheral mode. + * Default value is connectable + */ + void setConnectable(bool connectable); + + /** + * @brief Set the value of the device name characteristic + * + * @param[in] device User-defined name string for this device. Truncated if + * more than maximum allowed string length (20 bytes). + * + * @note This method must be called before the begin method + * If device name is not set, a default name will be used + */ + void setDeviceName(const char* deviceName); + + /** + * @brief Set the appearance type for the BLE Peripheral Device + * + * See https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml + * for available options. + * + * @param[in] appearance Appearance category identifier as defined by BLE Standard + * + * @return BleStatus indicating success or error + * + * @note This method must be called before the begin method + */ + void setAppearance(unsigned short appearance); + + /** + * @brief Add a Service to the BLE Peripheral Device + * + * @param[in] attribute The service that will add to Peripheral + * + * @return int Indicating success or error type @enum BLE_STATUS_T + * + * @note This method must be called before the begin method + */ + int addService(BLEService& attribute); + + /** + * @brief Construct the ADV data and start send advertisement + * + * @param none + * + * @return int 0 - Success. Others - error code @enum BLE_STATUS_T + * + * @note none + */ + int startAdvertising(); + + /** + * @brief Stop send advertisement + * + * @param none + * + * @return none + * + * @note none + */ + void stopAdvertising(); + + /** + * @brief Get currently connected central + * + * @return BLEDevice Connected central device + * + * @note Peripheral mode only + */ + BLEDevice central(); + + /** + * @brief Get currently connected peripheral + * + * @param none + * + * @return none + * + * @note Central mode only. How to distinguish the peripheral? + */ + BLEDevice peripheral(); + + operator bool() const; + bool operator==(const BLEDevice& device) const; + bool operator!=(const BLEDevice& device) const; + + // central mode + /** + * @brief Start scanning for peripherals without filter + * + * @param none + * + * @return none + * + * @note none + */ + void startScanning(); + + /** + * @brief Start scanning for peripherals and filter by device name in ADV + * + * @param name The device's local name. + * + * @return none + * + * @note none + */ + void startScanning(String name); + + /** + * @brief Start scanning for peripherals and filter by service in ADV + * + * @param service The service + * + * @return none + * + * @note none + */ + void startScanning(BLEService& service); + + /** + * @brief start scanning for peripherals, and report all duplicates + * + * @param none + * + * @return none + * + * @note none + // Does this necessory? This will take more memory to store the ADV + // I suggest delete it. + */ + void startScanningWithDuplicates(); + + /** + * @brief Stop scanning for peripherals + * + * @param none + * + * @return none + * + * @note none + */ + void stopScanning(); + + /** + * @brief Retrieve a discovered peripheral + * + * @param none + * + * @return BLEDevice The BLE device that central scanned + * + * @note none + */ + BLEDevice available(); + + /** + * @brief Does the peripheral advertise a local name + * + * @param none + * + * @return none + * + * @note none //TODO: The implementation doesn't save the ADV's local name. + */ + bool hasLocalName() const; + + bool hasAdvertisedServiceUuid() const; // does the peripheral advertise a service + bool hasAdvertisedServiceUuid(int index) const; // does the peripheral advertise a service n + int advertisedServiceUuidCount() const; // number of services the peripheral is advertising + + String localName() const; // returns the advertised local name as a String + void advertisedServiceUuid(char *buf) const; // returns the advertised service as a UUID String + void advertisedServiceUuid(int index, char *buf) const; // returns the nth advertised service as a UUID String + + int rssi() const; // returns the RSSI of the peripheral at discovery + + bool connect(); // connect to the peripheral + bool discoverAttributes(); // discover the peripheral's attributes + + String deviceName(); // read the device name attribute of the peripheral, and return String value + int appearance(); // read the appearance attribute of the peripheral and return value as int + + // For GATT + /** + * @brief returns the number of services the BLE device has + * + * @param none + * + * @return int The number of services + * + * @note none + */ + int serviceCount() const; + + /** + * @brief Does the peripheral have a service with the specified UUID + * + * @param uuid The 128/16 bits UUID + * + * @return bool true - Found + * false- Not found + * + * @note none + */ + bool hasService(const char* uuid) const; + + /** + * @brief Does the peripheral have an nth service with the specified UUID + * + * @param uuid The 128/16 bits UUID + * + * @param index The index + * + * @return bool true - Found + * false- Not found + * + * @note none + */ + bool hasService(const char* uuid, int index) const; + + /** + * @brief Return the nth service of the peripheral + * + * @param index The index + * + * @return BLEService The BLE service + * + * @note none + */ + BLEService service(int index) const; + + /** + * @brief Return the service with the specified UUID + * + * @param uuid The 128/16 bits UUID + * + * @return BLEService The BLE service + * + * @note none + */ + BLEService service(const char * uuid) const; + + /** + * @brief Return the nth service with the specified UUID + * + * @param uuid The 128/16 bits UUID + * + * @param index The index + * + * @return BLEService The BLE service + * + * @note none + */ + BLEService service(const char * uuid, int index) const; + + /** + * @brief Returns the number of characteristics the BLE device has + * + * @param none + * + * @return int The number of characteristics + * + * @note none + */ + int characteristicCount() const; + + /** + * @brief Does the device have a characteristic with the specified UUID + * + * @param uuid The 128/16 bits UUID + * + * @return bool true - Found + * false- Not found + * + * @note none + */ + bool hasCharacteristic(const char* uuid) const; + + /** + * @brief Does the device have an nth characteristic with the + * specified UUID + * + * @param uuid The 128/16 bits UUID + * + * @param index The index + * + * @return bool true - Found + * false- Not found + * + * @note none + */ + bool hasCharacteristic(const char* uuid, int index) const; + + /** + * @brief Return the nth characteristic of the BLE device + * + * @param index The index + * + * @return BLECharacteristic The BLE characteristic + * + * @note none + */ + BLECharacteristic characteristic(int index) const; + + /** + * @brief Return the characteristic with the specified UUID + * + * @param uuid The 128/16 bits UUID + * + * @return BLECharacteristic The BLE characteristic + * + * @note none + */ + BLECharacteristic characteristic(const char * uuid) const; + + /** + * @brief Return the nth characteristic with the specified UUID + * + * @param uuid The 128/16 bits UUID + * + * @param index The index + * + * @return BLECharacteristic The BLE characteristic + * + * @note none + */ + BLECharacteristic characteristic(const char * uuid, int index) const; + + // event handler + /** + * @brief Set the event callbacks + * + * @param event The BLE device event + * + * @param eventHandler The BLE device event handler + * + * @return none + * + * @note none + */ + void setEventHandler(BLEDeviceEvent event, BLEDeviceEventHandler eventHandler); // set an event handler (callback) + +protected: + friend class BLECharacteristicImp; + friend class BLEServiceImp; + friend class BLEDeviceManager; + friend class BLEProfileManager; + friend class BLECharacteristic; + friend class BLEDescriptor; + friend class BLEService; + const bt_addr_le_t* bt_le_address() const; + const bt_le_conn_param* bt_conn_param() const; + void setAddress(const bt_addr_le_t& addr); + void setAdvertiseData(const uint8_t* adv_data, uint8_t len); +private: + void preCheckProfile(); + +private: + bt_addr_le_t _bt_addr; + + bt_le_conn_param _conn_param; +}; + +#endif diff --git a/libraries/BLE/src/BLEPeripheral.cpp b/libraries/BLE/src/BLEPeripheral.cpp new file mode 100644 index 00000000..174be75f --- /dev/null +++ b/libraries/BLE/src/BLEPeripheral.cpp @@ -0,0 +1,200 @@ +/* + BLE Peripheral API (deprecated) + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "ArduinoBLE.h" + +#include "BLEPeripheral.h" + +static BLEPeripheralEventHandler m_eventHandlers[BLEDeviceLastEvent]; + +void bleBackCompatiblePeripheralConnectHandler(BLEDevice central) +{ + if (m_eventHandlers[BLEConnected]) + { + BLECentral temp(central); + m_eventHandlers[BLEConnected](temp); + } +} + +void bleBackCompatiblePeripheralDisconnectHandler(BLEDevice central) +{ + if (m_eventHandlers[BLEDisconnected]) + { + BLECentral temp(central); + m_eventHandlers[BLEDisconnected](temp); + } +} + + +BLEPeripheral::BLEPeripheral(void) : + _initCalled(false), + _lastService(NULL), + _lastCharacteristic(NULL) +{ +} + +BLEPeripheral::~BLEPeripheral(void) +{ +} + +void BLEPeripheral::setAdvertisedServiceUuid(const char* advertisedServiceUuid) +{ + if (!_initCalled) { + init(); + } + + BLE.setAdvertisedServiceUuid(advertisedServiceUuid); +} +void BLEPeripheral::setLocalName(const char* localName) +{ + if (!_initCalled) { + init(); + } + + BLE.setLocalName(localName); +} + + +void BLEPeripheral::setDeviceName(const char *deviceName) +{ + if (!_initCalled) { + init(); + } + + BLE.setDeviceName(deviceName); +} + +void BLEPeripheral::setAppearance(const unsigned short appearance) +{ + if (!_initCalled) { + init(); + } + + BLE.setAppearance(appearance); +} + +void BLEPeripheral::setConnectionInterval(const unsigned short minConnInterval, const unsigned short maxConnInterval) +{ + if (!_initCalled) { + init(); + } + + BLE.setConnectionInterval(minConnInterval, maxConnInterval); +} + +void BLEPeripheral::addAttribute(BLEService& service) +{ + if (!_initCalled) + { + init(); + } + + BLE.addService(service); + _lastService = &service; +} + +void BLEPeripheral::addAttribute(BLECharacteristic& characteristic) +{ + if (!_initCalled) + { + init(); + } + + if (_lastService) + { + _lastService->addCharacteristic(characteristic); + _lastCharacteristic = &characteristic; + } +} + +void BLEPeripheral::addAttribute(BLEDescriptor& descriptor) +{ + if (!_initCalled) + { + init(); + } + + if (_lastCharacteristic) + { + _lastCharacteristic->addDescriptor(descriptor); + } +} + +void BLEPeripheral::setEventHandler(BLEPeripheralEvent event, BLEPeripheralEventHandler callback) +{ + if (BLEConnected == event || BLEDisconnected == event) + { + m_eventHandlers[event] = callback; + } +} + +bool BLEPeripheral::begin(void) +{ + if (!_initCalled) + { + init(); + } + + if (_lastService) + { + BLE.addService(*_lastService); + } + + BLE.setEventHandler(BLEDisconnected, bleBackCompatiblePeripheralDisconnectHandler); + BLE.setEventHandler(BLEConnected, bleBackCompatiblePeripheralConnectHandler); + + BLE.startAdvertising(); + return true; +} + +void BLEPeripheral::poll(void) +{ + BLE.poll(); +} + +void BLEPeripheral::end(void) +{ + BLE.end(); +} + +bool BLEPeripheral::disconnect(void) +{ + return BLE.disconnect(); +} + +BLECentral BLEPeripheral::central(void) +{ + BLEDevice centralBle = BLE.central(); + return BLECentral(centralBle); +} + +bool BLEPeripheral::connected(void) +{ + return BLE.connected(); +} + +void BLEPeripheral::init() +{ + if (!_initCalled) + { + BLE.begin(); + _initCalled = true; + } +} + diff --git a/libraries/BLE/src/BLEPeripheral.h b/libraries/BLE/src/BLEPeripheral.h new file mode 100644 index 00000000..2b556011 --- /dev/null +++ b/libraries/BLE/src/BLEPeripheral.h @@ -0,0 +1,69 @@ +/* + BLE Peripheral API (deprecated) + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ARDUINO_BLE_PERIPHERAL_H +#define ARDUINO_BLE_PERIPHERAL_H + +typedef void (*BLEPeripheralEventHandler)(BLECentral ¢ral); + +typedef BLEDeviceEvent BLEPeripheralEvent; + +class BLEPeripheral { + public: + BLEPeripheral(void); + virtual ~BLEPeripheral(void); + + void setAdvertisedServiceUuid(const char* advertisedServiceUuid); // set the advertised service uuid + void setLocalName(const char* localName); // set the local name + + + void setDeviceName(const char *deviceName); // set the device name + void setAppearance(const unsigned short appearance); // set the appearance type + + // Set the min and max connection interval + void setConnectionInterval(const unsigned short minConnInterval, const unsigned short maxConnInterval); + + // Add an attribute to the BLE Peripheral Device + void addAttribute(BLEService& service); + void addAttribute(BLECharacteristic& characteristic); + void addAttribute(BLEDescriptor& descriptor); + + void setEventHandler(BLEDeviceEvent event, BLEPeripheralEventHandler callback); // register an event handler + + bool begin(void); // Setup attributes and start advertising + + void poll(void); // poll the BLE radio for events + + void end(void); // Stop advertising and disconnect a central if connected + + bool disconnect(void); // disconnect the central if connected + + + BLECentral central(void); + bool connected(void); // Is a central connected? + +private: + void init(); + + bool _initCalled; + BLEService* _lastService; + BLECharacteristic* _lastCharacteristic; +}; + +#endif // ARDUINO_BLE_PERIPHERAL_H \ No newline at end of file diff --git a/libraries/BLE/src/BLEService.cpp b/libraries/BLE/src/BLEService.cpp new file mode 100644 index 00000000..efa0f0b2 --- /dev/null +++ b/libraries/BLE/src/BLEService.cpp @@ -0,0 +1,201 @@ +/* + BLE Service API + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "BLEService.h" + +#include "./internal/BLEProfileManager.h" +#include "./internal/BLECharacteristicImp.h" + +#include "./internal/BLEUtils.h" + +BLEService::BLEService():_bledevice(),_service_imp(NULL) +{ + memset(_uuid_cstr, 0, sizeof (_uuid_cstr)); +} + +BLEService::BLEService(const char* uuid):_bledevice(),_service_imp(NULL) +{ + bt_uuid_128_t uuid_tmp; + memset(_uuid_cstr, 0, sizeof (_uuid_cstr)); + BLEUtils::uuidString2BT(uuid, (bt_uuid_t *)&uuid_tmp); + BLEUtils::uuidBT2String((const bt_uuid_t *)&uuid_tmp, _uuid_cstr); + + _bledevice.setAddress(*BLEUtils::bleGetLoalAddress()); +} + +BLEService::BLEService(const bt_uuid_t* uuid):_bledevice(),_service_imp(NULL) +{ + memset(_uuid_cstr, 0, sizeof (_uuid_cstr)); + BLEUtils::uuidBT2String(uuid, _uuid_cstr); + _bledevice.setAddress(*BLEUtils::bleGetLoalAddress()); +} + +BLEService::BLEService(BLEServiceImp* serviceImp, const BLEDevice* bledev): + _bledevice(bledev),_service_imp(serviceImp) +{ + memset(_uuid_cstr, 0, sizeof (_uuid_cstr)); + BLEUtils::uuidBT2String(serviceImp->bt_uuid(), _uuid_cstr); +} + +BLEService::~BLEService() +{ +} + +BLEService::operator bool() const +{ + return (strlen(_uuid_cstr) > 3); +} + +const char* BLEService::uuid() const +{ + return _uuid_cstr; +} + +void BLEService::addCharacteristic(BLECharacteristic& characteristic) +{ + BLEServiceImp* serviceImp = getServiceImp(); + + if (NULL != serviceImp) + { + serviceImp->addCharacteristic(_bledevice, characteristic); + } +} + +int BLEService::characteristicCount() const +{ + int count = 0; + BLEServiceImp* serviceImp = getServiceImp(); + if (NULL != serviceImp) + { + count = serviceImp->getCharacteristicCount(); + } + return count; +} + +bool BLEService::hasCharacteristic(const char* uuid) const +{ + BLECharacteristicImp* characteristicImp = NULL; + BLEServiceImp* serviceImp = getServiceImp(); + if (NULL != serviceImp) + { + characteristicImp = serviceImp->characteristic(uuid); + } + return (NULL != characteristicImp); +} + +bool BLEService::hasCharacteristic(const char* uuid, int index) const +{ + BLECharacteristicImp* characteristicImp = NULL; + BLEServiceImp* serviceImp = getServiceImp(); + if (NULL != serviceImp) + { + characteristicImp = serviceImp->characteristic(index); + if (false == characteristicImp->compareUuid(uuid)) + { + // UUID not align + characteristicImp = NULL; + } + } + return (NULL != characteristicImp); +} + +BLECharacteristic BLEService::characteristic(int index) const +{ + BLECharacteristicImp* characteristicImp = NULL; + BLEServiceImp* serviceImp = getServiceImp(); + if (NULL != serviceImp) + { + characteristicImp = serviceImp->characteristic(index); + } + if (NULL == characteristicImp) + { + BLECharacteristic temp; + return temp; + } + else + { + BLECharacteristic temp(characteristicImp, &_bledevice); + return temp; + } +} + +BLECharacteristic BLEService::characteristic(const char * uuid) const +{ + BLECharacteristicImp* characteristicImp = NULL; + BLEServiceImp* serviceImp = getServiceImp(); + if (NULL != serviceImp) + { + characteristicImp = serviceImp->characteristic(uuid); + } + + if (NULL == characteristicImp) + { + BLECharacteristic temp; + return temp; + } + else + { + BLECharacteristic temp(characteristicImp, &_bledevice); + return temp; + } +} + +BLECharacteristic BLEService::characteristic(const char * uuid, int index) const +{ + BLECharacteristicImp* characteristicImp = NULL; + BLEServiceImp* serviceImp = getServiceImp(); + if (NULL != serviceImp) + { + characteristicImp = serviceImp->characteristic(index); + if (false == characteristicImp->compareUuid(uuid)) + { + // UUID not align + characteristicImp = NULL; + } + } + if (NULL == characteristicImp) + { + BLECharacteristic temp; + return temp; + } + else + { + BLECharacteristic temp(characteristicImp, &_bledevice); + return temp; + } +} + +BLEServiceImp* BLEService::getServiceImp() +{ + if (NULL == _service_imp) + { + _service_imp = BLEProfileManager::instance()->service(_bledevice, uuid()); + } + return _service_imp; +} + +BLEServiceImp* BLEService::getServiceImp() const +{ + return _service_imp; +} + +void BLEService::setServiceImp(BLEServiceImp* serviceImp) +{ + _service_imp = serviceImp; +} + diff --git a/libraries/BLE/src/BLEService.h b/libraries/BLE/src/BLEService.h new file mode 100644 index 00000000..538ea1d7 --- /dev/null +++ b/libraries/BLE/src/BLEService.h @@ -0,0 +1,145 @@ +/* + BLE Service API + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ARDUINO_BLE_SERVICE_H +#define ARDUINO_BLE_SERVICE_H + +#include "ArduinoBLE.h" +#include "BLEDevice.h" + +//class BLECharacteristic; +class BLEServiceImp; + +class BLEService +{ +public: + BLEService(); + BLEService(const char* uuid); + virtual ~BLEService(); + + virtual operator bool() const; // is the service valid + + const char* uuid() const; + + /** + * @brief Add a characteristic in service + * + * @param characteristic The characteristic want to be added to service + * + * @return none + * + * @note none + */ + void addCharacteristic(BLECharacteristic& characteristic); + + /** + * @brief Get the number of characteristics the service has + * + * @param none + * + * @return none + * + * @note none + */ + int characteristicCount() const; + + /** + * @brief Does the service have a characteristic with the specified UUID + * + * @param uuid The UUID of the characteristic + * + * @return bool true - Yes. false - No + * + * @note none + */ + bool hasCharacteristic(const char* uuid) const; + + /** + * @brief Does the service have an nth characteristic with the + * specified UUID + * + * @param uuid The UUID of the characteristic + * + * @param index The index of characteristic + * + * @return bool true - Yes. false - No + * + * @note none + */ + bool hasCharacteristic(const char* uuid, int index) const; + + /** + * @brief Return the nth characteristic of the service + * + * @param index The index of characteristic + * + * @return BLECharacteristic The characteristic + * + * @note none + */ + BLECharacteristic characteristic(int index) const; + + /** + * @brief Return the characteristic with the specified UUID + * + * @param uuid The UUID of the characteristic + * + * @return BLECharacteristic The characteristic + * + * @note none + */ + BLECharacteristic characteristic(const char * uuid) const; + + /** + * @brief return the nth characteristic with the specified UUID + * + * @param uuid The UUID of the characteristic + * + * @param index The index of characteristic + * + * @return BLECharacteristic The characteristic + * + * @note none + */ + BLECharacteristic characteristic(const char * uuid, int index) const; + +protected: + friend class BLEDevice; + friend class BLEServiceImp; + friend class BLEProfileManager; + friend uint8_t profile_service_read_rsp_process(bt_conn_t *conn, + int err, + bt_gatt_read_params_t *params, + const void *data, + uint16_t length); + + BLEService(BLEServiceImp* serviceImp, const BLEDevice* bledev); + BLEService(const bt_uuid_t* uuid); + void setServiceImp(BLEServiceImp* serviceImp); +private: + BLEServiceImp* getServiceImp(); + BLEServiceImp* getServiceImp() const; + +private: + BLEDevice _bledevice; + BLEServiceImp* _service_imp; + char _uuid_cstr[37]; +}; + +#endif diff --git a/libraries/BLE/src/BLETypedCharacteristic.h b/libraries/BLE/src/BLETypedCharacteristic.h new file mode 100644 index 00000000..b3dc23c1 --- /dev/null +++ b/libraries/BLE/src/BLETypedCharacteristic.h @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2015 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _BLE_TYPED_CHARACTERISTIC_H_INCLUDED +#define _BLE_TYPED_CHARACTERISTIC_H_INCLUDED + +#include "ArduinoBLE.h" + +#include "BLECharacteristic.h" + +template class BLETypedCharacteristic : public BLECharacteristic +{ +public: + /** + * @brief The constructor of the template BLE Characteristic + * + * @param[in] uuid The characteristic UUID 16/128 bits + * + * @param[in] properties The property of the characteristic (BLERead, + * BLEWrite or BLE Notify. Combine with | ) + * + * @return none + * + * @note none + */ + BLETypedCharacteristic(const char* uuid, unsigned char properties); + + /** + * @brief Set the characteristic value + * + * @param[in] value New value to set + * + * @return bool true - set value success, + * false - on error + * + * @note none + */ + bool setValue(T value); + + /** + * @brief Update the characteristic value + * + * @param[in] value New value to set + * + * @return bool true - set value success, + * false - on error + * + * @note none + */ + bool writeValue(T value); + + /** + * @brief Get the value of the Characteristic + * + * @param none + * + * @return T The value of characteristic + * + * @note none + */ + T value(void); + + /** + * @brief Set the characteristic value in Little Endian + * + * @param[in] value New value to set + * + * @return bool true - set value success, + * false - on error + * + * @note none + */ + bool setValueLE(T value); + /** + * @brief Get the value of the Characteristic in Little Endian + * + * @param none + * + * @return T The value of characteristic + * + * @note none + */ + T valueLE(void); + + /** + * @brief Set the characteristic value in Big Endian + * + * @param[in] value New value to set + * + * @return bool true - set value success, + * false - on error + * + * @note none + */ + bool setValueBE(T value); + /** + * @brief Get the value of the Characteristic in Big Endian + * + * @param none + * + * @return T The value of characteristic + * + * @note none + */ + T valueBE(void); + +private: + /** + * @brief Swap the bytes + * + * @param value The typed value + * + * @return T The swapped value + * + * @note none + */ + T byteSwap(T value); +}; + +template BLETypedCharacteristic::BLETypedCharacteristic(const char* uuid, unsigned char properties) : + BLECharacteristic(uuid, properties, sizeof(T)) +{ + T value; + memset(&value, 0x00, sizeof(value)); + + setValue(value); +} + +template bool BLETypedCharacteristic::setValue(T value) { + return BLECharacteristic::setValue((unsigned char*)&value, sizeof(T)); +} + +template bool BLETypedCharacteristic::writeValue(T value) { + return BLECharacteristic::writeValue((unsigned char*)&value, sizeof(T)); +} + +template T BLETypedCharacteristic::value() { + T value; + + memcpy(&value, (unsigned char*)BLECharacteristic::value(), BLECharacteristic::valueSize()); + + return value; +} + +template bool BLETypedCharacteristic::setValueLE(T value) { + return setValue(value); +} + +template T BLETypedCharacteristic::valueLE() { + return value(); +} + +template bool BLETypedCharacteristic::setValueBE(T value) { + return setValue(byteSwap(value)); +} + +template T BLETypedCharacteristic::valueBE() { + return byteSwap(value()); +} + +template T BLETypedCharacteristic::byteSwap(T value) { + T result; + unsigned char* src = (unsigned char*)&value; + unsigned char* dst = (unsigned char*)&result; + + for (int i = 0; i < sizeof(T); i++) { + dst[i] = src[sizeof(T) - i - 1]; + } + + return result; +} + +#endif // _BLE_TYPED_CHARACTERISTIC_H_INCLUDED diff --git a/libraries/BLE/src/BLETypedCharacteristics.cpp b/libraries/BLE/src/BLETypedCharacteristics.cpp new file mode 100644 index 00000000..c9c89e24 --- /dev/null +++ b/libraries/BLE/src/BLETypedCharacteristics.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "BLETypedCharacteristics.h" + +BLECharCharacteristic::BLECharCharacteristic(const char* uuid, unsigned char properties) : + BLETypedCharacteristic(uuid, properties) { +} + +BLEUnsignedCharCharacteristic::BLEUnsignedCharCharacteristic(const char* uuid, unsigned char properties) : + BLETypedCharacteristic(uuid, properties) { +} + +BLEShortCharacteristic::BLEShortCharacteristic(const char* uuid, unsigned char properties) : + BLETypedCharacteristic(uuid, properties) { +} + +BLEUnsignedShortCharacteristic::BLEUnsignedShortCharacteristic(const char* uuid, unsigned char properties) : + BLETypedCharacteristic(uuid, properties) { +} + +BLEIntCharacteristic::BLEIntCharacteristic(const char* uuid, unsigned char properties) : + BLETypedCharacteristic(uuid, properties) { +} + +BLEUnsignedIntCharacteristic::BLEUnsignedIntCharacteristic(const char* uuid, unsigned char properties) : + BLETypedCharacteristic(uuid, properties) { +} + +BLELongCharacteristic::BLELongCharacteristic(const char* uuid, unsigned char properties) : + BLETypedCharacteristic(uuid, properties) { +} + +BLEUnsignedLongCharacteristic::BLEUnsignedLongCharacteristic(const char* uuid, unsigned char properties) : + BLETypedCharacteristic(uuid, properties) { +} + +BLEFloatCharacteristic::BLEFloatCharacteristic(const char* uuid, unsigned char properties) : + BLETypedCharacteristic(uuid, properties) { +} + +BLEDoubleCharacteristic::BLEDoubleCharacteristic(const char* uuid, unsigned char properties) : + BLETypedCharacteristic(uuid, properties) { +} diff --git a/libraries/BLE/src/BLETypedCharacteristics.h b/libraries/BLE/src/BLETypedCharacteristics.h new file mode 100644 index 00000000..1ecd2a6c --- /dev/null +++ b/libraries/BLE/src/BLETypedCharacteristics.h @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2015 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _BLE_TYPED_CHARACTERISTICS_H_INCLUDED +#define _BLE_TYPED_CHARACTERISTICS_H_INCLUDED + +#include "BLETypedCharacteristic.h" + +class BLEBoolCharacteristic : public BLETypedCharacteristic { +public: + /** + * @brief Instantiate a bool Typed Characteristic. + * Default constructor for BLE bool Characteristic + * + * @param[in] uuid The characteristic UUID 16/128 bits + * + * @param[in] properties The property of the characteristic (BLERead, + * BLEWrite or BLE Notify. Combine with | ) + * + * @return none + * + * @note none + */ + BLEBoolCharacteristic(const char* uuid, unsigned char properties); +}; + +class BLECharCharacteristic : public BLETypedCharacteristic { +public: + /** + * @brief Instantiate a Char Typed Characteristic. + * Default constructor for BLE Char Characteristic + * + * @param[in] uuid The characteristic UUID 16/128 bits + * + * @param[in] properties The property of the characteristic (BLERead, + * BLEWrite or BLE Notify. Combine with | ) + * + * @return none + * + * @note none + */ + BLECharCharacteristic(const char* uuid, unsigned char properties); +}; + +class BLEUnsignedCharCharacteristic : public BLETypedCharacteristic { +public: + /** + * @brief Instantiate a Unsigned Char Typed Characteristic. + * Default constructor for BLE Unsigned Char Characteristic + * + * @param[in] uuid The characteristic UUID 16/128 bits + * + * @param[in] properties The property of the characteristic (BLERead, + * BLEWrite or BLE Notify. Combine with | ) + * + * @return none + * + * @note none + */ + BLEUnsignedCharCharacteristic(const char* uuid, unsigned char properties); +}; + +class BLEShortCharacteristic : public BLETypedCharacteristic { +public: + /** + * @brief Instantiate a Short Typed Characteristic. + * Default constructor for BLE short Characteristic + * + * @param[in] uuid The characteristic UUID 16/128 bits + * + * @param[in] properties The property of the characteristic (BLERead, + * BLEWrite or BLE Notify. Combine with | ) + * + * @return none + * + * @note none + */ + BLEShortCharacteristic(const char* uuid, unsigned char properties); +}; + +class BLEUnsignedShortCharacteristic : public BLETypedCharacteristic { +public: + /** + * @brief Instantiate a Unsigned Short Typed Characteristic. + * Default constructor for BLE Unsigned Short Characteristic + * + * @param[in] uuid The characteristic UUID 16/128 bits + * + * @param[in] properties The property of the characteristic (BLERead, + * BLEWrite or BLE Notify. Combine with | ) + * + * @return none + * + * @note none + */ + BLEUnsignedShortCharacteristic(const char* uuid, unsigned char properties); +}; + +class BLEIntCharacteristic : public BLETypedCharacteristic { +public: + /** + * @brief Instantiate a Int Typed Characteristic. + * Default constructor for BLE Int Characteristic + * + * @param[in] uuid The characteristic UUID 16/128 bits + * + * @param[in] properties The property of the characteristic (BLERead, + * BLEWrite or BLE Notify. Combine with | ) + * + * @return none + * + * @note none + */ + BLEIntCharacteristic(const char* uuid, unsigned char properties); +}; + +class BLEUnsignedIntCharacteristic : public BLETypedCharacteristic { +public: + /** + * @brief Instantiate a Unsigned Int Typed Characteristic. + * Default constructor for BLE Unsigned Int Characteristic + * + * @param[in] uuid The characteristic UUID 16/128 bits + * + * @param[in] properties The property of the characteristic (BLERead, + * BLEWrite or BLE Notify. Combine with | ) + * + * @return none + * + * @note none + */ + BLEUnsignedIntCharacteristic(const char* uuid, unsigned char properties); +}; + +class BLELongCharacteristic : public BLETypedCharacteristic { +public: + /** + * @brief Instantiate a Long Typed Characteristic. + * Default constructor for BLE Long Characteristic + * + * @param[in] uuid The characteristic UUID 16/128 bits + * + * @param[in] properties The property of the characteristic (BLERead, + * BLEWrite or BLE Notify. Combine with | ) + * + * @return none + * + * @note none + */ + BLELongCharacteristic(const char* uuid, unsigned char properties); +}; + +class BLEUnsignedLongCharacteristic : public BLETypedCharacteristic { +public: + /** + * @brief Instantiate a Unsigned Long Typed Characteristic. + * Default constructor for BLE Unsigned Long Characteristic + * + * @param[in] uuid The characteristic UUID 16/128 bits + * + * @param[in] properties The property of the characteristic (BLERead, + * BLEWrite or BLE Notify. Combine with | ) + * + * @return none + * + * @note none + */ + BLEUnsignedLongCharacteristic(const char* uuid, unsigned char properties); +}; + +class BLEFloatCharacteristic : public BLETypedCharacteristic { +public: + /** + * @brief Instantiate a Float Typed Characteristic. + * Default constructor for BLE Float Characteristic + * + * @param[in] uuid The characteristic UUID 16/128 bits + * + * @param[in] properties The property of the characteristic (BLERead, + * BLEWrite or BLE Notify. Combine with | ) + * + * @return none + * + * @note none + */ + BLEFloatCharacteristic(const char* uuid, unsigned char properties); +}; + +class BLEDoubleCharacteristic : public BLETypedCharacteristic { +public: + /** + * @brief Instantiate a Double Typed Characteristic. + * Default constructor for BLE Double Characteristic + * + * @param[in] uuid The characteristic UUID 16/128 bits + * + * @param[in] properties The property of the characteristic (BLERead, + * BLEWrite or BLE Notify. Combine with | ) + * + * @return none + * + * @note none + */ + BLEDoubleCharacteristic(const char* uuid, unsigned char properties); +}; + +#endif // _BLE_TYPED_CHARACTERISTICS_H_INCLUDED diff --git a/libraries/BLE/src/internal/BLECallbacks.cpp b/libraries/BLE/src/internal/BLECallbacks.cpp new file mode 100644 index 00000000..ca5a5188 --- /dev/null +++ b/libraries/BLE/src/internal/BLECallbacks.cpp @@ -0,0 +1,208 @@ + + +#include + +#include "ArduinoBLE.h" + +#include "BLEAttribute.h" +#include "BLECharacteristicImp.h" +#include "BLEDeviceManager.h" +#include "BLEProfileManager.h" + +// GATT Server Only +ssize_t profile_read_process(bt_conn_t *conn, + const bt_gatt_attr_t *attr, + void *buf, uint16_t len, + uint16_t offset) +{ + const unsigned char *pvalue; + BLEAttribute *bleattr = (BLEAttribute *)attr->user_data; + BLEAttributeType type = bleattr->type(); + if (BLETypeCharacteristic == type) + { + BLECharacteristicImp* blecharacteritic = (BLECharacteristicImp*)bleattr; + pvalue = blecharacteritic->value(); + return bt_gatt_attr_read(conn, attr, buf, len, offset, pvalue, + blecharacteritic->valueLength()); + } + else if (BLETypeDescriptor == type) + { + BLEDescriptorImp* bledescriptor = (BLEDescriptorImp*)bleattr; + pvalue = bledescriptor->value(); + return bt_gatt_attr_read(conn, attr, buf, len, offset, pvalue, bledescriptor->valueLength()); + } + return 0; +} + +// GATT server only +ssize_t profile_write_process(bt_conn_t *conn, + const bt_gatt_attr_t *attr, + const void *buf, uint16_t len, + uint16_t offset) +{ + pr_info(LOG_MODULE_BLE, "%s1", __FUNCTION__); + BLEAttribute *bleattr = (BLEAttribute *)attr->user_data; + BLECharacteristicImp* blecharacteritic; + BLEAttributeType type = bleattr->type(); + if ((BLETypeCharacteristic != type) || 0 != offset) + { + return 0; + } + + blecharacteritic = (BLECharacteristicImp*)bleattr; + blecharacteritic->setValue((const uint8_t *) buf, len); + return len; +} + +ssize_t profile_longwrite_process(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, + uint16_t offset) +{ + BLECharacteristicImp *blecharacteritic = (BLECharacteristicImp*)attr->user_data; + + blecharacteritic->setBuffer((const uint8_t *) buf, len, offset); + + return len; +} + +int profile_longflush_process(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + uint8_t flags) +{ + BLECharacteristicImp *blecharacteritic = (BLECharacteristicImp*)attr->user_data; + + switch (flags) + { + case BT_GATT_FLUSH_DISCARD: + /* Discard buffer reseting it back with data */ + blecharacteritic->discardBuffer(); + return 0; + case BT_GATT_FLUSH_SYNC: + /* Sync buffer to data */ + blecharacteritic->syncupBuffer2Value(); + return 0; + } + + return -EINVAL; +} + + +// GATT client only +uint8_t profile_notify_process (bt_conn_t *conn, + bt_gatt_subscribe_params_t *params, + const void *data, uint16_t length) +{ + //BLEPeripheralHelper* peripheral = BLECentralRole::instance()->peripheral(conn);// Find peripheral by bt_conn + //BLEAttribute* notifyatt = peripheral->attribute(params); // Find attribute by params + BLECharacteristicImp* chrc = NULL; + BLEDevice bleDevice(bt_conn_get_dst(conn)); + chrc = BLEProfileManager::instance()->characteristic(bleDevice, params->value_handle); + + //assert(notifyatt->type() == BLETypeCharacteristic); + pr_debug(LOG_MODULE_APP, "%s1", __FUNCTION__); + if (NULL != chrc) + { + chrc->setValue((const unsigned char *)data, length); + } + return BT_GATT_ITER_CONTINUE; +} + +// GATT client only +uint8_t profile_discover_process(bt_conn_t *conn, + const bt_gatt_attr_t *attr, + bt_gatt_discover_params_t *params) +{ + uint8_t ret = BT_GATT_ITER_STOP; + pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + ret = BLEProfileManager::instance()->discoverResponseProc(conn, attr, params); + pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + return ret; +} + +// GATT Client only +uint8_t profile_read_rsp_process(bt_conn_t *conn, + int err, + bt_gatt_read_params_t *params, + const void *data, + uint16_t length) +{ + if (NULL == data) + { + return BT_GATT_ITER_STOP; + } + BLECharacteristicImp *chrc = NULL; + BLEDevice bleDevice(bt_conn_get_dst(conn)); + + // Get characteristic by handle params->single.handle + chrc = BLEProfileManager::instance()->characteristic(bleDevice, params->single.handle); + + if (chrc) // KW issue: may be NULL and will be dereferenced + chrc->setValue((const unsigned char *)data, length); + pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + return BT_GATT_ITER_STOP; +} + +uint8_t profile_service_read_rsp_process(bt_conn_t *conn, + int err, + bt_gatt_read_params_t *params, + const void *data, + uint16_t length) +{ + uint8_t ret = BLEProfileManager::instance()->serviceReadRspProc(conn, err, params, data, length); + pr_debug(LOG_MODULE_BLE, "%s-%d:ret-%d", __FUNCTION__, __LINE__, ret); + return ret; +} + + + +void bleConnectEventHandler(bt_conn_t *conn, + uint8_t err, + void *param) +{ + BLEDeviceManager* p = (BLEDeviceManager*)param; + + p->handleConnectEvent(conn, err); +} + + +void bleDisconnectEventHandler(bt_conn_t *conn, + uint8_t reason, + void *param) +{ + BLEDeviceManager* p = (BLEDeviceManager*)param; + + pr_info(LOG_MODULE_BLE, "Connect lost. Reason: %d", reason); + + p->handleDisconnectEvent(conn, reason); +} + +void bleParamUpdatedEventHandler(bt_conn_t *conn, + uint16_t interval, + uint16_t latency, + uint16_t timeout, + void *param) +{ + BLEDeviceManager* p = (BLEDeviceManager*)param; + + p->handleParamUpdated(conn, interval, latency, timeout); +} + + +void ble_central_device_found(const bt_addr_le_t *addr, + int8_t rssi, + uint8_t type, + const uint8_t *ad, + uint8_t len) +{ + char dev[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(addr, dev, sizeof(dev)); + //pr_debug(LOG_MODULE_BLE, "[DEVICE]: %s, AD evt type %u, AD data len %u, RSSI %i\n", + // dev, type, len, rssi); + + BLEDeviceManager::instance()->handleDeviceFound(addr, rssi, type, + ad, len); +} + + diff --git a/libraries/BLE/src/internal/BLECallbacks.h b/libraries/BLE/src/internal/BLECallbacks.h new file mode 100644 index 00000000..868fc3a6 --- /dev/null +++ b/libraries/BLE/src/internal/BLECallbacks.h @@ -0,0 +1,59 @@ + +#ifndef __BLECALLBACKS_H__ +#define __BLECALLBACKS_H__ + +uint8_t profile_notify_process (bt_conn_t *conn, + bt_gatt_subscribe_params_t *params, + const void *data, uint16_t length); +uint8_t profile_read_rsp_process(bt_conn_t *conn, int err, + bt_gatt_read_params_t *params, + const void *data, + uint16_t length); +int profile_longflush_process(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + uint8_t flags); +ssize_t profile_longwrite_process(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, + uint16_t offset); +ssize_t profile_write_process(bt_conn_t *conn, + const bt_gatt_attr_t *attr, + const void *buf, uint16_t len, + uint16_t offset); +ssize_t profile_read_process(bt_conn_t *conn, + const bt_gatt_attr_t *attr, + void *buf, uint16_t len, + uint16_t offset); + +uint8_t profile_discover_process(bt_conn_t *conn, + const bt_gatt_attr_t *attr, + bt_gatt_discover_params_t *params); + +void bleConnectEventHandler(bt_conn_t *conn, + uint8_t err, + void *param); + +void bleDisconnectEventHandler(bt_conn_t *conn, + uint8_t reason, + void *param); + +void bleParamUpdatedEventHandler(bt_conn_t *conn, + uint16_t interval, + uint16_t latency, + uint16_t timeout, + void *param); + +void ble_central_device_found(const bt_addr_le_t *addr, + int8_t rssi, + uint8_t type, + const uint8_t *ad, + uint8_t len); + +uint8_t profile_service_read_rsp_process(bt_conn_t *conn, + int err, + bt_gatt_read_params_t *params, + const void *data, + uint16_t length); + +#endif + diff --git a/libraries/BLE/src/internal/BLECharacteristicImp.cpp b/libraries/BLE/src/internal/BLECharacteristicImp.cpp new file mode 100644 index 00000000..8f3113ce --- /dev/null +++ b/libraries/BLE/src/internal/BLECharacteristicImp.cpp @@ -0,0 +1,952 @@ +/* + * Copyright (c) 2015 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "BLEAttribute.h" +#include "BLEServiceImp.h" +#include "BLECharacteristicImp.h" + +#include "BLECallbacks.h" +#include "BLEUtils.h" + +bt_uuid_16_t BLECharacteristicImp::_gatt_chrc_uuid = {BT_UUID_TYPE_16, BT_UUID_GATT_CHRC_VAL}; +bt_uuid_16_t BLECharacteristicImp::_gatt_ccc_uuid = {BT_UUID_TYPE_16, BT_UUID_GATT_CCC_VAL}; + +BLECharacteristicImp::BLECharacteristicImp(const bt_uuid_t* uuid, + unsigned char properties, + uint16_t handle, + const BLEDevice& bledevice): + BLEAttribute(uuid, BLETypeCharacteristic), + _value_length(0), + _value_buffer(NULL), + _value_updated(false), + _value_handle(handle), + _cccd_handle(0), + _attr_chrc_value(NULL), + _attr_cccd(NULL), + _subscribed(false), + _ble_device() +{ + _value_size = BLE_MAX_ATTR_DATA_LEN;// Set as MAX value. TODO: long read/write need to twist + _value = (unsigned char*)malloc(_value_size); + + // TODO: Enable when max value is not set. + // if (_value_size > BLE_MAX_ATTR_DATA_LEN) + // { + // _value_buffer = (unsigned char*)malloc(_value_size); + // } + + if (_value) + memset(_value, 0, _value_size); + + memset(&_ccc_cfg, 0, sizeof(_ccc_cfg)); + memset(&_ccc_value, 0, sizeof(_ccc_value)); + memset(&_gatt_chrc, 0, sizeof(_gatt_chrc)); + memset(&_sub_params, 0, sizeof(_sub_params)); + memset(&_discover_params, 0, sizeof(_discover_params)); + + _ccc_value.cfg = &_ccc_cfg; + _ccc_value.cfg_len = 1; + if (BLERead & properties) + { + _gatt_chrc.properties |= BT_GATT_CHRC_READ; + } + if (BLEWrite & properties) + { + _gatt_chrc.properties |= BT_GATT_CHRC_WRITE; + } + if (BLEWriteWithoutResponse & properties) + { + _gatt_chrc.properties |= BT_GATT_CHRC_WRITE_WITHOUT_RESP; + } + if (BLENotify & properties) + { + _gatt_chrc.properties |= BT_GATT_CHRC_NOTIFY; + _sub_params.value |= BT_GATT_CCC_NOTIFY; + } + if (BLEIndicate & properties) + { + _gatt_chrc.properties |= BT_GATT_CHRC_INDICATE; + _sub_params.value |= BT_GATT_CCC_INDICATE; + } + _gatt_chrc.uuid = (bt_uuid_t*)this->bt_uuid();//&_characteristic_uuid;//this->uuid(); + memset(_event_handlers, 0, sizeof(_event_handlers)); + + _sub_params.notify = profile_notify_process; + + // Update BLE device object + _ble_device.setAddress(*bledevice.bt_le_address()); + + memset(&_descriptors_header, 0, sizeof(_descriptors_header)); +} + +BLECharacteristicImp::BLECharacteristicImp(BLECharacteristic& characteristic, + const BLEDevice& bledevice): + BLEAttribute(characteristic.uuid(), BLETypeCharacteristic), + _value_length(0), + _value_buffer(NULL), + _value_updated(false), + _value_handle(0), + _cccd_handle(0), + _attr_chrc_value(NULL), + _attr_cccd(NULL), + _subscribed(false), + _ble_device() +{ + unsigned char properties = characteristic._properties; + _value_size = characteristic._value_size; + _value = (unsigned char*)malloc(_value_size); + if (_value_size > BLE_MAX_ATTR_DATA_LEN) + { + _value_buffer = (unsigned char*)malloc(_value_size); + } + + memset(&_ccc_cfg, 0, sizeof(_ccc_cfg)); + memset(&_ccc_value, 0, sizeof(_ccc_value)); + memset(&_gatt_chrc, 0, sizeof(_gatt_chrc)); + memset(&_sub_params, 0, sizeof(_sub_params)); + memset(&_discover_params, 0, sizeof(_discover_params)); + + _ccc_value.cfg = &_ccc_cfg; + _ccc_value.cfg_len = 1; + if (BLERead & properties) + { + _gatt_chrc.properties |= BT_GATT_CHRC_READ; + } + if (BLEWrite & properties) + { + _gatt_chrc.properties |= BT_GATT_CHRC_WRITE; + } + if (BLEWriteWithoutResponse & properties) + { + _gatt_chrc.properties |= BT_GATT_CHRC_WRITE_WITHOUT_RESP; + } + if (BLENotify & properties) + { + _gatt_chrc.properties |= BT_GATT_CHRC_NOTIFY; + _sub_params.value |= BT_GATT_CCC_NOTIFY; + } + if (BLEIndicate & properties) + { + _gatt_chrc.properties |= BT_GATT_CHRC_INDICATE; + _sub_params.value |= BT_GATT_CCC_INDICATE; + } + _gatt_chrc.uuid = (bt_uuid_t*)this->bt_uuid();//&_characteristic_uuid;//this->uuid(); + + memcpy(_event_handlers, characteristic._event_handlers, sizeof(_event_handlers)); + + _sub_params.notify = profile_notify_process; + + if (NULL != characteristic._value) + { + memcpy(_value, characteristic._value, _value_size); + } + + // Update BLE device object + _ble_device.setAddress(*bledevice.bt_le_address()); + + characteristic.setBLECharacteristicImp(this); + memset(&_descriptors_header, 0, sizeof(_descriptors_header)); +} + +BLECharacteristicImp::~BLECharacteristicImp() +{ + releaseDescriptors(); + if (_value) { + free(_value); + _value = (unsigned char *)NULL; + } + if (_value_buffer) + { + free(_value_buffer); + _value_buffer = (unsigned char *)NULL; + } +} + +unsigned char +BLECharacteristicImp::properties() const +{ + return _gatt_chrc.properties; +} + +bool BLECharacteristicImp::writeValue(const byte value[], int length) +{ + int status; + bool retVal = false; + + _setValue(value, length, 0); + + // Address same is GATT server. Send notification if CCCD enabled + // Different is GATT client. Send write request + if (true == BLEUtils::isLocalBLE(_ble_device) && + NULL != _attr_chrc_value) + { + // Notify for peripheral. + status = bt_gatt_notify(NULL, _attr_chrc_value, value, length, NULL); + // Sid. KW found status is always 0 + // if (!status) + // { + retVal = true; + // } + } + + //Not schedule write request for central + // The write request may failed. + // If user want to get latest set value. Call read and get the real value + return retVal; +} + +bool BLECharacteristicImp::writeValue(const byte value[], int length, int offset) +{ + int status; + bool retVal = false; + + _setValue(value, length, offset); + + // Address same is GATT server. Send notification if CCCD enabled + // Different is GATT client. Send write request + if (true == BLEUtils::isLocalBLE(_ble_device) && + NULL != _attr_chrc_value) + { + // Notify for peripheral. + status = bt_gatt_notify(NULL, _attr_chrc_value, value, length, NULL); + // Sid. KW found status is always 0. + // if (!status) + // { + retVal = true; + // } + } + + //Not schedule write request for central + // The write request may failed. + // If user want to get latest set value. Call read and get the real value + return retVal; +} + +bool +BLECharacteristicImp::setValue(const unsigned char value[], uint16_t length) +{ + _setValue(value, length, 0); + if (BLEUtils::isLocalBLE(_ble_device) == true) + { + // GATT server + // Write request for GATT server + if (_event_handlers[BLEWritten]) + { + BLECharacteristic chrcTmp(this, &_ble_device); + _event_handlers[BLEWritten](_ble_device, chrcTmp); + } + } + else + { + // GATT client + // Discovered attribute + // Read response/Notification/Indication for GATT client + if (_event_handlers[BLEValueUpdated]) + { + BLECharacteristic chrcTmp(this, &_ble_device); + _event_handlers[BLEValueUpdated](_ble_device, chrcTmp); + } + } + + return true; +} + +unsigned short +BLECharacteristicImp::valueSize() const +{ + return _value_size; +} + +const unsigned char* +BLECharacteristicImp::value() const +{ + return _value; +} + +unsigned short +BLECharacteristicImp::valueLength() const +{ + return _value_length; +} + +unsigned char +BLECharacteristicImp::operator[] (int offset) const +{ + return _value[offset]; +} + +bool +BLECharacteristicImp::written() +{ + bool written = false; + if (true == BLEUtils::isLocalBLE(_ble_device)) + { + // GATT server. The characteristic on local device + written = _value_updated; + _value_updated = false; + } + + return written; +} + +bool BLECharacteristicImp::valueUpdated() +{ + bool updated = false; + if (false == BLEUtils::isLocalBLE(_ble_device)) + { + // GATT client. The characteristic on remote device. + updated = _value_updated; + _value_updated = false; + } + return updated; +} + +bool +BLECharacteristicImp::subscribed() +{ + return _subscribed; +} + +bool BLECharacteristicImp::canNotify() +{ + if (false == BLEUtils::isLocalBLE(_ble_device)) + { + // GATT server can't subscribe + return false; + } + return (_ccc_value.value & BT_GATT_CCC_NOTIFY); +} + +bool BLECharacteristicImp::canIndicate() +{ + if (false == BLEUtils::isLocalBLE(_ble_device)) + { + // GATT server can't subscribe + return false; + } + return (_ccc_value.value & BT_GATT_CCC_INDICATE); +} + +bool BLECharacteristicImp::unsubscribe(void) +{ + int retval = 0; + bt_conn_t* conn = NULL; + + if (true == BLEUtils::isLocalBLE(_ble_device)) + { + // GATT server can't subscribe + return false; + } + + if (false == _subscribed) + { + return true; + } + + _sub_params.value = 0; + + if (0 == (_gatt_chrc.properties & (BT_GATT_CHRC_NOTIFY | BT_GATT_CHRC_INDICATE))) + { + // The characteristic not support the Notify and Indicate + return false; + } + + conn = bt_conn_lookup_addr_le(_ble_device.bt_le_address()); + if (NULL == conn) + { + return false; + } + + bt_addr_le_copy(&_sub_params._peer, bt_conn_get_dst(conn)); + _sub_params.ccc_handle = _cccd_handle; + _sub_params.value_handle = _value_handle; + + // Enable CCCD to allow peripheral send Notification/Indication + retval = bt_gatt_unsubscribe(conn, &_sub_params); + bt_conn_unref(conn); + if (0 == retval) + { + _subscribed = false; + } + return _subscribed; +} + +bool BLECharacteristicImp::subscribe(void) +{ + int retval = 0; + bt_conn_t* conn = NULL; + + if (true == BLEUtils::isLocalBLE(_ble_device)) + { + // GATT server can't subscribe + return false; + } + + if (_gatt_chrc.properties & BT_GATT_CHRC_NOTIFY) + { + _sub_params.value |= BT_GATT_CCC_NOTIFY; + } + + if (_gatt_chrc.properties & BT_GATT_CHRC_INDICATE) + { + _sub_params.value |= BT_GATT_CCC_INDICATE; + } + + if (_sub_params.value == 0) + { + return false; + } + + conn = bt_conn_lookup_addr_le(_ble_device.bt_le_address()); + if (NULL == conn) + { + return false; + } + + bt_addr_le_copy(&_sub_params._peer, bt_conn_get_dst(conn)); + _sub_params.ccc_handle = _cccd_handle; + _sub_params.value_handle = _value_handle; + + // Enable CCCD to allow peripheral send Notification/Indication + retval = bt_gatt_subscribe(conn, &_sub_params); + bt_conn_unref(conn); + if (0 == retval) + { + _subscribed = true; + } + return _subscribed; +} + +void +BLECharacteristicImp::setEventHandler(BLECharacteristicEvent event, BLECharacteristicEventHandler callback) +{ + noInterrupts(); + if (event < BLECharacteristicEventLast) { + _event_handlers[event] = callback; + } + interrupts(); +} + +void +BLECharacteristicImp::setHandle(uint16_t handle) +{ + // GATT client + _value_handle = handle; +} + +void +BLECharacteristicImp::setCCCDHandle(uint16_t handle) +{ + // GATT client + _cccd_handle = handle; +} + +uint16_t +BLECharacteristicImp::valueHandle() +{ + uint16_t handle = 0; + if (NULL != _attr_chrc_value) + { + //GATT server + handle = _attr_chrc_value->handle; + } + else + { + // GATT client + handle = _value_handle; + } + + return handle; +} + +void +BLECharacteristicImp::_setValue(const uint8_t value[], uint16_t length, uint16_t offset) +{ + if (length + offset > _value_size) + { + if (_value_size > offset) + { + uint16_t temp_len = _value_size - offset; + if (length > temp_len) + { + length = temp_len; + } + } + else + { + return; + } + } + + _value_updated = true; + memcpy(_value + offset, value, length); + _value_length = length; +} + +_bt_gatt_ccc_t* BLECharacteristicImp::getCccCfg(void) +{ + return &_ccc_value; +} + +bt_gatt_chrc_t* BLECharacteristicImp::getCharacteristicAttValue(void) +{ + return &_gatt_chrc; +} + +uint8_t BLECharacteristicImp::getPermission(void) +{ + uint8_t perm = 0; + if (_gatt_chrc.properties & BT_GATT_CHRC_READ) + { + perm |= BT_GATT_PERM_READ; + } + if (_gatt_chrc.properties & (BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP)) + { + perm |= BT_GATT_PERM_WRITE; + } + return perm; +} + +bt_uuid_t* BLECharacteristicImp::getCharacteristicAttributeUuid(void) +{ + return (bt_uuid_t*) &_gatt_chrc_uuid; +} + +bt_uuid_t* BLECharacteristicImp::getClientCharacteristicConfigUuid(void) +{ + return (bt_uuid_t*) &_gatt_ccc_uuid; +} + +bool BLECharacteristicImp::read() +{ + int retval = 0; + bt_conn_t* conn = NULL; + + if (true == BLEUtils::isLocalBLE(_ble_device)) + { + // GATT server can't write + return false; + } + + if (_reading) + { + // Already in reading state + return false; + } + + _read_params.func = profile_read_rsp_process; + _read_params.handle_count = 1; + _read_params.single.handle = _value_handle; + _read_params.single.offset = 0; + + if (0 == _read_params.single.handle) + { + // Discover not complete + return false; + } + + conn = bt_conn_lookup_addr_le(_ble_device.bt_le_address()); + if (NULL == conn) + { + return false; + } + + // Send read request + retval = bt_gatt_read(conn, &_read_params); + bt_conn_unref(conn); + if (0 == retval) + { + _reading = true; + } + return _reading; +} + +bool BLECharacteristicImp::write(const unsigned char value[], + uint16_t length) +{ + int retval = 0; + bt_conn_t* conn = NULL; + + if (true == BLEUtils::isLocalBLE(_ble_device)) + { + // GATT server can't write + return false; + } + + conn = bt_conn_lookup_addr_le(_ble_device.bt_le_address()); + if (NULL == conn) + { + return false; + } + + // Send read request + retval = bt_gatt_write_without_response(conn, + _value_handle, + value, + length, + false); + bt_conn_unref(conn); + return (0 == retval); +} + +void BLECharacteristicImp::setBuffer(const uint8_t value[], + uint16_t length, + uint16_t offset) +{ + if ((length + offset > _value_size) || + ((unsigned char *)NULL == _value_buffer)) { + // Ignore the data + return; + } + + memcpy(_value_buffer + offset, value, length); +} + +void BLECharacteristicImp::syncupBuffer2Value() +{ + setValue(_value_buffer, _value_size); +} + +void BLECharacteristicImp::discardBuffer() +{ + if(_value_buffer) + memcpy(_value_buffer, _value, _value_size); +} + +bool BLECharacteristicImp::longCharacteristic() +{ + return (_value_size > BLE_MAX_ATTR_DATA_LEN); +} + +int BLECharacteristicImp::updateProfile(bt_gatt_attr_t *attr_start, int& index) +{ + bt_gatt_attr_t *start = attr_start; + int base_index = index; + int offset = 0; + int counter = 0; + + // Characteristic declare + memset(start, 0, sizeof(bt_gatt_attr_t)); + start->uuid = getCharacteristicAttributeUuid(); + start->perm = BT_GATT_PERM_READ; + start->read = bt_gatt_attr_read_chrc; + start->user_data = this->getCharacteristicAttValue(); + pr_info(LOG_MODULE_BLE, "chrc-%p, uuid type-%d", start, start->uuid->type); + + start++; + index++; + counter++; + + // Descriptor + memset(start, 0, sizeof(bt_gatt_attr_t)); + start->uuid = (bt_uuid_t *)bt_uuid(); + start->perm = this->getPermission(); + start->user_data = (void*)((BLEAttribute*)this); + start->read = profile_read_process; + + if (this->longCharacteristic() == false) + { + // Normal characteristic MAX. 20 + start->write = profile_write_process; + } + else + { + // Long characteristic. MAX. 512 + start->write = profile_longwrite_process; + start->flush = profile_longflush_process; + } + _attr_chrc_value = start; + pr_debug(LOG_MODULE_BLE, "chrcdescripor-%p, chimp-%p type-%d", start, this, this->type()); + + start++; + index++; + counter++; + + if (0 != (_gatt_chrc.properties & (BT_GATT_CHRC_NOTIFY | BT_GATT_CHRC_INDICATE))) + { + // Descriptor + memset(start, 0, sizeof(bt_gatt_attr_t)); + start->uuid = this->getClientCharacteristicConfigUuid(); + start->perm = BT_GATT_PERM_READ | BT_GATT_PERM_WRITE; + start->read = bt_gatt_attr_read_ccc; + start->write = bt_gatt_attr_write_ccc; + start->user_data = this->getCccCfg(); + + pr_info(LOG_MODULE_BLE, "cccd-%p", start); + + start++; + index++; + counter++; + } + + BLEDescriptorNodePtr node = _descriptors_header.next; + while (NULL != node) + { + BLEDescriptorImp *descriptorImp = node->value; + start = attr_start + index - base_index; + offset = descriptorImp->updateProfile(start, index); + counter += offset; + node = node->next; + } + pr_debug(LOG_MODULE_BLE, "%s:type-%d", __FUNCTION__, this->type()); + return counter; +} + +int BLECharacteristicImp::addDescriptor(BLEDescriptor& descriptor) +{ + BLEDescriptorImp* descriptorImp = descrptor(descriptor.uuid()); + if (NULL != descriptorImp) + { + return BLE_STATUS_SUCCESS; + } + + descriptorImp = new BLEDescriptorImp(_ble_device, descriptor); + pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); + if (NULL == descriptorImp) + { + return BLE_STATUS_NO_MEMORY; + } + + pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); + BLEDescriptorNodePtr node = link_node_create(descriptorImp); + if (NULL == node) + { + delete descriptorImp; + return BLE_STATUS_NO_MEMORY; + } + link_node_insert_last(&_descriptors_header, node); + pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); + return BLE_STATUS_SUCCESS; +} + +int BLECharacteristicImp::addDescriptor(const bt_uuid_t* uuid, + unsigned char property, + uint16_t handle) +{ + BLEDescriptorImp* descriptorImp = descrptor(uuid); + if (NULL != descriptorImp) + { + return BLE_STATUS_SUCCESS; + } + + descriptorImp = new BLEDescriptorImp(uuid, property, handle, _ble_device); + pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); + if (NULL == descriptorImp) + { + return BLE_STATUS_NO_MEMORY; + } + + BLEDescriptorNodePtr node = link_node_create(descriptorImp); + if (NULL == node) + { + delete descriptorImp; + return BLE_STATUS_NO_MEMORY; + } + link_node_insert_last(&_descriptors_header, node); + pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); + return BLE_STATUS_SUCCESS; +} + +BLEDescriptorImp* BLECharacteristicImp::descrptor(const bt_uuid_t* uuid) +{ + BLEDescriptorImp* descriptorImp = NULL; + BLEDescriptorNodePtr node = link_node_get_first(&_descriptors_header); + + while (NULL != node) + { + descriptorImp = node->value; + if (true == descriptorImp->compareUuid(uuid)) + { + break; + } + } + + if (NULL == node) + { + descriptorImp = NULL; + } + return descriptorImp; +} + +BLEDescriptorImp* BLECharacteristicImp::descrptor(const char* uuid) +{ + bt_uuid_128_t uuid_tmp; + BLEUtils::uuidString2BT(uuid, (bt_uuid_t *)&uuid_tmp); + return descrptor((const bt_uuid_t *)&uuid_tmp); +} + + +BLEDescriptorImp* BLECharacteristicImp::descrptor(int index) +{ + BLEDescriptorImp* descriptorImp = NULL; + BLEDescriptorNodePtr node = link_node_get_first(&_descriptors_header); + while (NULL != node) + { + if (0 >= index) + { + descriptorImp = node->value; + break; + } + index--; + node = node->next; + } + return descriptorImp; +} + +void BLECharacteristicImp::releaseDescriptors() +{ + BLEDescriptorNodePtr node = link_node_get_first(&_descriptors_header); + + while (NULL != node) + { + BLEDescriptorImp* descriptorImp = node->value; + delete descriptorImp; + link_node_remove_first(&_descriptors_header); + node = link_node_get_first(&_descriptors_header); + } +} + +int BLECharacteristicImp::getAttributeCount() +{ + int counter = link_list_size(&_descriptors_header) + 2; // Declaration and descriptor + // Notification/Indecation + if (_gatt_chrc.properties & (BT_GATT_CHRC_NOTIFY | BT_GATT_CHRC_INDICATE)) + { + counter++; + } + return counter; +} + +int BLECharacteristicImp::descriptorCount() const +{ + int counter = link_list_size(&_descriptors_header); + return counter; +} + +bool BLECharacteristicImp::discoverAttributes(BLEDevice* device) +{ + + int err; + bt_conn_t* conn; + bt_gatt_discover_params_t* temp = NULL; + const bt_uuid_t* service_uuid = bt_uuid(); + + if (service_uuid->type == BT_UUID_TYPE_16) + { + uint16_t uuid_tmp = ((bt_uuid_16_t*)service_uuid)->val; + if (BT_UUID_GAP_VAL == uuid_tmp || + BT_UUID_GATT_VAL == uuid_tmp) + { + return false; + } + } + + conn = bt_conn_lookup_addr_le(device->bt_le_address()); + if (NULL == conn) + { + // Link lost + pr_debug(LOG_MODULE_BLE, "Can't find connection\n"); + return false; + } + temp = &_discover_params; + temp->start_handle = _value_handle + 1; + temp->end_handle = _value_handle + 20; // TODO: the max descriptor is not more than 20 + temp->uuid = NULL; + temp->type = BT_GATT_DISCOVER_DESCRIPTOR; + temp->func = profile_discover_process; + pr_debug(LOG_MODULE_BLE, "%s-%d-charc",__FUNCTION__, __LINE__); + err = bt_gatt_discover(conn, temp); + bt_conn_unref(conn); + if (err) + { + pr_debug(LOG_MODULE_BLE, "Discover failed(err %d)\n", err); + return false; + } + return true; +} + +bool BLECharacteristicImp::isClientCharacteristicConfigurationDescriptor(const bt_uuid_t* uuid) +{ + bool ret = false; + uint16_t cccd_uuid = BT_UUID_GATT_CCC_VAL; + if (uuid->type == BT_UUID_TYPE_16) + { + if (0 == memcmp(&BT_UUID_16(uuid)->val, &cccd_uuid, sizeof(uint16_t))) + { + ret = true; + } + } + return ret; +} + +uint8_t BLECharacteristicImp::discoverResponseProc(bt_conn_t *conn, + const bt_gatt_attr_t *attr, + bt_gatt_discover_params_t *params) +{ + const bt_addr_le_t* dst_addr = bt_conn_get_dst(conn); + BLEDevice device(dst_addr); + uint8_t retVal = BT_GATT_ITER_STOP; + + pr_debug(LOG_MODULE_BLE, "%s-%d: type-%d", __FUNCTION__, __LINE__, params->type); + + // Process the service + switch (params->type) + { + case BT_GATT_DISCOVER_DESCRIPTOR: + { + if (NULL != attr) + { + retVal = BT_GATT_ITER_CONTINUE; + const bt_uuid_t* desc_uuid = attr->uuid; + uint16_t desc_handle = attr->handle; + pr_debug(LOG_MODULE_BLE, "%s-%d:handle-%d:%d", __FUNCTION__, __LINE__,attr->handle, desc_handle); + if (isClientCharacteristicConfigurationDescriptor(desc_uuid)) + { + setCCCDHandle(desc_handle); + } + else if (bt_uuid_cmp(BLEServiceImp::getPrimayUuid(), desc_uuid) == 0 || + bt_uuid_cmp(getCharacteristicAttributeUuid(), desc_uuid) == 0 ) + { + retVal = BT_GATT_ITER_STOP; + } + else + { + int retval = (int)addDescriptor(desc_uuid, + attr->perm, + desc_handle); + + if (BLE_STATUS_SUCCESS != retval) + { + pr_error(LOG_MODULE_BLE, "%s-%d: Error-%d", + __FUNCTION__, __LINE__, retval); + } + + } + } + break; + } + default: + { + break; + } + } + return retVal; +} + + diff --git a/libraries/BLE/src/internal/BLECharacteristicImp.h b/libraries/BLE/src/internal/BLECharacteristicImp.h new file mode 100644 index 00000000..568597ef --- /dev/null +++ b/libraries/BLE/src/internal/BLECharacteristicImp.h @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2015 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _BLE_CHARACTERISTICIMP_H_INCLUDED +#define _BLE_CHARACTERISTICIMP_H_INCLUDED + +//#include "BLECommon.h" + +//#include "BLEDevice.h" +//#include "BLEDescriptor.h" + +#include "ArduinoBLE.h" +#include "BLEDescriptorImp.h" + +#include "BLEDevice.h" + +#include "LinkList.h" +class BLEDescriptorImp; +/** + * BLE GATT Characteristic : public BLEAttribute + */ +class BLECharacteristicImp: public BLEAttribute{ +public: + + virtual ~BLECharacteristicImp(); + + + /** + * @brief Add the characteristic's descriptor + * + * @param descriptor The descriptor for characteristic + * + * @return none + * + * @note none + */ + int addDescriptor(BLEDescriptor& descriptor); + int addDescriptor(const bt_uuid_t* uuid, + unsigned char property, + uint16_t handle); + + void releaseDescriptors(); + + /** + * @brief Write the value of the characteristic + * + * @param value The value buffer that want to write to characteristic + * + * @param length The value buffer's length + * + * @param offset The offset in the characteristic's data + * + * @return bool true - Success, false - Failed + * + * @note none + */ + bool writeValue(const byte value[], int length); + bool writeValue(const byte value[], int length, int offset); + + /** + * Set the current value of the Characteristic + * + * @param[in] value New value to set, as a byte array. Data is stored in internal copy. + * @param[in] length Length, in bytes, of valid data in the array to write. + * Must not exceed maxLength set for this characteristic. + * + * @return bool true set value success, false on error + */ + bool setValue(const unsigned char value[], unsigned short length); + + /** + * Get the property mask of the Characteristic + * + * @return unsigned char property mask of the Characteristic + */ + unsigned char properties(void) const; + + /** + * Get the (maximum) size of the Characteristic + * + * @return unsigned size of characateristic in bytes + */ + unsigned short valueSize(void) const; + + /** + * Get data pointer to the value of the Characteristic + * + * @return const unsigned char* pointer to the value of the Characteristic + */ + const unsigned char* value(void) const; + + /** + * Get the current length of the value of the Characteristic + * + * @return unsigned short size of characateristic value in bytes + */ + unsigned short valueLength() const; + + unsigned char operator[] (int offset) const; + + /** + * Has the value of the Characteristic been written by a central + * + * @return bool true is central has updated characteristic value, otherwise false + */ + bool written(void); + bool valueUpdated(); + + /** + * Is a central listening for notifications or indications of the Characteristic + * + * @return bool true is central is subscribed, otherwise false + */ + bool subscribed(void); + bool canNotify(); + bool canIndicate(); + + bool subscribe(void); + bool unsubscribe(void); + + /** + * Provide a function to be called when events related to this Characteristic are raised + * + * @param[in] event Event type to set event handler for + * @param[in] callback Pointer to callback function to invoke when the event occurs. + */ + void setEventHandler(BLECharacteristicEvent event, BLECharacteristicEventHandler callback); + + /** + * @brief Schedule the read request to read the characteristic in peripheral + * + * @param[in] none + * + * @return bool Indicate the success or error + * + * @note Only for central device + */ + bool read(); + + /** + * @brief Schedule the write request to update the characteristic in peripheral + * + * @param[in] peripheral The peripheral device that want to be updated + * @param[in] value New value to set, as a byte array. Data is stored in internal copy. + * @param[in] length Length, in bytes, of valid data in the array to write. + * Must not exceed maxLength set for this characteristic. + * + * @return bool true set value success, false on error + * + * @note none + */ + bool write(const unsigned char value[], + uint16_t length); + + int descriptorCount() const; + uint8_t discoverResponseProc(bt_conn_t *conn, + const bt_gatt_attr_t *attr, + bt_gatt_discover_params_t *params); + + bool discoverAttributes(BLEDevice* device); + + BLEDescriptorImp* descrptor(const bt_uuid_t* uuid); + BLEDescriptorImp* descrptor(const char* uuid); + BLEDescriptorImp* descrptor(int index); + +protected: + friend class BLEProfileManager; + friend class BLEServiceImp; + /** + * Constructor for BLE Characteristic + * + * @param[in] characteristic The characteristic + * @param[in] bledevice The device that has this characteristic + */ + BLECharacteristicImp(BLECharacteristic& characteristic, const BLEDevice& bledevice); + BLECharacteristicImp(const bt_uuid_t* uuid, + unsigned char properties, + uint16_t handle, + const BLEDevice& bledevice); + + friend int profile_longflush_process(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + uint8_t flags); + friend ssize_t profile_longwrite_process(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, + uint16_t offset); + + int updateProfile(bt_gatt_attr_t *attr_start, int& index); + + int getAttributeCount(); + + bool longCharacteristic(); + + void setBuffer(const uint8_t value[], + uint16_t length, + uint16_t offset); + void discardBuffer(); + void syncupBuffer2Value(); + + /** + * @brief Get the characteristic value handle + * + * @param none + * + * @return none + * + * @note Only for peripheral + */ + uint16_t valueHandle(void); + + /** + * @brief Get characteristic configuration descriptor value handle + * + * @param none + * + * @return uint16_t The value handle + * 0 is invalid handle + * + * @note Only for peripheral + */ + uint16_t cccdHandle(void); + + inline _bt_gatt_ccc_t* getCccCfg(void); + inline bt_gatt_chrc_t* getCharacteristicAttValue(void); + static bt_uuid_t* getCharacteristicAttributeUuid(void); + static bt_uuid_t* getClientCharacteristicConfigUuid(void); + + /** + * @brief Get the characteristic permission + * + * @param none + * + * @return uint8_t The characteristic permission + * + * @note none + */ + uint8_t getPermission(void); + + /** + * @brief For central to discover the peripherial profile + * + * @param[in] attr The discover response + * + * @param[in] params The discover parameter that need to fill + * + * @return none + * + * @note Only for central + */ + void discover(const bt_gatt_attr_t *attr, + bt_gatt_discover_params_t *params); + + /** + * @brief For central to discover the peripherial profile + * + * @param[in] params The discover parameter that need to fill + * + * @return none + * + * @note Only for central + */ + void discover(bt_gatt_discover_params_t *params); + + /** + * @brief Get the subscribe parameter + * + * @param none + * + * @return bt_gatt_subscribe_params_t * the subscribe parameter + * + * @note Only for central + */ + bt_gatt_subscribe_params_t* getSubscribeParams(); + +private: + + void setCCCDHandle(uint16_t handle); + void setHandle(uint16_t handle); + void _setValue(const uint8_t value[], uint16_t length, uint16_t offset); + bool isClientCharacteristicConfigurationDescriptor(const bt_uuid_t* uuid); + +private: + // Those 2 UUIDs are used for define the characteristic. + static bt_uuid_16_t _gatt_chrc_uuid; // Characteristic UUID + static bt_uuid_16_t _gatt_ccc_uuid; // CCCD UUID + + unsigned short _value_size; + unsigned short _value_length; + unsigned char* _value; + unsigned char* _value_buffer; + bool _value_updated; + + uint16_t _value_handle; // GATT client only + uint16_t _cccd_handle; // GATT client only + bt_gatt_discover_params_t _discover_params;// GATT client only + + bt_gatt_ccc_cfg_t _ccc_cfg; + _bt_gatt_ccc_t _ccc_value; + bt_gatt_chrc_t _gatt_chrc; + + bt_gatt_attr_t *_attr_chrc_value; // GATT server only + bt_gatt_attr_t *_attr_cccd; // GATT server only + + // For GATT Client to subscribe the Notification/Indication + bt_gatt_subscribe_params_t _sub_params; + bool _subscribed; + + bool _reading; + bt_gatt_read_params_t _read_params; // GATT read parameter + + typedef LinkNode BLEDescriptorLinkNodeHeader; + typedef LinkNode* BLEDescriptorNodePtr; + typedef LinkNode BLEDescriptorNode; + + BLECharacteristicEventHandler _event_handlers[BLECharacteristicEventLast]; + BLEDescriptorLinkNodeHeader _descriptors_header; + BLEDevice _ble_device; +}; + +#endif // _BLE_CHARACTERISTIC_H_INCLUDED diff --git a/libraries/BLE/src/internal/BLEDescriptorImp.cpp b/libraries/BLE/src/internal/BLEDescriptorImp.cpp new file mode 100644 index 00000000..fb7f7e04 --- /dev/null +++ b/libraries/BLE/src/internal/BLEDescriptorImp.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2015 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "BLEAttribute.h" +#include "BLEDescriptorImp.h" + +#include "internal/ble_client.h" + +#include "BLECallbacks.h" + +BLEDescriptorImp::BLEDescriptorImp(BLEDevice& bledevice, + BLEDescriptor &descriptor): + BLEAttribute(descriptor.uuid(), BLETypeDescriptor), + _value_handle(0) +{ + + _properties = descriptor.properties(); + _value_length = descriptor.valueLength(); + _value = (unsigned char*)malloc(_value_length); + + if (_value) + memcpy(_value, descriptor.value(), _value_length); + else + _value_length = 0; +} + +BLEDescriptorImp::BLEDescriptorImp(const bt_uuid_t* uuid, + unsigned char properties, + uint16_t handle, + BLEDevice& bledevice): + BLEAttribute(uuid, BLETypeDescriptor), + _value_handle(handle), + _properties(properties) +{ + _value_length = BLE_MAX_ATTR_DATA_LEN; + _value = (unsigned char*)malloc(_value_length); + + if (_value) + memset(_value, 0, _value_length); + else + _value_length = 0; +} + + +BLEDescriptorImp::BLEDescriptorImp(const BLEDescriptorImp& rhs) : + BLEAttribute(rhs) +{ + _value_length = rhs._value_length; + _value = (unsigned char *)malloc(_value_length); + if (_value) + memcpy(_value, rhs._value, sizeof(_value_length)); + else + _value_length = 0; + + _value_handle = rhs._value_handle; + _properties = rhs._properties; + _descriptor_uuid = rhs._descriptor_uuid; + _bledev = BLEDevice(&rhs._bledev); +} + + +BLEDescriptorImp& BLEDescriptorImp::operator=(const BLEDescriptorImp& that) +{ + if (this != &that) { + + BLEAttribute::operator=(that); + if (_value) + free(_value); + + _value_length = that._value_length; + _value = (unsigned char *)malloc(_value_length); + if (_value) + memcpy(_value, that._value, sizeof(_value_length)); + else + _value_length = 0; + + _value_handle = that._value_handle; + _properties = that._properties; + _descriptor_uuid = that._descriptor_uuid; + _bledev = BLEDevice(&that._bledev); + } + return *this; +} + +BLEDescriptorImp::~BLEDescriptorImp() { + if (_value != (unsigned char *)NULL) { + free(_value); + _value = (unsigned char *)NULL; + } +} + +const unsigned char* +BLEDescriptorImp::value() const +{ + return _value; +} + +unsigned short +BLEDescriptorImp::valueLength() const +{ + return _value_length; +} + +unsigned char +BLEDescriptorImp::operator[] (int offset) const +{ + return _value[offset]; +} + +int BLEDescriptorImp::updateProfile(bt_gatt_attr_t *attr_start, int& index) +{ + bt_gatt_attr_t *start = attr_start; + start->uuid = (struct bt_uuid *)bt_uuid(); + start->perm = BT_GATT_PERM_READ; + start->read = profile_read_process; + start->user_data = (void*)((BLEAttribute*)this); + + pr_debug(LOG_MODULE_BLE, "Descriptor-%p", start); + index++; + return 1; +} + +unsigned char BLEDescriptorImp::properties() const +{ + return _properties; +} + +int BLEDescriptorImp::valueSize() const +{ + return _value_length; +} + + diff --git a/libraries/BLE/src/internal/BLEDescriptorImp.h b/libraries/BLE/src/internal/BLEDescriptorImp.h new file mode 100644 index 00000000..bfd2635b --- /dev/null +++ b/libraries/BLE/src/internal/BLEDescriptorImp.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _BLE_DESCRIPTORIMP_H_INCLUDED +#define _BLE_DESCRIPTORIMP_H_INCLUDED + +#include "ArduinoBLE.h" + +/** + * BLE GATT Descriptor class + */ +class BLEDescriptorImp: public BLEAttribute{ +public: + /** + * Constructor for BLE Descriptor + * + * @param[in] uuid 16-bit UUID (in string form) defined by BLE standard + * @param[in] value Value of descriptor, as a byte array. Data is stored in internal copy. + * @param[in] valueLength Data length required for descriptor value (<= BLE_MAX_ATTR_DATA_LEN) + */ + BLEDescriptorImp(BLEDevice& bledevice, BLEDescriptor &descriptor); + BLEDescriptorImp(const bt_uuid_t* uuid, + unsigned char properties, + uint16_t handle, + BLEDevice& bledevice); + + BLEDescriptorImp(const BLEDescriptorImp& rhs); + + BLEDescriptorImp& operator=(const BLEDescriptorImp& that); + + virtual ~BLEDescriptorImp(); + + /** + * Get data pointer to the value of the Descriptor + * + * @return const unsigned char* pointer to the value of the Descriptor + */ + const unsigned char* value(void) const; + + /** + * Get the length of the value of the Descriptor + * + * @return unsigned short size of Descriptor value in bytes + */ + unsigned short valueLength(void) const; + + int updateProfile(bt_gatt_attr_t *attr_start, int& index); + + unsigned char operator[] (int offset) const; + unsigned char properties() const; + int valueSize() const; + +protected: + + +private: + unsigned short _value_length; + unsigned short _value_handle; + unsigned char* _value; + unsigned char _properties; // The characteristic property + + bt_uuid_128 _descriptor_uuid; + + BLEDevice _bledev; +}; + +#endif // _BLE_DESCRIPTOR_H_INCLUDED diff --git a/libraries/BLE/src/internal/BLEDeviceManager.cpp b/libraries/BLE/src/internal/BLEDeviceManager.cpp new file mode 100644 index 00000000..777ae59e --- /dev/null +++ b/libraries/BLE/src/internal/BLEDeviceManager.cpp @@ -0,0 +1,1230 @@ +/* + BLE Device API + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "ArduinoBLE.h" +#include "BLEDeviceManager.h" +#include "BLEProfileManager.h" + +#include "internal/ble_client.h" + +#include +#include "../src/services/ble/conn_internal.h" + +#include "BLEUtils.h" +#include "BLECallbacks.h" + +BLEDeviceManager* BLEDeviceManager::_instance; + +BLEDeviceManager::BLEDeviceManager(): + _min_conn_interval(0), + _max_conn_interval(0), + _adv_critical_local_name(""), + _wait_for_connect_peripheral_adv_rssi(0), + _available_for_connect_peripheral_adv_rssi(0), + _has_service_uuid(false), + _has_service_solicit_uuid(false), + _appearance(0), + _manufacturer_data_length(0), + _adv_type(0), + _adv_data_idx(0), + _local_name(""), + _state(BLE_PERIPH_STATE_NOT_READY), + _local_ble(NULL) +{ + memset(&_local_bda, 0, sizeof(_local_bda)); + memset(&_wait_for_connect_peripheral, 0, sizeof(_wait_for_connect_peripheral)); + + memset(&_service_uuid, 0, sizeof(_service_uuid)); + memset(&_service_solicit_uuid, 0, sizeof(_service_solicit_uuid)); + memset(_adv_data, 0, sizeof(_adv_data)); + + memset(&_peer_central, 0, sizeof (bt_addr_le_t)); + + ble_client_get_factory_config(&_local_bda, _device_name); + + _adv_param.type = BT_LE_ADV_IND; + _adv_param.addr_type = _local_bda.type; + _adv_param.interval_min = 0xA0; + _adv_param.interval_max = 0xF0; + + _scan_param.type = BT_HCI_LE_SCAN_ACTIVE; + _scan_param.filter_dup = BT_HCI_LE_SCAN_FILTER_DUP_ENABLE; + _scan_param.interval = BT_GAP_SCAN_FAST_INTERVAL; + _scan_param.window = BT_GAP_SCAN_FAST_WINDOW; + + memset(_peer_adv_buffer, 0, sizeof(_peer_adv_buffer)); + memset(_peer_adv_mill, 0, sizeof(_peer_adv_mill)); + memset(&_adv_accept_critical, 0, sizeof(_adv_accept_critical)); + memset(&_adv_critical_service_uuid, 0, sizeof(_adv_critical_service_uuid)); + + memset(_peer_peripheral, 0, sizeof(_peer_peripheral)); + memset(_peer_peripheral_adv_data, 0, sizeof(_peer_peripheral_adv_data)); + memset(_peer_peripheral_adv_data_len, 0, sizeof(_peer_peripheral_adv_data_len)); + memset(_peer_peripheral_adv_rssi, 0, sizeof(_peer_peripheral_adv_rssi)); + + memset(_device_events, 0, sizeof(_device_events)); + memset(_manufacturer_data, 0, sizeof(_manufacturer_data)); + memset(_peer_adv_data, 0, sizeof(_peer_adv_data)); + memset(_peer_adv_data_len, 0, sizeof(_peer_adv_data_len)); + memset(_peer_adv_rssi, 0, sizeof(_peer_adv_rssi)); +} + +BLEDeviceManager::~BLEDeviceManager() +{ + +} + +bool BLEDeviceManager::begin(BLEDevice *device) +{ + if (NULL == _local_ble && false == *device) + { + _local_ble = device; + _local_ble->setAddress(_local_bda); + bt_le_set_mac_address(_local_bda); + // Set device name + setDeviceName(); + _state = BLE_PERIPH_STATE_READY; + delay(4); + // TODO: Olny allow call one time + ble_client_init (bleConnectEventHandler, this, + bleDisconnectEventHandler, this, + bleParamUpdatedEventHandler, this); + return true; + } + else + { + return false; + } +} + +void BLEDeviceManager::poll() +{} + +void BLEDeviceManager::end() +{} + +bool BLEDeviceManager::connected(BLEDevice *device) +{ + bt_conn_t* conn = bt_conn_lookup_addr_le(device->bt_le_address()); + bool retval = false; + //pr_debug(LOG_MODULE_BLE, "%s-%d: add-%s", __FUNCTION__, __LINE__, device->address().c_str()); + if (NULL != conn) + { + //pr_debug(LOG_MODULE_BLE, "%s-%d: state-%d", __FUNCTION__, __LINE__,conn->state); + if (conn->state == BT_CONN_CONNECTED) + { + retval = true; + } + bt_conn_unref(conn); + } + return retval; +} + +bool BLEDeviceManager::disconnect(BLEDevice *device) +{ + int err = 0; + if (false == BLEUtils::isLocalBLE(*device)) + { + // Remote device disconnect one + bt_conn_t* conn = bt_conn_lookup_addr_le(device->bt_le_address()); + if (NULL == conn) + { + return false; + } + + err = bt_conn_disconnect (conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + bt_conn_unref(conn); + } + else + { + if (true == BLEUtils::macAddressValid(_peer_central)) + { + // Remote device disconnect one + bt_conn_t* conn = bt_conn_lookup_addr_le(&_peer_central); + if (NULL != conn) + { + err = bt_conn_disconnect (conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + bt_conn_unref(conn); + } + } + + // Local device disconnect all connections + for (int i = 0; i < BLE_MAX_CONN_CFG; i++) + { + if (true == BLEUtils::macAddressValid(_peer_peripheral[i])) + { + // Remote device disconnect one + bt_conn_t* conn = bt_conn_lookup_addr_le(&_peer_peripheral[i]); + if (NULL == conn) + { + continue; + } + + err = bt_conn_disconnect (conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + bt_conn_unref(conn); + } + } + } + return (err == 0); +} + +void BLEDeviceManager::setAdvertisedServiceUuid(const char* advertisedServiceUuid) +{ + _has_service_uuid = true; + BLEUtils::uuidString2BT(advertisedServiceUuid, (bt_uuid_t *)&_service_uuid); +} + +void BLEDeviceManager::setServiceSolicitationUuid(const char* serviceSolicitationUuid) +{ + _has_service_solicit_uuid = true; + BLEUtils::uuidString2BT(serviceSolicitationUuid, (bt_uuid_t *)&_service_solicit_uuid); +} + +void BLEDeviceManager::setManufacturerData(const unsigned char manufacturerData[], + unsigned char manufacturerDataLength) +{ + if (manufacturerDataLength > BLE_MAX_ADV_SIZE) + { + manufacturerDataLength = BLE_MAX_ADV_SIZE; + } + _manufacturer_data_length = manufacturerDataLength; + memcpy(_manufacturer_data, manufacturerData, manufacturerDataLength); +} + +void BLEDeviceManager::setLocalName(const char *localName) +{ + _local_name = localName; +} + +void BLEDeviceManager::setAdvertisingInterval(float advertisingInterval) +{ + uint16_t interval = (uint16_t) MSEC_TO_UNITS(advertisingInterval, UNIT_0_625_MS); + + _adv_param.interval_min = interval; + _adv_param.interval_max = interval; +} + +void BLEDeviceManager::setConnectionInterval(float minimumConnectionInterval, + float maximumConnectionInterval, + uint16_t latency, + uint16_t timeout) +{ +} + +void BLEDeviceManager::setConnectionInterval(float minimumConnectionInterval, + float maximumConnectionInterval) +{ + +} + +bool BLEDeviceManager::setTxPower(int txPower) +{ + ble_gap_set_tx_power(txPower); + return true; +} + +void BLEDeviceManager::setConnectable(bool connectable) +{ + uint8_t type = BT_LE_ADV_IND; + if (connectable == false) + { + type = BT_LE_ADV_NONCONN_IND; + } + _adv_param.type = type; +} + +void BLEDeviceManager::setDeviceName(const char* deviceName) +{ + memset(_device_name, 0, sizeof(_device_name)); + if (deviceName && deviceName[0]) + { + int len = strlen(deviceName); + if (len > BLE_MAX_DEVICE_NAME) + len = BLE_MAX_DEVICE_NAME; + memcpy(_device_name, deviceName, len); + setDeviceName(); + } +} + +void +BLEDeviceManager::setDeviceName() +{ + int len = strlen(_device_name); + bt_le_set_device_name(_device_name, len); +} + +void BLEDeviceManager::setAppearance(unsigned short appearance) +{ + _appearance = appearance; +} + +BLE_STATUS_T +BLEDeviceManager::_advDataInit(void) +{ + uint8_t lengthTotal = 2; // Flags data length + _adv_data_idx = 0; + + /* Add flags */ + _adv_type = (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR); + _adv_data[_adv_data_idx].type = BT_DATA_FLAGS; + _adv_data[_adv_data_idx].data = &_adv_type; + _adv_data[_adv_data_idx].data_len = 1; + _adv_data_idx++; + + if (_has_service_uuid) + { + uint8_t type; + uint8_t length; + uint8_t *data = NULL; + + pr_info(LOG_MODULE_BLE, "ADV Type-%d", _service_uuid.uuid.type); + if (BT_UUID_TYPE_16 == _service_uuid.uuid.type) + { + //UINT16_TO_LESTREAM(adv_tmp, uuid.uuid16); + data = (uint8_t *)&(((bt_uuid_16_t *)&_service_uuid)->val); + length = UUID_SIZE_16; + type = BT_DATA_UUID16_ALL; + } + else // Sid. KW, default is BT_UUID_TYPE_128 + { + data = _service_uuid.val; + length = UUID_SIZE_128; + type = BT_DATA_UUID128_ALL; + } + + // if (data) // Sid. KW, data is always initialized + { + _adv_data[_adv_data_idx].type = type; + _adv_data[_adv_data_idx].data = data; + _adv_data[_adv_data_idx].data_len = length; + _adv_data_idx++; + lengthTotal += length; + + pr_info(LOG_MODULE_BLE, "Service UUID Len -%d", length); + } + } + + if (_has_service_solicit_uuid) + { + uint8_t type; + uint8_t length; + uint8_t *data = NULL; + + pr_info(LOG_MODULE_BLE, "ADV Type-%d", _service_solicit_uuid.uuid.type); + if (BT_UUID_TYPE_16 == _service_solicit_uuid.uuid.type) + { + //UINT16_TO_LESTREAM(adv_tmp, uuid.uuid16); + data = (uint8_t *)&(((bt_uuid_16_t *)&_service_solicit_uuid)->val); + length = UUID_SIZE_16; + type = BT_DATA_SOLICIT16; + } + else // Sid. KW, default is BT_UUID_TYPE_128 + { + data = _service_solicit_uuid.val; + length = UUID_SIZE_128; + type = BT_DATA_SOLICIT128; + } + // Sid. KW, data is always initialized. if (data) + { + _adv_data[_adv_data_idx].type = type; + _adv_data[_adv_data_idx].data = data; + _adv_data[_adv_data_idx].data_len = length; + _adv_data_idx++; + lengthTotal += length; + + pr_info(LOG_MODULE_BLE, "Service UUID Len -%d", length); + } + } + + if (_local_name.length() > 0) + { + /* Add device name (truncated if too long) */ + _adv_data[_adv_data_idx].type = BT_DATA_NAME_COMPLETE; + _adv_data[_adv_data_idx].data = (const uint8_t*)_local_name.c_str(); + _adv_data[_adv_data_idx].data_len = _local_name.length(); + _adv_data_idx++; + + lengthTotal += _local_name.length(); + pr_info(LOG_MODULE_BLE, "Local Name -%s", _local_name.c_str()); + pr_info(LOG_MODULE_BLE, "Local Name Len -%d", _local_name.length()); + } + + if (_manufacturer_data_length > 0) + { + // Add manufacturer data + _adv_data[_adv_data_idx].type = BT_DATA_MANUFACTURER_DATA; + _adv_data[_adv_data_idx].data = _manufacturer_data; + _adv_data[_adv_data_idx].data_len = _manufacturer_data_length; + _adv_data_idx++; + + lengthTotal += _manufacturer_data_length; + } + +#if 0 + if (_service_data) + { + /* Add Service Data (if it will fit) */ + + /* A 128-bit Service Data UUID won't fit in an Advertising packet */ + if (BT_UUID_TYPE_16 != _service_data_uuid->type) + { + /* We support service data only for 16-bit service UUID */ + return BLE_STATUS_NOT_SUPPORTED; + } + + uint8_t block_len = sizeof(uint16_t) + _service_data_length; + if (1 + block_len > BLE_MAX_ADV_SIZE) + { + // Service data block is too large. + return BLE_STATUS_ERROR_PARAMETER; + } + + _adv_data[_adv_data_idx].type = BT_DATA_SVC_DATA16; + _adv_data[_adv_data_idx].data = _service_data_buf; + _adv_data[_adv_data_idx].data_len = block_len; + _adv_data_idx++; + + uint8_t *adv_tmp = _service_data_buf; + + UINT16_TO_LESTREAM(adv_tmp, (((bt_uuid_16_t *)_service_data_uuid)->val)); + memcpy(adv_tmp, _service_data, _service_data_length); + + lengthTotal += block_len; + pr_info(LOG_MODULE_BLE, "SVC Len -%d", block_len); + } +#endif + + if (lengthTotal > BLE_MAX_ADV_SIZE) + { + pr_error(LOG_MODULE_BLE, "ADV Total length-%d", lengthTotal); + // Service data block is too large. + return BLE_STATUS_ERROR_PARAMETER; + } + return BLE_STATUS_SUCCESS; +} + +BLE_STATUS_T BLEDeviceManager::startAdvertising() +{ + int ret; + BLE_STATUS_T status; + status = _advDataInit(); + if (BLE_STATUS_SUCCESS != status) + { + return status; + } + + pr_info(LOG_MODULE_BLE, "%s-ad_len%d", __FUNCTION__, _adv_data_idx); + if (_state != BLE_PERIPH_STATE_READY) + return BLE_STATUS_WRONG_STATE; + + ret = bt_le_adv_start(&_adv_param, _adv_data, _adv_data_idx, NULL, 0); + if (0 != ret) + { + pr_error(LOG_MODULE_APP, "[ADV] Start failed. Error: %d", ret); + return BLE_STATUS_WRONG_STATE; + } + delay(10); + _state = BLE_PERIPH_STATE_ADVERTISING; + return BLE_STATUS_SUCCESS; +} + +BLE_STATUS_T BLEDeviceManager::stopAdvertising() +{ + int err_code = 0; + BLE_STATUS_T status = BLE_STATUS_WRONG_STATE; + + if (BLE_PERIPH_STATE_ADVERTISING == _state) + { + err_code = bt_le_adv_stop(); + status = errorno_to_ble_status(err_code); + } + + if (BLE_STATUS_SUCCESS != status) + return status; + + _state = BLE_PERIPH_STATE_READY; + return BLE_STATUS_SUCCESS; +} + +BLEDevice BLEDeviceManager::central() +{ + BLEDevice temp(&_peer_central); + return temp; +} + +BLEDevice BLEDeviceManager::peripheral() +{ + // TODO + BLEDevice temp; + return temp; +} + +bool BLEDeviceManager::startScanning() +{ + _scan_param.filter_dup = BT_HCI_LE_SCAN_FILTER_DUP_ENABLE;//BT_HCI_LE_SCAN_FILTER_DUP_DISABLE; + int err = bt_le_scan_start(&_scan_param, ble_central_device_found); + if (err) + { + pr_info(LOG_MODULE_BLE, "Scanning failed to start (err %d)\n", err); + return false; + } + return true; +} + +bool BLEDeviceManager::startScanningWithDuplicates() +{ + _scan_param.filter_dup = BT_HCI_LE_SCAN_FILTER_DUP_ENABLE; + int err = bt_le_scan_start(&_scan_param, ble_central_device_found); + if (err) + { + pr_info(LOG_MODULE_BLE, "Scanning failed to start (err %d)\n", err); + return false; + } + return false; +} + +bool BLEDeviceManager::stopScanning() +{ + int err = bt_le_scan_stop(); + + if (err) // Sid. TODO: KW detected bt_le_scan_stop return only 0. + { + pr_info(LOG_MODULE_BLE, "Stop LE scan failed (err %d)\n", err); + return false; + } + return true; +} + +void BLEDeviceManager::clearAdvertiseCritical() +{ + memset(&_adv_accept_critical, 0, sizeof(_adv_accept_critical)); + //memset(&_adv_critical_service_uuid, 0, sizeof(_adv_critical_service_uuid)); +} + +void BLEDeviceManager::setAdvertiseCritical(String name) +{ + _adv_critical_local_name = name; + _adv_accept_critical.type = BT_DATA_NAME_COMPLETE; + _adv_accept_critical.data_len = name.length(); + _adv_accept_critical.data = (const uint8_t*)_adv_critical_local_name.c_str(); +} + +void BLEDeviceManager::setAdvertiseCritical(BLEService& service) +{ + BLEUtils::uuidString2BT(service.uuid(),(bt_uuid_t *)&_adv_critical_service_uuid); + uint8_t type = 0; + uint8_t length = 0; + uint8_t *data = NULL; + + pr_info(LOG_MODULE_BLE, "ADV Type-%d", _adv_critical_service_uuid.uuid.type); + if (BT_UUID_TYPE_16 == _adv_critical_service_uuid.uuid.type) + { + data = (uint8_t *)&(((bt_uuid_16_t *)&_adv_critical_service_uuid)->val); + length = UUID_SIZE_16; + type = BT_DATA_UUID16_ALL; + } + else // Sid. KW, default is BT_UUID_TYPE_128 + { + data = _adv_critical_service_uuid.val; + length = UUID_SIZE_128; + type = BT_DATA_UUID128_ALL; + } + _adv_accept_critical.type = type; + _adv_accept_critical.data_len = length; + _adv_accept_critical.data = data; +} + +bool BLEDeviceManager::hasLocalName(const BLEDevice* device) const +{ + if (BLEUtils::isLocalBLE(*device) == true) + { + return (_local_name.length() != 0); + } + + const uint8_t* adv_data = NULL; + uint8_t adv_data_len = 0; + getDeviceAdvertiseBuffer(device->bt_le_address(), + adv_data, + adv_data_len); + if (NULL == adv_data) + { + return false; + } + + while (adv_data_len > 1) + { + uint8_t len = adv_data[0]; + uint8_t type = adv_data[1]; + + /* Check for early termination */ + if (len == 0) + { + return false; + } + + if ((len + 1) > adv_data_len) { // Sid. KW, can't be (adv_data_len < 2) + pr_info(LOG_MODULE_BLE, "AD malformed\n"); + return false; + } + + if (type == BT_DATA_NAME_COMPLETE) + { + return true; + } + + adv_data_len -= len + 1; + adv_data += len + 1; + } + return false; +} + +bool BLEDeviceManager::hasAdvertisedServiceUuid(const BLEDevice* device) const +{ + if (BLEUtils::isLocalBLE(*device) == true) + { + return _has_service_uuid; + } + + uint8_t service_cnt = advertisedServiceUuidCount(device); + return (service_cnt > 0); +} + +bool BLEDeviceManager::hasAdvertisedServiceUuid(const BLEDevice* device, int index) const +{ + uint8_t service_cnt = advertisedServiceUuidCount(device); + return (service_cnt > index); +} + +void BLEDeviceManager::getDeviceAdvertiseBuffer(const bt_addr_le_t* addr, + const uint8_t* &adv_data, + uint8_t &adv_len) const +{ + const bt_addr_le_t* temp = NULL; + // Connected device + for (int i = 0; i < BLE_MAX_CONN_CFG; i++) + { + temp = &_peer_peripheral[i]; + if (bt_addr_le_cmp(temp, addr) == 0) + { + adv_data = _peer_peripheral_adv_data[i]; + adv_len = _peer_peripheral_adv_data_len[i]; + return; + } + } + + // Connecting device + if (bt_addr_le_cmp(&_wait_for_connect_peripheral, addr) == 0) + { + adv_data = _wait_for_connect_peripheral_adv_data; + adv_len = _wait_for_connect_peripheral_adv_data_len; + return; + } + + // Available device + if (bt_addr_le_cmp(&_available_for_connect_peripheral, addr) == 0) + { + adv_data = _available_for_connect_peripheral_adv_data; + adv_len = _available_for_connect_peripheral_adv_data_len; + return; + } + return; +} + +int BLEDeviceManager::advertisedServiceUuidCount(const BLEDevice* device) const +{ + const uint8_t* adv_data = NULL; + uint8_t adv_data_len = 0; + uint8_t service_cnt = 0; + + if (BLEUtils::isLocalBLE(*device) == true) + { + if (_has_service_uuid) + service_cnt++; + return service_cnt; + } + + getDeviceAdvertiseBuffer(device->bt_le_address(), + adv_data, + adv_data_len); + if (NULL == adv_data) + { + return service_cnt; + } + + while (adv_data_len > 1) + { + uint8_t len = adv_data[0]; + uint8_t type = adv_data[1]; + + /* Check for early termination */ + if (len == 0) + { + return service_cnt; + } + + if ((len + 1) > adv_data_len) { // Sid. KW, can't be (adv_data_len < 2) + pr_info(LOG_MODULE_BLE, "AD malformed\n"); + return service_cnt; + } + + if (type == BT_DATA_UUID16_ALL || + type == BT_DATA_UUID128_ALL) + { + service_cnt++; + } + + adv_data_len -= len + 1; + adv_data += len + 1; + } + return service_cnt; +} + +String BLEDeviceManager::localName(const BLEDevice* device) const +{ + if (BLEUtils::isLocalBLE(*device) == true) + { + return _local_name; + } + const uint8_t* adv_data = NULL; + uint8_t adv_data_len = 0; + char localname_string[BLE_MAX_ADV_SIZE]; + memset(localname_string, 0, sizeof(localname_string)); + + getDeviceAdvertiseBuffer(device->bt_le_address(), + adv_data, + adv_data_len); + + if (NULL == adv_data) { + String temp(localname_string); + return temp; + } + + while (adv_data_len > 1) + { + uint8_t len = adv_data[0]; + uint8_t type = adv_data[1]; + + /* Check for early termination */ + if (len == 0) { + String temp(localname_string); + return temp; + } + + if ((len + 1) > adv_data_len) { // Sid. KW, cannot be (adv_data_len < 2) + pr_info(LOG_MODULE_BLE, "AD malformed\n"); + String temp(localname_string); + return temp; + } + + if (type == BT_DATA_NAME_COMPLETE) + { + if (len >= BLE_MAX_ADV_SIZE) + len = BLE_MAX_ADV_SIZE-1; + memcpy(localname_string, &adv_data[2], len); + localname_string[len] = '\0'; + break; + } + + adv_data_len -= len + 1; + adv_data += len + 1; + } + + String temp(localname_string); + return temp; +} + +void BLEDeviceManager::advertisedServiceUuid(const BLEDevice* device, char *buf) const +{ + advertisedServiceUuid(device, 0, buf); +} + +void BLEDeviceManager::advertisedServiceUuid(const BLEDevice* device, int index, char *buf) const +{ + const uint8_t* adv_data = NULL; + uint8_t adv_data_len = 0; + uint8_t service_cnt = 0; + bt_uuid_128_t service_uuid; + + if (BLEUtils::isLocalBLE(*device) == true) + { + // Local device only support advertise 1 service now. + if (_has_service_uuid && index == 0) + { + BLEUtils::uuidBT2String(&_service_uuid.uuid, buf); + } + return; + } + + getDeviceAdvertiseBuffer(device->bt_le_address(), + adv_data, + adv_data_len); + + if ((uint8_t *)NULL == adv_data) + { + return; + } + + while (adv_data_len > 1) + { + uint8_t len = adv_data[0]; + uint8_t type = adv_data[1]; + + /* Check for early termination */ + if (len == 0) + { + return; + } + + if ((len + 1) > adv_data_len) { // Sid. KW, cannot be adv_data_len < 2 + pr_info(LOG_MODULE_BLE, "AD malformed\n"); + return; + } + + if (type == BT_DATA_UUID16_ALL || + type == BT_DATA_UUID128_ALL) + { + service_cnt++; + } + + if (index < service_cnt) + { + if (type == BT_DATA_UUID16_ALL) + { + service_uuid.uuid.type = BT_UUID_TYPE_16; + memcpy(&BT_UUID_16(&service_uuid.uuid)->val, &adv_data[2], 2); + } + else + { + service_uuid.uuid.type = BT_UUID_TYPE_128; + memcpy(service_uuid.val, &adv_data[2], 16); + } + + BLEUtils::uuidBT2String(&service_uuid.uuid, buf); + + break; + } + + adv_data_len -= len + 1; + adv_data += len + 1; + } +} + +int BLEDeviceManager::rssi(const BLEDevice* device) const +{ + const bt_addr_le_t* temp = NULL; + const bt_addr_le_t* addr = device->bt_le_address(); + // Connected device + for (int i = 0; i < BLE_MAX_CONN_CFG; i++) + { + temp = &_peer_peripheral[i]; + if (bt_addr_le_cmp(temp, addr) == 0) + { + return _peer_peripheral_adv_rssi[i]; + } + } + + // Connecting device + if (bt_addr_le_cmp(&_wait_for_connect_peripheral, addr) == 0) + { + return _wait_for_connect_peripheral_adv_rssi; + } + + // Available device + if (bt_addr_le_cmp(&_available_for_connect_peripheral, addr) == 0) + { + return _available_for_connect_peripheral_adv_rssi; + } + return 0; +} + +bool BLEDeviceManager::connect(BLEDevice &device) +{ + // + uint64_t timestamp = millis(); + uint64_t timestampcur = timestamp; + bool ret = true; + bt_addr_le_copy(&_wait_for_connect_peripheral, device.bt_le_address()); + // Buffer the ADV data + memcpy(_wait_for_connect_peripheral_adv_data, _available_for_connect_peripheral_adv_data, BLE_MAX_ADV_SIZE); + _wait_for_connect_peripheral_adv_data_len = _available_for_connect_peripheral_adv_data_len; + _wait_for_connect_peripheral_adv_rssi = _available_for_connect_peripheral_adv_rssi; + + startScanning(); + + pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + // Wait for the connection + while (ret && (true == BLEUtils::macAddressValid(_wait_for_connect_peripheral))) + { + timestampcur = millis(); + // TODO: dismiss the magic number + ret = (timestampcur - timestamp < 3000); // Time out + } + + pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + + if (ret == false) + { + memset(&_wait_for_connect_peripheral, 0, sizeof(_wait_for_connect_peripheral)); + } + return ret; +} + +bool BLEDeviceManager::connectToDevice(BLEDevice &device) +{ + bt_addr_le_t* temp = NULL; + bt_addr_le_t* unused = NULL; + bool link_existed = false; + bool retval = false; + + pr_debug(LOG_MODULE_BLE, "%s-%d-1", __FUNCTION__, __LINE__); + + // Find free peripheral Items + for (int i = 0; i < BLE_MAX_CONN_CFG; i++) + { + temp = &_peer_peripheral[i]; + if (true == BLEUtils::macAddressValid(*temp)) + { + if (bt_addr_le_cmp(temp, device.bt_le_address()) == 0) + { + // Connect request has scheduled but connection don't established. + // The central can see the ADV and no need to send connect request. + link_existed = true; + break; + } + } + else + { + if (NULL == unused) + { + unused = temp; + // Buffer the ADV data + memcpy(_peer_peripheral_adv_data[i], + _wait_for_connect_peripheral_adv_data, + BLE_MAX_ADV_SIZE); + _peer_peripheral_adv_data_len[i] = _wait_for_connect_peripheral_adv_data_len; + _peer_peripheral_adv_rssi[i] = _wait_for_connect_peripheral_adv_rssi; + } + } + } + pr_debug(LOG_MODULE_BLE, "%s-%d:link_existed-%d unused-%p", __FUNCTION__, __LINE__, link_existed, unused); + + if (!link_existed && NULL != unused) + { + pr_debug(LOG_MODULE_BLE, "%s-%d-Device:%s", __FUNCTION__, __LINE__, device.address().c_str()); + // Send connect request + bt_conn_t* conn = bt_conn_create_le(device.bt_le_address(), device.bt_conn_param()); + if (NULL != conn) + { + memcpy(unused, device.bt_le_address(), sizeof(bt_addr_le_t)); + retval = true; + bt_conn_unref(conn); + } + } + return retval; +} + +String BLEDeviceManager::deviceName() +{ + return _device_name; +} + +int BLEDeviceManager::appearance() +{ + return _appearance; +} + +BLEDeviceManager* BLEDeviceManager::instance() +{ + if (_instance == NULL) + { + _instance = new BLEDeviceManager(); + BLE_LIB_ASSERT(_instance != NULL); + } + return _instance; +} + +void BLEDeviceManager::setEventHandler(BLEDeviceEvent event, + BLEDeviceEventHandler eventHandler) +{ + if (event < BLEDeviceLastEvent) + _device_events[event] = eventHandler; +} + +void BLEDeviceManager::handleConnectEvent(bt_conn_t *conn, uint8_t err) +{ + struct bt_conn_info role_info; + bt_conn_get_info(conn, &role_info); + pr_info(LOG_MODULE_BLE, "%s-%d: role-%d", __FUNCTION__, __LINE__, role_info.role); + if (BT_CONN_ROLE_SLAVE == role_info.role) + { + // Central has established the connection with this peripheral device + memcpy(&_peer_central, bt_conn_get_dst(conn), sizeof (bt_addr_le_t)); + } + else + { + memset(&_wait_for_connect_peripheral, 0, sizeof(_wait_for_connect_peripheral)); + // Peripheral has established the connection with this Central device + BLEProfileManager::instance()->handleConnectedEvent(bt_conn_get_dst(conn)); + } + + if (NULL != _device_events[BLEConnected]) + { + BLEDevice tempdev(bt_conn_get_dst(conn)); + _device_events[BLEConnected](tempdev); + } +} + +void BLEDeviceManager::handleDisconnectEvent(bt_conn_t *conn, uint8_t reason) +{ + struct bt_conn_info role_info; + bt_conn_get_info(conn, &role_info); + pr_info(LOG_MODULE_BLE, "%s-%d: role-%d", __FUNCTION__, __LINE__, role_info.role); + if (BT_CONN_ROLE_SLAVE == role_info.role) + { + // Central has established the connection with this peripheral device + memset(&_peer_central, 0, sizeof (bt_addr_le_t)); + } + else + { + bt_addr_le_t* temp = NULL; + const bt_addr_le_t* disConnAddr = bt_conn_get_dst(conn); + for (int i = 0; i < BLE_MAX_CONN_CFG; i++) + { + temp = &_peer_peripheral[i]; + if (bt_addr_le_cmp(temp, disConnAddr) == 0) + { + memset(temp, 0, sizeof(bt_addr_le_t)); + memset(_peer_peripheral_adv_data[i], 0, BLE_MAX_ADV_SIZE); + _peer_peripheral_adv_data_len[i] = 0; + _peer_peripheral_adv_rssi[i] = 0; + break; + } + } + // Peripheral has established the connection with this Central device + BLEProfileManager::instance()->handleDisconnectedEvent(bt_conn_get_dst(conn)); + } + + if (NULL != _device_events[BLEDisconnected]) + { + BLEDevice tempdev(bt_conn_get_dst(conn)); + _device_events[BLEDisconnected](tempdev); + } +} + +void BLEDeviceManager::handleParamUpdated (bt_conn_t *conn, + uint16_t interval, + uint16_t latency, + uint16_t timeout) +{ + if (NULL != _device_events[BLEConParamUpdate]) + { + BLEDevice tempdev(bt_conn_get_dst(conn)); + _device_events[BLEConParamUpdate](tempdev); + } +} + +bool BLEDeviceManager::advertiseDataProc(uint8_t type, + const uint8_t *dataPtr, + uint8_t data_len) +{ + //Serial1.print("[AD]:"); + //Serial1.print(type); + //Serial1.print(" data_len "); + //Serial1.println(data_len); + + //const bt_data_t zero = {0, 0,0}; + if (_adv_accept_critical.type == 0 && + _adv_accept_critical.data_len == 0 && + _adv_accept_critical.data == NULL) + { + // Not set the critical. Accept all. + return true; + } + if (type == _adv_accept_critical.type && + data_len == _adv_accept_critical.data_len && + 0 == memcmp(dataPtr, _adv_accept_critical.data, data_len)) + { + // Now Only support 1 critical. Change those code if want support multi-criticals + return true; + } + + return false; +} + +BLEDevice BLEDeviceManager::available() +{ + BLEDevice tempdevice; + bt_addr_le_t* temp = NULL; + uint64_t timestamp = millis(); + uint8_t index = BLE_MAX_ADV_BUFFER_CFG; + uint8_t i = 0; + uint64_t max_delta = 0; + + for (i = 0; i < BLE_MAX_ADV_BUFFER_CFG; i++) + { + uint64_t timestamp_delta = timestamp - _peer_adv_mill[i]; + temp = &_peer_adv_buffer[i]; + if ((timestamp_delta <= 2000) && (max_delta < timestamp_delta)) + { + max_delta = timestamp_delta; + index = i; + } + } + //pr_debug(LOG_MODULE_BLE, "%s-%d:index %d, i-%d", __FUNCTION__, __LINE__, index, i); + + if (index < BLE_MAX_ADV_BUFFER_CFG) + { + temp = &_peer_adv_buffer[index]; + if (true == BLEUtils::macAddressValid(*temp)) + { + tempdevice.setAddress(*temp); + bt_addr_le_copy(&_available_for_connect_peripheral, temp); + memcpy(_available_for_connect_peripheral_adv_data, _peer_adv_data[index], BLE_MAX_ADV_SIZE); + _available_for_connect_peripheral_adv_data_len = _peer_adv_data_len[index]; + _available_for_connect_peripheral_adv_rssi = _peer_adv_rssi[index]; + + pr_debug(LOG_MODULE_BLE, "%s-%d:Con addr-%s", __FUNCTION__, __LINE__, BLEUtils::macAddressBT2String(*temp).c_str()); + _peer_adv_mill[index] -= 2000; // Set it as expired + } + } + return tempdevice; +} + +bool BLEDeviceManager::setAdvertiseBuffer(const bt_addr_le_t* bt_addr, + const uint8_t *ad, + uint8_t data_len, + int8_t rssi) +{ + bt_addr_le_t* temp = NULL; + uint64_t timestamp = millis(); + uint8_t index = BLE_MAX_ADV_BUFFER_CFG; + uint8_t i = 0; + uint64_t max_delta = 0; + bool retval = false; + //pr_debug(LOG_MODULE_BLE, "%s-%d-1", __FUNCTION__, __LINE__); + for (i = 0; i < BLE_MAX_ADV_BUFFER_CFG; i++) + { + uint64_t timestamp_delta = timestamp - _peer_adv_mill[i]; + temp = &_peer_adv_buffer[i]; + if (max_delta < timestamp_delta) + { + max_delta = timestamp_delta; + if (max_delta > 2000) // expired + index = i; + } + + if (bt_addr_le_cmp(temp, bt_addr) == 0) + //if (memcpy(temp->val, bt_addr->val, 6) == 0) + { + // The device alread in the buffer + index = i; + break; + } + } + //pr_debug(LOG_MODULE_BLE, "%s-%d:index %d, i-%d", __FUNCTION__, __LINE__, index, i); + + //pr_debug(LOG_MODULE_BLE, "%s-%d-2", __FUNCTION__, __LINE__); + if (index < BLE_MAX_ADV_BUFFER_CFG) + { + temp = &_peer_adv_buffer[index]; + if (i >= BLE_MAX_ADV_BUFFER_CFG) + { + memcpy(temp, bt_addr, sizeof (bt_addr_le_t)); + } + if (data_len > BLE_MAX_ADV_SIZE) + { + data_len = BLE_MAX_ADV_SIZE; + } + memcpy(_peer_adv_data[index], ad, data_len); + _peer_adv_data_len[index] = data_len; + _peer_adv_rssi[index] = rssi; + // Update the timestamp + _peer_adv_mill[index] = timestamp; + retval = true; + } + + return retval; +} + +void BLEDeviceManager::handleDeviceFound(const bt_addr_le_t *addr, + int8_t rssi, + uint8_t type, + const uint8_t *ad, + uint8_t data_len) +{ + const uint8_t *data = ad; + + /* We're only interested in connectable events */ + if (type == BT_LE_ADV_IND || type == BT_LE_ADV_DIRECT_IND) + { + //pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + while (data_len > 1) + { + uint8_t len = data[0]; + + /* Check for early termination */ + if (len == 0) + { + return; + } + + if ((len + 1) > data_len) { // Sid. KW, cannot be (data_len < 2) + pr_info(LOG_MODULE_BLE, "AD malformed\n"); + return; + } + + if (true == advertiseDataProc(data[1], &data[2], len - 1)) + { + if (true == BLEUtils::macAddressValid(_wait_for_connect_peripheral)) + { + // Not add to the buffer when try to establish the connection + if (true == BLEUtils::macAddressSame(*addr, _wait_for_connect_peripheral)) + { + BLEDevice testdev(addr); + stopScanning(); + connectToDevice(testdev); + } + } + else + { + // The critical is accepted + // Find the oldest and expired buffer + if(false == setAdvertiseBuffer(addr, ad, data_len, rssi)) + { + pr_info(LOG_MODULE_BLE, "No buffer to store the ADV\n"); + } + else if (NULL != _device_events[BLEDiscovered]) + { + BLEDevice tempdev = available(); + _device_events[BLEDiscovered](tempdev); + } + } + pr_debug(LOG_MODULE_BLE, "%s-%d: Done", __FUNCTION__, __LINE__); + return; + } + + data_len -= len + 1; + data += len + 1; + } + //pr_debug(LOG_MODULE_BLE, "%s: done", __FUNCTION__); + } + +} + + + diff --git a/libraries/BLE/src/internal/BLEDeviceManager.h b/libraries/BLE/src/internal/BLEDeviceManager.h new file mode 100644 index 00000000..06f2c97b --- /dev/null +++ b/libraries/BLE/src/internal/BLEDeviceManager.h @@ -0,0 +1,425 @@ +/* + BLE Device API + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ARDUINO_BLE_DEVICE_MANAGER_H +#define ARDUINO_BLE_DEVICE_MANAGER_H + +#include + +class BLEDeviceManager +{ + public: + /** + * @brief The BLE device constructure + * + * @param bleaddress BLE device address + * + * @return none + * + * @note none + */ + BLEDeviceManager(); + + virtual ~BLEDeviceManager(); + + + /** + * @brief Initiliaze the BLE hardware + * + * @return bool indicating success or error + * + * @note This method are for real BLE device. + * Not for peer BLE device. + */ + bool begin(BLEDevice *device); + + /** + * @brief Poll for events + * + * @param none + * + * @return none + * + * @note This method are for real BLE device. + * Not for peer BLE device. + */ + void poll(); // Do we need add the return value or + // input parameter to get the events? + // Events may inlcue: + // GAP : Connected, Disconnected, Update connetion parameter + // GATT: Discovered + + /** + * @brief Deinitiliaze the BLE hardware + * + * @param none + * + * @return none + * + * @note This method are for real BLE device. + * Not for peer BLE device. + */ + void end(); + + /** + * @brief Is the device connected with another BLE device. + * + * @param none + * + * @return none + * + * @note none + */ + bool connected(BLEDevice *device); + + /** + * @brief Disconnect the connected device/s. + * + * @param none + * + * @return none + * + * @note The BLE may connected multiple devices. + * This call will disconnect all conected devices. + */ + bool disconnect(BLEDevice *device); + + void setEventHandler(BLEDeviceEvent event, + BLEDeviceEventHandler eventHandler); + /** + * @brief Set the service UUID that the BLE Peripheral Device advertises + * + * @param[in] advertisedServiceUuid 16-bit or 128-bit UUID to advertis + * (in string form) + * + * @note This method must be called before the begin method + * Only for peripheral mode. + */ + void setAdvertisedServiceUuid(const char* advertisedServiceUuid); + + /** + * @brief Set the service UUID that is solicited in the BLE Peripheral + * Device advertises + * + * @param[in] advertisedServiceUuid 16-bit or 128-bit UUID to advertis + * (in string form) + * + * @note This method must be called before the begin method + * Only for peripheral mode. + */ + void setServiceSolicitationUuid(const char* serviceSolicitationUuid); + + /** + * @brief Set the manufacturer data in the BLE Peripheral Device advertises + * + * @param[in] manufacturerData The data about manufacturer will + * be set in advertisement + * @param[in] manufacturerDataLength The length of the manufacturer data + * + * @note This method must be called before the begin method + * Only for peripheral mode. + */ + void setManufacturerData(const unsigned char manufacturerData[], + unsigned char manufacturerDataLength); + + /** + * Set the local name that the BLE Peripheral Device advertises + * + * @param[in] localName local name to advertise + * + * @note This method must be called before the begin method + */ + void setLocalName(const char *localName); + + /** + * @brief Set advertising interval + * + * @param[in] advertisingInterval Advertising Interval in ms + * + * @return none + * + * @note none + */ + void setAdvertisingInterval(float advertisingInterval); + + /** + * @brief Set the connection parameters and send connection + * update request in both BLE peripheral and central + * + * @param[in] intervalmin Minimum Connection Interval (ms) + * + * @param[in] intervalmax Maximum Connection Interval (ms) + * + * @param[in] latency Connection Latency + * + * @param[in] timeout Supervision Timeout (ms) + * + * @return none + * + * @note none + */ + void setConnectionInterval(float minimumConnectionInterval, + float maximumConnectionInterval, + uint16_t latency, + uint16_t timeout); + + /** + * @brief Set the min and max connection interval and send connection + * update request in both BLE peripheral and central + * + * @param[in] intervalmin Minimum Connection Interval (ms) + * + * @param[in] intervalmax Maximum Connection Interval (ms) + * + * @return none + * + * @note none + */ + void setConnectionInterval(float minimumConnectionInterval, + float maximumConnectionInterval); + + /** + * @brief Set TX power of the radio in dBM + * + * @param[in] tx_power The antenna TX power + * + * @return boolean_t true if established connection, otherwise false + */ + bool setTxPower(int txPower); + + /** + * @brief Set advertising type as connectable/non-connectable + * + * @param[in] connectable true - The device connectable + * false - The device non-connectable + * + * @return none + * + * @note Only for peripheral mode. + * Default value is connectable + */ + void setConnectable(bool connectable); + + /** + * @brief Set the value of the device name characteristic + * + * @param[in] device User-defined name string for this device. Truncated if + * more than maximum allowed string length (20 bytes). + * + * @note This method must be called before the begin method + * If device name is not set, a default name will be used + */ + void setDeviceName(const char* deviceName); + void setDeviceName(); + /** + * @brief Set the appearance type for the BLE Peripheral Device + * + * See https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml + * for available options. + * + * @param[in] appearance Appearance category identifier as defined by BLE Standard + * + * @return BleStatus indicating success or error + * + * @note This method must be called before the begin method + */ + void setAppearance(unsigned short appearance); + + /** + * @brief Add a Service to the BLE Peripheral Device + * + * @param[in] attribute The service that will add to Peripheral + * + * @return BLE_STATUS_T Indicating success or error type + * + * @note This method must be called before the begin method + */ + BLE_STATUS_T addService(BLEService& attribute); + + /** + * @brief Construct the ADV data and start send advertisement + * + * @param none + * + * @return BLE_STATUS_T 0 - Success. Others - error code + * + * @note none + */ + BLE_STATUS_T startAdvertising(); + + /** + * @brief Stop send advertisement + * + * @param none + * + * @return none + * + * @note none + */ + BLE_STATUS_T stopAdvertising(); + + /** + * @brief Get currently connected central + * + * @return BLEDeviceManager Connected central device + * + * @note Peripheral mode only + */ + BLEDevice central(); + + /** + * @brief Get currently connected peripheral + * + * @param none + * + * @return none + * + * @note Central mode only. How to distinguish the peripheral? + */ + BLEDevice peripheral(); + + operator bool() const; + + // central mode + void clearAdvertiseCritical(); + void setAdvertiseCritical(String name); + void setAdvertiseCritical(BLEService& service); + bool startScanning(); // start scanning for peripherals + bool startScanningWithDuplicates(); // start scanning for peripherals, and report all duplicates + bool stopScanning(); // stop scanning for peripherals + + void setAcceptAdvertiseLocalName(String name); + void setAcceptAdvertiseLocalName(BLEService& service); + void setAcceptAdvertiseCallback(String name); + + BLEDevice available(); // retrieve a discovered peripheral + + bool hasLocalName(const BLEDevice* device) const; // does the peripheral advertise a local name + bool hasAdvertisedServiceUuid(const BLEDevice* device) const; // does the peripheral advertise a service + bool hasAdvertisedServiceUuid(const BLEDevice* device, int index) const; // does the peripheral advertise a service n + int advertisedServiceUuidCount(const BLEDevice* device) const; // number of services the peripheral is advertising + + String localName(const BLEDevice* device) const; // returns the advertised local name as a String + void advertisedServiceUuid(const BLEDevice* device, char *buf) const; // returns the advertised service as a UUID String + void advertisedServiceUuid(const BLEDevice* device, int index, char *buf) const; // returns the nth advertised service as a UUID String + + int rssi(const BLEDevice* device) const; // returns the RSSI of the peripheral at discovery + + bool connect(BLEDevice &device); // connect to the peripheral + bool connectToDevice(BLEDevice &device); + + String deviceName(); // read the device name attribute of the peripheral, and return String value + int appearance(); // read the appearance attribute of the peripheral and return value as int + + static BLEDeviceManager* instance(); + + void handleConnectEvent(bt_conn_t *conn, uint8_t err); + void handleDisconnectEvent(bt_conn_t *conn, uint8_t reason); + void handleParamUpdated (bt_conn_t *conn, + uint16_t interval, + uint16_t latency, + uint16_t timeout); + void handleDeviceFound(const bt_addr_le_t *addr, + int8_t rssi, + uint8_t type, + const uint8_t *ad, + uint8_t data_len); + +protected: + +private: + BLE_STATUS_T _advDataInit(void); + bool advertiseDataProc(uint8_t type, + const uint8_t *dataPtr, + uint8_t data_len); + bool setAdvertiseBuffer(const bt_addr_le_t* bt_addr, + const uint8_t *ad, + uint8_t data_len, + int8_t rssi); + void getDeviceAdvertiseBuffer(const bt_addr_le_t* addr, + const uint8_t* &adv_data, + uint8_t &adv_len) const; + +private: + uint16_t _min_conn_interval; + uint16_t _max_conn_interval; + bt_addr_le_t _local_bda; + char _device_name[BLE_MAX_DEVICE_NAME + 1]; + + // For Central + bt_le_scan_param_t _scan_param; // Scan parameter + bt_addr_le_t _peer_adv_buffer[BLE_MAX_ADV_BUFFER_CFG]; // Accepted peer device adress + uint64_t _peer_adv_mill[BLE_MAX_ADV_BUFFER_CFG]; // The ADV found time stamp + uint8_t _peer_adv_data[BLE_MAX_ADV_BUFFER_CFG][BLE_MAX_ADV_SIZE]; + uint8_t _peer_adv_data_len[BLE_MAX_ADV_BUFFER_CFG]; + int8_t _peer_adv_rssi[BLE_MAX_ADV_BUFFER_CFG]; + bt_data_t _adv_accept_critical; // The filters for central device + String _adv_critical_local_name; + bt_uuid_128_t _adv_critical_service_uuid; + + bt_addr_le_t _wait_for_connect_peripheral; + uint8_t _wait_for_connect_peripheral_adv_data[BLE_MAX_ADV_SIZE]; + uint8_t _wait_for_connect_peripheral_adv_data_len; + int8_t _wait_for_connect_peripheral_adv_rssi; + + bt_addr_le_t _available_for_connect_peripheral; + uint8_t _available_for_connect_peripheral_adv_data[BLE_MAX_ADV_SIZE]; + uint8_t _available_for_connect_peripheral_adv_data_len; + int8_t _available_for_connect_peripheral_adv_rssi; + + // For peripheral + struct bt_le_adv_param _adv_param; + bool _has_service_uuid; + bt_uuid_128_t _service_uuid; + bool _has_service_solicit_uuid; + bt_uuid_128_t _service_solicit_uuid; + uint16_t _appearance; + uint8_t _manufacturer_data[BLE_MAX_ADV_SIZE]; + uint8_t _manufacturer_data_length; + + // ADV data for peripheral + uint8_t _adv_type; + bt_data_t _adv_data[5]; // KW: fount _advDataInit() can use 5 slots. + size_t _adv_data_idx; + + String _local_name; + // Peripheral states + enum BLEPeripheralState { + BLE_PERIPH_STATE_NOT_READY = 0, + BLE_PERIPH_STATE_READY, + BLE_PERIPH_STATE_ADVERTISING, + BLE_PERIPH_STATE_CONNECTED, + }; + + BLEPeripheralState _state; + + // Local + static BLEDeviceManager* _instance; + BLEDevice *_local_ble; + // Connected device object + bt_addr_le_t _peer_central; + bt_addr_le_t _peer_peripheral[BLE_MAX_CONN_CFG]; + uint8_t _peer_peripheral_adv_data[BLE_MAX_CONN_CFG][BLE_MAX_ADV_SIZE]; + uint8_t _peer_peripheral_adv_data_len[BLE_MAX_CONN_CFG]; + uint8_t _peer_peripheral_adv_rssi[BLE_MAX_CONN_CFG]; + + BLEDeviceEventHandler _device_events[BLEDeviceLastEvent]; +}; + +#endif diff --git a/libraries/BLE/src/internal/BLEProfileManager.cpp b/libraries/BLE/src/internal/BLEProfileManager.cpp new file mode 100644 index 00000000..d1efb06d --- /dev/null +++ b/libraries/BLE/src/internal/BLEProfileManager.cpp @@ -0,0 +1,935 @@ +/* + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include "BLECommon.h" +#include "BLEProfileManager.h" +#include "BLECharacteristicImp.h" + +#include "BLECallbacks.h" +#include "BLEUtils.h" + +BLEDevice BLE; + +BLEProfileManager* BLEProfileManager::_instance = NULL; + +BLEProfileManager* BLEProfileManager::instance() +{ + if (NULL == _instance) + { + _instance = new BLEProfileManager(); + BLE_LIB_ASSERT(_instance != NULL); + } + pr_debug(LOG_MODULE_BLE, "%s-%d: %p", __FUNCTION__, __LINE__, _instance); + return _instance; +} + +BLEProfileManager::BLEProfileManager (): + _start_discover(false), + _discovering(false), + _discover_timestamp(0), + _cur_discover_service(NULL), + _reading(false), + _attr_base(NULL), + _attr_index(0), + _profile_registered(false) +{ + //memset(_service_header_array, 0, sizeof(_service_header_array)); + memset(_discover_params, 0, sizeof(_discover_params)); + + memset(_addresses, 0, sizeof(_addresses)); + memset(&_read_params, 0, sizeof(_read_params)); + memset(&_read_service_header, 0, sizeof(_read_service_header)); + bt_addr_le_copy(&_addresses[BLE_MAX_CONN_CFG], BLEUtils::bleGetLoalAddress()); + for (int i = 0; i <= BLE_MAX_CONN_CFG; i++) + { + _service_header_array[i].next = NULL; + _service_header_array[i].value = NULL; + } + + pr_debug(LOG_MODULE_BLE, "%s-%d: Construct", __FUNCTION__, __LINE__); +} + +BLEProfileManager::~BLEProfileManager (void) +{ + if (_attr_base) + { + free(_attr_base); + _attr_base = (bt_gatt_attr_t *)NULL; + } + ServiceReadLinkNodePtr node = link_node_get_first(&_read_service_header); + while (NULL != node) + { + link_node_remove_first(&_read_service_header); + node = link_node_get_first(&_read_service_header); + } +} + +BLE_STATUS_T +BLEProfileManager::addService (BLEDevice &bledevice, BLEService& service) +{ + + BLEServiceLinkNodeHeader* serviceheader = getServiceHeader(bledevice); + if (NULL == serviceheader) + { + int index = getUnusedIndex(); + if (index >= BLE_MAX_CONN_CFG) + { + return BLE_STATUS_NO_MEMORY; + } + serviceheader = &_service_header_array[index]; + bt_addr_le_copy(&_addresses[index], bledevice.bt_le_address()); + } + BLEServiceImp *serviceImp = this->service(bledevice, service.uuid()); + if (NULL != serviceImp) + { + // The service alreay exist + return BLE_STATUS_SUCCESS; + } + serviceImp = new BLEServiceImp(service); + if (NULL == serviceImp) + { + return BLE_STATUS_NO_MEMORY; + } + BLEServiceNodePtr node = link_node_create(serviceImp); + if (NULL == node) + { + delete serviceImp; + return BLE_STATUS_NO_MEMORY; + } + link_node_insert_last(serviceheader, node); + return BLE_STATUS_SUCCESS; +} + +BLE_STATUS_T +BLEProfileManager::addService (BLEDevice &bledevice, const bt_uuid_t* uuid) +{ + BLEService svc_obj(uuid); + return addService(bledevice, svc_obj); +} + +BLEProfileManager::BLEServiceLinkNodeHeader* BLEProfileManager::getServiceHeader(const BLEDevice &bledevice) +{ + String address = bledevice.address(); + int i; + for (i = 0; i <= BLE_MAX_CONN_CFG; i++) + { + if ((bt_addr_le_cmp(bledevice.bt_le_address(), &_addresses[i]) == 0)) + //if (true == BLEUtils::macAddressSame(*bledevice.bt_le_address(), _addresses[i])) + { + break; + } + } + if (i > BLE_MAX_CONN_CFG) + { + return NULL; + } + return &_service_header_array[i]; +} + +const BLEProfileManager::BLEServiceLinkNodeHeader* BLEProfileManager::getServiceHeader(const BLEDevice &bledevice) const +{ + String address = bledevice.address(); + int i; + for (i = 0; i <= BLE_MAX_CONN_CFG; i++) + { + if ((bt_addr_le_cmp(bledevice.bt_le_address(), &_addresses[i]) == 0)) + //if (true == BLEUtils::macAddressSame(*bledevice.bt_le_address(), _addresses[i])) + { + break; + } + } + if (i > BLE_MAX_CONN_CFG) + { + return NULL; + } + return &_service_header_array[i]; +} + +int BLEProfileManager::getUnusedIndex() +{ + int i; + for (i = 0; i < BLE_MAX_CONN_CFG; i++) + { + if (BLEUtils::macAddressValid(_addresses[i]) == false) + { + break; + } + } + + return i; +} + +int BLEProfileManager::getAttributeCount(BLEDevice &bledevice) +{ + BLEServiceLinkNodeHeader* serviceHeader = getServiceHeader(bledevice); + if (NULL == serviceHeader) + { + return 0; + } + + int attrCounter = 0; + + BLEServiceNodePtr node = serviceHeader->next; + while (node) + { + BLEServiceImp *service = node->value; + attrCounter += service->getAttributeCount(); + node = node->next; + } + return attrCounter; +} + +int BLEProfileManager::characteristicCount(const BLEDevice &bledevice) const +{ + const BLEServiceLinkNodeHeader* serviceHeader = getServiceHeader(bledevice); + if (NULL == serviceHeader) + { + return 0; + } + + int counter = 0; + + BLEServiceNodePtr node = serviceHeader->next; + while (node) + { + BLEServiceImp *service = node->value; + counter += service->getCharacteristicCount(); + node = node->next; + } + return counter; +} + +int BLEProfileManager::serviceCount(const BLEDevice &bledevice) const +{ + const BLEServiceLinkNodeHeader* serviceHeader = getServiceHeader(bledevice); + if (NULL == serviceHeader) + { + return 0; + } + return link_list_size(serviceHeader); +} + +int BLEProfileManager::registerProfile(BLEDevice &bledevice) +{ + int ret = 0; + + bt_gatt_attr_t *start; + BleStatus err_code = BLE_STATUS_SUCCESS; + + // The device is local BLE device. Register the service only allow local BLE device + BLEServiceLinkNodeHeader* serviceHeader = &_service_header_array[BLE_MAX_CONN_CFG]; + if ((bt_addr_le_cmp(bledevice.bt_le_address(), &_addresses[BLE_MAX_CONN_CFG]) != 0)) + { + return BLE_STATUS_FORBIDDEN; + } + + int attr_counter = getAttributeCount(bledevice); + if (0 == attr_counter) + { + return BLE_STATUS_NO_SERVICE; + } + + if (NULL == _attr_base) + { + _attr_base = (bt_gatt_attr_t *)malloc(attr_counter * sizeof(bt_gatt_attr_t)); + if (NULL == _attr_base) { + err_code = BLE_STATUS_NO_MEMORY; + } + else { + memset((void *)_attr_base, 0x00, (attr_counter * sizeof(bt_gatt_attr_t))); + pr_info(LOG_MODULE_BLE, "_attr_base_-%p, size-%d, attr_counter-%d", _attr_base, sizeof(_attr_base), attr_counter); + } + } + + if (BLE_STATUS_SUCCESS != err_code) + { + if (NULL != _attr_base) + { + free(_attr_base); + } + return err_code; + } + + pr_info(LOG_MODULE_BLE, "_attr_base_-%p", _attr_base); + + BLEServiceNodePtr node = serviceHeader->next; + while (node) + { + BLEServiceImp *service = node->value; + start = _attr_base + _attr_index; + service->updateProfile(start, _attr_index); + node = node->next; + } + +#if 0 + // Start debug + int i; + + for (i = 0; i < _attr_index; i++) { + { + pr_info(LOG_MODULE_APP, "gatt-: i %d, type %d, u16 0x%x", + i, + _attr_base[i].uuid->type, + BT_UUID_16(_attr_base[i].uuid)->val); + } + } + + delay(1000); + // End for debug +#endif + + ret = bt_gatt_register(_attr_base, + _attr_index); + pr_debug(LOG_MODULE_APP, "%s: ret, %d,_attr_index-%d", __FUNCTION__, ret, _attr_index); + if (0 == ret) + { + _profile_registered = true; + } + return ret; +} + +void BLEProfileManager::clearProfile(BLEServiceLinkNodeHeader* serviceHeader) +{ + if (NULL == serviceHeader) + { + return; + } + + BLEServiceNodePtr node = link_node_get_first(serviceHeader); + + while (NULL != node) + { + BLEServiceImp *service = node->value; + delete service; + link_node_remove_first(serviceHeader); + node = link_node_get_first(serviceHeader); + } +} + +BLECharacteristicImp* BLEProfileManager::characteristic(const BLEDevice &bledevice, int index) +{ + BLECharacteristicImp* characteristicImp = NULL; + BLEServiceLinkNodeHeader* serviceHeader = getServiceHeader(bledevice); + if (NULL == serviceHeader) + { + // Doesn't find the service + return NULL; + } + int counter = 0; + BLEServiceNodePtr node = serviceHeader->next; + while (node != NULL) + { + BLEServiceImp *service = node->value; + int counterTmp = service->getCharacteristicCount(); + if (counter + counterTmp > index) + { + break; + } + counter += counterTmp; + node = node->next; + } + + if (NULL != node) + { + BLEServiceImp *service = node->value; + characteristicImp = service->characteristic(index - counter); + } + return characteristicImp; +} + +BLECharacteristicImp* BLEProfileManager::characteristic(const BLEDevice &bledevice, uint16_t handle) +{ + BLECharacteristicImp* characteristicImp = NULL; + BLEServiceLinkNodeHeader* serviceHeader = getServiceHeader(bledevice); + if (NULL == serviceHeader) + { + // Doesn't find the service + return NULL; + } + + BLEServiceNodePtr node = serviceHeader->next; + while (node != NULL) + { + BLEServiceImp *service = node->value; + characteristicImp = service->characteristic(handle); + if (NULL != characteristicImp) + { + break; + } + node = node->next; + } + return characteristicImp; +} + +BLECharacteristicImp* BLEProfileManager::characteristic(const BLEDevice &bledevice, + const char* uuid, + int index) +{ + BLECharacteristicImp* characteristicImp = characteristic(bledevice, index); + if (NULL != characteristicImp) + { + if (false == characteristicImp->compareUuid(uuid)) + { + // UUID not align + characteristicImp = NULL; + } + } + return characteristicImp; +} + +BLECharacteristicImp* BLEProfileManager::characteristic(const BLEDevice &bledevice, + const char* uuid) +{ + BLECharacteristicImp* characteristicImp = NULL; + BLEServiceLinkNodeHeader* serviceHeader = getServiceHeader(bledevice); + if (NULL == serviceHeader) + { + // Doesn't find the service + return NULL; + } + BLEServiceNodePtr node = serviceHeader->next; + while (node != NULL) + { + BLEServiceImp *service = node->value; + characteristicImp = service->characteristic(uuid); + if (NULL != characteristicImp) + { + break; + } + node = node->next; + } + + return characteristicImp; +} + +BLEServiceImp* BLEProfileManager::service(const BLEDevice &bledevice, const char * uuid) const +{ + bt_uuid_128_t uuid_tmp; + BLEUtils::uuidString2BT(uuid, (bt_uuid_t *)&uuid_tmp); + //pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + return service(bledevice, (const bt_uuid_t *)&uuid_tmp); +} + +BLEServiceImp* BLEProfileManager::service(const BLEDevice &bledevice, const bt_uuid_t* uuid) const +{ + BLEServiceImp* serviceImp = NULL; + #if 1 + const BLEServiceLinkNodeHeader* serviceHeader = getServiceHeader(bledevice); + if (NULL == serviceHeader) + { + // Doesn't find the service + return NULL; + } + BLEServiceNodePtr node = serviceHeader->next; + + // Just for debug + char uuid_tmp[37]; + BLEUtils::uuidBT2String(uuid, uuid_tmp); + pr_debug(LOG_MODULE_BLE, "%s-%d: %s", __FUNCTION__, __LINE__, uuid_tmp); + + while (node != NULL) + { + serviceImp = node->value; + if (true == serviceImp->compareUuid(uuid)) + { + break; + } + node = node->next; + } + + if (NULL == node) + { + serviceImp = NULL; + } + #endif + return serviceImp; +} + +BLEServiceImp* BLEProfileManager::service(const BLEDevice &bledevice, int index) const +{ + BLEServiceImp* serviceImp = NULL; + const BLEServiceLinkNodeHeader* serviceHeader = getServiceHeader(bledevice); + if (NULL == serviceHeader) + { + // Doesn't find the service + return NULL; + } + BLEServiceNodePtr node = serviceHeader->next; + + while (node != NULL) + { + if (0 == index) + { + break; + } + index--; + node = node->next; + } + if (NULL == node) + { + serviceImp = NULL; + } + else + { + serviceImp = node->value; + } + return serviceImp; +} + +void BLEProfileManager::handleConnectedEvent(const bt_addr_le_t* deviceAddr) +{ + int index = getUnusedIndex(); + if (index >= BLE_MAX_CONN_CFG) + { + //BLE_STATUS_NO_MEMORY + return; + } + bt_addr_le_copy(&_addresses[index], deviceAddr); +} + +void BLEProfileManager::handleDisconnectedEvent(const bt_addr_le_t* deviceAddr) +{ + BLEServiceLinkNodeHeader* serviceheader = NULL; + int i; + for (i = 0; i < BLE_MAX_CONN_CFG; i++) + { + if ((bt_addr_le_cmp(deviceAddr, &_addresses[i]) == 0)) + { + break; + } + } + if (i >= BLE_MAX_CONN_CFG) + { + return; + } + + serviceheader = &_service_header_array[i]; + clearProfile(serviceheader); + memset(&_addresses[i], 0, sizeof(bt_addr_le_t)); +} + +bool BLEProfileManager::discoverAttributes(BLEDevice* device) +{ + int err; + bt_conn_t* conn; + int i = getDeviceIndex(device); + bool ret = false; + bt_gatt_discover_params_t* temp = NULL; + + pr_debug(LOG_MODULE_BLE, "%s-%d: index-%d,fun-%p", __FUNCTION__, __LINE__, i,profile_discover_process); + + if (i >= BLE_MAX_CONN_CFG) + { + // The device already in the buffer. + // This function only be called after connection established. + return ret; + } + + conn = bt_conn_lookup_addr_le(device->bt_le_address()); + if (NULL == conn) + { + // Link lost + pr_debug(LOG_MODULE_BLE, "Can't find connection\n"); + return ret; + } + temp = &_discover_params[i]; + temp->start_handle = 1; + temp->end_handle = 0xFFFF; + temp->uuid = NULL; + temp->type = BT_GATT_DISCOVER_PRIMARY; + temp->func = profile_discover_process; + + err = bt_gatt_discover(conn, temp); + bt_conn_unref(conn); + if (err) + { + pr_debug(LOG_MODULE_BLE, "Discover failed(err %d)\n", err); + return ret; + } + // Block it + _start_discover = true; + while (_start_discover) // Sid. KW warning acknowldged + { + delay(10); + } + return true; +} + +int BLEProfileManager::getDeviceIndex(const bt_addr_le_t* macAddr) +{ + int i; + for (i = 0; i < BLE_MAX_CONN_CFG; i++) + { + if ((bt_addr_le_cmp(macAddr, &_addresses[i]) == 0)) + { + break; + } + } + return i; +} + +int BLEProfileManager::getDeviceIndex(const BLEDevice* device) +{ + return getDeviceIndex(device->bt_le_address()); +} + +bool BLEProfileManager::discovering() +{ + bool ret = (millis() - _discover_timestamp) < 1500; + ret = (_discovering && ret); + if (_cur_discover_service != NULL) + { + ret = ret || _cur_discover_service->discovering(); + } + return ret; +} + +void BLEProfileManager::setDiscovering(bool discover) +{ + if (discover) + { + _discover_timestamp = millis(); + } + _discovering = discover; +} + +uint8_t BLEProfileManager::discoverResponseProc(bt_conn_t *conn, + const bt_gatt_attr_t *attr, + bt_gatt_discover_params_t *params) +{ + const bt_addr_le_t* dst_addr = bt_conn_get_dst(conn); + int i = getDeviceIndex(dst_addr); + BLEDevice device(dst_addr); + uint8_t retVal = BT_GATT_ITER_STOP; + + //pr_debug(LOG_MODULE_BLE, "%s-%d: index-%d", __FUNCTION__, __LINE__, i); + + if (i >= BLE_MAX_CONN_CFG) + { + return BT_GATT_ITER_STOP; + } + + // Process the service + switch (params->type) + { + case BT_GATT_DISCOVER_CHARACTERISTIC: + case BT_GATT_DISCOVER_DESCRIPTOR: + { + if (NULL != _cur_discover_service) + { + retVal = _cur_discover_service->discoverResponseProc(conn, + attr, + params); + } + break; + } + case BT_GATT_DISCOVER_PRIMARY: + { + if (NULL != attr) + { + struct bt_gatt_service *svc_value = (struct bt_gatt_service *)attr->user_data; + const bt_uuid_t* svc_uuid = svc_value->uuid; + + setDiscovering(false); + // TODO: Pontential bugs + if (svc_uuid->type == BT_UUID_TYPE_16 && + ((const bt_uuid_16_t *)svc_uuid)->val == 0) + { + // Discover failed. The service may unknow type. + // Need read the value and discovery again. + readService(device, attr->handle); + } + else + { + int err_code = (int)addService(device, svc_value->uuid); + params->uuid = NULL; + if (BLE_STATUS_SUCCESS == err_code) + { + BLEServiceImp* service_tmp = service(device, svc_value->uuid); + if (NULL != service_tmp) + { + service_tmp->setHandle(attr->handle); + service_tmp->setEndHandle(svc_value->end_handle); + } + } + else + { + pr_debug(LOG_MODULE_BLE, "%s-%d: Error-%d", + __FUNCTION__, __LINE__, err_code); + } + } + retVal = BT_GATT_ITER_CONTINUE; + } + else + { + // Service discover complete + retVal = BT_GATT_ITER_STOP; + } + } + default: + { + break; + } + } + + if (retVal == BT_GATT_ITER_STOP) + { + checkReadService(); + if (discovering() == false) + { + const BLEServiceLinkNodeHeader* serviceHeader = getServiceHeader(device); + BLEServiceImp* serviceCurImp = NULL; + if (NULL == serviceHeader) + { + // Doesn't find the service + return BT_GATT_ITER_STOP; + } + BLEServiceNodePtr node = serviceHeader->next; + + // Discover next service + while (node != NULL) + { + serviceCurImp = node->value; + + if (NULL == _cur_discover_service) + { + bool result = serviceCurImp->discoverAttributes(&device); + if (result == true) + { + // Record the current discovering service + _cur_discover_service = serviceCurImp; + break; + } + } + else if (_cur_discover_service == serviceCurImp) + { + // Find next discoverable service + _cur_discover_service = NULL; + } + + node = node->next; + } + if (NULL == node) + { + pr_debug(LOG_MODULE_BLE, "%s-%d: Discover completed", + __FUNCTION__, __LINE__); + _start_discover = false; + } + } + } + return retVal; +} + +void BLEProfileManager::serviceDiscoverComplete(const BLEDevice &bledevice) +{ + BLEServiceImp* serviceCurImp = NULL; + BLEServiceImp* servicePrevImp = NULL; + const BLEServiceLinkNodeHeader* serviceHeader = getServiceHeader(bledevice); + if (NULL == serviceHeader) + { + // Doesn't find the service + return ; + } + + BLEServiceNodePtr node = serviceHeader->next; + if (NULL != node) + { + servicePrevImp = node->value; + node = node->next; + } + + // Update the service handles + while (node != NULL) + { + serviceCurImp = node->value; + if (NULL != serviceCurImp) + { + if (servicePrevImp) // KW issue: Chk for NULL. + servicePrevImp->setEndHandle(serviceCurImp->startHandle() - 1); + } + + if (servicePrevImp) + { + pr_debug(LOG_MODULE_BLE, "Curr: start-%d, end-%d", servicePrevImp->startHandle(), servicePrevImp->endHandle()); + } + servicePrevImp = serviceCurImp; + if (servicePrevImp) // KW issue: Chk for NULL. + pr_debug(LOG_MODULE_BLE, "Curr: start-%d, end-%d", servicePrevImp->startHandle(), servicePrevImp->endHandle()); + node = node->next; + } + return; +} + +bool BLEProfileManager::readService(const BLEDevice &bledevice, uint16_t handle) +{ + int retval = 0; + bt_conn_t* conn = NULL; + + if (true == BLEUtils::isLocalBLE(bledevice)) + { + // GATT server can't write + return false; + } + + if (_reading) + { + // Read response not back + // Add to buffer + ServiceRead_t temp; + bt_addr_le_copy(&temp.address, bledevice.bt_le_address()); + temp.handle = handle; + ServiceReadLinkNodePtr node = link_node_create(temp); + link_node_insert_last(&_read_service_header, node); + return true; + } + + _read_params.func = profile_service_read_rsp_process; + _read_params.handle_count = 1; + _read_params.single.handle = handle; + _read_params.single.offset = 0; + + if (0 == _read_params.single.handle) + { + // Discover not complete + return false; + } + + conn = bt_conn_lookup_addr_le(bledevice.bt_le_address()); + if (NULL == conn) + { + return false; + } + // Send read request + retval = bt_gatt_read(conn, &_read_params); + bt_conn_unref(conn); + if (0 == retval) + { + setDiscovering(true); + _reading = true; + } + pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + return _reading; +} + +void BLEProfileManager::checkReadService() +{ + ServiceReadLinkNodePtr node = link_node_get_first(&_read_service_header); + while (NULL != node) + { + BLEDevice temp(&node->value.address); + if (true == readService(temp, node->value.handle)) + { + break; + } + link_node_remove_first(&_read_service_header); + node = link_node_get_first(&_read_service_header); + } +} + +bool BLEProfileManager::discoverService(BLEDevice* device, const bt_uuid_t* svc_uuid) +{ + int err = 0; + bt_conn_t* conn; + int i = getDeviceIndex(device); + bool ret = false; + bt_gatt_discover_params_t* temp = NULL; + + pr_debug(LOG_MODULE_BLE, "%s-%d: index-%d,fun-%p", __FUNCTION__, __LINE__, i,profile_discover_process); + + if (i >= BLE_MAX_CONN_CFG) + { + // The device already in the buffer. + // This function only be called after connection established. + return ret; + } + + BLEServiceImp* serviceImp = service(device, svc_uuid); + if (NULL == serviceImp) + { + return ret; + } + + conn = bt_conn_lookup_addr_le(device->bt_le_address()); + if (NULL == conn) + { + // Link lost + pr_debug(LOG_MODULE_BLE, "Can't find connection\n"); + return ret; + } + temp = &_discover_params[i]; + temp->start_handle = 1; + temp->end_handle = 0xFFFF; + temp->uuid = (bt_uuid_t*) serviceImp->bt_uuid(); + temp->type = BT_GATT_DISCOVER_PRIMARY; + temp->func = profile_discover_process; + + err = bt_gatt_discover(conn, temp); + bt_conn_unref(conn); + if (err) + { + pr_debug(LOG_MODULE_BLE, "Discover failed(err %d)\n", err); + return ret; + } + return true; +} + +uint8_t BLEProfileManager::serviceReadRspProc(bt_conn_t *conn, + int err, + bt_gatt_read_params_t *params, + const void *data, + uint16_t length) +{ + _reading = false; + if (NULL == data) + { + return BT_GATT_ITER_STOP; + } + BLEDevice bleDevice(bt_conn_get_dst(conn)); + + pr_debug(LOG_MODULE_BLE, "%s-%d:length-%d", __FUNCTION__, __LINE__, length); + if (length == UUID_SIZE_128) + { + bt_uuid_128_t uuid_tmp; + uuid_tmp.uuid.type = BT_UUID_TYPE_128; + memcpy(uuid_tmp.val, data, UUID_SIZE_128); + /**/ + int retval = (int)BLEProfileManager::instance()->addService(bleDevice, (const bt_uuid_t *)&uuid_tmp); + if (BLE_STATUS_SUCCESS != retval) + { + pr_error(LOG_MODULE_BLE, "%s-%d: Error-%d", + __FUNCTION__, __LINE__, retval); + return BT_GATT_ITER_STOP; + } + + BLEServiceImp* serviceImp = service(&bleDevice, (const bt_uuid_t *)&uuid_tmp);//(BLEServiceImp*)testTTTTTTT();// + if (NULL == serviceImp) + { + pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + return BT_GATT_ITER_STOP; + } + BLEProfileManager::instance()->discoverService(&bleDevice, (const bt_uuid_t *)&uuid_tmp); + } + pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + + return BT_GATT_ITER_STOP; +} + + + diff --git a/libraries/BLE/src/internal/BLEProfileManager.h b/libraries/BLE/src/internal/BLEProfileManager.h new file mode 100644 index 00000000..5c548f7d --- /dev/null +++ b/libraries/BLE/src/internal/BLEProfileManager.h @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __BLE_PROFILE_MANAGER_H__ +#define __BLE_PROFILE_MANAGER_H__ + +#include "ArduinoBLE.h" + +#include "BLEServiceImp.h" + +//#include "BLECommon.h" +//#include "BLEDevice.h" +//#include "BLEService.h" +typedef struct { + bt_addr_le_t address; + uint16_t handle; +}ServiceRead_t; + +class BLEProfileManager{ +public: + /** + * @brief Get the BLEProfile Manager instance + * + * @param none + * + * @return BLEProfileManager* BLE Profile manager + * + * @note none + */ + static BLEProfileManager* instance(); + + /** + * @brief Add an service to the BLE Device + * + * @param[in] bledevice The BLE device that owned the service + * + * @param[in] service The service to add to BLE device profile + * + * @return BleStatus indicating success or error + * + * @note This method must be called before the begin method in GATT server role + * Or be called in discover process. + */ + BLE_STATUS_T addService (BLEDevice &bledevice, BLEService& service); + BLE_STATUS_T addService (BLEDevice &bledevice, const bt_uuid_t* uuid); + + /** + * @brief Register the profile to Nordic BLE stack + * + * @param[in] bledevice The BLE Device + * + * @return int std C errno + * + * @note none + */ + int registerProfile(BLEDevice &bledevice); + + inline bool hasRegisterProfile(){return _profile_registered;} + + /** + * @brief Get the BLE's Characteristic implementation object by uuid and index + * + * @param[in] bledevice The BLE device + * + * @param[in] uuid The characteristic UUID + * + * @param[in] index The characteristic index in the profile + * + * @return BLECharacteristicImp* The BLE characteristic implementation object + * + * @note none + */ + BLECharacteristicImp* characteristic(const BLEDevice &bledevice, + const char* uuid, + int index); + BLECharacteristicImp* characteristic(const BLEDevice &bledevice, + const char* uuid); + BLECharacteristicImp* characteristic(const BLEDevice &bledevice, + int index); + BLECharacteristicImp* characteristic(const BLEDevice &bledevice, + uint16_t handle); + BLEServiceImp* service(const BLEDevice &bledevice, const char * uuid) const; + BLEServiceImp* service(const BLEDevice &bledevice, int index) const; + BLEServiceImp* service(const BLEDevice &bledevice, const bt_uuid_t* uuid) const; + int serviceCount(const BLEDevice &bledevice) const; + int characteristicCount(const BLEDevice &bledevice) const; + + uint8_t discoverResponseProc(bt_conn_t *conn, + const bt_gatt_attr_t *attr, + bt_gatt_discover_params_t *params); + + bool discoverAttributes(BLEDevice* device); + bool discoverService(BLEDevice* device, const bt_uuid_t* svc_uuid); + void handleConnectedEvent(const bt_addr_le_t* deviceAddr); + void handleDisconnectedEvent(const bt_addr_le_t* deviceAddr); + uint8_t serviceReadRspProc(bt_conn_t *conn, + int err, + bt_gatt_read_params_t *params, + const void *data, + uint16_t length); +protected: + friend ssize_t profile_write_process(bt_conn_t *conn, + const bt_gatt_attr_t *attr, + const void *buf, uint16_t len, + uint16_t offset); +private: + typedef LinkNode BLEServiceLinkNodeHeader; + typedef LinkNode* BLEServiceNodePtr; + typedef LinkNode BLEServiceNode; + + typedef LinkNode ServiceReadLinkNodeHeader; + typedef LinkNode* ServiceReadLinkNodePtr; + typedef LinkNode ServiceReadLinkNode; + + BLEProfileManager(); + ~BLEProfileManager (void); + + void serviceDiscoverComplete(const BLEDevice &bledevice); + + int getDeviceIndex(const bt_addr_le_t* macAddr); + int getDeviceIndex(const BLEDevice* device); + /** + * @brief Get the unused service header index + * + * @param none + * + * @return int The unused BLE profile index + * + * @note This object has a buffer to manage all devices profile. + * The buffer is an array. The different profiles + * distinguished by BLE address. + */ + int getUnusedIndex(); + + /** + * @brief Get the Service header by BLE device + * + * @param[in] bledevice The BLE device + * + * @return none + * + * @note none + */ + BLEServiceLinkNodeHeader* getServiceHeader(const BLEDevice &bledevice); + const BLEServiceLinkNodeHeader* getServiceHeader(const BLEDevice &bledevice) const; + + /** + * @brief Get the BLE attribute counter based on services, characteristics + * and descriptors. + * + * @param none + * + * @return none + * + * @note none + */ + int getAttributeCount(BLEDevice &bledevice); + + /** + * @brief Discard the profile by BLE device + * + * @param[in] bledevice The BLE device + * + * @return none + * + * @note none + */ + void clearProfile(BLEServiceLinkNodeHeader* serviceHeader); + + bool readService(const BLEDevice &bledevice, uint16_t handle); + bool discovering(); + void setDiscovering(bool discover); + void checkReadService(); + +private: + // The last header is for local BLE + BLEServiceLinkNodeHeader _service_header_array[BLE_MAX_CONN_CFG + 1]; // The connected devices' service and self service + bt_addr_le_t _addresses[BLE_MAX_CONN_CFG + 1]; // The BLE devices' address + + bool _start_discover; + + bool _discovering; + uint64_t _discover_timestamp; + bt_gatt_discover_params_t _discover_params[BLE_MAX_CONN_CFG]; + BLEServiceImp* _cur_discover_service; + bt_gatt_read_params_t _read_params; + bool _reading; + ServiceReadLinkNodeHeader _read_service_header; + + bt_gatt_attr_t *_attr_base; // Allocate the memory for BLE stack + int _attr_index; + + static BLEProfileManager* _instance; // The profile manager instance + bool _profile_registered; +}; + +#endif + diff --git a/libraries/BLE/src/internal/BLEServiceImp.cpp b/libraries/BLE/src/internal/BLEServiceImp.cpp new file mode 100644 index 00000000..b67d289a --- /dev/null +++ b/libraries/BLE/src/internal/BLEServiceImp.cpp @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2015 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "internal/ble_client.h" + +#include "BLEServiceImp.h" +#include "BLECallbacks.h" +#include "BLEUtils.h" +#include "BLECharacteristicImp.h" + +bt_uuid_16_t BLEServiceImp::_gatt_primary_uuid = {BT_UUID_TYPE_16, BT_UUID_GATT_PRIMARY_VAL}; + +bt_uuid_t *BLEServiceImp::getPrimayUuid(void) +{ + return (bt_uuid_t *)&_gatt_primary_uuid; +} + +BLEServiceImp::BLEServiceImp(BLEService& service): + BLEAttribute(service.uuid(), BLETypeService), + _start_handle(0), + _end_handle(0xFFFF), + _cur_discover_chrc(NULL) +{ + memset(&_characteristics_header, 0, sizeof(_characteristics_header)); + service.setServiceImp(this); +} + +BLEServiceImp::BLEServiceImp(const bt_uuid_t* uuid): + BLEAttribute(uuid, BLETypeService), + _start_handle(0), + _end_handle(0xFFFF), + _cur_discover_chrc(NULL) +{ + memset(&_characteristics_header, 0, sizeof(_characteristics_header)); +} + +BLEServiceImp::~BLEServiceImp() +{ + releaseCharacteristic(); +} + + +int BLEServiceImp::addCharacteristic(BLEDevice& bledevice, BLECharacteristic& characteristic) +{ + BLECharacteristicImp* characteristicImp = this->characteristic(characteristic.uuid()); + if (NULL != characteristicImp) + { + pr_info(LOG_MODULE_BLE, "%s-%d: Already exist",__FUNCTION__, __LINE__); + return BLE_STATUS_SUCCESS; + } + characteristicImp = new BLECharacteristicImp(characteristic, bledevice); + pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); + if (NULL == characteristicImp) + { + return BLE_STATUS_NO_MEMORY; + } + + BLECharacteristicNodePtr node = link_node_create(characteristicImp); + if (NULL == node) + { + delete characteristicImp; + return BLE_STATUS_NO_MEMORY; + } + link_node_insert_last(&_characteristics_header, node); + pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); + return BLE_STATUS_SUCCESS; +} + +int BLEServiceImp::addCharacteristic(BLEDevice& bledevice, + const bt_uuid_t* uuid, + uint16_t handle, + unsigned char properties) +{ + BLECharacteristicImp* characteristicImp = this->characteristic(uuid); + if (NULL != characteristicImp) + { + pr_info(LOG_MODULE_BLE, "%s-%d: Already exist",__FUNCTION__, __LINE__); + return BLE_STATUS_SUCCESS; + } + pr_debug(LOG_MODULE_BLE, "%s-%d:handle-%d",__FUNCTION__, __LINE__,handle); + characteristicImp = new BLECharacteristicImp(uuid, + properties, + handle, + bledevice); + if (NULL == characteristicImp) + { + return BLE_STATUS_NO_MEMORY; + } + + BLECharacteristicNodePtr node = link_node_create(characteristicImp); + if (NULL == node) + { + delete characteristicImp; + return BLE_STATUS_NO_MEMORY; + } + link_node_insert_last(&_characteristics_header, node); + pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); + return BLE_STATUS_SUCCESS; +} + +int BLEServiceImp::updateProfile(bt_gatt_attr_t *attr_start, int& index) +{ + bt_gatt_attr_t *start = attr_start; + int base_index = index; + int offset = 0; + int counter = 0; + start->uuid = BLEServiceImp::getPrimayUuid(); + start->perm = BT_GATT_PERM_READ; + start->read = bt_gatt_attr_read_service; + start->user_data = (void *)bt_uuid(); + + pr_debug(LOG_MODULE_BLE, "service-%p", start); + start++; + index++; + counter++; + + BLECharacteristicNodePtr node = _characteristics_header.next; + while (NULL != node) + { + BLECharacteristicImp *characteristicImp = node->value; + start = attr_start + index - base_index; + offset = characteristicImp->updateProfile(start, index); + counter += offset; + node = node->next; + } + return counter; +} + +int BLEServiceImp::getAttributeCount() +{ + int counter = 1; // Service itself + + BLECharacteristicNodePtr node = _characteristics_header.next; + while (NULL != node) + { + BLECharacteristicImp *characteristicImp = node->value; + + counter += characteristicImp->getAttributeCount(); + node = node->next; + } + return counter; +} + +int BLEServiceImp::getCharacteristicCount() +{ + return link_list_size(&_characteristics_header); +} + +void BLEServiceImp::releaseCharacteristic() +{ + BLECharacteristicNodePtr node = link_node_get_first(&_characteristics_header); + pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + while (NULL != node) + { + BLECharacteristicImp* characteristicImp = node->value; + delete characteristicImp; + link_node_remove_first(&_characteristics_header); + node = link_node_get_first(&_characteristics_header); + } + pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); +} + + +BLECharacteristicImp* BLEServiceImp::characteristic(int index) +{ + BLECharacteristicImp* characteristicImp = NULL; + BLECharacteristicNodePtr node = link_node_get_first(&_characteristics_header); + while (NULL != node) + { + if (0 >= index) + { + characteristicImp = node->value; + break; + } + index--; + node = node->next; + } + return characteristicImp; +} + +BLECharacteristicImp* BLEServiceImp::characteristic(uint16_t handle) +{ + BLECharacteristicImp* characteristicImp = NULL; + BLECharacteristicNodePtr node = link_node_get_first(&_characteristics_header); + while (NULL != node) + { + characteristicImp = node->value; + if (handle == characteristicImp->valueHandle()) + { + break; + } + node = node->next; + } + if (NULL == node) + { + characteristicImp = NULL; + } + return characteristicImp; +} + +BLECharacteristicImp* BLEServiceImp::characteristic(const bt_uuid_t* uuid) +{ + BLECharacteristicImp* characteristicImp = NULL; + BLECharacteristicNodePtr node = link_node_get_first(&_characteristics_header); + // Just for debug + //char uuid_tmp[37]; + //BLEUtils::uuidBT2String(uuid, uuid_tmp); + //pr_debug(LOG_MODULE_BLE, "%s-%d: %s", __FUNCTION__, __LINE__, uuid_tmp); + + while (NULL != node) + { + characteristicImp = node->value; + if (true == characteristicImp->compareUuid(uuid)) + { + break; + } + //BLEUtils::uuidBT2String(characteristicImp->bt_uuid(), uuid_tmp); + //pr_debug(LOG_MODULE_BLE, "%s-%d: %s", __FUNCTION__, __LINE__, uuid_tmp); + node = node->next; + } + + if (NULL == node) + { + characteristicImp = NULL; + } + return characteristicImp; +} + +BLECharacteristicImp* BLEServiceImp::characteristic(const char* uuid) +{ + bt_uuid_128_t uuid_tmp; + BLEUtils::uuidString2BT(uuid, (bt_uuid_t *)&uuid_tmp); + return characteristic((const bt_uuid_t *)&uuid_tmp); +} + +bool BLEServiceImp::discovering() +{ + return (_cur_discover_chrc != NULL); +} + +bool BLEServiceImp::discoverAttributes(BLEDevice* device) +{ + pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + int err; + bt_conn_t* conn; + bt_gatt_discover_params_t* temp = NULL; + const bt_uuid_t* service_uuid = bt_uuid(); + + if (service_uuid->type == BT_UUID_TYPE_16) + { + uint16_t uuid_tmp = ((bt_uuid_16_t*)service_uuid)->val; + if (BT_UUID_GAP_VAL == uuid_tmp || + BT_UUID_GATT_VAL == uuid_tmp) + { + return false; + } + } + + conn = bt_conn_lookup_addr_le(device->bt_le_address()); + if (NULL == conn) + { + // Link lost + pr_debug(LOG_MODULE_BLE, "Can't find connection\n"); + return false; + } + temp = &_discover_params; + temp->start_handle = _start_handle; + temp->end_handle = _end_handle; + temp->uuid = NULL; + temp->type = BT_GATT_DISCOVER_CHARACTERISTIC; + temp->func = profile_discover_process; + + err = bt_gatt_discover(conn, temp); + bt_conn_unref(conn); + if (err) + { + pr_debug(LOG_MODULE_BLE, "Discover failed(err %d)\n", err); + return false; + } + return true; +} + +uint8_t BLEServiceImp::discoverResponseProc(bt_conn_t *conn, + const bt_gatt_attr_t *attr, + bt_gatt_discover_params_t *params) +{ + const bt_addr_le_t* dst_addr = bt_conn_get_dst(conn); + BLEDevice device(dst_addr); + uint8_t retVal = BT_GATT_ITER_STOP; + + //pr_debug(LOG_MODULE_BLE, "%s-%d: type-%d", __FUNCTION__, __LINE__, params->type); + + // Process the service + switch (params->type) + { + case BT_GATT_DISCOVER_CHARACTERISTIC: + { + if (NULL != attr) + { + //const bt_uuid_t* chrc_uuid = attr->uuid; + uint16_t chrc_handle = attr->handle + 1; + struct bt_gatt_chrc* psttemp = (struct bt_gatt_chrc*)attr->user_data; + int retval = (int)addCharacteristic(device, + psttemp->uuid, + chrc_handle, + psttemp->properties); + + //pr_debug(LOG_MODULE_BLE, "%s-%d:handle-%d:%d", __FUNCTION__, __LINE__,attr->handle, chrc_handle); + if (BLE_STATUS_SUCCESS != retval) + { + pr_error(LOG_MODULE_BLE, "%s-%d: Error-%d", + __FUNCTION__, __LINE__, retval); + } + //retVal = BT_GATT_ITER_CONTINUE; + } + break; + } + case BT_GATT_DISCOVER_DESCRIPTOR: + { + // + + if (NULL != _cur_discover_chrc) + { + retVal = _cur_discover_chrc->discoverResponseProc(conn, + attr, + params); + } + break; + } + default: + { + //attribute_tmp->discover(attr, &_discover_params); + break; + } + } + + pr_debug(LOG_MODULE_BLE, "%s-%d:ret-%d",__FUNCTION__, __LINE__, retVal); + if (retVal == BT_GATT_ITER_STOP) + { + const BLECharacteristicLinkNodeHeader* chrcHeader = &_characteristics_header; + BLECharacteristicImp* chrcCurImp = NULL; + BLECharacteristicNodePtr node = chrcHeader->next; + + pr_debug(LOG_MODULE_BLE, "%s-%d: node-%p",__FUNCTION__, __LINE__, node); + // Discover next service + while (node != NULL) + { + chrcCurImp = node->value; + + if (NULL == _cur_discover_chrc) + { + bool result = chrcCurImp->discoverAttributes(&device); + pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); + if (result == true) + { + // Record the current discovering service + _cur_discover_chrc = chrcCurImp; + break; + } + } + else if (_cur_discover_chrc == chrcCurImp) + { + // Find next discoverable service + _cur_discover_chrc = NULL; + } + node = node->next; + } + } + return retVal; +} + + diff --git a/libraries/BLE/src/internal/BLEServiceImp.h b/libraries/BLE/src/internal/BLEServiceImp.h new file mode 100644 index 00000000..ccea6ab0 --- /dev/null +++ b/libraries/BLE/src/internal/BLEServiceImp.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _BLE_SERVICE_IMP_H_INCLUDED +#define _BLE_SERVICE_IMP_H_INCLUDED + +#include "ArduinoBLE.h" + +#include "BLEAttribute.h" + +#include "LinkList.h" + +/** + * BLE GATT Service + */ +class BLEServiceImp: public BLEAttribute{ +public: + /** + * Constructor for BLE Service + * + * @param[in] uuid 16-bit or 128-bit UUID (in string form) defined by BLE standard + */ + BLEServiceImp(BLEService& service); + BLEServiceImp(const bt_uuid_t* uuid); + ~BLEServiceImp(); + + /** + * @brief Add a characteristic in service + * + * @param[in] bledevice The BLE device want to add the characteristic + * + * @param[in] characteristic The characteristic want to be added to service + * + * @return none + * + * @note none + */ + int addCharacteristic(BLEDevice& bledevice, BLECharacteristic& characteristic); + int addCharacteristic(BLEDevice& bledevice, + const bt_uuid_t* uuid, + uint16_t handle, + unsigned char properties); + int getCharacteristicCount(); + + BLECharacteristicImp* characteristic(const bt_uuid_t* uuid); + BLECharacteristicImp* characteristic(const char* uuid); + BLECharacteristicImp* characteristic(int index); + BLECharacteristicImp* characteristic(uint16_t handle); + inline void setHandle(uint16_t handle){_start_handle = handle;} + inline void setEndHandle(uint16_t handle){_end_handle = handle;} + inline uint16_t endHandle(){return _end_handle;} + inline uint16_t startHandle(){return _start_handle;} + + bool discoverAttributes(BLEDevice* device); + uint8_t discoverResponseProc(bt_conn_t *conn, + const bt_gatt_attr_t *attr, + bt_gatt_discover_params_t *params); + bool discovering(); + + static bt_uuid_t *getPrimayUuid(void); +protected: + friend class BLEProfileManager; + + int getAttributeCount(); + + + int updateProfile(bt_gatt_attr_t *attr_start, int& index); +private: + typedef LinkNode BLECharacteristicLinkNodeHeader; + typedef LinkNode* BLECharacteristicNodePtr; + typedef LinkNode BLECharacteristicNode; + + uint16_t _start_handle; + uint16_t _end_handle; + + void releaseCharacteristic(); + BLECharacteristicImp *_cur_discover_chrc; + + static bt_uuid_16_t _gatt_primary_uuid; + bt_gatt_discover_params_t _discover_params; + + BLECharacteristicLinkNodeHeader _characteristics_header; // The characteristic link list +}; + +#endif // _BLE_SERVICE_H_INCLUDED diff --git a/libraries/BLE/src/internal/BLEUtils.cpp b/libraries/BLE/src/internal/BLEUtils.cpp new file mode 100644 index 00000000..ed9311ba --- /dev/null +++ b/libraries/BLE/src/internal/BLEUtils.cpp @@ -0,0 +1,190 @@ + +#include "ArduinoBLE.h" +#include "BLEUtils.h" +#include "internal/ble_client.h" + +String BLEUtils::macAddressBT2String(const bt_addr_le_t &bd_addr) +{ + char mac_string[BT_ADDR_STR_LEN]; + snprintf(mac_string, BT_ADDR_STR_LEN, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", + bd_addr.val[5], bd_addr.val[4], bd_addr.val[3], + bd_addr.val[2], bd_addr.val[1], bd_addr.val[0]); + String temp(mac_string); + return temp; +} + +void BLEUtils::macAddressString2BT(const char* mac_str, bt_addr_le_t &bd_addr) +{ + char temp[] = {0, 0, 0}; + int strLength = strlen(mac_str); + int length = 0; + + bd_addr.type = BT_ADDR_LE_PUBLIC; + + for (int i = strLength - 1; i >= 0 && length < BLE_ADDR_LEN; i -= 2) + { + if (mac_str[i] == ':') + { + i++; + continue; + } + + temp[0] = mac_str[i - 1]; + temp[1] = mac_str[i]; + + bd_addr.val[length] = strtoul(temp, NULL, 16); + + length++; + } + +} + +bool BLEUtils::macAddressSame(const bt_addr_le_t &bd_addr1, + const bt_addr_le_t &bd_addr2) +{ + bool temp = true;//(memcmp(bd_addr1.val, bd_addr2.val, 6) != 0);// + #if 1 + for (int i = 0; i < 6; i++) + { + if (bd_addr1.val[i] != bd_addr2.val[i]) + { + +pr_info(LOG_MODULE_BLE, "%s-idx %d-%.2x:%.2x", __FUNCTION__, i ,bd_addr1.val[i], bd_addr2.val[i]); +pr_info(LOG_MODULE_BLE,"%s",BLEUtils::macAddressBT2String(bd_addr1).c_str()); +pr_info(LOG_MODULE_BLE,"%s",BLEUtils::macAddressBT2String(bd_addr2).c_str()); + temp = false; + break; + } + } + #endif + return temp; + +} + +bool BLEUtils::macAddressValid(const bt_addr_le_t &bd_addr) +{ + static const bt_addr_le_t zero = {0,{0,0,0,0,0,0}}; + bool temp = (memcmp(bd_addr.val, zero.val, 6) != 0);//false;// + #if 0 + for (int i = 0; i < 6; i++) + { + if (bd_addr.val[i] != zero.val[i]) + { + +pr_info(LOG_MODULE_BLE, "%s-idx %d-%.2x:%.2x", __FUNCTION__, i ,bd_addr.val[i], zero.val[i]); +pr_info(LOG_MODULE_BLE,"%s",BLEUtils::macAddressBT2String(zero).c_str()); + temp = true; + break; + } + } + #endif + return temp; +} + + +bt_addr_le_t* BLEUtils::bleGetLoalAddress() +{ + static bt_addr_le_t board_addr; + if (false == macAddressValid(board_addr)) + ble_client_get_mac_address(&board_addr); + return &board_addr; +} + + + +void BLEUtils::uuidString2BT(const char* uuid, bt_uuid_t* pstuuid) +{ + char temp[] = {0, 0, 0}; + int strLength = strlen(uuid); + int length = 0; + bt_uuid_128_t uuid_tmp; + + memset (&uuid_tmp, 0x00, sizeof(uuid_tmp)); + + for (int i = strLength - 1; i >= 0 && length < MAX_UUID_SIZE; i -= 2) + { + if (uuid[i] == '-') + { + i++; + continue; + } + + temp[0] = uuid[i - 1]; + temp[1] = uuid[i]; + + uuid_tmp.val[length] = strtoul(temp, NULL, 16); + + length++; + } + + if (length == 2) + { + uint16_t temp = (uuid_tmp.val[1] << 8)| uuid_tmp.val[0]; + uint8_t* uuid16_val = (uint8_t*)&((bt_uuid_16_t*)(&uuid_tmp.uuid))->val; + uuid_tmp.uuid.type = BT_UUID_TYPE_16; + memcpy(uuid16_val, &temp, sizeof (uint16_t)); + } + else + { + uuid_tmp.uuid.type = BT_UUID_TYPE_128; + } + memcpy(pstuuid, &uuid_tmp, sizeof (uuid_tmp)); +} + +void BLEUtils::uuidBT2String(const bt_uuid_t* pstuuid, char* uuid) +{ + unsigned int tmp1, tmp5; + uint16_t tmp0, tmp2, tmp3, tmp4; + // TODO: Change the magic number 37 + switch (pstuuid->type) { + case BT_UUID_TYPE_16: + memcpy(&tmp0, &BT_UUID_16(pstuuid)->val, sizeof(tmp0)); + snprintf(uuid, 37, "%.4x", tmp0); + break; + case BT_UUID_TYPE_128: + memcpy(&tmp0, &BT_UUID_128(pstuuid)->val[0], sizeof(tmp0)); + memcpy(&tmp1, &BT_UUID_128(pstuuid)->val[2], sizeof(tmp1)); + memcpy(&tmp2, &BT_UUID_128(pstuuid)->val[6], sizeof(tmp2)); + memcpy(&tmp3, &BT_UUID_128(pstuuid)->val[8], sizeof(tmp3)); + memcpy(&tmp4, &BT_UUID_128(pstuuid)->val[10], sizeof(tmp4)); + memcpy(&tmp5, &BT_UUID_128(pstuuid)->val[12], sizeof(tmp5)); + snprintf(uuid, 37, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x", + tmp5, tmp4, tmp3, tmp2, tmp1, tmp0); + break; + default: + memset(uuid, 0, 37); + return; + } +} + +bool BLEUtils::uuidBTSame(const bt_uuid_t* pstuuid1, + const bt_uuid_t* pstuuid2) +{ + bool temp = (pstuuid1->type == pstuuid2->type); + if (true == temp) + { + if (pstuuid1->type == BT_UUID_TYPE_16) + { + temp = (0 == memcmp(&BT_UUID_16(pstuuid1)->val, &BT_UUID_16(pstuuid2)->val, 2)); + } + else + { + temp = (0 == memcmp(BT_UUID_128(pstuuid1)->val, BT_UUID_128(pstuuid2)->val, 16)); + } + } + return temp; + +} + +BLEDevice& BLEUtils::getLoacalBleDevice() +{ + return BLE; +} + +bool BLEUtils::isLocalBLE(const BLEDevice& device) +{ + return (device == BLE); +} + + + diff --git a/libraries/BLE/src/internal/BLEUtils.h b/libraries/BLE/src/internal/BLEUtils.h new file mode 100644 index 00000000..5fb70831 --- /dev/null +++ b/libraries/BLE/src/internal/BLEUtils.h @@ -0,0 +1,17 @@ + +namespace BLEUtils +{ + String macAddressBT2String(const bt_addr_le_t &bd_addr); + void macAddressString2BT(const char* mac_str, bt_addr_le_t &bd_addr); + bool macAddressValid(const bt_addr_le_t &bd_addr); + bool macAddressSame(const bt_addr_le_t &bd_addr1, const bt_addr_le_t &bd_addr2); + bt_addr_le_t* bleGetLoalAddress(); + void uuidString2BT(const char* uuid, bt_uuid_t* pstuuid); + void uuidBT2String(const bt_uuid_t* pstuuid, char* uuid); + bool uuidBTSame(const bt_uuid_t* pstuuid1, + const bt_uuid_t* pstuuid2); + + BLEDevice& getLoacalBleDevice(); + bool isLocalBLE(const BLEDevice& device); +} + diff --git a/libraries/BLE/src/internal/LinkList.h b/libraries/BLE/src/internal/LinkList.h new file mode 100644 index 00000000..04f51bba --- /dev/null +++ b/libraries/BLE/src/internal/LinkList.h @@ -0,0 +1,81 @@ +#ifndef _LINKLIST_H_ +#define _LINKLIST_H_ + +template struct LinkNode { + LinkNode *next; + T value; +}; + +template LinkNode* link_node_create(T value) +{ + LinkNode* node = (LinkNode*)malloc(sizeof(LinkNode)); + + if (node) { + node->value = value; + node->next = NULL; + } + return node; +} + +template void link_node_insert_last(LinkNode *root, LinkNode *node) +{ + while(root->next != 0) + { + root = root->next; + } + root->next = node; +} + +template void link_node_remove_last(LinkNode *root) +{ + LinkNode *temp1, *temp2; + if (root->next != NULL) + { + temp1 = root->next; + while(temp1->next != NULL) + { + temp2 = temp1; + temp1 = temp1->next; + } + + free(temp1); + temp2->next = NULL; + } +} + +template void link_node_remove_first(LinkNode *root) +{ + LinkNode *temp1; + if (root->next != NULL) + { + temp1 = root->next; + root->next = temp1->next; + free(temp1); + } +} + +template LinkNode * link_node_get_first(LinkNode *root) +{ + return root->next; +} + +template void link_node_insert_first(LinkNode *root, LinkNode *node) +{ + LinkNode* temp = root->next; + root->next = node; + node->next = temp; +} + +template int link_list_size(const LinkNode *root) +{ + int counter = 0; + while(root->next != 0) + { + root = root->next; + counter++; + } + return counter; +} + +#endif + diff --git a/libraries/BLE/src/internal/ble_client.c b/libraries/BLE/src/internal/ble_client.c new file mode 100644 index 00000000..5a9e6164 --- /dev/null +++ b/libraries/BLE/src/internal/ble_client.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include "cfw/cfw.h" +#include "cfw/cfw_debug.h" +#include "cfw/cfw_messages.h" +#include "cfw/cfw_internal.h" +#include "cfw/cfw_service.h" +#include "cfw_platform.h" +#include "infra/time.h" +#include "infra/factory_data.h" +#include "infra/version.h" +#include "curie_factory_data.h" +#include "portable.h" + +#include "uart.h" +#include "ipc_uart_ns16550.h" +#include "infra/ipc_uart.h" + +#include "ble_client.h" +#include "platform.h" + +#include "infra/log.h" + +// APP callback +static ble_client_connect_event_cb_t ble_client_connect_event_cb = NULL; +static void *ble_client_connect_event_param; + +static ble_client_disconnect_event_cb_t ble_client_disconnect_event_cb = NULL; +static void *ble_client_disconnect_event_param; + +static ble_client_update_param_event_cb_t ble_client_update_param_event_cb = NULL; +static void *ble_client_update_param_event_param; + + +#define NIBBLE_TO_CHAR(n) \ + ((n) >= 0xA ? ('A' + (n) - 0xA) : ('0' + (n))) + +#define BYTE_TO_STR(s, byte) \ + do { \ + *s++ = NIBBLE_TO_CHAR(byte >> 4); \ + *s++ = NIBBLE_TO_CHAR(byte & 0xF); \ + }while(0) + + +#ifdef __cplusplus +extern "C" { +#endif + +static void on_connected(bt_conn_t *conn, uint8_t err) +{ + if (ble_client_connect_event_cb) + { + ble_client_connect_event_cb(conn, err, ble_client_connect_event_param); + } +} + +static void on_disconnected(bt_conn_t *conn, uint8_t reason) +{ + if (ble_client_disconnect_event_cb) + { + ble_client_disconnect_event_cb(conn, reason, ble_client_disconnect_event_param); + } +} + +static void on_le_param_updated(bt_conn_t *conn, uint16_t interval, + uint16_t latency, uint16_t timeout) +{ + if (ble_client_update_param_event_cb) + { + ble_client_update_param_event_cb (conn, + interval, + latency, + timeout, + ble_client_update_param_event_param); + } +} + +static struct bt_conn_cb conn_callbacks = { + .connected = on_connected, + .disconnected = on_disconnected, + .le_param_updated = on_le_param_updated +}; + +void ble_client_get_mac_address(bt_addr_le_t *bda) +{ + struct curie_oem_data *p_oem = NULL; + unsigned i; + + /* Set the MAC address defined in Factory Data (if provided) + * Otherwise, the device will default to a static random address */ + if (bda) { + bda->type = BLE_DEVICE_ADDR_INVALID; + if (!strncmp((char*)global_factory_data->oem_data.magic, FACTORY_DATA_MAGIC, 4)) { + p_oem = (struct curie_oem_data *) &global_factory_data->oem_data.project_data; + if (p_oem->bt_mac_address_type < 2) { + bda->type = p_oem->bt_mac_address_type; + for (i = 0; i < BLE_ADDR_LEN; i++) + bda->val[i] = p_oem->bt_address[BLE_ADDR_LEN - 1 - i]; + } + } + } +} + +void ble_client_get_factory_config(bt_addr_le_t *bda, char *name) +{ + struct curie_oem_data *p_oem = NULL; + + ble_client_get_mac_address(bda); + + /* Set a default name if one has not been specified */ + if (name) { + + // Need to check in the OTP if there is some board name set + // If yes, let's read it, otherwise let's keep the default + // name set in BLE_DEVICE_NAME_DEFAULT_PREFIX + const struct customer_data* otp_data_ptr = (struct customer_data*)(FACTORY_DATA_ADDR + 0x200); + char *suffix; + + // checking the presence of key patterns + if ((otp_data_ptr->patternKeyStart == PATTERN_KEY_START) && + (otp_data_ptr->patternKeyEnd == PATTERN_KEY_END)) + { + // The board name is with OTP ar programmed + uint8_t len = otp_data_ptr->board_name_len; + + // We need to reserve 5 bytes for '-' and 4 last MAC address in ASCII + if (len > BLE_MAX_DEVICE_NAME - 5) len = BLE_MAX_DEVICE_NAME - 5; + strncpy(name, (const char *)otp_data_ptr->board_name, len); + suffix = name + len; + } + else + { + // There is no board name in the OTP area + suffix = name + strlen(BLE_DEVICE_NAME_DEFAULT_PREFIX); + strcpy(name, BLE_DEVICE_NAME_DEFAULT_PREFIX); + } + + // Adding the four last digits of MAC address separated by '-' sufix + if (bda && bda->type != BLE_DEVICE_ADDR_INVALID) + { + *suffix++ = '-'; + p_oem = (struct curie_oem_data *) &global_factory_data->oem_data.project_data; + BYTE_TO_STR(suffix, p_oem->bt_address[4]); + BYTE_TO_STR(suffix, p_oem->bt_address[5]); + *suffix = 0; /* NULL-terminate the string. Note the macro BYTE_TO_STR + automatically move the pointer */ + } + else + { + /* This code segment will be only reached if Curie module was not + provisioned properly with a BLE MAC address*/ + *suffix++ = 0; /* NULL-terminate the string */ + } + } +} + +void ble_client_init(ble_client_connect_event_cb_t connect_cb, void* connect_param, + ble_client_disconnect_event_cb_t disconnect_cb, void* disconnect_param, + ble_client_update_param_event_cb_t update_param_cb, void* update_param_param) +{ + //uint32_t delay_until; + pr_info(LOG_MODULE_BLE, "%s", __FUNCTION__); + ble_client_connect_event_cb = connect_cb; + ble_client_connect_event_param = connect_param; + + ble_client_disconnect_event_cb = disconnect_cb; + ble_client_disconnect_event_param = disconnect_param; + + ble_client_update_param_event_cb = update_param_cb; + ble_client_update_param_event_param = update_param_param; + + bt_conn_cb_register(&conn_callbacks); + return; +} + +BLE_STATUS_T errorno_to_ble_status(int err) +{ + BLE_STATUS_T err_code; + err = 0 - err; + + switch(err) { + case 0: + err_code = BLE_STATUS_SUCCESS; + break; + case EIO: + err_code = BLE_STATUS_WRONG_STATE; + break; + case EBUSY: + err_code = BLE_STATUS_TIMEOUT; + break; + case EFBIG: + case ENOTSUP: + err_code = BLE_STATUS_NOT_SUPPORTED; + break; + case EPERM: + case EACCES: + err_code = BLE_STATUS_NOT_ALLOWED; + break; + case ENOMEM: // No memeory + err_code = BLE_STATUS_NO_MEMORY; + break; + default: + err_code = BLE_STATUS_ERROR; + break; + } + return err_code; +} + + +#ifdef __cplusplus +} +#endif diff --git a/libraries/BLE/src/internal/ble_client.h b/libraries/BLE/src/internal/ble_client.h new file mode 100644 index 00000000..75c3d59f --- /dev/null +++ b/libraries/BLE/src/internal/ble_client.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _BLE_CLIENT_H_INCLUDED +#define _BLE_CLIENT_H_INCLUDED + +#include "BLECommon.h" + +enum { + UNIT_0_625_MS = 625, /**< Number of microseconds in 0.625 milliseconds. */ + UNIT_1_25_MS = 1250, /**< Number of microseconds in 1.25 milliseconds. */ + UNIT_10_MS = 10000 /**< Number of microseconds in 10 milliseconds. */ +}; + +#define MSEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000) / (RESOLUTION)) +#define UNITS_TO_MSEC(TIME, RESOLUTION) (((TIME) * RESOLUTION) / 1000) + +/* Connection parameters used for Peripheral Preferred Connection Parameterss (PPCP) and update request */ +#define DEFAULT_MIN_CONN_INTERVAL MSEC_TO_UNITS(80, UNIT_1_25_MS) +#define DEFAULT_MAX_CONN_INTERVAL MSEC_TO_UNITS(150, UNIT_1_25_MS) +#define MIN_CONN_INTERVAL 0x0006 +#define MAX_CONN_INTERVAL 0x0C80 +#define SLAVE_LATENCY 0 +#define CONN_SUP_TIMEOUT MSEC_TO_UNITS(6000, UNIT_10_MS) + +/* Borrowed from ble_service_utils.h */ +#define UINT8_TO_LESTREAM(p, i) \ + do { *(p)++ = (uint8_t)(i); } \ + while (0) +#define UINT16_TO_LESTREAM(p, i) UINT8_TO_LESTREAM(p, i); UINT8_TO_LESTREAM(p, (i)>>8) +#define UINT32_TO_LESTREAM(p, i) UINT16_TO_LESTREAM(p, i); UINT16_TO_LESTREAM(p, (i)>>16) + +#define INT8_TO_LESTREAM(p, i) UINT8_TO_LESTREAM(p, (uint8_t)(i)) +#define INT16_TO_LESTREAM(p, i) UINT16_TO_LESTREAM(p, (uint16_t)(i)) +#define INT32_TO_LESTREAM(p, i) UINT32_TO_LESTREAM(p, (uint32_t)(i)) + +#define LESTREAM_TO_UINT8(p, i) \ + do { i = *p; p++; } \ + while (0) +#define LESTREAM_TO_UINT16(p, i) \ + do { uint16_t temp16; LESTREAM_TO_UINT8(p, i); LESTREAM_TO_UINT8(p, temp16); i |= (temp16 << 8); } \ + while (0) +#define LESTREAM_TO_UINT32(p, i) \ + do { uint32_t temp32; LESTREAM_TO_UINT16(p, i); LESTREAM_TO_UINT16(p, temp32); i |= (temp32 << 16); } \ + while (0) + +#define LESTREAM_TO_INT8(p, i) \ + do {uint8_t __i; LESTREAM_TO_UINT8(p, __i); i = (int8_t)__i; } while (0) +#define LESTREAM_TO_INT16(p, i) \ + do {uint16_t __i; LESTREAM_TO_UINT16(p, __i); i = (int16_t)__i; } while (0) +#define LESTREAM_TO_INT32(p, i) \ + do {uint32_t __i; LESTREAM_TO_UINT32(p, __i); i = (int32_t)__i; } while (0) + +#define BLE_BASE_UUID_OCTET_OFFSET 12 +#define BLE_UUID16_TO_UUID128(uuid, base) \ + do { \ + uint16_t uuid16 = uuid.uuid16; \ + memcpy(uuid.uuid128, base.uuid128, sizeof(uuid.uuid128)); \ + uint8_t *p = &uuid.uuid128[BLE_BASE_UUID_OCTET_OFFSET]; \ + UINT16_TO_LESTREAM(p, uuid16); \ + uuid.type = BT_UUID128; \ + } while(0) + + +typedef void (*ble_client_connect_event_cb_t)(struct bt_conn *conn, uint8_t err, void *param); +typedef void (*ble_client_disconnect_event_cb_t)(struct bt_conn *conn, uint8_t reason, void *param); +typedef void (*ble_client_update_param_event_cb_t)(struct bt_conn *conn, + uint16_t interval, + uint16_t latency, + uint16_t timeout, + void *param); + + +#ifdef __cplusplus +extern "C" { +#endif + +void ble_client_init(ble_client_connect_event_cb_t connect_cb, void* connect_param, + ble_client_disconnect_event_cb_t disconnect_cb, void* disconnect_param, + ble_client_update_param_event_cb_t update_param_cb, void* update_param_param); +void ble_client_get_factory_config(bt_addr_le_t *bda, char *name); +void ble_gap_set_tx_power(int8_t tx_power); +BLE_STATUS_T errorno_to_ble_status(int err); + +void ble_client_get_mac_address(bt_addr_le_t *bda); + +#ifdef __cplusplus +} +#endif + + +#endif // _BLE_CLIENT_H_INCLUDED diff --git a/libraries/CurieBLE/src/BLECharacteristic.h b/libraries/CurieBLE/src/BLECharacteristic.h index 58274f67..c80edd08 100644 --- a/libraries/CurieBLE/src/BLECharacteristic.h +++ b/libraries/CurieBLE/src/BLECharacteristic.h @@ -329,7 +329,7 @@ class BLECharacteristic : public BLEAttribute { bt_gatt_attr_t *_attr_cccd; // For central device to subscribe the Notification/Indication - bt_gatt_subscribe_params_t _sub_params; + bt_gatt_subscribe_params_t _sub_params; bool _reading; bt_gatt_read_params_t _read_params; diff --git a/libraries/CurieBLE/src/BLEPeripheral.h b/libraries/CurieBLE/src/BLEPeripheral.h index 33b8bef7..25c53395 100644 --- a/libraries/CurieBLE/src/BLEPeripheral.h +++ b/libraries/CurieBLE/src/BLEPeripheral.h @@ -92,7 +92,7 @@ class BLEPeripheral{ /** * @brief Set advertising interval * - * @param[in] advertisingInterval Advertising Interval (N * 0.625) + * @param[in] advertisingInterval Advertising Interval in ms * * @return none * diff --git a/libraries/CurieBLE/src/BLEProfile.cpp b/libraries/CurieBLE/src/BLEProfile.cpp index 10f0c91e..0ffa12ff 100644 --- a/libraries/CurieBLE/src/BLEProfile.cpp +++ b/libraries/CurieBLE/src/BLEProfile.cpp @@ -146,7 +146,7 @@ uint8_t profile_discover_process(bt_conn_t *conn, return peripheral->discover(attr); } -// Only for central +// Only for GATT Client uint8_t profile_read_rsp_process(bt_conn_t *conn, int err, bt_gatt_read_params_t *params, const void *data, @@ -595,7 +595,7 @@ BLEAttribute *BLEProfile::attribute(const bt_uuid_t* uuid) continue; } chrc_tmp = (BLECharacteristic *)attr_tmp; - if (chrc_tmp->uuid() == uuid); + if (chrc_tmp->uuid() == uuid) { att_found = true; break; diff --git a/platform.txt b/platform.txt index f222a263..eea2379c 100644 --- a/platform.txt +++ b/platform.txt @@ -14,12 +14,12 @@ compiler.prefix=arc-elf32 compiler.path={runtime.tools.arc-elf32.path}/bin/ compiler.c.cmd=arc-elf32-gcc -compiler.c.flags=-c -std=gnu11 -mcpu=quarkse_em -mlittle-endian -g -Os -Wall -fno-reorder-functions -fno-asynchronous-unwind-tables -fno-omit-frame-pointer -fno-defer-pop -Wno-unused-but-set-variable -Wno-main -ffreestanding -fno-stack-protector -mno-sdata -ffunction-sections -fdata-sections -fsigned-char -MMD -D__ARDUINO_ARC__ -DCONFIG_BLUETOOTH_PERIPHERAL -DCONFIG_BLUETOOTH_CENTRAL -DCONFIG_BLUETOOTH_GATT_CLIENT +compiler.c.flags=-c -std=gnu11 -mcpu=quarkse_em -mlittle-endian -g -O0 -Wall -fno-reorder-functions -fno-asynchronous-unwind-tables -fno-omit-frame-pointer -fno-defer-pop -Wno-unused-but-set-variable -Wno-main -ffreestanding -fno-stack-protector -mno-sdata -ffunction-sections -fdata-sections -fsigned-char -MMD -D__ARDUINO_ARC__ -DCONFIG_BLUETOOTH_PERIPHERAL -DCONFIG_BLUETOOTH_CENTRAL -DCONFIG_BLUETOOTH_GATT_CLIENT compiler.c.elf.cmd=arc-elf32-gcc compiler.c.elf.flags=-nostartfiles -nodefaultlibs -nostdlib -static -Wl,-X -Wl,-N -Wl,-mcpu=quarkse_em -Wl,-marcelf -Wl,--gc-sections compiler.S.flags=-c -g -x assembler-with-cpp compiler.cpp.cmd=arc-elf32-g++ -compiler.cpp.flags=-c -mcpu=quarkse_em -mlittle-endian -g -Os -Wall -fno-reorder-functions -fno-asynchronous-unwind-tables -fno-omit-frame-pointer -fno-defer-pop -Wno-unused-but-set-variable -Wno-main -ffreestanding -fno-stack-protector -mno-sdata -ffunction-sections -fdata-sections -fsigned-char -MMD -fno-rtti -fno-exceptions -D__ARDUINO_ARC__ -std=c++11 -DCONFIG_BLUETOOTH_PERIPHERAL -DCONFIG_BLUETOOTH_CENTRAL -DCONFIG_BLUETOOTH_GATT_CLIENT +compiler.cpp.flags=-c -mcpu=quarkse_em -mlittle-endian -g -O0 -Wall -fno-reorder-functions -fno-asynchronous-unwind-tables -fno-omit-frame-pointer -fno-defer-pop -Wno-unused-but-set-variable -Wno-main -ffreestanding -fno-stack-protector -mno-sdata -ffunction-sections -fdata-sections -fsigned-char -MMD -fno-rtti -fno-exceptions -D__ARDUINO_ARC__ -std=c++11 -DCONFIG_BLUETOOTH_PERIPHERAL -DCONFIG_BLUETOOTH_CENTRAL -DCONFIG_BLUETOOTH_GATT_CLIENT compiler.ar.cmd=arc-elf32-ar compiler.ar.flags=rcs compiler.objcopy.cmd=arc-elf32-objcopy @@ -71,8 +71,8 @@ recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compil recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" "-L{build.variant.path}" -Wl,--whole-archive "-l{build.variant_system_lib}" -Wl,--no-whole-archive -Wl,--start-group "-l{build.variant_system_lib}" -lnsim -lc -lm -lgcc {object_files} "{build.path}/{archive_file}" ## Save output with debug symbols (.debug.elf file). Uncomment if you wish to use OpenOCD to debug. -#recipe.hooks.objcopy.preobjcopy.1.pattern=cp -f "{build.path}/{build.project_name}.elf" "{build.path}/../arduino101_sketch.debug.elf" -#recipe.hooks.objcopy.preobjcopy.1.pattern.windows=cmd /C copy /y "{build.path}\{build.project_name}.elf" "{build.path}\..\arduino101_sketch.debug.elf" +recipe.hooks.objcopy.preobjcopy.1.pattern=cp -f "{build.path}/{build.project_name}.elf" "{build.path}/../arduino101_sketch.debug.elf" +recipe.hooks.objcopy.preobjcopy.1.pattern.windows={runtime.tools.arduino101load.path}/arduino101load/arduino101copy.exe "{build.path}\{build.project_name}.elf" "{build.path}\..\arduino101_sketch.debug.elf" ## Create output (.bin file) recipe.objcopy.bin.pattern="{compiler.path}{compiler.elf2bin.cmd}" {compiler.elf2bin.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin" diff --git a/system/libarc32_arduino101/bootcode/init.S b/system/libarc32_arduino101/bootcode/init.S index 28aab7d6..b566b488 100644 --- a/system/libarc32_arduino101/bootcode/init.S +++ b/system/libarc32_arduino101/bootcode/init.S @@ -61,9 +61,10 @@ _do_reset: .balign 4 _do_fault: _exit_halt: - /* Set halt flag */ - flag 0x01 + /* Set halt flag + flag 0x0 */ nop + j @_Fault nop nop /* loop forever */ diff --git a/system/libarc32_arduino101/drivers/bluetooth/bluetooth.h b/system/libarc32_arduino101/drivers/bluetooth/bluetooth.h index e87cf2ab..faf03b2f 100644 --- a/system/libarc32_arduino101/drivers/bluetooth/bluetooth.h +++ b/system/libarc32_arduino101/drivers/bluetooth/bluetooth.h @@ -345,6 +345,7 @@ int bt_br_set_connectable(bool enable); #endif void bt_le_set_device_name(char *device_name, int len); +void bt_le_set_mac_address(bt_addr_le_t bda); #ifdef __cplusplus } diff --git a/system/libarc32_arduino101/drivers/ipc_uart_ns16550.c b/system/libarc32_arduino101/drivers/ipc_uart_ns16550.c index b2f6c08f..9b9880a6 100644 --- a/system/libarc32_arduino101/drivers/ipc_uart_ns16550.c +++ b/system/libarc32_arduino101/drivers/ipc_uart_ns16550.c @@ -155,7 +155,7 @@ static void ipc_uart_push_frame(uint16_t len, uint8_t *p_data) // "len %d, src %d, channel %d", ipc.rx_hdr.len, len, // ipc.rx_hdr.src_cpu_id, // ipc.rx_hdr.channel); - pr_debug(LOG_MODULE_IPC,"data[0 - 1]: %x-%x", p_data[0], p_data[1]); + //pr_debug(LOG_MODULE_IPC,"data[0 - 1]: %x-%x", p_data[0], p_data[1]); if ((ipc.rx_hdr.channel < IPC_UART_MAX_CHANNEL) && (ipc.channels[ipc.rx_hdr.channel].cb != NULL)) { @@ -208,7 +208,7 @@ void ipc_uart_isr() if (ipc.rx_size == 0) { if (ipc.rx_state == STATUS_RX_HDR) { - pr_error(0, "%s-%d", __FUNCTION__, ipc.rx_hdr.len); + //pr_error(0, "%s-%d", __FUNCTION__, ipc.rx_hdr.len); ipc.rx_ptr = balloc( ipc.rx_hdr.len, NULL); @@ -368,7 +368,7 @@ int ipc_uart_ns16550_send_pdu(void *handle, int len, void *p_data) { struct ipc_uart_channels *chan = (struct ipc_uart_channels *)handle; - pr_debug(LOG_MODULE_IPC, "%s: %d", __FUNCTION__, ipc.tx_state); + //pr_debug(LOG_MODULE_IPC, "%s: %d", __FUNCTION__, ipc.tx_state); if (ipc.tx_state == STATUS_TX_BUSY) { return IPC_UART_TX_BUSY; diff --git a/system/libarc32_arduino101/framework/src/cfw/service_api.c b/system/libarc32_arduino101/framework/src/cfw/service_api.c index 28b5bfe5..183167b6 100644 --- a/system/libarc32_arduino101/framework/src/cfw/service_api.c +++ b/system/libarc32_arduino101/framework/src/cfw/service_api.c @@ -111,6 +111,11 @@ struct cfw_message * cfw_alloc_evt_msg(service_t *svc, int msg_id, int size) { struct cfw_message * cfw_alloc_internal_msg(int msg_id, int size, void * priv) { struct cfw_message * evt = (struct cfw_message *) cfw_alloc_message(size, NULL); + if (NULL == evt) + { + return NULL; + } + CFW_MESSAGE_TYPE(evt) = TYPE_INT; CFW_MESSAGE_ID(evt) = msg_id; CFW_MESSAGE_LEN(evt) = size; diff --git a/system/libarc32_arduino101/framework/src/infra/port.c b/system/libarc32_arduino101/framework/src/infra/port.c index e9f7eef6..d150ccd3 100644 --- a/system/libarc32_arduino101/framework/src/infra/port.c +++ b/system/libarc32_arduino101/framework/src/infra/port.c @@ -121,6 +121,7 @@ static struct port * get_port(uint16_t port_id) if (port_id == 0 || port_id > MAX_PORTS) { pr_error(LOG_MODULE_MAIN, "Invalid port: %d", port_id); panic(-1); /*TODO: replace with an assert */ + return NULL; } return &ports[port_id - 1]; } @@ -128,7 +129,10 @@ static struct port * get_port(uint16_t port_id) void port_set_queue(uint16_t port_id, void * queue) { struct port * p = get_port(port_id); - p->queue = queue; + if (p) + { + p->queue = queue; + } } #ifdef CONFIG_INFRA_IS_MASTER @@ -175,8 +179,11 @@ uint16_t port_alloc(void *queue) void port_set_handler(uint16_t port_id, void (*handler)(struct message*, void*), void *param) { struct port * port = get_port(port_id); - port->handle_message = handler; - port->handle_param = param; + if (port) + { + port->handle_message = handler; + port->handle_param = param; + } } struct message * message_alloc(int size, OS_ERR_TYPE * err) @@ -192,7 +199,7 @@ struct message * message_alloc(int size, OS_ERR_TYPE * err) void port_process_message(struct message * msg) { struct port * p = get_port(msg->dst_port_id); - if (p->handle_message != NULL) { + if (p && p->handle_message != NULL) { p->handle_message(msg, p->handle_param); } } @@ -200,19 +207,32 @@ void port_process_message(struct message * msg) void port_set_cpu_id(uint16_t port_id, uint8_t cpu_id) { struct port * p = get_port(port_id); - p->cpu_id = cpu_id; + if (p) + { + p->cpu_id = cpu_id; + } } void port_set_port_id(uint16_t port_id) { struct port * p = get_port(port_id); - p->id = port_id; + if (p) + { + p->id = port_id; + } } uint8_t port_get_cpu_id(uint16_t port_id) { struct port * p = get_port(port_id); - return p->cpu_id; + if (p) + { + return p->cpu_id; + } + else + { + return 0; + } } #ifdef INFRA_MULTI_CPU_SUPPORT @@ -257,7 +277,7 @@ int port_send_message(struct message * message) pr_info(LOG_MODULE_MAIN, "Sending message %p to port %p(q:%p) ret: %d", message, port, port->queue, err); #endif struct port *src_port = get_port(MESSAGE_SRC(message)); - if (src_port->cpu_id == get_cpu_id()) { + if (src_port && src_port->cpu_id == get_cpu_id()) { /* We bypass the software queue here and process directly * due to lack of background thread on this implementation */ @@ -277,6 +297,10 @@ int port_send_message(struct message * message) void message_free(struct message * msg) { struct port * port = get_port(MESSAGE_SRC(msg)); + if (!port) + { + return; + } pr_debug(LOG_MODULE_MAIN, "free message %p: port %p[%d] this %d id %d", msg, port, port->cpu_id, get_cpu_id(), MESSAGE_SRC(msg)); if (port->cpu_id == get_cpu_id()) { @@ -290,8 +314,12 @@ void message_free(struct message * msg) int port_send_message(struct message * msg) { - struct port * port = get_port(MESSAGE_DST(msg)); OS_ERR_TYPE err; + struct port * port = get_port(MESSAGE_DST(msg)); + if (!port) + { + return E_OS_ERR_NO_MEMORY; + } if (src_port->cpu_id == get_cpu_id()) { /* We bypass the software queue here and process directly * due to lack of background thread on this implementation @@ -317,7 +345,7 @@ uint16_t queue_process_message(T_QUEUE queue) uint16_t id = 0; queue_get_message(queue, &m, OS_NO_WAIT, &err); message = (struct message *) m; - if ( message != NULL && err == E_OS_OK) { + if ( message != NULL) { // && err == E_OS_OK dismiss Klock scan issue id = MESSAGE_ID(message); port_process_message(message); } diff --git a/system/libarc32_arduino101/framework/src/os/panic.c b/system/libarc32_arduino101/framework/src/os/panic.c index 9fe88ef9..c77fc501 100644 --- a/system/libarc32_arduino101/framework/src/os/panic.c +++ b/system/libarc32_arduino101/framework/src/os/panic.c @@ -1,6 +1,9 @@ #include "os/os.h" +#include "infra/log.h" +#include "aux_regs.h" + extern void _do_fault(); void panic(int x) { @@ -14,3 +17,16 @@ void __assert_fail() } +void __attribute__((weak)) _Fault(void) +{ + uint32_t exc_addr = aux_reg_read(ARC_V2_EFA); + uint32_t ecr = aux_reg_read(ARC_V2_ECR); + + pr_error(0, "Exception vector: 0x%x, cause code: 0x%x, parameter 0x%x\n", + ARC_V2_ECR_VECTOR(ecr), + ARC_V2_ECR_CODE(ecr), + ARC_V2_ECR_PARAMETER(ecr)); + pr_error(0, "Address 0x%x\n", exc_addr); + while (1); // Sid. Acknowledge KW warning. +} + diff --git a/system/libarc32_arduino101/framework/src/services/ble/gap.c b/system/libarc32_arduino101/framework/src/services/ble/gap.c index 4cf71d47..26858281 100644 --- a/system/libarc32_arduino101/framework/src/services/ble/gap.c +++ b/system/libarc32_arduino101/framework/src/services/ble/gap.c @@ -910,3 +910,14 @@ void bt_le_set_device_name(char *device_name, int len) nble_gap_service_write_req(&gap_service_params); } +void bt_le_set_mac_address(bt_addr_le_t bda) +{ + // Update the MAC addr + struct nble_set_bda_params params; + params.cb = NULL; + params.user_data = NULL; + params.bda = bda; + + nble_set_bda_req(¶ms); +} + diff --git a/system/libarc32_arduino101/framework/src/services/ble/gatt.c b/system/libarc32_arduino101/framework/src/services/ble/gatt.c index d3ef4c09..44c82e5c 100644 --- a/system/libarc32_arduino101/framework/src/services/ble/gatt.c +++ b/system/libarc32_arduino101/framework/src/services/ble/gatt.c @@ -1040,6 +1040,7 @@ void on_nble_gattc_discover_rsp(const struct nble_gattc_discover_rsp *rsp, struct bt_gatt_attr *attr = NULL; if (rsp->type == BT_GATT_DISCOVER_PRIMARY) { + //BT_DBG("%s-%d", __FUNCTION__, __LINE__); const struct nble_gattc_primary *gattr = (void *)&data[i * sizeof(*gattr)]; if ((gattr->range.start_handle < params->start_handle) && @@ -1052,7 +1053,7 @@ void on_nble_gattc_discover_rsp(const struct nble_gattc_discover_rsp *rsp, goto complete; } svc_value.end_handle = gattr->range.end_handle; - svc_value.uuid = params->uuid; + svc_value.uuid = (struct bt_uuid*)(&(gattr->uuid));//params->uuid; attr = (&(struct bt_gatt_attr)BT_GATT_PRIMARY_SERVICE(&svc_value)); attr->handle = gattr->handle; last_handle = svc_value.end_handle; diff --git a/system/libarc32_arduino101/framework/src/services/ble/uuid.c b/system/libarc32_arduino101/framework/src/services/ble/uuid.c index dbacfd94..365ea2c7 100644 --- a/system/libarc32_arduino101/framework/src/services/ble/uuid.c +++ b/system/libarc32_arduino101/framework/src/services/ble/uuid.c @@ -89,7 +89,7 @@ int bt_uuid_cmp(const struct bt_uuid *u1, const struct bt_uuid *u2) switch (u1->type) { case BT_UUID_TYPE_16: - return (int)BT_UUID_16(u1)->val - (int)BT_UUID_16(u2)->val; + return memcmp(&BT_UUID_16(u1)->val, &BT_UUID_16(u2)->val, 2);//(int)BT_UUID_16(u1)->val - (int)BT_UUID_16(u2)->val; case BT_UUID_TYPE_128: return memcmp(BT_UUID_128(u1)->val, BT_UUID_128(u2)->val, 16); } diff --git a/system/libarc32_arduino101/framework/src/services/ble_service/ble_service.c b/system/libarc32_arduino101/framework/src/services/ble_service/ble_service.c index 405c984a..07231cb1 100644 --- a/system/libarc32_arduino101/framework/src/services/ble_service/ble_service.c +++ b/system/libarc32_arduino101/framework/src/services/ble_service/ble_service.c @@ -113,9 +113,11 @@ static void handle_msg_id_ble_rpc_callin(struct message *msg, void *priv) { struct ble_rpc_callin *rpc = container_of(msg, struct ble_rpc_callin, msg); /* handle incoming message */ + //pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); rpc_deserialize(rpc->p_data, rpc->len); bfree(rpc->p_data); message_free(msg); + //pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); } static void ble_set_bda_cb(int status, void *user_data) @@ -192,7 +194,7 @@ static void handle_ble_disable(struct ble_enable_req *req, struct _ble_service_c resp = (void *)cfw_alloc_rsp_msg(&req->header, MSG_ID_BLE_ENABLE_RSP, sizeof(*resp)); - cfw_send_message(resp); + cfw_send_message(resp); // Sid. KW warning ack. } @@ -225,7 +227,7 @@ static void ble_service_message_handler(struct cfw_message *msg, void *param) MSG_ID_BLE_ENABLE_RSP, sizeof(*resp)); resp->status = -EINPROGRESS; resp->enable = 0; - cfw_send_message(resp); + cfw_send_message(resp); // Sid. KW warning ack. } } break; diff --git a/variants/arduino_101/libarc32drv_arduino101.a b/variants/arduino_101/libarc32drv_arduino101.a index e0cb6b8e..c87e0b52 100644 Binary files a/variants/arduino_101/libarc32drv_arduino101.a and b/variants/arduino_101/libarc32drv_arduino101.a differ diff --git a/variants/arduino_101/linker_scripts/flash.ld b/variants/arduino_101/linker_scripts/flash.ld index e75a7059..fca2693c 100644 --- a/variants/arduino_101/linker_scripts/flash.ld +++ b/variants/arduino_101/linker_scripts/flash.ld @@ -47,12 +47,12 @@ MEMORY /* Define default stack size and FIRQ stack size. * See below stack section for __stack_start and __firq_stack_start */ -__stack_size = 2048; -__firq_stack_size = 512; +__stack_size = 3072; +__firq_stack_size = 1024; -/* Minimum heap size to allocate +/* Minimum heap size to allocate 8192 * Actual heap size might be bigger due to page size alignment */ -__HEAP_SIZE_MIN = 8192; +__HEAP_SIZE_MIN = 9216; /* This should be set to the page size used by the malloc implementation */ __PAGE_SIZE = 4096; diff --git a/variants/libarc32drv_arduino101.a b/variants/libarc32drv_arduino101.a new file mode 100644 index 00000000..7fe479f8 Binary files /dev/null and b/variants/libarc32drv_arduino101.a differ