Skip to content

Commit 06a83c0

Browse files
authored
Merge pull request #1531 from agessaman/add-recv-errors-stats
Add recv_errors to CMD_GET_STATS STATS_TYPE_PACKETS response
2 parents cf7d95c + 019bbf7 commit 06a83c0

2 files changed

Lines changed: 23 additions & 5 deletions

File tree

docs/stats_binary_frames.md

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ struct StatsRadio {
9494

9595
## RESP_CODE_STATS + STATS_TYPE_PACKETS (24, 2)
9696

97-
**Total Frame Size:** 26 bytes
97+
**Total Frame Size:** 26 bytes (legacy) or 30 bytes (includes `recv_errors`)
9898

9999
| Offset | Size | Type | Field Name | Description | Range/Notes |
100100
|--------|------|------|------------|-------------|-------------|
@@ -106,12 +106,14 @@ struct StatsRadio {
106106
| 14 | 4 | uint32_t | direct_tx | Packets sent via direct routing | 0 - 4,294,967,295 |
107107
| 18 | 4 | uint32_t | flood_rx | Packets received via flood routing | 0 - 4,294,967,295 |
108108
| 22 | 4 | uint32_t | direct_rx | Packets received via direct routing | 0 - 4,294,967,295 |
109+
| 26 | 4 | uint32_t | recv_errors | Receive/CRC errors (RadioLib); present only in 30-byte frame | 0 - 4,294,967,295 |
109110

110111
### Notes
111112

112113
- Counters are cumulative from boot and may wrap.
113114
- `recv = flood_rx + direct_rx`
114115
- `sent = flood_tx + direct_tx`
116+
- Clients should accept frame length ≥ 26; if length ≥ 30, parse `recv_errors` at offset 26.
115117

116118
### Example Structure (C/C++)
117119

@@ -125,6 +127,7 @@ struct StatsPackets {
125127
uint32_t direct_tx;
126128
uint32_t flood_rx;
127129
uint32_t direct_rx;
130+
uint32_t recv_errors; // present when frame size is 30
128131
} __attribute__((packed));
129132
```
130133

@@ -183,18 +186,23 @@ def parse_stats_radio(frame):
183186
}
184187

185188
def parse_stats_packets(frame):
186-
"""Parse RESP_CODE_STATS + STATS_TYPE_PACKETS frame (26 bytes)"""
189+
"""Parse RESP_CODE_STATS + STATS_TYPE_PACKETS frame (26 or 30 bytes)"""
190+
assert len(frame) >= 26, "STATS_TYPE_PACKETS frame too short"
187191
response_code, stats_type, recv, sent, flood_tx, direct_tx, flood_rx, direct_rx = \
188-
struct.unpack('<B B I I I I I I', frame)
192+
struct.unpack('<B B I I I I I I', frame[:26])
189193
assert response_code == 24 and stats_type == 2, "Invalid response type"
190-
return {
194+
result = {
191195
'recv': recv,
192196
'sent': sent,
193197
'flood_tx': flood_tx,
194198
'direct_tx': direct_tx,
195199
'flood_rx': flood_rx,
196200
'direct_rx': direct_rx
197201
}
202+
if len(frame) >= 30:
203+
(recv_errors,) = struct.unpack('<I', frame[26:30])
204+
result['recv_errors'] = recv_errors
205+
return result
198206
```
199207

200208
---
@@ -251,6 +259,7 @@ interface StatsPackets {
251259
direct_tx: number;
252260
flood_rx: number;
253261
direct_rx: number;
262+
recv_errors?: number; // present when frame is 30 bytes
254263
}
255264

256265
function parseStatsCore(buffer: ArrayBuffer): StatsCore {
@@ -286,19 +295,26 @@ function parseStatsRadio(buffer: ArrayBuffer): StatsRadio {
286295

287296
function parseStatsPackets(buffer: ArrayBuffer): StatsPackets {
288297
const view = new DataView(buffer);
298+
if (buffer.byteLength < 26) {
299+
throw new Error('STATS_TYPE_PACKETS frame too short');
300+
}
289301
const response_code = view.getUint8(0);
290302
const stats_type = view.getUint8(1);
291303
if (response_code !== 24 || stats_type !== 2) {
292304
throw new Error('Invalid response type');
293305
}
294-
return {
306+
const result: StatsPackets = {
295307
recv: view.getUint32(2, true),
296308
sent: view.getUint32(6, true),
297309
flood_tx: view.getUint32(10, true),
298310
direct_tx: view.getUint32(14, true),
299311
flood_rx: view.getUint32(18, true),
300312
direct_rx: view.getUint32(22, true)
301313
};
314+
if (buffer.byteLength >= 30) {
315+
result.recv_errors = view.getUint32(26, true);
316+
}
317+
return result;
302318
}
303319
```
304320

examples/companion_radio/MyMesh.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1689,12 +1689,14 @@ void MyMesh::handleCmdFrame(size_t len) {
16891689
uint32_t n_sent_direct = getNumSentDirect();
16901690
uint32_t n_recv_flood = getNumRecvFlood();
16911691
uint32_t n_recv_direct = getNumRecvDirect();
1692+
uint32_t n_recv_errors = radio_driver.getPacketsRecvErrors();
16921693
memcpy(&out_frame[i], &recv, 4); i += 4;
16931694
memcpy(&out_frame[i], &sent, 4); i += 4;
16941695
memcpy(&out_frame[i], &n_sent_flood, 4); i += 4;
16951696
memcpy(&out_frame[i], &n_sent_direct, 4); i += 4;
16961697
memcpy(&out_frame[i], &n_recv_flood, 4); i += 4;
16971698
memcpy(&out_frame[i], &n_recv_direct, 4); i += 4;
1699+
memcpy(&out_frame[i], &n_recv_errors, 4); i += 4;
16981700
_serial->writeFrame(out_frame, i);
16991701
} else {
17001702
writeErrFrame(ERR_CODE_ILLEGAL_ARG); // invalid stats sub-type

0 commit comments

Comments
 (0)