|
|
@ -207,7 +207,7 @@ uint8_t CommonCLI::buildAdvertData(uint8_t node_type, uint8_t* app_data) { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, char* reply) { |
|
|
void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* reply) { |
|
|
if (memcmp(command, "poweroff", 8) == 0 || memcmp(command, "shutdown", 8) == 0) { |
|
|
if (memcmp(command, "poweroff", 8) == 0 || memcmp(command, "shutdown", 8) == 0) { |
|
|
_board->powerOff(); // doesn't return
|
|
|
_board->powerOff(); // doesn't return
|
|
|
} else if (memcmp(command, "reboot", 6) == 0) { |
|
|
} else if (memcmp(command, "reboot", 6) == 0) { |
|
|
@ -289,172 +289,180 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch |
|
|
} else if (memcmp(command, "clear stats", 11) == 0) { |
|
|
} else if (memcmp(command, "clear stats", 11) == 0) { |
|
|
_callbacks->clearStats(); |
|
|
_callbacks->clearStats(); |
|
|
strcpy(reply, "(OK - stats reset)"); |
|
|
strcpy(reply, "(OK - stats reset)"); |
|
|
/*
|
|
|
|
|
|
* GET commands |
|
|
|
|
|
*/ |
|
|
|
|
|
} else if (memcmp(command, "get ", 4) == 0) { |
|
|
} else if (memcmp(command, "get ", 4) == 0) { |
|
|
const char* config = &command[4]; |
|
|
handleGetCmd(sender_timestamp, command, reply); |
|
|
if (memcmp(config, "dutycycle", 9) == 0) { |
|
|
} else if (memcmp(command, "set ", 4) == 0) { |
|
|
float dc = 100.0f / (_prefs->airtime_factor + 1.0f); |
|
|
handleSetCmd(sender_timestamp, command, reply); |
|
|
int dc_int = (int)dc; |
|
|
} else if (sender_timestamp == 0 && strcmp(command, "erase") == 0) { |
|
|
int dc_frac = (int)((dc - dc_int) * 10.0f + 0.5f); |
|
|
bool s = _callbacks->formatFileSystem(); |
|
|
sprintf(reply, "> %d.%d%%", dc_int, dc_frac); |
|
|
sprintf(reply, "File system erase: %s", s ? "OK" : "Err"); |
|
|
} else if (memcmp(config, "af", 2) == 0) { |
|
|
} else if (memcmp(command, "ver", 3) == 0) { |
|
|
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->airtime_factor)); |
|
|
sprintf(reply, "%s (Build: %s)", _callbacks->getFirmwareVer(), _callbacks->getBuildDate()); |
|
|
} else if (memcmp(config, "int.thresh", 10) == 0) { |
|
|
} else if (memcmp(command, "board", 5) == 0) { |
|
|
sprintf(reply, "> %d", (uint32_t) _prefs->interference_threshold); |
|
|
sprintf(reply, "%s", _board->getManufacturerName()); |
|
|
} else if (memcmp(config, "agc.reset.interval", 18) == 0) { |
|
|
} else if (memcmp(command, "sensor get ", 11) == 0) { |
|
|
sprintf(reply, "> %d", ((uint32_t) _prefs->agc_reset_interval) * 4); |
|
|
const char* key = command + 11; |
|
|
} else if (memcmp(config, "multi.acks", 10) == 0) { |
|
|
const char* val = _sensors->getSettingByKey(key); |
|
|
sprintf(reply, "> %d", (uint32_t) _prefs->multi_acks); |
|
|
if (val != NULL) { |
|
|
} else if (memcmp(config, "allow.read.only", 15) == 0) { |
|
|
sprintf(reply, "> %s", val); |
|
|
sprintf(reply, "> %s", _prefs->allow_read_only ? "on" : "off"); |
|
|
} else { |
|
|
} else if (memcmp(config, "flood.advert.interval", 21) == 0) { |
|
|
strcpy(reply, "null"); |
|
|
sprintf(reply, "> %d", ((uint32_t) _prefs->flood_advert_interval)); |
|
|
|
|
|
} else if (memcmp(config, "advert.interval", 15) == 0) { |
|
|
|
|
|
sprintf(reply, "> %d", ((uint32_t) _prefs->advert_interval) * 2); |
|
|
|
|
|
} else if (memcmp(config, "guest.password", 14) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", _prefs->guest_password); |
|
|
|
|
|
} else if (sender_timestamp == 0 && memcmp(config, "prv.key", 7) == 0) { // from serial command line only
|
|
|
|
|
|
uint8_t prv_key[PRV_KEY_SIZE]; |
|
|
|
|
|
int len = _callbacks->getSelfId().writeTo(prv_key, PRV_KEY_SIZE); |
|
|
|
|
|
mesh::Utils::toHex(tmp, prv_key, len); |
|
|
|
|
|
sprintf(reply, "> %s", tmp); |
|
|
|
|
|
} else if (memcmp(config, "name", 4) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", _prefs->node_name); |
|
|
|
|
|
} else if (memcmp(config, "repeat", 6) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", _prefs->disable_fwd ? "off" : "on"); |
|
|
|
|
|
} else if (memcmp(config, "lat", 3) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->node_lat)); |
|
|
|
|
|
} else if (memcmp(config, "lon", 3) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->node_lon)); |
|
|
|
|
|
#if defined(USE_SX1262) || defined(USE_SX1268) |
|
|
|
|
|
} else if (memcmp(config, "radio.rxgain", 12) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", _prefs->rx_boosted_gain ? "on" : "off"); |
|
|
|
|
|
#endif |
|
|
|
|
|
} else if (memcmp(config, "radio", 5) == 0) { |
|
|
|
|
|
char freq[16], bw[16]; |
|
|
|
|
|
strcpy(freq, StrHelper::ftoa(_prefs->freq)); |
|
|
|
|
|
strcpy(bw, StrHelper::ftoa3(_prefs->bw)); |
|
|
|
|
|
sprintf(reply, "> %s,%s,%d,%d", freq, bw, (uint32_t)_prefs->sf, (uint32_t)_prefs->cr); |
|
|
|
|
|
} else if (memcmp(config, "rxdelay", 7) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->rx_delay_base)); |
|
|
|
|
|
} else if (memcmp(config, "txdelay", 7) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->tx_delay_factor)); |
|
|
|
|
|
} else if (memcmp(config, "flood.max", 9) == 0) { |
|
|
|
|
|
sprintf(reply, "> %d", (uint32_t)_prefs->flood_max); |
|
|
|
|
|
} else if (memcmp(config, "direct.txdelay", 14) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->direct_tx_delay_factor)); |
|
|
|
|
|
} else if (memcmp(config, "owner.info", 10) == 0) { |
|
|
|
|
|
*reply++ = '>'; |
|
|
|
|
|
*reply++ = ' '; |
|
|
|
|
|
const char* sp = _prefs->owner_info; |
|
|
|
|
|
while (*sp) { |
|
|
|
|
|
*reply++ = (*sp == '\n') ? '|' : *sp; // translate newline back to orig '|'
|
|
|
|
|
|
sp++; |
|
|
|
|
|
} |
|
|
} |
|
|
*reply = 0; // set null terminator
|
|
|
} else if (memcmp(command, "sensor set ", 11) == 0) { |
|
|
} else if (memcmp(config, "path.hash.mode", 14) == 0) { |
|
|
strcpy(tmp, &command[11]); |
|
|
sprintf(reply, "> %d", (uint32_t)_prefs->path_hash_mode); |
|
|
const char *parts[2]; |
|
|
} else if (memcmp(config, "loop.detect", 11) == 0) { |
|
|
int num = mesh::Utils::parseTextParts(tmp, parts, 2, ' '); |
|
|
if (_prefs->loop_detect == LOOP_DETECT_OFF) { |
|
|
const char *key = (num > 0) ? parts[0] : ""; |
|
|
strcpy(reply, "> off"); |
|
|
const char *value = (num > 1) ? parts[1] : "null"; |
|
|
} else if (_prefs->loop_detect == LOOP_DETECT_MINIMAL) { |
|
|
if (_sensors->setSettingValue(key, value)) { |
|
|
strcpy(reply, "> minimal"); |
|
|
strcpy(reply, "ok"); |
|
|
} else if (_prefs->loop_detect == LOOP_DETECT_MODERATE) { |
|
|
|
|
|
strcpy(reply, "> moderate"); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
strcpy(reply, "> strict"); |
|
|
strcpy(reply, "can't find custom var"); |
|
|
} |
|
|
} |
|
|
} else if (memcmp(config, "tx", 2) == 0 && (config[2] == 0 || config[2] == ' ')) { |
|
|
} else if (memcmp(command, "sensor list", 11) == 0) { |
|
|
sprintf(reply, "> %d", (int32_t) _prefs->tx_power_dbm); |
|
|
char* dp = reply; |
|
|
} else if (memcmp(config, "freq", 4) == 0) { |
|
|
int start = 0; |
|
|
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->freq)); |
|
|
int end = _sensors->getNumSettings(); |
|
|
} else if (memcmp(config, "public.key", 10) == 0) { |
|
|
if (strlen(command) > 11) { |
|
|
strcpy(reply, "> "); |
|
|
start = _atoi(command+12); |
|
|
mesh::Utils::toHex(&reply[2], _callbacks->getSelfId().pub_key, PUB_KEY_SIZE); |
|
|
} |
|
|
} else if (memcmp(config, "role", 4) == 0) { |
|
|
if (start >= end) { |
|
|
sprintf(reply, "> %s", _callbacks->getRole()); |
|
|
strcpy(reply, "no custom var"); |
|
|
} else if (memcmp(config, "bridge.type", 11) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", |
|
|
|
|
|
#ifdef WITH_RS232_BRIDGE |
|
|
|
|
|
"rs232" |
|
|
|
|
|
#elif WITH_ESPNOW_BRIDGE |
|
|
|
|
|
"espnow" |
|
|
|
|
|
#else |
|
|
|
|
|
"none" |
|
|
|
|
|
#endif |
|
|
|
|
|
); |
|
|
|
|
|
#ifdef WITH_BRIDGE |
|
|
|
|
|
} else if (memcmp(config, "bridge.enabled", 14) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", _prefs->bridge_enabled ? "on" : "off"); |
|
|
|
|
|
} else if (memcmp(config, "bridge.delay", 12) == 0) { |
|
|
|
|
|
sprintf(reply, "> %d", (uint32_t)_prefs->bridge_delay); |
|
|
|
|
|
} else if (memcmp(config, "bridge.source", 13) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", _prefs->bridge_pkt_src ? "logRx" : "logTx"); |
|
|
|
|
|
#endif |
|
|
|
|
|
#ifdef WITH_RS232_BRIDGE |
|
|
|
|
|
} else if (memcmp(config, "bridge.baud", 11) == 0) { |
|
|
|
|
|
sprintf(reply, "> %d", (uint32_t)_prefs->bridge_baud); |
|
|
|
|
|
#endif |
|
|
|
|
|
#ifdef WITH_ESPNOW_BRIDGE |
|
|
|
|
|
} else if (memcmp(config, "bridge.channel", 14) == 0) { |
|
|
|
|
|
sprintf(reply, "> %d", (uint32_t)_prefs->bridge_channel); |
|
|
|
|
|
} else if (memcmp(config, "bridge.secret", 13) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", _prefs->bridge_secret); |
|
|
|
|
|
#endif |
|
|
|
|
|
} else if (memcmp(config, "bootloader.ver", 14) == 0) { |
|
|
|
|
|
#ifdef NRF52_PLATFORM |
|
|
|
|
|
char ver[32]; |
|
|
|
|
|
if (_board->getBootloaderVersion(ver, sizeof(ver))) { |
|
|
|
|
|
sprintf(reply, "> %s", ver); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
strcpy(reply, "> unknown"); |
|
|
sprintf(dp, "%d vars\n", end); |
|
|
|
|
|
dp = strchr(dp, 0); |
|
|
|
|
|
int i; |
|
|
|
|
|
for (i = start; i < end && (dp-reply < 134); i++) { |
|
|
|
|
|
sprintf(dp, "%s=%s\n", |
|
|
|
|
|
_sensors->getSettingName(i), |
|
|
|
|
|
_sensors->getSettingValue(i)); |
|
|
|
|
|
dp = strchr(dp, 0); |
|
|
} |
|
|
} |
|
|
#else |
|
|
if (i < end) { |
|
|
strcpy(reply, "ERROR: unsupported"); |
|
|
sprintf(dp, "... next:%d", i); |
|
|
#endif |
|
|
|
|
|
} else if (memcmp(config, "adc.multiplier", 14) == 0) { |
|
|
|
|
|
float adc_mult = _board->getAdcMultiplier(); |
|
|
|
|
|
if (adc_mult == 0.0f) { |
|
|
|
|
|
strcpy(reply, "Error: unsupported by this board"); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
sprintf(reply, "> %.3f", adc_mult); |
|
|
*(dp-1) = 0; // remove last CR
|
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} else if (memcmp(command, "region", 6) == 0) { |
|
|
|
|
|
handleRegionCmd(command, reply); |
|
|
|
|
|
#if ENV_INCLUDE_GPS == 1 |
|
|
|
|
|
} else if (memcmp(command, "gps on", 6) == 0) { |
|
|
|
|
|
if (_sensors->setSettingValue("gps", "1")) { |
|
|
|
|
|
_prefs->gps_enabled = 1; |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "ok"); |
|
|
|
|
|
} else { |
|
|
|
|
|
strcpy(reply, "gps toggle not found"); |
|
|
|
|
|
} |
|
|
|
|
|
} else if (memcmp(command, "gps off", 7) == 0) { |
|
|
|
|
|
if (_sensors->setSettingValue("gps", "0")) { |
|
|
|
|
|
_prefs->gps_enabled = 0; |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "ok"); |
|
|
|
|
|
} else { |
|
|
|
|
|
strcpy(reply, "gps toggle not found"); |
|
|
|
|
|
} |
|
|
|
|
|
} else if (memcmp(command, "gps sync", 8) == 0) { |
|
|
|
|
|
LocationProvider * l = _sensors->getLocationProvider(); |
|
|
|
|
|
if (l != NULL) { |
|
|
|
|
|
l->syncTime(); |
|
|
|
|
|
strcpy(reply, "ok"); |
|
|
|
|
|
} else { |
|
|
|
|
|
strcpy(reply, "gps provider not found"); |
|
|
|
|
|
} |
|
|
|
|
|
} else if (memcmp(command, "gps setloc", 10) == 0) { |
|
|
|
|
|
_prefs->node_lat = _sensors->node_lat; |
|
|
|
|
|
_prefs->node_lon = _sensors->node_lon; |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "ok"); |
|
|
|
|
|
} else if (memcmp(command, "gps advert", 10) == 0) { |
|
|
|
|
|
if (strlen(command) == 10) { |
|
|
|
|
|
switch (_prefs->advert_loc_policy) { |
|
|
|
|
|
case ADVERT_LOC_NONE: |
|
|
|
|
|
strcpy(reply, "> none"); |
|
|
|
|
|
break; |
|
|
|
|
|
case ADVERT_LOC_PREFS: |
|
|
|
|
|
strcpy(reply, "> prefs"); |
|
|
|
|
|
break; |
|
|
|
|
|
case ADVERT_LOC_SHARE: |
|
|
|
|
|
strcpy(reply, "> share"); |
|
|
|
|
|
break; |
|
|
|
|
|
default: |
|
|
|
|
|
strcpy(reply, "error"); |
|
|
|
|
|
} |
|
|
|
|
|
} else if (memcmp(command+11, "none", 4) == 0) { |
|
|
|
|
|
_prefs->advert_loc_policy = ADVERT_LOC_NONE; |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "ok"); |
|
|
|
|
|
} else if (memcmp(command+11, "share", 5) == 0) { |
|
|
|
|
|
_prefs->advert_loc_policy = ADVERT_LOC_SHARE; |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "ok"); |
|
|
|
|
|
} else if (memcmp(command+11, "prefs", 5) == 0) { |
|
|
|
|
|
_prefs->advert_loc_policy = ADVERT_LOC_PREFS; |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "ok"); |
|
|
|
|
|
} else { |
|
|
|
|
|
strcpy(reply, "error"); |
|
|
|
|
|
} |
|
|
|
|
|
} else if (memcmp(command, "gps", 3) == 0) { |
|
|
|
|
|
LocationProvider * l = _sensors->getLocationProvider(); |
|
|
|
|
|
if (l != NULL) { |
|
|
|
|
|
bool enabled = l->isEnabled(); // is EN pin on ?
|
|
|
|
|
|
bool fix = l->isValid(); // has fix ?
|
|
|
|
|
|
int sats = l->satellitesCount(); |
|
|
|
|
|
bool active = !strcmp(_sensors->getSettingByKey("gps"), "1"); |
|
|
|
|
|
if (enabled) { |
|
|
|
|
|
sprintf(reply, "on, %s, %s, %d sats", |
|
|
|
|
|
active?"active":"deactivated", |
|
|
|
|
|
fix?"fix":"no fix", |
|
|
|
|
|
sats); |
|
|
|
|
|
} else { |
|
|
|
|
|
strcpy(reply, "off"); |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
strcpy(reply, "Can't find GPS"); |
|
|
} |
|
|
} |
|
|
// Power management commands
|
|
|
|
|
|
} else if (memcmp(config, "pwrmgt.support", 14) == 0) { |
|
|
|
|
|
#ifdef NRF52_POWER_MANAGEMENT |
|
|
|
|
|
strcpy(reply, "> supported"); |
|
|
|
|
|
#else |
|
|
|
|
|
strcpy(reply, "> unsupported"); |
|
|
|
|
|
#endif |
|
|
|
|
|
} else if (memcmp(config, "pwrmgt.source", 13) == 0) { |
|
|
|
|
|
#ifdef NRF52_POWER_MANAGEMENT |
|
|
|
|
|
strcpy(reply, _board->isExternalPowered() ? "> external" : "> battery"); |
|
|
|
|
|
#else |
|
|
|
|
|
strcpy(reply, "ERROR: Power management not supported"); |
|
|
|
|
|
#endif |
|
|
|
|
|
} else if (memcmp(config, "pwrmgt.bootreason", 17) == 0) { |
|
|
|
|
|
#ifdef NRF52_POWER_MANAGEMENT |
|
|
|
|
|
sprintf(reply, "> Reset: %s; Shutdown: %s", |
|
|
|
|
|
_board->getResetReasonString(_board->getResetReason()), |
|
|
|
|
|
_board->getShutdownReasonString(_board->getShutdownReason())); |
|
|
|
|
|
#else |
|
|
|
|
|
strcpy(reply, "ERROR: Power management not supported"); |
|
|
|
|
|
#endif |
|
|
|
|
|
} else if (memcmp(config, "pwrmgt.bootmv", 13) == 0) { |
|
|
|
|
|
#ifdef NRF52_POWER_MANAGEMENT |
|
|
|
|
|
sprintf(reply, "> %u mV", _board->getBootVoltage()); |
|
|
|
|
|
#else |
|
|
|
|
|
strcpy(reply, "ERROR: Power management not supported"); |
|
|
|
|
|
#endif |
|
|
#endif |
|
|
|
|
|
} else if (memcmp(command, "powersaving on", 14) == 0) { |
|
|
|
|
|
_prefs->powersaving_enabled = 1; |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "ok"); // TODO: to return Not supported if required
|
|
|
|
|
|
} else if (memcmp(command, "powersaving off", 15) == 0) { |
|
|
|
|
|
_prefs->powersaving_enabled = 0; |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "ok"); |
|
|
|
|
|
} else if (memcmp(command, "powersaving", 11) == 0) { |
|
|
|
|
|
if (_prefs->powersaving_enabled) { |
|
|
|
|
|
strcpy(reply, "on"); |
|
|
} else { |
|
|
} else { |
|
|
sprintf(reply, "??: %s", config); |
|
|
strcpy(reply, "off"); |
|
|
} |
|
|
} |
|
|
/*
|
|
|
} else if (memcmp(command, "log start", 9) == 0) { |
|
|
* SET commands |
|
|
_callbacks->setLoggingOn(true); |
|
|
*/ |
|
|
strcpy(reply, " logging on"); |
|
|
} else if (memcmp(command, "set ", 4) == 0) { |
|
|
} 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 if (sender_timestamp == 0 && memcmp(command, "stats-packets", 13) == 0 && (command[13] == 0 || command[13] == ' ')) { |
|
|
|
|
|
_callbacks->formatPacketStatsReply(reply); |
|
|
|
|
|
} else if (sender_timestamp == 0 && memcmp(command, "stats-radio", 11) == 0 && (command[11] == 0 || command[11] == ' ')) { |
|
|
|
|
|
_callbacks->formatRadioStatsReply(reply); |
|
|
|
|
|
} else if (sender_timestamp == 0 && memcmp(command, "stats-core", 10) == 0 && (command[10] == 0 || command[10] == ' ')) { |
|
|
|
|
|
_callbacks->formatStatsReply(reply); |
|
|
|
|
|
} else { |
|
|
|
|
|
strcpy(reply, "Unknown command"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* reply) { |
|
|
const char* config = &command[4]; |
|
|
const char* config = &command[4]; |
|
|
if (memcmp(config, "dutycycle ", 10) == 0) { |
|
|
if (memcmp(config, "dutycycle ", 10) == 0) { |
|
|
float dc = atof(&config[10]); |
|
|
float dc = atof(&config[10]); |
|
|
@ -638,251 +646,372 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch |
|
|
} else if (memcmp(config, "strict", 6) == 0) { |
|
|
} else if (memcmp(config, "strict", 6) == 0) { |
|
|
mode = LOOP_DETECT_STRICT; |
|
|
mode = LOOP_DETECT_STRICT; |
|
|
} else { |
|
|
} else { |
|
|
mode = 0xFF; |
|
|
mode = 0xFF; |
|
|
strcpy(reply, "Error, must be: off, minimal, moderate, or strict"); |
|
|
strcpy(reply, "Error, must be: off, minimal, moderate, or strict"); |
|
|
} |
|
|
} |
|
|
if (mode != 0xFF) { |
|
|
if (mode != 0xFF) { |
|
|
_prefs->loop_detect = mode; |
|
|
_prefs->loop_detect = mode; |
|
|
savePrefs(); |
|
|
savePrefs(); |
|
|
strcpy(reply, "OK"); |
|
|
strcpy(reply, "OK"); |
|
|
|
|
|
} |
|
|
|
|
|
} else if (memcmp(config, "tx ", 3) == 0) { |
|
|
|
|
|
_prefs->tx_power_dbm = atoi(&config[3]); |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
_callbacks->setTxPower(_prefs->tx_power_dbm); |
|
|
|
|
|
strcpy(reply, "OK"); |
|
|
|
|
|
} else if (sender_timestamp == 0 && memcmp(config, "freq ", 5) == 0) { |
|
|
|
|
|
_prefs->freq = atof(&config[5]); |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "OK - reboot to apply"); |
|
|
|
|
|
#ifdef WITH_BRIDGE |
|
|
|
|
|
} else if (memcmp(config, "bridge.enabled ", 15) == 0) { |
|
|
|
|
|
_prefs->bridge_enabled = memcmp(&config[15], "on", 2) == 0; |
|
|
|
|
|
_callbacks->setBridgeState(_prefs->bridge_enabled); |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "OK"); |
|
|
|
|
|
} else if (memcmp(config, "bridge.delay ", 13) == 0) { |
|
|
|
|
|
int delay = _atoi(&config[13]); |
|
|
|
|
|
if (delay >= 0 && delay <= 10000) { |
|
|
|
|
|
_prefs->bridge_delay = (uint16_t)delay; |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "OK"); |
|
|
|
|
|
} else { |
|
|
|
|
|
strcpy(reply, "Error: delay must be between 0-10000 ms"); |
|
|
|
|
|
} |
|
|
|
|
|
} else if (memcmp(config, "bridge.source ", 14) == 0) { |
|
|
|
|
|
_prefs->bridge_pkt_src = memcmp(&config[14], "rx", 2) == 0; |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "OK"); |
|
|
|
|
|
#endif |
|
|
|
|
|
#ifdef WITH_RS232_BRIDGE |
|
|
|
|
|
} else if (memcmp(config, "bridge.baud ", 12) == 0) { |
|
|
|
|
|
uint32_t baud = atoi(&config[12]); |
|
|
|
|
|
if (baud >= 9600 && baud <= BRIDGE_MAX_BAUD) { |
|
|
|
|
|
_prefs->bridge_baud = (uint32_t)baud; |
|
|
|
|
|
_callbacks->restartBridge(); |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "OK"); |
|
|
|
|
|
} else { |
|
|
|
|
|
sprintf(reply, "Error: baud rate must be between 9600-%d",BRIDGE_MAX_BAUD); |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
#ifdef WITH_ESPNOW_BRIDGE |
|
|
|
|
|
} else if (memcmp(config, "bridge.channel ", 15) == 0) { |
|
|
|
|
|
int ch = atoi(&config[15]); |
|
|
|
|
|
if (ch > 0 && ch < 15) { |
|
|
|
|
|
_prefs->bridge_channel = (uint8_t)ch; |
|
|
|
|
|
_callbacks->restartBridge(); |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "OK"); |
|
|
|
|
|
} else { |
|
|
|
|
|
strcpy(reply, "Error: channel must be between 1-14"); |
|
|
|
|
|
} |
|
|
|
|
|
} else if (memcmp(config, "bridge.secret ", 14) == 0) { |
|
|
|
|
|
StrHelper::strncpy(_prefs->bridge_secret, &config[14], sizeof(_prefs->bridge_secret)); |
|
|
|
|
|
_callbacks->restartBridge(); |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "OK"); |
|
|
|
|
|
#endif |
|
|
|
|
|
} else if (memcmp(config, "adc.multiplier ", 15) == 0) { |
|
|
|
|
|
_prefs->adc_multiplier = atof(&config[15]); |
|
|
|
|
|
if (_board->setAdcMultiplier(_prefs->adc_multiplier)) { |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
if (_prefs->adc_multiplier == 0.0f) { |
|
|
|
|
|
strcpy(reply, "OK - using default board multiplier"); |
|
|
|
|
|
} else { |
|
|
|
|
|
sprintf(reply, "OK - multiplier set to %.3f", _prefs->adc_multiplier); |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
_prefs->adc_multiplier = 0.0f; |
|
|
|
|
|
strcpy(reply, "Error: unsupported by this board"); |
|
|
|
|
|
}; |
|
|
|
|
|
} else { |
|
|
|
|
|
sprintf(reply, "unknown config: %s", config); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* reply) { |
|
|
|
|
|
const char* config = &command[4]; |
|
|
|
|
|
if (memcmp(config, "dutycycle", 9) == 0) { |
|
|
|
|
|
float dc = 100.0f / (_prefs->airtime_factor + 1.0f); |
|
|
|
|
|
int dc_int = (int)dc; |
|
|
|
|
|
int dc_frac = (int)((dc - dc_int) * 10.0f + 0.5f); |
|
|
|
|
|
sprintf(reply, "> %d.%d%%", dc_int, dc_frac); |
|
|
|
|
|
} else if (memcmp(config, "af", 2) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->airtime_factor)); |
|
|
|
|
|
} else if (memcmp(config, "int.thresh", 10) == 0) { |
|
|
|
|
|
sprintf(reply, "> %d", (uint32_t) _prefs->interference_threshold); |
|
|
|
|
|
} else if (memcmp(config, "agc.reset.interval", 18) == 0) { |
|
|
|
|
|
sprintf(reply, "> %d", ((uint32_t) _prefs->agc_reset_interval) * 4); |
|
|
|
|
|
} else if (memcmp(config, "multi.acks", 10) == 0) { |
|
|
|
|
|
sprintf(reply, "> %d", (uint32_t) _prefs->multi_acks); |
|
|
|
|
|
} else if (memcmp(config, "allow.read.only", 15) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", _prefs->allow_read_only ? "on" : "off"); |
|
|
|
|
|
} else if (memcmp(config, "flood.advert.interval", 21) == 0) { |
|
|
|
|
|
sprintf(reply, "> %d", ((uint32_t) _prefs->flood_advert_interval)); |
|
|
|
|
|
} else if (memcmp(config, "advert.interval", 15) == 0) { |
|
|
|
|
|
sprintf(reply, "> %d", ((uint32_t) _prefs->advert_interval) * 2); |
|
|
|
|
|
} else if (memcmp(config, "guest.password", 14) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", _prefs->guest_password); |
|
|
|
|
|
} else if (sender_timestamp == 0 && memcmp(config, "prv.key", 7) == 0) { // from serial command line only
|
|
|
|
|
|
uint8_t prv_key[PRV_KEY_SIZE]; |
|
|
|
|
|
int len = _callbacks->getSelfId().writeTo(prv_key, PRV_KEY_SIZE); |
|
|
|
|
|
mesh::Utils::toHex(tmp, prv_key, len); |
|
|
|
|
|
sprintf(reply, "> %s", tmp); |
|
|
|
|
|
} else if (memcmp(config, "name", 4) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", _prefs->node_name); |
|
|
|
|
|
} else if (memcmp(config, "repeat", 6) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", _prefs->disable_fwd ? "off" : "on"); |
|
|
|
|
|
} else if (memcmp(config, "lat", 3) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->node_lat)); |
|
|
|
|
|
} else if (memcmp(config, "lon", 3) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->node_lon)); |
|
|
|
|
|
#if defined(USE_SX1262) || defined(USE_SX1268) |
|
|
|
|
|
} else if (memcmp(config, "radio.rxgain", 12) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", _prefs->rx_boosted_gain ? "on" : "off"); |
|
|
|
|
|
#endif |
|
|
|
|
|
} else if (memcmp(config, "radio", 5) == 0) { |
|
|
|
|
|
char freq[16], bw[16]; |
|
|
|
|
|
strcpy(freq, StrHelper::ftoa(_prefs->freq)); |
|
|
|
|
|
strcpy(bw, StrHelper::ftoa3(_prefs->bw)); |
|
|
|
|
|
sprintf(reply, "> %s,%s,%d,%d", freq, bw, (uint32_t)_prefs->sf, (uint32_t)_prefs->cr); |
|
|
|
|
|
} else if (memcmp(config, "rxdelay", 7) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->rx_delay_base)); |
|
|
|
|
|
} else if (memcmp(config, "txdelay", 7) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->tx_delay_factor)); |
|
|
|
|
|
} else if (memcmp(config, "flood.max", 9) == 0) { |
|
|
|
|
|
sprintf(reply, "> %d", (uint32_t)_prefs->flood_max); |
|
|
|
|
|
} else if (memcmp(config, "direct.txdelay", 14) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->direct_tx_delay_factor)); |
|
|
|
|
|
} else if (memcmp(config, "owner.info", 10) == 0) { |
|
|
|
|
|
*reply++ = '>'; |
|
|
|
|
|
*reply++ = ' '; |
|
|
|
|
|
const char* sp = _prefs->owner_info; |
|
|
|
|
|
while (*sp) { |
|
|
|
|
|
*reply++ = (*sp == '\n') ? '|' : *sp; // translate newline back to orig '|'
|
|
|
|
|
|
sp++; |
|
|
|
|
|
} |
|
|
|
|
|
*reply = 0; // set null terminator
|
|
|
|
|
|
} else if (memcmp(config, "path.hash.mode", 14) == 0) { |
|
|
|
|
|
sprintf(reply, "> %d", (uint32_t)_prefs->path_hash_mode); |
|
|
|
|
|
} else if (memcmp(config, "loop.detect", 11) == 0) { |
|
|
|
|
|
if (_prefs->loop_detect == LOOP_DETECT_OFF) { |
|
|
|
|
|
strcpy(reply, "> off"); |
|
|
|
|
|
} else if (_prefs->loop_detect == LOOP_DETECT_MINIMAL) { |
|
|
|
|
|
strcpy(reply, "> minimal"); |
|
|
|
|
|
} else if (_prefs->loop_detect == LOOP_DETECT_MODERATE) { |
|
|
|
|
|
strcpy(reply, "> moderate"); |
|
|
|
|
|
} else { |
|
|
|
|
|
strcpy(reply, "> strict"); |
|
|
|
|
|
} |
|
|
|
|
|
} else if (memcmp(config, "tx", 2) == 0 && (config[2] == 0 || config[2] == ' ')) { |
|
|
|
|
|
sprintf(reply, "> %d", (int32_t) _prefs->tx_power_dbm); |
|
|
|
|
|
} else if (memcmp(config, "freq", 4) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->freq)); |
|
|
|
|
|
} else if (memcmp(config, "public.key", 10) == 0) { |
|
|
|
|
|
strcpy(reply, "> "); |
|
|
|
|
|
mesh::Utils::toHex(&reply[2], _callbacks->getSelfId().pub_key, PUB_KEY_SIZE); |
|
|
|
|
|
} else if (memcmp(config, "role", 4) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", _callbacks->getRole()); |
|
|
|
|
|
} else if (memcmp(config, "bridge.type", 11) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", |
|
|
|
|
|
#ifdef WITH_RS232_BRIDGE |
|
|
|
|
|
"rs232" |
|
|
|
|
|
#elif WITH_ESPNOW_BRIDGE |
|
|
|
|
|
"espnow" |
|
|
|
|
|
#else |
|
|
|
|
|
"none" |
|
|
|
|
|
#endif |
|
|
|
|
|
); |
|
|
|
|
|
#ifdef WITH_BRIDGE |
|
|
|
|
|
} else if (memcmp(config, "bridge.enabled", 14) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", _prefs->bridge_enabled ? "on" : "off"); |
|
|
|
|
|
} else if (memcmp(config, "bridge.delay", 12) == 0) { |
|
|
|
|
|
sprintf(reply, "> %d", (uint32_t)_prefs->bridge_delay); |
|
|
|
|
|
} else if (memcmp(config, "bridge.source", 13) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", _prefs->bridge_pkt_src ? "logRx" : "logTx"); |
|
|
|
|
|
#endif |
|
|
|
|
|
#ifdef WITH_RS232_BRIDGE |
|
|
|
|
|
} else if (memcmp(config, "bridge.baud", 11) == 0) { |
|
|
|
|
|
sprintf(reply, "> %d", (uint32_t)_prefs->bridge_baud); |
|
|
|
|
|
#endif |
|
|
|
|
|
#ifdef WITH_ESPNOW_BRIDGE |
|
|
|
|
|
} else if (memcmp(config, "bridge.channel", 14) == 0) { |
|
|
|
|
|
sprintf(reply, "> %d", (uint32_t)_prefs->bridge_channel); |
|
|
|
|
|
} else if (memcmp(config, "bridge.secret", 13) == 0) { |
|
|
|
|
|
sprintf(reply, "> %s", _prefs->bridge_secret); |
|
|
|
|
|
#endif |
|
|
|
|
|
} else if (memcmp(config, "bootloader.ver", 14) == 0) { |
|
|
|
|
|
#ifdef NRF52_PLATFORM |
|
|
|
|
|
char ver[32]; |
|
|
|
|
|
if (_board->getBootloaderVersion(ver, sizeof(ver))) { |
|
|
|
|
|
sprintf(reply, "> %s", ver); |
|
|
|
|
|
} else { |
|
|
|
|
|
strcpy(reply, "> unknown"); |
|
|
} |
|
|
} |
|
|
} else if (memcmp(config, "tx ", 3) == 0) { |
|
|
#else |
|
|
_prefs->tx_power_dbm = atoi(&config[3]); |
|
|
strcpy(reply, "ERROR: unsupported"); |
|
|
savePrefs(); |
|
|
#endif |
|
|
_callbacks->setTxPower(_prefs->tx_power_dbm); |
|
|
} else if (memcmp(config, "adc.multiplier", 14) == 0) { |
|
|
strcpy(reply, "OK"); |
|
|
float adc_mult = _board->getAdcMultiplier(); |
|
|
} else if (sender_timestamp == 0 && memcmp(config, "freq ", 5) == 0) { |
|
|
if (adc_mult == 0.0f) { |
|
|
_prefs->freq = atof(&config[5]); |
|
|
strcpy(reply, "Error: unsupported by this board"); |
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "OK - reboot to apply"); |
|
|
|
|
|
#ifdef WITH_BRIDGE |
|
|
|
|
|
} else if (memcmp(config, "bridge.enabled ", 15) == 0) { |
|
|
|
|
|
_prefs->bridge_enabled = memcmp(&config[15], "on", 2) == 0; |
|
|
|
|
|
_callbacks->setBridgeState(_prefs->bridge_enabled); |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "OK"); |
|
|
|
|
|
} else if (memcmp(config, "bridge.delay ", 13) == 0) { |
|
|
|
|
|
int delay = _atoi(&config[13]); |
|
|
|
|
|
if (delay >= 0 && delay <= 10000) { |
|
|
|
|
|
_prefs->bridge_delay = (uint16_t)delay; |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "OK"); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
strcpy(reply, "Error: delay must be between 0-10000 ms"); |
|
|
sprintf(reply, "> %.3f", adc_mult); |
|
|
} |
|
|
} |
|
|
} else if (memcmp(config, "bridge.source ", 14) == 0) { |
|
|
// Power management commands
|
|
|
_prefs->bridge_pkt_src = memcmp(&config[14], "rx", 2) == 0; |
|
|
} else if (memcmp(config, "pwrmgt.support", 14) == 0) { |
|
|
savePrefs(); |
|
|
#ifdef NRF52_POWER_MANAGEMENT |
|
|
strcpy(reply, "OK"); |
|
|
strcpy(reply, "> supported"); |
|
|
|
|
|
#else |
|
|
|
|
|
strcpy(reply, "> unsupported"); |
|
|
|
|
|
#endif |
|
|
|
|
|
} else if (memcmp(config, "pwrmgt.source", 13) == 0) { |
|
|
|
|
|
#ifdef NRF52_POWER_MANAGEMENT |
|
|
|
|
|
strcpy(reply, _board->isExternalPowered() ? "> external" : "> battery"); |
|
|
|
|
|
#else |
|
|
|
|
|
strcpy(reply, "ERROR: Power management not supported"); |
|
|
|
|
|
#endif |
|
|
|
|
|
} else if (memcmp(config, "pwrmgt.bootreason", 17) == 0) { |
|
|
|
|
|
#ifdef NRF52_POWER_MANAGEMENT |
|
|
|
|
|
sprintf(reply, "> Reset: %s; Shutdown: %s", |
|
|
|
|
|
_board->getResetReasonString(_board->getResetReason()), |
|
|
|
|
|
_board->getShutdownReasonString(_board->getShutdownReason())); |
|
|
|
|
|
#else |
|
|
|
|
|
strcpy(reply, "ERROR: Power management not supported"); |
|
|
|
|
|
#endif |
|
|
|
|
|
} else if (memcmp(config, "pwrmgt.bootmv", 13) == 0) { |
|
|
|
|
|
#ifdef NRF52_POWER_MANAGEMENT |
|
|
|
|
|
sprintf(reply, "> %u mV", _board->getBootVoltage()); |
|
|
|
|
|
#else |
|
|
|
|
|
strcpy(reply, "ERROR: Power management not supported"); |
|
|
#endif |
|
|
#endif |
|
|
#ifdef WITH_RS232_BRIDGE |
|
|
|
|
|
} else if (memcmp(config, "bridge.baud ", 12) == 0) { |
|
|
|
|
|
uint32_t baud = atoi(&config[12]); |
|
|
|
|
|
if (baud >= 9600 && baud <= BRIDGE_MAX_BAUD) { |
|
|
|
|
|
_prefs->bridge_baud = (uint32_t)baud; |
|
|
|
|
|
_callbacks->restartBridge(); |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "OK"); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
sprintf(reply, "Error: baud rate must be between 9600-%d",BRIDGE_MAX_BAUD); |
|
|
sprintf(reply, "??: %s", config); |
|
|
} |
|
|
} |
|
|
#endif |
|
|
} |
|
|
#ifdef WITH_ESPNOW_BRIDGE |
|
|
|
|
|
} else if (memcmp(config, "bridge.channel ", 15) == 0) { |
|
|
void CommonCLI::handleRegionCmd(char* command, char* reply) { |
|
|
int ch = atoi(&config[15]); |
|
|
reply[0] = 0; |
|
|
if (ch > 0 && ch < 15) { |
|
|
|
|
|
_prefs->bridge_channel = (uint8_t)ch; |
|
|
const char* parts[4]; |
|
|
_callbacks->restartBridge(); |
|
|
int n = mesh::Utils::parseTextParts(command, parts, 4, ' '); |
|
|
savePrefs(); |
|
|
if (n == 1) { |
|
|
|
|
|
_region_map->exportTo(reply, 160); |
|
|
|
|
|
} else if (n >= 2 && strcmp(parts[1], "load") == 0) { |
|
|
|
|
|
_callbacks->startRegionsLoad(); |
|
|
|
|
|
} else if (n >= 2 && strcmp(parts[1], "save") == 0) { |
|
|
|
|
|
_prefs->discovery_mod_timestamp = getRTCClock()->getCurrentTime(); // this node is now 'modified' (for discovery info)
|
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
bool success = _callbacks->saveRegions(); |
|
|
|
|
|
strcpy(reply, success ? "OK" : "Err - save failed"); |
|
|
|
|
|
} else if (n >= 3 && strcmp(parts[1], "allowf") == 0) { |
|
|
|
|
|
auto region = _region_map->findByNamePrefix(parts[2]); |
|
|
|
|
|
if (region) { |
|
|
|
|
|
region->flags &= ~REGION_DENY_FLOOD; |
|
|
strcpy(reply, "OK"); |
|
|
strcpy(reply, "OK"); |
|
|
} else { |
|
|
} else { |
|
|
strcpy(reply, "Error: channel must be between 1-14"); |
|
|
strcpy(reply, "Err - unknown region"); |
|
|
} |
|
|
} |
|
|
} else if (memcmp(config, "bridge.secret ", 14) == 0) { |
|
|
} else if (n >= 3 && strcmp(parts[1], "denyf") == 0) { |
|
|
StrHelper::strncpy(_prefs->bridge_secret, &config[14], sizeof(_prefs->bridge_secret)); |
|
|
auto region = _region_map->findByNamePrefix(parts[2]); |
|
|
_callbacks->restartBridge(); |
|
|
if (region) { |
|
|
savePrefs(); |
|
|
region->flags |= REGION_DENY_FLOOD; |
|
|
strcpy(reply, "OK"); |
|
|
strcpy(reply, "OK"); |
|
|
#endif |
|
|
|
|
|
} else if (memcmp(config, "adc.multiplier ", 15) == 0) { |
|
|
|
|
|
_prefs->adc_multiplier = atof(&config[15]); |
|
|
|
|
|
if (_board->setAdcMultiplier(_prefs->adc_multiplier)) { |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
if (_prefs->adc_multiplier == 0.0f) { |
|
|
|
|
|
strcpy(reply, "OK - using default board multiplier"); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
sprintf(reply, "OK - multiplier set to %.3f", _prefs->adc_multiplier); |
|
|
strcpy(reply, "Err - unknown region"); |
|
|
} |
|
|
} |
|
|
|
|
|
} else if (n >= 3 && strcmp(parts[1], "get") == 0) { |
|
|
|
|
|
auto region = _region_map->findByNamePrefix(parts[2]); |
|
|
|
|
|
if (region) { |
|
|
|
|
|
auto parent = _region_map->findById(region->parent); |
|
|
|
|
|
if (parent && parent->id != 0) { |
|
|
|
|
|
sprintf(reply, " %s (%s) %s", region->name, parent->name, (region->flags & REGION_DENY_FLOOD) ? "" : "F"); |
|
|
} else { |
|
|
} else { |
|
|
_prefs->adc_multiplier = 0.0f; |
|
|
sprintf(reply, " %s %s", region->name, (region->flags & REGION_DENY_FLOOD) ? "" : "F"); |
|
|
strcpy(reply, "Error: unsupported by this board"); |
|
|
|
|
|
}; |
|
|
|
|
|
} 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) { |
|
|
|
|
|
sprintf(reply, "%s (Build: %s)", _callbacks->getFirmwareVer(), _callbacks->getBuildDate()); |
|
|
|
|
|
} else if (memcmp(command, "board", 5) == 0) { |
|
|
|
|
|
sprintf(reply, "%s", _board->getManufacturerName()); |
|
|
|
|
|
} else if (memcmp(command, "sensor get ", 11) == 0) { |
|
|
|
|
|
const char* key = command + 11; |
|
|
|
|
|
const char* val = _sensors->getSettingByKey(key); |
|
|
|
|
|
if (val != NULL) { |
|
|
|
|
|
sprintf(reply, "> %s", val); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
strcpy(reply, "null"); |
|
|
strcpy(reply, "Err - unknown region"); |
|
|
} |
|
|
} |
|
|
} else if (memcmp(command, "sensor set ", 11) == 0) { |
|
|
} else if (n >= 3 && strcmp(parts[1], "home") == 0) { |
|
|
strcpy(tmp, &command[11]); |
|
|
auto home = _region_map->findByNamePrefix(parts[2]); |
|
|
const char *parts[2]; |
|
|
if (home) { |
|
|
int num = mesh::Utils::parseTextParts(tmp, parts, 2, ' '); |
|
|
_region_map->setHomeRegion(home); |
|
|
const char *key = (num > 0) ? parts[0] : ""; |
|
|
sprintf(reply, " home is now %s", home->name); |
|
|
const char *value = (num > 1) ? parts[1] : "null"; |
|
|
|
|
|
if (_sensors->setSettingValue(key, value)) { |
|
|
|
|
|
strcpy(reply, "ok"); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
strcpy(reply, "can't find custom var"); |
|
|
strcpy(reply, "Err - unknown region"); |
|
|
} |
|
|
|
|
|
} else if (memcmp(command, "sensor list", 11) == 0) { |
|
|
|
|
|
char* dp = reply; |
|
|
|
|
|
int start = 0; |
|
|
|
|
|
int end = _sensors->getNumSettings(); |
|
|
|
|
|
if (strlen(command) > 11) { |
|
|
|
|
|
start = _atoi(command+12); |
|
|
|
|
|
} |
|
|
} |
|
|
if (start >= end) { |
|
|
} else if (n == 2 && strcmp(parts[1], "home") == 0) { |
|
|
strcpy(reply, "no custom var"); |
|
|
auto home = _region_map->getHomeRegion(); |
|
|
|
|
|
sprintf(reply, " home is %s", home ? home->name : "*"); |
|
|
|
|
|
} else if (n >= 3 && strcmp(parts[1], "default") == 0) { |
|
|
|
|
|
if (strcmp(parts[2], "<null>") == 0) { |
|
|
|
|
|
_region_map->setDefaultRegion(NULL); |
|
|
|
|
|
_callbacks->onDefaultRegionChanged(NULL); |
|
|
|
|
|
_callbacks->saveRegions(); // persist in one atomic step
|
|
|
|
|
|
sprintf(reply, " default scope is now <null>"); |
|
|
} else { |
|
|
} else { |
|
|
sprintf(dp, "%d vars\n", end); |
|
|
auto def = _region_map->findByNamePrefix(parts[2]); |
|
|
dp = strchr(dp, 0); |
|
|
if (def == NULL) { |
|
|
int i; |
|
|
def = _region_map->putRegion(parts[2], 0); // auto-create the default region
|
|
|
for (i = start; i < end && (dp-reply < 134); i++) { |
|
|
|
|
|
sprintf(dp, "%s=%s\n", |
|
|
|
|
|
_sensors->getSettingName(i), |
|
|
|
|
|
_sensors->getSettingValue(i)); |
|
|
|
|
|
dp = strchr(dp, 0); |
|
|
|
|
|
} |
|
|
} |
|
|
if (i < end) { |
|
|
if (def) { |
|
|
sprintf(dp, "... next:%d", i); |
|
|
def->flags = 0; // make sure allow flood enabled
|
|
|
|
|
|
_region_map->setDefaultRegion(def); |
|
|
|
|
|
_callbacks->onDefaultRegionChanged(def); |
|
|
|
|
|
_callbacks->saveRegions(); // persist in one atomic step
|
|
|
|
|
|
sprintf(reply, " default scope is now %s", def->name); |
|
|
} else { |
|
|
} else { |
|
|
*(dp-1) = 0; // remove last CR
|
|
|
strcpy(reply, "Err - region table full"); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
#if ENV_INCLUDE_GPS == 1 |
|
|
} else if (n == 2 && strcmp(parts[1], "default") == 0) { |
|
|
} else if (memcmp(command, "gps on", 6) == 0) { |
|
|
auto def = _region_map->getDefaultRegion(); |
|
|
if (_sensors->setSettingValue("gps", "1")) { |
|
|
sprintf(reply, " default scope is %s", def ? def->name : "<null>"); |
|
|
_prefs->gps_enabled = 1; |
|
|
} else if (n >= 3 && strcmp(parts[1], "put") == 0) { |
|
|
savePrefs(); |
|
|
auto parent = n >= 4 ? _region_map->findByNamePrefix(parts[3]) : &(_region_map->getWildcard()); |
|
|
strcpy(reply, "ok"); |
|
|
if (parent == NULL) { |
|
|
} else { |
|
|
strcpy(reply, "Err - unknown parent"); |
|
|
strcpy(reply, "gps toggle not found"); |
|
|
|
|
|
} |
|
|
|
|
|
} else if (memcmp(command, "gps off", 7) == 0) { |
|
|
|
|
|
if (_sensors->setSettingValue("gps", "0")) { |
|
|
|
|
|
_prefs->gps_enabled = 0; |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "ok"); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
strcpy(reply, "gps toggle not found"); |
|
|
auto region = _region_map->putRegion(parts[2], parent->id); |
|
|
} |
|
|
if (region == NULL) { |
|
|
} else if (memcmp(command, "gps sync", 8) == 0) { |
|
|
strcpy(reply, "Err - unable to put"); |
|
|
LocationProvider * l = _sensors->getLocationProvider(); |
|
|
|
|
|
if (l != NULL) { |
|
|
|
|
|
l->syncTime(); |
|
|
|
|
|
strcpy(reply, "ok"); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
strcpy(reply, "gps provider not found"); |
|
|
region->flags = 0; // New default: enable flood
|
|
|
|
|
|
strcpy(reply, "OK - (flood allowed)"); |
|
|
} |
|
|
} |
|
|
} else if (memcmp(command, "gps setloc", 10) == 0) { |
|
|
|
|
|
_prefs->node_lat = _sensors->node_lat; |
|
|
|
|
|
_prefs->node_lon = _sensors->node_lon; |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "ok"); |
|
|
|
|
|
} else if (memcmp(command, "gps advert", 10) == 0) { |
|
|
|
|
|
if (strlen(command) == 10) { |
|
|
|
|
|
switch (_prefs->advert_loc_policy) { |
|
|
|
|
|
case ADVERT_LOC_NONE: |
|
|
|
|
|
strcpy(reply, "> none"); |
|
|
|
|
|
break; |
|
|
|
|
|
case ADVERT_LOC_PREFS: |
|
|
|
|
|
strcpy(reply, "> prefs"); |
|
|
|
|
|
break; |
|
|
|
|
|
case ADVERT_LOC_SHARE: |
|
|
|
|
|
strcpy(reply, "> share"); |
|
|
|
|
|
break; |
|
|
|
|
|
default: |
|
|
|
|
|
strcpy(reply, "error"); |
|
|
|
|
|
} |
|
|
} |
|
|
} else if (memcmp(command+11, "none", 4) == 0) { |
|
|
} else if (n >= 3 && strcmp(parts[1], "remove") == 0) { |
|
|
_prefs->advert_loc_policy = ADVERT_LOC_NONE; |
|
|
auto region = _region_map->findByName(parts[2]); |
|
|
savePrefs(); |
|
|
if (region) { |
|
|
strcpy(reply, "ok"); |
|
|
if (_region_map->removeRegion(*region)) { |
|
|
} else if (memcmp(command+11, "share", 5) == 0) { |
|
|
strcpy(reply, "OK"); |
|
|
_prefs->advert_loc_policy = ADVERT_LOC_SHARE; |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "ok"); |
|
|
|
|
|
} else if (memcmp(command+11, "prefs", 5) == 0) { |
|
|
|
|
|
_prefs->advert_loc_policy = ADVERT_LOC_PREFS; |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "ok"); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
strcpy(reply, "error"); |
|
|
strcpy(reply, "Err - not empty"); |
|
|
} |
|
|
} |
|
|
} else if (memcmp(command, "gps", 3) == 0) { |
|
|
|
|
|
LocationProvider * l = _sensors->getLocationProvider(); |
|
|
|
|
|
if (l != NULL) { |
|
|
|
|
|
bool enabled = l->isEnabled(); // is EN pin on ?
|
|
|
|
|
|
bool fix = l->isValid(); // has fix ?
|
|
|
|
|
|
int sats = l->satellitesCount(); |
|
|
|
|
|
bool active = !strcmp(_sensors->getSettingByKey("gps"), "1"); |
|
|
|
|
|
if (enabled) { |
|
|
|
|
|
sprintf(reply, "on, %s, %s, %d sats", |
|
|
|
|
|
active?"active":"deactivated", |
|
|
|
|
|
fix?"fix":"no fix", |
|
|
|
|
|
sats); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
strcpy(reply, "off"); |
|
|
strcpy(reply, "Err - not found"); |
|
|
} |
|
|
} |
|
|
|
|
|
} else if (n >= 3 && strcmp(parts[1], "list") == 0) { |
|
|
|
|
|
uint8_t mask = 0; |
|
|
|
|
|
bool invert = false; |
|
|
|
|
|
|
|
|
|
|
|
if (strcmp(parts[2], "allowed") == 0) { |
|
|
|
|
|
mask = REGION_DENY_FLOOD; |
|
|
|
|
|
invert = false; // list regions that DON'T have DENY flag
|
|
|
|
|
|
} else if (strcmp(parts[2], "denied") == 0) { |
|
|
|
|
|
mask = REGION_DENY_FLOOD; |
|
|
|
|
|
invert = true; // list regions that DO have DENY flag
|
|
|
} else { |
|
|
} else { |
|
|
strcpy(reply, "Can't find GPS"); |
|
|
strcpy(reply, "Err - use 'allowed' or 'denied'"); |
|
|
|
|
|
return; |
|
|
} |
|
|
} |
|
|
#endif |
|
|
|
|
|
} else if (memcmp(command, "powersaving on", 14) == 0) { |
|
|
int len = _region_map->exportNamesTo(reply, 160, mask, invert); |
|
|
_prefs->powersaving_enabled = 1; |
|
|
if (len == 0) { |
|
|
savePrefs(); |
|
|
strcpy(reply, "-none-"); |
|
|
strcpy(reply, "ok"); // TODO: to return Not supported if required
|
|
|
|
|
|
} else if (memcmp(command, "powersaving off", 15) == 0) { |
|
|
|
|
|
_prefs->powersaving_enabled = 0; |
|
|
|
|
|
savePrefs(); |
|
|
|
|
|
strcpy(reply, "ok"); |
|
|
|
|
|
} else if (memcmp(command, "powersaving", 11) == 0) { |
|
|
|
|
|
if (_prefs->powersaving_enabled) { |
|
|
|
|
|
strcpy(reply, "on"); |
|
|
|
|
|
} else { |
|
|
|
|
|
strcpy(reply, "off"); |
|
|
|
|
|
} |
|
|
} |
|
|
} 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 if (sender_timestamp == 0 && memcmp(command, "stats-packets", 13) == 0 && (command[13] == 0 || command[13] == ' ')) { |
|
|
|
|
|
_callbacks->formatPacketStatsReply(reply); |
|
|
|
|
|
} else if (sender_timestamp == 0 && memcmp(command, "stats-radio", 11) == 0 && (command[11] == 0 || command[11] == ' ')) { |
|
|
|
|
|
_callbacks->formatRadioStatsReply(reply); |
|
|
|
|
|
} else if (sender_timestamp == 0 && memcmp(command, "stats-core", 10) == 0 && (command[10] == 0 || command[10] == ' ')) { |
|
|
|
|
|
_callbacks->formatStatsReply(reply); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
strcpy(reply, "Unknown command"); |
|
|
strcpy(reply, "Err - ??"); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|