diff --git a/BLESerial.cpp b/BLESerial.cpp new file mode 100644 index 0000000..a0bf0ef --- /dev/null +++ b/BLESerial.cpp @@ -0,0 +1,122 @@ +#include "BLESerial.h" + +uint32_t bt_passkey_callback(); +void bt_passkey_notify_callback(uint32_t passkey); +bool bt_security_request_callback(); +void bt_authentication_complete_callback(esp_ble_auth_cmpl_t auth_result); +bool bt_confirm_pin_callback(uint32_t pin); +void bt_connect_callback(uint16_t conn_handle); +void bt_disconnect_callback(uint16_t conn_handle, uint8_t reason); + +uint32_t BLESerial::onPassKeyRequest() { return bt_passkey_callback(); } +void BLESerial::onPassKeyNotify(uint32_t passkey) { bt_passkey_notify_callback(passkey); } +bool BLESerial::onSecurityRequest() { return bt_security_request_callback(); } +void BLESerial::onAuthenticationComplete(esp_ble_auth_cmpl_t auth_result) { bt_authentication_complete_callback(auth_result); } +void BLESerial::onConnect(BLEServer *server) { bt_connect_callback(0); } +void BLESerial::onDisconnect(BLEServer *server) { bt_disconnect_callback(0, 0); ble_server->startAdvertising(); } +bool BLESerial::onConfirmPIN(uint32_t pin) { return false; }; +bool BLESerial::connected() { return ble_server->getConnectedCount() > 0; } + +int BLESerial::read() { + int result = this->rx_buffer.pop(); + if (result == '\n') { this->numAvailableLines--; } + return result; +} + +size_t BLESerial::readBytes(uint8_t *buffer, size_t bufferSize) { + int i = 0; + while (i < bufferSize && available()) { buffer[i] = (uint8_t)this->rx_buffer.pop(); i++; } + return i; +} + +int BLESerial::peek() { + if (this->rx_buffer.getLength() == 0) return -1; + return this->rx_buffer.get(0); +} + +int BLESerial::available() { return this->rx_buffer.getLength(); } + +size_t BLESerial::print(const char *str) { + if (ble_server->getConnectedCount() <= 0) return 0; + size_t written = 0; for (size_t i = 0; str[i] != '\0'; i++) { written += this->write(str[i]); } + flush(); + + return written; +} + +size_t BLESerial::write(const uint8_t *buffer, size_t bufferSize) { + if (ble_server->getConnectedCount() <= 0) { return 0; } else { + size_t written = 0; for (int i = 0; i < bufferSize; i++) { written += this->write(buffer[i]); } + flush(); + + return written; + } +} + +size_t BLESerial::write(uint8_t byte) { + if (ble_server->getConnectedCount() <= 0) { return 0; } else { + this->transmitBuffer[this->transmitBufferLength] = byte; + this->transmitBufferLength++; + if (this->transmitBufferLength == maxTransferSize) { flush(); } + return 1; + } +} + +void BLESerial::flush() { + if (this->transmitBufferLength > 0) { + TxCharacteristic->setValue(this->transmitBuffer, this->transmitBufferLength); + this->transmitBufferLength = 0; + this->lastFlushTime = millis(); + TxCharacteristic->notify(true); + } +} + +void BLESerial::begin(const char *name) { + ConnectedDeviceCount = 0; + BLEDevice::init(name); + + esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_DEFAULT, ESP_PWR_LVL_P9); + esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, ESP_PWR_LVL_P9); + esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_SCAN ,ESP_PWR_LVL_P9); + + ble_server = BLEDevice::createServer(); + ble_server->setCallbacks(this); + BLEDevice::setSecurityCallbacks(this); + + SetupSerialService(); + + ble_adv = BLEDevice::getAdvertising(); + ble_adv->addServiceUUID(BLE_SERIAL_SERVICE_UUID); + ble_adv->setMinPreferred(0x20); + ble_adv->setMaxPreferred(0x40); + ble_adv->setScanResponse(true); + ble_adv->start(); +} + +void BLESerial::end() { BLEDevice::deinit(); } + +void BLESerial::onWrite(BLECharacteristic *characteristic) { + if (characteristic->getUUID().toString() == BLE_RX_UUID) { + auto value = characteristic->getValue(); + for (int i = 0; i < value.length(); i++) { rx_buffer.push(value[i]); } + } +} + +void BLESerial::SetupSerialService() { + SerialService = ble_server->createService(BLE_SERIAL_SERVICE_UUID); + + RxCharacteristic = SerialService->createCharacteristic(BLE_RX_UUID, BLECharacteristic::PROPERTY_WRITE); + RxCharacteristic->setAccessPermissions(ESP_GATT_PERM_WRITE_ENC_MITM); + RxCharacteristic->addDescriptor(new BLE2902()); + RxCharacteristic->setWriteProperty(true); + RxCharacteristic->setCallbacks(this); + + TxCharacteristic = SerialService->createCharacteristic(BLE_TX_UUID, BLECharacteristic::PROPERTY_NOTIFY); + TxCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENC_MITM); + TxCharacteristic->addDescriptor(new BLE2902()); + TxCharacteristic->setReadProperty(true); + + SerialService->start(); +} + +BLESerial::BLESerial() { } diff --git a/BLESerial.h b/BLESerial.h new file mode 100644 index 0000000..d1cae4d --- /dev/null +++ b/BLESerial.h @@ -0,0 +1,111 @@ +#pragma once +#include + +#include +#include +#include +#include + +template +class BLEFIFO { +private: + uint8_t buffer[n]; + int head = 0; + int tail = 0; + +public: + void push(uint8_t value) { + buffer[head] = value; + head = (head + 1) % n; + if (head == tail) { tail = (tail + 1) % n; } + } + + int pop() { + if (head == tail) { + return -1; + } else { + uint8_t value = buffer[tail]; + tail = (tail + 1) % n; + return value; + } + } + + void clear() { head = 0; tail = 0; } + + int get(size_t index) { + if (index >= this->getLength()) { + return -1; + } else { + return buffer[(tail + index) % n]; + } + } + + size_t getLength() { + if (head >= tail) { + return head - tail; + } else { + return n - tail + head; + } + } +}; + +#define RX_BUFFER_SIZE 6144 +#define BLE_BUFFER_SIZE 512 // Must fit in max GATT attribute length +#define MIN_MTU 50 + +class BLESerial : public BLECharacteristicCallbacks, public BLEServerCallbacks, public BLESecurityCallbacks, public Stream { +public: + BLESerial(); + + void begin(const char *name); + void end(); + void onWrite(BLECharacteristic *characteristic); + int available(); + int peek(); + int read(); + size_t readBytes(uint8_t *buffer, size_t bufferSize); + size_t write(uint8_t byte); + size_t write(const uint8_t *buffer, size_t bufferSize); + size_t print(const char *value); + void flush(); + void onConnect(BLEServer *server); + void onDisconnect(BLEServer *server); + + uint32_t onPassKeyRequest(); + void onPassKeyNotify(uint32_t passkey); + bool onSecurityRequest(); + void onAuthenticationComplete(esp_ble_auth_cmpl_t); + bool onConfirmPIN(uint32_t pin); + + bool connected(); + + BLEServer *ble_server; + BLEAdvertising *ble_adv; + BLEService *SerialService; + BLECharacteristic *TxCharacteristic; + BLECharacteristic *RxCharacteristic; + size_t transmitBufferLength; + unsigned long long lastFlushTime; + +private: + BLESerial(BLESerial const &other) = delete; + void operator=(BLESerial const &other) = delete; + + BLEFIFO rx_buffer; + size_t numAvailableLines; + uint8_t transmitBuffer[BLE_BUFFER_SIZE]; + + int ConnectedDeviceCount; + void SetupSerialService(); + + uint16_t peerMTU; + uint16_t maxTransferSize = BLE_BUFFER_SIZE; + + bool checkMTU(); + + const char *BLE_SERIAL_SERVICE_UUID = "6e400001-b5a3-f393-e0a9-e50e24dcca9e"; + const char *BLE_RX_UUID = "6e400002-b5a3-f393-e0a9-e50e24dcca9e"; + const char *BLE_TX_UUID = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"; + + bool started = false; +};