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.

549 lines
14 KiB

Rework settings (#2282) * wip based on early draft. todo benchmarking * fixup eraser, assume keys are unique * fix cursor copy, test removal at random * small benchmark via permutations. todo lambdas and novirtual * fix empty condition / reset * overwrite optimizations, fix move offsets overflows * ...erase using 0xff instead of 0 * test the theory with code, different length kv were bugged * try to check for out-of-bounds writes / reads * style * trying to fix mover again * clarify length, defend against reading len on edge * fix uncommited rewind change * prove space assumptions * more concise traces, fix move condition (agrh!!!) * slightly more internal knowledge (estimates API?) * make sure cursor is only valid within the range * ensure 0 does not blow things * go back up * cursor comments * comments * rewrite writes through cursor * in del too * estimate kv storage requirements, return available size * move raw erase / move into a method, allow ::set to avoid scanning storage twice * refactor naming, use in code * amend storage slicing test * fix crash handler offsets, cleanup configuration * start -> begin * eeprom readiness * dependencies * unused * SPI_FLASH constants for older Core * vtables -> templates * less include dependencies * gcov help, move estimate outside of the class * writer position can never match, use begin + offset * tweak save_crash to trigger only once in a serious crash * doh, header function should be inline * foreach api, tweak structs for public api * use test helper class * when not using foreach, move cursor reset closer to the loop using read_kv * coverage comments, fix typo in tests decltype * ensure set() does not break with offset * make codacy happy again
4 years ago
Rework settings (#2282) * wip based on early draft. todo benchmarking * fixup eraser, assume keys are unique * fix cursor copy, test removal at random * small benchmark via permutations. todo lambdas and novirtual * fix empty condition / reset * overwrite optimizations, fix move offsets overflows * ...erase using 0xff instead of 0 * test the theory with code, different length kv were bugged * try to check for out-of-bounds writes / reads * style * trying to fix mover again * clarify length, defend against reading len on edge * fix uncommited rewind change * prove space assumptions * more concise traces, fix move condition (agrh!!!) * slightly more internal knowledge (estimates API?) * make sure cursor is only valid within the range * ensure 0 does not blow things * go back up * cursor comments * comments * rewrite writes through cursor * in del too * estimate kv storage requirements, return available size * move raw erase / move into a method, allow ::set to avoid scanning storage twice * refactor naming, use in code * amend storage slicing test * fix crash handler offsets, cleanup configuration * start -> begin * eeprom readiness * dependencies * unused * SPI_FLASH constants for older Core * vtables -> templates * less include dependencies * gcov help, move estimate outside of the class * writer position can never match, use begin + offset * tweak save_crash to trigger only once in a serious crash * doh, header function should be inline * foreach api, tweak structs for public api * use test helper class * when not using foreach, move cursor reset closer to the loop using read_kv * coverage comments, fix typo in tests decltype * ensure set() does not break with offset * make codacy happy again
4 years ago
Terminal: change command-line parser (#2247) Change the underlying command line handling: - switch to a custom parser, inspired by redis / sds - update terminalRegisterCommand signature, pass only bare minimum - clean-up `help` & `commands`. update settings `set`, `get` and `del` - allow our custom test suite to run command-line tests - clean-up Stream IO to allow us to print large things into debug stream (for example, `eeprom.dump`) - send parsing errors to the debug log As a proof of concept, introduce `TERMINAL_MQTT_SUPPORT` and `TERMINAL_WEB_API_SUPPORT` - MQTT subscribes to the `<root>/cmd/set` and sends response to the `<root>/cmd`. We can't output too much, as we don't have any large-send API. - Web API listens to the `/api/cmd?apikey=...&line=...` (or PUT, params inside the body). This one is intended as a possible replacement of the `API_SUPPORT`. Internals introduce a 'task' around the AsyncWebServerRequest object that will simulate what WiFiClient does and push data into it continuously, switching between CONT and SYS. Both are experimental. We only accept a single command and not every command is updated to use Print `ctx.output` object. We are also somewhat limited by the Print / Stream overall, perhaps I am overestimating the usefulness of Arduino compatibility to such an extent :) Web API handler can also sometimes show only part of the result, whenever the command tries to yield() by itself waiting for something. Perhaps we would need to create a custom request handler for that specific use-case.
4 years ago
Rework settings (#2282) * wip based on early draft. todo benchmarking * fixup eraser, assume keys are unique * fix cursor copy, test removal at random * small benchmark via permutations. todo lambdas and novirtual * fix empty condition / reset * overwrite optimizations, fix move offsets overflows * ...erase using 0xff instead of 0 * test the theory with code, different length kv were bugged * try to check for out-of-bounds writes / reads * style * trying to fix mover again * clarify length, defend against reading len on edge * fix uncommited rewind change * prove space assumptions * more concise traces, fix move condition (agrh!!!) * slightly more internal knowledge (estimates API?) * make sure cursor is only valid within the range * ensure 0 does not blow things * go back up * cursor comments * comments * rewrite writes through cursor * in del too * estimate kv storage requirements, return available size * move raw erase / move into a method, allow ::set to avoid scanning storage twice * refactor naming, use in code * amend storage slicing test * fix crash handler offsets, cleanup configuration * start -> begin * eeprom readiness * dependencies * unused * SPI_FLASH constants for older Core * vtables -> templates * less include dependencies * gcov help, move estimate outside of the class * writer position can never match, use begin + offset * tweak save_crash to trigger only once in a serious crash * doh, header function should be inline * foreach api, tweak structs for public api * use test helper class * when not using foreach, move cursor reset closer to the loop using read_kv * coverage comments, fix typo in tests decltype * ensure set() does not break with offset * make codacy happy again
4 years ago
Terminal: change command-line parser (#2247) Change the underlying command line handling: - switch to a custom parser, inspired by redis / sds - update terminalRegisterCommand signature, pass only bare minimum - clean-up `help` & `commands`. update settings `set`, `get` and `del` - allow our custom test suite to run command-line tests - clean-up Stream IO to allow us to print large things into debug stream (for example, `eeprom.dump`) - send parsing errors to the debug log As a proof of concept, introduce `TERMINAL_MQTT_SUPPORT` and `TERMINAL_WEB_API_SUPPORT` - MQTT subscribes to the `<root>/cmd/set` and sends response to the `<root>/cmd`. We can't output too much, as we don't have any large-send API. - Web API listens to the `/api/cmd?apikey=...&line=...` (or PUT, params inside the body). This one is intended as a possible replacement of the `API_SUPPORT`. Internals introduce a 'task' around the AsyncWebServerRequest object that will simulate what WiFiClient does and push data into it continuously, switching between CONT and SYS. Both are experimental. We only accept a single command and not every command is updated to use Print `ctx.output` object. We are also somewhat limited by the Print / Stream overall, perhaps I am overestimating the usefulness of Arduino compatibility to such an extent :) Web API handler can also sometimes show only part of the result, whenever the command tries to yield() by itself waiting for something. Perhaps we would need to create a custom request handler for that specific use-case.
4 years ago
Rework settings (#2282) * wip based on early draft. todo benchmarking * fixup eraser, assume keys are unique * fix cursor copy, test removal at random * small benchmark via permutations. todo lambdas and novirtual * fix empty condition / reset * overwrite optimizations, fix move offsets overflows * ...erase using 0xff instead of 0 * test the theory with code, different length kv were bugged * try to check for out-of-bounds writes / reads * style * trying to fix mover again * clarify length, defend against reading len on edge * fix uncommited rewind change * prove space assumptions * more concise traces, fix move condition (agrh!!!) * slightly more internal knowledge (estimates API?) * make sure cursor is only valid within the range * ensure 0 does not blow things * go back up * cursor comments * comments * rewrite writes through cursor * in del too * estimate kv storage requirements, return available size * move raw erase / move into a method, allow ::set to avoid scanning storage twice * refactor naming, use in code * amend storage slicing test * fix crash handler offsets, cleanup configuration * start -> begin * eeprom readiness * dependencies * unused * SPI_FLASH constants for older Core * vtables -> templates * less include dependencies * gcov help, move estimate outside of the class * writer position can never match, use begin + offset * tweak save_crash to trigger only once in a serious crash * doh, header function should be inline * foreach api, tweak structs for public api * use test helper class * when not using foreach, move cursor reset closer to the loop using read_kv * coverage comments, fix typo in tests decltype * ensure set() does not break with offset * make codacy happy again
4 years ago
Rework settings (#2282) * wip based on early draft. todo benchmarking * fixup eraser, assume keys are unique * fix cursor copy, test removal at random * small benchmark via permutations. todo lambdas and novirtual * fix empty condition / reset * overwrite optimizations, fix move offsets overflows * ...erase using 0xff instead of 0 * test the theory with code, different length kv were bugged * try to check for out-of-bounds writes / reads * style * trying to fix mover again * clarify length, defend against reading len on edge * fix uncommited rewind change * prove space assumptions * more concise traces, fix move condition (agrh!!!) * slightly more internal knowledge (estimates API?) * make sure cursor is only valid within the range * ensure 0 does not blow things * go back up * cursor comments * comments * rewrite writes through cursor * in del too * estimate kv storage requirements, return available size * move raw erase / move into a method, allow ::set to avoid scanning storage twice * refactor naming, use in code * amend storage slicing test * fix crash handler offsets, cleanup configuration * start -> begin * eeprom readiness * dependencies * unused * SPI_FLASH constants for older Core * vtables -> templates * less include dependencies * gcov help, move estimate outside of the class * writer position can never match, use begin + offset * tweak save_crash to trigger only once in a serious crash * doh, header function should be inline * foreach api, tweak structs for public api * use test helper class * when not using foreach, move cursor reset closer to the loop using read_kv * coverage comments, fix typo in tests decltype * ensure set() does not break with offset * make codacy happy again
4 years ago
Rework settings (#2282) * wip based on early draft. todo benchmarking * fixup eraser, assume keys are unique * fix cursor copy, test removal at random * small benchmark via permutations. todo lambdas and novirtual * fix empty condition / reset * overwrite optimizations, fix move offsets overflows * ...erase using 0xff instead of 0 * test the theory with code, different length kv were bugged * try to check for out-of-bounds writes / reads * style * trying to fix mover again * clarify length, defend against reading len on edge * fix uncommited rewind change * prove space assumptions * more concise traces, fix move condition (agrh!!!) * slightly more internal knowledge (estimates API?) * make sure cursor is only valid within the range * ensure 0 does not blow things * go back up * cursor comments * comments * rewrite writes through cursor * in del too * estimate kv storage requirements, return available size * move raw erase / move into a method, allow ::set to avoid scanning storage twice * refactor naming, use in code * amend storage slicing test * fix crash handler offsets, cleanup configuration * start -> begin * eeprom readiness * dependencies * unused * SPI_FLASH constants for older Core * vtables -> templates * less include dependencies * gcov help, move estimate outside of the class * writer position can never match, use begin + offset * tweak save_crash to trigger only once in a serious crash * doh, header function should be inline * foreach api, tweak structs for public api * use test helper class * when not using foreach, move cursor reset closer to the loop using read_kv * coverage comments, fix typo in tests decltype * ensure set() does not break with offset * make codacy happy again
4 years ago
Rework settings (#2282) * wip based on early draft. todo benchmarking * fixup eraser, assume keys are unique * fix cursor copy, test removal at random * small benchmark via permutations. todo lambdas and novirtual * fix empty condition / reset * overwrite optimizations, fix move offsets overflows * ...erase using 0xff instead of 0 * test the theory with code, different length kv were bugged * try to check for out-of-bounds writes / reads * style * trying to fix mover again * clarify length, defend against reading len on edge * fix uncommited rewind change * prove space assumptions * more concise traces, fix move condition (agrh!!!) * slightly more internal knowledge (estimates API?) * make sure cursor is only valid within the range * ensure 0 does not blow things * go back up * cursor comments * comments * rewrite writes through cursor * in del too * estimate kv storage requirements, return available size * move raw erase / move into a method, allow ::set to avoid scanning storage twice * refactor naming, use in code * amend storage slicing test * fix crash handler offsets, cleanup configuration * start -> begin * eeprom readiness * dependencies * unused * SPI_FLASH constants for older Core * vtables -> templates * less include dependencies * gcov help, move estimate outside of the class * writer position can never match, use begin + offset * tweak save_crash to trigger only once in a serious crash * doh, header function should be inline * foreach api, tweak structs for public api * use test helper class * when not using foreach, move cursor reset closer to the loop using read_kv * coverage comments, fix typo in tests decltype * ensure set() does not break with offset * make codacy happy again
4 years ago
Rework settings (#2282) * wip based on early draft. todo benchmarking * fixup eraser, assume keys are unique * fix cursor copy, test removal at random * small benchmark via permutations. todo lambdas and novirtual * fix empty condition / reset * overwrite optimizations, fix move offsets overflows * ...erase using 0xff instead of 0 * test the theory with code, different length kv were bugged * try to check for out-of-bounds writes / reads * style * trying to fix mover again * clarify length, defend against reading len on edge * fix uncommited rewind change * prove space assumptions * more concise traces, fix move condition (agrh!!!) * slightly more internal knowledge (estimates API?) * make sure cursor is only valid within the range * ensure 0 does not blow things * go back up * cursor comments * comments * rewrite writes through cursor * in del too * estimate kv storage requirements, return available size * move raw erase / move into a method, allow ::set to avoid scanning storage twice * refactor naming, use in code * amend storage slicing test * fix crash handler offsets, cleanup configuration * start -> begin * eeprom readiness * dependencies * unused * SPI_FLASH constants for older Core * vtables -> templates * less include dependencies * gcov help, move estimate outside of the class * writer position can never match, use begin + offset * tweak save_crash to trigger only once in a serious crash * doh, header function should be inline * foreach api, tweak structs for public api * use test helper class * when not using foreach, move cursor reset closer to the loop using read_kv * coverage comments, fix typo in tests decltype * ensure set() does not break with offset * make codacy happy again
4 years ago
Rework settings (#2282) * wip based on early draft. todo benchmarking * fixup eraser, assume keys are unique * fix cursor copy, test removal at random * small benchmark via permutations. todo lambdas and novirtual * fix empty condition / reset * overwrite optimizations, fix move offsets overflows * ...erase using 0xff instead of 0 * test the theory with code, different length kv were bugged * try to check for out-of-bounds writes / reads * style * trying to fix mover again * clarify length, defend against reading len on edge * fix uncommited rewind change * prove space assumptions * more concise traces, fix move condition (agrh!!!) * slightly more internal knowledge (estimates API?) * make sure cursor is only valid within the range * ensure 0 does not blow things * go back up * cursor comments * comments * rewrite writes through cursor * in del too * estimate kv storage requirements, return available size * move raw erase / move into a method, allow ::set to avoid scanning storage twice * refactor naming, use in code * amend storage slicing test * fix crash handler offsets, cleanup configuration * start -> begin * eeprom readiness * dependencies * unused * SPI_FLASH constants for older Core * vtables -> templates * less include dependencies * gcov help, move estimate outside of the class * writer position can never match, use begin + offset * tweak save_crash to trigger only once in a serious crash * doh, header function should be inline * foreach api, tweak structs for public api * use test helper class * when not using foreach, move cursor reset closer to the loop using read_kv * coverage comments, fix typo in tests decltype * ensure set() does not break with offset * make codacy happy again
4 years ago
6 years ago
Terminal: change command-line parser (#2247) Change the underlying command line handling: - switch to a custom parser, inspired by redis / sds - update terminalRegisterCommand signature, pass only bare minimum - clean-up `help` & `commands`. update settings `set`, `get` and `del` - allow our custom test suite to run command-line tests - clean-up Stream IO to allow us to print large things into debug stream (for example, `eeprom.dump`) - send parsing errors to the debug log As a proof of concept, introduce `TERMINAL_MQTT_SUPPORT` and `TERMINAL_WEB_API_SUPPORT` - MQTT subscribes to the `<root>/cmd/set` and sends response to the `<root>/cmd`. We can't output too much, as we don't have any large-send API. - Web API listens to the `/api/cmd?apikey=...&line=...` (or PUT, params inside the body). This one is intended as a possible replacement of the `API_SUPPORT`. Internals introduce a 'task' around the AsyncWebServerRequest object that will simulate what WiFiClient does and push data into it continuously, switching between CONT and SYS. Both are experimental. We only accept a single command and not every command is updated to use Print `ctx.output` object. We are also somewhat limited by the Print / Stream overall, perhaps I am overestimating the usefulness of Arduino compatibility to such an extent :) Web API handler can also sometimes show only part of the result, whenever the command tries to yield() by itself waiting for something. Perhaps we would need to create a custom request handler for that specific use-case.
4 years ago
Rework settings (#2282) * wip based on early draft. todo benchmarking * fixup eraser, assume keys are unique * fix cursor copy, test removal at random * small benchmark via permutations. todo lambdas and novirtual * fix empty condition / reset * overwrite optimizations, fix move offsets overflows * ...erase using 0xff instead of 0 * test the theory with code, different length kv were bugged * try to check for out-of-bounds writes / reads * style * trying to fix mover again * clarify length, defend against reading len on edge * fix uncommited rewind change * prove space assumptions * more concise traces, fix move condition (agrh!!!) * slightly more internal knowledge (estimates API?) * make sure cursor is only valid within the range * ensure 0 does not blow things * go back up * cursor comments * comments * rewrite writes through cursor * in del too * estimate kv storage requirements, return available size * move raw erase / move into a method, allow ::set to avoid scanning storage twice * refactor naming, use in code * amend storage slicing test * fix crash handler offsets, cleanup configuration * start -> begin * eeprom readiness * dependencies * unused * SPI_FLASH constants for older Core * vtables -> templates * less include dependencies * gcov help, move estimate outside of the class * writer position can never match, use begin + offset * tweak save_crash to trigger only once in a serious crash * doh, header function should be inline * foreach api, tweak structs for public api * use test helper class * when not using foreach, move cursor reset closer to the loop using read_kv * coverage comments, fix typo in tests decltype * ensure set() does not break with offset * make codacy happy again
4 years ago
Terminal: change command-line parser (#2247) Change the underlying command line handling: - switch to a custom parser, inspired by redis / sds - update terminalRegisterCommand signature, pass only bare minimum - clean-up `help` & `commands`. update settings `set`, `get` and `del` - allow our custom test suite to run command-line tests - clean-up Stream IO to allow us to print large things into debug stream (for example, `eeprom.dump`) - send parsing errors to the debug log As a proof of concept, introduce `TERMINAL_MQTT_SUPPORT` and `TERMINAL_WEB_API_SUPPORT` - MQTT subscribes to the `<root>/cmd/set` and sends response to the `<root>/cmd`. We can't output too much, as we don't have any large-send API. - Web API listens to the `/api/cmd?apikey=...&line=...` (or PUT, params inside the body). This one is intended as a possible replacement of the `API_SUPPORT`. Internals introduce a 'task' around the AsyncWebServerRequest object that will simulate what WiFiClient does and push data into it continuously, switching between CONT and SYS. Both are experimental. We only accept a single command and not every command is updated to use Print `ctx.output` object. We are also somewhat limited by the Print / Stream overall, perhaps I am overestimating the usefulness of Arduino compatibility to such an extent :) Web API handler can also sometimes show only part of the result, whenever the command tries to yield() by itself waiting for something. Perhaps we would need to create a custom request handler for that specific use-case.
4 years ago
Rework settings (#2282) * wip based on early draft. todo benchmarking * fixup eraser, assume keys are unique * fix cursor copy, test removal at random * small benchmark via permutations. todo lambdas and novirtual * fix empty condition / reset * overwrite optimizations, fix move offsets overflows * ...erase using 0xff instead of 0 * test the theory with code, different length kv were bugged * try to check for out-of-bounds writes / reads * style * trying to fix mover again * clarify length, defend against reading len on edge * fix uncommited rewind change * prove space assumptions * more concise traces, fix move condition (agrh!!!) * slightly more internal knowledge (estimates API?) * make sure cursor is only valid within the range * ensure 0 does not blow things * go back up * cursor comments * comments * rewrite writes through cursor * in del too * estimate kv storage requirements, return available size * move raw erase / move into a method, allow ::set to avoid scanning storage twice * refactor naming, use in code * amend storage slicing test * fix crash handler offsets, cleanup configuration * start -> begin * eeprom readiness * dependencies * unused * SPI_FLASH constants for older Core * vtables -> templates * less include dependencies * gcov help, move estimate outside of the class * writer position can never match, use begin + offset * tweak save_crash to trigger only once in a serious crash * doh, header function should be inline * foreach api, tweak structs for public api * use test helper class * when not using foreach, move cursor reset closer to the loop using read_kv * coverage comments, fix typo in tests decltype * ensure set() does not break with offset * make codacy happy again
4 years ago
Terminal: change command-line parser (#2247) Change the underlying command line handling: - switch to a custom parser, inspired by redis / sds - update terminalRegisterCommand signature, pass only bare minimum - clean-up `help` & `commands`. update settings `set`, `get` and `del` - allow our custom test suite to run command-line tests - clean-up Stream IO to allow us to print large things into debug stream (for example, `eeprom.dump`) - send parsing errors to the debug log As a proof of concept, introduce `TERMINAL_MQTT_SUPPORT` and `TERMINAL_WEB_API_SUPPORT` - MQTT subscribes to the `<root>/cmd/set` and sends response to the `<root>/cmd`. We can't output too much, as we don't have any large-send API. - Web API listens to the `/api/cmd?apikey=...&line=...` (or PUT, params inside the body). This one is intended as a possible replacement of the `API_SUPPORT`. Internals introduce a 'task' around the AsyncWebServerRequest object that will simulate what WiFiClient does and push data into it continuously, switching between CONT and SYS. Both are experimental. We only accept a single command and not every command is updated to use Print `ctx.output` object. We are also somewhat limited by the Print / Stream overall, perhaps I am overestimating the usefulness of Arduino compatibility to such an extent :) Web API handler can also sometimes show only part of the result, whenever the command tries to yield() by itself waiting for something. Perhaps we would need to create a custom request handler for that specific use-case.
4 years ago
Rework settings (#2282) * wip based on early draft. todo benchmarking * fixup eraser, assume keys are unique * fix cursor copy, test removal at random * small benchmark via permutations. todo lambdas and novirtual * fix empty condition / reset * overwrite optimizations, fix move offsets overflows * ...erase using 0xff instead of 0 * test the theory with code, different length kv were bugged * try to check for out-of-bounds writes / reads * style * trying to fix mover again * clarify length, defend against reading len on edge * fix uncommited rewind change * prove space assumptions * more concise traces, fix move condition (agrh!!!) * slightly more internal knowledge (estimates API?) * make sure cursor is only valid within the range * ensure 0 does not blow things * go back up * cursor comments * comments * rewrite writes through cursor * in del too * estimate kv storage requirements, return available size * move raw erase / move into a method, allow ::set to avoid scanning storage twice * refactor naming, use in code * amend storage slicing test * fix crash handler offsets, cleanup configuration * start -> begin * eeprom readiness * dependencies * unused * SPI_FLASH constants for older Core * vtables -> templates * less include dependencies * gcov help, move estimate outside of the class * writer position can never match, use begin + offset * tweak save_crash to trigger only once in a serious crash * doh, header function should be inline * foreach api, tweak structs for public api * use test helper class * when not using foreach, move cursor reset closer to the loop using read_kv * coverage comments, fix typo in tests decltype * ensure set() does not break with offset * make codacy happy again
4 years ago
Terminal: change command-line parser (#2247) Change the underlying command line handling: - switch to a custom parser, inspired by redis / sds - update terminalRegisterCommand signature, pass only bare minimum - clean-up `help` & `commands`. update settings `set`, `get` and `del` - allow our custom test suite to run command-line tests - clean-up Stream IO to allow us to print large things into debug stream (for example, `eeprom.dump`) - send parsing errors to the debug log As a proof of concept, introduce `TERMINAL_MQTT_SUPPORT` and `TERMINAL_WEB_API_SUPPORT` - MQTT subscribes to the `<root>/cmd/set` and sends response to the `<root>/cmd`. We can't output too much, as we don't have any large-send API. - Web API listens to the `/api/cmd?apikey=...&line=...` (or PUT, params inside the body). This one is intended as a possible replacement of the `API_SUPPORT`. Internals introduce a 'task' around the AsyncWebServerRequest object that will simulate what WiFiClient does and push data into it continuously, switching between CONT and SYS. Both are experimental. We only accept a single command and not every command is updated to use Print `ctx.output` object. We are also somewhat limited by the Print / Stream overall, perhaps I am overestimating the usefulness of Arduino compatibility to such an extent :) Web API handler can also sometimes show only part of the result, whenever the command tries to yield() by itself waiting for something. Perhaps we would need to create a custom request handler for that specific use-case.
4 years ago
Rework settings (#2282) * wip based on early draft. todo benchmarking * fixup eraser, assume keys are unique * fix cursor copy, test removal at random * small benchmark via permutations. todo lambdas and novirtual * fix empty condition / reset * overwrite optimizations, fix move offsets overflows * ...erase using 0xff instead of 0 * test the theory with code, different length kv were bugged * try to check for out-of-bounds writes / reads * style * trying to fix mover again * clarify length, defend against reading len on edge * fix uncommited rewind change * prove space assumptions * more concise traces, fix move condition (agrh!!!) * slightly more internal knowledge (estimates API?) * make sure cursor is only valid within the range * ensure 0 does not blow things * go back up * cursor comments * comments * rewrite writes through cursor * in del too * estimate kv storage requirements, return available size * move raw erase / move into a method, allow ::set to avoid scanning storage twice * refactor naming, use in code * amend storage slicing test * fix crash handler offsets, cleanup configuration * start -> begin * eeprom readiness * dependencies * unused * SPI_FLASH constants for older Core * vtables -> templates * less include dependencies * gcov help, move estimate outside of the class * writer position can never match, use begin + offset * tweak save_crash to trigger only once in a serious crash * doh, header function should be inline * foreach api, tweak structs for public api * use test helper class * when not using foreach, move cursor reset closer to the loop using read_kv * coverage comments, fix typo in tests decltype * ensure set() does not break with offset * make codacy happy again
4 years ago
Terminal: change command-line parser (#2247) Change the underlying command line handling: - switch to a custom parser, inspired by redis / sds - update terminalRegisterCommand signature, pass only bare minimum - clean-up `help` & `commands`. update settings `set`, `get` and `del` - allow our custom test suite to run command-line tests - clean-up Stream IO to allow us to print large things into debug stream (for example, `eeprom.dump`) - send parsing errors to the debug log As a proof of concept, introduce `TERMINAL_MQTT_SUPPORT` and `TERMINAL_WEB_API_SUPPORT` - MQTT subscribes to the `<root>/cmd/set` and sends response to the `<root>/cmd`. We can't output too much, as we don't have any large-send API. - Web API listens to the `/api/cmd?apikey=...&line=...` (or PUT, params inside the body). This one is intended as a possible replacement of the `API_SUPPORT`. Internals introduce a 'task' around the AsyncWebServerRequest object that will simulate what WiFiClient does and push data into it continuously, switching between CONT and SYS. Both are experimental. We only accept a single command and not every command is updated to use Print `ctx.output` object. We are also somewhat limited by the Print / Stream overall, perhaps I am overestimating the usefulness of Arduino compatibility to such an extent :) Web API handler can also sometimes show only part of the result, whenever the command tries to yield() by itself waiting for something. Perhaps we would need to create a custom request handler for that specific use-case.
4 years ago
Rework settings (#2282) * wip based on early draft. todo benchmarking * fixup eraser, assume keys are unique * fix cursor copy, test removal at random * small benchmark via permutations. todo lambdas and novirtual * fix empty condition / reset * overwrite optimizations, fix move offsets overflows * ...erase using 0xff instead of 0 * test the theory with code, different length kv were bugged * try to check for out-of-bounds writes / reads * style * trying to fix mover again * clarify length, defend against reading len on edge * fix uncommited rewind change * prove space assumptions * more concise traces, fix move condition (agrh!!!) * slightly more internal knowledge (estimates API?) * make sure cursor is only valid within the range * ensure 0 does not blow things * go back up * cursor comments * comments * rewrite writes through cursor * in del too * estimate kv storage requirements, return available size * move raw erase / move into a method, allow ::set to avoid scanning storage twice * refactor naming, use in code * amend storage slicing test * fix crash handler offsets, cleanup configuration * start -> begin * eeprom readiness * dependencies * unused * SPI_FLASH constants for older Core * vtables -> templates * less include dependencies * gcov help, move estimate outside of the class * writer position can never match, use begin + offset * tweak save_crash to trigger only once in a serious crash * doh, header function should be inline * foreach api, tweak structs for public api * use test helper class * when not using foreach, move cursor reset closer to the loop using read_kv * coverage comments, fix typo in tests decltype * ensure set() does not break with offset * make codacy happy again
4 years ago
Terminal: change command-line parser (#2247) Change the underlying command line handling: - switch to a custom parser, inspired by redis / sds - update terminalRegisterCommand signature, pass only bare minimum - clean-up `help` & `commands`. update settings `set`, `get` and `del` - allow our custom test suite to run command-line tests - clean-up Stream IO to allow us to print large things into debug stream (for example, `eeprom.dump`) - send parsing errors to the debug log As a proof of concept, introduce `TERMINAL_MQTT_SUPPORT` and `TERMINAL_WEB_API_SUPPORT` - MQTT subscribes to the `<root>/cmd/set` and sends response to the `<root>/cmd`. We can't output too much, as we don't have any large-send API. - Web API listens to the `/api/cmd?apikey=...&line=...` (or PUT, params inside the body). This one is intended as a possible replacement of the `API_SUPPORT`. Internals introduce a 'task' around the AsyncWebServerRequest object that will simulate what WiFiClient does and push data into it continuously, switching between CONT and SYS. Both are experimental. We only accept a single command and not every command is updated to use Print `ctx.output` object. We are also somewhat limited by the Print / Stream overall, perhaps I am overestimating the usefulness of Arduino compatibility to such an extent :) Web API handler can also sometimes show only part of the result, whenever the command tries to yield() by itself waiting for something. Perhaps we would need to create a custom request handler for that specific use-case.
4 years ago
Rework settings (#2282) * wip based on early draft. todo benchmarking * fixup eraser, assume keys are unique * fix cursor copy, test removal at random * small benchmark via permutations. todo lambdas and novirtual * fix empty condition / reset * overwrite optimizations, fix move offsets overflows * ...erase using 0xff instead of 0 * test the theory with code, different length kv were bugged * try to check for out-of-bounds writes / reads * style * trying to fix mover again * clarify length, defend against reading len on edge * fix uncommited rewind change * prove space assumptions * more concise traces, fix move condition (agrh!!!) * slightly more internal knowledge (estimates API?) * make sure cursor is only valid within the range * ensure 0 does not blow things * go back up * cursor comments * comments * rewrite writes through cursor * in del too * estimate kv storage requirements, return available size * move raw erase / move into a method, allow ::set to avoid scanning storage twice * refactor naming, use in code * amend storage slicing test * fix crash handler offsets, cleanup configuration * start -> begin * eeprom readiness * dependencies * unused * SPI_FLASH constants for older Core * vtables -> templates * less include dependencies * gcov help, move estimate outside of the class * writer position can never match, use begin + offset * tweak save_crash to trigger only once in a serious crash * doh, header function should be inline * foreach api, tweak structs for public api * use test helper class * when not using foreach, move cursor reset closer to the loop using read_kv * coverage comments, fix typo in tests decltype * ensure set() does not break with offset * make codacy happy again
4 years ago
Terminal: change command-line parser (#2247) Change the underlying command line handling: - switch to a custom parser, inspired by redis / sds - update terminalRegisterCommand signature, pass only bare minimum - clean-up `help` & `commands`. update settings `set`, `get` and `del` - allow our custom test suite to run command-line tests - clean-up Stream IO to allow us to print large things into debug stream (for example, `eeprom.dump`) - send parsing errors to the debug log As a proof of concept, introduce `TERMINAL_MQTT_SUPPORT` and `TERMINAL_WEB_API_SUPPORT` - MQTT subscribes to the `<root>/cmd/set` and sends response to the `<root>/cmd`. We can't output too much, as we don't have any large-send API. - Web API listens to the `/api/cmd?apikey=...&line=...` (or PUT, params inside the body). This one is intended as a possible replacement of the `API_SUPPORT`. Internals introduce a 'task' around the AsyncWebServerRequest object that will simulate what WiFiClient does and push data into it continuously, switching between CONT and SYS. Both are experimental. We only accept a single command and not every command is updated to use Print `ctx.output` object. We are also somewhat limited by the Print / Stream overall, perhaps I am overestimating the usefulness of Arduino compatibility to such an extent :) Web API handler can also sometimes show only part of the result, whenever the command tries to yield() by itself waiting for something. Perhaps we would need to create a custom request handler for that specific use-case.
4 years ago
Terminal: change command-line parser (#2247) Change the underlying command line handling: - switch to a custom parser, inspired by redis / sds - update terminalRegisterCommand signature, pass only bare minimum - clean-up `help` & `commands`. update settings `set`, `get` and `del` - allow our custom test suite to run command-line tests - clean-up Stream IO to allow us to print large things into debug stream (for example, `eeprom.dump`) - send parsing errors to the debug log As a proof of concept, introduce `TERMINAL_MQTT_SUPPORT` and `TERMINAL_WEB_API_SUPPORT` - MQTT subscribes to the `<root>/cmd/set` and sends response to the `<root>/cmd`. We can't output too much, as we don't have any large-send API. - Web API listens to the `/api/cmd?apikey=...&line=...` (or PUT, params inside the body). This one is intended as a possible replacement of the `API_SUPPORT`. Internals introduce a 'task' around the AsyncWebServerRequest object that will simulate what WiFiClient does and push data into it continuously, switching between CONT and SYS. Both are experimental. We only accept a single command and not every command is updated to use Print `ctx.output` object. We are also somewhat limited by the Print / Stream overall, perhaps I am overestimating the usefulness of Arduino compatibility to such an extent :) Web API handler can also sometimes show only part of the result, whenever the command tries to yield() by itself waiting for something. Perhaps we would need to create a custom request handler for that specific use-case.
4 years ago
Terminal: change command-line parser (#2247) Change the underlying command line handling: - switch to a custom parser, inspired by redis / sds - update terminalRegisterCommand signature, pass only bare minimum - clean-up `help` & `commands`. update settings `set`, `get` and `del` - allow our custom test suite to run command-line tests - clean-up Stream IO to allow us to print large things into debug stream (for example, `eeprom.dump`) - send parsing errors to the debug log As a proof of concept, introduce `TERMINAL_MQTT_SUPPORT` and `TERMINAL_WEB_API_SUPPORT` - MQTT subscribes to the `<root>/cmd/set` and sends response to the `<root>/cmd`. We can't output too much, as we don't have any large-send API. - Web API listens to the `/api/cmd?apikey=...&line=...` (or PUT, params inside the body). This one is intended as a possible replacement of the `API_SUPPORT`. Internals introduce a 'task' around the AsyncWebServerRequest object that will simulate what WiFiClient does and push data into it continuously, switching between CONT and SYS. Both are experimental. We only accept a single command and not every command is updated to use Print `ctx.output` object. We are also somewhat limited by the Print / Stream overall, perhaps I am overestimating the usefulness of Arduino compatibility to such an extent :) Web API handler can also sometimes show only part of the result, whenever the command tries to yield() by itself waiting for something. Perhaps we would need to create a custom request handler for that specific use-case.
4 years ago
Terminal: change command-line parser (#2247) Change the underlying command line handling: - switch to a custom parser, inspired by redis / sds - update terminalRegisterCommand signature, pass only bare minimum - clean-up `help` & `commands`. update settings `set`, `get` and `del` - allow our custom test suite to run command-line tests - clean-up Stream IO to allow us to print large things into debug stream (for example, `eeprom.dump`) - send parsing errors to the debug log As a proof of concept, introduce `TERMINAL_MQTT_SUPPORT` and `TERMINAL_WEB_API_SUPPORT` - MQTT subscribes to the `<root>/cmd/set` and sends response to the `<root>/cmd`. We can't output too much, as we don't have any large-send API. - Web API listens to the `/api/cmd?apikey=...&line=...` (or PUT, params inside the body). This one is intended as a possible replacement of the `API_SUPPORT`. Internals introduce a 'task' around the AsyncWebServerRequest object that will simulate what WiFiClient does and push data into it continuously, switching between CONT and SYS. Both are experimental. We only accept a single command and not every command is updated to use Print `ctx.output` object. We are also somewhat limited by the Print / Stream overall, perhaps I am overestimating the usefulness of Arduino compatibility to such an extent :) Web API handler can also sometimes show only part of the result, whenever the command tries to yield() by itself waiting for something. Perhaps we would need to create a custom request handler for that specific use-case.
4 years ago
Terminal: change command-line parser (#2247) Change the underlying command line handling: - switch to a custom parser, inspired by redis / sds - update terminalRegisterCommand signature, pass only bare minimum - clean-up `help` & `commands`. update settings `set`, `get` and `del` - allow our custom test suite to run command-line tests - clean-up Stream IO to allow us to print large things into debug stream (for example, `eeprom.dump`) - send parsing errors to the debug log As a proof of concept, introduce `TERMINAL_MQTT_SUPPORT` and `TERMINAL_WEB_API_SUPPORT` - MQTT subscribes to the `<root>/cmd/set` and sends response to the `<root>/cmd`. We can't output too much, as we don't have any large-send API. - Web API listens to the `/api/cmd?apikey=...&line=...` (or PUT, params inside the body). This one is intended as a possible replacement of the `API_SUPPORT`. Internals introduce a 'task' around the AsyncWebServerRequest object that will simulate what WiFiClient does and push data into it continuously, switching between CONT and SYS. Both are experimental. We only accept a single command and not every command is updated to use Print `ctx.output` object. We are also somewhat limited by the Print / Stream overall, perhaps I am overestimating the usefulness of Arduino compatibility to such an extent :) Web API handler can also sometimes show only part of the result, whenever the command tries to yield() by itself waiting for something. Perhaps we would need to create a custom request handler for that specific use-case.
4 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 "espurna.h"
  6. #include "crash.h"
  7. #include "terminal.h"
  8. #include "storage_eeprom.h"
  9. #include <algorithm>
  10. #include <vector>
  11. #include <cstdlib>
  12. #include <ArduinoJson.h>
  13. // -----------------------------------------------------------------------------
  14. namespace settings {
  15. // Depending on features enabled, we may end up with different left boundary
  16. // Settings are written right-to-left, so we only have issues when there are a lot of key-values
  17. // XXX: slightly hacky, because we EEPROMr.length() is 0 before we enter setup() code
  18. kvs_type kv_store(
  19. EepromStorage{},
  20. #if DEBUG_SUPPORT
  21. EepromReservedSize + CrashReservedSize,
  22. #else
  23. EepromReservedSize,
  24. #endif
  25. EepromSize
  26. );
  27. } // namespace settings
  28. size_t settingsSize() {
  29. return settings::kv_store.size() - settings::kv_store.available();
  30. }
  31. // --------------------------------------------------------------------------
  32. namespace settings {
  33. namespace internal {
  34. uint32_t u32fromString(const String& string, int base) {
  35. const char *ptr = string.c_str();
  36. char *value_endptr = nullptr;
  37. // invalidate the whole string when invalid chars are detected
  38. const auto value = strtoul(ptr, &value_endptr, base);
  39. if (value_endptr == ptr || value_endptr[0] != '\0') {
  40. return 0;
  41. }
  42. return value;
  43. }
  44. // --------------------------------------------------------------------------
  45. template <>
  46. float convert(const String& value) {
  47. return atof(value.c_str());
  48. }
  49. template <>
  50. double convert(const String& value) {
  51. return atof(value.c_str());
  52. }
  53. template <>
  54. signed char convert(const String& value) {
  55. return value.toInt();
  56. }
  57. template <>
  58. short convert(const String& value) {
  59. return value.toInt();
  60. }
  61. template <>
  62. int convert(const String& value) {
  63. return value.toInt();
  64. }
  65. template <>
  66. long convert(const String& value) {
  67. return value.toInt();
  68. }
  69. template <>
  70. bool convert(const String& value) {
  71. if (value.length()) {
  72. if ((value == "0")
  73. || (value == "n")
  74. || (value == "no")
  75. || (value == "false")
  76. || (value == "off")) {
  77. return false;
  78. }
  79. return (value == "1")
  80. || (value == "y")
  81. || (value == "yes")
  82. || (value == "true")
  83. || (value == "on");
  84. }
  85. return false;
  86. }
  87. template <>
  88. uint32_t convert(const String& value) {
  89. if (!value.length()) {
  90. return 0;
  91. }
  92. int base = 10;
  93. if (value.length() > 2) {
  94. auto* ptr = value.c_str();
  95. if (*ptr == '0') {
  96. switch (*(ptr + 1)) {
  97. case 'b':
  98. base = 2;
  99. break;
  100. case 'o':
  101. base = 8;
  102. break;
  103. case 'x':
  104. base = 16;
  105. break;
  106. }
  107. }
  108. }
  109. return u32fromString((base == 10) ? value : value.substring(2), base);
  110. }
  111. String serialize(uint32_t value, int base) {
  112. constexpr size_t Size { 4 * sizeof(decltype(value)) };
  113. constexpr size_t Length { Size - 1 };
  114. String result;
  115. result.reserve(Length);
  116. if (base == 2) {
  117. result += "0b";
  118. } else if (base == 8) {
  119. result += "0o";
  120. } else if (base == 16) {
  121. result += "0x";
  122. }
  123. char buffer[Size] = {0};
  124. ultoa(value, buffer, base);
  125. result += buffer;
  126. return result;
  127. }
  128. template <>
  129. unsigned long convert(const String& value) {
  130. return convert<unsigned int>(value);
  131. }
  132. template <>
  133. unsigned short convert(const String& value) {
  134. return convert<unsigned long>(value);
  135. }
  136. template <>
  137. unsigned char convert(const String& value) {
  138. return convert<unsigned long>(value);
  139. }
  140. } // namespace settings::internal
  141. } // namespace settings
  142. // -----------------------------------------------------------------------------
  143. // Key-value API
  144. // -----------------------------------------------------------------------------
  145. // TODO: UI needs this to avoid showing keys in storage order
  146. std::vector<String> settingsKeys() {
  147. auto keys = settings::kv_store.keys();
  148. std::sort(keys.begin(), keys.end(), [](const String& rhs, const String& lhs) -> bool {
  149. return lhs.compareTo(rhs) > 0;
  150. });
  151. return keys;
  152. }
  153. static std::vector<settings_key_match_t> _settings_matchers;
  154. void settingsRegisterDefaults(const settings_key_match_t& matcher) {
  155. _settings_matchers.push_back(matcher);
  156. }
  157. String settingsQueryDefaults(const String& key) {
  158. for (auto& matcher : _settings_matchers) {
  159. if (matcher.match(key.c_str())) {
  160. return matcher.key(key);
  161. }
  162. }
  163. return String();
  164. }
  165. settings_move_key_t _moveKeys(const String& from, const String& to, unsigned char index) {
  166. return settings_move_key_t {{from, index}, {to, index}};
  167. }
  168. void moveSetting(const String& from, const String& to) {
  169. const auto value = getSetting(from);
  170. if (value.length() > 0) setSetting(to, value);
  171. delSetting(from);
  172. }
  173. void moveSetting(const String& from, const String& to, unsigned char index) {
  174. const auto keys = _moveKeys(from, to, index);
  175. const auto value = getSetting(keys.first);
  176. if (value.length() > 0) setSetting(keys.second, value);
  177. delSetting(keys.first);
  178. }
  179. void moveSettings(const String& from, const String& to) {
  180. unsigned char index = 0;
  181. while (index < 100) {
  182. const auto keys = _moveKeys(from, to, index);
  183. const auto value = getSetting(keys.first);
  184. if (value.length() == 0) break;
  185. setSetting(keys.second, value);
  186. delSetting(keys.first);
  187. ++index;
  188. }
  189. }
  190. template
  191. bool getSetting(const SettingsKey& key, bool defaultValue);
  192. template
  193. int getSetting(const SettingsKey& key, int defaultValue);
  194. template
  195. long getSetting(const SettingsKey& key, long defaultValue);
  196. template
  197. unsigned char getSetting(const SettingsKey& key, unsigned char defaultValue);
  198. template
  199. unsigned short getSetting(const SettingsKey& key, unsigned short defaultValue);
  200. template
  201. unsigned int getSetting(const SettingsKey& key, unsigned int defaultValue);
  202. template
  203. unsigned long getSetting(const SettingsKey& key, unsigned long defaultValue);
  204. template
  205. float getSetting(const SettingsKey& key, float defaultValue);
  206. template
  207. double getSetting(const SettingsKey& key, double defaultValue);
  208. String getSetting(const String& key) {
  209. return std::move(settings::kv_store.get(key)).get();
  210. }
  211. String getSetting(const __FlashStringHelper* key) {
  212. return getSetting(String(key));
  213. }
  214. String getSetting(const char* key) {
  215. return getSetting(String(key));
  216. }
  217. String getSetting(const SettingsKey& key) {
  218. static const String defaultValue("");
  219. return getSetting(key, defaultValue);
  220. }
  221. String getSetting(const SettingsKey& key, const char* defaultValue) {
  222. return getSetting(key, std::move(String(defaultValue)));
  223. }
  224. String getSetting(const SettingsKey& key, const __FlashStringHelper* defaultValue) {
  225. return getSetting(key, std::move(String(defaultValue)));
  226. }
  227. String getSetting(const SettingsKey& key, const String& defaultValue) {
  228. auto result = settings::kv_store.get(key.value());
  229. if (result) {
  230. return std::move(result).get();
  231. }
  232. return defaultValue;
  233. }
  234. String getSetting(const SettingsKey& key, String&& defaultValue) {
  235. auto result = settings::kv_store.get(key.value());
  236. if (result) {
  237. return std::move(result).get();
  238. }
  239. return std::move(defaultValue);
  240. }
  241. bool delSetting(const String& key) {
  242. return settings::kv_store.del(key);
  243. }
  244. bool delSetting(const SettingsKey& key) {
  245. return delSetting(key.value());
  246. }
  247. bool delSetting(const char* key) {
  248. return delSetting(String(key));
  249. }
  250. bool delSetting(const __FlashStringHelper* key) {
  251. return delSetting(String(key));
  252. }
  253. bool hasSetting(const String& key) {
  254. return settings::kv_store.has(key);
  255. }
  256. bool hasSetting(const SettingsKey& key) {
  257. return hasSetting(key.value());
  258. }
  259. bool hasSetting(const char* key) {
  260. return hasSetting(String(key));
  261. }
  262. bool hasSetting(const __FlashStringHelper* key) {
  263. return hasSetting(String(key));
  264. }
  265. void saveSettings() {
  266. #if not SETTINGS_AUTOSAVE
  267. eepromCommit();
  268. #endif
  269. }
  270. void autosaveSettings() {
  271. #if SETTINGS_AUTOSAVE
  272. eepromCommit();
  273. #endif
  274. }
  275. void resetSettings() {
  276. eepromClear();
  277. }
  278. // -----------------------------------------------------------------------------
  279. // API
  280. // -----------------------------------------------------------------------------
  281. bool settingsRestoreJson(JsonObject& data) {
  282. // Note: we try to match what /config generates, expect {"app":"ESPURNA",...}
  283. const char* app = data["app"];
  284. if (!app || strcmp(app, APP_NAME) != 0) {
  285. DEBUG_MSG_P(PSTR("[SETTING] Wrong or missing 'app' key\n"));
  286. return false;
  287. }
  288. // .../config will add this key, but it is optional
  289. if (data["backup"].as<bool>()) {
  290. resetSettings();
  291. }
  292. // These three are just metadata, no need to actually store them
  293. for (auto element : data) {
  294. if (strcmp(element.key, "app") == 0) continue;
  295. if (strcmp(element.key, "version") == 0) continue;
  296. if (strcmp(element.key, "backup") == 0) continue;
  297. setSetting(element.key, element.value.as<char*>());
  298. }
  299. saveSettings();
  300. DEBUG_MSG_P(PSTR("[SETTINGS] Settings restored successfully\n"));
  301. return true;
  302. }
  303. bool settingsRestoreJson(char* json_string, size_t json_buffer_size) {
  304. // XXX: as of right now, arduinojson cannot trigger callbacks for each key individually
  305. // 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.
  306. // Current parsing method is limited only by keys (~sizeof(uintptr_t) bytes per key, data is not copied when string is non-const)
  307. DynamicJsonBuffer jsonBuffer(json_buffer_size);
  308. JsonObject& root = jsonBuffer.parseObject((char *) json_string);
  309. if (!root.success()) {
  310. DEBUG_MSG_P(PSTR("[SETTINGS] JSON parsing error\n"));
  311. return false;
  312. }
  313. return settingsRestoreJson(root);
  314. }
  315. void settingsGetJson(JsonObject& root) {
  316. // Get sorted list of keys
  317. auto keys = settingsKeys();
  318. // Add the key-values to the json object
  319. for (unsigned int i=0; i<keys.size(); i++) {
  320. String value = getSetting(keys[i]);
  321. root[keys[i]] = value;
  322. }
  323. }
  324. void settingsProcessConfig(const settings_cfg_list_t& config, settings_filter_t filter) {
  325. for (auto& entry : config) {
  326. String value = getSetting(entry.key, entry.default_value);
  327. if (filter) {
  328. value = filter(value);
  329. }
  330. if (value.equals(entry.setting)) continue;
  331. entry.setting = std::move(value);
  332. }
  333. }
  334. // -----------------------------------------------------------------------------
  335. // Initialization
  336. // -----------------------------------------------------------------------------
  337. #if TERMINAL_SUPPORT
  338. void _settingsInitCommands() {
  339. terminalRegisterCommand(F("CONFIG"), [](const terminal::CommandContext& ctx) {
  340. // TODO: enough of a buffer?
  341. DynamicJsonBuffer jsonBuffer(1024);
  342. JsonObject& root = jsonBuffer.createObject();
  343. settingsGetJson(root);
  344. root.prettyPrintTo(ctx.output);
  345. terminalOK(ctx);
  346. });
  347. terminalRegisterCommand(F("KEYS"), [](const terminal::CommandContext& ctx) {
  348. auto keys = settingsKeys();
  349. ctx.output.println(F("Current settings:"));
  350. for (unsigned int i=0; i<keys.size(); i++) {
  351. const auto value = getSetting(keys[i]);
  352. ctx.output.printf("> %s => \"%s\"\n", (keys[i]).c_str(), value.c_str());
  353. }
  354. auto available [[gnu::unused]] = settings::kv_store.available();
  355. ctx.output.printf("Number of keys: %u\n", keys.size());
  356. ctx.output.printf("Available: %u bytes (%u%%)\n", available, (100 * available) / settings::kv_store.size());
  357. terminalOK(ctx);
  358. });
  359. terminalRegisterCommand(F("DEL"), [](const terminal::CommandContext& ctx) {
  360. if (ctx.argc != 2) {
  361. terminalError(ctx, F("del <key> [<key>...]"));
  362. return;
  363. }
  364. int result = 0;
  365. for (auto it = (ctx.argv.begin() + 1); it != ctx.argv.end(); ++it) {
  366. result += settings::kv_store.del(*it);
  367. }
  368. if (result) {
  369. terminalOK(ctx);
  370. } else {
  371. terminalError(ctx, F("no keys were removed"));
  372. }
  373. });
  374. terminalRegisterCommand(F("SET"), [](const terminal::CommandContext& ctx) {
  375. if (ctx.argc != 3) {
  376. terminalError(ctx, F("set <key> <value>"));
  377. return;
  378. }
  379. if (settings::kv_store.set(ctx.argv[1], ctx.argv[2])) {
  380. terminalOK(ctx);
  381. return;
  382. }
  383. terminalError(ctx, F("could not set the key"));
  384. });
  385. terminalRegisterCommand(F("GET"), [](const terminal::CommandContext& ctx) {
  386. if (ctx.argc < 2) {
  387. terminalError(ctx, F("Wrong arguments"));
  388. return;
  389. }
  390. for (auto it = (ctx.argv.begin() + 1); it != ctx.argv.end(); ++it) {
  391. const String& key = *it;
  392. auto result = settings::kv_store.get(key);
  393. if (!result) {
  394. const auto maybeDefault = settingsQueryDefaults(key);
  395. if (maybeDefault.length()) {
  396. ctx.output.printf("> %s => %s (default)\n", key.c_str(), maybeDefault.c_str());
  397. } else {
  398. ctx.output.printf("> %s =>\n", key.c_str());
  399. }
  400. continue;
  401. }
  402. ctx.output.printf("> %s => \"%s\"\n", key.c_str(), result.value.c_str());
  403. }
  404. terminalOK(ctx);
  405. });
  406. terminalRegisterCommand(F("RELOAD"), [](const terminal::CommandContext& ctx) {
  407. espurnaReload();
  408. terminalOK(ctx);
  409. });
  410. terminalRegisterCommand(F("FACTORY.RESET"), [](const terminal::CommandContext& ctx) {
  411. factoryReset();
  412. terminalOK(ctx);
  413. });
  414. #if not SETTINGS_AUTOSAVE
  415. terminalRegisterCommand(F("SAVE"), [](const terminal::CommandContext& ctx) {
  416. eepromCommit();
  417. terminalOK(ctx);
  418. });
  419. #endif
  420. }
  421. #endif
  422. void settingsSetup() {
  423. #if TERMINAL_SUPPORT
  424. _settingsInitCommands();
  425. #endif
  426. }