diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 7e03cfe54..4088eb28a 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -49,6 +49,7 @@ jobs:
ARDUINO_CLI_VERSION: 0.34.2
ARDUINO_BLE_VERSION: 1.3.6
ENERGIA_IDE_VERSION: 1.8.10E23
+ NIM_BLE_VERSION: 1.4.1
BOARD: ${{ matrix.board }}
# Steps represent a sequence of tasks that will be executed as part of the job
@@ -214,6 +215,10 @@ jobs:
arduino --pref "custom_UploadSpeed=esp32c6_921600" --save-prefs ;
cd $HOME/.arduino15/packages/esp32/hardware/esp32/3.0.0-alpha3 ;
sed -i "s\echo '-DARDUINO_CORE_BUILD'\echo -DARDUINO_CORE_BUILD\g" platform.txt ;
+ wget https://github.com/h2zero/NimBLE-Arduino/archive/refs/tags/${NIM_BLE_VERSION}.tar.gz ;
+ tar xzf ${NIM_BLE_VERSION}.tar.gz ;
+ rm ${NIM_BLE_VERSION}.tar.gz ;
+ mv NimBLE-Arduino-${NIM_BLE_VERSION} $HOME/Arduino/libraries/ ;
cd $GITHUB_WORKSPACE ;
fi
if [[ "$BOARD" =~ "STM32:stm32:" ]]; then
diff --git a/software/firmware/source/SoftRF/src/driver/Bluetooth.h b/software/firmware/source/SoftRF/src/driver/Bluetooth.h
index 312d5d49f..032ccbd53 100644
--- a/software/firmware/source/SoftRF/src/driver/Bluetooth.h
+++ b/software/firmware/source/SoftRF/src/driver/Bluetooth.h
@@ -32,7 +32,12 @@ enum
#endif
#if defined(ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
+#include "../system/SoC.h"
+#if defined(USE_NIMBLE)
+#include "../platform/bluetooth/NimBLE.h"
+#else
#include "../platform/bluetooth/Bluedroid.h"
+#endif /* USE_NIMBLE */
#elif defined(ARDUINO_ARCH_NRF52)
#include "../platform/bluetooth/Bluefruit.h"
#elif defined(ARDUINO_ARCH_RP2040) && defined(ARDUINO_RASPBERRY_PI_PICO_W)
diff --git a/software/firmware/source/SoftRF/src/platform/ESP32.cpp b/software/firmware/source/SoftRF/src/platform/ESP32.cpp
index fd96427fb..e3bf4dc74 100644
--- a/software/firmware/source/SoftRF/src/platform/ESP32.cpp
+++ b/software/firmware/source/SoftRF/src/platform/ESP32.cpp
@@ -4082,8 +4082,9 @@ void handleMainEvent(AceButton* button, uint8_t eventType,
switch (eventType) {
#if defined(USE_SA8X8)
case AceButton::kEventPressed:
- if (button == &button_ptt &&
- Voice_Frequency > 0 &&
+ if (button == &button_ptt &&
+ hw_info.rf == RF_IC_SA8X8 &&
+ Voice_Frequency > 0 &&
(settings->power_save & POWER_SAVE_NORECEIVE)) {
bool playback = false;
#if !defined(EXCLUDE_VOICE_MESSAGE)
@@ -4135,8 +4136,9 @@ void handleMainEvent(AceButton* button, uint8_t eventType,
}
#endif /* USE_OLED */
#if defined(USE_SA8X8)
- if (button == &button_ptt &&
- Voice_Frequency > 0 &&
+ if (button == &button_ptt &&
+ hw_info.rf == RF_IC_SA8X8 &&
+ Voice_Frequency > 0 &&
(settings->power_save & POWER_SAVE_NORECEIVE)) {
controller.receive();
sa868_Tx_LED_state(false);
diff --git a/software/firmware/source/SoftRF/src/platform/ESP32.h b/software/firmware/source/SoftRF/src/platform/ESP32.h
index 98d2892dc..8b94126ac 100644
--- a/software/firmware/source/SoftRF/src/platform/ESP32.h
+++ b/software/firmware/source/SoftRF/src/platform/ESP32.h
@@ -402,10 +402,12 @@ extern const USB_Device_List_t supported_USB_devices[];
#define EXCLUDE_WATCHOUT_MODE
#undef USE_NMEALIB
#undef ENABLE_PROL
+//#define USE_NIMBLE
#endif /* C6 */
#endif /* CONFIG_IDF_TARGET_ESP32SX | C3 | C6 */
#else
//#define ENABLE_BT_VOICE
+//#define USE_NIMBLE
#endif /* NOT CONFIG_IDF_TARGET_ESP32 */
#define POWER_SAVING_WIFI_TIMEOUT 600000UL /* 10 minutes */
diff --git a/software/firmware/source/SoftRF/src/platform/bluetooth/Bluedroid.cpp b/software/firmware/source/SoftRF/src/platform/bluetooth/Bluedroid.cpp
index a6653938a..ef3bd9045 100644
--- a/software/firmware/source/SoftRF/src/platform/bluetooth/Bluedroid.cpp
+++ b/software/firmware/source/SoftRF/src/platform/bluetooth/Bluedroid.cpp
@@ -19,8 +19,9 @@
#if defined(ESP32)
#include "sdkconfig.h"
-#if defined(CONFIG_BLUEDROID_ENABLED)
+#include "../../system/SoC.h"
+#if defined(CONFIG_BLUEDROID_ENABLED) && !defined(USE_NIMBLE)
/*
* BLE code is based on Neil Kolban example for IDF:
* https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
@@ -34,7 +35,6 @@
#include "esp_gap_bt_api.h"
-#include "../../system/SoC.h"
#include "../../driver/EEPROM.h"
#include "../../driver/Bluetooth.h"
#include "../../driver/WiFi.h"
diff --git a/software/firmware/source/SoftRF/src/platform/bluetooth/NimBLE.cpp b/software/firmware/source/SoftRF/src/platform/bluetooth/NimBLE.cpp
new file mode 100644
index 000000000..e8f2aea05
--- /dev/null
+++ b/software/firmware/source/SoftRF/src/platform/bluetooth/NimBLE.cpp
@@ -0,0 +1,388 @@
+/*
+ * NimBLE.cpp
+ * Copyright (C) 2024 Linar Yusupov
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#if defined(ESP32)
+#include "sdkconfig.h"
+
+#include "../../system/SoC.h"
+
+#if defined(USE_NIMBLE)
+/*
+ * BLE code is based on Neil Kolban example for IDF:
+ * https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
+ * Ported to Arduino ESP32 by Evandro Copercini
+ * HM-10 emulation and adaptation for SoftRF is done by Linar Yusupov.
+ */
+#include
+#include
+#include
+
+#include "esp_gap_bt_api.h"
+
+#include "../../driver/EEPROM.h"
+#include "../../driver/Bluetooth.h"
+#include "../../driver/WiFi.h"
+#include "../../driver/Battery.h"
+
+#include
+
+NimBLEServer* pServer = NULL;
+NimBLECharacteristic* pUARTCharacteristic = NULL;
+NimBLECharacteristic* pBATCharacteristic = NULL;
+
+NimBLECharacteristic* pModelCharacteristic = NULL;
+NimBLECharacteristic* pSerialCharacteristic = NULL;
+NimBLECharacteristic* pFirmwareCharacteristic = NULL;
+NimBLECharacteristic* pHardwareCharacteristic = NULL;
+NimBLECharacteristic* pSoftwareCharacteristic = NULL;
+NimBLECharacteristic* pManufacturerCharacteristic = NULL;
+
+bool deviceConnected = false;
+bool oldDeviceConnected = false;
+
+#if defined(USE_BLE_MIDI)
+NimBLECharacteristic* pMIDICharacteristic = NULL;
+#endif /* USE_BLE_MIDI */
+
+cbuf *BLE_FIFO_RX, *BLE_FIFO_TX;
+
+String BT_name = HOSTNAME;
+
+static unsigned long BLE_Notify_TimeMarker = 0;
+static unsigned long BLE_Advertising_TimeMarker = 0;
+
+// NimBLEDescriptor UserDescriptor(NimBLEUUID((uint16_t)0x2901));
+
+class MyServerCallbacks: public NimBLEServerCallbacks {
+ void onConnect(NimBLEServer* pServer) {
+ deviceConnected = true;
+ };
+
+ void onDisconnect(NimBLEServer* pServer) {
+ deviceConnected = false;
+ BLE_Advertising_TimeMarker = millis();
+ }
+};
+
+class UARTCallbacks: public BLECharacteristicCallbacks {
+ void onWrite(NimBLECharacteristic *pUARTCharacteristic) {
+#if defined(ESP_IDF_VERSION_MAJOR) && ESP_IDF_VERSION_MAJOR>=5
+ String rxValue = pUARTCharacteristic->getValue();
+#else
+ std::string rxValue = pUARTCharacteristic->getValue();
+#endif /* ESP_IDF_VERSION_MAJOR */
+
+ if (rxValue.length() > 0) {
+ BLE_FIFO_RX->write(rxValue.c_str(),
+ (BLE_FIFO_RX->room() > rxValue.length() ?
+ rxValue.length() : BLE_FIFO_RX->room()));
+ }
+ }
+};
+
+static void ESP32_Bluetooth_setup()
+{
+ BT_name += "-";
+ BT_name += String(SoC->getChipId() & 0x00FFFFFFU, HEX);
+
+ switch (settings->bluetooth)
+ {
+ case BLUETOOTH_LE_HM10_SERIAL:
+ {
+ BLE_FIFO_RX = new cbuf(BLE_FIFO_RX_SIZE);
+ BLE_FIFO_TX = new cbuf(BLE_FIFO_TX_SIZE);
+
+ // Create the BLE Device
+ NimBLEDevice::init((BT_name+"-LE").c_str());
+
+ /*
+ * Set the MTU of the packets sent,
+ * maximum is 500, Apple needs 23 apparently.
+ */
+ // NimBLEDevice::setMTU(23);
+
+ // Create the BLE Server
+ pServer = NimBLEDevice::createServer();
+ pServer->setCallbacks(new MyServerCallbacks());
+
+ // Create the BLE Service
+ NimBLEService *pService = pServer->createService(NimBLEUUID(UART_SERVICE_UUID16));
+
+ // Create a BLE Characteristic
+ pUARTCharacteristic = pService->createCharacteristic(
+ NimBLEUUID(UART_CHARACTERISTIC_UUID16),
+ NIMBLE_PROPERTY::READ |
+ NIMBLE_PROPERTY::NOTIFY |
+ NIMBLE_PROPERTY::WRITE_NR
+ );
+
+// UserDescriptor.setValue("HMSoft");
+// pUARTCharacteristic->addDescriptor(&UserDescriptor);
+
+ pUARTCharacteristic->setCallbacks(new UARTCallbacks());
+
+ // Start the service
+ pService->start();
+
+ // Create the BLE Service
+ pService = pServer->createService(NimBLEUUID(UUID16_SVC_BATTERY));
+
+ // Create a BLE Characteristic
+ pBATCharacteristic = pService->createCharacteristic(
+ NimBLEUUID(UUID16_CHR_BATTERY_LEVEL),
+ NIMBLE_PROPERTY::READ |
+ NIMBLE_PROPERTY::NOTIFY
+ );
+
+ // Start the service
+ pService->start();
+
+ // Create the BLE Service
+ pService = pServer->createService(NimBLEUUID(UUID16_SVC_DEVICE_INFORMATION));
+
+ // Create BLE Characteristics
+ pModelCharacteristic = pService->createCharacteristic(
+ NimBLEUUID(UUID16_CHR_MODEL_NUMBER_STRING),
+ NIMBLE_PROPERTY::READ
+ );
+ pSerialCharacteristic = pService->createCharacteristic(
+ NimBLEUUID(UUID16_CHR_SERIAL_NUMBER_STRING),
+ NIMBLE_PROPERTY::READ
+ );
+ pFirmwareCharacteristic = pService->createCharacteristic(
+ NimBLEUUID(UUID16_CHR_FIRMWARE_REVISION_STRING),
+ NIMBLE_PROPERTY::READ
+ );
+ pHardwareCharacteristic = pService->createCharacteristic(
+ NimBLEUUID(UUID16_CHR_HARDWARE_REVISION_STRING),
+ NIMBLE_PROPERTY::READ
+ );
+ pSoftwareCharacteristic = pService->createCharacteristic(
+ NimBLEUUID(UUID16_CHR_SOFTWARE_REVISION_STRING),
+ NIMBLE_PROPERTY::READ
+ );
+ pManufacturerCharacteristic = pService->createCharacteristic(
+ NimBLEUUID(UUID16_CHR_MANUFACTURER_NAME_STRING),
+ NIMBLE_PROPERTY::READ
+ );
+
+ const char *Model = hw_info.model == SOFTRF_MODEL_STANDALONE ? "Standalone Edition" :
+ hw_info.model == SOFTRF_MODEL_PRIME_MK2 ? "Prime Mark II" :
+ hw_info.model == SOFTRF_MODEL_PRIME_MK3 ? "Prime Mark III" :
+ hw_info.model == SOFTRF_MODEL_HAM ? "Ham Edition" :
+ hw_info.model == SOFTRF_MODEL_MIDI ? "Midi Edition" :
+ "Unknown";
+ char SerialNum[9];
+ snprintf(SerialNum, sizeof(SerialNum), "%08X", SoC->getChipId());
+
+ const char *Firmware = "Arduino ESP32 " ARDUINO_ESP32_RELEASE;
+
+ char Hardware[9];
+ snprintf(Hardware, sizeof(Hardware), "%08X", hw_info.revision);
+
+ const char *Manufacturer = SOFTRF_IDENT;
+ const char *Software = SOFTRF_FIRMWARE_VERSION;
+
+ pModelCharacteristic-> setValue((uint8_t *) Model, strlen(Model));
+ pSerialCharacteristic-> setValue((uint8_t *) SerialNum, strlen(SerialNum));
+ pFirmwareCharacteristic-> setValue((uint8_t *) Firmware, strlen(Firmware));
+ pHardwareCharacteristic-> setValue((uint8_t *) Hardware, strlen(Hardware));
+ pSoftwareCharacteristic-> setValue((uint8_t *) Software, strlen(Software));
+ pManufacturerCharacteristic->setValue((uint8_t *) Manufacturer, strlen(Manufacturer));
+
+ // Start the service
+ pService->start();
+
+#if defined(USE_BLE_MIDI)
+ // Create the BLE Service
+ pService = pServer->createService(NimBLEUUID(MIDI_SERVICE_UUID));
+
+ // Create a BLE Characteristic
+ pMIDICharacteristic = pService->createCharacteristic(
+ NimBLEUUID(MIDI_CHARACTERISTIC_UUID),
+ NIMBLE_PROPERTY::READ |
+ NIMBLE_PROPERTY::WRITE |
+ NIMBLE_PROPERTY::NOTIFY |
+ NIMBLE_PROPERTY::WRITE_NR
+ );
+
+ // Start the service
+ pService->start();
+#endif /* USE_BLE_MIDI */
+
+ // Start advertising
+ NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
+#if 0
+ pAdvertising->addServiceUUID(NimBLEUUID(UART_SERVICE_UUID16));
+ pAdvertising->addServiceUUID(NimBLEUUID(UUID16_SVC_BATTERY));
+#if defined(USE_BLE_MIDI)
+ pAdvertising->addServiceUUID(NimBLEUUID(MIDI_SERVICE_UUID));
+#endif /* USE_BLE_MIDI */
+#else
+ /* work around https://github.com/espressif/arduino-esp32/issues/6750 */
+ NimBLEAdvertisementData BLEAdvData;
+ BLEAdvData.setFlags(0x06);
+ BLEAdvData.setCompleteServices(NimBLEUUID(UART_SERVICE_UUID16));
+ BLEAdvData.setCompleteServices(NimBLEUUID(UUID16_SVC_BATTERY));
+#if defined(USE_BLE_MIDI)
+ BLEAdvData.setCompleteServices(NimBLEUUID(MIDI_SERVICE_UUID));
+#endif /* USE_BLE_MIDI */
+ pAdvertising->setAdvertisementData(BLEAdvData);
+#endif
+ pAdvertising->setScanResponse(true);
+ pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
+ pAdvertising->setMaxPreferred(0x12);
+ NimBLEDevice::startAdvertising();
+
+ BLE_Advertising_TimeMarker = millis();
+ }
+ break;
+ case BLUETOOTH_NONE:
+ case BLUETOOTH_SPP:
+ case BLUETOOTH_A2DP_SOURCE:
+ default:
+ break;
+ }
+}
+
+static void ESP32_Bluetooth_loop()
+{
+ switch (settings->bluetooth)
+ {
+ case BLUETOOTH_LE_HM10_SERIAL:
+ {
+ // notify changed value
+ // bluetooth stack will go into congestion, if too many packets are sent
+ if (deviceConnected && (millis() - BLE_Notify_TimeMarker > 10)) { /* < 18000 baud */
+
+ uint8_t chunk[BLE_MAX_WRITE_CHUNK_SIZE];
+ size_t size = BLE_FIFO_TX->available();
+ size = size < BLE_MAX_WRITE_CHUNK_SIZE ? size : BLE_MAX_WRITE_CHUNK_SIZE;
+
+ if (size > 0) {
+ BLE_FIFO_TX->read((char *) chunk, size);
+
+ pUARTCharacteristic->setValue(chunk, size);
+ pUARTCharacteristic->notify();
+ }
+
+ BLE_Notify_TimeMarker = millis();
+ }
+ // disconnecting
+ if (!deviceConnected && oldDeviceConnected && (millis() - BLE_Advertising_TimeMarker > 500) ) {
+ // give the bluetooth stack the chance to get things ready
+ pServer->startAdvertising(); // restart advertising
+ oldDeviceConnected = deviceConnected;
+ BLE_Advertising_TimeMarker = millis();
+ }
+ // connecting
+ if (deviceConnected && !oldDeviceConnected) {
+ // do stuff here on connecting
+ oldDeviceConnected = deviceConnected;
+ }
+ if (deviceConnected && isTimeToBattery()) {
+ uint8_t battery_level = Battery_charge();
+
+ pBATCharacteristic->setValue(&battery_level, 1);
+ pBATCharacteristic->notify();
+ }
+ }
+ break;
+ case BLUETOOTH_NONE:
+ case BLUETOOTH_SPP:
+ case BLUETOOTH_A2DP_SOURCE:
+ default:
+ break;
+ }
+}
+
+static void ESP32_Bluetooth_fini()
+{
+ /* TBD */
+}
+
+static int ESP32_Bluetooth_available()
+{
+ int rval = 0;
+
+ switch (settings->bluetooth)
+ {
+ case BLUETOOTH_LE_HM10_SERIAL:
+ rval = BLE_FIFO_RX->available();
+ break;
+ case BLUETOOTH_NONE:
+ case BLUETOOTH_A2DP_SOURCE:
+ case BLUETOOTH_SPP:
+ default:
+ break;
+ }
+
+ return rval;
+}
+
+static int ESP32_Bluetooth_read()
+{
+ int rval = -1;
+
+ switch (settings->bluetooth)
+ {
+ case BLUETOOTH_LE_HM10_SERIAL:
+ rval = BLE_FIFO_RX->read();
+ break;
+ case BLUETOOTH_NONE:
+ case BLUETOOTH_A2DP_SOURCE:
+ case BLUETOOTH_SPP:
+ default:
+ break;
+ }
+
+ return rval;
+}
+
+static size_t ESP32_Bluetooth_write(const uint8_t *buffer, size_t size)
+{
+ size_t rval = size;
+
+ switch (settings->bluetooth)
+ {
+ case BLUETOOTH_LE_HM10_SERIAL:
+ rval = BLE_FIFO_TX->write((char *) buffer,
+ (BLE_FIFO_TX->room() > size ? size : BLE_FIFO_TX->room()));
+ break;
+ case BLUETOOTH_NONE:
+ case BLUETOOTH_A2DP_SOURCE:
+ case BLUETOOTH_SPP:
+ default:
+ break;
+ }
+
+ return rval;
+}
+
+IODev_ops_t ESP32_Bluetooth_ops = {
+ "ESP32 Bluetooth",
+ ESP32_Bluetooth_setup,
+ ESP32_Bluetooth_loop,
+ ESP32_Bluetooth_fini,
+ ESP32_Bluetooth_available,
+ ESP32_Bluetooth_read,
+ ESP32_Bluetooth_write
+};
+
+#endif /* USE_NIMBLE */
+#endif /* ESP32 */
diff --git a/software/firmware/source/SoftRF/src/platform/bluetooth/NimBLE.h b/software/firmware/source/SoftRF/src/platform/bluetooth/NimBLE.h
new file mode 100644
index 000000000..6ed99552a
--- /dev/null
+++ b/software/firmware/source/SoftRF/src/platform/bluetooth/NimBLE.h
@@ -0,0 +1,55 @@
+/*
+ * NimBLE.h
+ * Copyright (C) 2024 Linar Yusupov
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef NIMBLE_H
+#define NIMBLE_H
+
+#define UART_SERVICE_UUID16 ((uint16_t) 0xFFE0)
+#define UART_CHARACTERISTIC_UUID16 ((uint16_t) 0xFFE1)
+#define UART_SERVICE_UUID128 "0000ffe0-0000-1000-8000-00805f9b34fb"
+#define UART_CHARACTERISTIC_UUID128 "0000ffe1-0000-1000-8000-00805f9b34fb"
+
+#define MIDI_SERVICE_UUID "03b80e5a-ede8-4b33-a751-6ce34ec4c700"
+#define MIDI_CHARACTERISTIC_UUID "7772e5db-3868-4112-a1a9-f2669d106bf3"
+
+#define UUID16_SVC_BATTERY ((uint16_t) 0x180F)
+#define UUID16_CHR_BATTERY_LEVEL ((uint16_t) 0x2A19)
+
+#define UUID16_SVC_DEVICE_INFORMATION ((uint16_t) 0x180A)
+#define UUID16_CHR_MODEL_NUMBER_STRING ((uint16_t) 0x2A24)
+#define UUID16_CHR_SERIAL_NUMBER_STRING ((uint16_t) 0x2A25)
+#define UUID16_CHR_FIRMWARE_REVISION_STRING ((uint16_t) 0x2A26)
+#define UUID16_CHR_HARDWARE_REVISION_STRING ((uint16_t) 0x2A27)
+#define UUID16_CHR_SOFTWARE_REVISION_STRING ((uint16_t) 0x2A28)
+#define UUID16_CHR_MANUFACTURER_NAME_STRING ((uint16_t) 0x2A29)
+
+#define SENSBOX_SERVICE_UUID "aba27100-143b-4b81-a444-edcd0000f020"
+#define NAVIGATION_CHARACTERISTIC_UUID "aba27100-143b-4b81-a444-edcd0000f022"
+#define MOVEMENT_CHARACTERISTIC_UUID "aba27100-143b-4b81-a444-edcd0000f023"
+#define GPS2_CHARACTERISTIC_UUID "aba27100-143b-4b81-a444-edcd0000f024"
+#define SYSTEM_CHARACTERISTIC_UUID "aba27100-143b-4b81-a444-edcd0000f025"
+
+/* (FLAA x MAX_TRACKING_OBJECTS + GNGGA + GNRMC + FLAU) x 80 symbols */
+#define BLE_FIFO_TX_SIZE 1024
+#define BLE_FIFO_RX_SIZE 256
+
+#define BLE_MAX_WRITE_CHUNK_SIZE 20
+
+extern IODev_ops_t ESP32_Bluetooth_ops;
+
+#endif /* NIMBLE_H */