Skip to content

Commit c1041af

Browse files
author
Scott Powell
committed
Merge branch 'dev'
2 parents c6b469f + 365cb89 commit c1041af

File tree

79 files changed

+812
-783
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+812
-783
lines changed

docs/packet_structure.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
# Packet Structure
22

3-
| Field | Size (bytes) | Description |
4-
|----------|----------------------------------|-----------------------------------------------------------|
5-
| header | 1 | Contains routing type, payload type, and payload version. |
6-
| path_len | 1 | Length of the path field in bytes. |
7-
| path | up to 64 (`MAX_PATH_SIZE`) | Stores the routing path if applicable. |
8-
| payload | up to 184 (`MAX_PACKET_PAYLOAD`) | The actual data being transmitted. |
3+
| Field | Size (bytes) | Description |
4+
|-----------------|----------------------------------|-----------------------------------------------------------|
5+
| header | 1 | Contains routing type, payload type, and payload version. |
6+
| transport_codes | 4 (optional) | 2x 16-bit transport codes (if ROUTE_TYPE_TRANSPORT_*) |
7+
| path_len | 1 | Length of the path field in bytes. |
8+
| path | up to 64 (`MAX_PATH_SIZE`) | Stores the routing path if applicable. |
9+
| payload | up to 184 (`MAX_PACKET_PAYLOAD`) | The actual data being transmitted. |
910

1011
Note: see the [payloads doc](./payloads.md) for more information about the content of payload.
1112

@@ -42,6 +43,7 @@ bit 0 means the lowest bit (1s place)
4243
| `0x07` | `PAYLOAD_TYPE_ANON_REQ` | Anonymous request. |
4344
| `0x08` | `PAYLOAD_TYPE_PATH` | Returned path. |
4445
| `0x09` | `PAYLOAD_TYPE_TRACE` | trace a path, collecting SNI for each hop. |
46+
| `0x0A` | `PAYLOAD_TYPE_MULTIPART` | packet is part of a sequence of packets. |
4547
| `0x0F` | `PAYLOAD_TYPE_RAW_CUSTOM` | Custom packet (raw bytes, custom encryption). |
4648

4749
## Payload Version Values

docs/payloads.md

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,16 @@ Inside of each [meshcore packet](./packet_structure.md) is a payload, identified
1010
* Anonymous request.
1111
* Group text message (unverified).
1212
* Group datagram (unverified).
13+
* Multi-part packet
1314
* Custom packet (raw bytes, custom encryption).
1415

15-
This document defines the structure of each of these payload types
16+
This document defines the structure of each of these payload types.
17+
18+
NOTE: all 16 and 32-bit integer fields are Little Endian.
1619

1720
## Important concepts:
1821

19-
* Node/channel hash: the first byte of the node or channel's public key
22+
* Node hash: the first byte of the node's public key
2023

2124
# Node advertisement
2225
This kind of payload notifies receivers that a node exists, and gives information about the node
@@ -33,10 +36,10 @@ Appdata
3336
| Field | Size (bytes) | Description |
3437
|---------------|-----------------|-------------------------------------------------------|
3538
| flags | 1 | specifies which of the fields are present, see below |
36-
| latitude | 4 | decimal latitude multiplied by 1000000, integer |
37-
| longitude | 4 | decimal longitude multiplied by 1000000, integer |
38-
| feature 1 | 2 | reserved for future use |
39-
| feature 2 | 2 | reserved for future use |
39+
| latitude | 4 (optional) | decimal latitude multiplied by 1000000, integer |
40+
| longitude | 4 (optional) | decimal longitude multiplied by 1000000, integer |
41+
| feature 1 | 2 (optional) | reserved for future use |
42+
| feature 2 | 2 (optional) | reserved for future use |
4043
| name | rest of appdata | name of the node |
4144

4245
Appdata Flags
@@ -46,6 +49,7 @@ Appdata Flags
4649
| `0x01` | is chat node | advert is for a chat node |
4750
| `0x02` | is repeater | advert is for a repeater |
4851
| `0x03` | is room server | advert is for a room server |
52+
| `0x04` | is sensor | advert is for a sensor server |
4953
| `0x10` | has location | appdata contains lat/long information |
5054
| `0x20` | has feature 1 | Reserved for future use. |
5155
| `0x40` | has feature 2 | Reserved for future use. |
@@ -92,13 +96,15 @@ Returned path messages provide a description of the route a packet took from the
9296

9397
Request type
9498

95-
| Value | Name | Description |
96-
|--------|--------------------|---------------------------------------|
97-
| `0x01` | get status | get status of repeater or room server |
98-
| `0x02` | keepalive | TODO |
99-
| `0x03` | get telemetry data | TODO |
99+
| Value | Name | Description |
100+
|--------|----------------------|---------------------------------------|
101+
| `0x01` | get stats | get stats of repeater or room server |
102+
| `0x02` | keepalive | (deprecated) |
103+
| `0x03` | get telemetry data | TODO |
104+
| `0x04` | get min,max,avg data | sensor nodes - get min, max, average for given time span |
105+
| `0x05` | get access list | get node's approved access list |
100106

101-
### Get status
107+
### Get stats
102108

103109
Gets information about the node, possibly including the following:
104110

@@ -121,10 +127,6 @@ Gets information about the node, possibly including the following:
121127
* Number posted (?)
122128
* Number of post pushes (?)
123129

124-
### Keepalive
125-
126-
No-op request.
127-
128130
### Get telemetry data
129131

130132
Request data about sensors on the node, including battery level.
@@ -138,19 +140,19 @@ Request data about sensors on the node, including battery level.
138140

139141
## Plain text message
140142

141-
| Field | Size (bytes) | Description |
142-
|--------------|-----------------|--------------------------------------------------------------|
143-
| timestamp | 4 | send time (unix timestamp) |
144-
| flags + TODO | 1 | first six bits are flags (see below), last two bits are TODO |
145-
| message | rest of payload | the message content, see next table |
143+
| Field | Size (bytes) | Description |
144+
|-----------------|-----------------|--------------------------------------------------------------|
145+
| timestamp | 4 | send time (unix timestamp) |
146+
| flags + attempt | 1 | upper six bits are flags (see below), lower two bits are attempt number (0..3) |
147+
| message | rest of payload | the message content, see next table |
146148

147149
Flags
148150

149151
| Value | Description | Message content |
150152
|--------|---------------------------|------------------------------------------------------------|
151153
| `0x00` | plain text message | the plain text of the message |
152154
| `0x01` | CLI command | the command text of the message |
153-
| `0x02` | signed plain text message | two bytes of sender prefix, followed by plain text message |
155+
| `0x02` | signed plain text message | first four bytes is sender pubkey prefix, followed by plain text message |
154156

155157
# Anonymous request
156158

@@ -166,14 +168,14 @@ Plaintext message
166168
| Field | Size (bytes) | Description |
167169
|----------------|-----------------|-------------------------------------------------------------------------------|
168170
| timestamp | 4 | send time (unix timestamp) |
169-
| sync timestamp | 4 | for room server, otherwise absent: sender's "sync messages SINCE x" timestamp |
171+
| sync timestamp | 4 | NOTE: room server only! - sender's "sync messages SINCE x" timestamp |
170172
| password | rest of message | password for repeater/room |
171173

172174
# Group text message / datagram
173175

174176
| Field | Size (bytes) | Description |
175177
|--------------|-----------------|--------------------------------------------|
176-
| channel hash | 1 | the first byte of the channel's public key |
178+
| channel hash | 1 | first byte of SHA256 of channel's shared key |
177179
| cipher MAC | 2 | MAC for encrypted data in next field |
178180
| ciphertext | rest of payload | encrypted message, see below for details |
179181

