Skip to content

Commit a6c8dc4

Browse files
authored
Merge branch 'ripplebiz:dev' into dev
2 parents 3adbb50 + f74819f commit a6c8dc4

File tree

10 files changed

+168
-69
lines changed

10 files changed

+168
-69
lines changed

examples/companion_radio/MyMesh.cpp

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@
4646
#define CMD_SET_CUSTOM_VAR 41
4747
#define CMD_GET_ADVERT_PATH 42
4848
#define CMD_GET_TUNING_PARAMS 43
49+
// NOTE: CMD range 44..49 parked, potentially for WiFi operations
50+
#define CMD_SEND_BINARY_REQ 50
51+
#define CMD_FACTORY_RESET 51
4952

5053
#define RESP_CODE_OK 0
5154
#define RESP_CODE_ERR 1
@@ -93,6 +96,7 @@
9396
#define PUSH_CODE_TRACE_DATA 0x89
9497
#define PUSH_CODE_NEW_ADVERT 0x8A
9598
#define PUSH_CODE_TELEMETRY_RESPONSE 0x8B
99+
#define PUSH_CODE_BINARY_RESPONSE 0x8C
96100

97101
#define ERR_CODE_UNSUPPORTED_CMD 1
98102
#define ERR_CODE_NOT_FOUND 2
@@ -468,6 +472,7 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data,
468472
i += 6; // pub_key_prefix
469473
memcpy(&out_frame[i], &tag, 4);
470474
i += 4; // NEW: include server timestamp
475+
out_frame[i++] = data[7]; // NEW (v7): ACL permissions
471476
} else {
472477
out_frame[i++] = PUSH_CODE_LOGIN_FAIL;
473478
out_frame[i++] = 0; // reserved
@@ -490,7 +495,7 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data,
490495
memcpy(&out_frame[i], &data[4], len - 4);
491496
i += (len - 4);
492497
_serial->writeFrame(out_frame, i);
493-
} else if (len > 4 && tag == pending_telemetry) { // check for telemetry response
498+
} else if (len > 4 && tag == pending_telemetry) { // check for matching response tag
494499
pending_telemetry = 0;
495500

496501
int i = 0;
@@ -501,6 +506,17 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data,
501506
memcpy(&out_frame[i], &data[4], len - 4);
502507
i += (len - 4);
503508
_serial->writeFrame(out_frame, i);
509+
} else if (len > 4 && tag == pending_req) { // check for matching response tag
510+
pending_req = 0;
511+
512+
int i = 0;
513+
out_frame[i++] = PUSH_CODE_BINARY_RESPONSE;
514+
out_frame[i++] = 0; // reserved
515+
memcpy(&out_frame[i], &tag, 4); // app needs to match this to RESP_CODE_SENT.tag
516+
i += 4;
517+
memcpy(&out_frame[i], &data[4], len - 4);
518+
i += (len - 4);
519+
_serial->writeFrame(out_frame, i);
504520
}
505521
}
506522

