Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions examples/simple_repeater/MyMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,84 @@ void MyMesh::removeNeighbor(const uint8_t *pubkey, int key_len) {
#endif
}

void MyMesh::formatStatsReply(char* reply, const char* subcommand) {
RepeaterStats stats;
stats.batt_milli_volts = board.getBattMilliVolts();
stats.curr_tx_queue_len = _mgr->getOutboundCount(0xFFFFFFFF);
stats.noise_floor = (int16_t)_radio->getNoiseFloor();
stats.last_rssi = (int16_t)radio_driver.getLastRSSI();
stats.n_packets_recv = radio_driver.getPacketsRecv();
stats.n_packets_sent = radio_driver.getPacketsSent();
stats.total_air_time_secs = getTotalAirTime() / 1000;
stats.total_up_time_secs = _ms->getMillis() / 1000;
stats.n_sent_flood = getNumSentFlood();
stats.n_sent_direct = getNumSentDirect();
stats.n_recv_flood = getNumRecvFlood();
stats.n_recv_direct = getNumRecvDirect();
stats.err_events = _err_flags;
stats.last_snr = (int16_t)(radio_driver.getLastSNR() * 4);
stats.n_direct_dups = ((SimpleMeshTables *)getTables())->getNumDirectDups();
stats.n_flood_dups = ((SimpleMeshTables *)getTables())->getNumFloodDups();
stats.total_rx_air_time_secs = getReceiveAirTime() / 1000;

if (subcommand) {
if (strcmp(subcommand, "sent") == 0) {
snprintf(reply, 128, "{\"sent\":\"%lu/%lu\"}", stats.n_sent_flood, stats.n_sent_direct);
} else if (strcmp(subcommand, "recv") == 0) {
snprintf(reply, 128, "{\"recv\":\"%lu/%lu\"}", stats.n_recv_flood, stats.n_recv_direct);
} else if (strcmp(subcommand, "uptime") == 0) {
snprintf(reply, 128, "{\"uptime\":%lu}", stats.total_up_time_secs);
} else if (strcmp(subcommand, "batt") == 0) {
snprintf(reply, 128, "{\"batt\":%u}", stats.batt_milli_volts);
} else if (strcmp(subcommand, "queue") == 0) {
snprintf(reply, 128, "{\"queue\":%u}", stats.curr_tx_queue_len);
} else if (strcmp(subcommand, "noise") == 0) {
snprintf(reply, 128, "{\"noise\":%d}", stats.noise_floor);
} else if (strcmp(subcommand, "rssi") == 0) {
snprintf(reply, 128, "{\"rssi\":%d}", stats.last_rssi);
} else if (strcmp(subcommand, "snr") == 0) {
snprintf(reply, 128, "{\"snr\":%.2f}", stats.last_snr / 4.0f);
} else if (strcmp(subcommand, "errors") == 0) {
snprintf(reply, 128, "{\"errors\":%u}", stats.err_events);
} else if (strcmp(subcommand, "airtime") == 0) {
snprintf(reply, 128, "{\"airtime\":%lu}", stats.total_air_time_secs);
} else if (strcmp(subcommand, "rxairtime") == 0) {
snprintf(reply, 128, "{\"rxairtime\":%lu}", stats.total_rx_air_time_secs);
} else {
snprintf(reply, 128, "{\"error\":\"Unknown stat: %s\"}", subcommand+1);
}
return;
}

// Default: full stats as JSON
snprintf(reply, 512,
"{"
"\"sent\":\"%lu/%lu\","
"\"recv\":\"%lu/%lu\","
"\"uptime\":%lu,"
"\"batt\":%u,"
"\"queue\":%u,"
"\"noise\":%d,"
"\"rssi\":%d,"
"\"snr\":%.2f,"
"\"errors\":%u,"
"\"airtime\":%lu,"
"\"rxairtime\":%lu"
"}",
stats.n_sent_flood, stats.n_sent_direct,
stats.n_recv_flood, stats.n_recv_direct,
stats.total_up_time_secs,
stats.batt_milli_volts,
stats.curr_tx_queue_len,
stats.noise_floor,
stats.last_rssi,
stats.last_snr / 4.0f,
stats.err_events,
stats.total_air_time_secs,
stats.total_rx_air_time_secs
);
}

