132 lines
4.4 KiB
C++
132 lines
4.4 KiB
C++
#include "DisplayRotationSettings.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
namespace mesh { namespace ui {
|
|
namespace {
|
|
FILESYSTEM* settings_fs = nullptr;
|
|
uint16_t degrees = 0;
|
|
const char* const path = "/display_rotation";
|
|
const char* const backup = "/display_rotation.bak";
|
|
const char* const temporary = "/display_rotation.tmp";
|
|
|
|
void encode(uint16_t value, uint8_t (&data)[6]) {
|
|
data[0] = 'D'; data[1] = 'R'; data[2] = 1;
|
|
data[3] = value & 255; data[4] = value >> 8;
|
|
data[5] = 0;
|
|
for (unsigned i = 0; i < 5; ++i) data[5] ^= data[i];
|
|
}
|
|
|
|
bool valid(uint16_t value) { return value <= 270 && value % 90 == 0; }
|
|
|
|
bool readPrefs(const char* name, uint16_t& value) {
|
|
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
|
File file(*settings_fs);
|
|
if (!file.open(name, FILE_O_READ)) return false;
|
|
#else
|
|
File file = settings_fs->open(name, "r");
|
|
if (!file) return false;
|
|
#endif
|
|
uint8_t data[6], expected[6];
|
|
const bool complete = file.size() == sizeof(data)
|
|
&& file.read(data, sizeof(data)) == sizeof(data);
|
|
file.close();
|
|
if (!complete) return false;
|
|
value = uint16_t(data[3]) | (uint16_t(data[4]) << 8);
|
|
encode(value, expected);
|
|
return valid(value) && memcmp(data, expected, sizeof(data)) == 0;
|
|
}
|
|
|
|
bool savePrefs(uint16_t value) {
|
|
if (!settings_fs) return false;
|
|
settings_fs->remove(temporary);
|
|
if (settings_fs->exists(temporary)) return false;
|
|
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
|
File file(*settings_fs);
|
|
if (!file.open(temporary, FILE_O_WRITE)) return false;
|
|
#elif defined(RP2040_PLATFORM)
|
|
File file = settings_fs->open(temporary, "w");
|
|
if (!file) return false;
|
|
#else
|
|
File file = settings_fs->open(temporary, "w", true);
|
|
if (!file) return false;
|
|
#endif
|
|
uint8_t data[6];
|
|
encode(value, data);
|
|
const bool written = file.write(data, sizeof(data)) == sizeof(data);
|
|
file.close();
|
|
uint16_t checked = 0;
|
|
if (!written || !readPrefs(temporary, checked) || checked != value) return false;
|
|
if (settings_fs->exists(backup) && !settings_fs->remove(backup)) return false;
|
|
if (settings_fs->exists(path) && !settings_fs->rename(path, backup)) return false;
|
|
if (!settings_fs->rename(temporary, path)) {
|
|
if (settings_fs->exists(backup)) settings_fs->rename(backup, path);
|
|
return false;
|
|
}
|
|
settings_fs->remove(backup);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool loadDisplayRotationSettings(FILESYSTEM* fs) {
|
|
settings_fs = fs;
|
|
degrees = 0;
|
|
if (!fs) return false;
|
|
uint16_t loaded = 0;
|
|
bool found = readPrefs(path, loaded);
|
|
if (!found && readPrefs(backup, loaded)) {
|
|
found = true;
|
|
fs->remove(path);
|
|
fs->rename(backup, path);
|
|
}
|
|
if (found) degrees = loaded;
|
|
return found;
|
|
}
|
|
|
|
uint16_t displayRotationDegrees() { return degrees; }
|
|
|
|
bool handleDisplayRotationCommand(const char* command, char* reply,
|
|
size_t reply_size, bool supported) {
|
|
const bool get = strncmp(command, "get ", 4) == 0;
|
|
const bool set = strncmp(command, "set ", 4) == 0;
|
|
if (!get && !set) return false;
|
|
const char* key = command + 4;
|
|
constexpr size_t key_length = sizeof("display.rotation") - 1;
|
|
if (strncmp(key, "display.rotation", key_length) != 0
|
|
|| (key[key_length] != 0 && key[key_length] != ' ')) return false;
|
|
if (!supported) {
|
|
snprintf(reply, reply_size, "Error: display rotation unsupported");
|
|
return true;
|
|
}
|
|
const char* value = key + key_length;
|
|
if (get) {
|
|
if (*value) snprintf(reply, reply_size, "Error: unexpected argument");
|
|
else if (degrees == 0) snprintf(reply, reply_size, "display.rotation default");
|
|
else snprintf(reply, reply_size, "display.rotation %u", unsigned(degrees));
|
|
return true;
|
|
}
|
|
while (*value == ' ') ++value;
|
|
unsigned candidate = 0;
|
|
bool parsed = *value != 0;
|
|
for (const char* p = value; *p && parsed; ++p) {
|
|
parsed = *p >= '0' && *p <= '9';
|
|
if (parsed) {
|
|
candidate = candidate * 10 + unsigned(*p - '0');
|
|
parsed = candidate <= 270;
|
|
}
|
|
}
|
|
if (!parsed || !valid(candidate)) {
|
|
snprintf(reply, reply_size, "Error: use set display.rotation <0|90|180|270>");
|
|
} else if (!savePrefs(uint16_t(candidate))) {
|
|
snprintf(reply, reply_size, "Error: display rotation save failed");
|
|
} else {
|
|
degrees = uint16_t(candidate);
|
|
if (degrees == 0) snprintf(reply, reply_size, "OK - display rotation reset to board default");
|
|
else snprintf(reply, reply_size, "OK - display rotation %u", unsigned(degrees));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
}} // namespace mesh::ui
|