Skip to content

Feature Request - BLE Nordic UART Peripheral Example #3204

@drmpf

Description

@drmpf

The only LEPeripheral example in the library is marked as

// LE Peripheral Example - not working yet

Can you add a Nordic Uart example Peripheral example

Here is the corresponding ESP32 code

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>

// =========== pfodBLESerial definitions
const char* localName = "ESP32 BLE";  // <<<<<<  change this string to customize the adverised name of your board
class pfodBLESerial : public Stream, public BLEServerCallbacks, public BLECharacteristicCallbacks {
public:
  pfodBLESerial();
  void begin();
  void poll();
  size_t write(uint8_t);
  size_t write(const uint8_t*, size_t);
  int read();
  int available();
  void flush();
  int peek();
  void close();
  bool isConnected();
  static void addReceiveBytes(const uint8_t* bytes, size_t len);
  const static uint8_t pfodEOF[1];
  const static char* pfodCloseConnection;
  volatile static bool connected;
  void onConnect(BLEServer* serverPtr);
  void onDisconnect(BLEServer* serverPtr);
  void onWrite(BLECharacteristic* pCharacteristic);

private:
  static const int BLE_MAX_LENGTH = 20;
  static const int BLE_RX_MAX_LENGTH = 256;
  static volatile size_t rxHead;
  static volatile size_t rxTail;
  volatile static uint8_t rxBuffer[BLE_RX_MAX_LENGTH];
  size_t txIdx;
  uint8_t txBuffer[BLE_MAX_LENGTH];
};
volatile size_t pfodBLESerial::rxHead = 0;
volatile size_t pfodBLESerial::rxTail = 0;
volatile uint8_t pfodBLESerial::rxBuffer[BLE_RX_MAX_LENGTH];
const uint8_t pfodBLESerial::pfodEOF[1] = { (uint8_t)-1 };
volatile bool pfodBLESerial::connected = false;

#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"  // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
// NOTE: the reverse characteristics do no work

BLEServer* serverPtr = NULL;
BLECharacteristic* characteristicTXPtr;
// =========== end pfodBLESerial definitions

                                          // create a parser to handle the pfod messages
pfodBLESerial bleSerial;                  // create a BLE serial connection


// the setup routine runs once on reset:
void setup() {
  Serial.begin(115200);
  Serial.println();

  // Create the BLE Device
  BLEDevice::init(localName);
  // Create the BLE Server
  serverPtr = BLEDevice::createServer();
  serverPtr->setCallbacks(&bleSerial);
  // Create the BLE Service
  BLEService* servicePtr = serverPtr->createService(SERVICE_UUID);
  // Create a BLE Characteristic
  characteristicTXPtr = servicePtr->createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY);
  characteristicTXPtr->addDescriptor(new BLE2902());
  BLECharacteristic* characteristicRXPtr = servicePtr->createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE);
  characteristicRXPtr->setCallbacks(&bleSerial);

  serverPtr->getAdvertising()->addServiceUUID(BLEUUID(SERVICE_UUID));
  // Start the service
  servicePtr->start();
  // Start advertising
  serverPtr->getAdvertising()->start();
  Serial.println("BLE Server and Advertising started");

  bleSerial.begin();
}

void loop() {
  while (bleSerial.available()) {
   Serial.println((char)bleSerial.read());
  }
  while (Serial.available()) {
    bleSerial.write(Serial.read());
  }
  //  <<<<<<<<<<<  Your other loop() code goes here
}

// ========== pfodBLESerial methods
pfodBLESerial::pfodBLESerial() {}

bool pfodBLESerial::isConnected() {
  return (connected);
}
void pfodBLESerial::begin() {}

void pfodBLESerial::close() {}

void pfodBLESerial::poll() {}

size_t pfodBLESerial::write(const uint8_t* bytes, size_t len) {
  for (size_t i = 0; i < len; i++) { write(bytes[i]); }
  return len;  // just assume it is all written
}

size_t pfodBLESerial::write(uint8_t b) {
  if (!isConnected()) { return 1; }
  txBuffer[txIdx++] = b;
  if ((txIdx == sizeof(txBuffer)) || (b == ((uint8_t)'\n')) || (b == ((uint8_t)'}'))) {
    flush();  // send this buffer if full or end of msg or rawdata newline
  }
  return 1;
}

int pfodBLESerial::read() {
  if (rxTail == rxHead) { return -1; }
  // note increment rxHead befor writing
  // so need to increment rxTail befor reading
  rxTail = (rxTail + 1) % sizeof(rxBuffer);
  uint8_t b = rxBuffer[rxTail];
  return b;
}

// called as part of parser.parse() so will poll() each loop()
int pfodBLESerial::available() {
  flush();  // send any pending data now. This happens at the top of each loop()
  int rtn = ((rxHead + sizeof(rxBuffer)) - rxTail) % sizeof(rxBuffer);
  return rtn;
}

void pfodBLESerial::flush() {
  if (txIdx == 0) { return; }
  characteristicTXPtr->setValue((uint8_t*)txBuffer, txIdx);
  txIdx = 0;
  characteristicTXPtr->notify();
}

int pfodBLESerial::peek() {
  if (rxTail == rxHead) { return -1; }
  size_t nextIdx = (rxTail + 1) % sizeof(rxBuffer);
  uint8_t byte = rxBuffer[nextIdx];
  return byte;
}

void pfodBLESerial::addReceiveBytes(const uint8_t* bytes, size_t len) {
  // note increment rxHead befor writing
  // so need to increment rxTail befor reading
  for (size_t i = 0; i < len; i++) {
    rxHead = (rxHead + 1) % sizeof(rxBuffer);
    Serial.print((char)bytes[i]);
    rxBuffer[rxHead] = bytes[i];
  }
}

//=========== ESP32 BLE callback methods
void pfodBLESerial::onConnect(BLEServer* serverPtr) {
  Serial.println("Connect");
  connected = true;
}

void pfodBLESerial::onDisconnect(BLEServer* serverPtr) {
  Serial.println("Disconnect");
  connected = false;
  Serial.println("Start Advert");
  serverPtr->getAdvertising()->start();
}

void pfodBLESerial::onWrite(BLECharacteristic* pCharacteristic) {
  String rxValue = pCharacteristic->getValue();
  uint8_t* data = (uint8_t*)rxValue.c_str();
  size_t len = rxValue.length();
  addReceiveBytes((const uint8_t*)data, len);
}
//======================= end pfodBLESerial methods


Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions