aboutsummaryrefslogtreecommitdiff
path: root/src/diller/utils.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/diller/utils.h')
-rw-r--r--src/diller/utils.h348
1 files changed, 348 insertions, 0 deletions
diff --git a/src/diller/utils.h b/src/diller/utils.h
new file mode 100644
index 0000000..5b1224d
--- /dev/null
+++ b/src/diller/utils.h
@@ -0,0 +1,348 @@
+#pragma once
+
+#include <Arduino.h>
+
+namespace diller {
+namespace utils {
+
+enum class tty_status : uint8_t {
+ NEED_MORE,
+ TIMEOUT,
+ EMPTY_LINE,
+ FULL_LINE,
+ LINE_OVERFLOW,
+};
+
+class serial_io {
+ public:
+ static auto available() -> decltype(Serial.available()) {
+ return Serial.available();
+ }
+
+ static auto read() -> decltype(Serial.read()) {
+ return Serial.read();
+ }
+
+ template<typename A>
+ static auto print(A a) -> decltype(Serial.print(a)) {
+ return Serial.print(a);
+ }
+
+ template<typename A>
+ static auto println(A a) -> decltype(Serial.println(a)) {
+ return Serial.println(a);
+ }
+};
+
+template<typename instance>
+class software_serial_io {
+ public:
+ static auto available() -> decltype(instance::software_serial.available()) {
+ return instance::software_serial.available();
+ }
+
+ static auto read() -> decltype(instance::software_serial.read()) {
+ return instance::software_serial.read();
+ }
+
+ template<typename A>
+ static auto print(A a) -> decltype(instance::software_serial.print(a)) {
+ return instance::software_serial.print(a);
+ }
+
+ template<typename A>
+ static auto println(A a) -> decltype(instance::software_serial.println(a)) {
+ return instance::software_serial.println(a);
+ }
+};
+
+template<typename io, uint8_t buffer_size, int timeout_ms_, bool debug_ = false>
+class tty {
+ public:
+ char line[buffer_size];
+ uint8_t size = 0;
+ const bool debug = debug_;
+ const unsigned long timeout_ms = timeout_ms_;
+
+ void init(bool reset = false) {
+ if (reset) {
+ line[0] = '\0';
+ }
+
+ size = 0;
+ last_char = 0;
+ }
+
+ void quote(const String &s) {
+ Serial.print(s.c_str());
+ }
+
+ void quote(const char *str) {
+ Serial.print(str);
+ }
+
+ void escape(const char *str) {
+ Serial.print(str);
+ }
+
+ tty_status readline() {
+ while (io::available()) {
+ int c = io::read();
+
+ if (debug) {
+ Serial.print("read: c=");
+ Serial.println(c, HEX);
+ }
+
+ if (c == '\n') {
+ // ignore
+ last_char = millis();
+ } else if (c == '\r') {
+ line[size] = '\0';
+ auto status = size > 0 ? tty_status::FULL_LINE : tty_status::EMPTY_LINE;
+ init();
+
+ if (debug) {
+ Serial.print("debug src=tty state=\"new line\" size=");
+ Serial.print(size, DEC);
+ Serial.print(" line=");
+ quote(line);
+ Serial.println();
+ }
+
+ return status;
+ } else {
+ if (size == buffer_size - 1) {
+
+ if (debug) {
+ Serial.print("debug src=tty state=overflow size=");
+ Serial.print(size, DEC);
+ Serial.print(" line=");
+ quote(line);
+ Serial.println();
+ }
+ init();
+
+ return tty_status::LINE_OVERFLOW;
+ }
+ line[size++] = static_cast<char>(c);
+ last_char = millis();
+ }
+ }
+
+ unsigned long now = millis();
+
+ if (last_char > 0 && now >= (last_char + timeout_ms)) {
+ if (debug) {
+ line[size] = '\0';
+ Serial.print("debug src=tty state=\"timeout\" line=");
+ quote(line);
+ Serial.println();
+ }
+
+ init(true);
+ return tty_status::TIMEOUT;
+ }
+
+ return tty_status::NEED_MORE;
+ }
+ private:
+ unsigned long last_char = 0;
+};
+
+class key_value_map {
+ public:
+ virtual void clear();
+ virtual void put(char *key, char *value) = 0;
+ virtual const char *key(uint8_t index) const = 0;
+ virtual const char *value(uint8_t index) const = 0;
+ virtual const char *find(const char *key) const = 0;
+ virtual uint8_t size() const = 0;
+ virtual bool is_empty() const = 0;
+ virtual bool is_full() const = 0;
+};
+
+template<int max_args>
+class fixed_size_key_value_map : public key_value_map {
+ public:
+ uint8_t size_;
+ static_assert(max_args <= 256, "max_args is too big");
+ char *keys[max_args];
+ char *values[max_args];
+
+ void clear() {
+ size_ = 0;
+ }
+
+ void put(char *key, char *value) {
+ if (size_ < max_args) {
+ keys[size_] = key;
+ values[size_] = value;
+ size_++;
+ }
+ }
+
+ const char *key(uint8_t index) const {
+ return keys[index];
+ }
+
+ const char *value(uint8_t index) const {
+ return values[index];
+ }
+
+ const char *find(const char *key) const {
+ for (int i = 0; i < size_; i++) {
+ if (strcmp(keys[i], key) == 0) {
+ return values[i];
+ }
+ }
+
+ return nullptr;
+ }
+
+ uint8_t size() const {
+ return size_;
+ }
+
+ bool is_empty() const {
+ return size_ >= max_args;
+ }
+
+ bool is_full() const {
+ return size_ >= max_args;
+ }
+};
+
+class diller_parser {
+ public:
+ diller_parser(key_value_map &map) : map(map) {
+ }
+
+ void parse(char *line) {
+ char *c = line;
+ map.clear();
+
+ while (*c != '\0') {
+ while (*c == ' ') {
+ c++;
+ }
+ if (*c == '\0') {
+ break;
+ }
+ char *key = c,
+ *value = nullptr;
+
+ while (*c != ' ' && *c != '\0') {
+ if (*c == '=') {
+ *c = '\0';
+ c++;
+ value = c;
+ }
+
+ c++;
+ }
+
+ map.put(key, value);
+
+ if (*c == '\0' || map.is_full()) {
+ break;
+ }
+
+ *c++ = '\0';
+ }
+ }
+ protected:
+ key_value_map &map;
+};
+
+class property {
+ public:
+ property() : new_(true) {
+ }
+
+ const String &id() const {
+ return id_;
+ }
+
+ const String &value() const {
+ return value_;
+ }
+
+ const String &name() const {
+ return name_;
+ }
+
+ const String &description() const {
+ return description_;
+ }
+
+ bool dirty() const {
+ return dirty_;
+ }
+
+ void init(const String &id) {
+ id_ = id;
+ dirty_ = false;
+ }
+
+ bool is_new() const {
+ return new_;
+ }
+
+ void set_old() {
+ new_ = false;
+ }
+
+ private:
+ String id_;
+ boolean dirty_;
+ boolean new_;
+
+ String value_;
+ String name_;
+ String description_;
+};
+
+template<size_t max_property_count>
+class properties {
+ public:
+ properties() : size_(0) {
+ }
+
+ property* operator[](uint8_t i) {
+ if (i >= size_) {
+ return nullptr;
+ }
+
+ return &properties_[i];
+ }
+
+ property* find(const char *id) {
+ for (int i = 0; i < size_; i++) {
+ if (properties_[i].id() == id) {
+ return &properties_[i];
+ }
+ }
+
+ if (size_ < max_property_count) {
+ auto p = &properties_[size_];
+ size_++;
+ p->init(id);
+ return p;
+ }
+
+ return nullptr;
+ }
+
+ uint8_t size() {
+ return size_;
+ }
+
+ private:
+ property properties_[max_property_count];
+ uint8_t size_;
+};
+
+} // namespace utils
+} // namespace diller
+