Skip to content

Commit 3600e49

Browse files
committed
unify nRF and ESP32 BLE interface implementations - Phase 1
1 parent 90d1e87 commit 3600e49

3 files changed

Lines changed: 414 additions & 138 deletions

File tree

src/helpers/SerialBLECommon.h

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
#pragma once
2+
3+
#include "BaseSerialInterface.h"
4+
#include <string.h>
5+
6+
// Units: interval=1.25ms, timeout=10ms
7+
#define BLE_MIN_CONN_INTERVAL 12
8+
#define BLE_MAX_CONN_INTERVAL 36
9+
#define BLE_SLAVE_LATENCY 3
10+
#define BLE_CONN_SUP_TIMEOUT 500
11+
12+
// Sync mode: higher throughput (min 15ms for Apple compliance)
13+
#define BLE_SYNC_MIN_CONN_INTERVAL 12
14+
#define BLE_SYNC_MAX_CONN_INTERVAL 24
15+
#define BLE_SYNC_SLAVE_LATENCY 0
16+
#define BLE_SYNC_CONN_SUP_TIMEOUT 300
17+
18+
#define BLE_SYNC_INACTIVITY_TIMEOUT_MS 5000
19+
20+
// Units: advertising interval=0.625ms
21+
// ESP randomly chooses between 32 and 338
22+
// max seems slow, but we can wait a few seconds for it to connect, worth the battery
23+
#define BLE_ADV_INTERVAL_MIN 32
24+
#define BLE_ADV_INTERVAL_MAX 338
25+
#define BLE_ADV_FAST_TIMEOUT 30
26+
27+
#define BLE_HEALTH_CHECK_INTERVAL 10000
28+
#define BLE_RETRY_THROTTLE_MS 250
29+
#define BLE_MIN_SEND_INTERVAL_MS 8
30+
#define BLE_RX_DRAIN_BUF_SIZE 32
31+
32+
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
33+
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
34+
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
35+
36+
#define BLE_SYNC_FRAME_SIZE_THRESHOLD 40
37+
#define BLE_SYNC_LARGE_FRAME_COUNT_THRESHOLD 3
38+
#define BLE_SYNC_LARGE_FRAME_WINDOW_MS 1500
39+
40+
#define BLE_CONN_HANDLE_INVALID 0xFFFF
41+
42+
// BLE specific MTU target, ESP can do more, but we don't need it, so stay at max nRF52
43+
#define BLE_MAX_MTU 247
44+
45+
// ESP needs this to set manually, nRF52 handles it automatically
46+
#define BLE_DLE_MAX_TX_OCTETS 251
47+
#define BLE_DLE_MAX_TX_TIME_US 2120
48+
49+
// nRF only, NimBLE cannot set TX power on ESP, so ESP is fixed 0dBm
50+
#ifndef BLE_TX_POWER
51+
#define BLE_TX_POWER 4
52+
#endif
53+
54+
struct SerialBLEFrame {
55+
uint8_t len;
56+
uint8_t buf[MAX_FRAME_SIZE];
57+
};
58+
59+
// 12 is adequate for most use cases
60+
#define FRAME_QUEUE_SIZE 12
61+
62+
struct CircularFrameQueue {
63+
SerialBLEFrame frames[FRAME_QUEUE_SIZE];
64+
uint8_t head;
65+
uint8_t tail;
66+
uint8_t count;
67+
68+
void init() {
69+
head = 0;
70+
tail = 0;
71+
count = 0;
72+
}
73+
74+
bool isEmpty() const {
75+
return count == 0;
76+
}
77+
78+
bool isFull() const {
79+
return count >= FRAME_QUEUE_SIZE;
80+
}
81+
82+
SerialBLEFrame* peekFront() {
83+
if (isEmpty()) return nullptr;
84+
return &frames[tail];
85+
}
86+
87+
SerialBLEFrame* getWriteSlot() {
88+
if (isFull()) return nullptr;
89+
return &frames[head];
90+
}
91+
92+
void push() {
93+
if (!isFull()) {
94+
head = (head + 1) % FRAME_QUEUE_SIZE;
95+
count++;
96+
}
97+
}
98+
99+
void pop() {
100+
if (!isEmpty()) {
101+
tail = (tail + 1) % FRAME_QUEUE_SIZE;
102+
count--;
103+
}
104+
}
105+
106+
uint8_t size() const {
107+
return count;
108+
}
109+
};
110+
111+
#if BLE_DEBUG_LOGGING && ARDUINO
112+
#include <Arduino.h>
113+
#define BLE_DEBUG_PRINT(F, ...) Serial.printf("BLE: " F, ##__VA_ARGS__)
114+
#define BLE_DEBUG_PRINTLN(F, ...) Serial.printf("BLE: " F "\n", ##__VA_ARGS__)
115+
#else
116+
#define BLE_DEBUG_PRINT(...) {}
117+
#define BLE_DEBUG_PRINTLN(...) {}
118+
#endif
119+
120+
class SerialBLEInterfaceBase : public BaseSerialInterface {
121+
protected:
122+
bool _isEnabled;
123+
bool _isDeviceConnected;
124+
uint16_t _conn_handle;
125+
unsigned long _last_health_check;
126+
unsigned long _last_retry_attempt;
127+
unsigned long _last_send_time;
128+
unsigned long _last_activity_time;
129+
bool _sync_mode;
130+
bool _conn_param_update_pending;
131+
uint8_t _large_frame_count;
132+
unsigned long _large_frame_window_start;
133+
134+
CircularFrameQueue send_queue;
135+
CircularFrameQueue recv_queue;
136+
137+
void clearTransferState() {
138+
send_queue.init();
139+
recv_queue.init();
140+
_last_retry_attempt = 0;
141+
_last_send_time = 0;
142+
_last_activity_time = 0;
143+
_sync_mode = false;
144+
_conn_param_update_pending = false;
145+
_large_frame_count = 0;
146+
_large_frame_window_start = 0;
147+
}
148+
149+
void popSendQueue() {
150+
send_queue.pop();
151+
}
152+
153+
void popRecvQueue() {
154+
recv_queue.pop();
155+
}
156+
157+
bool noteFrameActivity(unsigned long now, size_t frame_len) {
158+
if (frame_len < BLE_SYNC_FRAME_SIZE_THRESHOLD) {
159+
return false;
160+
}
161+
162+
_last_activity_time = now;
163+
164+
if (_large_frame_window_start == 0 ||
165+
(now - _large_frame_window_start) > BLE_SYNC_LARGE_FRAME_WINDOW_MS) {
166+
_large_frame_count = 1;
167+
_large_frame_window_start = now;
168+
} else if (_large_frame_count < 255) {
169+
_large_frame_count++;
170+
}
171+
172+
return (!_sync_mode && _large_frame_count >= BLE_SYNC_LARGE_FRAME_COUNT_THRESHOLD);
173+
}
174+
175+
bool isWriteBusyCommon() const {
176+
return send_queue.size() >= (FRAME_QUEUE_SIZE * 2 / 3);
177+
}
178+
179+
void initCommonState() {
180+
_isEnabled = false;
181+
_isDeviceConnected = false;
182+
_conn_handle = BLE_CONN_HANDLE_INVALID;
183+
_last_health_check = 0;
184+
_last_retry_attempt = 0;
185+
_last_send_time = 0;
186+
_last_activity_time = 0;
187+
_sync_mode = false;
188+
_conn_param_update_pending = false;
189+
_large_frame_count = 0;
190+
_large_frame_window_start = 0;
191+
send_queue.init();
192+
recv_queue.init();
193+
}
194+
};
195+

0 commit comments

Comments
 (0)