From 1effc988e95a7c39ed673bbcc840ff20cec4bb75 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Sun, 13 Mar 2016 11:10:51 +0100 Subject: o Initial import of Diller Arduino library. --- src/diller_utils.h | 348 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 348 insertions(+) create mode 100644 src/diller_utils.h (limited to 'src/diller_utils.h') 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 + +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 + static auto print(A a) -> decltype(Serial.print(a)) { + return Serial.print(a); + } + + template + static auto println(A a) -> decltype(Serial.println(a)) { + return Serial.println(a); + } +}; + +template +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 + static auto print(A a) -> decltype(instance::software_serial.print(a)) { + return instance::software_serial.print(a); + } + + template + static auto println(A a) -> decltype(instance::software_serial.println(a)) { + return instance::software_serial.println(a); + } +}; + +template +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(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 +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 ↦ +}; + +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 +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 + -- cgit v1.2.3