Skip to content

Commit

Permalink
BLE Support (#87)
Browse files Browse the repository at this point in the history
* Add support for BLE

Currently the cadence is set to 100ms and the minimum required by
FlySkyHigh is 200ms

* [Feature] Debugging:  Memory Usage Task

Adds a task for debugging memory utilization, once per second to print to console on debug releases.

* [Memory] Reduce the number of waypoints

Greatly reduces the amount of RAM needed.

[Memory] Memory optimization.  Make the graphics Consts.  Get them out of DRAM

* [BLE] Finished first run.

- Moved BLE to use the NimBLE package.  Apparently it's lighter on resources
- This demo also had a callback class that could let us re-advertise on a disconnect
- Plugged it into the preferences.

---------

Co-authored-by: Ankit Goyal <goyalankit40@gmail.com>
  • Loading branch information
scottyob and layog authored Mar 1, 2025
1 parent 98c1195 commit 16e9818
Show file tree
Hide file tree
Showing 9 changed files with 728 additions and 611 deletions.
4 changes: 4 additions & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ lib_deps =
; RadioLib for LoRa / Fanet
jgromes/RadioLib@^7.1.2

; For reduced memory BLE Server Support
h2zero/NimBLE-Arduino@^2.2.3

[env:release]
extends = env
build_unflags = -D ARDUINO_USB_MODE
Expand All @@ -65,6 +68,7 @@ build_flags =
${env.build_flags}
-D DEBUG_WIFI # Enables WiFi on boot, enables webserver, does not disable Wifi after setup
-D DISABLE_MASS_STORAGE # Disables mass storage on SD card mount
-D MEMORY_PROFILING # Enables memory profiling troubleshooting features
-D ARDUINO_USB_MODE=1
-D ARDUINO_USB_CDC_ON_BOOT=1 # Required for USB Serial on boot (for debugging)

Expand Down
9 changes: 8 additions & 1 deletion src/vario/PageMenuSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "PageMenuAbout.h"
#include "PageMenuSystemWifi.h"
#include "ble.h"
#include "buttons.h"
#include "display.h"
#include "displayFields.h"
Expand Down Expand Up @@ -196,8 +197,14 @@ void SystemMenuPage::setting_change(Button dir, ButtonState state, uint8_t count
redraw = true;
break;
case cursor_system_bluetooth:
if (state == RELEASED) {
if (state != RELEASED) break;
BLUETOOTH_ON = !BLUETOOTH_ON;
if (BLUETOOTH_ON) {
BLE::get().setup();
} else {
BLE::get().end();
}
settings_save();
break;
case cursor_system_reset:
if (state == RELEASED || state == NO_STATE) {
Expand Down
115 changes: 115 additions & 0 deletions src/vario/ble.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#include "ble.h"
#include <Arduino.h>

#include <NimBLEDevice.h>
#include "baro.h"
#include "etl/string.h"
#include "fanet_radio.h"

// These new unique UUIDs came from
// https://www.uuidgenerator.net/

#define LEAF_SERVICE_UUID "92b38cf3-4bd0-428c-aca4-ae6c3a586835"
// LK8EX1 Telemetry notification
#define LEAF_LK8EX1_UUID "583918da-fb9b-4645-bbaf-2db3b1a9c1b3"

class ServerCallbacks : public NimBLEServerCallbacks {
// Not sure we need this. Taken from the demo
void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) override {
/**
* We can use the connection handle here to ask for different connection parameters.
* Args: connection handle, min connection interval, max connection interval
* latency, supervision timeout.
* Units; Min/Max Intervals: 1.25 millisecond increments.
* Latency: number of intervals allowed to skip.
* Timeout: 10 millisecond increments.
*/
pServer->updateConnParams(connInfo.getConnHandle(), 24, 48, 0, 180);
}

// This one seems import to re-advertise
void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) override {
// Re-advertise after a disconnect
NimBLEDevice::startAdvertising();
}

} serverCallbacks;

BLE& BLE::get() {
static BLE instance;
return instance;
}

void BLE::setup() {
// Initialize the BLE with the unique device name
etl::string<13> name = "Leaf: ";
name += FanetRadio::getAddress().c_str();
NimBLEDevice::init(name.c_str());

// Create a server using the callback class to re-advertise on a disconnect
pServer = NimBLEDevice::createServer();
pServer->setCallbacks(&serverCallbacks);

// Create the characteristic and start advertising climb rate information
NimBLEService* pService = pServer->createService(LEAF_SERVICE_UUID);
pCharacteristic = pService->createCharacteristic(LEAF_LK8EX1_UUID,
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY);
pService->start();

/** Create an advertising instance and add the services to the advertised data */
pAdvertising = NimBLEDevice::getAdvertising();
pAdvertising->setName(name.c_str());
pAdvertising->addServiceUUID(pService->getUUID());
/**
* If your device is battery powered you may consider setting scan response
* to false as it will extend battery life at the expense of less data sent.
*/
pAdvertising->enableScanResponse(true);
pAdvertising->start();
}

uint8_t checksum(std::string_view string) {
uint8_t result = 0;
for (int i = 1; i < string.find('*'); i++) {
result ^= string[i];
}
return result;
}

void BLE::loop() {
// Short circuit if not running or no connected clients
if (!pServer || !pServer->getConnectedCount()) return;

char stringified[50];
snprintf(stringified,
sizeof(stringified),
// See https://raw.githubusercontent.com/LK8000/LK8000/master/Docs/LK8EX1.txt
("$LK8EX1," // Type of update
"%u," // raw pressure in hPascal
"99999," // altitude in meters, relative to QNH 1013.25. 99999 if not available/needed
"%d," // Climb rate in cm/s. Can be 99999 if not available
"99," // Temperature in C. If not available, send 99
"999," // Battery voltage OR percentage. If percentage, add 1000 (if 1014 is 14%). 999
// if unavailable
"*" // Checksum to follow
),
baro.pressureFiltered,
baro.climbRateFiltered);
// Add checksum and delimeter with newline
snprintf(stringified + strlen(stringified), sizeof(stringified), "%02X\n", checksum(stringified));
pCharacteristic->setValue((const uint8_t*)stringified, sizeof(stringified));
pCharacteristic->notify();

// TODO: Need lines for GPS and Fanet updates
}

void BLE::end() {
// Delete any objects created and deinit manually.. Seems to crash setting this to true
NimBLEDevice::deinit(false);

// Reset null pointers.
pServer = nullptr;
pService = nullptr;
pCharacteristic = nullptr;
pAdvertising = nullptr;
}
21 changes: 21 additions & 0 deletions src/vario/ble.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include <NimBLEDevice.h>

class BLE {
public:
static BLE& get();

void setup();
void loop();
void end();

private:
BLE() : pServer(nullptr), pService(nullptr), pCharacteristic(nullptr), pAdvertising(nullptr) {}

NimBLEServer* pServer;
NimBLEService* pService;
NimBLECharacteristic* pCharacteristic;
NimBLEAdvertising* pAdvertising;
};
;
Loading

0 comments on commit 16e9818

Please sign in to comment.