void MyMesh::saveIdentity(const mesh::LocalIdentity &new_id) {
self_id = new_id;
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
Expand Down Expand Up @@ -861,6 +939,18 @@ void MyMesh::loop() {

mesh::Mesh::loop();

// Handle serial CLI frames if serial interface is enabled
if (_serial) {
size_t len = _serial->checkRecvFrame(cmd_frame);
if (len > 0) {
char reply[160] = {0};
handleCommand(0, (char*)cmd_frame, reply);
if (reply[0]) {
_serial->writeFrame((const uint8_t*)reply, strlen(reply));
}
}
}

if (next_flood_advert && millisHasNowPassed(next_flood_advert)) {
mesh::Packet *pkt = createSelfAdvert();
if (pkt) sendFlood(pkt);
Expand Down
9 changes: 9 additions & 0 deletions examples/simple_repeater/MyMesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <helpers/SimpleMeshTables.h>
#include <helpers/StaticPoolPacketManager.h>
#include <helpers/TxtDataHelpers.h>
#include <helpers/BaseSerialInterface.h>

#ifdef WITH_BRIDGE
extern AbstractBridge* bridge;
Expand Down Expand Up @@ -100,6 +101,8 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
#elif defined(WITH_ESPNOW_BRIDGE)
ESPNowBridge bridge;
#endif
BaseSerialInterface *_serial = nullptr;
uint8_t cmd_frame[MAX_PACKET_PAYLOAD+1];

void putNeighbour(const mesh::Identity& id, uint32_t timestamp, float snr);
uint8_t handleLoginReq(const mesh::Identity& sender, const uint8_t* secret, uint32_t sender_timestamp, const uint8_t* data);
Expand Down Expand Up @@ -180,6 +183,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
void dumpLogFile() override;
void setTxPower(uint8_t power_dbm) override;
void formatNeighborsReply(char *reply) override;
void formatStatsReply(char* reply, const char* subcommand) override;
void removeNeighbor(const uint8_t* pubkey, int key_len) override;

mesh::LocalIdentity& getSelfId() override { return self_id; }
Expand All @@ -189,6 +193,11 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
void handleCommand(uint32_t sender_timestamp, char* command, char* reply);
void loop();

void startInterface(BaseSerialInterface &serial) {
_serial = &serial;
serial.enable();
}

#if defined(WITH_BRIDGE)
void setBridgeState(bool enable) override {
if (enable == bridge.isRunning()) return;
Expand Down
67 changes: 43 additions & 24 deletions examples/simple_repeater/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,29 @@ void halt() {

static char command[160];

#ifdef ESP32
#ifdef WIFI_SSID
#include <helpers/esp32/SerialWifiInterface.h>
SerialWifiInterface serial_interface;
#ifndef TCP_PORT
#define TCP_PORT 5000
#endif
#elif defined(BLE_PIN_CODE)
#include <helpers/esp32/SerialBLEInterface.h>
SerialBLEInterface serial_interface;
#elif defined(SERIAL_RX)
#include <helpers/ArduinoSerialInterface.h>
ArduinoSerialInterface serial_interface;
HardwareSerial companion_serial(1);
#else
#include <helpers/ArduinoSerialInterface.h>
ArduinoSerialInterface serial_interface;
#endif
#else
#include <helpers/ArduinoSerialInterface.h>
ArduinoSerialInterface serial_interface;
#endif

void setup() {
Serial.begin(115200);
delay(1000);
Expand Down Expand Up @@ -82,33 +105,29 @@ void setup() {

// send out initial Advertisement to the mesh
the_mesh.sendSelfAdvertisement(16000);

#ifdef ESP32
#ifdef WIFI_SSID
WiFi.begin(WIFI_SSID, WIFI_PWD);
serial_interface.begin(TCP_PORT);
#elif defined(BLE_PIN_CODE)
char dev_name[32+16];
sprintf(dev_name, "%s%s", BLE_NAME_PREFIX, the_mesh.getNodeName());
serial_interface.begin(dev_name, the_mesh.getBLEPin());
#elif defined(SERIAL_RX)
companion_serial.setPins(SERIAL_RX, SERIAL_TX);
companion_serial.begin(115200);
serial_interface.begin(companion_serial);
#else
serial_interface.begin(Serial);
#endif
#else
serial_interface.begin(Serial);
#endif
the_mesh.startInterface(serial_interface);
}

void loop() {
int len = strlen(command);
while (Serial.available() && len < sizeof(command)-1) {
char c = Serial.read();
if (c != '\n') {
command[len++] = c;
command[len] = 0;
}
Serial.print(c);
}
if (len == sizeof(command)-1) { // command buffer full
command[sizeof(command)-1] = '\r';
}

if (len > 0 && command[len - 1] == '\r') { // received complete line
command[len - 1] = 0; // replace newline with C string null terminator
char reply[160];
the_mesh.handleCommand(0, command, reply); // NOTE: there is no sender_timestamp via serial!
if (reply[0]) {
Serial.print(" -> "); Serial.println(reply);
}

command[0] = 0; // reset command buffer
}

the_mesh.loop();
sensors.loop();
#ifdef DISPLAY_CLASS
Expand Down
10 changes: 9 additions & 1 deletion src/helpers/CommonCLI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,12 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
} else if (memcmp(command, "clear stats", 11) == 0) {
_callbacks->clearStats();
strcpy(reply, "(OK - stats reset)");
} else if (memcmp(command, "stats", 5) == 0) {
if (command[5] == '.' && command[6]) {
_callbacks->formatStatsReply(reply, &command[6]);
} else {
_callbacks->formatStatsReply(reply, nullptr);
}
/*
* GET commands
*/
Expand Down Expand Up @@ -664,6 +670,8 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
_callbacks->dumpLogFile();
strcpy(reply, " EOF");
} else {
strcpy(reply, "Unknown command");
sprintf(reply, "Unknown command: %s", command);
}
// Clear the command buffer after processing
if (command) memset((char*)command, 0, strlen(command) + 1);
}
1 change: 1 addition & 0 deletions src/helpers/CommonCLI.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class CommonCLICallbacks {
virtual void dumpLogFile() = 0;
virtual void setTxPower(uint8_t power_dbm) = 0;
virtual void formatNeighborsReply(char *reply) = 0;
virtual void formatStatsReply(char *reply, const char* subcommand) = 0;
virtual void removeNeighbor(const uint8_t* pubkey, int key_len) {
// no op by default
};
Expand Down
4 changes: 4 additions & 0 deletions variants/heltec_v4/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,15 @@ build_flags =
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D MAX_NEIGHBOURS=50
-D WIFI_DEBUG_LOGGING=1
-D WIFI_SSID='"myssid"'
-D WIFI_PWD='"mypwd"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v4.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<../examples/simple_repeater>
+<helpers/esp32/*.cpp>
lib_deps =
${Heltec_lora32_v4.lib_deps}
${esp32_ota.lib_deps}
Expand Down
22 changes: 22 additions & 0 deletions variants/lilygo_tbeam_SX1276/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,28 @@ lib_deps =
${LilyGo_TBeam_SX1276.lib_deps}
${esp32_ota.lib_deps}

[env:Tbeam_SX1276_repeater_wifi]
extends = LilyGo_TBeam_SX1276
build_flags =
${LilyGo_TBeam_SX1276.build_flags}
-D ADVERT_NAME='"Tbeam Repeater"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D MAX_NEIGHBOURS=50
-D PERSISTANT_GPS=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
-D WIFI_DEBUG_LOGGING=1
-D WIFI_SSID='"myssid"'
-D WIFI_PWD='"mypwd"'
build_src_filter = ${LilyGo_TBeam_SX1276.build_src_filter}
+<../examples/simple_repeater>
+<helpers/esp32/*.cpp>
lib_deps =
${LilyGo_TBeam_SX1276.lib_deps}
${esp32_ota.lib_deps}

; [env:Tbeam_SX1276_repeater_bridge_rs232]
; extends = LilyGo_TBeam_SX1276
; build_flags =
Expand Down