Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

491 lines
12 KiB

7 years ago
6 years ago
  1. /*
  2. SETTINGS MODULE
  3. Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #include "settings.h"
  6. #include <ArduinoJson.h>
  7. #include <vector>
  8. #include <cstdlib>
  9. // -----------------------------------------------------------------------------
  10. // (HACK) Embedis storage format, reverse engineered
  11. // -----------------------------------------------------------------------------
  12. unsigned long settingsSize() {
  13. unsigned pos = SPI_FLASH_SEC_SIZE - 1;
  14. while (size_t len = EEPROMr.read(pos)) {
  15. if (0xFF == len) break;
  16. pos = pos - len - 2;
  17. }
  18. return SPI_FLASH_SEC_SIZE - pos + EEPROM_DATA_END;
  19. }
  20. // --------------------------------------------------------------------------
  21. namespace settings {
  22. namespace internal {
  23. uint32_t u32fromString(const String& string, int base) {
  24. const char *ptr = string.c_str();
  25. char *value_endptr = nullptr;
  26. // invalidate the whole string when invalid chars are detected
  27. const auto value = strtoul(ptr, &value_endptr, base);
  28. if (value_endptr == ptr || value_endptr[0] != '\0') {
  29. return 0;
  30. }
  31. return value;
  32. }
  33. // --------------------------------------------------------------------------
  34. template <>
  35. float convert(const String& value) {
  36. return atof(value.c_str());
  37. }
  38. template <>
  39. double convert(const String& value) {
  40. return atof(value.c_str());
  41. }
  42. template <>
  43. int convert(const String& value) {
  44. return value.toInt();
  45. }
  46. template <>
  47. long convert(const String& value) {
  48. return value.toInt();
  49. }
  50. template <>
  51. bool convert(const String& value) {
  52. return convert<int>(value) == 1;
  53. }
  54. template <>
  55. unsigned long convert(const String& value) {
  56. if (!value.length()) {
  57. return 0;
  58. }
  59. int base = 10;
  60. if (value.length() > 2) {
  61. if (value.startsWith("0b")) {
  62. base = 2;
  63. } else if (value.startsWith("0o")) {
  64. base = 8;
  65. } else if (value.startsWith("0x")) {
  66. base = 16;
  67. }
  68. }
  69. return u32fromString((base == 10) ? value : value.substring(2), base);
  70. }
  71. template <>
  72. unsigned int convert(const String& value) {
  73. return convert<unsigned long>(value);
  74. }
  75. template <>
  76. unsigned short convert(const String& value) {
  77. return convert<unsigned long>(value);
  78. }
  79. template <>
  80. unsigned char convert(const String& value) {
  81. return convert<unsigned long>(value);
  82. }
  83. } // namespace settings::internal
  84. } // namespace settings
  85. // -----------------------------------------------------------------------------
  86. size_t settingsKeyCount() {
  87. unsigned count = 0;
  88. unsigned pos = SPI_FLASH_SEC_SIZE - 1;
  89. while (size_t len = EEPROMr.read(pos)) {
  90. if (0xFF == len) break;
  91. pos = pos - len - 2;
  92. len = EEPROMr.read(pos);
  93. pos = pos - len - 2;
  94. count ++;
  95. }
  96. return count;
  97. }
  98. String settingsKeyName(unsigned int index) {
  99. String s;
  100. unsigned count = 0;
  101. unsigned pos = SPI_FLASH_SEC_SIZE - 1;
  102. while (size_t len = EEPROMr.read(pos)) {
  103. if (0xFF == len) break;
  104. pos = pos - len - 2;
  105. if (count == index) {
  106. s.reserve(len);
  107. for (unsigned char i = 0 ; i < len; i++) {
  108. s += (char) EEPROMr.read(pos + i + 1);
  109. }
  110. break;
  111. }
  112. count++;
  113. len = EEPROMr.read(pos);
  114. pos = pos - len - 2;
  115. }
  116. return s;
  117. }
  118. /*
  119. struct SettingsKeys {
  120. struct iterator {
  121. iterator(size_t total) :
  122. total(total)
  123. {}
  124. iterator& operator++() {
  125. if (total && (current_index < (total - 1))) {
  126. ++current_index
  127. current_value = settingsKeyName(current_index);
  128. return *this;
  129. }
  130. return end();
  131. }
  132. iterator operator++(int) {
  133. iterator val = *this;
  134. ++(*this);
  135. return val;
  136. }
  137. operator String() {
  138. return (current_index < total) ? current_value : empty_value;
  139. }
  140. bool operator ==(iterator& const other) const {
  141. return (total == other.total) && (current_index == other.current_index);
  142. }
  143. bool operator !=(iterator& const other) const {
  144. return !(*this == other);
  145. }
  146. using difference_type = size_t;
  147. using value_type = size_t;
  148. using pointer = const size_t*;
  149. using reference = const size_t&;
  150. using iterator_category = std::forward_iterator_tag;
  151. const size_t total;
  152. String empty_value;
  153. String current_value;
  154. size_t current_index = 0;
  155. };
  156. iterator begin() {
  157. return iterator {total};
  158. }
  159. iterator end() {
  160. return iterator {0};
  161. }
  162. };
  163. */
  164. std::vector<String> settingsKeys() {
  165. // Get sorted list of keys
  166. std::vector<String> keys;
  167. //unsigned int size = settingsKeyCount();
  168. auto size = settingsKeyCount();
  169. for (unsigned int i=0; i<size; i++) {
  170. //String key = settingsKeyName(i);
  171. String key = settingsKeyName(i);
  172. bool inserted = false;
  173. for (unsigned char j=0; j<keys.size(); j++) {
  174. // Check if we have to insert it before the current element
  175. if (keys[j].compareTo(key) > 0) {
  176. keys.insert(keys.begin() + j, key);
  177. inserted = true;
  178. break;
  179. }
  180. }
  181. // If we could not insert it, just push it at the end
  182. if (!inserted) keys.push_back(key);
  183. }
  184. return keys;
  185. }
  186. static std::vector<settings_key_match_t> _settings_matchers;
  187. void settingsRegisterDefaults(const settings_key_match_t& matcher) {
  188. _settings_matchers.push_back(matcher);
  189. }
  190. String settingsQueryDefaults(const String& key) {
  191. for (auto& matcher : _settings_matchers) {
  192. if (matcher.match(key.c_str())) {
  193. return matcher.key(key);
  194. }
  195. }
  196. return String();
  197. }
  198. // -----------------------------------------------------------------------------
  199. // Key-value API
  200. // -----------------------------------------------------------------------------
  201. String settings_key_t::toString() const {
  202. if (index < 0) {
  203. return value;
  204. } else {
  205. return value + index;
  206. }
  207. }
  208. settings_move_key_t _moveKeys(const String& from, const String& to, unsigned char index) {
  209. return settings_move_key_t {{from, index}, {to, index}};
  210. }
  211. void moveSetting(const String& from, const String& to) {
  212. const auto value = getSetting(from);
  213. if (value.length() > 0) setSetting(to, value);
  214. delSetting(from);
  215. }
  216. void moveSetting(const String& from, const String& to, unsigned char index) {
  217. const auto keys = _moveKeys(from, to, index);
  218. const auto value = getSetting(keys.first);
  219. if (value.length() > 0) setSetting(keys.second, value);
  220. delSetting(keys.first);
  221. }
  222. void moveSettings(const String& from, const String& to) {
  223. unsigned char index = 0;
  224. while (index < 100) {
  225. const auto keys = _moveKeys(from, to, index);
  226. const auto value = getSetting(keys.first);
  227. if (value.length() == 0) break;
  228. setSetting(keys.second, value);
  229. delSetting(keys.first);
  230. ++index;
  231. }
  232. }
  233. #if 0
  234. template<typename R, settings::internal::convert_t<R> Rfunc = settings::internal::convert>
  235. R getSetting(const settings_key_t& key, R defaultValue) {
  236. String value;
  237. if (!Embedis::get(key.toString(), value)) {
  238. return defaultValue;
  239. }
  240. return Rfunc(value);
  241. }
  242. #endif
  243. template<>
  244. String getSetting(const settings_key_t& key, String defaultValue) {
  245. String value;
  246. if (!Embedis::get(key.toString(), value)) {
  247. value = defaultValue;
  248. }
  249. return value;
  250. }
  251. template
  252. bool getSetting(const settings_key_t& key, bool defaultValue);
  253. template
  254. int getSetting(const settings_key_t& key, int defaultValue);
  255. template
  256. long getSetting(const settings_key_t& key, long defaultValue);
  257. template
  258. unsigned char getSetting(const settings_key_t& key, unsigned char defaultValue);
  259. template
  260. unsigned short getSetting(const settings_key_t& key, unsigned short defaultValue);
  261. template
  262. unsigned int getSetting(const settings_key_t& key, unsigned int defaultValue);
  263. template
  264. unsigned long getSetting(const settings_key_t& key, unsigned long defaultValue);
  265. template
  266. float getSetting(const settings_key_t& key, float defaultValue);
  267. template
  268. double getSetting(const settings_key_t& key, double defaultValue);
  269. String getSetting(const settings_key_t& key) {
  270. static const String defaultValue("");
  271. return getSetting(key, defaultValue);
  272. }
  273. String getSetting(const settings_key_t& key, const char* defaultValue) {
  274. return getSetting(key, String(defaultValue));
  275. }
  276. String getSetting(const settings_key_t& key, const __FlashStringHelper* defaultValue) {
  277. return getSetting(key, String(defaultValue));
  278. }
  279. template<>
  280. bool setSetting(const settings_key_t& key, const String& value) {
  281. return Embedis::set(key.toString(), value);
  282. }
  283. bool delSetting(const settings_key_t& key) {
  284. return Embedis::del(key.toString());
  285. }
  286. bool hasSetting(const settings_key_t& key) {
  287. String value;
  288. return Embedis::get(key.toString(), value);
  289. }
  290. void saveSettings() {
  291. #if not SETTINGS_AUTOSAVE
  292. eepromCommit();
  293. #endif
  294. }
  295. void resetSettings() {
  296. for (unsigned int i = 0; i < EEPROM_SIZE; i++) {
  297. EEPROMr.write(i, 0xFF);
  298. }
  299. EEPROMr.commit();
  300. }
  301. // -----------------------------------------------------------------------------
  302. // API
  303. // -----------------------------------------------------------------------------
  304. size_t settingsMaxSize() {
  305. size_t size = EEPROM_SIZE;
  306. if (size > SPI_FLASH_SEC_SIZE) size = SPI_FLASH_SEC_SIZE;
  307. size = (size + 3) & (~3);
  308. return size;
  309. }
  310. bool settingsRestoreJson(JsonObject& data) {
  311. // Check this is an ESPurna configuration file (must have "app":"ESPURNA")
  312. const char* app = data["app"];
  313. if (!app || strcmp(app, APP_NAME) != 0) {
  314. DEBUG_MSG_P(PSTR("[SETTING] Wrong or missing 'app' key\n"));
  315. return false;
  316. }
  317. // Clear settings
  318. bool is_backup = data["backup"];
  319. if (is_backup) {
  320. for (unsigned int i = EEPROM_DATA_END; i < SPI_FLASH_SEC_SIZE; i++) {
  321. EEPROMr.write(i, 0xFF);
  322. }
  323. }
  324. // Dump settings to memory buffer
  325. for (auto element : data) {
  326. if (strcmp(element.key, "app") == 0) continue;
  327. if (strcmp(element.key, "version") == 0) continue;
  328. if (strcmp(element.key, "backup") == 0) continue;
  329. setSetting(element.key, element.value.as<char*>());
  330. }
  331. // Persist to EEPROM
  332. saveSettings();
  333. DEBUG_MSG_P(PSTR("[SETTINGS] Settings restored successfully\n"));
  334. return true;
  335. }
  336. bool settingsRestoreJson(char* json_string, size_t json_buffer_size) {
  337. // XXX: as of right now, arduinojson cannot trigger callbacks for each key individually
  338. // Manually separating kv pairs can allow to parse only a small chunk, since we know that there is only string type used (even with bools / ints). Can be problematic when parsing data that was not generated by us.
  339. // Current parsing method is limited only by keys (~sizeof(uintptr_t) bytes per key, data is not copied when string is non-const)
  340. DynamicJsonBuffer jsonBuffer(json_buffer_size);
  341. JsonObject& root = jsonBuffer.parseObject((char *) json_string);
  342. if (!root.success()) {
  343. DEBUG_MSG_P(PSTR("[SETTINGS] JSON parsing error\n"));
  344. return false;
  345. }
  346. return settingsRestoreJson(root);
  347. }
  348. void settingsGetJson(JsonObject& root) {
  349. // Get sorted list of keys
  350. auto keys = settingsKeys();
  351. // Add the key-values to the json object
  352. for (unsigned int i=0; i<keys.size(); i++) {
  353. String value = getSetting(keys[i]);
  354. root[keys[i]] = value;
  355. }
  356. }
  357. void settingsProcessConfig(const settings_cfg_list_t& config, settings_filter_t filter) {
  358. for (auto& entry : config) {
  359. String value = getSetting(entry.key, entry.default_value);
  360. if (filter) {
  361. value = filter(value);
  362. }
  363. if (value.equals(entry.setting)) continue;
  364. entry.setting = std::move(value);
  365. }
  366. }
  367. // -----------------------------------------------------------------------------
  368. // Initialization
  369. // -----------------------------------------------------------------------------
  370. void settingsSetup() {
  371. Embedis::dictionary( F("EEPROM"),
  372. SPI_FLASH_SEC_SIZE,
  373. [](size_t pos) -> char { return EEPROMr.read(pos); },
  374. [](size_t pos, char value) { EEPROMr.write(pos, value); },
  375. #if SETTINGS_AUTOSAVE
  376. []() { eepromCommit(); }
  377. #else
  378. []() {}
  379. #endif
  380. );
  381. }