mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-11-05 05:37:33 +00:00
106 lines
3.4 KiB
C++
106 lines
3.4 KiB
C++
#include "LedSettings.h"
|
|
#include <MeshCore.h>
|
|
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
|
#include <helpers/AtomicFileWriter.h>
|
|
#else
|
|
#include <helpers/ContactFileTransaction.h>
|
|
#endif
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
namespace mesh { namespace leds {
|
|
namespace {
|
|
MainBoard* main_board = nullptr;
|
|
FILESYSTEM* settings_fs = nullptr;
|
|
const char* const path = "/leds_v1";
|
|
const char* const backup = "/leds_v1.bak";
|
|
|
|
const uint8_t images[2][8] = {
|
|
{'L', 'E', 'D', 1, 0, 0xff, 0, 0},
|
|
{'L', 'E', 'D', 1, 1, 0xfe, 0, 0}};
|
|
|
|
// Return the saved value, or -1 for an absent or invalid image. Comparing the
|
|
// two canonical images shares the write format without a second encoder.
|
|
int readSetting(const char* name) {
|
|
if (!settings_fs) return -1;
|
|
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
|
File file(*settings_fs);
|
|
if (!file.open(name, FILE_O_READ)) return -1;
|
|
#else
|
|
File file = settings_fs->open(name, "r");
|
|
if (!file) return -1;
|
|
#endif
|
|
uint8_t data[8];
|
|
const bool complete = file.size() == sizeof(data)
|
|
&& file.read(data, sizeof(data)) == sizeof(data);
|
|
file.close();
|
|
if (!complete || data[4] > 1
|
|
|| memcmp(data, images[data[4]], sizeof(data)) != 0) return -1;
|
|
return data[4];
|
|
}
|
|
|
|
bool saveSetting(bool on) {
|
|
if (!settings_fs) return false;
|
|
const uint8_t* data = images[on ? 1 : 0];
|
|
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
|
AtomicFileWriter file(settings_fs, path);
|
|
#else
|
|
ContactFileTransaction file(settings_fs, path);
|
|
#endif
|
|
if (!file || file.write(data, sizeof(images[0])) != sizeof(images[0]) || !file.commit())
|
|
return false;
|
|
return readSetting(path) == int(on);
|
|
}
|
|
} // namespace
|
|
|
|
void beginSettings(MainBoard& board, FILESYSTEM* fs) {
|
|
main_board = &board;
|
|
settings_fs = fs;
|
|
int setting = readSetting(path);
|
|
if (setting < 0 && (setting = readSetting(backup)) >= 0) {
|
|
// Recover the rename gap without discarding the last complete preference.
|
|
if ((!fs->exists(path) || fs->remove(path)) && fs->rename(backup, path)) {
|
|
if (readSetting(path) != setting) settings_fs = nullptr;
|
|
} else {
|
|
settings_fs = nullptr;
|
|
}
|
|
}
|
|
setEnabled(setting != 0);
|
|
board.applyLedPolicy();
|
|
applyStatusPolicy();
|
|
}
|
|
|
|
// Keep the uncommon filesystem transaction out of the large STM32 CLI
|
|
// dispatcher, while retaining ordinary inlining choices elsewhere.
|
|
#if defined(STM32_PLATFORM)
|
|
__attribute__((noinline))
|
|
#endif
|
|
bool handleCommand(const char* command, char* reply, size_t capacity) {
|
|
if (!command || !reply || capacity == 0) return false;
|
|
const bool get = command[0] == 'g';
|
|
if ((!get && command[0] != 's')
|
|
|| strncmp(command + 1, "et leds", 7) != 0) return false;
|
|
const char* value = command + 8;
|
|
if (*value && *value != ' ' && *value != '\t') return false;
|
|
const char* message;
|
|
if (get) {
|
|
message = *value ? "Error: usage get leds" : enabled() ? "> on" : "> off";
|
|
} else {
|
|
while (*value == ' ' || *value == '\t') ++value;
|
|
const bool on = strcmp(value, "on") == 0;
|
|
if (!on && strcmp(value, "off") != 0) {
|
|
message = "Error: usage set leds on|off";
|
|
} else if (!main_board || !saveSetting(on)) {
|
|
message = "Error: LED setting save unconfirmed; reboot may differ";
|
|
} else {
|
|
setEnabled(on);
|
|
main_board->applyLedPolicy();
|
|
applyStatusPolicy();
|
|
message = "OK";
|
|
}
|
|
}
|
|
snprintf(reply, capacity, "%s", message);
|
|
return true;
|
|
}
|
|
} } // namespace mesh::leds
|