Skip to content

Commit 1d45c7e

Browse files
committed
Add bridge management CLI
1 parent ea13fa8 commit 1d45c7e

File tree

11 files changed

+340
-137
lines changed

11 files changed

+340
-137
lines changed

examples/simple_repeater/MyMesh.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,8 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
513513
_prefs.flood_advert_interval = 12; // 12 hours
514514
_prefs.flood_max = 64;
515515
_prefs.interference_threshold = 0; // disabled
516+
_prefs.bridge_enabled = 1; // enabled
517+
_prefs.bridge_channel = 0; // auto
516518
}
517519

518520
void MyMesh::begin(FILESYSTEM *fs) {
@@ -523,8 +525,13 @@ void MyMesh::begin(FILESYSTEM *fs) {
523525

524526
acl.load(_fs);
525527

526-
#ifdef WITH_BRIDGE
527-
bridge.begin();
528+
#if defined(WITH_ESPNOW_BRIDGE)
529+
bridge.setChannel(_prefs.bridge_channel);
530+
#endif
531+
#if defined(WITH_BRIDGE)
532+
if (_prefs.bridge_enabled) {
533+
bridge.begin();
534+
}
528535
#endif
529536

530537
radio_set_params(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);

examples/simple_repeater/MyMesh.h

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
#include <Arduino.h>
44
#include <Mesh.h>
5-
#include <helpers/CommonCLI.h>
5+
#include <RTClib.h>
6+
#include <target.h>
67

78
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
89
#include <InternalFileSystem.h>
@@ -12,16 +13,6 @@
1213
#include <SPIFFS.h>
1314
#endif
1415

15-
#include <helpers/ArduinoHelpers.h>
16-
#include <helpers/StaticPoolPacketManager.h>
17-
#include <helpers/SimpleMeshTables.h>
18-
#include <helpers/IdentityStore.h>
19-
#include <helpers/AdvertDataHelpers.h>
20-
#include <helpers/TxtDataHelpers.h>
21-
#include <helpers/ClientACL.h>
22-
#include <RTClib.h>
23-
#include <target.h>
24-
2516
#ifdef WITH_RS232_BRIDGE
2617
#include "helpers/bridges/RS232Bridge.h"
2718
#define WITH_BRIDGE
@@ -32,6 +23,15 @@
3223
#define WITH_BRIDGE
3324
#endif
3425

26+
#include <helpers/AdvertDataHelpers.h>
27+
#include <helpers/ArduinoHelpers.h>
28+
#include <helpers/ClientACL.h>
29+
#include <helpers/CommonCLI.h>
30+
#include <helpers/IdentityStore.h>
31+
#include <helpers/SimpleMeshTables.h>
32+
#include <helpers/StaticPoolPacketManager.h>
33+
#include <helpers/TxtDataHelpers.h>
34+
3535
#ifdef WITH_BRIDGE
3636
extern AbstractBridge* bridge;
3737
#endif
@@ -165,6 +165,21 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
165165
void updateAdvertTimer() override;
166166
void updateFloodAdvertTimer() override;
167167

168+
#if defined(WITH_ESPNOW_BRIDGE)
169+
void setBridgeState(bool enable) {
170+
if (enable == bridge.getState()) return;
171+
enable ? bridge.begin() : bridge.end();
172+
}
173+
174+
void updateBridgeChannel(int ch) override {
175+
bridge.setChannel(ch);
176+
if (bridge.getState()) {
177+
bridge.end();
178+
bridge.begin();
179+
}
180+
}
181+
#endif
182+
168183
void setLoggingOn(bool enable) override { _logging = enable; }
169184

170185
void eraseLogFile() override {

src/helpers/AbstractBridge.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@ class AbstractBridge {
1111
*/
1212
virtual void begin() = 0;
1313

14+
/**
15+
* @brief Stops the bridge.
16+
*/
17+
virtual void end() = 0;
18+
19+
/**
20+
* @brief Gets the current state of the bridge.
21+
*
22+
* @return true if the bridge is initialized and running, false otherwise.
23+
*/
24+
virtual bool getState() const = 0;
25+
1426
/**
1527
* @brief A method to be called on every main loop iteration.
1628
* Used for tasks like checking for incoming data.
@@ -20,14 +32,14 @@ class AbstractBridge {
2032
/**
2133
* @brief A callback that is triggered when the mesh transmits a packet.
2234
* The bridge can use this to forward the packet.
23-
*
35+
*
2436
* @param packet The packet that was transmitted.
2537
*/
2638
virtual void onPacketTransmitted(mesh::Packet* packet) = 0;
2739

2840
/**
2941
* @brief Processes a received packet from the bridge's medium.
30-
*
42+
*
3143
* @param packet The packet that was received.
3244
*/
3345
virtual void onPacketReceived(mesh::Packet* packet) = 0;

src/helpers/CommonCLI.cpp

Lines changed: 90 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -32,32 +32,34 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
3232
if (file) {
3333
uint8_t pad[8];
3434

35-
file.read((uint8_t *) &_prefs->airtime_factor, sizeof(_prefs->airtime_factor)); // 0
36-
file.read((uint8_t *) &_prefs->node_name, sizeof(_prefs->node_name)); // 4
37-
file.read(pad, 4); // 36
38-
file.read((uint8_t *) &_prefs->node_lat, sizeof(_prefs->node_lat)); // 40
39-
file.read((uint8_t *) &_prefs->node_lon, sizeof(_prefs->node_lon)); // 48
40-
file.read((uint8_t *) &_prefs->password[0], sizeof(_prefs->password)); // 56
41-
file.read((uint8_t *) &_prefs->freq, sizeof(_prefs->freq)); // 72
42-
file.read((uint8_t *) &_prefs->tx_power_dbm, sizeof(_prefs->tx_power_dbm)); // 76
43-
file.read((uint8_t *) &_prefs->disable_fwd, sizeof(_prefs->disable_fwd)); // 77
44-
file.read((uint8_t *) &_prefs->advert_interval, sizeof(_prefs->advert_interval)); // 78
45-
file.read((uint8_t *) pad, 1); // 79 was 'unused'
46-
file.read((uint8_t *) &_prefs->rx_delay_base, sizeof(_prefs->rx_delay_base)); // 80
47-
file.read((uint8_t *) &_prefs->tx_delay_factor, sizeof(_prefs->tx_delay_factor)); // 84
48-
file.read((uint8_t *) &_prefs->guest_password[0], sizeof(_prefs->guest_password)); // 88
49-
file.read((uint8_t *) &_prefs->direct_tx_delay_factor, sizeof(_prefs->direct_tx_delay_factor)); // 104
50-
file.read(pad, 4); // 108
51-
file.read((uint8_t *) &_prefs->sf, sizeof(_prefs->sf)); // 112
52-
file.read((uint8_t *) &_prefs->cr, sizeof(_prefs->cr)); // 113
53-
file.read((uint8_t *) &_prefs->allow_read_only, sizeof(_prefs->allow_read_only)); // 114
54-
file.read((uint8_t *) &_prefs->multi_acks, sizeof(_prefs->multi_acks)); // 115
55-
file.read((uint8_t *) &_prefs->bw, sizeof(_prefs->bw)); // 116
56-
file.read((uint8_t *) &_prefs->agc_reset_interval, sizeof(_prefs->agc_reset_interval)); // 120
57-
file.read(pad, 3); // 121
58-
file.read((uint8_t *) &_prefs->flood_max, sizeof(_prefs->flood_max)); // 124
59-
file.read((uint8_t *) &_prefs->flood_advert_interval, sizeof(_prefs->flood_advert_interval)); // 125
60-
file.read((uint8_t *) &_prefs->interference_threshold, sizeof(_prefs->interference_threshold)); // 126
35+
file.read((uint8_t *)&_prefs->airtime_factor, sizeof(_prefs->airtime_factor)); // 0
36+
file.read((uint8_t *)&_prefs->node_name, sizeof(_prefs->node_name)); // 4
37+
file.read(pad, 4); // 36
38+
file.read((uint8_t *)&_prefs->node_lat, sizeof(_prefs->node_lat)); // 40
39+
file.read((uint8_t *)&_prefs->node_lon, sizeof(_prefs->node_lon)); // 48
40+
file.read((uint8_t *)&_prefs->password[0], sizeof(_prefs->password)); // 56
41+
file.read((uint8_t *)&_prefs->freq, sizeof(_prefs->freq)); // 72
42+
file.read((uint8_t *)&_prefs->tx_power_dbm, sizeof(_prefs->tx_power_dbm)); // 76
43+
file.read((uint8_t *)&_prefs->disable_fwd, sizeof(_prefs->disable_fwd)); // 77
44+
file.read((uint8_t *)&_prefs->advert_interval, sizeof(_prefs->advert_interval)); // 78
45+
file.read((uint8_t *)pad, 1); // 79 was 'unused'
46+
file.read((uint8_t *)&_prefs->rx_delay_base, sizeof(_prefs->rx_delay_base)); // 80
47+
file.read((uint8_t *)&_prefs->tx_delay_factor, sizeof(_prefs->tx_delay_factor)); // 84
48+
file.read((uint8_t *)&_prefs->guest_password[0], sizeof(_prefs->guest_password)); // 88
49+
file.read((uint8_t *)&_prefs->direct_tx_delay_factor, sizeof(_prefs->direct_tx_delay_factor)); // 104
50+
file.read(pad, 4); // 108
51+
file.read((uint8_t *)&_prefs->sf, sizeof(_prefs->sf)); // 112
52+
file.read((uint8_t *)&_prefs->cr, sizeof(_prefs->cr)); // 113
53+
file.read((uint8_t *)&_prefs->allow_read_only, sizeof(_prefs->allow_read_only)); // 114
54+
file.read((uint8_t *)&_prefs->multi_acks, sizeof(_prefs->multi_acks)); // 115
55+
file.read((uint8_t *)&_prefs->bw, sizeof(_prefs->bw)); // 116
56+
file.read((uint8_t *)&_prefs->agc_reset_interval, sizeof(_prefs->agc_reset_interval)); // 120
57+
file.read(pad, 3); // 121
58+
file.read((uint8_t *)&_prefs->flood_max, sizeof(_prefs->flood_max)); // 124
59+
file.read((uint8_t *)&_prefs->flood_advert_interval, sizeof(_prefs->flood_advert_interval)); // 125
60+
file.read((uint8_t *)&_prefs->interference_threshold, sizeof(_prefs->interference_threshold)); // 126
61+
file.read((uint8_t *)&_prefs->bridge_enabled, sizeof(_prefs->bridge_enabled)); // 127
62+
file.read((uint8_t *)&_prefs->bridge_channel, sizeof(_prefs->bridge_channel)); // 128
6163

6264
// sanitise bad pref values
6365
_prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f);
@@ -70,6 +72,8 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
7072
_prefs->cr = constrain(_prefs->cr, 5, 8);
7173
_prefs->tx_power_dbm = constrain(_prefs->tx_power_dbm, 1, 30);
7274
_prefs->multi_acks = constrain(_prefs->multi_acks, 0, 1);
75+
_prefs->bridge_enabled = constrain(_prefs->bridge_enabled, 0, 1);
76+
_prefs->bridge_channel = constrain(_prefs->bridge_channel, 0, 14);
7377

7478
file.close();
7579
}
@@ -88,32 +92,34 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
8892
uint8_t pad[8];
8993
memset(pad, 0, sizeof(pad));
9094

91-
file.write((uint8_t *) &_prefs->airtime_factor, sizeof(_prefs->airtime_factor)); // 0
92-
file.write((uint8_t *) &_prefs->node_name, sizeof(_prefs->node_name)); // 4
93-
file.write(pad, 4); // 36
94-
file.write((uint8_t *) &_prefs->node_lat, sizeof(_prefs->node_lat)); // 40
95-
file.write((uint8_t *) &_prefs->node_lon, sizeof(_prefs->node_lon)); // 48
96-
file.write((uint8_t *) &_prefs->password[0], sizeof(_prefs->password)); // 56
97-
file.write((uint8_t *) &_prefs->freq, sizeof(_prefs->freq)); // 72
98-
file.write((uint8_t *) &_prefs->tx_power_dbm, sizeof(_prefs->tx_power_dbm)); // 76
99-
file.write((uint8_t *) &_prefs->disable_fwd, sizeof(_prefs->disable_fwd)); // 77
100-
file.write((uint8_t *) &_prefs->advert_interval, sizeof(_prefs->advert_interval)); // 78
101-
file.write((uint8_t *) pad, 1); // 79 was 'unused'
102-
file.write((uint8_t *) &_prefs->rx_delay_base, sizeof(_prefs->rx_delay_base)); // 80
103-
file.write((uint8_t *) &_prefs->tx_delay_factor, sizeof(_prefs->tx_delay_factor)); // 84
104-
file.write((uint8_t *) &_prefs->guest_password[0], sizeof(_prefs->guest_password)); // 88
105-
file.write((uint8_t *) &_prefs->direct_tx_delay_factor, sizeof(_prefs->direct_tx_delay_factor)); // 104
106-
file.write(pad, 4); // 108
107-
file.write((uint8_t *) &_prefs->sf, sizeof(_prefs->sf)); // 112
108-
file.write((uint8_t *) &_prefs->cr, sizeof(_prefs->cr)); // 113
109-
file.write((uint8_t *) &_prefs->allow_read_only, sizeof(_prefs->allow_read_only)); // 114
110-
file.write((uint8_t *) &_prefs->multi_acks, sizeof(_prefs->multi_acks)); // 115
111-
file.write((uint8_t *) &_prefs->bw, sizeof(_prefs->bw)); // 116
112-
file.write((uint8_t *) &_prefs->agc_reset_interval, sizeof(_prefs->agc_reset_interval)); // 120
113-
file.write(pad, 3); // 121
114-
file.write((uint8_t *) &_prefs->flood_max, sizeof(_prefs->flood_max)); // 124
115-
file.write((uint8_t *) &_prefs->flood_advert_interval, sizeof(_prefs->flood_advert_interval)); // 125
116-
file.write((uint8_t *) &_prefs->interference_threshold, sizeof(_prefs->interference_threshold)); // 126
95+
file.write((uint8_t *)&_prefs->airtime_factor, sizeof(_prefs->airtime_factor)); // 0
96+
file.write((uint8_t *)&_prefs->node_name, sizeof(_prefs->node_name)); // 4
97+
file.write(pad, 4); // 36
98+
file.write((uint8_t *)&_prefs->node_lat, sizeof(_prefs->node_lat)); // 40
99+
file.write((uint8_t *)&_prefs->node_lon, sizeof(_prefs->node_lon)); // 48
100+
file.write((uint8_t *)&_prefs->password[0], sizeof(_prefs->password)); // 56
101+
file.write((uint8_t *)&_prefs->freq, sizeof(_prefs->freq)); // 72
102+
file.write((uint8_t *)&_prefs->tx_power_dbm, sizeof(_prefs->tx_power_dbm)); // 76
103+
file.write((uint8_t *)&_prefs->disable_fwd, sizeof(_prefs->disable_fwd)); // 77
104+
file.write((uint8_t *)&_prefs->advert_interval, sizeof(_prefs->advert_interval)); // 78
105+
file.write((uint8_t *)pad, 1); // 79 was 'unused'
106+
file.write((uint8_t *)&_prefs->rx_delay_base, sizeof(_prefs->rx_delay_base)); // 80
107+
file.write((uint8_t *)&_prefs->tx_delay_factor, sizeof(_prefs->tx_delay_factor)); // 84
108+
file.write((uint8_t *)&_prefs->guest_password[0], sizeof(_prefs->guest_password)); // 88
109+
file.write((uint8_t *)&_prefs->direct_tx_delay_factor, sizeof(_prefs->direct_tx_delay_factor)); // 104
110+
file.write(pad, 4); // 108
111+
file.write((uint8_t *)&_prefs->sf, sizeof(_prefs->sf)); // 112
112+
file.write((uint8_t *)&_prefs->cr, sizeof(_prefs->cr)); // 113
113+
file.write((uint8_t *)&_prefs->allow_read_only, sizeof(_prefs->allow_read_only)); // 114
114+
file.write((uint8_t *)&_prefs->multi_acks, sizeof(_prefs->multi_acks)); // 115
115+
file.write((uint8_t *)&_prefs->bw, sizeof(_prefs->bw)); // 116
116+
file.write((uint8_t *)&_prefs->agc_reset_interval, sizeof(_prefs->agc_reset_interval)); // 120
117+
file.write(pad, 3); // 121
118+
file.write((uint8_t *)&_prefs->flood_max, sizeof(_prefs->flood_max)); // 124
119+
file.write((uint8_t *)&_prefs->flood_advert_interval, sizeof(_prefs->flood_advert_interval)); // 125
120+
file.write((uint8_t *)&_prefs->interference_threshold, sizeof(_prefs->interference_threshold)); // 126
121+
file.write((uint8_t *)&_prefs->bridge_enabled, sizeof(_prefs->bridge_enabled)); // 127
122+
file.write((uint8_t *)&_prefs->bridge_channel, sizeof(_prefs->bridge_channel)); // 128
117123

118124
file.close();
119125
}
@@ -252,11 +258,41 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
252258
mesh::Utils::toHex(&reply[2], _callbacks->getSelfId().pub_key, PUB_KEY_SIZE);
253259
} else if (memcmp(config, "role", 4) == 0) {
254260
sprintf(reply, "> %s", _callbacks->getRole());
261+
#ifdef WITH_BRIDGE
262+
} else if (memcmp(config, "bridge.enabled", 14) == 0) {
263+
sprintf(reply, "> %s", _prefs->bridge_enabled ? "on" : "off");
264+
#ifdef WITH_ESPNOW_BRIDGE
265+
} else if (memcmp(config, "bridge.channel", 14) == 0) {
266+
sprintf(reply, "> %d", (uint32_t)_prefs->bridge_channel);
267+
#endif
268+
#endif
255269
} else {
256270
sprintf(reply, "??: %s", config);
257271
}
258272
} else if (memcmp(command, "set ", 4) == 0) {
259273
const char* config = &command[4];
274+
#ifdef WITH_BRIDGE
275+
if (memcmp(config, "bridge.enabled ", 15) == 0) {
276+
_prefs->bridge_enabled = memcmp(&config[15], "on", 2) == 0;
277+
_callbacks->setBridgeState(_prefs->bridge_enabled);
278+
savePrefs();
279+
strcpy(reply, "OK");
280+
}
281+
else
282+
#ifdef WITH_ESPNOW_BRIDGE
283+
if (memcmp(config, "bridge.channel ", 15) == 0) {
284+
int ch = atoi(&config[15]);
285+
if (ch > 0 && ch < 15) {
286+
_prefs->bridge_channel = (uint8_t)ch;
287+
_callbacks->updateBridgeChannel(ch);
288+
savePrefs();
289+
strcpy(reply, "OK");
290+
} else {
291+
strcpy(reply, "Error: channel must be 0 (AUTO) or 1-14");
292+
}
293+
} else
294+
#endif
295+
#endif
260296
if (memcmp(config, "af ", 3) == 0) {
261297
_prefs->airtime_factor = atof(&config[3]);
262298
savePrefs();
@@ -301,7 +337,8 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
301337
StrHelper::strncpy(_prefs->guest_password, &config[15], sizeof(_prefs->guest_password));
302338
savePrefs();
303339
strcpy(reply, "OK");
304-
} else if (sender_timestamp == 0 && memcmp(config, "prv.key ", 8) == 0) { // from serial command line only
340+
} else if (sender_timestamp == 0 &&
341+
memcmp(config, "prv.key ", 8) == 0) { // from serial command line only
305342
uint8_t prv_key[PRV_KEY_SIZE];
306343
bool success = mesh::Utils::fromHex(prv_key, PRV_KEY_SIZE, &config[8]);
307344
if (success) {

src/helpers/CommonCLI.h

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,35 @@
33
#include "Mesh.h"
44
#include <helpers/IdentityStore.h>
55

6-
struct NodePrefs { // persisted to file
7-
float airtime_factor;
8-
char node_name[32];
9-
double node_lat, node_lon;
10-
char password[16];
11-
float freq;
12-
uint8_t tx_power_dbm;
13-
uint8_t disable_fwd;
14-
uint8_t advert_interval; // minutes / 2
15-
uint8_t flood_advert_interval; // hours
16-
float rx_delay_base;
17-
float tx_delay_factor;
18-
char guest_password[16];
19-
float direct_tx_delay_factor;
20-
uint32_t guard;
21-
uint8_t sf;
22-
uint8_t cr;
23-
uint8_t allow_read_only;
24-
uint8_t multi_acks;
25-
float bw;
26-
uint8_t flood_max;
27-
uint8_t interference_threshold;
28-
uint8_t agc_reset_interval; // secs / 4
6+
#if defined(WITH_RS232_BRIDGE) || defined(WITH_ESPNOW_BRIDGE)
7+
#define WITH_BRIDGE
8+
#endif
9+
10+
struct NodePrefs { // persisted to file
11+
float airtime_factor;
12+
char node_name[32];
13+
double node_lat, node_lon;
14+
char password[16];
15+
float freq;
16+
uint8_t tx_power_dbm;
17+
uint8_t disable_fwd;
18+
uint8_t advert_interval; // minutes / 2
19+
uint8_t flood_advert_interval; // hours
20+
float rx_delay_base;
21+
float tx_delay_factor;
22+
char guest_password[16];
23+
float direct_tx_delay_factor;
24+
uint32_t guard;
25+
uint8_t sf;
26+
uint8_t cr;
27+
uint8_t allow_read_only;
28+
uint8_t multi_acks;
29+
float bw;
30+
uint8_t flood_max;
31+
uint8_t interference_threshold;
32+
uint8_t agc_reset_interval; // secs / 4
33+
uint8_t bridge_enabled; // boolean
34+
uint8_t bridge_channel; // 0 = AUTO, 1-14 valid
2935
};
3036

3137
class CommonCLICallbacks {
@@ -50,6 +56,11 @@ class CommonCLICallbacks {
5056
virtual void saveIdentity(const mesh::LocalIdentity& new_id) = 0;
5157
virtual void clearStats() = 0;
5258
virtual void applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t cr, int timeout_mins) = 0;
59+
60+
#ifdef WITH_ESPNOW_BRIDGE
61+
virtual void setBridgeState(bool enable) = 0;
62+
virtual void updateBridgeChannel(int ch) = 0;
63+
#endif
5364
};
5465

5566
class CommonCLI {

0 commit comments

Comments
 (0)