2019-05-10 05:17:29 +00:00
|
|
|
#pragma once
|
2021-03-29 08:10:55 +00:00
|
|
|
#include <Figments.h>
|
2023-02-18 15:14:00 +00:00
|
|
|
#include "JsonCoordinateMapping.h"
|
2023-02-20 06:07:32 +00:00
|
|
|
#include <ArduinoJson.h>
|
2023-12-11 06:59:47 +00:00
|
|
|
#include <LittleFS.h>
|
2023-02-20 06:07:32 +00:00
|
|
|
|
|
|
|
class Configuration {
|
|
|
|
public:
|
|
|
|
Configuration(const JsonObject& data);
|
|
|
|
const char* get(const char* key, const char* defaultVal) const;
|
|
|
|
int get(const char* key, int defaultVal) const;
|
|
|
|
bool get(const char* key, bool defaultVal) const;
|
|
|
|
|
|
|
|
private:
|
|
|
|
const JsonObject& m_json;
|
|
|
|
};
|
|
|
|
|
|
|
|
class ConfigTaskMixin : public virtual Loopable {
|
|
|
|
public:
|
|
|
|
void handleEvent(const InputEvent &evt) override;
|
|
|
|
|
|
|
|
void loop() override {}
|
|
|
|
|
|
|
|
virtual void handleConfigChange(const Configuration& config) {}
|
|
|
|
};
|
2019-05-10 05:17:29 +00:00
|
|
|
|
|
|
|
struct HardwareConfig {
|
2022-06-11 09:02:27 +00:00
|
|
|
uint8_t version = 3;
|
2019-05-10 05:17:29 +00:00
|
|
|
uint8_t checksum = 0;
|
|
|
|
struct Data {
|
2023-02-18 15:14:00 +00:00
|
|
|
char loadedProfile[16] = {0};
|
2021-03-29 00:18:03 +00:00
|
|
|
uint8_t lastRed = 255;
|
|
|
|
uint8_t lastGreen = 255;
|
|
|
|
uint8_t lastBlue = 255;
|
|
|
|
char lastScene[16] = {0};
|
2019-05-10 05:17:29 +00:00
|
|
|
};
|
|
|
|
Data data;
|
|
|
|
|
|
|
|
static HardwareConfig load();
|
|
|
|
void save();
|
|
|
|
bool isValid() const;
|
|
|
|
|
2023-12-11 06:59:26 +00:00
|
|
|
static constexpr uint16_t MAX_LED_NUM = 512;
|
2021-03-28 01:19:55 +00:00
|
|
|
|
2019-05-10 05:17:29 +00:00
|
|
|
private:
|
|
|
|
uint8_t getCRC() const;
|
|
|
|
|
|
|
|
static constexpr uint8_t CRC7_POLY = 0x91;
|
|
|
|
};
|
|
|
|
|
|
|
|
// A task that manages the EEPROM settings and coord mapping when modified via
|
|
|
|
// Particle. This allows for multiple devices with wildly different displays to
|
|
|
|
// run the same code
|
|
|
|
struct ConfigService: public Task {
|
2023-02-18 15:33:09 +00:00
|
|
|
ConfigService() : Task("Configuration") {state = Task::Running;}
|
2019-05-10 05:17:29 +00:00
|
|
|
void onStart();
|
|
|
|
void loop() override;
|
|
|
|
void handleEvent(const InputEvent &evt) override;
|
2023-02-18 15:14:00 +00:00
|
|
|
const CoordinateMapping* coordMap() const { return &m_jsonMap; }
|
|
|
|
const char* loadedProfile() const;
|
2023-02-18 16:15:21 +00:00
|
|
|
void overrideProfile(const char* profileName);
|
2023-02-18 17:44:44 +00:00
|
|
|
const char* getConfigValue(const char* key) const;
|
2023-12-11 06:59:47 +00:00
|
|
|
const std::vector<Command>& commands() const override;
|
|
|
|
|
|
|
|
struct filename_iterator: public std::iterator<std::input_iterator_tag, const char*> {
|
|
|
|
Dir dir;
|
|
|
|
String ret;
|
|
|
|
bool valid;
|
|
|
|
const char* suffix;
|
|
|
|
explicit filename_iterator() : suffix(NULL), valid(false) {}
|
|
|
|
explicit filename_iterator(const char* path, const char* suffix) : dir(LittleFS.openDir(path)), valid(true), suffix(suffix) {
|
|
|
|
next();
|
|
|
|
}
|
|
|
|
|
|
|
|
void next() {
|
|
|
|
if (!valid) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int extPos = -1;
|
|
|
|
do {
|
|
|
|
valid = dir.next();
|
|
|
|
Log.info("valid %F", valid);
|
|
|
|
if (valid) {
|
|
|
|
String fname = dir.fileName();
|
|
|
|
extPos = fname.lastIndexOf(suffix);
|
|
|
|
Log.info("compare %s %d", fname.c_str(), extPos);
|
|
|
|
if (extPos != -1) {
|
|
|
|
ret = fname.substring(0, extPos);
|
|
|
|
Log.info("found %s", ret.c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (valid && extPos == -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
filename_iterator& operator++() {
|
|
|
|
next();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
filename_iterator& operator++(int) {filename_iterator ret = *this; ++(*this); return ret;}
|
|
|
|
bool operator==(const filename_iterator &other) const { return valid == other.valid;}
|
|
|
|
bool operator!=(const filename_iterator &other) const { return !(*this == other); }
|
|
|
|
const char* operator*() const {
|
|
|
|
if (!valid) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return ret.c_str();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
filename_iterator mapsBegin() const { return filename_iterator("/maps/", ".json"); }
|
|
|
|
filename_iterator mapsEnd() const { return filename_iterator(); }
|
|
|
|
|
|
|
|
filename_iterator profilesBegin() const { return filename_iterator("/profiles/", ".json"); }
|
|
|
|
filename_iterator profilesEnd() const { return filename_iterator(); }
|
2019-05-10 05:17:29 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
HardwareConfig m_config;
|
2023-02-18 15:14:00 +00:00
|
|
|
JsonCoordinateMapping m_jsonMap;
|
2023-02-18 16:15:21 +00:00
|
|
|
const char* m_overrideProfile = nullptr;
|
2023-02-18 15:14:00 +00:00
|
|
|
|
2023-02-19 17:41:55 +00:00
|
|
|
bool loadProfile(const char* name);
|
|
|
|
bool loadMap(const String& mapName);
|
2023-12-20 08:13:23 +00:00
|
|
|
|
|
|
|
void doSave(Args& args, Print& print);
|
|
|
|
void doSetProfile(Args& args, Print& print);
|
|
|
|
void doCoordMap(Args& args, Print& print);
|
|
|
|
void doMapList(Args& args, Print& print);
|
2019-05-10 05:17:29 +00:00
|
|
|
};
|