@@ -566,7 +582,7 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
566582
_cli_rescue = false;
567583
offline_queue_len = 0;
568584
app_target_ver = 0;
569-
pending_login = pending_status = pending_telemetry = 0;
585+
pending_login = pending_status = pending_telemetry = pending_req = 0;
570586
next_ack_idx = 0;
571587
sign_data = NULL;
572588
dirty_contacts_expiry = 0;
@@ -1103,7 +1119,7 @@ void MyMesh::handleCmdFrame(size_t len) {
11031119
if (result == MSG_SEND_FAILED) {
11041120
writeErrFrame(ERR_CODE_TABLE_FULL);
11051121
} else {
1106-
pending_telemetry = pending_status = 0;
1122+
pending_req = pending_telemetry = pending_status = 0;
11071123
memcpy(&pending_login, recipient->id.pub_key, 4); // match this to onContactResponse()
11081124
out_frame[0] = RESP_CODE_SENT;
11091125
out_frame[1] = (result == MSG_SEND_SENT_FLOOD) ? 1 : 0;
@@ -1123,7 +1139,7 @@ void MyMesh::handleCmdFrame(size_t len) {
11231139
if (result == MSG_SEND_FAILED) {
11241140
writeErrFrame(ERR_CODE_TABLE_FULL);
11251141
} else {
1126-
pending_telemetry = pending_login = 0;
1142+
pending_req = pending_telemetry = pending_login = 0;
11271143
// FUTURE: pending_status = tag; // match this in onContactResponse()
11281144
memcpy(&pending_status, recipient->id.pub_key, 4); // legacy matching scheme
11291145
out_frame[0] = RESP_CODE_SENT;
@@ -1135,7 +1151,7 @@ void MyMesh::handleCmdFrame(size_t len) {
11351151
} else {
11361152
writeErrFrame(ERR_CODE_NOT_FOUND); // contact not found
11371153
}
1138-
} else if (cmd_frame[0] == CMD_SEND_TELEMETRY_REQ && len >= 4 + PUB_KEY_SIZE) {
1154+
} else if (cmd_frame[0] == CMD_SEND_TELEMETRY_REQ && len >= 4 + PUB_KEY_SIZE) { // can deprecate, in favour of CMD_SEND_BINARY_REQ
11391155
uint8_t *pub_key = &cmd_frame[4];
11401156
ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE);
11411157
if (recipient) {
@@ -1144,7 +1160,7 @@ void MyMesh::handleCmdFrame(size_t len) {
11441160
if (result == MSG_SEND_FAILED) {
11451161
writeErrFrame(ERR_CODE_TABLE_FULL);
11461162
} else {
1147-
pending_status = pending_login = 0;
1163+
pending_status = pending_login = pending_req = 0;
11481164
pending_telemetry = tag; // match this in onContactResponse()
11491165
out_frame[0] = RESP_CODE_SENT;
11501166
out_frame[1] = (result == MSG_SEND_SENT_FLOOD) ? 1 : 0;
@@ -1170,6 +1186,27 @@ void MyMesh::handleCmdFrame(size_t len) {
11701186
memcpy(&out_frame[i], telemetry.getBuffer(), tlen);
11711187
i += tlen;
11721188
_serial->writeFrame(out_frame, i);
1189+
} else if (cmd_frame[0] == CMD_SEND_BINARY_REQ && len >= 2 + PUB_KEY_SIZE) {
1190+
uint8_t *pub_key = &cmd_frame[1];
1191+
ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE);
1192+
if (recipient) {
1193+
uint8_t *req_data = &cmd_frame[1 + PUB_KEY_SIZE];
1194+
uint32_t tag, est_timeout;
1195+
int result = sendRequest(*recipient, req_data, len - (1 + PUB_KEY_SIZE), tag, est_timeout);
1196+
if (result == MSG_SEND_FAILED) {
1197+
writeErrFrame(ERR_CODE_TABLE_FULL);
1198+
} else {
1199+
pending_status = pending_login = pending_telemetry = 0;
1200+
pending_req = tag; // match this in onContactResponse()
1201+
out_frame[0] = RESP_CODE_SENT;
1202+
out_frame[1] = (result == MSG_SEND_SENT_FLOOD) ? 1 : 0;
1203+
memcpy(&out_frame[2], &tag, 4);
1204+
memcpy(&out_frame[6], &est_timeout, 4);
1205+
_serial->writeFrame(out_frame, 10);
1206+
}
1207+
} else {
1208+
writeErrFrame(ERR_CODE_NOT_FOUND); // contact not found
1209+
}
11731210
} else if (cmd_frame[0] == CMD_HAS_CONNECTION && len >= 1 + PUB_KEY_SIZE) {
11741211
uint8_t *pub_key = &cmd_frame[1];
11751212
if (hasConnectionTo(pub_key)) {
@@ -1325,6 +1362,15 @@ void MyMesh::handleCmdFrame(size_t len) {
13251362
} else {
13261363
writeErrFrame(ERR_CODE_NOT_FOUND);
13271364
}
1365+
} else if (cmd_frame[0] == CMD_FACTORY_RESET && memcmp(&cmd_frame[1], "reset", 5) == 0) {
1366+
bool success = _store->formatFileSystem();
1367+
if (success) {
1368+
writeOKFrame();
1369+
delay(1000);
1370+
board.reboot(); // doesn't return
1371+
} else {
1372+
writeErrFrame(ERR_CODE_FILE_IO_ERROR);
1373+
}
13281374
} else {
13291375
writeErrFrame(ERR_CODE_UNSUPPORTED_CMD);
13301376
MESH_DEBUG_PRINTLN("ERROR: unknown command: %02X", cmd_frame[0]);

examples/companion_radio/MyMesh.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
#endif
88

99
/*------------ Frame Protocol --------------*/
10-
#define FIRMWARE_VER_CODE 6
10+
#define FIRMWARE_VER_CODE 7
1111

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

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

2020
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
@@ -160,7 +160,8 @@ class MyMesh : public BaseChatMesh, public DataStoreHost {
160160
NodePrefs _prefs;
161161
uint32_t pending_login;
162162
uint32_t pending_status;
163-
uint32_t pending_telemetry;
163+
uint32_t pending_telemetry; // pending _TELEMETRY_REQ
164+
uint32_t pending_req; // pending _BINARY_REQ
164165
BaseSerialInterface *_serial;
165166

166167
ContactsIterator _iter;

examples/simple_repeater/main.cpp

Lines changed: 2 additions & 2 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 "2 Jul 2025"
25+
#define FIRMWARE_BUILD_DATE "15 Jul 2025"
2626
#endif
2727

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

3232
#ifndef LORA_FREQ

examples/simple_room_server/main.cpp

Lines changed: 2 additions & 2 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 "2 Jul 2025"
25+
#define FIRMWARE_BUILD_DATE "15 Jul 2025"
2626
#endif
2727

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

3232
#ifndef LORA_FREQ

examples/simple_sensor/SensorMesh.cpp

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959

6060
#define LAZY_CONTACTS_WRITE_DELAY 5000
6161

62-
#define ALERT_ACK_EXPIRY_MILLIS 6000 // wait 6 secs for ACKs to alert messages
62+
#define ALERT_ACK_EXPIRY_MILLIS 8000 // wait 8 secs for ACKs to alert messages
6363

6464
static File openAppend(FILESYSTEM* _fs, const char* fname) {
6565
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
@@ -95,11 +95,11 @@ void SensorMesh::loadContacts() {
9595
while (!full) {
9696
ContactInfo c;
9797
uint8_t pub_key[32];
98-
uint8_t unused[5];
98+
uint8_t unused[6];
9999

100100
bool success = (file.read(pub_key, 32) == 32);
101-
success = success && (file.read((uint8_t *) &c.permissions, 2) == 2);
102-
success = success && (file.read(unused, 5) == 5);
101+
success = success && (file.read((uint8_t *) &c.permissions, 1) == 1);
102+
success = success && (file.read(unused, 6) == 6);
103103
success = success && (file.read((uint8_t *)&c.out_path_len, 1) == 1);
104104
success = success && (file.read(c.out_path, 64) == 64);
105105
success = success && (file.read(c.shared_secret, PUB_KEY_SIZE) == PUB_KEY_SIZE);
@@ -131,8 +131,8 @@ void SensorMesh::saveContacts() {
131131
if (c->permissions == 0) continue; // skip deleted entries
132132

133133
bool success = (file.write(c->id.pub_key, 32) == 32);
134-
success = success && (file.write((uint8_t *) &c->permissions, 2) == 2);
135-
success = success && (file.write(unused, 5) == 5);
134+
success = success && (file.write((uint8_t *) &c->permissions, 1) == 1);
135+
success = success && (file.write(unused, 6) == 6);
136136
success = success && (file.write((uint8_t *)&c->out_path_len, 1) == 1);
137137
success = success && (file.write(c->out_path, 64) == 64);
138138
success = success && (file.write(c->shared_secret, PUB_KEY_SIZE) == PUB_KEY_SIZE);
@@ -240,20 +240,21 @@ static uint8_t putFloat(uint8_t * dest, float value, uint8_t size, uint32_t mult
240240
return size;
241241
}
242242

243-
uint8_t SensorMesh::handleRequest(uint16_t perms, uint32_t sender_timestamp, uint8_t req_type, uint8_t* payload, size_t payload_len) {
243+
uint8_t SensorMesh::handleRequest(uint8_t perms, uint32_t sender_timestamp, uint8_t req_type, uint8_t* payload, size_t payload_len) {
244244
memcpy(reply_data, &sender_timestamp, 4); // reflect sender_timestamp back in response packet (kind of like a 'tag')
245245

246246
if (req_type == REQ_TYPE_GET_TELEMETRY_DATA && (perms & PERM_GET_TELEMETRY) != 0) {
247247
telemetry.reset();
248248
telemetry.addVoltage(TELEM_CHANNEL_SELF, (float)board.getBattMilliVolts() / 1000.0f);
249249
// query other sensors -- target specific
250250
sensors.querySensors(0xFF, telemetry); // allow all telemetry permissions for admin or guest
251+
// TODO: let requester know permissions they have: telemetry.addPresence(TELEM_CHANNEL_SELF, perms);
251252

252253
uint8_t tlen = telemetry.getSize();
253254
memcpy(&reply_data[4], telemetry.getBuffer(), tlen);
254255
return 4 + tlen; // reply_len
255256
}
256-
if (req_type == REQ_TYPE_GET_AVG_MIN_MAX && (perms & PERM_GET_MIN_MAX_AVG) != 0) {
257+
if (req_type == REQ_TYPE_GET_AVG_MIN_MAX && (perms & PERM_GET_OTHER_STATS) != 0) {
257258
uint32_t start_secs_ago, end_secs_ago;
258259
memcpy(&start_secs_ago, &payload[0], 4);
259260
memcpy(&end_secs_ago, &payload[4], 4);
@@ -287,15 +288,15 @@ uint8_t SensorMesh::handleRequest(uint16_t perms, uint32_t sender_timestamp, uin
287288
}
288289
return ofs;
289290
}
290-
if (req_type == REQ_TYPE_GET_ACCESS_LIST && (perms & PERM_IS_ADMIN) != 0) {
291+
if (req_type == REQ_TYPE_GET_ACCESS_LIST && (perms & PERM_ACL_ROLE_MASK) == PERM_ACL_LEVEL3) {
291292
uint8_t res1 = payload[0]; // reserved for future (extra query params)
292293
uint8_t res2 = payload[1];
293294
if (res1 == 0 && res2 == 0) {
294295
uint8_t ofs = 4;
295-
for (int i = 0; i < num_contacts && ofs + 8 <= sizeof(reply_data) - 4; i++) {
296+
for (int i = 0; i < num_contacts && ofs + 7 <= sizeof(reply_data) - 4; i++) {
296297
auto c = &contacts[i];
297298
memcpy(&reply_data[ofs], c->id.pub_key, 6); ofs += 6; // just 6-byte pub_key prefix
298-
memcpy(&reply_data[ofs], &c->permissions, 2); ofs += 2;
299+
reply_data[ofs++] = c->permissions;
299300
}
300301
return ofs;
301302
}
@@ -337,11 +338,11 @@ ContactInfo* SensorMesh::putContact(const mesh::Identity& id) {
337338
return c;
338339
}
339340

340-
void SensorMesh::applyContactPermissions(const uint8_t* pubkey, uint16_t perms) {
341+
void SensorMesh::applyContactPermissions(const uint8_t* pubkey, uint8_t perms) {
341342
mesh::Identity id(pubkey);
342343
auto c = putContact(id);
343344

344-
if (perms == 0) { // no permissions, remove from contacts
345+
if ((perms & PERM_ACL_ROLE_MASK) == PERM_ACL_GUEST) { // guest role is not persisted in contacts
345346
memset(c, 0, sizeof(*c));
346347
} else {
347348
c->permissions = perms; // update their permissions
@@ -449,7 +450,7 @@ uint8_t SensorMesh::handleLoginReq(const mesh::Identity& sender, const uint8_t*
449450
MESH_DEBUG_PRINTLN("Login success!");
450451
client->last_timestamp = sender_timestamp;
451452
client->last_activity = getRTCClock()->getCurrentTime();
452-
client->permissions = PERM_IS_ADMIN | PERM_RECV_ALERTS_HI | PERM_RECV_ALERTS_LO; // initially opt-in to receive alerts (can opt out)
453+
client->permissions = PERM_ACL_LEVEL3 | PERM_RECV_ALERTS_HI | PERM_RECV_ALERTS_LO; // initially opt-in to receive alerts (can opt out)
453454
memcpy(client->shared_secret, secret, PUB_KEY_SIZE);
454455

455456
dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY);
@@ -459,7 +460,7 @@ uint8_t SensorMesh::handleLoginReq(const mesh::Identity& sender, const uint8_t*
459460
reply_data[4] = RESP_SERVER_LOGIN_OK;
460461
reply_data[5] = 0; // NEW: recommended keep-alive interval (secs / 16)
461462
reply_data[6] = 1; // 1 = is admin
462-
reply_data[7] = 0; // FUTURE: reserved
463+
reply_data[7] = client->permissions;
463464
getRNG()->random(&reply_data[8], 4); // random blob to help packet-hash uniqueness
464465

465466
return 12; // reply length
@@ -480,7 +481,7 @@ void SensorMesh::handleCommand(uint32_t sender_timestamp, char* command, char* r
480481
}
481482

482483
// handle sensor-specific CLI commands
483-
if (memcmp(command, "setperm ", 8) == 0) { // format: setperm {pubkey-hex} {permissions-int16}
484+
if (memcmp(command, "setperm ", 8) == 0) { // format: setperm {pubkey-hex} {permissions-int8}
484485
char* hex = &command[8];
485486
char* sp = strchr(hex, ' '); // look for separator char
486487
if (sp == NULL || sp - hex != PUB_KEY_SIZE*2) {
@@ -490,20 +491,21 @@ void SensorMesh::handleCommand(uint32_t sender_timestamp, char* command, char* r
490491

491492
uint8_t pubkey[PUB_KEY_SIZE];
492493
if (mesh::Utils::fromHex(pubkey, PUB_KEY_SIZE, hex)) {
493-
uint16_t perms = atoi(sp);
494+
uint8_t perms = atoi(sp);
494495
applyContactPermissions(pubkey, perms);
495496
strcpy(reply, "OK");
496497
} else {
497498
strcpy(reply, "Err - bad pubkey");
498499
}
499500
}
500-
} else if (sender_timestamp == 0 && strcmp(command, "getperm") == 0) {
501-
Serial.println("Permissions:");
501+
} else if (sender_timestamp == 0 && strcmp(command, "get acl") == 0) {
502+
Serial.println("ACL:");
502503
for (int i = 0; i < num_contacts; i++) {
503504
auto c = &contacts[i];
504505

506+
Serial.printf("%02X ", c->permissions);
505507
mesh::Utils::printHex(Serial, c->id.pub_key, PUB_KEY_SIZE);
506-
Serial.printf(" %04X\n", c->permissions);
508+
Serial.printf("\n");
507509
}
508510
reply[0] = 0;
509511
} else {

examples/simple_sensor/SensorMesh.h

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,29 @@
2323
#include <RTClib.h>
2424
#include <target.h>
2525

26-
#define PERM_IS_ADMIN 0x8000
27-
#define PERM_GET_TELEMETRY 0x0001
28-
#define PERM_GET_MIN_MAX_AVG 0x0002
29-
#define PERM_RECV_ALERTS_LO 0x0100 // low priority alerts
30-
#define PERM_RECV_ALERTS_HI 0x0200 // high priority alerts
26+
#define PERM_ACL_ROLE_MASK 3 // lower 2 bits
27+
#define PERM_ACL_GUEST 0
28+
#define PERM_ACL_LEVEL1 1
29+
#define PERM_ACL_LEVEL2 2
30+
#define PERM_ACL_LEVEL3 3 // admin
31+
32+
#define PERM_GET_TELEMETRY (1 << 2)
33+
#define PERM_GET_OTHER_STATS (1 << 3)
34+
#define PERM_RESERVED1 (1 << 4)
35+
#define PERM_RESERVED2 (1 << 5)
36+
#define PERM_RECV_ALERTS_LO (1 << 6) // low priority alerts
37+
#define PERM_RECV_ALERTS_HI (1 << 7) // high priority alerts
3138

3239
struct ContactInfo {
3340
mesh::Identity id;
34-
uint16_t permissions;
41+
uint8_t permissions;
3542
int8_t out_path_len;
3643
uint8_t out_path[MAX_PATH_SIZE];
3744
uint8_t shared_secret[PUB_KEY_SIZE];
3845
uint32_t last_timestamp; // by THEIR clock (transient)
3946
uint32_t last_activity; // by OUR clock (transient)
4047

41-
bool isAdmin() const { return (permissions & PERM_IS_ADMIN) != 0; }
48+
bool isAdmin() const { return (permissions & PERM_ACL_ROLE_MASK) == PERM_ACL_LEVEL3; }
4249
};
4350

4451
#ifndef FIRMWARE_BUILD_DATE
@@ -151,10 +158,10 @@ class SensorMesh : public mesh::Mesh, public CommonCLICallbacks {
151158
void loadContacts();
152159
void saveContacts();
153160
uint8_t handleLoginReq(const mesh::Identity& sender, const uint8_t* secret, uint32_t sender_timestamp, const uint8_t* data);
154-
uint8_t handleRequest(uint16_t perms, uint32_t sender_timestamp, uint8_t req_type, uint8_t* payload, size_t payload_len);
161+
uint8_t handleRequest(uint8_t perms, uint32_t sender_timestamp, uint8_t req_type, uint8_t* payload, size_t payload_len);
155162
mesh::Packet* createSelfAdvert();
156163
ContactInfo* putContact(const mesh::Identity& id);
157-
void applyContactPermissions(const uint8_t* pubkey, uint16_t perms);
164+
void applyContactPermissions(const uint8_t* pubkey, uint8_t perms);
158165

159166
void sendAlert(ContactInfo* c, Trigger* t);
160167

0 commit comments

Comments
 (0)