SE-TP2/libs/Firmata/utility/ArduinoBLE_UART_Stream.h
2025-05-10 16:33:54 +01:00

257 lines
6.2 KiB
C++

/*
ArduinoBLE_UART_Stream.h
Based on BLEStream.h and the HardwareBLESerial library:
https://github.com/Uberi/Arduino-HardwareBLESerial
*/
#ifndef _ARDUINO_BLE_UART_STREAM_H_
#define _ARDUINO_BLE_UART_STREAM_H_
#include <ArduinoBLE.h>
#define BLE_ATTRIBUTE_MAX_VALUE_LENGTH 20
class ArduinoBLE_UART_Stream : public Stream
{
public:
ArduinoBLE_UART_Stream();
void setLocalName(const char *localName);
void setAdvertisingInterval(unsigned short advertisingInterval);
void setConnectionInterval(unsigned short minConnInterval, unsigned short maxConnInterval);
void setFlushInterval(int flushInterval);
void begin();
bool poll();
void end();
// Print overrides
size_t write(uint8_t byte);
using Print::write; // Expose other write variants
// Stream overrides
int available();
int read();
int peek();
void flush();
private:
void dataReceived(const unsigned char *data, size_t size);
static void connectedHandler(BLEDevice central);
static void disconnectedHandler(BLEDevice central);
static void rxWrittenHandler(BLEDevice central, BLECharacteristic characteristic);
static void txSubscribedHandler(BLEDevice central, BLECharacteristic characteristic);
static void txUnsubscribedHandler(BLEDevice central, BLECharacteristic characteristic);
BLEService uartService;
BLECharacteristic rxCharacteristic;
BLECharacteristic txCharacteristic;
String localName;
unsigned short advertisingInterval;
unsigned short minConnInterval;
unsigned short maxConnInterval;
int flushInterval;
bool connected;
unsigned char rxBuffer[256];
size_t rxHead;
size_t rxTail;
bool txSubscribed;
unsigned char txBuffer[BLE_ATTRIBUTE_MAX_VALUE_LENGTH];
size_t txCount;
unsigned long lastFlushTime;
static ArduinoBLE_UART_Stream *instance;
};
ArduinoBLE_UART_Stream::ArduinoBLE_UART_Stream() :
uartService("6E400001-B5A3-F393-E0A9-E50E24DCCA9E"),
rxCharacteristic("6E400002-B5A3-F393-E0A9-E50E24DCCA9E", BLEWriteWithoutResponse | BLEWrite, BLE_ATTRIBUTE_MAX_VALUE_LENGTH),
txCharacteristic("6E400003-B5A3-F393-E0A9-E50E24DCCA9E", BLENotify, BLE_ATTRIBUTE_MAX_VALUE_LENGTH),
advertisingInterval(0),
minConnInterval(0),
maxConnInterval(0),
flushInterval(100), // Default flush interval is 100ms
connected(false),
rxHead(0),
rxTail(0),
txSubscribed(false),
txCount(0),
lastFlushTime(0)
{
instance = this;
}
void ArduinoBLE_UART_Stream::setLocalName(const char *localName)
{
this->localName = localName;
}
void ArduinoBLE_UART_Stream::setAdvertisingInterval(unsigned short advertisingInterval)
{
this->advertisingInterval = advertisingInterval;
}
void ArduinoBLE_UART_Stream::setConnectionInterval(unsigned short minConnInterval, unsigned short maxConnInterval)
{
this->minConnInterval = minConnInterval;
this->maxConnInterval = maxConnInterval;
}
void ArduinoBLE_UART_Stream::setFlushInterval(int flushInterval)
{
// The minimum allowed connection interval is 7.5ms, so don't try to flush
// more frequently than that
this->flushInterval = max(flushInterval, 8);
}
void ArduinoBLE_UART_Stream::begin()
{
BLE.begin();
if (localName.length() > 0) {
BLE.setLocalName(localName.c_str());
}
if (advertisingInterval > 0) {
BLE.setAdvertisingInterval(advertisingInterval);
}
if (minConnInterval > 0 && maxConnInterval > 0) {
BLE.setConnectionInterval(minConnInterval, maxConnInterval);
}
BLE.setEventHandler(BLEConnected, connectedHandler);
BLE.setEventHandler(BLEDisconnected, disconnectedHandler);
rxCharacteristic.setEventHandler(BLEWritten, rxWrittenHandler);
uartService.addCharacteristic(rxCharacteristic);
txCharacteristic.setEventHandler(BLESubscribed, txSubscribedHandler);
txCharacteristic.setEventHandler(BLEUnsubscribed, txUnsubscribedHandler);
uartService.addCharacteristic(txCharacteristic);
BLE.addService(uartService);
BLE.setAdvertisedService(uartService);
BLE.advertise();
}
bool ArduinoBLE_UART_Stream::poll()
{
if (millis() - lastFlushTime > flushInterval) {
flush(); // Always calls BLE.poll()
} else {
BLE.poll();
}
return connected;
}
void ArduinoBLE_UART_Stream::end()
{
flush();
txCharacteristic.setEventHandler(BLEUnsubscribed, NULL);
txCharacteristic.setEventHandler(BLESubscribed, NULL);
txSubscribed = false;
rxCharacteristic.setEventHandler(BLEWritten, NULL);
rxHead = 0;
rxTail = 0;
BLE.setEventHandler(BLEDisconnected, NULL);
BLE.setEventHandler(BLEConnected, NULL);
connected = false;
BLE.end();
}
size_t ArduinoBLE_UART_Stream::write(uint8_t byte)
{
if (!txSubscribed) {
return 0;
}
txBuffer[txCount] = byte;
txCount++;
if (txCount == sizeof(txBuffer)) {
flush();
}
return 1;
}
int ArduinoBLE_UART_Stream::available()
{
return (rxHead - rxTail + sizeof(rxBuffer)) % sizeof(rxBuffer);
}
int ArduinoBLE_UART_Stream::read()
{
if (rxTail == rxHead) {
return -1;
}
uint8_t byte = rxBuffer[rxTail];
rxTail = (rxTail + 1) % sizeof(rxBuffer);
return byte;
}
int ArduinoBLE_UART_Stream::peek()
{
if (rxTail == rxHead) {
return -1;
}
return rxBuffer[rxTail];
}
void ArduinoBLE_UART_Stream::flush()
{
if (txCount > 0) {
txCharacteristic.setValue(txBuffer, txCount);
txCount = 0;
}
lastFlushTime = millis();
BLE.poll();
}
void ArduinoBLE_UART_Stream::dataReceived(const unsigned char *data, size_t size)
{
for (size_t i = 0; i < size; i++) {
rxBuffer[rxHead] = data[i];
rxHead = (rxHead + 1) % sizeof(rxBuffer);
}
}
void ArduinoBLE_UART_Stream::connectedHandler(BLEDevice central)
{
instance->connected = true;
}
void ArduinoBLE_UART_Stream::disconnectedHandler(BLEDevice central)
{
instance->connected = false;
}
void ArduinoBLE_UART_Stream::rxWrittenHandler(BLEDevice central, BLECharacteristic characteristic)
{
instance->dataReceived(characteristic.value(), characteristic.valueLength());
}
void ArduinoBLE_UART_Stream::txSubscribedHandler(BLEDevice central, BLECharacteristic characteristic)
{
instance->txSubscribed = true;
}
void ArduinoBLE_UART_Stream::txUnsubscribedHandler(BLEDevice central, BLECharacteristic characteristic)
{
instance->txSubscribed = false;
}
ArduinoBLE_UART_Stream * ArduinoBLE_UART_Stream::instance = NULL;
#endif // _ARDUINO_BLE_UART_STREAM_H_