mirror of
https://github.com/meshcore-dev/MeshCore.git
synced 2026-04-01 12:25:45 +00:00
Add recv_errors to CMD_GET_STATS STATS_TYPE_PACKETS response
Append uint32_t recv_errors (RadioLib receive/CRC errors) to packet stats binary frame. Frame size 26 -> 30 bytes. Update stats_binary_frames.md and Python/TypeScript parsing examples for backward compatibility (accept >=26).
This commit is contained in:
@@ -94,7 +94,7 @@ struct StatsRadio {
|
|||||||
|
|
||||||
## RESP_CODE_STATS + STATS_TYPE_PACKETS (24, 2)
|
## RESP_CODE_STATS + STATS_TYPE_PACKETS (24, 2)
|
||||||
|
|
||||||
**Total Frame Size:** 26 bytes
|
**Total Frame Size:** 26 bytes (legacy) or 30 bytes (includes `recv_errors`)
|
||||||
|
|
||||||
| Offset | Size | Type | Field Name | Description | Range/Notes |
|
| Offset | Size | Type | Field Name | Description | Range/Notes |
|
||||||
|--------|------|------|------------|-------------|-------------|
|
|--------|------|------|------------|-------------|-------------|
|
||||||
@@ -106,12 +106,14 @@ struct StatsRadio {
|
|||||||
| 14 | 4 | uint32_t | direct_tx | Packets sent via direct routing | 0 - 4,294,967,295 |
|
| 14 | 4 | uint32_t | direct_tx | Packets sent via direct routing | 0 - 4,294,967,295 |
|
||||||
| 18 | 4 | uint32_t | flood_rx | Packets received via flood routing | 0 - 4,294,967,295 |
|
| 18 | 4 | uint32_t | flood_rx | Packets received via flood routing | 0 - 4,294,967,295 |
|
||||||
| 22 | 4 | uint32_t | direct_rx | Packets received via direct routing | 0 - 4,294,967,295 |
|
| 22 | 4 | uint32_t | direct_rx | Packets received via direct routing | 0 - 4,294,967,295 |
|
||||||
|
| 26 | 4 | uint32_t | recv_errors | Receive/CRC errors (RadioLib); present only in 30-byte frame | 0 - 4,294,967,295 |
|
||||||
|
|
||||||
### Notes
|
### Notes
|
||||||
|
|
||||||
- Counters are cumulative from boot and may wrap.
|
- Counters are cumulative from boot and may wrap.
|
||||||
- `recv = flood_rx + direct_rx`
|
- `recv = flood_rx + direct_rx`
|
||||||
- `sent = flood_tx + direct_tx`
|
- `sent = flood_tx + direct_tx`
|
||||||
|
- Clients should accept frame length ≥ 26; if length ≥ 30, parse `recv_errors` at offset 26.
|
||||||
|
|
||||||
### Example Structure (C/C++)
|
### Example Structure (C/C++)
|
||||||
|
|
||||||
@@ -125,6 +127,7 @@ struct StatsPackets {
|
|||||||
uint32_t direct_tx;
|
uint32_t direct_tx;
|
||||||
uint32_t flood_rx;
|
uint32_t flood_rx;
|
||||||
uint32_t direct_rx;
|
uint32_t direct_rx;
|
||||||
|
uint32_t recv_errors; // present when frame size is 30
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -183,11 +186,12 @@ def parse_stats_radio(frame):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def parse_stats_packets(frame):
|
def parse_stats_packets(frame):
|
||||||
"""Parse RESP_CODE_STATS + STATS_TYPE_PACKETS frame (26 bytes)"""
|
"""Parse RESP_CODE_STATS + STATS_TYPE_PACKETS frame (26 or 30 bytes)"""
|
||||||
|
assert len(frame) >= 26, "STATS_TYPE_PACKETS frame too short"
|
||||||
response_code, stats_type, recv, sent, flood_tx, direct_tx, flood_rx, direct_rx = \
|
response_code, stats_type, recv, sent, flood_tx, direct_tx, flood_rx, direct_rx = \
|
||||||
struct.unpack('<B B I I I I I I', frame)
|
struct.unpack('<B B I I I I I I', frame[:26])
|
||||||
assert response_code == 24 and stats_type == 2, "Invalid response type"
|
assert response_code == 24 and stats_type == 2, "Invalid response type"
|
||||||
return {
|
result = {
|
||||||
'recv': recv,
|
'recv': recv,
|
||||||
'sent': sent,
|
'sent': sent,
|
||||||
'flood_tx': flood_tx,
|
'flood_tx': flood_tx,
|
||||||
@@ -195,6 +199,10 @@ def parse_stats_packets(frame):
|
|||||||
'flood_rx': flood_rx,
|
'flood_rx': flood_rx,
|
||||||
'direct_rx': direct_rx
|
'direct_rx': direct_rx
|
||||||
}
|
}
|
||||||
|
if len(frame) >= 30:
|
||||||
|
(recv_errors,) = struct.unpack('<I', frame[26:30])
|
||||||
|
result['recv_errors'] = recv_errors
|
||||||
|
return result
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -251,6 +259,7 @@ interface StatsPackets {
|
|||||||
direct_tx: number;
|
direct_tx: number;
|
||||||
flood_rx: number;
|
flood_rx: number;
|
||||||
direct_rx: number;
|
direct_rx: number;
|
||||||
|
recv_errors?: number; // present when frame is 30 bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStatsCore(buffer: ArrayBuffer): StatsCore {
|
function parseStatsCore(buffer: ArrayBuffer): StatsCore {
|
||||||
@@ -286,12 +295,15 @@ function parseStatsRadio(buffer: ArrayBuffer): StatsRadio {
|
|||||||
|
|
||||||
function parseStatsPackets(buffer: ArrayBuffer): StatsPackets {
|
function parseStatsPackets(buffer: ArrayBuffer): StatsPackets {
|
||||||
const view = new DataView(buffer);
|
const view = new DataView(buffer);
|
||||||
|
if (buffer.byteLength < 26) {
|
||||||
|
throw new Error('STATS_TYPE_PACKETS frame too short');
|
||||||
|
}
|
||||||
const response_code = view.getUint8(0);
|
const response_code = view.getUint8(0);
|
||||||
const stats_type = view.getUint8(1);
|
const stats_type = view.getUint8(1);
|
||||||
if (response_code !== 24 || stats_type !== 2) {
|
if (response_code !== 24 || stats_type !== 2) {
|
||||||
throw new Error('Invalid response type');
|
throw new Error('Invalid response type');
|
||||||
}
|
}
|
||||||
return {
|
const result: StatsPackets = {
|
||||||
recv: view.getUint32(2, true),
|
recv: view.getUint32(2, true),
|
||||||
sent: view.getUint32(6, true),
|
sent: view.getUint32(6, true),
|
||||||
flood_tx: view.getUint32(10, true),
|
flood_tx: view.getUint32(10, true),
|
||||||
@@ -299,6 +311,10 @@ function parseStatsPackets(buffer: ArrayBuffer): StatsPackets {
|
|||||||
flood_rx: view.getUint32(18, true),
|
flood_rx: view.getUint32(18, true),
|
||||||
direct_rx: view.getUint32(22, true)
|
direct_rx: view.getUint32(22, true)
|
||||||
};
|
};
|
||||||
|
if (buffer.byteLength >= 30) {
|
||||||
|
result.recv_errors = view.getUint32(26, true);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1688,12 +1688,14 @@ void MyMesh::handleCmdFrame(size_t len) {
|
|||||||
uint32_t n_sent_direct = getNumSentDirect();
|
uint32_t n_sent_direct = getNumSentDirect();
|
||||||
uint32_t n_recv_flood = getNumRecvFlood();
|
uint32_t n_recv_flood = getNumRecvFlood();
|
||||||
uint32_t n_recv_direct = getNumRecvDirect();
|
uint32_t n_recv_direct = getNumRecvDirect();
|
||||||
|
uint32_t n_recv_errors = radio_driver.getPacketsRecvErrors();
|
||||||
memcpy(&out_frame[i], &recv, 4); i += 4;
|
memcpy(&out_frame[i], &recv, 4); i += 4;
|
||||||
memcpy(&out_frame[i], &sent, 4); i += 4;
|
memcpy(&out_frame[i], &sent, 4); i += 4;
|
||||||
memcpy(&out_frame[i], &n_sent_flood, 4); i += 4;
|
memcpy(&out_frame[i], &n_sent_flood, 4); i += 4;
|
||||||
memcpy(&out_frame[i], &n_sent_direct, 4); i += 4;
|
memcpy(&out_frame[i], &n_sent_direct, 4); i += 4;
|
||||||
memcpy(&out_frame[i], &n_recv_flood, 4); i += 4;
|
memcpy(&out_frame[i], &n_recv_flood, 4); i += 4;
|
||||||
memcpy(&out_frame[i], &n_recv_direct, 4); i += 4;
|
memcpy(&out_frame[i], &n_recv_direct, 4); i += 4;
|
||||||
|
memcpy(&out_frame[i], &n_recv_errors, 4); i += 4;
|
||||||
_serial->writeFrame(out_frame, i);
|
_serial->writeFrame(out_frame, i);
|
||||||
} else {
|
} else {
|
||||||
writeErrFrame(ERR_CODE_ILLEGAL_ARG); // invalid stats sub-type
|
writeErrFrame(ERR_CODE_ILLEGAL_ARG); // invalid stats sub-type
|
||||||
|
|||||||
Reference in New Issue
Block a user