mirror of https://github.com/meshcore-dev/MeshCore
Browse Source
* experimental NRF52 impl of SerialBLEInterface, and experimental RAK BLE companion radio targetpull/20/head
5 changed files with 237 additions and 1 deletions
@ -0,0 +1,149 @@ |
|||||
|
#include "SerialBLEInterface.h" |
||||
|
|
||||
|
void SerialBLEInterface::begin(const char* device_name, uint32_t pin_code) { |
||||
|
_pin_code = pin_code; |
||||
|
|
||||
|
Bluefruit.begin(); |
||||
|
Bluefruit.setTxPower(4); // Check bluefruit.h for supported values
|
||||
|
|
||||
|
// To be consistent OTA DFU should be added first if it exists
|
||||
|
//bledfu.begin();
|
||||
|
} |
||||
|
|
||||
|
void SerialBLEInterface::startAdv() { |
||||
|
// Advertising packet
|
||||
|
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); |
||||
|
Bluefruit.Advertising.addTxPower(); |
||||
|
|
||||
|
// Include the BLE UART (AKA 'NUS') 128-bit UUID
|
||||
|
Bluefruit.Advertising.addService(bleuart); |
||||
|
|
||||
|
// Secondary Scan Response packet (optional)
|
||||
|
// Since there is no room for 'Name' in Advertising packet
|
||||
|
Bluefruit.ScanResponse.addName(); |
||||
|
|
||||
|
/* Start Advertising
|
||||
|
* - Enable auto advertising if disconnected |
||||
|
* - Interval: fast mode = 20 ms, slow mode = 152.5 ms |
||||
|
* - Timeout for fast mode is 30 seconds |
||||
|
* - Start(timeout) with timeout = 0 will advertise forever (until connected) |
||||
|
* |
||||
|
* For recommended advertising interval |
||||
|
* https://developer.apple.com/library/content/qa/qa1931/_index.html
|
||||
|
*/ |
||||
|
Bluefruit.Advertising.restartOnDisconnect(true); |
||||
|
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
|
||||
|
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
|
||||
|
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
|
||||
|
} |
||||
|
|
||||
|
// ---------- public methods
|
||||
|
|
||||
|
void SerialBLEInterface::enable() { |
||||
|
if (_isEnabled) return; |
||||
|
|
||||
|
_isEnabled = true; |
||||
|
clearBuffers(); |
||||
|
|
||||
|
// Configure and start the BLE Uart service
|
||||
|
bleuart.begin(); |
||||
|
|
||||
|
// Start advertising
|
||||
|
startAdv(); |
||||
|
|
||||
|
checkAdvRestart = false; |
||||
|
} |
||||
|
|
||||
|
void SerialBLEInterface::disable() { |
||||
|
_isEnabled = false; |
||||
|
|
||||
|
BLE_DEBUG_PRINTLN("SerialBLEInterface::disable"); |
||||
|
|
||||
|
Bluefruit.Advertising.stop(); |
||||
|
|
||||
|
oldDeviceConnected = deviceConnected = false; |
||||
|
checkAdvRestart = false; |
||||
|
} |
||||
|
|
||||
|
size_t SerialBLEInterface::writeFrame(const uint8_t src[], size_t len) { |
||||
|
if (len > MAX_FRAME_SIZE) { |
||||
|
BLE_DEBUG_PRINTLN("writeFrame(), frame too big, len=%d", len); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
if (deviceConnected && len > 0) { |
||||
|
if (send_queue_len >= FRAME_QUEUE_SIZE) { |
||||
|
BLE_DEBUG_PRINTLN("writeFrame(), send_queue is full!"); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
send_queue[send_queue_len].len = len; // add to send queue
|
||||
|
memcpy(send_queue[send_queue_len].buf, src, len); |
||||
|
send_queue_len++; |
||||
|
|
||||
|
return len; |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
#define BLE_WRITE_MIN_INTERVAL 20 |
||||
|
|
||||
|
bool SerialBLEInterface::isWriteBusy() const { |
||||
|
return millis() < _last_write + BLE_WRITE_MIN_INTERVAL; // still too soon to start another write?
|
||||
|
} |
||||
|
|
||||
|
size_t SerialBLEInterface::checkRecvFrame(uint8_t dest[]) { |
||||
|
if (send_queue_len > 0 // first, check send queue
|
||||
|
&& millis() >= _last_write + BLE_WRITE_MIN_INTERVAL // space the writes apart
|
||||
|
) { |
||||
|
_last_write = millis(); |
||||
|
bleuart.write(send_queue[0].buf, send_queue[0].len); |
||||
|
BLE_DEBUG_PRINTLN("writeBytes: sz=%d, hdr=%d", (uint32_t)send_queue[0].len, (uint32_t) send_queue[0].buf[0]); |
||||
|
|
||||
|
send_queue_len--; |
||||
|
for (int i = 0; i < send_queue_len; i++) { // delete top item from queue
|
||||
|
send_queue[i] = send_queue[i + 1]; |
||||
|
} |
||||
|
} else { |
||||
|
int len = bleuart.available(); |
||||
|
if (len > 0) { |
||||
|
bleuart.readBytes(dest, len); |
||||
|
BLE_DEBUG_PRINTLN("readBytes: sz=%d, hdr=%d", len, (uint32_t) dest[0]); |
||||
|
return len; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (Bluefruit.connected() == 0) deviceConnected = false; |
||||
|
|
||||
|
if (deviceConnected != oldDeviceConnected) { |
||||
|
if (!deviceConnected) { // disconnecting
|
||||
|
clearBuffers(); |
||||
|
|
||||
|
BLE_DEBUG_PRINTLN("SerialBLEInterface -> disconnecting..."); |
||||
|
delay(500); // give the bluetooth stack the chance to get things ready
|
||||
|
|
||||
|
checkAdvRestart = true; |
||||
|
} else { |
||||
|
BLE_DEBUG_PRINTLN("SerialBLEInterface -> stopping advertising"); |
||||
|
BLE_DEBUG_PRINTLN("SerialBLEInterface -> connecting..."); |
||||
|
// connecting
|
||||
|
// do stuff here on connecting
|
||||
|
Bluefruit.Advertising.stop(); |
||||
|
checkAdvRestart = false; |
||||
|
} |
||||
|
oldDeviceConnected = deviceConnected; |
||||
|
} |
||||
|
|
||||
|
if (checkAdvRestart) { |
||||
|
if (Bluefruit.connected() == 0) { |
||||
|
BLE_DEBUG_PRINTLN("SerialBLEInterface -> re-starting advertising"); |
||||
|
startAdv(); |
||||
|
} |
||||
|
checkAdvRestart = false; |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
bool SerialBLEInterface::isConnected() const { |
||||
|
return deviceConnected; //pServer != NULL && pServer->getConnectedCount() > 0;
|
||||
|
} |
||||
@ -0,0 +1,58 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#include "../BaseSerialInterface.h" |
||||
|
#include <bluefruit.h> |
||||
|
|
||||
|
class SerialBLEInterface : public BaseSerialInterface { |
||||
|
BLEUart bleuart; |
||||
|
bool deviceConnected; |
||||
|
bool oldDeviceConnected; |
||||
|
bool checkAdvRestart; |
||||
|
bool _isEnabled; |
||||
|
uint32_t _pin_code; |
||||
|
unsigned long _last_write; |
||||
|
|
||||
|
struct Frame { |
||||
|
uint8_t len; |
||||
|
uint8_t buf[MAX_FRAME_SIZE]; |
||||
|
}; |
||||
|
|
||||
|
#define FRAME_QUEUE_SIZE 4 |
||||
|
int send_queue_len; |
||||
|
Frame send_queue[FRAME_QUEUE_SIZE]; |
||||
|
|
||||
|
void clearBuffers() { send_queue_len = 0; } |
||||
|
void startAdv(); |
||||
|
|
||||
|
public: |
||||
|
SerialBLEInterface() { |
||||
|
deviceConnected = false; |
||||
|
oldDeviceConnected = false; |
||||
|
checkAdvRestart = false; |
||||
|
_isEnabled = false; |
||||
|
_last_write = 0; |
||||
|
send_queue_len = 0; |
||||
|
} |
||||
|
|
||||
|
void begin(const char* device_name, uint32_t pin_code); |
||||
|
|
||||
|
// BaseSerialInterface methods
|
||||
|
void enable() override; |
||||
|
void disable() override; |
||||
|
bool isEnabled() const override { return _isEnabled; } |
||||
|
|
||||
|
bool isConnected() const override; |
||||
|
|
||||
|
bool isWriteBusy() const override; |
||||
|
size_t writeFrame(const uint8_t src[], size_t len) override; |
||||
|
size_t checkRecvFrame(uint8_t dest[]) override; |
||||
|
}; |
||||
|
|
||||
|
#if BLE_DEBUG_LOGGING && ARDUINO |
||||
|
#include <Arduino.h> |
||||
|
#define BLE_DEBUG_PRINT(F, ...) Serial.printf("BLE: " F, ##__VA_ARGS__) |
||||
|
#define BLE_DEBUG_PRINTLN(F, ...) Serial.printf("BLE: " F "\n", ##__VA_ARGS__) |
||||
|
#else |
||||
|
#define BLE_DEBUG_PRINT(...) {} |
||||
|
#define BLE_DEBUG_PRINTLN(...) {} |
||||
|
#endif |
||||
Loading…
Reference in new issue