diff --git a/examples/BLE_ios_serial/BLE_ios_serial.ino b/examples/BLE_ios_serial/BLE_ios_serial.ino new file mode 100644 index 0000000..097ec61 --- /dev/null +++ b/examples/BLE_ios_serial/BLE_ios_serial.ino @@ -0,0 +1,78 @@ +/* + * This example illustrates use of BLEDeviceID which makes the device + * discoverable on iOS, which requires all Bluetooth devices to implement the + * Device ID Profile: + * https://developer.apple.com/hardwaredrivers/BluetoothDesignGuidelines.pdf + * + * It also shows usage of BLESerial which implements a Stream-compliant serial + * protocol. + * + * This imitates a DFRobot Bluno BLE device which uses a simple serial protocol + * for communication. BLESerial on ESP32 can be used equivalently with + * Serial on Bluno BLE devices. + * + * Connect to "Bluno ESP" using LightBlue or another BLE test app. + * The DFB1 characteristic in the DFB0 service is rewritten every + * two seconds, and values written to this characteristc will be displayed + * on the ESP's serial console. + */ + +#include +#include +#include +#include + +BLESerial bleSerial = BLESerial(); + +void setup() { + Serial.begin(115200); + + BLEDevice::init("Bluno ESP"); + BLEServer *server = BLEDevice::createServer(); + + bleSerial.begin(server, BLEUUID((uint16_t)0xDFB0), BLEUUID((uint16_t)0xDFB1)); + + BLEDeviceID* did = new BLEDeviceID( + server, + "0x0BB9FD999969D238", + "DF Bluno", + "0123456789", + "FW V1.97", + "HW V1.7", + "SW V1.97", + "DFRobot", + "", + 1, + 0x0010, + 0x0D00, + 0); + did->start(); + server->getAdvertising()->start(); +} + +// This digit will be the first character of our message. +byte counter = 0; + +void loop() { + // The message we'll send to the client. + // First byte will be an incrementing digit. + std::string message = " Hi!"; + // Convert counter digit to ASCII and put it in our message. + message[0] = '0' + counter; + counter = (counter + 1) % 10; + bleSerial.write(message.c_str()); + + if (bleSerial.available() > 0) { + // Read up to 20 characters from the client, plus one for null-termination + char buf[21]; + byte len = bleSerial.readBytesUntil('\0', buf, sizeof(buf) - 1); + // Make sure the string is null-terminated. + buf[len] = '\0'; + Serial.print("Got serial data: "); + Serial.println(buf); + } else { + Serial.print(millis()); + Serial.println(" No serial data."); + } + delay(2000); +} diff --git a/library.properties b/library.properties index f473071..f21f17e 100644 --- a/library.properties +++ b/library.properties @@ -7,4 +7,4 @@ paragraph=This library provides an implementation Bluetooth Low Energy support f category=Communication url=https://github.com/nkolban/ESP32_BLE_Arduino architectures=esp32 -includes=BLE.h, BLEUtils.h, BLEScan.h, BLEAdvertisedDevice.h \ No newline at end of file +includes=BLE.h, BLEUtils.h, BLEScan.h, BLEAdvertisedDevice.h, BLEDeviceID.h, BLESerial.h diff --git a/src/BLEDeviceID.cpp b/src/BLEDeviceID.cpp new file mode 100644 index 0000000..bb1b5a0 --- /dev/null +++ b/src/BLEDeviceID.cpp @@ -0,0 +1,109 @@ +/* + BLEDeviceID.cpp - Bluetooth Low Energy Device ID Profile implementation. + Copyright (c) 2017 by Grant Patterson. 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include + +#include "BLEDeviceID.h" + +BLEDeviceID::BLEDeviceID( + BLEServer* server, + std::string systemId, // 0x2A23, 64 bits, use strtoull format "0x..." + std::string modelNumber, // 0x2A24 + std::string serialNumber, // 0x2A25 + std::string firmwareRevision, // 0x2A26 + std::string hardwareRevision, // 0x2A27 + std::string softwareRevision, // 0x2A28 + std::string manufacturerName, // 0x2A29 + std::string ieee11073_20601, // 0x2A2A, standard is behind paywall. + // 0x2A50 PnP ID values: + uint8_t vendorIdSource, // 1=Bluetooth SIG, 2=USB Impl. Forum + uint16_t vendorId, + uint16_t productId, + uint16_t productVersion) { + // Need space for 20 handles to hold all the characteristics we have. + service = server->createService(BLEUUID((uint16_t)0x180A), 20); + + // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.system_id.xml + // Use strtoull to convert string to 64-bit value. + // systemId should probably be of format "0x0123456789ABCDEF" + unsigned long long systemIdLong = strtoull(systemId.c_str(), NULL, 0); + // Store 64 bits as byte stream; string is convenient + systemId = std::string((char*)&systemIdLong, sizeof(systemIdLong)); + // Need to reverse string to correct for bigendian + systemId = std::string(systemId.rbegin(), systemId.rend()); + service->createCharacteristic( + BLEUUID((uint16_t)0x2A23), + BLECharacteristic::PROPERTY_READ) + ->setValue(systemId); + + // Straightforward string values. + service->createCharacteristic( + BLEUUID((uint16_t)0x2A24), + BLECharacteristic::PROPERTY_READ) + ->setValue(modelNumber); + service->createCharacteristic( + BLEUUID((uint16_t)0x2A25), + BLECharacteristic::PROPERTY_READ) + ->setValue(serialNumber); + service->createCharacteristic( + BLEUUID((uint16_t)0x2A26), + BLECharacteristic::PROPERTY_READ) + ->setValue(firmwareRevision); + service->createCharacteristic( + BLEUUID((uint16_t)0x2A27), + BLECharacteristic::PROPERTY_READ) + ->setValue(hardwareRevision); + service->createCharacteristic( + BLEUUID((uint16_t)0x2A28), + BLECharacteristic::PROPERTY_READ) + ->setValue(softwareRevision); + service->createCharacteristic( + BLEUUID((uint16_t)0x2A29), + BLECharacteristic::PROPERTY_READ) + ->setValue(manufacturerName); + // Format is mysterious. + // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.ieee_11073-20601_regulatory_certification_data_list.xml + service->createCharacteristic( + BLEUUID((uint16_t)0x2A2A), + BLECharacteristic::PROPERTY_READ) + ->setValue(ieee11073_20601); + + // Per spec, order these from least-significant octet to most. + // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.pnp_id.xml + uint8_t val2a50[7]; + val2a50[6] = vendorIdSource; + val2a50[5] = vendorId; + val2a50[4] = vendorId >> 8; + val2a50[3] = productId; + val2a50[2] = productId >> 8; + val2a50[1] = productVersion; + val2a50[0] = productVersion >> 8; + service->createCharacteristic( + BLEUUID((uint16_t)0x2A50), + BLECharacteristic::PROPERTY_READ) + ->setValue(val2a50, sizeof(val2a50)); +} + +void BLEDeviceID::start() { + service->start(); +} + +#endif // CONFIG_BT_ENABLED diff --git a/src/BLEDeviceID.h b/src/BLEDeviceID.h new file mode 100644 index 0000000..63c46b0 --- /dev/null +++ b/src/BLEDeviceID.h @@ -0,0 +1,55 @@ +/* + BLEDeviceID.h - Bluetooth Low Energy Device ID Profile implementation. + Copyright (c) 2017 by Grant Patterson. 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef MAIN_BLEDeviceID_H_ +#define MAIN_BLEDeviceID_H_ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include +#include + +#include "BLEService.h" + +class BLEDeviceID { +public: + // Specify server and all values needed to implement the Device ID spec: + // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.device_information.xml + BLEDeviceID( + BLEServer* server, + std::string systemId, // 0x2A23, 64 bits, use strtoull format "0x..." + std::string modelNumber, // 0x2A24 + std::string serialNumber, // 0x2A25 + std::string firmwareRevision, // 0x2A26 + std::string hardwareRevision, // 0x2A27 + std::string softwareRevision, // 0x2A28 + std::string manufacturerName, // 0x2A29 + std::string ieee11073_20601, // 0x2A2A, standard is behind paywall. + // 0x2A50 PnP ID values: + uint8_t vendorIdSource, // 1=Bluetooth SIG, 2=USB Impl. Forum + uint16_t vendorId, + uint16_t productId, + uint16_t productVersion); + void start(); + +protected: + BLEService* service; +}; + +#endif // CONFIG_BT_ENABLED +#endif /* MAIN_BLEDeviceID_H_ */ diff --git a/src/BLESerial.cpp b/src/BLESerial.cpp new file mode 100644 index 0000000..4fef19a --- /dev/null +++ b/src/BLESerial.cpp @@ -0,0 +1,94 @@ +/* + BLESerial.cpp - Bluetooth Low Energy Serial library. + Copyright (c) 2017 by Grant Patterson. 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "BLESerial.h" + +BLESerial::BLESerial() { +} + +// From BLECharacteristicCallbacks +void BLESerial::onWrite(BLECharacteristic* characteristic) { + buffer += characteristic->getValue(); +} + +void BLESerial::begin(BLEServer* server, BLEUUID service_uuid, BLEUUID characteristic_uuid) +{ + service = server->createService(service_uuid); + buffer = ""; + characteristic = service->createCharacteristic(characteristic_uuid, + BLECharacteristic::PROPERTY_READ | + BLECharacteristic::PROPERTY_WRITE | + BLECharacteristic::PROPERTY_NOTIFY); + BLEDescriptor* desc = new BLEDescriptor(BLEUUID((uint16_t)0x2901)); + desc->setValue("Serial"); + characteristic->addDescriptor(desc); + characteristic->setCallbacks(this); + service->start(); +} + +void BLESerial::end() { +} + +void BLESerial::setDebugOutput(bool en) { +} + +int BLESerial::available(void) { + return buffer.size(); +} + +int BLESerial::peek(void) { + if (available()) { + return (int)buffer[0]; + } + return -1; +} + +int BLESerial::read(void) { + if (available()) { + int result = (int)buffer[0]; + buffer.erase(0, 1); + return result; + } + return -1; +} + +void BLESerial::flush() { + // Pretty sure this is supposed to go both ways in Arduino. + buffer.clear(); +} + +size_t BLESerial::write(uint8_t c) { + characteristic->setValue(&c, 1); + characteristic->notify(); + return 1; +} + +size_t BLESerial::write(const uint8_t *buffer, size_t size) { + characteristic->setValue((uint8_t*)buffer, size); + characteristic->notify(); + return size; +} + +uint32_t BLESerial::baudRate() { + return 0; +} + +BLESerial::operator bool() const { + return true; +} diff --git a/src/BLESerial.h b/src/BLESerial.h new file mode 100644 index 0000000..b36d057 --- /dev/null +++ b/src/BLESerial.h @@ -0,0 +1,71 @@ +/* + BLESerial.h - Bluetooth Low Energy Serial library. + Copyright (c) 2017 by Grant Patterson. 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef BLESerial_h +#define BLESerial_h + +#include +#include + +#include "BLECharacteristic.h" +#include "BLEService.h" +#include "Stream.h" + +class BLESerial: public Stream, public BLECharacteristicCallbacks { +public: + BLESerial(); + + void begin(BLEServer* server, BLEUUID service_uuid, BLEUUID characteristic_uuid); + void end(); + int available(void); + int peek(void); + int read(void); + void flush(void); + size_t write(uint8_t); + size_t write(const uint8_t *buffer, size_t size); + + inline size_t write(const char * s) { + return write((uint8_t*) s, strlen(s)); + } + inline size_t write(unsigned long n) { + return write((uint8_t) n); + } + inline size_t write(long n) { + return write((uint8_t) n); + } + inline size_t write(unsigned int n) { + return write((uint8_t) n); + } + inline size_t write(int n) { + return write((uint8_t) n); + } + uint32_t baudRate(); + operator bool() const; + + void setDebugOutput(bool); + + void onWrite(BLECharacteristic* characteristic); + +protected: + BLEService* service; + BLECharacteristic* characteristic; + std::string buffer; +}; + +#endif