mirror of
https://github.com/meshtastic/firmware.git
synced 2025-10-27 15:02:41 +00:00
NimbleBluetooth: switch to high-throughput BLE mode during config, then lower-power BLE mode for steady-state
This commit is contained in:
parent
a4785eed80
commit
cdb4d689b0
@ -27,14 +27,6 @@
|
|||||||
#include "nimble/nimble/host/include/host/ble_gap.h"
|
#include "nimble/nimble/host/include/host/ble_gap.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Debugging options: careful, they slow things down quite a bit!
|
|
||||||
// #define DEBUG_NIMBLE_ON_READ_TIMING // uncomment to time onRead duration
|
|
||||||
// #define DEBUG_NIMBLE_ON_WRITE_TIMING // uncomment to time onWrite duration
|
|
||||||
// #define DEBUG_NIMBLE_NOTIFY // uncomment to enable notify logging
|
|
||||||
|
|
||||||
#define NIMBLE_BLUETOOTH_TO_PHONE_QUEUE_SIZE 3
|
|
||||||
#define NIMBLE_BLUETOOTH_FROM_PHONE_QUEUE_SIZE 3
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
constexpr uint16_t kPreferredBleMtu = 517;
|
constexpr uint16_t kPreferredBleMtu = 517;
|
||||||
@ -43,12 +35,21 @@ constexpr uint16_t kPreferredBleTxTimeUs = (kPreferredBleTxOctets + 14) * 8;
|
|||||||
} // namespace
|
} // namespace
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Debugging options: careful, they slow things down quite a bit!
|
||||||
|
// #define DEBUG_NIMBLE_ON_READ_TIMING // uncomment to time onRead duration
|
||||||
|
// #define DEBUG_NIMBLE_ON_WRITE_TIMING // uncomment to time onWrite duration
|
||||||
|
// #define DEBUG_NIMBLE_NOTIFY // uncomment to enable notify logging
|
||||||
|
|
||||||
|
#define NIMBLE_BLUETOOTH_TO_PHONE_QUEUE_SIZE 3
|
||||||
|
#define NIMBLE_BLUETOOTH_FROM_PHONE_QUEUE_SIZE 3
|
||||||
|
|
||||||
NimBLECharacteristic *fromNumCharacteristic;
|
NimBLECharacteristic *fromNumCharacteristic;
|
||||||
NimBLECharacteristic *BatteryCharacteristic;
|
NimBLECharacteristic *BatteryCharacteristic;
|
||||||
NimBLECharacteristic *logRadioCharacteristic;
|
NimBLECharacteristic *logRadioCharacteristic;
|
||||||
NimBLEServer *bleServer;
|
NimBLEServer *bleServer;
|
||||||
|
|
||||||
static bool passkeyShowing;
|
static bool passkeyShowing;
|
||||||
|
static std::atomic<int32_t> nimbleBluetoothConnHandle{-1}; // actual handles are uint16_t, so -1 means "no connection"
|
||||||
|
|
||||||
class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread
|
class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread
|
||||||
{
|
{
|
||||||
@ -90,6 +91,32 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread
|
|||||||
return INT32_MAX;
|
return INT32_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void onConfigStart() override
|
||||||
|
{
|
||||||
|
LOG_INFO("BLE onConfigStart");
|
||||||
|
|
||||||
|
// Prefer high throughput during config/setup, at the cost of high power consumption (for a few seconds)
|
||||||
|
if (bleServer && isConnected()) {
|
||||||
|
int32_t conn_handle = nimbleBluetoothConnHandle.load();
|
||||||
|
if (conn_handle != -1) {
|
||||||
|
requestHighThroughputConnection(static_cast<uint16_t>(conn_handle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void onConfigComplete() override
|
||||||
|
{
|
||||||
|
LOG_INFO("BLE onConfigComplete");
|
||||||
|
|
||||||
|
// Switch to lower power consumption BLE connection params for steady-state use after config/setup is complete
|
||||||
|
if (bleServer && isConnected()) {
|
||||||
|
int32_t conn_handle = nimbleBluetoothConnHandle.load();
|
||||||
|
if (conn_handle != -1) {
|
||||||
|
requestLowerPowerConnection(static_cast<uint16_t>(conn_handle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool runOnceHasWorkToDo() { return runOnceHasWorkToPhone() || runOnceHasWorkFromPhone(); }
|
bool runOnceHasWorkToDo() { return runOnceHasWorkToPhone() || runOnceHasWorkFromPhone(); }
|
||||||
|
|
||||||
bool runOnceHasWorkToPhone() { return onReadCallbackIsWaitingForData || runOnceToPhoneCanPreloadNextPacket(); }
|
bool runOnceHasWorkToPhone() { return onReadCallbackIsWaitingForData || runOnceToPhoneCanPreloadNextPacket(); }
|
||||||
@ -236,6 +263,54 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread
|
|||||||
|
|
||||||
/// Check the current underlying physical link to see if the client is currently connected
|
/// Check the current underlying physical link to see if the client is currently connected
|
||||||
virtual bool checkIsConnected() { return bleServer && bleServer->getConnectedCount() > 0; }
|
virtual bool checkIsConnected() { return bleServer && bleServer->getConnectedCount() > 0; }
|
||||||
|
|
||||||
|
void requestHighThroughputConnection(uint16_t conn_handle)
|
||||||
|
{
|
||||||
|
/* Request a lower-latency, higher-throughput BLE connection.
|
||||||
|
|
||||||
|
This comes at the cost of higher power consumption, so we may want to only use this for initial setup, and then switch to
|
||||||
|
a slower mode.
|
||||||
|
|
||||||
|
See https://developer.apple.com/library/archive/qa/qa1931/_index.html for formulas to calculate values, iOS/macOS
|
||||||
|
constraints, and recommendations. (Android doesn't have specific constraints, but seems to be compatible with the Apple
|
||||||
|
recommendations.)
|
||||||
|
|
||||||
|
Selected settings:
|
||||||
|
minInterval (units of 1.25ms): 7.5ms = 6 (lower than the Apple recommended minimum, but allows faster when the client
|
||||||
|
supports it.)
|
||||||
|
maxInterval (units of 1.25ms): 15ms = 12
|
||||||
|
latency: 0 (don't allow peripheral to skip any connection events)
|
||||||
|
timeout (units of 10ms): 6 seconds = 600 (supervision timeout)
|
||||||
|
|
||||||
|
These are intentionally aggressive to prioritize speed over power consumption, but are only used for a few seconds at
|
||||||
|
setup. Not worth adjusting much.
|
||||||
|
*/
|
||||||
|
LOG_INFO("BLE requestHighThroughputConnection");
|
||||||
|
bleServer->updateConnParams(conn_handle, 6, 12, 0, 600);
|
||||||
|
}
|
||||||
|
|
||||||
|
void requestLowerPowerConnection(uint16_t conn_handle)
|
||||||
|
{
|
||||||
|
/* Request a lower power consumption (but higher latency, lower throughput) BLE connection.
|
||||||
|
|
||||||
|
This is suitable for steady-state operation after initial setup is complete.
|
||||||
|
|
||||||
|
See https://developer.apple.com/library/archive/qa/qa1931/_index.html for formulas to calculate values, iOS/macOS
|
||||||
|
constraints, and recommendations. (Android doesn't have specific constraints, but seems to be compatible with the Apple
|
||||||
|
recommendations.)
|
||||||
|
|
||||||
|
Selected settings:
|
||||||
|
minInterval (units of 1.25ms): 30ms = 24
|
||||||
|
maxInterval (units of 1.25ms): 50ms = 40
|
||||||
|
latency: 2 (allow peripheral to skip up to 2 consecutive connection events to save power)
|
||||||
|
timeout (units of 10ms): 6 seconds = 600 (supervision timeout)
|
||||||
|
|
||||||
|
There's an opportunity for tuning here if anyone wants to do some power measurements, but these should allow 10-20 packets
|
||||||
|
per second.
|
||||||
|
*/
|
||||||
|
LOG_INFO("BLE requestLowerPowerConnection");
|
||||||
|
bleServer->updateConnParams(conn_handle, 24, 40, 2, 600);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static BluetoothPhoneAPI *bluetoothPhoneAPI;
|
static BluetoothPhoneAPI *bluetoothPhoneAPI;
|
||||||
@ -489,11 +564,11 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks
|
|||||||
screen->endAlert();
|
screen->endAlert();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request high-throughput connection parameters for faster setup
|
// Store the connection handle for future use
|
||||||
#ifdef NIMBLE_TWO
|
#ifdef NIMBLE_TWO
|
||||||
requestHighThroughputConnection(connInfo);
|
nimbleBluetoothConnHandle = connInfo.getConnHandle();
|
||||||
#else
|
#else
|
||||||
requestHighThroughputConnection(desc);
|
nimbleBluetoothConnHandle = desc->conn_handle;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -561,6 +636,9 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks
|
|||||||
|
|
||||||
// Clear the last ToRadio packet buffer to avoid rejecting first packet from new connection
|
// Clear the last ToRadio packet buffer to avoid rejecting first packet from new connection
|
||||||
memset(lastToRadio, 0, sizeof(lastToRadio));
|
memset(lastToRadio, 0, sizeof(lastToRadio));
|
||||||
|
|
||||||
|
nimbleBluetoothConnHandle = -1; // -1 means "no connection"
|
||||||
|
|
||||||
#ifdef NIMBLE_TWO
|
#ifdef NIMBLE_TWO
|
||||||
// Restart Advertising
|
// Restart Advertising
|
||||||
ble->startAdvertising();
|
ble->startAdvertising();
|
||||||
@ -575,70 +653,6 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef NIMBLE_TWO
|
|
||||||
void requestHighThroughputConnection(NimBLEConnInfo &connInfo)
|
|
||||||
#else
|
|
||||||
void requestHighThroughputConnection(ble_gap_conn_desc *desc)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
/* Request a lower-latency, higher-throughput BLE connection.
|
|
||||||
|
|
||||||
This comes at the cost of higher power consumption, so we may want to only use this for initial setup, and then switch to
|
|
||||||
a slower mode.
|
|
||||||
|
|
||||||
See https://developer.apple.com/library/archive/qa/qa1931/_index.html for formulas to calculate values, iOS/macOS
|
|
||||||
constraints, and recommendations. (Android doesn't have specific constraints, but seems to be compatible with the Apple
|
|
||||||
recommendations.)
|
|
||||||
|
|
||||||
Selected settings:
|
|
||||||
minInterval (units of 1.25ms): 7.5ms = 6 (lower than the Apple recommended minimum, but allows faster when the client
|
|
||||||
supports it.)
|
|
||||||
maxInterval (units of 1.25ms): 15ms = 12
|
|
||||||
latency: 0 (don't allow peripheral to skip any connection events)
|
|
||||||
timeout (units of 10ms): 6 seconds = 600 (supervision timeout)
|
|
||||||
|
|
||||||
These are intentionally aggressive to prioritize speed over power consumption, but are only used for a few seconds at
|
|
||||||
setup. Not worth adjusting much.
|
|
||||||
*/
|
|
||||||
LOG_INFO("BLE requestHighThroughputConnection");
|
|
||||||
#ifdef NIMBLE_TWO
|
|
||||||
bleServer->updateConnParams(connInfo.getConnHandle(), 6, 12, 0, 600);
|
|
||||||
#else
|
|
||||||
bleServer->updateConnParams(desc->conn_handle, 6, 12, 0, 600);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef NIMBLE_TWO
|
|
||||||
void requestLowerPowerConnection(NimBLEConnInfo &connInfo)
|
|
||||||
#else
|
|
||||||
void requestLowerPowerConnection(ble_gap_conn_desc *desc)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
/* Request a lower power consumption (but higher latency, lower throughput) BLE connection.
|
|
||||||
|
|
||||||
This is suitable for steady-state operation after initial setup is complete.
|
|
||||||
|
|
||||||
See https://developer.apple.com/library/archive/qa/qa1931/_index.html for formulas to calculate values, iOS/macOS
|
|
||||||
constraints, and recommendations. (Android doesn't have specific constraints, but seems to be compatible with the Apple
|
|
||||||
recommendations.)
|
|
||||||
|
|
||||||
Selected settings:
|
|
||||||
minInterval (units of 1.25ms): 30ms = 24
|
|
||||||
maxInterval (units of 1.25ms): 50ms = 40
|
|
||||||
latency: 2 (allow peripheral to skip up to 2 consecutive connection events to save power)
|
|
||||||
timeout (units of 10ms): 6 seconds = 600 (supervision timeout)
|
|
||||||
|
|
||||||
There's an opportunity for tuning here if anyone wants to do some power measurements, but these should allow 10-20 packets
|
|
||||||
per second.
|
|
||||||
*/
|
|
||||||
LOG_INFO("BLE requestLowerPowerConnection");
|
|
||||||
#ifdef NIMBLE_TWO
|
|
||||||
bleServer->updateConnParams(connInfo.getConnHandle(), 24, 40, 2, 600);
|
|
||||||
#else
|
|
||||||
bleServer->updateConnParams(desc->conn_handle, 24, 40, 2, 600);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static NimbleBluetoothToRadioCallback *toRadioCallbacks;
|
static NimbleBluetoothToRadioCallback *toRadioCallbacks;
|
||||||
@ -879,4 +893,4 @@ void clearNVS()
|
|||||||
ESP.restart();
|
ESP.restart();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
Loading…
Reference in New Issue
Block a user