@@ -6,37 +6,53 @@ Binary frame structures for companion radio stats commands. All multi-byte integ
66
77| Command | Code | Description |
88| ---------| ------| -------------|
9- | ` CMD_GET_STATS_CORE ` | 56 | Get core device statistics |
10- | ` CMD_GET_STATS_RADIO ` | 57 | Get radio statistics |
11- | ` CMD_GET_STATS_PACKETS ` | 58 | Get packet statistics |
9+ | ` CMD_GET_STATS ` | 56 | Get statistics (2-byte command: code + sub-type) |
10+
11+ ### Stats Sub-Types
12+
13+ The ` CMD_GET_STATS ` command uses a 2-byte frame structure:
14+ - ** Byte 0:** ` CMD_GET_STATS ` (56)
15+ - ** Byte 1:** Stats sub-type:
16+ - ` STATS_TYPE_CORE ` (0) - Get core device statistics
17+ - ` STATS_TYPE_RADIO ` (1) - Get radio statistics
18+ - ` STATS_TYPE_PACKETS ` (2) - Get packet statistics
1219
1320## Response Codes
1421
1522| Response | Code | Description |
1623| ----------| ------| -------------|
17- | ` RESP_CODE_STATS_CORE ` | 24 | Core stats response |
18- | ` RESP_CODE_STATS_RADIO ` | 25 | Radio stats response |
19- | ` RESP_CODE_STATS_PACKETS ` | 26 | Packet stats response |
24+ | ` RESP_CODE_STATS ` | 24 | Statistics response (2-byte response: code + sub-type) |
25+
26+ ### Stats Response Sub-Types
27+
28+ The ` RESP_CODE_STATS ` response uses a 2-byte header structure:
29+ - ** Byte 0:** ` RESP_CODE_STATS ` (24)
30+ - ** Byte 1:** Stats sub-type (matches command sub-type):
31+ - ` STATS_TYPE_CORE ` (0) - Core device statistics response
32+ - ` STATS_TYPE_RADIO ` (1) - Radio statistics response
33+ - ` STATS_TYPE_PACKETS ` (2) - Packet statistics response
2034
2135---
2236
23- ## RESP_CODE_STATS_CORE (24)
37+ ## RESP_CODE_STATS + STATS_TYPE_CORE (24, 0 )
2438
25- ** Total Frame Size:** 10 bytes
39+ ** Total Frame Size:** 11 bytes
2640
2741| Offset | Size | Type | Field Name | Description | Range/Notes |
2842| --------| ------| ------| ------------| -------------| -------------|
2943| 0 | 1 | uint8_t | response_code | Always ` 0x18 ` (24) | - |
30- | 1 | 2 | uint16_t | battery_mv | Battery voltage in millivolts | 0 - 65,535 |
31- | 3 | 4 | uint32_t | uptime_secs | Device uptime in seconds | 0 - 4,294,967,295 |
32- | 7 | 2 | uint16_t | errors | Error flags bitmask | - |
33- | 9 | 1 | uint8_t | queue_len | Outbound packet queue length | 0 - 255 |
44+ | 1 | 1 | uint8_t | stats_type | Always ` 0x00 ` (STATS_TYPE_CORE) | - |
45+ | 2 | 2 | uint16_t | battery_mv | Battery voltage in millivolts | 0 - 65,535 |
46+ | 4 | 4 | uint32_t | uptime_secs | Device uptime in seconds | 0 - 4,294,967,295 |
47+ | 8 | 2 | uint16_t | errors | Error flags bitmask | - |
48+ | 10 | 1 | uint8_t | queue_len | Outbound packet queue length | 0 - 255 |
3449
3550### Example Structure (C/C++)
3651
3752``` c
3853struct StatsCore {
3954 uint8_t response_code; // 0x18
55+ uint8_t stats_type; // 0x00 (STATS_TYPE_CORE)
4056 uint16_t battery_mv;
4157 uint32_t uptime_secs;
4258 uint16_t errors;
@@ -46,24 +62,26 @@ struct StatsCore {
4662
4763---
4864
49- ## RESP_CODE_STATS_RADIO (25 )
65+ ## RESP_CODE_STATS + STATS_TYPE_RADIO (24, 1 )
5066
51- ** Total Frame Size:** 13 bytes
67+ ** Total Frame Size:** 14 bytes
5268
5369| Offset | Size | Type | Field Name | Description | Range/Notes |
5470| --------| ------| ------| ------------| -------------| -------------|
55- | 0 | 1 | uint8_t | response_code | Always ` 0x19 ` (25) | - |
56- | 1 | 2 | int16_t | noise_floor | Radio noise floor in dBm | -140 to +10 |
57- | 3 | 1 | int8_t | last_rssi | Last received signal strength in dBm | -128 to +127 |
58- | 4 | 1 | int8_t | last_snr | SNR scaled by 4 | Divide by 4.0 for dB |
59- | 5 | 4 | uint32_t | tx_air_secs | Cumulative transmit airtime in seconds | 0 - 4,294,967,295 |
60- | 9 | 4 | uint32_t | rx_air_secs | Cumulative receive airtime in seconds | 0 - 4,294,967,295 |
71+ | 0 | 1 | uint8_t | response_code | Always ` 0x18 ` (24) | - |
72+ | 1 | 1 | uint8_t | stats_type | Always ` 0x01 ` (STATS_TYPE_RADIO) | - |
73+ | 2 | 2 | int16_t | noise_floor | Radio noise floor in dBm | -140 to +10 |
74+ | 4 | 1 | int8_t | last_rssi | Last received signal strength in dBm | -128 to +127 |
75+ | 5 | 1 | int8_t | last_snr | SNR scaled by 4 | Divide by 4.0 for dB |
76+ | 6 | 4 | uint32_t | tx_air_secs | Cumulative transmit airtime in seconds | 0 - 4,294,967,295 |
77+ | 10 | 4 | uint32_t | rx_air_secs | Cumulative receive airtime in seconds | 0 - 4,294,967,295 |
6178
6279### Example Structure (C/C++)
6380
6481``` c
6582struct StatsRadio {
66- uint8_t response_code; // 0x19
83+ uint8_t response_code; // 0x18
84+ uint8_t stats_type; // 0x01 (STATS_TYPE_RADIO)
6785 int16_t noise_floor;
6886 int8_t last_rssi;
6987 int8_t last_snr; // Divide by 4.0 to get actual SNR in dB
@@ -74,19 +92,20 @@ struct StatsRadio {
7492
7593---
7694
77- ## RESP_CODE_STATS_PACKETS (26 )
95+ ## RESP_CODE_STATS + STATS_TYPE_PACKETS (24, 2 )
7896
79- ** Total Frame Size:** 25 bytes
97+ ** Total Frame Size:** 26 bytes
8098
8199| Offset | Size | Type | Field Name | Description | Range/Notes |
82100| --------| ------| ------| ------------| -------------| -------------|
83- | 0 | 1 | uint8_t | response_code | Always ` 0x1A ` (26) | - |
84- | 1 | 4 | uint32_t | recv | Total packets received | 0 - 4,294,967,295 |
85- | 5 | 4 | uint32_t | sent | Total packets sent | 0 - 4,294,967,295 |
86- | 9 | 4 | uint32_t | flood_tx | Packets sent via flood routing | 0 - 4,294,967,295 |
87- | 13 | 4 | uint32_t | direct_tx | Packets sent via direct routing | 0 - 4,294,967,295 |
88- | 17 | 4 | uint32_t | flood_rx | Packets received via flood routing | 0 - 4,294,967,295 |
89- | 21 | 4 | uint32_t | direct_rx | Packets received via direct routing | 0 - 4,294,967,295 |
101+ | 0 | 1 | uint8_t | response_code | Always ` 0x18 ` (24) | - |
102+ | 1 | 1 | uint8_t | stats_type | Always ` 0x02 ` (STATS_TYPE_PACKETS) | - |
103+ | 2 | 4 | uint32_t | recv | Total packets received | 0 - 4,294,967,295 |
104+ | 6 | 4 | uint32_t | sent | Total packets sent | 0 - 4,294,967,295 |
105+ | 10 | 4 | uint32_t | flood_tx | Packets sent via flood routing | 0 - 4,294,967,295 |
106+ | 14 | 4 | uint32_t | direct_tx | Packets sent via direct routing | 0 - 4,294,967,295 |
107+ | 18 | 4 | uint32_t | flood_rx | Packets received via flood routing | 0 - 4,294,967,295 |
108+ | 22 | 4 | uint32_t | direct_rx | Packets received via direct routing | 0 - 4,294,967,295 |
90109
91110### Notes
92111
@@ -98,7 +117,8 @@ struct StatsRadio {
98117
99118``` c
100119struct StatsPackets {
101- uint8_t response_code; // 0x1A
120+ uint8_t response_code; // 0x18
121+ uint8_t stats_type; // 0x02 (STATS_TYPE_PACKETS)
102122 uint32_t recv;
103123 uint32_t sent;
104124 uint32_t flood_tx;
@@ -110,15 +130,38 @@ struct StatsPackets {
110130
111131---
112132
113- ## Usage Example (Python)
133+ ## Command Usage Example (Python)
134+
135+ ``` python
136+ # Send CMD_GET_STATS command
137+ def send_get_stats_core (serial_interface ):
138+ """ Send command to get core stats"""
139+ cmd = bytes ([56 , 0 ]) # CMD_GET_STATS (56) + STATS_TYPE_CORE (0)
140+ serial_interface.write(cmd)
141+
142+ def send_get_stats_radio (serial_interface ):
143+ """ Send command to get radio stats"""
144+ cmd = bytes ([56 , 1 ]) # CMD_GET_STATS (56) + STATS_TYPE_RADIO (1)
145+ serial_interface.write(cmd)
146+
147+ def send_get_stats_packets (serial_interface ):
148+ """ Send command to get packet stats"""
149+ cmd = bytes ([56 , 2 ]) # CMD_GET_STATS (56) + STATS_TYPE_PACKETS (2)
150+ serial_interface.write(cmd)
151+ ```
152+
153+ ---
154+
155+ ## Response Parsing Example (Python)
114156
115157``` python
116158import struct
117159
118160def parse_stats_core (frame ):
119- """ Parse RESP_CODE_STATS_CORE frame (10 bytes)"""
120- response_code, battery_mv, uptime_secs, errors, queue_len = \
121- struct.unpack(' <B H I H B' , frame)
161+ """ Parse RESP_CODE_STATS + STATS_TYPE_CORE frame (11 bytes)"""
162+ response_code, stats_type, battery_mv, uptime_secs, errors, queue_len = \
163+ struct.unpack(' <B B H I H B' , frame)
164+ assert response_code == 24 and stats_type == 0 , " Invalid response type"
122165 return {
123166 ' battery_mv' : battery_mv,
124167 ' uptime_secs' : uptime_secs,
@@ -127,9 +170,10 @@ def parse_stats_core(frame):
127170 }
128171
129172def parse_stats_radio (frame ):
130- """ Parse RESP_CODE_STATS_RADIO frame (13 bytes)"""
131- response_code, noise_floor, last_rssi, last_snr, tx_air_secs, rx_air_secs = \
132- struct.unpack(' <B h b b I I' , frame)
173+ """ Parse RESP_CODE_STATS + STATS_TYPE_RADIO frame (14 bytes)"""
174+ response_code, stats_type, noise_floor, last_rssi, last_snr, tx_air_secs, rx_air_secs = \
175+ struct.unpack(' <B B h b b I I' , frame)
176+ assert response_code == 24 and stats_type == 1 , " Invalid response type"
133177 return {
134178 ' noise_floor' : noise_floor,
135179 ' last_rssi' : last_rssi,
@@ -139,9 +183,10 @@ def parse_stats_radio(frame):
139183 }
140184
141185def parse_stats_packets (frame ):
142- """ Parse RESP_CODE_STATS_PACKETS frame (25 bytes)"""
143- response_code, recv, sent, flood_tx, direct_tx, flood_rx, direct_rx = \
144- struct.unpack(' <B I I I I I I' , frame)
186+ """ Parse RESP_CODE_STATS + STATS_TYPE_PACKETS frame (26 bytes)"""
187+ 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)
189+ assert response_code == 24 and stats_type == 2 , " Invalid response type"
145190 return {
146191 ' recv' : recv,
147192 ' sent' : sent,
@@ -154,7 +199,34 @@ def parse_stats_packets(frame):
154199
155200---
156201
157- ## Usage Example (JavaScript/TypeScript)
202+ ## Command Usage Example (JavaScript/TypeScript)
203+
204+ ``` typescript
205+ // Send CMD_GET_STATS command
206+ const CMD_GET_STATS = 56 ;
207+ const STATS_TYPE_CORE = 0 ;
208+ const STATS_TYPE_RADIO = 1 ;
209+ const STATS_TYPE_PACKETS = 2 ;
210+
211+ function sendGetStatsCore(serialInterface : SerialPort ): void {
212+ const cmd = new Uint8Array ([CMD_GET_STATS , STATS_TYPE_CORE ]);
213+ serialInterface .write (cmd );
214+ }
215+
216+ function sendGetStatsRadio(serialInterface : SerialPort ): void {
217+ const cmd = new Uint8Array ([CMD_GET_STATS , STATS_TYPE_RADIO ]);
218+ serialInterface .write (cmd );
219+ }
220+
221+ function sendGetStatsPackets(serialInterface : SerialPort ): void {
222+ const cmd = new Uint8Array ([CMD_GET_STATS , STATS_TYPE_PACKETS ]);
223+ serialInterface .write (cmd );
224+ }
225+ ```
226+
227+ ---
228+
229+ ## Response Parsing Example (JavaScript/TypeScript)
158230
159231``` typescript
160232interface StatsCore {
@@ -183,34 +255,49 @@ interface StatsPackets {
183255
184256function parseStatsCore(buffer : ArrayBuffer ): StatsCore {
185257 const view = new DataView (buffer );
258+ const response_code = view .getUint8 (0 );
259+ const stats_type = view .getUint8 (1 );
260+ if (response_code !== 24 || stats_type !== 0 ) {
261+ throw new Error (' Invalid response type' );
262+ }
186263 return {
187- battery_mv: view .getUint16 (1 , true ),
188- uptime_secs: view .getUint32 (3 , true ),
189- errors: view .getUint16 (7 , true ),
190- queue_len: view .getUint8 (9 )
264+ battery_mv: view .getUint16 (2 , true ),
265+ uptime_secs: view .getUint32 (4 , true ),
266+ errors: view .getUint16 (8 , true ),
267+ queue_len: view .getUint8 (10 )
191268 };
192269}
193270
194271function parseStatsRadio(buffer : ArrayBuffer ): StatsRadio {
195272 const view = new DataView (buffer );
273+ const response_code = view .getUint8 (0 );
274+ const stats_type = view .getUint8 (1 );
275+ if (response_code !== 24 || stats_type !== 1 ) {
276+ throw new Error (' Invalid response type' );
277+ }
196278 return {
197- noise_floor: view .getInt16 (1 , true ),
198- last_rssi: view .getInt8 (3 ),
199- last_snr: view .getInt8 (4 ) / 4.0 , // Unscale SNR
200- tx_air_secs: view .getUint32 (5 , true ),
201- rx_air_secs: view .getUint32 (9 , true )
279+ noise_floor: view .getInt16 (2 , true ),
280+ last_rssi: view .getInt8 (4 ),
281+ last_snr: view .getInt8 (5 ) / 4.0 , // Unscale SNR
282+ tx_air_secs: view .getUint32 (6 , true ),
283+ rx_air_secs: view .getUint32 (10 , true )
202284 };
203285}
204286
205287function parseStatsPackets(buffer : ArrayBuffer ): StatsPackets {
206288 const view = new DataView (buffer );
289+ const response_code = view .getUint8 (0 );
290+ const stats_type = view .getUint8 (1 );
291+ if (response_code !== 24 || stats_type !== 2 ) {
292+ throw new Error (' Invalid response type' );
293+ }
207294 return {
208- recv: view .getUint32 (1 , true ),
209- sent: view .getUint32 (5 , true ),
210- flood_tx: view .getUint32 (9 , true ),
211- direct_tx: view .getUint32 (13 , true ),
212- flood_rx: view .getUint32 (17 , true ),
213- direct_rx: view .getUint32 (21 , true )
295+ recv: view .getUint32 (2 , true ),
296+ sent: view .getUint32 (6 , true ),
297+ flood_tx: view .getUint32 (10 , true ),
298+ direct_tx: view .getUint32 (14 , true ),
299+ flood_rx: view .getUint32 (18 , true ),
300+ direct_rx: view .getUint32 (22 , true )
214301 };
215302}
216303```
0 commit comments