mirror of https://github.com/meshcore-dev/MeshCore
4 changed files with 302 additions and 385 deletions
@ -0,0 +1,170 @@ |
|||
#include <Arduino.h> |
|||
#include "CommonCLI.h" |
|||
#include "TxtDataHelpers.h" |
|||
#include <RTClib.h> |
|||
|
|||
// Believe it or not, this std C function is busted on some platforms!
|
|||
static uint32_t _atoi(const char* sp) { |
|||
uint32_t n = 0; |
|||
while (*sp && *sp >= '0' && *sp <= '9') { |
|||
n *= 10; |
|||
n += (*sp++ - '0'); |
|||
} |
|||
return n; |
|||
} |
|||
|
|||
#define MIN_LOCAL_ADVERT_INTERVAL 60 |
|||
|
|||
void CommonCLI::checkAdvertInterval() { |
|||
if (_prefs->advert_interval * 2 < MIN_LOCAL_ADVERT_INTERVAL) { |
|||
_prefs->advert_interval = 0; // turn it off, now that device has been manually configured
|
|||
} |
|||
} |
|||
|
|||
void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, char* reply) { |
|||
while (*command == ' ') command++; // skip leading spaces
|
|||
|
|||
if (strlen(command) > 4 && command[2] == '|') { // optional prefix (for companion radio CLI)
|
|||
memcpy(reply, command, 3); // reflect the prefix back
|
|||
reply += 3; |
|||
command += 3; |
|||
} |
|||
|
|||
if (memcmp(command, "reboot", 6) == 0) { |
|||
_board->reboot(); // doesn't return
|
|||
} else if (memcmp(command, "advert", 6) == 0) { |
|||
_callbacks->sendSelfAdvertisement(400); |
|||
strcpy(reply, "OK - Advert sent"); |
|||
} else if (memcmp(command, "clock sync", 10) == 0) { |
|||
uint32_t curr = getRTCClock()->getCurrentTime(); |
|||
if (sender_timestamp > curr) { |
|||
getRTCClock()->setCurrentTime(sender_timestamp + 1); |
|||
strcpy(reply, "OK - clock set"); |
|||
} else { |
|||
strcpy(reply, "ERR: clock cannot go backwards"); |
|||
} |
|||
} else if (memcmp(command, "start ota", 9) == 0) { |
|||
if (_board->startOTAUpdate()) { |
|||
strcpy(reply, "OK"); |
|||
} else { |
|||
strcpy(reply, "Error"); |
|||
} |
|||
} else if (memcmp(command, "clock", 5) == 0) { |
|||
uint32_t now = getRTCClock()->getCurrentTime(); |
|||
DateTime dt = DateTime(now); |
|||
sprintf(reply, "%02d:%02d - %d/%d/%d UTC", dt.hour(), dt.minute(), dt.day(), dt.month(), dt.year()); |
|||
} else if (memcmp(command, "time ", 5) == 0) { // set time (to epoch seconds)
|
|||
uint32_t secs = _atoi(&command[5]); |
|||
uint32_t curr = getRTCClock()->getCurrentTime(); |
|||
if (secs > curr) { |
|||
getRTCClock()->setCurrentTime(secs); |
|||
strcpy(reply, "(OK - clock set!)"); |
|||
} else { |
|||
strcpy(reply, "(ERR: clock cannot go backwards)"); |
|||
} |
|||
} else if (memcmp(command, "password ", 9) == 0) { |
|||
// change admin password
|
|||
StrHelper::strncpy(_prefs->password, &command[9], sizeof(_prefs->password)); |
|||
checkAdvertInterval(); |
|||
savePrefs(); |
|||
sprintf(reply, "password now: %s", _prefs->password); // echo back just to let admin know for sure!!
|
|||
} else if (memcmp(command, "set ", 4) == 0) { |
|||
const char* config = &command[4]; |
|||
if (memcmp(config, "af ", 3) == 0) { |
|||
_prefs->airtime_factor = atof(&config[3]); |
|||
savePrefs(); |
|||
strcpy(reply, "OK"); |
|||
} else if (memcmp(config, "advert.interval ", 16) == 0) { |
|||
int mins = _atoi(&config[16]); |
|||
if (mins > 0 && mins < MIN_LOCAL_ADVERT_INTERVAL) { |
|||
sprintf(reply, "Error: min is %d mins", MIN_LOCAL_ADVERT_INTERVAL); |
|||
} else if (mins > 240) { |
|||
strcpy(reply, "Error: max is 240 mins"); |
|||
} else { |
|||
_prefs->advert_interval = (uint8_t)(mins / 2); |
|||
_callbacks->updateAdvertTimer(); |
|||
savePrefs(); |
|||
strcpy(reply, "OK"); |
|||
} |
|||
} else if (memcmp(config, "guest.password ", 15) == 0) { |
|||
StrHelper::strncpy(_prefs->guest_password, &config[15], sizeof(_prefs->guest_password)); |
|||
savePrefs(); |
|||
strcpy(reply, "OK"); |
|||
} else if (memcmp(config, "name ", 5) == 0) { |
|||
StrHelper::strncpy(_prefs->node_name, &config[5], sizeof(_prefs->node_name)); |
|||
checkAdvertInterval(); |
|||
savePrefs(); |
|||
strcpy(reply, "OK"); |
|||
} else if (memcmp(config, "repeat ", 7) == 0) { |
|||
_prefs->disable_fwd = memcmp(&config[7], "off", 3) == 0; |
|||
savePrefs(); |
|||
strcpy(reply, _prefs->disable_fwd ? "OK - repeat is now OFF" : "OK - repeat is now ON"); |
|||
} else if (memcmp(config, "lat ", 4) == 0) { |
|||
_prefs->node_lat = atof(&config[4]); |
|||
checkAdvertInterval(); |
|||
savePrefs(); |
|||
strcpy(reply, "OK"); |
|||
} else if (memcmp(config, "lon ", 4) == 0) { |
|||
_prefs->node_lon = atof(&config[4]); |
|||
checkAdvertInterval(); |
|||
savePrefs(); |
|||
strcpy(reply, "OK"); |
|||
} else if (memcmp(config, "rxdelay ", 8) == 0) { |
|||
float db = atof(&config[8]); |
|||
if (db >= 0) { |
|||
_prefs->rx_delay_base = db; |
|||
savePrefs(); |
|||
strcpy(reply, "OK"); |
|||
} else { |
|||
strcpy(reply, "Error, cannot be negative"); |
|||
} |
|||
} else if (memcmp(config, "txdelay ", 8) == 0) { |
|||
float f = atof(&config[8]); |
|||
if (f >= 0) { |
|||
_prefs->tx_delay_factor = f; |
|||
savePrefs(); |
|||
strcpy(reply, "OK"); |
|||
} else { |
|||
strcpy(reply, "Error, cannot be negative"); |
|||
} |
|||
} else if (memcmp(config, "direct.txdelay ", 15) == 0) { |
|||
float f = atof(&config[15]); |
|||
if (f >= 0) { |
|||
_prefs->direct_tx_delay_factor = f; |
|||
savePrefs(); |
|||
strcpy(reply, "OK"); |
|||
} else { |
|||
strcpy(reply, "Error, cannot be negative"); |
|||
} |
|||
} else if (memcmp(config, "tx ", 3) == 0) { |
|||
_prefs->tx_power_dbm = atoi(&config[3]); |
|||
savePrefs(); |
|||
strcpy(reply, "OK - reboot to apply"); |
|||
} else if (sender_timestamp == 0 && memcmp(config, "freq ", 5) == 0) { |
|||
_prefs->freq = atof(&config[5]); |
|||
savePrefs(); |
|||
strcpy(reply, "OK - reboot to apply"); |
|||
} else { |
|||
sprintf(reply, "unknown config: %s", config); |
|||
} |
|||
} else if (sender_timestamp == 0 && strcmp(command, "erase") == 0) { |
|||
bool s = _callbacks->formatFileSystem(); |
|||
sprintf(reply, "File system erase: %s", s ? "OK" : "Err"); |
|||
} else if (memcmp(command, "ver", 3) == 0) { |
|||
strcpy(reply, _callbacks->getFirmwareVer()); |
|||
} else if (memcmp(command, "log start", 9) == 0) { |
|||
_callbacks->setLoggingOn(true); |
|||
strcpy(reply, " logging on"); |
|||
} else if (memcmp(command, "log stop", 8) == 0) { |
|||
_callbacks->setLoggingOn(false); |
|||
strcpy(reply, " logging off"); |
|||
} else if (memcmp(command, "log erase", 9) == 0) { |
|||
_callbacks->eraseLogFile(); |
|||
strcpy(reply, " log erased"); |
|||
} else if (sender_timestamp == 0 && memcmp(command, "log", 3) == 0) { |
|||
_callbacks->dumpLogFile(); |
|||
strcpy(reply, " EOF"); |
|||
} else { |
|||
sprintf(reply, "Unknown: %s", command); |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
#pragma once |
|||
|
|||
#include "Mesh.h" |
|||
|
|||
struct NodePrefs { // persisted to file
|
|||
float airtime_factor; |
|||
char node_name[32]; |
|||
double node_lat, node_lon; |
|||
char password[16]; |
|||
float freq; |
|||
uint8_t tx_power_dbm; |
|||
uint8_t disable_fwd; |
|||
uint8_t advert_interval; // minutes
|
|||
uint8_t unused; |
|||
float rx_delay_base; |
|||
float tx_delay_factor; |
|||
char guest_password[16]; |
|||
float direct_tx_delay_factor; |
|||
}; |
|||
|
|||
class CommonCLICallbacks { |
|||
public: |
|||
virtual void savePrefs() = 0; |
|||
virtual const char* getFirmwareVer() = 0; |
|||
virtual bool formatFileSystem() = 0; |
|||
virtual void sendSelfAdvertisement(int delay_millis) = 0; |
|||
virtual void updateAdvertTimer() = 0; |
|||
virtual void setLoggingOn(bool enable) = 0; |
|||
virtual void eraseLogFile() = 0; |
|||
virtual void dumpLogFile() = 0; |
|||
}; |
|||
|
|||
class CommonCLI { |
|||
mesh::Mesh* _mesh; |
|||
NodePrefs* _prefs; |
|||
CommonCLICallbacks* _callbacks; |
|||
mesh::MainBoard* _board; |
|||
|
|||
mesh::RTCClock* getRTCClock() { return _mesh->getRTCClock(); } |
|||
void savePrefs() { _callbacks->savePrefs(); } |
|||
|
|||
void checkAdvertInterval(); |
|||
|
|||
public: |
|||
CommonCLI(mesh::MainBoard& board, mesh::Mesh* mesh, NodePrefs* prefs, CommonCLICallbacks* callbacks) |
|||
: _board(&board), _mesh(mesh), _prefs(prefs), _callbacks(callbacks) { } |
|||
|
|||
void handleCommand(uint32_t sender_timestamp, const char* command, char* reply); |
|||
}; |
|||
Loading…
Reference in new issue