examples/companion_radio/DataStore.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
154154
file.read((uint8_t *)&_prefs.freq, sizeof(_prefs.freq)); // 56
155155
file.read((uint8_t *)&_prefs.sf, sizeof(_prefs.sf)); // 60
156156
file.read((uint8_t *)&_prefs.cr, sizeof(_prefs.cr)); // 61
157-
file.read((uint8_t *)&_prefs.reserved1, sizeof(_prefs.reserved1)); // 62
157+
file.read(pad, 1); // 62
158158
file.read((uint8_t *)&_prefs.manual_add_contacts, sizeof(_prefs.manual_add_contacts)); // 63
159159
file.read((uint8_t *)&_prefs.bw, sizeof(_prefs.bw)); // 64
160160
file.read((uint8_t *)&_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68
@@ -163,7 +163,8 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
163163
file.read((uint8_t *)&_prefs.telemetry_mode_env, sizeof(_prefs.telemetry_mode_env)); // 71
164164
file.read((uint8_t *)&_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72
165165
file.read((uint8_t *)&_prefs.advert_loc_policy, sizeof(_prefs.advert_loc_policy)); // 76
166-
file.read(pad, 3); // 77
166+
file.read((uint8_t *)&_prefs.multi_acks, sizeof(_prefs.multi_acks)); // 77
167+
file.read(pad, 2); // 78
167168
file.read((uint8_t *)&_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80
168169

169170
file.close();
@@ -184,7 +185,7 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_
184185
file.write((uint8_t *)&_prefs.freq, sizeof(_prefs.freq)); // 56
185186
file.write((uint8_t *)&_prefs.sf, sizeof(_prefs.sf)); // 60
186187
file.write((uint8_t *)&_prefs.cr, sizeof(_prefs.cr)); // 61
187-
file.write((uint8_t *)&_prefs.reserved1, sizeof(_prefs.reserved1)); // 62
188+
file.write(pad, 1); // 62
188189
file.write((uint8_t *)&_prefs.manual_add_contacts, sizeof(_prefs.manual_add_contacts)); // 63
189190
file.write((uint8_t *)&_prefs.bw, sizeof(_prefs.bw)); // 64
190191
file.write((uint8_t *)&_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68
@@ -193,7 +194,8 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_
193194
file.write((uint8_t *)&_prefs.telemetry_mode_env, sizeof(_prefs.telemetry_mode_env)); // 71
194195
file.write((uint8_t *)&_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72
195196
file.write((uint8_t *)&_prefs.advert_loc_policy, sizeof(_prefs.advert_loc_policy)); // 76
196-
file.write(pad, 3); // 77
197+
file.write((uint8_t *)&_prefs.multi_acks, sizeof(_prefs.multi_acks)); // 77
198+
file.write(pad, 2); // 78
197199
file.write((uint8_t *)&_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80
198200

199201
file.close();

examples/companion_radio/MyMesh.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,10 @@ int MyMesh::calcRxDelay(float score, uint32_t air_time) const {
210210
return (int)((pow(_prefs.rx_delay_base, 0.85f - score) - 1.0) * air_time);
211211
}
212212

213+
uint8_t MyMesh::getExtraAckTransmitCount() const {
214+
return _prefs.multi_acks;
215+
}
216+
213217
void MyMesh::logRxRaw(float snr, float rssi, const uint8_t raw[], int len) {
214218
if (_serial->isConnected() && len + 3 <= MAX_FRAME_SIZE) {
215219
int i = 0;
@@ -719,7 +723,7 @@ void MyMesh::handleCmdFrame(size_t len) {
719723
i += 4;
720724
memcpy(&out_frame[i], &lon, 4);
721725
i += 4;
722-
out_frame[i++] = 0; // reserved
726+
out_frame[i++] = _prefs.multi_acks; // new v7+
723727
out_frame[i++] = _prefs.advert_loc_policy;
724728
out_frame[i++] = (_prefs.telemetry_mode_env << 4) | (_prefs.telemetry_mode_loc << 2) |
725729
(_prefs.telemetry_mode_base); // v5+
@@ -1050,6 +1054,9 @@ void MyMesh::handleCmdFrame(size_t len) {
10501054

10511055
if (len >= 4) {
10521056
_prefs.advert_loc_policy = cmd_frame[3];
1057+
if (len >= 5) {
1058+
_prefs.multi_acks = cmd_frame[4];
1059+
}
10531060
}
10541061
}
10551062
savePrefs();

examples/companion_radio/MyMesh.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@
1010
#define FIRMWARE_VER_CODE 7
1111

1212
#ifndef FIRMWARE_BUILD_DATE
13-
#define FIRMWARE_BUILD_DATE "15 Jul 2025"
13+
#define FIRMWARE_BUILD_DATE "24 Jul 2025"
1414
#endif
1515

1616
#ifndef FIRMWARE_VERSION
17-
#define FIRMWARE_VERSION "v1.7.3"
17+
#define FIRMWARE_VERSION "v1.7.4"
1818
#endif
1919

2020
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
@@ -97,6 +97,7 @@ class MyMesh : public BaseChatMesh, public DataStoreHost {
9797
float getAirtimeBudgetFactor() const override;
9898
int getInterferenceThreshold() const override;
9999
int calcRxDelay(float score, uint32_t air_time) const override;
100+
uint8_t getExtraAckTransmitCount() const override;
100101

101102
void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) override;
102103
bool isAutoAddEnabled() const override;

examples/companion_radio/NodePrefs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ struct NodePrefs { // persisted to file
1414
float freq;
1515
uint8_t sf;
1616
uint8_t cr;
17-
uint8_t reserved1;
17+
uint8_t multi_acks;
1818
uint8_t manual_add_contacts;
1919
float bw;
2020
uint8_t tx_power_dbm;

examples/companion_radio/UITask.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,8 +408,12 @@ void UITask::handleButtonQuadruplePress() {
408408
if (strcmp(_sensors->getSettingName(i), "gps") == 0) {
409409
if (strcmp(_sensors->getSettingValue(i), "1") == 0) {
410410
_sensors->setSettingValue("gps", "0");
411+
soundBuzzer(UIEventType::ack);
412+
sprintf(_alert, "GPS: Disabled");
411413
} else {
412414
_sensors->setSettingValue("gps", "1");
415+
soundBuzzer(UIEventType::ack);
416+
sprintf(_alert, "GPS: Enabled");
413417
}
414418
break;
415419
}

examples/simple_repeater/main.cpp

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@
2222
/* ------------------------------ Config -------------------------------- */
2323

2424
#ifndef FIRMWARE_BUILD_DATE
25-
#define FIRMWARE_BUILD_DATE "15 Jul 2025"
25+
#define FIRMWARE_BUILD_DATE "24 Jul 2025"
2626
#endif
2727

2828
#ifndef FIRMWARE_VERSION
29-
#define FIRMWARE_VERSION "v1.7.3"
29+
#define FIRMWARE_VERSION "v1.7.4"
3030
#endif
3131

3232
#ifndef LORA_FREQ
@@ -120,7 +120,7 @@ struct NeighbourInfo {
120120
int8_t snr; // multiplied by 4, user should divide to get float value
121121
};
122122

123-
#define CLI_REPLY_DELAY_MILLIS 1000
123+
#define CLI_REPLY_DELAY_MILLIS 600
124124

125125
class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
126126
FILESYSTEM* _fs;
@@ -134,6 +134,11 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
134134
NeighbourInfo neighbours[MAX_NEIGHBOURS];
135135
#endif
136136
CayenneLPP telemetry;
137+
unsigned long set_radio_at, revert_radio_at;
138+
float pending_freq;
139+
float pending_bw;
140+
uint8_t pending_sf;
141+
uint8_t pending_cr;
137142

138143
ClientInfo* putClient(const mesh::Identity& id) {
139144
uint32_t min_time = 0xFFFFFFFF;
@@ -339,6 +344,9 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
339344
int getAGCResetInterval() const override {
340345
return ((int)_prefs.agc_reset_interval) * 4000; // milliseconds
341346
}
347+
uint8_t getExtraAckTransmitCount() const override {
348+
return _prefs.multi_acks;
349+
}
342350

343351
void onAnonDataRecv(mesh::Packet* packet, const uint8_t* secret, const mesh::Identity& sender, uint8_t* data, size_t len) override {
344352
if (packet->getPayloadType() == PAYLOAD_TYPE_ANON_REQ) { // received an initial request by a possible admin client (unknown at this stage)
@@ -555,6 +563,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
555563
{
556564
memset(known_clients, 0, sizeof(known_clients));
557565
next_local_advert = next_flood_advert = 0;
566+
set_radio_at = revert_radio_at = 0;
558567
_logging = false;
559568

560569
#if MAX_NEIGHBOURS
@@ -606,6 +615,16 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
606615
_cli.savePrefs(_fs);
607616
}
608617

618+
void applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t cr, int timeout_mins) override {
619+
set_radio_at = futureMillis(2000); // give CLI reply some time to be sent back, before applying temp radio params
620+
pending_freq = freq;
621+
pending_bw = bw;
622+
pending_sf = sf;
623+
pending_cr = cr;
624+
625+
revert_radio_at = futureMillis(2000 + timeout_mins*60*1000); // schedule when to revert radio params
626+
}
627+
609628
bool formatFileSystem() override {
610629
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
611630
return InternalFS.format();
@@ -731,6 +750,19 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
731750

732751
updateAdvertTimer(); // schedule next local advert
733752
}
753+
754+
if (set_radio_at && millisHasNowPassed(set_radio_at)) { // apply pending (temporary) radio params
755+
set_radio_at = 0; // clear timer
756+
radio_set_params(pending_freq, pending_bw, pending_sf, pending_cr);
757+
MESH_DEBUG_PRINTLN("Temp radio params");
758+
}
759+
760+
if (revert_radio_at && millisHasNowPassed(revert_radio_at)) { // revert radio params to orig
761+
revert_radio_at = 0; // clear timer
762+
radio_set_params(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
763+
MESH_DEBUG_PRINTLN("Radio params restored");
764+
}
765+
734766
#ifdef DISPLAY_CLASS
735767
ui_task.loop();
736768
#endif

0 commit comments

Comments
 (0)