189 lines
7.2 KiB
C++
189 lines
7.2 KiB
C++
#include <NimBLEDevice.h>
|
|
#include "configuration.h"
|
|
#include "lora_utils.h"
|
|
#include "kiss_utils.h"
|
|
#include "ble_utils.h"
|
|
#include "display.h"
|
|
#include "logger.h"
|
|
|
|
#define BLE_CHUNK_SIZE 64
|
|
|
|
|
|
// APPLE - APRS.fi app
|
|
#define SERVICE_UUID_0 "00000001-ba2a-46c9-ae49-01b0961f68bb"
|
|
#define CHARACTERISTIC_UUID_TX_0 "00000003-ba2a-46c9-ae49-01b0961f68bb"
|
|
#define CHARACTERISTIC_UUID_RX_0 "00000002-ba2a-46c9-ae49-01b0961f68bb"
|
|
|
|
// ANDROID - BLE Terminal app (Serial Bluetooth Terminal from Playstore)
|
|
#define SERVICE_UUID_2 "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
|
|
#define CHARACTERISTIC_UUID_TX_2 "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
|
|
#define CHARACTERISTIC_UUID_RX_2 "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
|
|
|
|
BLEServer *pServer;
|
|
BLECharacteristic *pCharacteristicTx;
|
|
BLECharacteristic *pCharacteristicRx;
|
|
|
|
extern Configuration Config;
|
|
extern Beacon *currentBeacon;
|
|
extern logging::Logger logger;
|
|
extern bool bluetoothConnected;
|
|
|
|
bool shouldSendBLEtoLoRa = false;
|
|
String BLEToLoRaPacket = "";
|
|
|
|
String kissSerialBuffer = "";
|
|
|
|
|
|
class MyServerCallbacks : public NimBLEServerCallbacks {
|
|
void onConnect(NimBLEServer* pServer) {
|
|
bluetoothConnected = true;
|
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "BLE", "%s", "BLE Client Connected");
|
|
delay(100);
|
|
}
|
|
|
|
void onDisconnect(NimBLEServer* pServer) {
|
|
bluetoothConnected = false;
|
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "BLE", "%s", "BLE client Disconnected, Started Advertising");
|
|
delay(100);
|
|
pServer->startAdvertising();
|
|
}
|
|
};
|
|
|
|
|
|
class MyCallbacks : public NimBLECharacteristicCallbacks {
|
|
void onWrite(NimBLECharacteristic *pCharacteristic) {
|
|
if (Config.bluetooth.type == 0) { // AX25 KISS
|
|
std::string receivedData = pCharacteristic->getValue();
|
|
delay(100);
|
|
for (int i = 0; i < receivedData.length(); i++) {
|
|
char character = receivedData[i];
|
|
|
|
if (kissSerialBuffer.length() == 0 && character != (char)KissChar::FEND) continue;
|
|
kissSerialBuffer += receivedData[i];
|
|
|
|
if (character == (char)KissChar::FEND && kissSerialBuffer.length() > 3) {
|
|
bool isDataFrame = false;
|
|
|
|
BLEToLoRaPacket = KISS_Utils::decodeKISS(kissSerialBuffer, isDataFrame);
|
|
|
|
if (isDataFrame) {
|
|
shouldSendBLEtoLoRa = true;
|
|
kissSerialBuffer = "";
|
|
}
|
|
}
|
|
}
|
|
} else if (Config.bluetooth.type == 2) { // TNC2
|
|
std::string receivedData = pCharacteristic->getValue();
|
|
String receivedString = "";
|
|
for (int i = 0; i < receivedData.length(); i++) receivedString += receivedData[i];
|
|
BLEToLoRaPacket = receivedString;
|
|
shouldSendBLEtoLoRa = true;
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
namespace BLE_Utils {
|
|
|
|
void stop() {
|
|
BLEDevice::deinit();
|
|
}
|
|
|
|
void setup() {
|
|
String id = currentBeacon->callsign;
|
|
String BLEid = id.substring(0, id.indexOf("-")) + "-BLE";
|
|
BLEDevice::init(BLEid.c_str());
|
|
pServer = BLEDevice::createServer();
|
|
pServer->setCallbacks(new MyServerCallbacks());
|
|
|
|
BLEService *pService = nullptr;
|
|
|
|
if (Config.bluetooth.type == 0) {
|
|
pService = pServer->createService(SERVICE_UUID_0);
|
|
pCharacteristicTx = pService->createCharacteristic(CHARACTERISTIC_UUID_TX_0, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY);
|
|
pCharacteristicRx = pService->createCharacteristic(CHARACTERISTIC_UUID_RX_0, NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR);
|
|
} else if (Config.bluetooth.type == 2) {
|
|
pService = pServer->createService(SERVICE_UUID_2);
|
|
pCharacteristicTx = pService->createCharacteristic(CHARACTERISTIC_UUID_TX_2, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY);
|
|
pCharacteristicRx = pService->createCharacteristic(CHARACTERISTIC_UUID_RX_2, NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR);
|
|
}
|
|
|
|
if (pService != nullptr) {
|
|
pCharacteristicRx->setCallbacks(new MyCallbacks());
|
|
pService->start();
|
|
|
|
BLEAdvertising* pAdvertising = BLEDevice::getAdvertising();
|
|
|
|
if (Config.bluetooth.type == 0) {
|
|
pAdvertising->addServiceUUID(SERVICE_UUID_0);
|
|
} else if (Config.bluetooth.type == 2) {
|
|
pAdvertising->addServiceUUID(SERVICE_UUID_2);
|
|
}
|
|
pServer->getAdvertising()->setScanResponse(true);
|
|
pServer->getAdvertising()->setMinPreferred(0x06);
|
|
pServer->getAdvertising()->setMaxPreferred(0x0C);
|
|
pAdvertising->start();
|
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, "BLE", "%s", "Waiting for BLE central to connect...");
|
|
} else {
|
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "BLE", "Failed to create BLE service. Invalid bluetoothType: %d", Config.bluetooth.type);
|
|
}
|
|
}
|
|
|
|
void sendToLoRa() {
|
|
if (!shouldSendBLEtoLoRa) return;
|
|
|
|
if (!Config.acceptOwnFrameFromTNC && BLEToLoRaPacket.indexOf("::") == -1) {
|
|
String sender = BLEToLoRaPacket.substring(0, BLEToLoRaPacket.indexOf(">"));
|
|
if (sender == currentBeacon->callsign) {
|
|
BLEToLoRaPacket = "";
|
|
shouldSendBLEtoLoRa = false;
|
|
return;
|
|
}
|
|
}
|
|
|
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, "BLE Tx", "%s", BLEToLoRaPacket.c_str());
|
|
displayShow("BLE Tx >>", "", BLEToLoRaPacket, 1000);
|
|
LoRa_Utils::sendNewPacket(BLEToLoRaPacket);
|
|
BLEToLoRaPacket = "";
|
|
shouldSendBLEtoLoRa = false;
|
|
}
|
|
|
|
void txBLE(uint8_t p) {
|
|
pCharacteristicTx->setValue(&p,1);
|
|
pCharacteristicTx->notify();
|
|
delay(3);
|
|
}
|
|
|
|
void txToPhoneOverBLE(const String& frame) {
|
|
if (Config.bluetooth.type == 0) { // AX25 KISS
|
|
const String kissEncodedFrame = KISS_Utils::encodeKISS(frame);
|
|
|
|
const char* t = kissEncodedFrame.c_str();
|
|
int length = kissEncodedFrame.length();
|
|
for (int i = 0; i < length; i += BLE_CHUNK_SIZE) {
|
|
int chunkSize = (length - i < BLE_CHUNK_SIZE) ? (length - i) : BLE_CHUNK_SIZE;
|
|
|
|
uint8_t* chunk = new uint8_t[chunkSize];
|
|
memcpy(chunk, t + i, chunkSize);
|
|
|
|
pCharacteristicTx->setValue(chunk, chunkSize);
|
|
pCharacteristicTx->notify();
|
|
delete[] chunk;
|
|
delay(200);
|
|
}
|
|
} else { // TNC2
|
|
for(int n = 0; n < frame.length(); n++) txBLE(frame[n]);
|
|
txBLE('\n');
|
|
}
|
|
}
|
|
|
|
void sendToPhone(const String& packet) {
|
|
if (!packet.isEmpty() && bluetoothConnected) {
|
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, "BLE Rx", "%s", packet.c_str());
|
|
String receivedPacketString = "";
|
|
for (int i = 0; i < packet.length(); i++) receivedPacketString += packet[i];
|
|
txToPhoneOverBLE(receivedPacketString);
|
|
}
|
|
}
|
|
|
|
} |