From 194a1d653298e62343076dedde3aa9bd5d3f50c9 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sun, 6 Dec 2020 22:57:00 +0100 Subject: [PATCH 01/60] move config into external repository --- .gitmodules | 3 + lib | 1 + src/configuration.cpp | 155 ------------------------ src/configuration.h | 125 -------------------- src/display.cpp | 127 -------------------- src/display.h | 15 --- src/logger.cpp | 248 --------------------------------------- src/logger.h | 75 ------------ src/pins.h | 56 --------- src/power_management.cpp | 55 --------- src/power_management.h | 26 ---- 11 files changed, 4 insertions(+), 882 deletions(-) create mode 100644 .gitmodules create mode 160000 lib delete mode 100644 src/configuration.cpp delete mode 100644 src/configuration.h delete mode 100644 src/display.cpp delete mode 100644 src/display.h delete mode 100644 src/logger.cpp delete mode 100644 src/logger.h delete mode 100644 src/pins.h delete mode 100644 src/power_management.cpp delete mode 100644 src/power_management.h diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..37a6bca --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib"] + path = lib + url = ../LoRa_APRS_Common diff --git a/lib b/lib new file mode 160000 index 0000000..757733b --- /dev/null +++ b/lib @@ -0,0 +1 @@ +Subproject commit 757733be04730095a27be008363b4f51dd68bacb diff --git a/src/configuration.cpp b/src/configuration.cpp deleted file mode 100644 index bbc8d3a..0000000 --- a/src/configuration.cpp +++ /dev/null @@ -1,155 +0,0 @@ -#include - -#include "configuration.h" -#include "logger.h" - -ConfigurationManagement::ConfigurationManagement(String FilePath) - : mFilePath(FilePath) -{ - if(!SPIFFS.begin(true)) - { - logPrintlnE("Mounting SPIFFS was not possible. Trying to format SPIFFS..."); - SPIFFS.format(); - if(!SPIFFS.begin()) - { - logPrintlnE("Formating SPIFFS was not okay!"); - } - } -} - -Configuration ConfigurationManagement::readConfiguration() -{ - File file = SPIFFS.open(mFilePath); - if(!file) - { - logPrintlnE("Failed to open file for reading..."); - return Configuration(); - } - DynamicJsonDocument data(2048); - DeserializationError error = deserializeJson(data, file); - if(error) - { - logPrintlnW("Failed to read file, using default configuration."); - } - //serializeJson(data, Serial); - //Serial.println(); - file.close(); - - Configuration conf; - if(data.containsKey("callsign")) - conf.callsign = data["callsign"].as(); - - conf.wifi.active = data["wifi"]["active"] | false; - JsonArray aps = data["wifi"]["AP"].as(); - for(JsonVariant v : aps) - { - Configuration::Wifi::AP ap; - ap.SSID = v["SSID"].as(); - ap.password = v["password"].as(); - conf.wifi.APs.push_back(ap); - } - if(data.containsKey("beacon") && data["beacon"].containsKey("message")) - conf.beacon.message = data["beacon"]["message"].as(); - conf.beacon.positionLatitude = data["beacon"]["position"]["latitude"] | 0.0; - conf.beacon.positionLongitude = data["beacon"]["position"]["longitude"] | 0.0; - conf.aprs_is.active = data["aprs_is"]["active"] | false; - if(data.containsKey("aprs_is") && data["aprs_is"].containsKey("password")) - conf.aprs_is.password = data["aprs_is"]["password"].as(); - if(data.containsKey("aprs_is") && data["aprs_is"].containsKey("server")) - conf.aprs_is.server = data["aprs_is"]["server"].as(); - conf.aprs_is.port = data["aprs_is"]["port"] | 14580; - conf.aprs_is.beacon = data["aprs_is"]["beacon"] | true; - conf.aprs_is.beaconTimeout = data["aprs_is"]["beacon_timeout"] | 15; - conf.digi.active = data["digi"]["active"] | false; - conf.digi.forwardTimeout = data["digi"]["forward_timeout"] | 5; - conf.digi.beacon = data["digi"]["beacon"] | true; - conf.digi.beaconTimeout = data["digi"]["beacon_timeout"] | 30; - - conf.lora.frequencyRx = data["lora"]["frequency_rx"] | 433775000; - conf.lora.frequencyTx = data["lora"]["frequency_tx"] | 433775000; - conf.lora.power = data["lora"]["power"] | 20; - conf.lora.spreadingFactor = data["lora"]["spreading_factor"] | 12; - conf.lora.signalBandwidth = data["lora"]["signal_bandwidth"] | 125000; - conf.lora.codingRate4 = data["lora"]["coding_rate4"] | 5; - conf.display.alwaysOn = data["display"]["always_on"] | true; - conf.display.timeout = data["display"]["timeout"] | 10; - conf.display.overwritePin = data["display"]["overwrite_pin"] | 0; - - conf.ftp.active = data["ftp"]["active"] | false; - JsonArray users = data["ftp"]["user"].as(); - for(JsonVariant u : users) - { - Configuration::Ftp::User us; - us.name = u["name"].as(); - us.password = u["password"].as(); - conf.ftp.users.push_back(us); - } - if(conf.ftp.users.empty()) - { - Configuration::Ftp::User us; - us.name = "ftp"; - us.password = "ftp"; - conf.ftp.users.push_back(us); - } - - // update config in memory to get the new fields: - writeConfiguration(conf); - - return conf; -} - -void ConfigurationManagement::writeConfiguration(Configuration conf) -{ - File file = SPIFFS.open(mFilePath, "w"); - if(!file) - { - logPrintlnE("Failed to open file for writing..."); - return; - } - DynamicJsonDocument data(2048); - - data["callsign"] = conf.callsign; - data["wifi"]["active"] = conf.wifi.active; - JsonArray aps = data["wifi"].createNestedArray("AP"); - for(Configuration::Wifi::AP ap : conf.wifi.APs) - { - JsonObject v = aps.createNestedObject(); - v["SSID"] = ap.SSID; - v["password"] = ap.password; - } - data["beacon"]["message"] = conf.beacon.message; - data["beacon"]["position"]["latitude"] = conf.beacon.positionLatitude; - data["beacon"]["position"]["longitude"] = conf.beacon.positionLongitude; - data["aprs_is"]["active"] = conf.aprs_is.active; - data["aprs_is"]["password"] = conf.aprs_is.password; - data["aprs_is"]["server"] = conf.aprs_is.server; - data["aprs_is"]["port"] = conf.aprs_is.port; - data["aprs_is"]["beacon"] = conf.aprs_is.beacon; - data["aprs_is"]["beacon_timeout"] = conf.aprs_is.beaconTimeout; - data["digi"]["active"] = conf.digi.active; - data["digi"]["forward_timeout"] = conf.digi.forwardTimeout; - data["digi"]["beacon"] = conf.digi.beacon; - data["digi"]["beacon_timeout"] = conf.digi.beaconTimeout; - data["lora"]["frequency_rx"] = conf.lora.frequencyRx; - data["lora"]["frequency_tx"] = conf.lora.frequencyTx; - data["lora"]["power"] = conf.lora.power; - data["lora"]["spreading_factor"] = conf.lora.spreadingFactor; - data["lora"]["signal_bandwidth"] = conf.lora.signalBandwidth; - data["lora"]["coding_rate4"] = conf.lora.codingRate4; - data["display"]["always_on"] = conf.display.alwaysOn; - data["display"]["timeout"] = conf.display.timeout; - data["display"]["overwrite_pin"] = conf.display.overwritePin; - data["ftp"]["active"] = conf.ftp.active; - JsonArray users = data["ftp"].createNestedArray("user"); - for(Configuration::Ftp::User u : conf.ftp.users) - { - JsonObject v = users.createNestedObject(); - v["name"] = u.name; - v["password"] = u.password; - } - - serializeJson(data, file); - //serializeJson(data, Serial); - //Serial.println(); - file.close(); -} diff --git a/src/configuration.h b/src/configuration.h deleted file mode 100644 index 8e7e101..0000000 --- a/src/configuration.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef CONFIGURATION_H_ -#define CONFIGURATION_H_ - -#include - -#include -#include - -class Configuration -{ -public: - class Wifi - { - public: - class AP - { - public: - String SSID; - String password; - }; - - Wifi() : active(false) {} - - bool active; - std::list APs; - }; - - class Beacon - { - public: - Beacon() : message("LoRa iGATE & Digi, Info: github.com/peterus/LoRa_APRS_iGate"), positionLatitude(0.0), positionLongitude(0.0) {} - - String message; - double positionLatitude; - double positionLongitude; - }; - - class APRS_IS - { - public: - APRS_IS() : active(false), server("euro.aprs2.net"), port(14580), beacon(true), beaconTimeout(15) {} - - bool active; - String password; - String server; - int port; - bool beacon; - int beaconTimeout; - }; - - class Digi - { - public: - Digi() : active(false), forwardTimeout(5), beacon(true), beaconTimeout(30) {} - - bool active; - int forwardTimeout; - bool beacon; - int beaconTimeout; - }; - - class LoRa - { - public: - LoRa() : frequencyRx(433775000), frequencyTx(433775000), power(20), spreadingFactor(12), signalBandwidth(125000), codingRate4(5) {} - - long frequencyRx; - long frequencyTx; - int power; - int spreadingFactor; - long signalBandwidth; - int codingRate4; - }; - - class Display - { - public: - Display() : alwaysOn(true), timeout(10), overwritePin(0) {} - - bool alwaysOn; - int timeout; - int overwritePin; - }; - - class Ftp - { - public: - class User - { - public: - String name; - String password; - }; - - Ftp() : active(false) {} - - bool active; - std::list users; - }; - - Configuration() : callsign("NOCALL-10") {}; - - String callsign; - Wifi wifi; - Beacon beacon; - APRS_IS aprs_is; - Digi digi; - LoRa lora; - Display display; - Ftp ftp; -}; - -class ConfigurationManagement -{ -public: - explicit ConfigurationManagement(String FilePath); - - Configuration readConfiguration(); - void writeConfiguration(Configuration conf); - -private: - const String mFilePath; -}; - -#endif diff --git a/src/display.cpp b/src/display.cpp deleted file mode 100644 index 292b63e..0000000 --- a/src/display.cpp +++ /dev/null @@ -1,127 +0,0 @@ - -#include -#include -#include - -#include "display.h" -#include "pins.h" -#include "logger.h" - -Adafruit_SSD1306 display(128, 64, &Wire); - -void setup_display() -{ - Wire.begin(OLED_SDA, OLED_SCL); - if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3c, false, false)) - { - logPrintlnE("SSD1306 allocation failed"); - while (1); - } - logPrintlnI("Display init done!"); -} - -void turn_off_display() -{ - display.ssd1306_command(SSD1306_DISPLAYOFF); -} - -void show_display(String header, int wait) -{ - display.clearDisplay(); - display.setTextColor(WHITE); - display.setTextSize(2); - display.setCursor(0,0); - display.println(header); - display.display(); - delay(wait); -} - -void show_display(String header, String line1, int wait) -{ - display.clearDisplay(); - display.setTextColor(WHITE); - display.setTextSize(2); - display.setCursor(0,0); - display.println(header); - display.setTextSize(1); - display.setCursor(0,16); - display.println(line1); - display.display(); - delay(wait); -} - -void show_display(String header, String line1, String line2, int wait) -{ - display.clearDisplay(); - display.setTextColor(WHITE); - display.setTextSize(2); - display.setCursor(0,0); - display.println(header); - display.setTextSize(1); - display.setCursor(0,16); - display.println(line1); - display.setCursor(0,26); - display.println(line2); - display.display(); - delay(wait); -} - -void show_display(String header, String line1, String line2, String line3, int wait) -{ - display.clearDisplay(); - display.setTextColor(WHITE); - display.setTextSize(2); - display.setCursor(0,0); - display.println(header); - display.setTextSize(1); - display.setCursor(0,16); - display.println(line1); - display.setCursor(0,26); - display.println(line2); - display.setCursor(0,36); - display.println(line3); - display.display(); - delay(wait); -} - -void show_display(String header, String line1, String line2, String line3, String line4, int wait) -{ - display.clearDisplay(); - display.setTextColor(WHITE); - display.setTextSize(2); - display.setCursor(0,0); - display.println(header); - display.setTextSize(1); - display.setCursor(0,16); - display.println(line1); - display.setCursor(0,26); - display.println(line2); - display.setCursor(0,36); - display.println(line3); - display.setCursor(0,46); - display.println(line4); - display.display(); - delay(wait); -} - -void show_display(String header, String line1, String line2, String line3, String line4, String line5, int wait) -{ - display.clearDisplay(); - display.setTextColor(WHITE); - display.setTextSize(2); - display.setCursor(0,0); - display.println(header); - display.setTextSize(1); - display.setCursor(0,16); - display.println(line1); - display.setCursor(0,26); - display.println(line2); - display.setCursor(0,36); - display.println(line3); - display.setCursor(0,46); - display.println(line4); - display.setCursor(0,56); - display.println(line5); - display.display(); - delay(wait); -} diff --git a/src/display.h b/src/display.h deleted file mode 100644 index 2df251a..0000000 --- a/src/display.h +++ /dev/null @@ -1,15 +0,0 @@ - -#ifndef DISPLAY_H_ -#define DISPLAY_H_ - -void setup_display(); -void turn_off_display(); - -void show_display(String header, int wait = 0); -void show_display(String header, String line1, int wait = 0); -void show_display(String header, String line1, String line2, int wait = 0); -void show_display(String header, String line1, String line2, String line3, int wait = 0); -void show_display(String header, String line1, String line2, String line3, String line4, int wait = 0); -void show_display(String header, String line1, String line2, String line3, String line4, String line5, int wait = 0); - -#endif diff --git a/src/logger.cpp b/src/logger.cpp deleted file mode 100644 index 0e63503..0000000 --- a/src/logger.cpp +++ /dev/null @@ -1,248 +0,0 @@ -#include "logger.h" - -#undef LOG_RESET_COLOR -#undef LOG_COLOR_E -#undef LOG_COLOR_W -#undef LOG_COLOR_I -#undef LOG_COLOR_D -#undef LOG_COLOR_V - -#define LOG_COLOR_BLACK "30" -#define LOG_COLOR_RED "31" -#define LOG_COLOR_GREEN "32" -#define LOG_COLOR_BROWN "33" -#define LOG_COLOR_BLUE "34" -#define LOG_COLOR_PURPLE "35" -#define LOG_COLOR_CYAN "36" -#define LOG_COLOR(COLOR) "\033[0;" COLOR "m" -#define LOG_BOLD(COLOR) "\033[1;" COLOR "m" -#define LOG_RESET_COLOR "\033[0m" -#define LOG_COLOR_E LOG_COLOR(LOG_COLOR_RED) -#define LOG_COLOR_W LOG_COLOR(LOG_COLOR_BROWN) -#define LOG_COLOR_I LOG_COLOR(LOG_COLOR_GREEN) -#define LOG_COLOR_D LOG_COLOR(LOG_COLOR_BLUE) -#define LOG_COLOR_V LOG_COLOR(LOG_COLOR_CYAN) - -Logger::Logger() - : _serial(Serial), _level(DEBUG_LEVEL_DEBUG), _printIsNewline(true) -{ -} - -// cppcheck-suppress unusedFunction -void Logger::setSerial(const HardwareSerial & serial) -{ - _serial = serial; -} - -// cppcheck-suppress unusedFunction -void Logger::setDebugLevel(debug_level_t level) -{ - _level = level; -} - -// cppcheck-suppress unusedFunction -void Logger::printA(const String & text, const char * file, uint32_t line) -{ - printStartColor(DEBUG_LEVEL_NONE); - printHeader(DEBUG_LEVEL_NONE, file, line, false); - _serial.print(text); - printEndColor(DEBUG_LEVEL_NONE); -} - -// cppcheck-suppress unusedFunction -void Logger::printE(const String & text, const char * file, uint32_t line) -{ - printStartColor(DEBUG_LEVEL_ERROR); - printHeader(DEBUG_LEVEL_ERROR, file, line, false); - _serial.print(text); - printEndColor(DEBUG_LEVEL_ERROR); -} - -// cppcheck-suppress unusedFunction -void Logger::printlnA(const String & text, const char * file, uint32_t line) -{ - printStartColor(DEBUG_LEVEL_NONE); - printHeader(DEBUG_LEVEL_NONE, file, line, true); - _serial.println(text); - printEndColor(DEBUG_LEVEL_NONE); -} - -// cppcheck-suppress unusedFunction -void Logger::printlnE(const String & text, const char * file, uint32_t line) -{ - printStartColor(DEBUG_LEVEL_ERROR); - printHeader(DEBUG_LEVEL_ERROR, file, line, true); - _serial.println(text); - printEndColor(DEBUG_LEVEL_ERROR); -} - -// cppcheck-suppress unusedFunction -void Logger::printV(const String & text, const char * file, uint32_t line) -{ - if (_level >= DEBUG_LEVEL_VERBOSE) - { - printStartColor(DEBUG_LEVEL_VERBOSE); - printHeader(DEBUG_LEVEL_VERBOSE, file, line, false); - _serial.print(text); - printEndColor(DEBUG_LEVEL_VERBOSE); - } -} - -// cppcheck-suppress unusedFunction -void Logger::printD(const String & text, const char * file, uint32_t line) -{ - if (_level >= DEBUG_LEVEL_DEBUG) - { - printStartColor(DEBUG_LEVEL_DEBUG); - printHeader(DEBUG_LEVEL_DEBUG, file, line, false); - _serial.print(text); - printEndColor(DEBUG_LEVEL_DEBUG); - } -} - -// cppcheck-suppress unusedFunction -void Logger::printI(const String & text, const char * file, uint32_t line) -{ - if (_level >= DEBUG_LEVEL_INFO) - { - printStartColor(DEBUG_LEVEL_INFO); - printHeader(DEBUG_LEVEL_INFO, file, line, false); - _serial.print(text); - printEndColor(DEBUG_LEVEL_INFO); - } -} - -// cppcheck-suppress unusedFunction -void Logger::printW(const String & text, const char * file, uint32_t line) -{ - if (_level >= DEBUG_LEVEL_WARN) - { - printStartColor(DEBUG_LEVEL_WARN); - printHeader(DEBUG_LEVEL_WARN, file, line, false); - _serial.print(text); - printEndColor(DEBUG_LEVEL_WARN); - } -} - -// cppcheck-suppress unusedFunction -void Logger::printlnV(const String & text, const char * file, uint32_t line) -{ - if (_level >= DEBUG_LEVEL_VERBOSE) - { - printStartColor(DEBUG_LEVEL_VERBOSE); - printHeader(DEBUG_LEVEL_VERBOSE, file, line, true); - _serial.println(text); - printEndColor(DEBUG_LEVEL_VERBOSE); - } -} - -// cppcheck-suppress unusedFunction -void Logger::printlnD(const String & text, const char * file, uint32_t line) -{ - if (_level >= DEBUG_LEVEL_DEBUG) - { - printStartColor(DEBUG_LEVEL_DEBUG); - printHeader(DEBUG_LEVEL_DEBUG, file, line, true); - _serial.println(text); - printEndColor(DEBUG_LEVEL_DEBUG); - } -} - -// cppcheck-suppress unusedFunction -void Logger::printlnI(const String & text, const char * file, uint32_t line) -{ - if (_level >= DEBUG_LEVEL_INFO) - { - printStartColor(DEBUG_LEVEL_INFO); - printHeader(DEBUG_LEVEL_INFO, file, line, true); - _serial.println(text); - printEndColor(DEBUG_LEVEL_INFO); - } -} - -// cppcheck-suppress unusedFunction -void Logger::printlnW(const String & text, const char * file, uint32_t line) -{ - if (_level >= DEBUG_LEVEL_WARN) - { - printStartColor(DEBUG_LEVEL_WARN); - printHeader(DEBUG_LEVEL_WARN, file, line, true); - _serial.println(text); - printEndColor(DEBUG_LEVEL_WARN); - } -} - -void Logger::printStartColor(debug_level_t level) -{ - switch (level) - { - case DEBUG_LEVEL_ERROR: - _serial.print(LOG_COLOR_E); - break; - case DEBUG_LEVEL_WARN: - _serial.print(LOG_COLOR_W); - break; - case DEBUG_LEVEL_INFO: - _serial.print(LOG_COLOR_I); - break; - case DEBUG_LEVEL_DEBUG: - _serial.print(LOG_COLOR_D); - break; - case DEBUG_LEVEL_VERBOSE: - _serial.print(LOG_COLOR_V); - break; - default: - break; - } -} - -void Logger::printHeader(debug_level_t level, const char * file, uint32_t line, bool isln) -{ - if (_printIsNewline) - { - Serial.printf("%c %25s %4d : ", levelToChar(level), file, line); - if(!isln) - { - _printIsNewline = false; - } - } - else - { - _printIsNewline = isln; - } -} - -void Logger::printEndColor(debug_level_t level) -{ - switch (level) - { - case DEBUG_LEVEL_ERROR: - case DEBUG_LEVEL_WARN: - case DEBUG_LEVEL_INFO: - case DEBUG_LEVEL_DEBUG: - case DEBUG_LEVEL_VERBOSE: - _serial.print(LOG_RESET_COLOR); - break; - default: - break; - } -} - -char Logger::levelToChar(debug_level_t level) -{ - switch (level) - { - case DEBUG_LEVEL_ERROR: - return 'E'; - case DEBUG_LEVEL_WARN: - return 'W'; - case DEBUG_LEVEL_INFO: - return 'I'; - case DEBUG_LEVEL_DEBUG: - return 'D'; - case DEBUG_LEVEL_VERBOSE: - return 'V'; - default: - return ' '; - } -} diff --git a/src/logger.h b/src/logger.h deleted file mode 100644 index 51ddedb..0000000 --- a/src/logger.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef _LOGGER_H_ -#define _LOGGER_H_ - -#include - -class Logger -{ -public: - enum debug_level_t { - DEBUG_LEVEL_NONE, // No debug output - DEBUG_LEVEL_ERROR, // Critical errors - DEBUG_LEVEL_WARN, // Error conditions but not critical - DEBUG_LEVEL_INFO, // Information messages - DEBUG_LEVEL_DEBUG, // Extra information - default level (if not changed) - DEBUG_LEVEL_VERBOSE, // More information than the usual - DEBUG_LEVELS_SIZE - }; - - static Logger & instance() - { - static Logger _instance; - return _instance; - } - - ~Logger() {} - - void setSerial(const HardwareSerial & serial = Serial); - void setDebugLevel(debug_level_t level); - - // print always: - void printA(const String & text, const char * file, uint32_t line); // always - void printE(const String & text, const char * file, uint32_t line); // error - void printlnA(const String & text, const char * file, uint32_t line); // always with new line - void printlnE(const String & text, const char * file, uint32_t line); // error with new line - - // depending on verbose level: - void printV(const String & text, const char * file, uint32_t line); // verbose - void printD(const String & text, const char * file, uint32_t line); // debug - void printI(const String & text, const char * file, uint32_t line); // information - void printW(const String & text, const char * file, uint32_t line); // warning - - void printlnV(const String & text, const char * file, uint32_t line); // verbose with new line - void printlnD(const String & text, const char * file, uint32_t line); // debug with new line - void printlnI(const String & text, const char * file, uint32_t line); // information with new line - void printlnW(const String & text, const char * file, uint32_t line); // warning with new line - -private: - HardwareSerial & _serial; - debug_level_t _level; - bool _printIsNewline; - - void printStartColor(debug_level_t level); - void printHeader(debug_level_t level, const char * file, uint32_t line, bool isln); - void printEndColor(debug_level_t level); - char levelToChar(debug_level_t level); - - Logger(); - Logger(const Logger &); - Logger & operator = (const Logger &); -}; - -#define logPrintA(text) Logger::instance().printA(text, __FILE__, __LINE__) -#define logPrintE(text) Logger::instance().printE(text, __FILE__, __LINE__) -#define logPrintlnA(text) Logger::instance().printlnA(text, __FILE__, __LINE__) -#define logPrintlnE(text) Logger::instance().printlnE(text, __FILE__, __LINE__) -#define logPrintV(text) Logger::instance().printV(text, __FILE__, __LINE__) -#define logPrintD(text) Logger::instance().printD(text, __FILE__, __LINE__) -#define logPrintI(text) Logger::instance().printI(text, __FILE__, __LINE__) -#define logPrintW(text) Logger::instance().printW(text, __FILE__, __LINE__) -#define logPrintlnV(text) Logger::instance().printlnV(text, __FILE__, __LINE__) -#define logPrintlnD(text) Logger::instance().printlnD(text, __FILE__, __LINE__) -#define logPrintlnI(text) Logger::instance().printlnI(text, __FILE__, __LINE__) -#define logPrintlnW(text) Logger::instance().printlnW(text, __FILE__, __LINE__) - -#endif diff --git a/src/pins.h b/src/pins.h deleted file mode 100644 index 4c764cb..0000000 --- a/src/pins.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef PINS_H_ -#define PINS_H_ - -#undef OLED_SDA -#undef OLED_SCL -#undef OLED_RST - -#if defined(HELTEC_WIFI_LORA_32_V1) || defined(HELTEC_WIFI_LORA_32_V2) || defined(TTGO_LORA32_V1) - #define OLED_SDA 4 - #define OLED_SCL 15 -#endif - -#if defined(TTGO_LORA32_V2) || defined(TTGO_T_Beam_V0_7) || defined(TTGO_T_Beam_V1_0) - #define OLED_SDA 21 - #define OLED_SCL 22 -#endif - -#ifdef TRACKERD - #define OLED_SDA 5 - #define OLED_SCL 4 -#endif - -#ifdef ETH_BOARD - #define OLED_SDA 33 - #define OLED_SCL 32 - #define ETH_POWER_PIN -1 - #define ETH_TYPE ETH_PHY_LAN8720 - #define ETH_ADDR 0 - #define ETH_MDC_PIN 23 - #define ETH_MDIO_PIN 18 - #define NRST 5 -#endif - -#ifdef ETH_BOARD_V1_0 - #define ETH_CLK ETH_CLOCK_GPIO17_OUT // TTGO PoE V1.0 -#endif - -#ifdef ETH_BOARD_V1_2 - #define ETH_CLK ETH_CLOCK_GPIO0_OUT // TTGO PoE V1.2 -#endif - - -#undef KEY_BUILTIN -#if defined(TTGO_T_Beam_V0_7) - #define KEY_BUILTIN 39 -#endif - -#if defined(TTGO_T_Beam_V1_0) - #define KEY_BUILTIN 38 -#endif - -#ifndef KEY_BUILTIN - #define KEY_BUILTIN 0 -#endif - -#endif diff --git a/src/power_management.cpp b/src/power_management.cpp deleted file mode 100644 index 8f017b6..0000000 --- a/src/power_management.cpp +++ /dev/null @@ -1,55 +0,0 @@ - -#include "power_management.h" - -// cppcheck-suppress uninitMemberVar -PowerManagement::PowerManagement() -{ -} - -// cppcheck-suppress unusedFunction -bool PowerManagement::begin(TwoWire & port) -{ - bool result = axp.begin(port, AXP192_SLAVE_ADDRESS); - if(!result) - { - axp.setDCDC1Voltage(3300); - } - return result; -} - -// cppcheck-suppress unusedFunction -void PowerManagement::activateLoRa() -{ - axp.setPowerOutPut(AXP192_LDO2, AXP202_ON); -} - -// cppcheck-suppress unusedFunction -void PowerManagement::deactivateLoRa() -{ - axp.setPowerOutPut(AXP192_LDO2, AXP202_OFF); -} - -// cppcheck-suppress unusedFunction -void PowerManagement::activateGPS() -{ - axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); -} - -// cppcheck-suppress unusedFunction -void PowerManagement::deactivateGPS() -{ - axp.setPowerOutPut(AXP192_LDO3, AXP202_OFF); -} - -// cppcheck-suppress unusedFunction -void PowerManagement::activateOLED() -{ - axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON); -} - -// cppcheck-suppress unusedFunction -void PowerManagement::decativateOLED() -{ - axp.setPowerOutPut(AXP192_DCDC1, AXP202_OFF); -} - diff --git a/src/power_management.h b/src/power_management.h deleted file mode 100644 index ecd6cf6..0000000 --- a/src/power_management.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef POWER_MANAGEMENT_H_ -#define POWER_MANAGEMENT_H_ - -#include -#include - -class PowerManagement -{ -public: - PowerManagement(); - bool begin(TwoWire & port); - - void activateLoRa(); - void deactivateLoRa(); - - void activateGPS(); - void deactivateGPS(); - - void activateOLED(); - void decativateOLED(); - -private: - AXP20X_Class axp; -}; - -#endif From fec518d73b0980f7f5ecb8d5d950a386950a2921 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sun, 6 Dec 2020 23:11:54 +0100 Subject: [PATCH 02/60] add github submodule support --- .github/workflows/build_check.yml | 4 ++++ .github/workflows/release.yml | 2 ++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/build_check.yml b/.github/workflows/build_check.yml index a65a723..7034fd3 100644 --- a/.github/workflows/build_check.yml +++ b/.github/workflows/build_check.yml @@ -16,6 +16,8 @@ jobs: - run: pip3 install platformio - run: echo "$HOME/.local/bin" >> $GITHUB_PATH - uses: actions/checkout@v2 + with: + submodules: 'recursive' - run: platformio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high --skip-packages --flags "--suppress=*:*.pio\* --inline-suppr" -v PlatformIO-Build: @@ -25,6 +27,8 @@ jobs: - run: pip3 install platformio - run: echo "$HOME/.local/bin" >> $GITHUB_PATH - uses: actions/checkout@v2 + with: + submodules: 'recursive' - run: platformio run - uses: actions/upload-artifact@v2 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8c763dc..8edda0f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,6 +14,8 @@ jobs: - run: pip3 install platformio - run: echo "$HOME/.local/bin" >> $GITHUB_PATH - uses: actions/checkout@v2 + with: + submodules: 'recursive' - run: platformio run - id: create_release uses: actions/create-release@v1 From d0cfe7f580f7d5f5a5644a8d56f1e49b82b6ccba Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sun, 6 Dec 2020 23:51:59 +0100 Subject: [PATCH 03/60] update config handling on project level --- .gitmodules | 2 +- lib | 1 - lib/Common | 1 + src/LoRa_APRS_iGate.cpp | 112 +++++++++++++++---------------- src/project_configuration.cpp | 109 ++++++++++++++++++++++++++++++ src/project_configuration.h | 121 ++++++++++++++++++++++++++++++++++ 6 files changed, 288 insertions(+), 58 deletions(-) delete mode 160000 lib create mode 160000 lib/Common create mode 100644 src/project_configuration.cpp create mode 100644 src/project_configuration.h diff --git a/.gitmodules b/.gitmodules index 37a6bca..2a34780 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "lib"] - path = lib + path = lib/Common url = ../LoRa_APRS_Common diff --git a/lib b/lib deleted file mode 160000 index 757733b..0000000 --- a/lib +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 757733be04730095a27be008363b4f51dd68bacb diff --git a/lib/Common b/lib/Common new file mode 160000 index 0000000..ae8be81 --- /dev/null +++ b/lib/Common @@ -0,0 +1 @@ +Subproject commit ae8be81399487ba62ea04bc771d2c628c41135c4 diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index 51c1c17..bde09dc 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -17,7 +17,7 @@ #include "pins.h" #include "display.h" -#include "configuration.h" +#include "project_configuration.h" #if defined(ARDUINO_T_Beam) && !defined(ARDUINO_T_Beam_V0_7) #include "power_management.h" @@ -35,7 +35,7 @@ WiFiMulti WiFiMulti; WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP, 60*60); FTPServer ftpServer; -Configuration Config; +Configuration * Config; APRS_IS * aprs_is = 0; LoRa_APRS lora_aprs; std::shared_ptr BeaconMsg; @@ -97,7 +97,7 @@ void setup() setup_ftp(); setup_aprs_is(); #else - if(Config.wifi.active) + if(Config->wifi.active) { setup_wifi(); setup_ota(); @@ -110,14 +110,14 @@ void setup() WiFi.mode(WIFI_OFF); btStop(); } - if(Config.aprs_is.active) setup_aprs_is(); + if(Config->aprs_is.active) setup_aprs_is(); #endif setup_timer(); - if(Config.display.overwritePin != 0) + if(Config->display.overwritePin != 0) { - pinMode(Config.display.overwritePin, INPUT); - pinMode(Config.display.overwritePin, INPUT_PULLUP); + pinMode(Config->display.overwritePin, INPUT); + pinMode(Config->display.overwritePin, INPUT_PULLUP); } delay(500); @@ -129,37 +129,37 @@ void setup() void loop() { static bool display_is_on = true; - if(Config.display.overwritePin != 0 && !digitalRead(Config.display.overwritePin)) + if(Config->display.overwritePin != 0 && !digitalRead(Config->display.overwritePin)) { secondsSinceDisplay = 0; display_is_on = true; setup_display(); } else - if(!Config.display.alwaysOn && secondsSinceDisplay > Config.display.timeout && display_is_on) + if(!Config->display.alwaysOn && secondsSinceDisplay > Config->display.timeout && display_is_on) { turn_off_display(); display_is_on = false; } - static bool beacon_aprs_is = Config.aprs_is.active && Config.aprs_is.beacon; - static bool beacon_digi = Config.digi.active && Config.digi.beacon; + static bool beacon_aprs_is = Config->aprs_is.active && Config->aprs_is.beacon; + static bool beacon_digi = Config->digi.active && Config->digi.beacon; - if(Config.aprs_is.active && Config.aprs_is.beacon && secondsSinceLastAPRSISBeacon >= (Config.aprs_is.beaconTimeout*60)) + if(Config->aprs_is.active && Config->aprs_is.beacon && secondsSinceLastAPRSISBeacon >= (Config->aprs_is.beaconTimeout*60)) { portENTER_CRITICAL(&timerMux); - secondsSinceLastAPRSISBeacon -= (Config.aprs_is.beaconTimeout*60); + secondsSinceLastAPRSISBeacon -= (Config->aprs_is.beaconTimeout*60); portEXIT_CRITICAL(&timerMux); beacon_aprs_is = true; } - if(Config.digi.active && Config.digi.beacon && secondsSinceLastDigiBeacon >= (Config.digi.beaconTimeout*60)) + if(Config->digi.active && Config->digi.beacon && secondsSinceLastDigiBeacon >= (Config->digi.beaconTimeout*60)) { portENTER_CRITICAL(&timerMux); - secondsSinceLastDigiBeacon -= (Config.digi.beaconTimeout*60); + secondsSinceLastDigiBeacon -= (Config->digi.beaconTimeout*60); portEXIT_CRITICAL(&timerMux); beacon_digi = true; } - if(Config.ftp.active) + if(Config->ftp.active) { ftpServer.handle(); static bool configWasOpen = false; @@ -175,8 +175,8 @@ void loop() } } - if(Config.wifi.active || eth_connected) ArduinoOTA.handle(); - if(Config.wifi.active && WiFiMulti.run() != WL_CONNECTED) + if(Config->wifi.active || eth_connected) ArduinoOTA.handle(); + if(Config->wifi.active && WiFiMulti.run() != WL_CONNECTED) { setup_display(); secondsSinceDisplay = 0; display_is_on = true; logPrintlnE("WiFi not connected!"); @@ -184,15 +184,15 @@ void loop() delay(1000); return; } - if((eth_connected && !aprs_is->connected()) || (Config.aprs_is.active && !aprs_is->connected())) + if((eth_connected && !aprs_is->connected()) || (Config->aprs_is.active && !aprs_is->connected())) { setup_display(); secondsSinceDisplay = 0; display_is_on = true; logPrintI("connecting to APRS-IS server: "); - logPrintI(Config.aprs_is.server); + logPrintI(Config->aprs_is.server); logPrintI(" on port: "); - logPrintlnI(String(Config.aprs_is.port)); + logPrintlnI(String(Config->aprs_is.port)); show_display("INFO", "Connecting to APRS-IS server"); - if(!aprs_is->connect(Config.aprs_is.server, Config.aprs_is.port)) + if(!aprs_is->connect(Config->aprs_is.server, Config->aprs_is.port)) { logPrintlnE("Connection failed."); logPrintlnI("Waiting 5 seconds before retrying..."); @@ -202,7 +202,7 @@ void loop() } logPrintlnI("Connected to APRS-IS server!"); } - if(Config.aprs_is.active && aprs_is->available() > 0) + if(Config->aprs_is.active && aprs_is->available() > 0) { String str = aprs_is->getMessage(); logPrintD("[" + timeClient.getFormattedTime() + "] "); @@ -213,7 +213,7 @@ void loop() std::shared_ptr msg = lora_aprs.getMessage(); setup_display(); secondsSinceDisplay = 0; display_is_on = true; - show_display(Config.callsign, timeClient.getFormattedTime() + " LoRa", "RSSI: " + String(lora_aprs.packetRssi()) + ", SNR: " + String(lora_aprs.packetSnr()), msg->toString()); + show_display(Config->callsign, timeClient.getFormattedTime() + " LoRa", "RSSI: " + String(lora_aprs.packetRssi()) + ", SNR: " + String(lora_aprs.packetSnr()), msg->toString()); logPrintD("[" + timeClient.getFormattedTime() + "] "); logPrintD(" Received packet '"); logPrintD(msg->toString()); @@ -222,13 +222,13 @@ void loop() logPrintD(" and SNR "); logPrintlnD(String(lora_aprs.packetSnr())); - if(Config.aprs_is.active) + if(Config->aprs_is.active) { aprs_is->sendMessage(msg->encode()); } - if(Config.digi.active) + if(Config->digi.active) { - if(msg->getSource().indexOf(Config.callsign) != -1) + if(msg->getSource().indexOf(Config->callsign) != -1) { logPrintD("Message already received as repeater: '"); logPrintD(msg->toString()); @@ -254,14 +254,14 @@ void loop() if(foundMsg == lastMessages.end()) { setup_display(); secondsSinceDisplay = 0; display_is_on = true; - show_display(Config.callsign, "RSSI: " + String(lora_aprs.packetRssi()) + ", SNR: " + String(lora_aprs.packetSnr()), msg->toString(), 0); + show_display(Config->callsign, "RSSI: " + String(lora_aprs.packetRssi()) + ", SNR: " + String(lora_aprs.packetSnr()), msg->toString(), 0); logPrintD("Received packet '"); logPrintD(msg->toString()); logPrintD("' with RSSI "); logPrintD(String(lora_aprs.packetRssi())); logPrintD(" and SNR "); logPrintlnD(String(lora_aprs.packetSnr())); - msg->setPath(String(Config.callsign) + "*"); + msg->setPath(String(Config->callsign) + "*"); lora_aprs.sendMessage(msg); lastMessages.insert({secondsSinceStartup, msg}); } @@ -277,11 +277,11 @@ void loop() return; } } - if(Config.digi.active) + if(Config->digi.active) { for(std::map>::iterator iter = lastMessages.begin(); iter != lastMessages.end(); ) { - if(secondsSinceStartup >= iter->first + Config.digi.forwardTimeout*60) + if(secondsSinceStartup >= iter->first + Config->digi.forwardTimeout*60) { iter = lastMessages.erase(iter); } @@ -295,30 +295,30 @@ void loop() { beacon_digi = false; setup_display(); secondsSinceDisplay = 0; display_is_on = true; - show_display(Config.callsign, "Beacon to HF..."); + show_display(Config->callsign, "Beacon to HF..."); logPrintD("[" + timeClient.getFormattedTime() + "] "); logPrintlnD(BeaconMsg->encode()); lora_aprs.sendMessage(BeaconMsg); logPrintlnD("finished TXing..."); - show_display(Config.callsign, "Standby..."); + show_display(Config->callsign, "Standby..."); } if(beacon_aprs_is) { beacon_aprs_is = false; setup_display(); secondsSinceDisplay = 0; display_is_on = true; - show_display(Config.callsign, "Beacon to APRS-IS Server..."); + show_display(Config->callsign, "Beacon to APRS-IS Server..."); logPrintD("[" + timeClient.getFormattedTime() + "] "); logPrintlnD(BeaconMsg->encode()); aprs_is->sendMessage(BeaconMsg); - show_display(Config.callsign, "Standby..."); + show_display(Config->callsign, "Standby..."); } } void load_config() { - ConfigurationManagement confmg("/is-cfg.json"); + ProjectConfigurationManagement confmg; Config = confmg.readConfiguration(); - if(Config.callsign == "NOCALL-10") + if(Config->callsign == "NOCALL-10") { logPrintlnE("You have to change your settings in 'data/is-cfg.json' and upload it via \"Upload File System image\"!"); show_display("ERROR", "You have to change your settings in 'data/is-cfg.json' and upload it via \"Upload File System image\"!"); @@ -327,7 +327,7 @@ void load_config() } #ifndef ETH_BOARD - if(Config.aprs_is.active && !Config.wifi.active) + if(Config->aprs_is.active && !Config->wifi.active) { logPrintlnE("You have to activate Wifi for APRS IS to work, please check your settings!"); show_display("ERROR", "You have to activate Wifi for APRS IS to work, please check your settings!"); @@ -336,9 +336,9 @@ void load_config() } #endif - if(KEY_BUILTIN != 0 && Config.display.overwritePin == 0) + if(KEY_BUILTIN != 0 && Config->display.overwritePin == 0) { - Config.display.overwritePin = KEY_BUILTIN; + Config->display.overwritePin = KEY_BUILTIN; } logPrintlnI("Configuration loaded!"); } @@ -403,8 +403,8 @@ void setup_eth() void setup_wifi() { WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); - WiFi.setHostname(Config.callsign.c_str()); - for(Configuration::Wifi::AP ap : Config.wifi.APs) + WiFi.setHostname(Config->callsign.c_str()); + for(Configuration::Wifi::AP ap : Config->wifi.APs) { logPrintD("Looking for AP: "); logPrintlnD(ap.SSID); @@ -459,34 +459,34 @@ void setup_ota() else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); else if (error == OTA_END_ERROR) Serial.println("End Failed"); }); - ArduinoOTA.setHostname(Config.callsign.c_str()); + ArduinoOTA.setHostname(Config->callsign.c_str()); ArduinoOTA.begin(); logPrintlnI("OTA init done!"); } void setup_lora() { - lora_aprs.setRxFrequency(Config.lora.frequencyRx); - lora_aprs.setTxFrequency(Config.lora.frequencyTx); + lora_aprs.setRxFrequency(Config->lora.frequencyRx); + lora_aprs.setTxFrequency(Config->lora.frequencyTx); if (!lora_aprs.begin(lora_aprs.getRxFrequency())) { logPrintlnE("Starting LoRa failed!"); show_display("ERROR", "Starting LoRa failed!"); while (1); } - lora_aprs.setTxPower(Config.lora.power); - lora_aprs.setSpreadingFactor(Config.lora.spreadingFactor); - lora_aprs.setSignalBandwidth(Config.lora.signalBandwidth); - lora_aprs.setCodingRate4(Config.lora.codingRate4); + lora_aprs.setTxPower(Config->lora.power); + lora_aprs.setSpreadingFactor(Config->lora.spreadingFactor); + lora_aprs.setSignalBandwidth(Config->lora.signalBandwidth); + lora_aprs.setCodingRate4(Config->lora.codingRate4); logPrintlnI("LoRa init done!"); show_display("INFO", "LoRa init done!", 2000); BeaconMsg = std::shared_ptr(new APRSMessage()); - BeaconMsg->setSource(Config.callsign); + BeaconMsg->setSource(Config->callsign); BeaconMsg->setDestination("APLG0"); - String lat = create_lat_aprs(Config.beacon.positionLatitude); - String lng = create_long_aprs(Config.beacon.positionLongitude); - BeaconMsg->getAPRSBody()->setData(String("=") + lat + "I" + lng + "&" + Config.beacon.message); + String lat = create_lat_aprs(Config->beacon.positionLatitude); + String lng = create_long_aprs(Config->beacon.positionLongitude); + BeaconMsg->getAPRSBody()->setData(String("=") + lat + "I" + lng + "&" + Config->beacon.message); } void setup_ntp() @@ -503,7 +503,7 @@ void setup_ntp() void setup_aprs_is() { - aprs_is = new APRS_IS(Config.callsign, Config.aprs_is.password , "ESP32-APRS-IS", "0.1"); + aprs_is = new APRS_IS(Config->callsign, Config->aprs_is.password , "ESP32-APRS-IS", "0.1"); } void IRAM_ATTR onTimer() @@ -526,11 +526,11 @@ void setup_timer() void setup_ftp() { - if(!Config.ftp.active) + if(!Config->ftp.active) { return; } - for(Configuration::Ftp::User user : Config.ftp.users) + for(Configuration::Ftp::User user : Config->ftp.users) { logPrintD("Adding user to FTP Server: "); logPrintlnD(user.name); diff --git a/src/project_configuration.cpp b/src/project_configuration.cpp new file mode 100644 index 0000000..6cfaec8 --- /dev/null +++ b/src/project_configuration.cpp @@ -0,0 +1,109 @@ +#include + +#include "project_configuration.h" +#include "logger.h" + +Configuration * ProjectConfigurationManagement::readProjectConfiguration(DynamicJsonDocument & data) +{ + Configuration * conf = new Configuration; + if(data.containsKey("callsign")) + conf->callsign = data["callsign"].as(); + + conf->wifi.active = data["wifi"]["active"] | false; + JsonArray aps = data["wifi"]["AP"].as(); + for(JsonVariant v : aps) + { + Configuration::Wifi::AP ap; + ap.SSID = v["SSID"].as(); + ap.password = v["password"].as(); + conf->wifi.APs.push_back(ap); + } + if(data.containsKey("beacon") && data["beacon"].containsKey("message")) + conf->beacon.message = data["beacon"]["message"].as(); + conf->beacon.positionLatitude = data["beacon"]["position"]["latitude"] | 0.0; + conf->beacon.positionLongitude = data["beacon"]["position"]["longitude"] | 0.0; + conf->aprs_is.active = data["aprs_is"]["active"] | false; + if(data.containsKey("aprs_is") && data["aprs_is"].containsKey("password")) + conf->aprs_is.password = data["aprs_is"]["password"].as(); + if(data.containsKey("aprs_is") && data["aprs_is"].containsKey("server")) + conf->aprs_is.server = data["aprs_is"]["server"].as(); + conf->aprs_is.port = data["aprs_is"]["port"] | 14580; + conf->aprs_is.beacon = data["aprs_is"]["beacon"] | true; + conf->aprs_is.beaconTimeout = data["aprs_is"]["beacon_timeout"] | 15; + conf->digi.active = data["digi"]["active"] | false; + conf->digi.forwardTimeout = data["digi"]["forward_timeout"] | 5; + conf->digi.beacon = data["digi"]["beacon"] | true; + conf->digi.beaconTimeout = data["digi"]["beacon_timeout"] | 30; + + conf->lora.frequencyRx = data["lora"]["frequency_rx"] | 433775000; + conf->lora.frequencyTx = data["lora"]["frequency_tx"] | 433775000; + conf->lora.power = data["lora"]["power"] | 20; + conf->lora.spreadingFactor = data["lora"]["spreading_factor"] | 12; + conf->lora.signalBandwidth = data["lora"]["signal_bandwidth"] | 125000; + conf->lora.codingRate4 = data["lora"]["coding_rate4"] | 5; + conf->display.alwaysOn = data["display"]["always_on"] | true; + conf->display.timeout = data["display"]["timeout"] | 10; + conf->display.overwritePin = data["display"]["overwrite_pin"] | 0; + + conf->ftp.active = data["ftp"]["active"] | false; + JsonArray users = data["ftp"]["user"].as(); + for(JsonVariant u : users) + { + Configuration::Ftp::User us; + us.name = u["name"].as(); + us.password = u["password"].as(); + conf->ftp.users.push_back(us); + } + if(conf->ftp.users.empty()) + { + Configuration::Ftp::User us; + us.name = "ftp"; + us.password = "ftp"; + conf->ftp.users.push_back(us); + } + + return conf; +} + +void ProjectConfigurationManagement::writeProjectConfiguration(Configuration * conf, DynamicJsonDocument & data) +{ + data["callsign"] = conf->callsign; + data["wifi"]["active"] = conf->wifi.active; + JsonArray aps = data["wifi"].createNestedArray("AP"); + for(Configuration::Wifi::AP ap : conf->wifi.APs) + { + JsonObject v = aps.createNestedObject(); + v["SSID"] = ap.SSID; + v["password"] = ap.password; + } + data["beacon"]["message"] = conf->beacon.message; + data["beacon"]["position"]["latitude"] = conf->beacon.positionLatitude; + data["beacon"]["position"]["longitude"] = conf->beacon.positionLongitude; + data["aprs_is"]["active"] = conf->aprs_is.active; + data["aprs_is"]["password"] = conf->aprs_is.password; + data["aprs_is"]["server"] = conf->aprs_is.server; + data["aprs_is"]["port"] = conf->aprs_is.port; + data["aprs_is"]["beacon"] = conf->aprs_is.beacon; + data["aprs_is"]["beacon_timeout"] = conf->aprs_is.beaconTimeout; + data["digi"]["active"] = conf->digi.active; + data["digi"]["forward_timeout"] = conf->digi.forwardTimeout; + data["digi"]["beacon"] = conf->digi.beacon; + data["digi"]["beacon_timeout"] = conf->digi.beaconTimeout; + data["lora"]["frequency_rx"] = conf->lora.frequencyRx; + data["lora"]["frequency_tx"] = conf->lora.frequencyTx; + data["lora"]["power"] = conf->lora.power; + data["lora"]["spreading_factor"] = conf->lora.spreadingFactor; + data["lora"]["signal_bandwidth"] = conf->lora.signalBandwidth; + data["lora"]["coding_rate4"] = conf->lora.codingRate4; + data["display"]["always_on"] = conf->display.alwaysOn; + data["display"]["timeout"] = conf->display.timeout; + data["display"]["overwrite_pin"] = conf->display.overwritePin; + data["ftp"]["active"] = conf->ftp.active; + JsonArray users = data["ftp"].createNestedArray("user"); + for(Configuration::Ftp::User u : conf->ftp.users) + { + JsonObject v = users.createNestedObject(); + v["name"] = u.name; + v["password"] = u.password; + } +} diff --git a/src/project_configuration.h b/src/project_configuration.h new file mode 100644 index 0000000..5a65724 --- /dev/null +++ b/src/project_configuration.h @@ -0,0 +1,121 @@ +#ifndef PROJECT_CONFIGURATION_H_ +#define PROJECT_CONFIGURATION_H_ + +#include "configuration.h" + +class Configuration +{ +public: + class Wifi + { + public: + class AP + { + public: + String SSID; + String password; + }; + + Wifi() : active(false) {} + + bool active; + std::list APs; + }; + + class Beacon + { + public: + Beacon() : message("LoRa iGATE & Digi, Info: github.com/peterus/LoRa_APRS_iGate"), positionLatitude(0.0), positionLongitude(0.0) {} + + String message; + double positionLatitude; + double positionLongitude; + }; + + class APRS_IS + { + public: + APRS_IS() : active(false), server("euro.aprs2.net"), port(14580), beacon(true), beaconTimeout(15) {} + + bool active; + String password; + String server; + int port; + bool beacon; + int beaconTimeout; + }; + + class Digi + { + public: + Digi() : active(false), forwardTimeout(5), beacon(true), beaconTimeout(30) {} + + bool active; + int forwardTimeout; + bool beacon; + int beaconTimeout; + }; + + class LoRa + { + public: + LoRa() : frequencyRx(433775000), frequencyTx(433775000), power(20), spreadingFactor(12), signalBandwidth(125000), codingRate4(5) {} + + long frequencyRx; + long frequencyTx; + int power; + int spreadingFactor; + long signalBandwidth; + int codingRate4; + }; + + class Display + { + public: + Display() : alwaysOn(true), timeout(10), overwritePin(0) {} + + bool alwaysOn; + int timeout; + int overwritePin; + }; + + class Ftp + { + public: + class User + { + public: + String name; + String password; + }; + + Ftp() : active(false) {} + + bool active; + std::list users; + }; + + Configuration() : callsign("NOCALL-10") {}; + + String callsign; + Wifi wifi; + Beacon beacon; + APRS_IS aprs_is; + Digi digi; + LoRa lora; + Display display; + Ftp ftp; +}; + +class ProjectConfigurationManagement : public ConfigurationManagement +{ +public: + explicit ProjectConfigurationManagement() : ConfigurationManagement("/is-cfg.json") {} + virtual ~ProjectConfigurationManagement() {} + +private: + virtual Configuration * readProjectConfiguration(DynamicJsonDocument & data); + virtual void writeProjectConfiguration(Configuration * conf, DynamicJsonDocument & data); +}; + +#endif From 9a9b494ab9fa9c892174bc18a0197aaa3fb8bf4d Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sun, 6 Dec 2020 23:54:35 +0100 Subject: [PATCH 04/60] lib update --- lib/Common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Common b/lib/Common index ae8be81..87d7cb9 160000 --- a/lib/Common +++ b/lib/Common @@ -1 +1 @@ -Subproject commit ae8be81399487ba62ea04bc771d2c628c41135c4 +Subproject commit 87d7cb9c81d691acb3a22a0b26ca071be56d1816 From fa5e1736fa6c1c07342d3f6e399a4e9039382b07 Mon Sep 17 00:00:00 2001 From: "Stefan Schultheis, OE1SCS" Date: Wed, 9 Dec 2020 22:15:05 +0100 Subject: [PATCH 05/60] typo inside comment, platformio.ini --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index d03274d..0a1f8c6 100644 --- a/platformio.ini +++ b/platformio.ini @@ -18,7 +18,7 @@ check_tool = cppcheck check_flags = cppcheck: --suppress=*:*.pio\* --inline-suppr monitor_flags = --raw -# activate for OTA Update, use the CALLSIGN from is-cfg.h as upload_port: +# activate for OTA Update, use the CALLSIGN from is-cfg.json as upload_port: #upload_protocol = espota #upload_port = .local From 7ae1238fe625dc5540ef5e3ff3877ab5e79bd681 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sun, 13 Dec 2020 22:05:53 +0100 Subject: [PATCH 06/60] working cppcheck --- .github/workflows/build_check.yml | 2 +- .gitmodules | 2 +- lib/{Common => common} | 0 platformio.ini | 2 +- src/project_configuration.h | 4 ++-- 5 files changed, 5 insertions(+), 5 deletions(-) rename lib/{Common => common} (100%) diff --git a/.github/workflows/build_check.yml b/.github/workflows/build_check.yml index 7034fd3..3298f0b 100644 --- a/.github/workflows/build_check.yml +++ b/.github/workflows/build_check.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/checkout@v2 with: submodules: 'recursive' - - run: platformio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high --skip-packages --flags "--suppress=*:*.pio\* --inline-suppr" -v + - run: platformio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high --skip-packages --flags "--suppress=*:*.pio\* --inline-suppr lib/common/src" -v PlatformIO-Build: runs-on: ubuntu-latest diff --git a/.gitmodules b/.gitmodules index 2a34780..e8683d4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "lib"] - path = lib/Common + path = lib/common url = ../LoRa_APRS_Common diff --git a/lib/Common b/lib/common similarity index 100% rename from lib/Common rename to lib/common diff --git a/platformio.ini b/platformio.ini index d03274d..5a3bcde 100644 --- a/platformio.ini +++ b/platformio.ini @@ -16,7 +16,7 @@ lib_deps = peterus/LoRa-APRS-Lib @ 0.0.5 check_tool = cppcheck check_flags = - cppcheck: --suppress=*:*.pio\* --inline-suppr + cppcheck: --suppress=*:*.pio\* --inline-suppr lib/common/src monitor_flags = --raw # activate for OTA Update, use the CALLSIGN from is-cfg.h as upload_port: #upload_protocol = espota diff --git a/src/project_configuration.h b/src/project_configuration.h index 5a65724..1e8a71a 100644 --- a/src/project_configuration.h +++ b/src/project_configuration.h @@ -114,8 +114,8 @@ public: virtual ~ProjectConfigurationManagement() {} private: - virtual Configuration * readProjectConfiguration(DynamicJsonDocument & data); - virtual void writeProjectConfiguration(Configuration * conf, DynamicJsonDocument & data); + virtual Configuration * readProjectConfiguration(DynamicJsonDocument & data) override; + virtual void writeProjectConfiguration(Configuration * conf, DynamicJsonDocument & data) override; }; #endif From 394fde0b52a083e030e3912a57eba8bd49f7c121 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sun, 13 Dec 2020 22:45:49 +0100 Subject: [PATCH 07/60] force version --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 03c4358..4a9a7a5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1,5 +1,5 @@ [env] -platform = espressif32 +platform = espressif32 @ 2.1.0 framework = arduino lib_ldf_mode = deep+ monitor_speed = 115200 From 7313d15c2defc0f1511cb6b74ecfcfb9e543b5a3 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sun, 13 Dec 2020 23:04:32 +0100 Subject: [PATCH 08/60] add french quick start link --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ac540ec..d90874f 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ Keep in minde: you need a 433MHz version! ## Compiling and configuration **There is a german [quick start](https://www.lora-aprs.info/docs/LoRa_APRS_iGate/quick-start-guide/) page! Take a look ;)** +**There is a french [quick start](http://www.f5kmy.fr/spip.php?article509) page! Take a look ;)** ### How to compile From f6422c47a576ecc81f3ca5cd8a4d30c178cdd87d Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sun, 13 Dec 2020 23:25:06 +0100 Subject: [PATCH 09/60] update common --- lib/common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common b/lib/common index 87d7cb9..c182327 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit 87d7cb9c81d691acb3a22a0b26ca071be56d1816 +Subproject commit c182327d8c8174bdead1c0e5cf46e64a7a3b2146 From 16acd0a6d03976bd673cbbbbf4d550b38121b0de Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sun, 13 Dec 2020 23:32:02 +0100 Subject: [PATCH 10/60] update --- lib/common | 2 +- platformio.ini | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/common b/lib/common index c182327..4f0b027 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit c182327d8c8174bdead1c0e5cf46e64a7a3b2146 +Subproject commit 4f0b027ea868dbd40907f0f97d5f8f57df958b76 diff --git a/platformio.ini b/platformio.ini index 4a9a7a5..5e65a42 100644 --- a/platformio.ini +++ b/platformio.ini @@ -13,7 +13,6 @@ lib_deps = peterus/APRS-Decoder-Lib @ 0.0.5 peterus/APRS-IS-Lib @ 0.0.7 peterus/ESP-FTP-Server-Lib @ 0.9.4 - peterus/LoRa-APRS-Lib @ 0.0.5 check_tool = cppcheck check_flags = cppcheck: --suppress=*:*.pio\* --inline-suppr lib/common/src From 04831ba93fff96e28e0fb0920dd3879236802f42 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sun, 13 Dec 2020 23:53:37 +0100 Subject: [PATCH 11/60] remove lora pin definition from ini file and move it to common --- lib/common | 2 +- platformio.ini | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/common b/lib/common index 4f0b027..3a244e5 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit 4f0b027ea868dbd40907f0f97d5f8f57df958b76 +Subproject commit 3a244e533140c3447a081e032614b6684d433499 diff --git a/platformio.ini b/platformio.ini index 5e65a42..847f21e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -47,12 +47,12 @@ build_flags = -Werror -Wall -DTTGO_T_Beam_V0_7 [env:TrackerD-OE1ACM] board = esp32doit-devkit-v1 -build_flags = -Werror -Wall -DTRACKERD -DLORA_SCK=18 -DLORA_MISO=19 -DLORA_MOSI=23 -DLORA_CS=16 -DLORA_RST=14 -DLORA_IRQ=26 +build_flags = -Werror -Wall -DTRACKERD [env:ttgo-poe-v1_0] board = esp32doit-devkit-v1 -build_flags = -Werror -Wall -DETH_BOARD -DETH_BOARD_V1_0 -DLORA_SCK=14 -DLORA_MISO=2 -DLORA_MOSI=15 -DLORA_CS=12 -DLORA_RST=4 -DLORA_IRQ=36 +build_flags = -Werror -Wall -DETH_BOARD -DETH_BOARD_V1_0 [env:ttgo-poe-v1_2] board = esp32doit-devkit-v1 -build_flags = -Werror -Wall -DETH_BOARD -DETH_BOARD_V1_2 -DLORA_SCK=14 -DLORA_MISO=2 -DLORA_MOSI=15 -DLORA_CS=12 -DLORA_RST=4 -DLORA_IRQ=36 +build_flags = -Werror -Wall -DETH_BOARD -DETH_BOARD_V1_2 From 12ff22ca75d126cd67c119b04ffe63712402fd6b Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Mon, 14 Dec 2020 00:08:48 +0100 Subject: [PATCH 12/60] add empty line to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d90874f..364ab1c 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ Keep in minde: you need a 433MHz version! ## Compiling and configuration **There is a german [quick start](https://www.lora-aprs.info/docs/LoRa_APRS_iGate/quick-start-guide/) page! Take a look ;)** + **There is a french [quick start](http://www.f5kmy.fr/spip.php?article509) page! Take a look ;)** ### How to compile From 7a0f3661dc9515cd5e6cb85232cdffc625f12168 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Thu, 17 Dec 2020 22:13:06 +0100 Subject: [PATCH 13/60] changes ini: - update ftp lib to 0.9.5 - remove all board configs config: - add ntp server seetting - add board config code: - add board finder - NO_GLOBAL_INSTANCES - ntp server config - modem config update (not found bugs fixed) libs: - update common lib - update ntp lib --- data/is-cfg.json | 3 +- lib/common | 2 +- platformio.ini | 37 +----- src/LoRa_APRS_iGate.cpp | 212 ++++++++++++++++++++-------------- src/project_configuration.cpp | 8 ++ src/project_configuration.h | 4 +- 6 files changed, 142 insertions(+), 124 deletions(-) diff --git a/data/is-cfg.json b/data/is-cfg.json index 8c3ed65..0fdfdb5 100644 --- a/data/is-cfg.json +++ b/data/is-cfg.json @@ -53,5 +53,6 @@ "user": [ { "name":"ftp", "password":"ftp" } ] - } + }, + "ntp_server": "pool.ntp.org" } diff --git a/lib/common b/lib/common index 3a244e5..b93d7b8 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit 3a244e533140c3447a081e032614b6684d433499 +Subproject commit b93d7b8a5bcab57d4bf453ba6ce1352b61e5cd37 diff --git a/platformio.ini b/platformio.ini index 847f21e..e3808e9 100644 --- a/platformio.ini +++ b/platformio.ini @@ -12,7 +12,7 @@ lib_deps = sandeepmistry/LoRa @ 0.7.2 peterus/APRS-Decoder-Lib @ 0.0.5 peterus/APRS-IS-Lib @ 0.0.7 - peterus/ESP-FTP-Server-Lib @ 0.9.4 + peterus/ESP-FTP-Server-Lib @ 0.9.5 check_tool = cppcheck check_flags = cppcheck: --suppress=*:*.pio\* --inline-suppr lib/common/src @@ -21,38 +21,7 @@ monitor_flags = --raw #upload_protocol = espota #upload_port = .local -[env:heltec_wifi_lora_32_v1] -board = ttgo-lora32-v1 -build_flags = -Werror -Wall -DHELTEC_WIFI_LORA_32_V1 -[env:heltec_wifi_lora_32_v2] -board = ttgo-lora32-v1 -build_flags = -Werror -Wall -DHELTEC_WIFI_LORA_32_V2 - -[env:ttgo-lora32-v1] -board = ttgo-lora32-v1 -build_flags = -Werror -Wall -DTTGO_LORA32_V1 - -[env:ttgo-lora32-v2] -board = ttgo-lora32-v1 -build_flags = -Werror -Wall -DTTGO_LORA32_V2 - -[env:ttgo-t-beam-v1] -board = ttgo-t-beam -build_flags = -Werror -Wall -DTTGO_T_Beam_V1_0 - -[env:ttgo-t-beam-v0_7] -board = ttgo-t-beam -build_flags = -Werror -Wall -DTTGO_T_Beam_V0_7 - -[env:TrackerD-OE1ACM] +[env:lora_board] board = esp32doit-devkit-v1 -build_flags = -Werror -Wall -DTRACKERD - -[env:ttgo-poe-v1_0] -board = esp32doit-devkit-v1 -build_flags = -Werror -Wall -DETH_BOARD -DETH_BOARD_V1_0 - -[env:ttgo-poe-v1_2] -board = esp32doit-devkit-v1 -build_flags = -Werror -Wall -DETH_BOARD -DETH_BOARD_V1_2 +build_flags = -Werror -Wall -DNO_GLOBAL_INSTANCES diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index bde09dc..431337e 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -12,17 +12,19 @@ #include #include "logger.h" - +#include "BoardFinder.h" #include "LoRa_APRS.h" - #include "pins.h" #include "display.h" #include "project_configuration.h" -#if defined(ARDUINO_T_Beam) && !defined(ARDUINO_T_Beam_V0_7) +#ifdef NO_GLOBAL_INSTANCES +HardwareSerial Serial(0); +ArduinoOTAClass ArduinoOTA; +#endif + #include "power_management.h" PowerManagement powerManagement; -#endif portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; hw_timer_t * timer = NULL; @@ -33,11 +35,12 @@ volatile uint secondsSinceDisplay = 0; WiFiMulti WiFiMulti; WiFiUDP ntpUDP; -NTPClient timeClient(ntpUDP, 60*60); +NTPClient * timeClient; FTPServer ftpServer; Configuration * Config; +std::shared_ptr boardConfig; APRS_IS * aprs_is = 0; -LoRa_APRS lora_aprs; +LoRa_APRS * lora_aprs; std::shared_ptr BeaconMsg; volatile bool eth_connected = false; @@ -45,11 +48,8 @@ volatile bool eth_connected = false; String create_lat_aprs(double lat); String create_long_aprs(double lng); -#ifdef ETH_BOARD void setup_eth(); -#else void setup_wifi(); -#endif void load_config(); void setup_wifi(); @@ -66,52 +66,83 @@ std::map> lastMessages; void setup() { Serial.begin(115200); - -#if defined(ARDUINO_T_Beam) && !defined(ARDUINO_T_Beam_V0_7) - Wire.begin(SDA, SCL); - if (!powerManagement.begin(Wire)) - { - logPrintlnI("AXP192 init done!"); - } - else - { - logPrintlnE("AXP192 init failed!"); - } - powerManagement.activateLoRa(); - powerManagement.activateOLED(); - powerManagement.deactivateGPS(); -#endif - + Logger::instance().setSerial(&Serial); delay(500); - logPrintlnA("LoRa APRS iGate & Digi by OE5BPA (Peter Buchegger)"); - logPrintlnA("Version: 20.49.0-dev"); - setup_display(); + + ProjectConfigurationManagement confmg; + Config = confmg.readConfiguration(); + + BoardFinder finder; + boardConfig = finder.getBoardConfig(Config->board); + if(boardConfig == 0) + { + boardConfig = finder.searchBoardConfig(); + if(boardConfig == 0) + { + logPrintlnE("Board config not set and search failed!"); + while (true) + { + } + } + Config->board = boardConfig->Name; + confmg.writeConfiguration(Config); + logPrintlnI("will restart board now!"); + ESP.restart(); + } + logPrintI("Board "); + logPrintI(boardConfig->Name); + logPrintlnI(" loaded."); + + if(boardConfig->Type == eTTGO_T_Beam_V1_0) + { + TwoWire wire(0); + wire.begin(boardConfig->OledSda, boardConfig->OledScl); + if (!powerManagement.begin(wire)) + { + logPrintlnI("AXP192 init done!"); + } + else + { + logPrintlnE("AXP192 init failed!"); + } + powerManagement.activateLoRa(); + powerManagement.activateOLED(); + powerManagement.deactivateGPS(); + } + + logPrintlnW("LoRa APRS iGate & Digi by OE5BPA (Peter Buchegger)"); + logPrintlnW("Version: 20.49.0-dev"); + setup_display(boardConfig); show_display("OE5BPA", "LoRa APRS iGate & Digi", "by Peter Buchegger", "20.49.0-dev", 3000); load_config(); setup_lora(); -#ifdef ETH_BOARD - setup_eth(); - setup_ota(); - setup_ntp(); - setup_ftp(); - setup_aprs_is(); -#else - if(Config->wifi.active) + timeClient = new NTPClient(ntpUDP, Config->ntpServer.c_str()); + if(boardConfig->Type == eETH_BOARD) { - setup_wifi(); + setup_eth(); setup_ota(); setup_ntp(); setup_ftp(); + setup_aprs_is(); } else { - // make sure wifi and bt is off if we don't need it: - WiFi.mode(WIFI_OFF); - btStop(); + if(Config->wifi.active) + { + setup_wifi(); + setup_ota(); + setup_ntp(); + setup_ftp(); + } + else + { + // make sure wifi and bt is off if we don't need it: + WiFi.mode(WIFI_OFF); + btStop(); + } + if(Config->aprs_is.active) setup_aprs_is(); } - if(Config->aprs_is.active) setup_aprs_is(); -#endif setup_timer(); if(Config->display.overwritePin != 0) @@ -133,7 +164,7 @@ void loop() { secondsSinceDisplay = 0; display_is_on = true; - setup_display(); + setup_display(boardConfig); } else if(!Config->display.alwaysOn && secondsSinceDisplay > Config->display.timeout && display_is_on) { @@ -178,7 +209,7 @@ void loop() if(Config->wifi.active || eth_connected) ArduinoOTA.handle(); if(Config->wifi.active && WiFiMulti.run() != WL_CONNECTED) { - setup_display(); secondsSinceDisplay = 0; display_is_on = true; + setup_display(boardConfig); secondsSinceDisplay = 0; display_is_on = true; logPrintlnE("WiFi not connected!"); show_display("ERROR", "WiFi not connected!"); delay(1000); @@ -186,7 +217,7 @@ void loop() } if((eth_connected && !aprs_is->connected()) || (Config->aprs_is.active && !aprs_is->connected())) { - setup_display(); secondsSinceDisplay = 0; display_is_on = true; + setup_display(boardConfig); secondsSinceDisplay = 0; display_is_on = true; logPrintI("connecting to APRS-IS server: "); logPrintI(Config->aprs_is.server); logPrintI(" on port: "); @@ -205,22 +236,22 @@ void loop() if(Config->aprs_is.active && aprs_is->available() > 0) { String str = aprs_is->getMessage(); - logPrintD("[" + timeClient.getFormattedTime() + "] "); + logPrintD("[" + timeClient->getFormattedTime() + "] "); logPrintlnD(str); } - if(lora_aprs.hasMessage()) + if(lora_aprs->hasMessage()) { - std::shared_ptr msg = lora_aprs.getMessage(); + std::shared_ptr msg = lora_aprs->getMessage(); - setup_display(); secondsSinceDisplay = 0; display_is_on = true; - show_display(Config->callsign, timeClient.getFormattedTime() + " LoRa", "RSSI: " + String(lora_aprs.packetRssi()) + ", SNR: " + String(lora_aprs.packetSnr()), msg->toString()); - logPrintD("[" + timeClient.getFormattedTime() + "] "); + setup_display(boardConfig); secondsSinceDisplay = 0; display_is_on = true; + show_display(Config->callsign, timeClient->getFormattedTime() + " LoRa", "RSSI: " + String(lora_aprs->packetRssi()) + ", SNR: " + String(lora_aprs->packetSnr()), msg->toString()); + logPrintD("[" + timeClient->getFormattedTime() + "] "); logPrintD(" Received packet '"); logPrintD(msg->toString()); logPrintD("' with RSSI "); - logPrintD(String(lora_aprs.packetRssi())); + logPrintD(String(lora_aprs->packetRssi())); logPrintD(" and SNR "); - logPrintlnD(String(lora_aprs.packetSnr())); + logPrintlnD(String(lora_aprs->packetSnr())); if(Config->aprs_is.active) { @@ -233,9 +264,9 @@ void loop() logPrintD("Message already received as repeater: '"); logPrintD(msg->toString()); logPrintD("' with RSSI "); - logPrintD(String(lora_aprs.packetRssi())); + logPrintD(String(lora_aprs->packetRssi())); logPrintD(" and SNR "); - logPrintlnD(String(lora_aprs.packetSnr())); + logPrintlnD(String(lora_aprs->packetSnr())); return; } @@ -253,16 +284,16 @@ void loop() if(foundMsg == lastMessages.end()) { - setup_display(); secondsSinceDisplay = 0; display_is_on = true; - show_display(Config->callsign, "RSSI: " + String(lora_aprs.packetRssi()) + ", SNR: " + String(lora_aprs.packetSnr()), msg->toString(), 0); + setup_display(boardConfig); secondsSinceDisplay = 0; display_is_on = true; + show_display(Config->callsign, "RSSI: " + String(lora_aprs->packetRssi()) + ", SNR: " + String(lora_aprs->packetSnr()), msg->toString(), 0); logPrintD("Received packet '"); logPrintD(msg->toString()); logPrintD("' with RSSI "); - logPrintD(String(lora_aprs.packetRssi())); + logPrintD(String(lora_aprs->packetRssi())); logPrintD(" and SNR "); - logPrintlnD(String(lora_aprs.packetSnr())); + logPrintlnD(String(lora_aprs->packetSnr())); msg->setPath(String(Config->callsign) + "*"); - lora_aprs.sendMessage(msg); + lora_aprs->sendMessage(msg); lastMessages.insert({secondsSinceStartup, msg}); } else @@ -270,9 +301,9 @@ void loop() logPrintD("Message already received (timeout): '"); logPrintD(msg->toString()); logPrintD("' with RSSI "); - logPrintD(String(lora_aprs.packetRssi())); + logPrintD(String(lora_aprs->packetRssi())); logPrintD(" and SNR "); - logPrintlnD(String(lora_aprs.packetSnr())); + logPrintlnD(String(lora_aprs->packetSnr())); } return; } @@ -294,20 +325,20 @@ void loop() if(beacon_digi) { beacon_digi = false; - setup_display(); secondsSinceDisplay = 0; display_is_on = true; + setup_display(boardConfig); secondsSinceDisplay = 0; display_is_on = true; show_display(Config->callsign, "Beacon to HF..."); - logPrintD("[" + timeClient.getFormattedTime() + "] "); + logPrintD("[" + timeClient->getFormattedTime() + "] "); logPrintlnD(BeaconMsg->encode()); - lora_aprs.sendMessage(BeaconMsg); + lora_aprs->sendMessage(BeaconMsg); logPrintlnD("finished TXing..."); show_display(Config->callsign, "Standby..."); } if(beacon_aprs_is) { beacon_aprs_is = false; - setup_display(); secondsSinceDisplay = 0; display_is_on = true; + setup_display(boardConfig); secondsSinceDisplay = 0; display_is_on = true; show_display(Config->callsign, "Beacon to APRS-IS Server..."); - logPrintD("[" + timeClient.getFormattedTime() + "] "); + logPrintD("[" + timeClient->getFormattedTime() + "] "); logPrintlnD(BeaconMsg->encode()); aprs_is->sendMessage(BeaconMsg); show_display(Config->callsign, "Standby..."); @@ -326,15 +357,13 @@ void load_config() {} } -#ifndef ETH_BOARD - if(Config->aprs_is.active && !Config->wifi.active) + if(boardConfig->Type != eETH_BOARD && Config->aprs_is.active && !Config->wifi.active) { logPrintlnE("You have to activate Wifi for APRS IS to work, please check your settings!"); show_display("ERROR", "You have to activate Wifi for APRS IS to work, please check your settings!"); while (true) {} } -#endif if(KEY_BUILTIN != 0 && Config->display.overwritePin == 0) { @@ -343,7 +372,6 @@ void load_config() logPrintlnI("Configuration loaded!"); } -#ifdef ETH_BOARD void WiFiEvent(WiFiEvent_t event) { switch (event) { @@ -384,14 +412,23 @@ void setup_eth() { WiFi.onEvent(WiFiEvent); - pinMode(NRST, OUTPUT); - digitalWrite(NRST, 0); + #define ETH_POWER_PIN -1 + #define ETH_TYPE ETH_PHY_LAN8720 + #define ETH_ADDR 0 + #define ETH_MDC_PIN 23 + #define ETH_MDIO_PIN 18 + #define ETH_NRST 5 + #define ETH_CLK ETH_CLOCK_GPIO17_OUT // TTGO PoE V1.0 + //#define ETH_CLK ETH_CLOCK_GPIO0_OUT // TTGO PoE V1.2 + + pinMode(ETH_NRST, OUTPUT); + digitalWrite(ETH_NRST, 0); delay(200); - digitalWrite(NRST, 1); + digitalWrite(ETH_NRST, 1); delay(200); - digitalWrite(NRST, 0); + digitalWrite(ETH_NRST, 0); delay(200); - digitalWrite(NRST, 1); + digitalWrite(ETH_NRST, 1); ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK); while(!eth_connected) @@ -399,7 +436,7 @@ void setup_eth() sleep(1); } } -#else + void setup_wifi() { WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); @@ -422,7 +459,6 @@ void setup_wifi() logPrintlnD(WiFi.localIP().toString()); show_display("INFO", "WiFi connected", "IP: ", WiFi.localIP().toString(), 2000); } -#endif void setup_ota() { @@ -466,18 +502,20 @@ void setup_ota() void setup_lora() { - lora_aprs.setRxFrequency(Config->lora.frequencyRx); - lora_aprs.setTxFrequency(Config->lora.frequencyTx); - if (!lora_aprs.begin(lora_aprs.getRxFrequency())) + lora_aprs = new LoRa_APRS(boardConfig); + if (!lora_aprs->begin(lora_aprs->getRxFrequency())) { logPrintlnE("Starting LoRa failed!"); show_display("ERROR", "Starting LoRa failed!"); while (1); } - lora_aprs.setTxPower(Config->lora.power); - lora_aprs.setSpreadingFactor(Config->lora.spreadingFactor); - lora_aprs.setSignalBandwidth(Config->lora.signalBandwidth); - lora_aprs.setCodingRate4(Config->lora.codingRate4); + lora_aprs->setRxFrequency(Config->lora.frequencyRx); + lora_aprs->setTxFrequency(Config->lora.frequencyTx); + lora_aprs->setTxPower(Config->lora.power); + lora_aprs->setSpreadingFactor(Config->lora.spreadingFactor); + lora_aprs->setSignalBandwidth(Config->lora.signalBandwidth); + lora_aprs->setCodingRate4(Config->lora.codingRate4); + lora_aprs->enableCrc(); logPrintlnI("LoRa init done!"); show_display("INFO", "LoRa init done!", 2000); @@ -491,8 +529,8 @@ void setup_lora() void setup_ntp() { - timeClient.begin(); - while(!timeClient.forceUpdate()) + timeClient->begin(); + while(!timeClient->forceUpdate()) { logPrintlnW("NTP Client force update issue! Waiting 1 sek..."); show_display("WARN", "NTP Client force update issue! Waiting 1 sek...", 1000); diff --git a/src/project_configuration.cpp b/src/project_configuration.cpp index 6cfaec8..4adc06d 100644 --- a/src/project_configuration.cpp +++ b/src/project_configuration.cpp @@ -61,6 +61,11 @@ Configuration * ProjectConfigurationManagement::readProjectConfiguration(Dynamic us.password = "ftp"; conf->ftp.users.push_back(us); } + if(data.containsKey("ntp_server")) + conf->ntpServer = data["ntp_server"].as(); + + if(data.containsKey("board")) + conf->board = data["board"].as(); return conf; } @@ -106,4 +111,7 @@ void ProjectConfigurationManagement::writeProjectConfiguration(Configuration * c v["name"] = u.name; v["password"] = u.password; } + data["ntp_server"] = conf->ntpServer; + + data["board"] = conf->board; } diff --git a/src/project_configuration.h b/src/project_configuration.h index 1e8a71a..65cd6bb 100644 --- a/src/project_configuration.h +++ b/src/project_configuration.h @@ -95,7 +95,7 @@ public: std::list users; }; - Configuration() : callsign("NOCALL-10") {}; + Configuration() : callsign("NOCALL-10"), board(""), ntpServer("pool.ntp.org") {}; String callsign; Wifi wifi; @@ -105,6 +105,8 @@ public: LoRa lora; Display display; Ftp ftp; + String board; + String ntpServer; }; class ProjectConfigurationManagement : public ConfigurationManagement From 1039a340c9f914f60464d653f0b7c67d6e042321 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Thu, 17 Dec 2020 22:30:24 +0100 Subject: [PATCH 14/60] update common --- lib/common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common b/lib/common index b93d7b8..285c641 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit b93d7b8a5bcab57d4bf453ba6ce1352b61e5cd37 +Subproject commit 285c641c628e803e54d847d65165a7dbbbe271df From 0a44f68e2baa037029db36bc4c7ef54246490f41 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Thu, 17 Dec 2020 22:32:01 +0100 Subject: [PATCH 15/60] update github workflow --- .github/workflows/build_check.yml | 2 +- .github/workflows/release.yml | 78 ++----------------------------- 2 files changed, 4 insertions(+), 76 deletions(-) diff --git a/.github/workflows/build_check.yml b/.github/workflows/build_check.yml index 3298f0b..b9fec7c 100644 --- a/.github/workflows/build_check.yml +++ b/.github/workflows/build_check.yml @@ -33,4 +33,4 @@ jobs: - uses: actions/upload-artifact@v2 with: name: firmware - path: .pio/build/*/firmware.bin + path: .pio/build/lora_board/firmware.bin diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8edda0f..476d9c0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,78 +32,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: .pio/build/heltec_wifi_lora_32_v1/firmware.bin - asset_name: heltec_wifi_lora_32_v1.bin - asset_content_type: application/bin - # upload heltec_wifi_lora_32_v2 - - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: .pio/build/heltec_wifi_lora_32_v2/firmware.bin - asset_name: heltec_wifi_lora_32_v2.bin - asset_content_type: application/bin - # upload ttgo-lora32-v1 - - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: .pio/build/ttgo-lora32-v1/firmware.bin - asset_name: ttgo-lora32-v1.bin - asset_content_type: application/bin - # upload ttgo-lora32-v2 - - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: .pio/build/ttgo-lora32-v2/firmware.bin - asset_name: ttgo-lora32-v2.bin - asset_content_type: application/bin - # upload ttgo-t-beam-v0_7 - - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: .pio/build/ttgo-t-beam-v0_7/firmware.bin - asset_name: ttgo-t-beam-v0_7.bin - asset_content_type: application/bin - # upload ttgo-t-beam-v1 - - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: .pio/build/ttgo-t-beam-v1/firmware.bin - asset_name: ttgo-t-beam-v1.bin - asset_content_type: application/bin - # upload TrackerD-OE1ACM - - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: .pio/build/TrackerD-OE1ACM/firmware.bin - asset_name: TrackerD-OE1ACM.bin - asset_content_type: application/bin - # upload ttgo-poe-v1_0 - - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: .pio/build/ttgo-poe-v1_0/firmware.bin - asset_name: ttgo-poe-v1_0.bin - asset_content_type: application/bin - # upload ttgo-poe-v1_2 - - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: .pio/build/ttgo-poe-v1_2/firmware.bin - asset_name: ttgo-poe-v1_2.bin - asset_content_type: application/bin + asset_path: .pio/build/lora_board/firmware.bin + asset_name: lora_board.bin + asset_content_type: application/bin \ No newline at end of file From e45a2c8e744f4f9cdcf5e8fb7e8a76cfc4ac1245 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Thu, 17 Dec 2020 22:37:05 +0100 Subject: [PATCH 16/60] add json file to upload --- .github/workflows/release.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 476d9c0..1ccc28a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: release_name: Release ${{ github.ref }} draft: false prerelease: false - # upload heltec_wifi_lora_32_v1 + # upload firmware bin - uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -34,4 +34,13 @@ jobs: upload_url: ${{ steps.create_release.outputs.upload_url }} asset_path: .pio/build/lora_board/firmware.bin asset_name: lora_board.bin - asset_content_type: application/bin \ No newline at end of file + asset_content_type: application/bin + # upload json file + - uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: data/is-cfg.json + asset_name: is-cfg.json + asset_content_type: application/json \ No newline at end of file From ed5e6a6ba9872da8af126d5b642bd6c5245e47cf Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Thu, 24 Dec 2020 21:50:36 +0100 Subject: [PATCH 17/60] remove digi --- data/is-cfg.json | 7 --- src/LoRa_APRS_iGate.cpp | 89 +---------------------------------- src/project_configuration.cpp | 8 ---- src/project_configuration.h | 12 ----- 4 files changed, 2 insertions(+), 114 deletions(-) diff --git a/data/is-cfg.json b/data/is-cfg.json index 0fdfdb5..7a24d5e 100644 --- a/data/is-cfg.json +++ b/data/is-cfg.json @@ -25,13 +25,6 @@ "beacon":true, "beacon_timeout":15 }, - "digi": - { - "active":false, - "forward_timeout":5, - "beacon":true, - "beacon_timeout":30 - }, "lora": { "frequency_rx":433775000, diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index 431337e..f01ac92 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -29,7 +29,6 @@ PowerManagement powerManagement; portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; hw_timer_t * timer = NULL; volatile uint secondsSinceLastAPRSISBeacon = 0; -volatile uint secondsSinceLastDigiBeacon = 0; volatile uint secondsSinceStartup = 0; volatile uint secondsSinceDisplay = 0; @@ -110,10 +109,10 @@ void setup() powerManagement.deactivateGPS(); } - logPrintlnW("LoRa APRS iGate & Digi by OE5BPA (Peter Buchegger)"); + logPrintlnW("LoRa APRS iGate by OE5BPA (Peter Buchegger)"); logPrintlnW("Version: 20.49.0-dev"); setup_display(boardConfig); - show_display("OE5BPA", "LoRa APRS iGate & Digi", "by Peter Buchegger", "20.49.0-dev", 3000); + show_display("OE5BPA", "LoRa APRS iGate", "by Peter Buchegger", "20.49.0-dev", 3000); load_config(); setup_lora(); @@ -173,7 +172,6 @@ void loop() } static bool beacon_aprs_is = Config->aprs_is.active && Config->aprs_is.beacon; - static bool beacon_digi = Config->digi.active && Config->digi.beacon; if(Config->aprs_is.active && Config->aprs_is.beacon && secondsSinceLastAPRSISBeacon >= (Config->aprs_is.beaconTimeout*60)) { @@ -182,13 +180,6 @@ void loop() portEXIT_CRITICAL(&timerMux); beacon_aprs_is = true; } - if(Config->digi.active && Config->digi.beacon && secondsSinceLastDigiBeacon >= (Config->digi.beaconTimeout*60)) - { - portENTER_CRITICAL(&timerMux); - secondsSinceLastDigiBeacon -= (Config->digi.beaconTimeout*60); - portEXIT_CRITICAL(&timerMux); - beacon_digi = true; - } if(Config->ftp.active) { @@ -257,81 +248,6 @@ void loop() { aprs_is->sendMessage(msg->encode()); } - if(Config->digi.active) - { - if(msg->getSource().indexOf(Config->callsign) != -1) - { - logPrintD("Message already received as repeater: '"); - logPrintD(msg->toString()); - logPrintD("' with RSSI "); - logPrintD(String(lora_aprs->packetRssi())); - logPrintD(" and SNR "); - logPrintlnD(String(lora_aprs->packetSnr())); - return; - } - - // lets try not to flood the LoRa frequency in limiting the same messages: - std::map>::iterator foundMsg = std::find_if(lastMessages.begin(), lastMessages.end(), [&](std::pair > & old_msg) - { - if(msg->getSource() == old_msg.second->getSource() && - msg->getDestination() == old_msg.second->getDestination() && - msg->getAPRSBody()->getData() == old_msg.second->getAPRSBody()->getData()) - { - return true; - } - return false; - }); - - if(foundMsg == lastMessages.end()) - { - setup_display(boardConfig); secondsSinceDisplay = 0; display_is_on = true; - show_display(Config->callsign, "RSSI: " + String(lora_aprs->packetRssi()) + ", SNR: " + String(lora_aprs->packetSnr()), msg->toString(), 0); - logPrintD("Received packet '"); - logPrintD(msg->toString()); - logPrintD("' with RSSI "); - logPrintD(String(lora_aprs->packetRssi())); - logPrintD(" and SNR "); - logPrintlnD(String(lora_aprs->packetSnr())); - msg->setPath(String(Config->callsign) + "*"); - lora_aprs->sendMessage(msg); - lastMessages.insert({secondsSinceStartup, msg}); - } - else - { - logPrintD("Message already received (timeout): '"); - logPrintD(msg->toString()); - logPrintD("' with RSSI "); - logPrintD(String(lora_aprs->packetRssi())); - logPrintD(" and SNR "); - logPrintlnD(String(lora_aprs->packetSnr())); - } - return; - } - } - if(Config->digi.active) - { - for(std::map>::iterator iter = lastMessages.begin(); iter != lastMessages.end(); ) - { - if(secondsSinceStartup >= iter->first + Config->digi.forwardTimeout*60) - { - iter = lastMessages.erase(iter); - } - else - { - ++iter; - } - } - } - if(beacon_digi) - { - beacon_digi = false; - setup_display(boardConfig); secondsSinceDisplay = 0; display_is_on = true; - show_display(Config->callsign, "Beacon to HF..."); - logPrintD("[" + timeClient->getFormattedTime() + "] "); - logPrintlnD(BeaconMsg->encode()); - lora_aprs->sendMessage(BeaconMsg); - logPrintlnD("finished TXing..."); - show_display(Config->callsign, "Standby..."); } if(beacon_aprs_is) { @@ -548,7 +464,6 @@ void IRAM_ATTR onTimer() { portENTER_CRITICAL_ISR(&timerMux); secondsSinceLastAPRSISBeacon++; - secondsSinceLastDigiBeacon++; secondsSinceStartup++; secondsSinceDisplay++; portEXIT_CRITICAL_ISR(&timerMux); diff --git a/src/project_configuration.cpp b/src/project_configuration.cpp index 4adc06d..93e3b9a 100644 --- a/src/project_configuration.cpp +++ b/src/project_configuration.cpp @@ -30,10 +30,6 @@ Configuration * ProjectConfigurationManagement::readProjectConfiguration(Dynamic conf->aprs_is.port = data["aprs_is"]["port"] | 14580; conf->aprs_is.beacon = data["aprs_is"]["beacon"] | true; conf->aprs_is.beaconTimeout = data["aprs_is"]["beacon_timeout"] | 15; - conf->digi.active = data["digi"]["active"] | false; - conf->digi.forwardTimeout = data["digi"]["forward_timeout"] | 5; - conf->digi.beacon = data["digi"]["beacon"] | true; - conf->digi.beaconTimeout = data["digi"]["beacon_timeout"] | 30; conf->lora.frequencyRx = data["lora"]["frequency_rx"] | 433775000; conf->lora.frequencyTx = data["lora"]["frequency_tx"] | 433775000; @@ -90,10 +86,6 @@ void ProjectConfigurationManagement::writeProjectConfiguration(Configuration * c data["aprs_is"]["port"] = conf->aprs_is.port; data["aprs_is"]["beacon"] = conf->aprs_is.beacon; data["aprs_is"]["beacon_timeout"] = conf->aprs_is.beaconTimeout; - data["digi"]["active"] = conf->digi.active; - data["digi"]["forward_timeout"] = conf->digi.forwardTimeout; - data["digi"]["beacon"] = conf->digi.beacon; - data["digi"]["beacon_timeout"] = conf->digi.beaconTimeout; data["lora"]["frequency_rx"] = conf->lora.frequencyRx; data["lora"]["frequency_tx"] = conf->lora.frequencyTx; data["lora"]["power"] = conf->lora.power; diff --git a/src/project_configuration.h b/src/project_configuration.h index 65cd6bb..b9c4d5d 100644 --- a/src/project_configuration.h +++ b/src/project_configuration.h @@ -45,17 +45,6 @@ public: int beaconTimeout; }; - class Digi - { - public: - Digi() : active(false), forwardTimeout(5), beacon(true), beaconTimeout(30) {} - - bool active; - int forwardTimeout; - bool beacon; - int beaconTimeout; - }; - class LoRa { public: @@ -101,7 +90,6 @@ public: Wifi wifi; Beacon beacon; APRS_IS aprs_is; - Digi digi; LoRa lora; Display display; Ftp ftp; From 295feb98ccf10a14ad1ef3c69cc5ba03f3d58ae8 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Thu, 24 Dec 2020 21:51:30 +0100 Subject: [PATCH 18/60] fixing tabs --- src/project_configuration.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/project_configuration.cpp b/src/project_configuration.cpp index 93e3b9a..dd8be2f 100644 --- a/src/project_configuration.cpp +++ b/src/project_configuration.cpp @@ -19,21 +19,21 @@ Configuration * ProjectConfigurationManagement::readProjectConfiguration(Dynamic conf->wifi.APs.push_back(ap); } if(data.containsKey("beacon") && data["beacon"].containsKey("message")) - conf->beacon.message = data["beacon"]["message"].as(); + conf->beacon.message = data["beacon"]["message"].as(); conf->beacon.positionLatitude = data["beacon"]["position"]["latitude"] | 0.0; conf->beacon.positionLongitude = data["beacon"]["position"]["longitude"] | 0.0; - conf->aprs_is.active = data["aprs_is"]["active"] | false; + conf->aprs_is.active = data["aprs_is"]["active"] | false; if(data.containsKey("aprs_is") && data["aprs_is"].containsKey("password")) conf->aprs_is.password = data["aprs_is"]["password"].as(); if(data.containsKey("aprs_is") && data["aprs_is"].containsKey("server")) - conf->aprs_is.server = data["aprs_is"]["server"].as(); + conf->aprs_is.server = data["aprs_is"]["server"].as(); conf->aprs_is.port = data["aprs_is"]["port"] | 14580; - conf->aprs_is.beacon = data["aprs_is"]["beacon"] | true; + conf->aprs_is.beacon = data["aprs_is"]["beacon"] | true; conf->aprs_is.beaconTimeout = data["aprs_is"]["beacon_timeout"] | 15; conf->lora.frequencyRx = data["lora"]["frequency_rx"] | 433775000; conf->lora.frequencyTx = data["lora"]["frequency_tx"] | 433775000; - conf->lora.power = data["lora"]["power"] | 20; + conf->lora.power = data["lora"]["power"] | 20; conf->lora.spreadingFactor = data["lora"]["spreading_factor"] | 12; conf->lora.signalBandwidth = data["lora"]["signal_bandwidth"] | 125000; conf->lora.codingRate4 = data["lora"]["coding_rate4"] | 5; @@ -41,7 +41,7 @@ Configuration * ProjectConfigurationManagement::readProjectConfiguration(Dynamic conf->display.timeout = data["display"]["timeout"] | 10; conf->display.overwritePin = data["display"]["overwrite_pin"] | 0; - conf->ftp.active = data["ftp"]["active"] | false; + conf->ftp.active = data["ftp"]["active"] | false; JsonArray users = data["ftp"]["user"].as(); for(JsonVariant u : users) { From d5c015f4b981a228180232aeb0dd40b8d50b85b4 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Fri, 1 Jan 2021 23:23:27 +0100 Subject: [PATCH 19/60] push a lot of changes... --- .gitmodules | 3 - data/is-cfg.json | 2 - lib/APRS-IS/APRS-IS.cpp | 92 +++ lib/APRS-IS/APRS-IS.h | 37 + lib/BoardFinder/BoardFinder.cpp | 167 +++++ lib/BoardFinder/BoardFinder.h | 68 ++ lib/ConfigurationManagement/configuration.cpp | 65 ++ lib/ConfigurationManagement/configuration.h | 27 + lib/LoRa_APRS/LoRa.cpp | 673 ++++++++++++++++++ lib/LoRa_APRS/LoRa.h | 119 ++++ lib/LoRa_APRS/LoRa_APRS.cpp | 87 +++ lib/LoRa_APRS/LoRa_APRS.h | 40 ++ lib/NTPClient/NTPClient.cpp | 202 ++++++ lib/NTPClient/NTPClient.h | 106 +++ lib/PowerManagement/power_management.cpp | 55 ++ lib/PowerManagement/power_management.h | 26 + lib/SignalSlot/SignalSlot.h | 116 +++ lib/TimeLib/TimeLib.cpp | 329 +++++++++ lib/TimeLib/TimeLib.h | 126 ++++ lib/TimeLib/TimeLibString.cpp | 56 ++ lib/common | 1 - platformio.ini | 4 +- src/LoRa_APRS_iGate.cpp | 463 +++--------- src/connection.cpp | 183 +++++ src/connection.h | 19 + src/display.cpp | 142 ++++ src/display.h | 47 ++ src/project_configuration.cpp | 30 +- src/project_configuration.h | 13 +- 29 files changed, 2907 insertions(+), 391 deletions(-) create mode 100644 lib/APRS-IS/APRS-IS.cpp create mode 100644 lib/APRS-IS/APRS-IS.h create mode 100644 lib/BoardFinder/BoardFinder.cpp create mode 100644 lib/BoardFinder/BoardFinder.h create mode 100644 lib/ConfigurationManagement/configuration.cpp create mode 100644 lib/ConfigurationManagement/configuration.h create mode 100644 lib/LoRa_APRS/LoRa.cpp create mode 100644 lib/LoRa_APRS/LoRa.h create mode 100644 lib/LoRa_APRS/LoRa_APRS.cpp create mode 100644 lib/LoRa_APRS/LoRa_APRS.h create mode 100644 lib/NTPClient/NTPClient.cpp create mode 100644 lib/NTPClient/NTPClient.h create mode 100644 lib/PowerManagement/power_management.cpp create mode 100644 lib/PowerManagement/power_management.h create mode 100644 lib/SignalSlot/SignalSlot.h create mode 100644 lib/TimeLib/TimeLib.cpp create mode 100644 lib/TimeLib/TimeLib.h create mode 100644 lib/TimeLib/TimeLibString.cpp delete mode 160000 lib/common create mode 100644 src/connection.cpp create mode 100644 src/connection.h create mode 100644 src/display.cpp create mode 100644 src/display.h diff --git a/.gitmodules b/.gitmodules index e8683d4..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "lib"] - path = lib/common - url = ../LoRa_APRS_Common diff --git a/data/is-cfg.json b/data/is-cfg.json index 7a24d5e..a9fc508 100644 --- a/data/is-cfg.json +++ b/data/is-cfg.json @@ -2,7 +2,6 @@ "callsign":"NOCALL-10", "wifi": { - "active":false, "AP": [ { "SSID":"YOURSSID", "password":"YOURPASSWORD" } ] @@ -18,7 +17,6 @@ }, "aprs_is": { - "active":false, "password":"", "server":"euro.aprs2.net", "port":14580, diff --git a/lib/APRS-IS/APRS-IS.cpp b/lib/APRS-IS/APRS-IS.cpp new file mode 100644 index 0000000..5b50d94 --- /dev/null +++ b/lib/APRS-IS/APRS-IS.cpp @@ -0,0 +1,92 @@ +#include "APRS-IS.h" + +APRS_IS::APRS_IS(const String & user, const String & passcode, const String & tool_name, const String & version) + : _user(user), _passcode(passcode), _tool_name(tool_name), _version(version) +{ +} + +bool APRS_IS::connect(const String & server, const int port) +{ + const String login = "user " + _user + " pass " + _passcode + " vers " + _tool_name + " " + _version + "\n\r"; + return connect_(server, port, login); +} + +bool APRS_IS::connect(const String & server, const int port, const String & filter) +{ + const String login = "user " + _user + " pass " + _passcode + " vers " + _tool_name + " " + _version + " filter " + filter + "\n\r"; + return connect_(server, port, login); +} + +bool APRS_IS::connect_(const String & server, const int port, const String & login_line) +{ + if(!_client.connect(server.c_str(), port)) + { + return false; + } + sendMessage(login_line); + // TODO: implement check if auth was successfull! + //while(!available()); + return true; +} + +bool APRS_IS::connected() +{ + return _client.connected(); +} + +bool APRS_IS::sendMessage(const String & message) +{ + if(!connected()) + { + return false; + } + _client.println(message); + return true; +} + +bool APRS_IS::sendMessage(const std::shared_ptr message) +{ + if(!connected()) + { + return false; + } + _client.println(message->encode()); + return true; +} + +void APRS_IS::action(std::shared_ptr elem, int rssi, float snr) +{ + sendMessage(elem); +} + +int APRS_IS::available() +{ + return _client.available(); +} + +String APRS_IS::getMessage() +{ + String line; + if (_client.available() > 0) + { + line = _client.readStringUntil('\n'); + } + return line; +} + +std::shared_ptr APRS_IS::getAPRSMessage() +{ + String line; + if (_client.available() > 0) + { + line = _client.readStringUntil('\n'); + } + if(line.length() == 0 || line.startsWith("#")) + { + return 0; + } + std::shared_ptr msg = std::shared_ptr(new APRSMessage()); + msg->decode(line); + emit(msg); + return msg; +} diff --git a/lib/APRS-IS/APRS-IS.h b/lib/APRS-IS/APRS-IS.h new file mode 100644 index 0000000..a7df11f --- /dev/null +++ b/lib/APRS-IS/APRS-IS.h @@ -0,0 +1,37 @@ + +#ifndef APRS_IS_Lib_h_ +#define APRS_IS_Lib_h_ + +#include +#include +#include + +class APRS_IS : public Signal1>, public Slot3, int, float> +{ +public: + APRS_IS(const String & user, const String & passcode, const String & tool_name, const String & version); + + bool connect(const String & server, const int port); + bool connect(const String & server, const int port, const String & filter); + bool connect_(const String & server, const int port, const String & login_line); + bool connected(); + + bool sendMessage(const String & message); + bool sendMessage(const std::shared_ptr message); + void action(std::shared_ptr msg, int rssi, float snr) override; + + int available(); + + String getMessage(); + std::shared_ptr getAPRSMessage(); + +private: + const String _user; + const String _passcode; + const String _tool_name; + const String _version; + WiFiClient _client; +}; + +#endif + diff --git a/lib/BoardFinder/BoardFinder.cpp b/lib/BoardFinder/BoardFinder.cpp new file mode 100644 index 0000000..39e0ca0 --- /dev/null +++ b/lib/BoardFinder/BoardFinder.cpp @@ -0,0 +1,167 @@ +#include +#include +#include "BoardFinder.h" + +BoardConfig::BoardConfig( + String name, BoardType type, + uint8_t oledsda, uint8_t oledscl, uint8_t oledaddr, uint8_t oledreset, + uint8_t lorasck, uint8_t loramiso, uint8_t loramosi, uint8_t loracs, uint8_t lorareset, uint8_t lorairq, + bool needcheckpowerchip, bool powercheckstatus) + : + Name(name), Type(type), + OledSda(oledsda), OledScl(oledscl), OledAddr(oledaddr), OledReset(oledreset), + LoraSck(lorasck), LoraMiso(loramiso), LoraMosi(loramosi), LoraCS(loracs), LoraReset(lorareset), LoraIRQ(lorairq), + needCheckPowerChip(needcheckpowerchip), powerCheckStatus(powercheckstatus) +{ +} + +BoardFinder::BoardFinder(std::list> boardConfigs) +{ + _boardConfigs = boardConfigs; +} + +std::shared_ptr BoardFinder::searchBoardConfig() +{ + logPrintlnI("looking for a board config."); + logPrintlnI("searching for OLED..."); + + for(std::shared_ptr boardconf : _boardConfigs) + { + if(boardconf->needCheckPowerChip && checkPowerConfig(boardconf) == boardconf->powerCheckStatus) + { + PowerManagement powerManagement; + TwoWire wire(0); + wire.begin(boardconf->OledSda, boardconf->OledScl); + powerManagement.begin(wire); + powerManagement.activateOLED(); + } + else if(boardconf->needCheckPowerChip) + { + continue; + } + if(checkOledConfig(boardconf)) + { + logPrintI("found a board config: "); + logPrintlnI(boardconf->Name); + return boardconf; + } + } + + logPrintlnW("could not find OLED, will search for the modem now..."); + + for(std::shared_ptr boardconf : _boardConfigs) + { + if(boardconf->needCheckPowerChip && checkPowerConfig(boardconf) == boardconf->powerCheckStatus) + { + PowerManagement powerManagement; + TwoWire wire(0); + wire.begin(boardconf->OledSda, boardconf->OledScl); + powerManagement.begin(wire); + powerManagement.activateLoRa(); + } + if(checkModemConfig(boardconf)) + { + logPrintI("found a board config: "); + logPrintlnI(boardconf->Name); + return boardconf; + } + } + + logPrintlnW("could not find a board config!"); + + return 0; +} + +std::shared_ptr BoardFinder::getBoardConfig(String name) +{ + std::_List_iterator> elem = std::find_if(_boardConfigs.begin(), _boardConfigs.end(), [&](std::shared_ptr conf) + { + return conf->Name == name; + }); + if(elem == _boardConfigs.end()) + { + return 0; + } + return *elem; +} + +bool BoardFinder::checkOledConfig(std::shared_ptr boardConfig) +{ + if(boardConfig->OledReset > 0) + { + pinMode(boardConfig->OledReset, OUTPUT); + digitalWrite(boardConfig->OledReset, HIGH); + delay(1); + digitalWrite(boardConfig->OledReset, LOW); + delay(10); + digitalWrite(boardConfig->OledReset, HIGH); + } + TwoWire wire(0); + if(!wire.begin(boardConfig->OledSda, boardConfig->OledScl)) + { + logPrintlnW("issue with wire"); + return false; + } + wire.beginTransmission(boardConfig->OledAddr); + if(!wire.endTransmission()) + { + return true; + } + return false; +} + +bool BoardFinder::checkModemConfig(std::shared_ptr boardConfig) +{ + pinMode(boardConfig->LoraReset, OUTPUT); + digitalWrite(boardConfig->LoraReset, LOW); + delay(10); + digitalWrite(boardConfig->LoraReset, HIGH); + delay(10); + + pinMode(boardConfig->LoraCS, OUTPUT); + digitalWrite(boardConfig->LoraCS, HIGH); + + SPIClass spi; + spi.begin(boardConfig->LoraSck, boardConfig->LoraMiso, boardConfig->LoraMosi, boardConfig->LoraCS); + + digitalWrite(boardConfig->LoraCS, LOW); + + spi.beginTransaction(SPISettings(8E6, MSBFIRST, SPI_MODE0)); + spi.transfer(0x42); + uint8_t response = spi.transfer(0x00); + spi.endTransaction(); + + digitalWrite(boardConfig->LoraCS, HIGH); + + if(response == 0x12) + { + return true; + } + return false; +} + +bool BoardFinder::checkPowerConfig(std::shared_ptr boardConfig) +{ + TwoWire wire(0); + if(!wire.begin(boardConfig->OledSda, boardConfig->OledScl)) + { + logPrintlnW("issue with wire"); + return false; + } + wire.beginTransmission(0x34); + wire.write(0x03); + wire.endTransmission(); + + wire.requestFrom(0x34, 1); + int response = wire.read(); + wire.endTransmission(); + + logPrintlnD(String(response)); + if(response == 0x03) + { + logPrintlnD("power chip found!"); + return true; + } + logPrintlnD("power chip NOT found"); + return false; +} diff --git a/lib/BoardFinder/BoardFinder.h b/lib/BoardFinder/BoardFinder.h new file mode 100644 index 0000000..45b9243 --- /dev/null +++ b/lib/BoardFinder/BoardFinder.h @@ -0,0 +1,68 @@ +#ifndef BOARD_FINDER_H_ +#define BOARD_FINDER_H_ + +#include +#include + +#include +#include +#include + +enum BoardType +{ + eHELTEC_WIFI_LORA_32_V1, + eHELTEC_WIFI_LORA_32_V2, + eTTGO_LORA32_V1, + eTTGO_LORA32_V2, + eTTGO_T_Beam_V0_7, + eTTGO_T_Beam_V1_0, + eETH_BOARD, + eTRACKERD +}; + +class BoardConfig +{ +public: + BoardConfig( + String name, BoardType type, + uint8_t oledsda, uint8_t oledscl, uint8_t oledaddr, uint8_t oledreset, + uint8_t lorasck, uint8_t loramiso, uint8_t loramosi, uint8_t loracs, uint8_t lorareset, uint8_t lorairq, + bool needcheckpowerchip = false, bool powercheckstatus = false); + + String Name; + BoardType Type; + + uint8_t OledSda; + uint8_t OledScl; + uint8_t OledAddr; + uint8_t OledReset; + + uint8_t LoraSck; + uint8_t LoraMiso; + uint8_t LoraMosi; + uint8_t LoraCS; + uint8_t LoraReset; + uint8_t LoraIRQ; + + bool needCheckPowerChip; + bool powerCheckStatus; +}; + +class BoardFinder +{ +public: + BoardFinder(std::list> boardConfigs); + + std::shared_ptr searchBoardConfig(); + + std::shared_ptr getBoardConfig(String name); + +private: + std::list> _boardConfigs; + + bool checkOledConfig(std::shared_ptr boardConfig); + bool checkModemConfig(std::shared_ptr boardConfig); + bool checkPowerConfig(std::shared_ptr boardConfig); +}; + +#endif diff --git a/lib/ConfigurationManagement/configuration.cpp b/lib/ConfigurationManagement/configuration.cpp new file mode 100644 index 0000000..b713489 --- /dev/null +++ b/lib/ConfigurationManagement/configuration.cpp @@ -0,0 +1,65 @@ +#include +#include +#include "configuration.h" + +ConfigurationManagement::ConfigurationManagement(String FilePath) + : mFilePath(FilePath) +{ + if(!SPIFFS.begin(true)) + { + logPrintlnE("Mounting SPIFFS was not possible. Trying to format SPIFFS..."); + SPIFFS.format(); + if(!SPIFFS.begin()) + { + logPrintlnE("Formating SPIFFS was not okay!"); + } + } +} + +ConfigurationManagement::~ConfigurationManagement() +{ +} + +std::shared_ptr ConfigurationManagement::readConfiguration() +{ + File file = SPIFFS.open(mFilePath); + if(!file) + { + logPrintlnE("Failed to open file for reading..."); + return 0; + } + DynamicJsonDocument data(2048); + DeserializationError error = deserializeJson(data, file); + if(error) + { + logPrintlnW("Failed to read file, using default configuration."); + } + //serializeJson(data, Serial); + //Serial.println(); + file.close(); + + std::shared_ptr conf = readProjectConfiguration(data); + + // update config in memory to get the new fields: + writeConfiguration(conf); + + return conf; +} + +void ConfigurationManagement::writeConfiguration(std::shared_ptr conf) +{ + File file = SPIFFS.open(mFilePath, "w"); + if(!file) + { + logPrintlnE("Failed to open file for writing..."); + return; + } + DynamicJsonDocument data(2048); + + writeProjectConfiguration(conf, data); + + serializeJson(data, file); + //serializeJson(data, Serial); + //Serial.println(); + file.close(); +} diff --git a/lib/ConfigurationManagement/configuration.h b/lib/ConfigurationManagement/configuration.h new file mode 100644 index 0000000..0e22b10 --- /dev/null +++ b/lib/ConfigurationManagement/configuration.h @@ -0,0 +1,27 @@ +#ifndef CONFIGURATION_H_ +#define CONFIGURATION_H_ + +#include + +#include +#include + +class Configuration; + +class ConfigurationManagement +{ +public: + explicit ConfigurationManagement(String FilePath); + virtual ~ConfigurationManagement(); + + std::shared_ptr readConfiguration(); + void writeConfiguration(std::shared_ptr conf); + +private: + virtual std::shared_ptr readProjectConfiguration(DynamicJsonDocument & data) = 0; + virtual void writeProjectConfiguration(std::shared_ptr conf, DynamicJsonDocument & data) = 0; + + const String mFilePath; +}; + +#endif diff --git a/lib/LoRa_APRS/LoRa.cpp b/lib/LoRa_APRS/LoRa.cpp new file mode 100644 index 0000000..59142ec --- /dev/null +++ b/lib/LoRa_APRS/LoRa.cpp @@ -0,0 +1,673 @@ +// Copyright (c) Sandeep Mistry. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include + +// registers +#define REG_FIFO 0x00 +#define REG_OP_MODE 0x01 +#define REG_FRF_MSB 0x06 +#define REG_FRF_MID 0x07 +#define REG_FRF_LSB 0x08 +#define REG_PA_CONFIG 0x09 +#define REG_OCP 0x0b +#define REG_LNA 0x0c +#define REG_FIFO_ADDR_PTR 0x0d +#define REG_FIFO_TX_BASE_ADDR 0x0e +#define REG_FIFO_RX_BASE_ADDR 0x0f +#define REG_FIFO_RX_CURRENT_ADDR 0x10 +#define REG_IRQ_FLAGS 0x12 +#define REG_RX_NB_BYTES 0x13 +#define REG_PKT_SNR_VALUE 0x19 +#define REG_PKT_RSSI_VALUE 0x1a +#define REG_RSSI_VALUE 0x1b +#define REG_MODEM_CONFIG_1 0x1d +#define REG_MODEM_CONFIG_2 0x1e +#define REG_PREAMBLE_MSB 0x20 +#define REG_PREAMBLE_LSB 0x21 +#define REG_PAYLOAD_LENGTH 0x22 +#define REG_MODEM_CONFIG_3 0x26 +#define REG_FREQ_ERROR_MSB 0x28 +#define REG_FREQ_ERROR_MID 0x29 +#define REG_FREQ_ERROR_LSB 0x2a +#define REG_RSSI_WIDEBAND 0x2c +#define REG_DETECTION_OPTIMIZE 0x31 +#define REG_INVERTIQ 0x33 +#define REG_DETECTION_THRESHOLD 0x37 +#define REG_SYNC_WORD 0x39 +#define REG_INVERTIQ2 0x3b +#define REG_DIO_MAPPING_1 0x40 +#define REG_VERSION 0x42 +#define REG_PA_DAC 0x4d + +// modes +#define MODE_LONG_RANGE_MODE 0x80 +#define MODE_SLEEP 0x00 +#define MODE_STDBY 0x01 +#define MODE_TX 0x03 +#define MODE_RX_CONTINUOUS 0x05 +#define MODE_RX_SINGLE 0x06 + +// PA config +#define PA_BOOST 0x80 + +// IRQ masks +#define IRQ_TX_DONE_MASK 0x08 +#define IRQ_PAYLOAD_CRC_ERROR_MASK 0x20 +#define IRQ_RX_DONE_MASK 0x40 + +#define RF_MID_BAND_THRESHOLD 525E6 +#define RSSI_OFFSET_HF_PORT 157 +#define RSSI_OFFSET_LF_PORT 164 + +#define MAX_PKT_LENGTH 255 + +#if (ESP8266 || ESP32) + #define ISR_PREFIX ICACHE_RAM_ATTR +#else + #define ISR_PREFIX +#endif + +LoRaClass::LoRaClass() : + _spiSettings(LORA_DEFAULT_SPI_FREQUENCY, MSBFIRST, SPI_MODE0), + _spi(&LORA_DEFAULT_SPI), + _ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN), + _frequency(0), + _packetIndex(0), + _implicitHeaderMode(0) +{ + // overide Stream timeout value + setTimeout(0); +} + +int LoRaClass::begin(long frequency) +{ +#if defined(ARDUINO_SAMD_MKRWAN1300) || defined(ARDUINO_SAMD_MKRWAN1310) + pinMode(LORA_IRQ_DUMB, OUTPUT); + digitalWrite(LORA_IRQ_DUMB, LOW); + + // Hardware reset + pinMode(LORA_BOOT0, OUTPUT); + digitalWrite(LORA_BOOT0, LOW); + + pinMode(LORA_RESET, OUTPUT); + digitalWrite(LORA_RESET, HIGH); + delay(200); + digitalWrite(LORA_RESET, LOW); + delay(200); + digitalWrite(LORA_RESET, HIGH); + delay(50); +#endif + + // setup pins + pinMode(_ss, OUTPUT); + // set SS high + digitalWrite(_ss, HIGH); + + if (_reset != -1) { + pinMode(_reset, OUTPUT); + + // perform reset + digitalWrite(_reset, LOW); + delay(10); + digitalWrite(_reset, HIGH); + delay(10); + } + + // start SPI + _spi->begin(); + + // check version + uint8_t version = readRegister(REG_VERSION); + if (version != 0x12) { + return 0; + } + + // put in sleep mode + sleep(); + + // set frequency + setFrequency(frequency); + + // set base addresses + writeRegister(REG_FIFO_TX_BASE_ADDR, 0); + writeRegister(REG_FIFO_RX_BASE_ADDR, 0); + + // set LNA boost + writeRegister(REG_LNA, readRegister(REG_LNA) | 0x03); + + // set auto AGC + writeRegister(REG_MODEM_CONFIG_3, 0x04); + + // set output power to 17 dBm + setTxPower(17); + + // put in standby mode + idle(); + + return 1; +} + +void LoRaClass::end() +{ + // put in sleep mode + sleep(); + + // stop SPI + _spi->end(); +} + +int LoRaClass::beginPacket(int implicitHeader) +{ + if (isTransmitting()) { + return 0; + } + + // put in standby mode + idle(); + + if (implicitHeader) { + implicitHeaderMode(); + } else { + explicitHeaderMode(); + } + + // reset FIFO address and paload length + writeRegister(REG_FIFO_ADDR_PTR, 0); + writeRegister(REG_PAYLOAD_LENGTH, 0); + + return 1; +} + +int LoRaClass::endPacket(bool async) +{ + + // put in TX mode + writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX); + + if (!async) { + // wait for TX done + while ((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) { + yield(); + } + // clear IRQ's + writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); + } + + return 1; +} + +bool LoRaClass::isTransmitting() +{ + if ((readRegister(REG_OP_MODE) & MODE_TX) == MODE_TX) { + return true; + } + + if (readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) { + // clear IRQ's + writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); + } + + return false; +} + +int LoRaClass::parsePacket(int size) +{ + int packetLength = 0; + int irqFlags = readRegister(REG_IRQ_FLAGS); + + if (size > 0) { + implicitHeaderMode(); + + writeRegister(REG_PAYLOAD_LENGTH, size & 0xff); + } else { + explicitHeaderMode(); + } + + // clear IRQ's + writeRegister(REG_IRQ_FLAGS, irqFlags); + + if ((irqFlags & IRQ_RX_DONE_MASK) && (irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) { + // received a packet + _packetIndex = 0; + + // read packet length + if (_implicitHeaderMode) { + packetLength = readRegister(REG_PAYLOAD_LENGTH); + } else { + packetLength = readRegister(REG_RX_NB_BYTES); + } + + // set FIFO address to current RX address + writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR)); + + // put in standby mode + idle(); + } else if (readRegister(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE)) { + // not currently in RX mode + + // reset FIFO address + writeRegister(REG_FIFO_ADDR_PTR, 0); + + // put in single RX mode + writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE); + } + + return packetLength; +} + +int LoRaClass::packetRssi() +{ + return (readRegister(REG_PKT_RSSI_VALUE) - (_frequency < RF_MID_BAND_THRESHOLD ? RSSI_OFFSET_LF_PORT : RSSI_OFFSET_HF_PORT)); +} + +float LoRaClass::packetSnr() +{ + return ((int8_t)readRegister(REG_PKT_SNR_VALUE)) * 0.25; +} + +long LoRaClass::packetFrequencyError() +{ + int32_t freqError = 0; + freqError = static_cast(readRegister(REG_FREQ_ERROR_MSB) & B111); + freqError <<= 8L; + freqError += static_cast(readRegister(REG_FREQ_ERROR_MID)); + freqError <<= 8L; + freqError += static_cast(readRegister(REG_FREQ_ERROR_LSB)); + + if (readRegister(REG_FREQ_ERROR_MSB) & B1000) { // Sign bit is on + freqError -= 524288; // B1000'0000'0000'0000'0000 + } + + const float fXtal = 32E6; // FXOSC: crystal oscillator (XTAL) frequency (2.5. Chip Specification, p. 14) + const float fError = ((static_cast(freqError) * (1L << 24)) / fXtal) * (getSignalBandwidth() / 500000.0f); // p. 37 + + return static_cast(fError); +} + +int LoRaClass::rssi() +{ + return (readRegister(REG_RSSI_VALUE) - (_frequency < RF_MID_BAND_THRESHOLD ? RSSI_OFFSET_LF_PORT : RSSI_OFFSET_HF_PORT)); +} + +size_t LoRaClass::write(uint8_t byte) +{ + return write(&byte, sizeof(byte)); +} + +size_t LoRaClass::write(const uint8_t *buffer, size_t size) +{ + int currentLength = readRegister(REG_PAYLOAD_LENGTH); + + // check size + if ((currentLength + size) > MAX_PKT_LENGTH) { + size = MAX_PKT_LENGTH - currentLength; + } + + // write data + for (size_t i = 0; i < size; i++) { + writeRegister(REG_FIFO, buffer[i]); + } + + // update length + writeRegister(REG_PAYLOAD_LENGTH, currentLength + size); + + return size; +} + +int LoRaClass::available() +{ + return (readRegister(REG_RX_NB_BYTES) - _packetIndex); +} + +int LoRaClass::read() +{ + if (!available()) { + return -1; + } + + _packetIndex++; + + return readRegister(REG_FIFO); +} + +int LoRaClass::peek() +{ + if (!available()) { + return -1; + } + + // store current FIFO address + int currentAddress = readRegister(REG_FIFO_ADDR_PTR); + + // read + uint8_t b = readRegister(REG_FIFO); + + // restore FIFO address + writeRegister(REG_FIFO_ADDR_PTR, currentAddress); + + return b; +} + +void LoRaClass::flush() +{ +} + +void LoRaClass::receive(int size) +{ + + writeRegister(REG_DIO_MAPPING_1, 0x00); // DIO0 => RXDONE + + if (size > 0) { + implicitHeaderMode(); + + writeRegister(REG_PAYLOAD_LENGTH, size & 0xff); + } else { + explicitHeaderMode(); + } + + writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS); +} + +void LoRaClass::idle() +{ + writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_STDBY); +} + +void LoRaClass::sleep() +{ + writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_SLEEP); +} + +void LoRaClass::setTxPower(int level, int outputPin) +{ + if (PA_OUTPUT_RFO_PIN == outputPin) { + // RFO + if (level < 0) { + level = 0; + } else if (level > 14) { + level = 14; + } + + writeRegister(REG_PA_CONFIG, 0x70 | level); + } else { + // PA BOOST + if (level > 17) { + if (level > 20) { + level = 20; + } + + // subtract 3 from level, so 18 - 20 maps to 15 - 17 + level -= 3; + + // High Power +20 dBm Operation (Semtech SX1276/77/78/79 5.4.3.) + writeRegister(REG_PA_DAC, 0x87); + setOCP(140); + } else { + if (level < 2) { + level = 2; + } + //Default value PA_HF/LF or +17dBm + writeRegister(REG_PA_DAC, 0x84); + setOCP(100); + } + + writeRegister(REG_PA_CONFIG, PA_BOOST | (level - 2)); + } +} + +void LoRaClass::setFrequency(long frequency) +{ + _frequency = frequency; + + uint64_t frf = ((uint64_t)frequency << 19) / 32000000; + + writeRegister(REG_FRF_MSB, (uint8_t)(frf >> 16)); + writeRegister(REG_FRF_MID, (uint8_t)(frf >> 8)); + writeRegister(REG_FRF_LSB, (uint8_t)(frf >> 0)); +} + +int LoRaClass::getSpreadingFactor() +{ + return readRegister(REG_MODEM_CONFIG_2) >> 4; +} + +void LoRaClass::setSpreadingFactor(int sf) +{ + if (sf < 6) { + sf = 6; + } else if (sf > 12) { + sf = 12; + } + + if (sf == 6) { + writeRegister(REG_DETECTION_OPTIMIZE, 0xc5); + writeRegister(REG_DETECTION_THRESHOLD, 0x0c); + } else { + writeRegister(REG_DETECTION_OPTIMIZE, 0xc3); + writeRegister(REG_DETECTION_THRESHOLD, 0x0a); + } + + writeRegister(REG_MODEM_CONFIG_2, (readRegister(REG_MODEM_CONFIG_2) & 0x0f) | ((sf << 4) & 0xf0)); + setLdoFlag(); +} + +long LoRaClass::getSignalBandwidth() +{ + byte bw = (readRegister(REG_MODEM_CONFIG_1) >> 4); + + switch (bw) { + case 0: return 7.8E3; + case 1: return 10.4E3; + case 2: return 15.6E3; + case 3: return 20.8E3; + case 4: return 31.25E3; + case 5: return 41.7E3; + case 6: return 62.5E3; + case 7: return 125E3; + case 8: return 250E3; + case 9: return 500E3; + } + + return -1; +} + +void LoRaClass::setSignalBandwidth(long sbw) +{ + int bw; + + if (sbw <= 7.8E3) { + bw = 0; + } else if (sbw <= 10.4E3) { + bw = 1; + } else if (sbw <= 15.6E3) { + bw = 2; + } else if (sbw <= 20.8E3) { + bw = 3; + } else if (sbw <= 31.25E3) { + bw = 4; + } else if (sbw <= 41.7E3) { + bw = 5; + } else if (sbw <= 62.5E3) { + bw = 6; + } else if (sbw <= 125E3) { + bw = 7; + } else if (sbw <= 250E3) { + bw = 8; + } else /*if (sbw <= 250E3)*/ { + bw = 9; + } + + writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0x0f) | (bw << 4)); + setLdoFlag(); +} + +void LoRaClass::setLdoFlag() +{ + // Section 4.1.1.5 + long symbolDuration = 1000 / ( getSignalBandwidth() / (1L << getSpreadingFactor()) ) ; + + // Section 4.1.1.6 + boolean ldoOn = symbolDuration > 16; + + uint8_t config3 = readRegister(REG_MODEM_CONFIG_3); + bitWrite(config3, 3, ldoOn); + writeRegister(REG_MODEM_CONFIG_3, config3); +} + +void LoRaClass::setCodingRate4(int denominator) +{ + if (denominator < 5) { + denominator = 5; + } else if (denominator > 8) { + denominator = 8; + } + + int cr = denominator - 4; + + writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0xf1) | (cr << 1)); +} + +void LoRaClass::setPreambleLength(long length) +{ + writeRegister(REG_PREAMBLE_MSB, (uint8_t)(length >> 8)); + writeRegister(REG_PREAMBLE_LSB, (uint8_t)(length >> 0)); +} + +void LoRaClass::setSyncWord(int sw) +{ + writeRegister(REG_SYNC_WORD, sw); +} + +void LoRaClass::enableCrc() +{ + writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) | 0x04); +} + +void LoRaClass::disableCrc() +{ + writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) & 0xfb); +} + +void LoRaClass::enableInvertIQ() +{ + writeRegister(REG_INVERTIQ, 0x66); + writeRegister(REG_INVERTIQ2, 0x19); +} + +void LoRaClass::disableInvertIQ() +{ + writeRegister(REG_INVERTIQ, 0x27); + writeRegister(REG_INVERTIQ2, 0x1d); +} + +void LoRaClass::setOCP(uint8_t mA) +{ + uint8_t ocpTrim = 27; + + if (mA <= 120) { + ocpTrim = (mA - 45) / 5; + } else if (mA <=240) { + ocpTrim = (mA + 30) / 10; + } + + writeRegister(REG_OCP, 0x20 | (0x1F & ocpTrim)); +} + +void LoRaClass::setGain(uint8_t gain) +{ + // check allowed range + if (gain > 6) { + gain = 6; + } + + // set to standby + idle(); + + // set gain + if (gain == 0) { + // if gain = 0, enable AGC + writeRegister(REG_MODEM_CONFIG_3, 0x04); + } else { + // disable AGC + writeRegister(REG_MODEM_CONFIG_3, 0x00); + + // clear Gain and set LNA boost + writeRegister(REG_LNA, 0x03); + + // set gain + writeRegister(REG_LNA, readRegister(REG_LNA) | (gain << 5)); + } +} + +byte LoRaClass::random() +{ + return readRegister(REG_RSSI_WIDEBAND); +} + +void LoRaClass::setPins(int ss, int reset, int dio0) +{ + _ss = ss; + _reset = reset; + _dio0 = dio0; +} + +void LoRaClass::setSPI(SPIClass& spi) +{ + _spi = &spi; +} + +void LoRaClass::setSPIFrequency(uint32_t frequency) +{ + _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); +} + +void LoRaClass::dumpRegisters(Stream& out) +{ + for (int i = 0; i < 128; i++) { + out.print("0x"); + out.print(i, HEX); + out.print(": 0x"); + out.println(readRegister(i), HEX); + } +} + +void LoRaClass::explicitHeaderMode() +{ + _implicitHeaderMode = 0; + + writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) & 0xfe); +} + +void LoRaClass::implicitHeaderMode() +{ + _implicitHeaderMode = 1; + + writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) | 0x01); +} + +uint8_t LoRaClass::readRegister(uint8_t address) +{ + return singleTransfer(address & 0x7f, 0x00); +} + +void LoRaClass::writeRegister(uint8_t address, uint8_t value) +{ + singleTransfer(address | 0x80, value); +} + +uint8_t LoRaClass::singleTransfer(uint8_t address, uint8_t value) +{ + uint8_t response; + + digitalWrite(_ss, LOW); + + _spi->beginTransaction(_spiSettings); + _spi->transfer(address); + response = _spi->transfer(value); + _spi->endTransaction(); + + digitalWrite(_ss, HIGH); + + return response; +} diff --git a/lib/LoRa_APRS/LoRa.h b/lib/LoRa_APRS/LoRa.h new file mode 100644 index 0000000..51e089a --- /dev/null +++ b/lib/LoRa_APRS/LoRa.h @@ -0,0 +1,119 @@ +// Copyright (c) Sandeep Mistry. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef LORA_H +#define LORA_H + +#include +#include + +#if defined(ARDUINO_SAMD_MKRWAN1300) +#define LORA_DEFAULT_SPI SPI1 +#define LORA_DEFAULT_SPI_FREQUENCY 200000 +#define LORA_DEFAULT_SS_PIN LORA_IRQ_DUMB +#define LORA_DEFAULT_RESET_PIN -1 +#define LORA_DEFAULT_DIO0_PIN -1 +#elif defined(ARDUINO_SAMD_MKRWAN1310) +#define LORA_DEFAULT_SPI SPI1 +#define LORA_DEFAULT_SPI_FREQUENCY 200000 +#define LORA_DEFAULT_SS_PIN LORA_IRQ_DUMB +#define LORA_DEFAULT_RESET_PIN -1 +#define LORA_DEFAULT_DIO0_PIN LORA_IRQ +#else +#define LORA_DEFAULT_SPI SPI +#define LORA_DEFAULT_SPI_FREQUENCY 8E6 +#define LORA_DEFAULT_SS_PIN 10 +#define LORA_DEFAULT_RESET_PIN 9 +#define LORA_DEFAULT_DIO0_PIN 2 +#endif + +#define PA_OUTPUT_RFO_PIN 0 +#define PA_OUTPUT_PA_BOOST_PIN 1 + +class LoRaClass : public Stream { +public: + LoRaClass(); + + int begin(long frequency); + void end(); + + int beginPacket(int implicitHeader = false); + int endPacket(bool async = false); + + int parsePacket(int size = 0); + int packetRssi(); + float packetSnr(); + long packetFrequencyError(); + + int rssi(); + + // from Print + virtual size_t write(uint8_t byte); + virtual size_t write(const uint8_t *buffer, size_t size); + + // from Stream + virtual int available(); + virtual int read(); + virtual int peek(); + virtual void flush(); + + void receive(int size = 0); + + void idle(); + void sleep(); + + void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN); + void setFrequency(long frequency); + void setSpreadingFactor(int sf); + void setSignalBandwidth(long sbw); + void setCodingRate4(int denominator); + void setPreambleLength(long length); + void setSyncWord(int sw); + void enableCrc(); + void disableCrc(); + void enableInvertIQ(); + void disableInvertIQ(); + + void setOCP(uint8_t mA); // Over Current Protection control + + void setGain(uint8_t gain); // Set LNA gain + + // deprecated + void crc() { enableCrc(); } + void noCrc() { disableCrc(); } + + byte random(); + + void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN); + void setSPI(SPIClass& spi); + void setSPIFrequency(uint32_t frequency); + + void dumpRegisters(Stream& out); + +private: + void explicitHeaderMode(); + void implicitHeaderMode(); + + bool isTransmitting(); + + int getSpreadingFactor(); + long getSignalBandwidth(); + + void setLdoFlag(); + + uint8_t readRegister(uint8_t address); + void writeRegister(uint8_t address, uint8_t value); + uint8_t singleTransfer(uint8_t address, uint8_t value); + +private: + SPISettings _spiSettings; + SPIClass* _spi; + int _ss; + int _reset; + int _dio0; + long _frequency; + int _packetIndex; + int _implicitHeaderMode; +}; + +#endif diff --git a/lib/LoRa_APRS/LoRa_APRS.cpp b/lib/LoRa_APRS/LoRa_APRS.cpp new file mode 100644 index 0000000..8f8a5a2 --- /dev/null +++ b/lib/LoRa_APRS/LoRa_APRS.cpp @@ -0,0 +1,87 @@ +#include +#include "LoRa_APRS.h" + +LoRa_APRS::LoRa_APRS(std::shared_ptr boardConfig) + : _LastReceivedMsg(0), _RxFrequency(LORA_RX_FREQUENCY), _TxFrequency(LORA_TX_FREQUENCY) +{ + SPI.begin(boardConfig->LoraSck, boardConfig->LoraMiso, boardConfig->LoraMosi, boardConfig->LoraCS); + setPins(boardConfig->LoraCS, boardConfig->LoraReset, boardConfig->LoraIRQ); +} + +bool LoRa_APRS::checkMessage() +{ + if(!parsePacket()) + { + return false; + } + // read header: + char dummy[4]; + readBytes(dummy, 3); + if(dummy[0] != '<') + { + // is no APRS message, ignore message + while(available()) + { + read(); + } + return false; + } + // read APRS data: + String str; + while(available()) + { + str += (char)read(); + } + _LastReceivedMsg = std::shared_ptr(new APRSMessage()); + _LastReceivedMsg->decode(str); + emit(_LastReceivedMsg, packetRssi(), packetSnr()); + return true; +} + +std::shared_ptr LoRa_APRS::getMessage() +{ + return _LastReceivedMsg; +} + +// cppcheck-suppress unusedFunction +void LoRa_APRS::sendMessage(const std::shared_ptr msg) +{ + setFrequency(_TxFrequency); + String data = msg->encode(); + beginPacket(); + // Header: + write('<'); + write(0xFF); + write(0x01); + // APRS Data: + write((const uint8_t *)data.c_str(), data.length()); + endPacket(); + setFrequency(_RxFrequency); +} + +void LoRa_APRS::setRxFrequency(long frequency) +{ + _RxFrequency = frequency; + setFrequency(_RxFrequency); +} + +long LoRa_APRS::getRxFrequency() const +{ + return _RxFrequency; +} + +void LoRa_APRS::setTxFrequency(long frequency) +{ + _TxFrequency = frequency; +} + +// cppcheck-suppress unusedFunction +long LoRa_APRS::getTxFrequency() const +{ + return _TxFrequency; +} + +void LoRa_APRS::action(const std::shared_ptr elem) +{ + sendMessage(elem); +} diff --git a/lib/LoRa_APRS/LoRa_APRS.h b/lib/LoRa_APRS/LoRa_APRS.h new file mode 100644 index 0000000..71bad11 --- /dev/null +++ b/lib/LoRa_APRS/LoRa_APRS.h @@ -0,0 +1,40 @@ +#ifndef LORA_H_ +#define LORA_H_ + +#include +#include +#include +#include +#include + +#define LORA_RX_FREQUENCY (433775000) +#define LORA_TX_FREQUENCY (433900000) +#define LORA_SPREADING_FACTOR (12) +#define LORA_SIGNAL_BANDWIDTH (125E3) +#define LORA_CODING_RATE4 (5) + +class LoRa_APRS : public LoRaClass, public Slot1>, public Signal3, int, float> +{ +public: + explicit LoRa_APRS(std::shared_ptr boardConfig); + + bool checkMessage(); + std::shared_ptr getMessage(); + + void sendMessage(const std::shared_ptr msg); + + void setRxFrequency(long frequency); + long getRxFrequency() const; + + void setTxFrequency(long frequency); + long getTxFrequency() const; + + void action(const std::shared_ptr elem) override; + +private: + std::shared_ptr _LastReceivedMsg; + long _RxFrequency; + long _TxFrequency; +}; + +#endif diff --git a/lib/NTPClient/NTPClient.cpp b/lib/NTPClient/NTPClient.cpp new file mode 100644 index 0000000..13447f7 --- /dev/null +++ b/lib/NTPClient/NTPClient.cpp @@ -0,0 +1,202 @@ +/** + * The MIT License (MIT) + * Copyright (c) 2015 by Fabrice Weinberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "NTPClient.h" + +NTPClient::NTPClient() { +} + +NTPClient::NTPClient(long timeOffset) { + this->_timeOffset = timeOffset; +} + +NTPClient::NTPClient(const char* poolServerName) { + this->_poolServerName = poolServerName; +} + +NTPClient::NTPClient(IPAddress poolServerIP) { + this->_poolServerIP = poolServerIP; + this->_poolServerName = NULL; +} + +NTPClient::NTPClient(const char* poolServerName, long timeOffset) { + this->_timeOffset = timeOffset; + this->_poolServerName = poolServerName; +} + +NTPClient::NTPClient(IPAddress poolServerIP, long timeOffset){ + this->_timeOffset = timeOffset; + this->_poolServerIP = poolServerIP; + this->_poolServerName = NULL; +} + +NTPClient::NTPClient(const char* poolServerName, long timeOffset, unsigned long updateInterval) { + this->_timeOffset = timeOffset; + this->_poolServerName = poolServerName; + this->_updateInterval = updateInterval; +} + +NTPClient::NTPClient(IPAddress poolServerIP, long timeOffset, unsigned long updateInterval) { + this->_timeOffset = timeOffset; + this->_poolServerIP = poolServerIP; + this->_poolServerName = NULL; + this->_updateInterval = updateInterval; +} + +void NTPClient::begin() { + this->begin(NTP_DEFAULT_LOCAL_PORT); +} + +void NTPClient::begin(unsigned int port) { + this->_port = port; + + this->_udp.begin(this->_port); + + this->_udpSetup = true; +} + +bool NTPClient::forceUpdate() { + #ifdef DEBUG_NTPClient + Serial.println("Update from NTP Server"); + #endif + + // flush any existing packets + while(this->_udp.parsePacket() != 0) + this->_udp.flush(); + + this->sendNTPPacket(); + + // Wait till data is there or timeout... + byte timeout = 0; + int cb = 0; + do { + delay ( 10 ); + cb = this->_udp.parsePacket(); + if (timeout > 100) return false; // timeout after 1000 ms + timeout++; + } while (cb == 0); + + this->_lastUpdate = millis() - (10 * (timeout + 1)); // Account for delay in reading the time + + this->_udp.read(this->_packetBuffer, NTP_PACKET_SIZE); + + unsigned long highWord = word(this->_packetBuffer[40], this->_packetBuffer[41]); + unsigned long lowWord = word(this->_packetBuffer[42], this->_packetBuffer[43]); + // combine the four bytes (two words) into a long integer + // this is NTP time (seconds since Jan 1 1900): + unsigned long secsSince1900 = highWord << 16 | lowWord; + + this->_currentEpoc = secsSince1900 - SEVENZYYEARS; + + return true; // return true after successful update +} + +bool NTPClient::update() { + if ((millis() - this->_lastUpdate >= this->_updateInterval) // Update after _updateInterval + || this->_lastUpdate == 0) { // Update if there was no update yet. + if (!this->_udpSetup || this->_port != NTP_DEFAULT_LOCAL_PORT) this->begin(this->_port); // setup the UDP client if needed + return this->forceUpdate(); + } + return false; // return false if update does not occur +} + +unsigned long NTPClient::getEpochTime() const { + return this->_timeOffset + // User offset + this->_currentEpoc + // Epoc returned by the NTP server + ((millis() - this->_lastUpdate) / 1000); // Time since last update +} + +int NTPClient::getDay() const { + return (((this->getEpochTime() / 86400L) + 4 ) % 7); //0 is Sunday +} +int NTPClient::getHours() const { + return ((this->getEpochTime() % 86400L) / 3600); +} +int NTPClient::getMinutes() const { + return ((this->getEpochTime() % 3600) / 60); +} +int NTPClient::getSeconds() const { + return (this->getEpochTime() % 60); +} + +String NTPClient::getFormattedTime() const { + unsigned long rawTime = this->getEpochTime(); + unsigned long hours = (rawTime % 86400L) / 3600; + String hoursStr = hours < 10 ? "0" + String(hours) : String(hours); + + unsigned long minutes = (rawTime % 3600) / 60; + String minuteStr = minutes < 10 ? "0" + String(minutes) : String(minutes); + + unsigned long seconds = rawTime % 60; + String secondStr = seconds < 10 ? "0" + String(seconds) : String(seconds); + + return hoursStr + ":" + minuteStr + ":" + secondStr; +} + +void NTPClient::end() { + this->_udp.stop(); + + this->_udpSetup = false; +} + +void NTPClient::setTimeOffset(int timeOffset) { + this->_timeOffset = timeOffset; +} + +void NTPClient::setUpdateInterval(unsigned long updateInterval) { + this->_updateInterval = updateInterval; +} + +void NTPClient::setPoolServerName(const char* poolServerName) { + this->_poolServerName = poolServerName; +} + +void NTPClient::sendNTPPacket() { + // set all bytes in the buffer to 0 + memset(this->_packetBuffer, 0, NTP_PACKET_SIZE); + // Initialize values needed to form NTP request + // (see URL above for details on the packets) + + this->_packetBuffer[0] = 0b11100011; // LI, Version, Mode + this->_packetBuffer[1] = 0; // Stratum, or type of clock + this->_packetBuffer[2] = 6; // Polling Interval + this->_packetBuffer[3] = 0xEC; // Peer Clock Precision + // 8 bytes of zero for Root Delay & Root Dispersion + this->_packetBuffer[12] = 49; + this->_packetBuffer[13] = 0x4E; + this->_packetBuffer[14] = 49; + this->_packetBuffer[15] = 52; + + // all NTP fields have been given values, now + // you can send a packet requesting a timestamp: + if (this->_poolServerName) { + this->_udp.beginPacket(this->_poolServerName, 123); + } else { + this->_udp.beginPacket(this->_poolServerIP, 123); + } + this->_udp.write(this->_packetBuffer, NTP_PACKET_SIZE); + this->_udp.endPacket(); +} + +void NTPClient::setRandomPort(unsigned int minValue, unsigned int maxValue) { + randomSeed(analogRead(0)); + this->_port = random(minValue, maxValue); +} \ No newline at end of file diff --git a/lib/NTPClient/NTPClient.h b/lib/NTPClient/NTPClient.h new file mode 100644 index 0000000..1407c68 --- /dev/null +++ b/lib/NTPClient/NTPClient.h @@ -0,0 +1,106 @@ +#pragma once + +#include +#include + +#define SEVENZYYEARS 2208988800UL +#define NTP_PACKET_SIZE 48 +#define NTP_DEFAULT_LOCAL_PORT 1337 + +class NTPClient { + private: + WiFiUDP _udp; + bool _udpSetup = false; + + const char* _poolServerName = "pool.ntp.org"; // Default time server + IPAddress _poolServerIP; + unsigned int _port = NTP_DEFAULT_LOCAL_PORT; + long _timeOffset = 0; + + unsigned long _updateInterval = 60000; // In ms + + unsigned long _currentEpoc = 0; // In s + unsigned long _lastUpdate = 0; // In ms + + byte _packetBuffer[NTP_PACKET_SIZE]; + + void sendNTPPacket(); + + public: + NTPClient(); + NTPClient(long timeOffset); + NTPClient(const char* poolServerName); + NTPClient(const char* poolServerName, long timeOffset); + NTPClient(const char* poolServerName, long timeOffset, unsigned long updateInterval); + NTPClient(IPAddress poolServerIP); + NTPClient(IPAddress poolServerIP, long timeOffset); + NTPClient(IPAddress poolServerIP, long timeOffset, unsigned long updateInterval); + + /** + * Set time server name + * + * @param poolServerName + */ + void setPoolServerName(const char* poolServerName); + + /** + * Set random local port + */ + void setRandomPort(unsigned int minValue = 49152, unsigned int maxValue = 65535); + + /** + * Starts the underlying UDP client with the default local port + */ + void begin(); + + /** + * Starts the underlying UDP client with the specified local port + */ + void begin(unsigned int port); + + /** + * This should be called in the main loop of your application. By default an update from the NTP Server is only + * made every 60 seconds. This can be configured in the NTPClient constructor. + * + * @return true on success, false on failure + */ + bool update(); + + /** + * This will force the update from the NTP Server. + * + * @return true on success, false on failure + */ + bool forceUpdate(); + + int getDay() const; + int getHours() const; + int getMinutes() const; + int getSeconds() const; + + /** + * Changes the time offset. Useful for changing timezones dynamically + */ + void setTimeOffset(int timeOffset); + + /** + * Set the update interval to another frequency. E.g. useful when the + * timeOffset should not be set in the constructor + */ + void setUpdateInterval(unsigned long updateInterval); + + /** + * @return time formatted like `hh:mm:ss` + */ + String getFormattedTime() const; + + /** + * @return time in seconds since Jan. 1, 1970 + */ + unsigned long getEpochTime() const; + + /** + * Stops the underlying UDP client + */ + void end(); +}; diff --git a/lib/PowerManagement/power_management.cpp b/lib/PowerManagement/power_management.cpp new file mode 100644 index 0000000..8f017b6 --- /dev/null +++ b/lib/PowerManagement/power_management.cpp @@ -0,0 +1,55 @@ + +#include "power_management.h" + +// cppcheck-suppress uninitMemberVar +PowerManagement::PowerManagement() +{ +} + +// cppcheck-suppress unusedFunction +bool PowerManagement::begin(TwoWire & port) +{ + bool result = axp.begin(port, AXP192_SLAVE_ADDRESS); + if(!result) + { + axp.setDCDC1Voltage(3300); + } + return result; +} + +// cppcheck-suppress unusedFunction +void PowerManagement::activateLoRa() +{ + axp.setPowerOutPut(AXP192_LDO2, AXP202_ON); +} + +// cppcheck-suppress unusedFunction +void PowerManagement::deactivateLoRa() +{ + axp.setPowerOutPut(AXP192_LDO2, AXP202_OFF); +} + +// cppcheck-suppress unusedFunction +void PowerManagement::activateGPS() +{ + axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); +} + +// cppcheck-suppress unusedFunction +void PowerManagement::deactivateGPS() +{ + axp.setPowerOutPut(AXP192_LDO3, AXP202_OFF); +} + +// cppcheck-suppress unusedFunction +void PowerManagement::activateOLED() +{ + axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON); +} + +// cppcheck-suppress unusedFunction +void PowerManagement::decativateOLED() +{ + axp.setPowerOutPut(AXP192_DCDC1, AXP202_OFF); +} + diff --git a/lib/PowerManagement/power_management.h b/lib/PowerManagement/power_management.h new file mode 100644 index 0000000..ecd6cf6 --- /dev/null +++ b/lib/PowerManagement/power_management.h @@ -0,0 +1,26 @@ +#ifndef POWER_MANAGEMENT_H_ +#define POWER_MANAGEMENT_H_ + +#include +#include + +class PowerManagement +{ +public: + PowerManagement(); + bool begin(TwoWire & port); + + void activateLoRa(); + void deactivateLoRa(); + + void activateGPS(); + void deactivateGPS(); + + void activateOLED(); + void decativateOLED(); + +private: + AXP20X_Class axp; +}; + +#endif diff --git a/lib/SignalSlot/SignalSlot.h b/lib/SignalSlot/SignalSlot.h new file mode 100644 index 0000000..28c92b5 --- /dev/null +++ b/lib/SignalSlot/SignalSlot.h @@ -0,0 +1,116 @@ +#ifndef SIGNAL_SLOT_H_ +#define SIGNAL_SLOT_H_ + +#include + +class Slot0 +{ +public: + virtual void action() = 0; +}; + +template +class Slot1 +{ +public: + virtual void action(T elem1) = 0; +}; + +template +class Slot2 +{ +public: + virtual void action(T elem1, H elem2) = 0; +}; + +template +class Slot3 +{ +public: + virtual void action(T elem1, H elem2, K elem3) = 0; +}; + +class Signal0 +{ +public: + void emit() + { + for(Slot0 * slot: _slots) + { + slot->action(); + } + } + + void connectSlot(Slot0 * slot) + { + _slots.push_back(slot); + } + +private: + std::list _slots; +}; + +template +class Signal1 +{ +public: + void emit(T elem1) + { + for(Slot1 * slot: _slots) + { + slot->action(elem1); + } + } + + void connectSlot(Slot1 * slot) + { + _slots.push_back(slot); + } + +private: + std::list *> _slots; +}; + +template +class Signal2 +{ +public: + void emit(T elem1, H elem2) + { + for(Slot2 * slot: _slots) + { + slot->action(elem1, elem2); + } + } + + void connectSlot(Slot2 * slot) + { + _slots.push_back(slot); + } + +private: + std::list *> _slots; +}; + +template +class Signal3 +{ +public: + void emit(T elem1, H elem2, K elem3) + { + for(Slot3 * slot: _slots) + { + slot->action(elem1, elem2, elem3); + } + } + + void connectSlot(Slot3 * slot) + { + _slots.push_back(slot); + } + +private: + std::list *> _slots; +}; + +#endif diff --git a/lib/TimeLib/TimeLib.cpp b/lib/TimeLib/TimeLib.cpp new file mode 100644 index 0000000..9394574 --- /dev/null +++ b/lib/TimeLib/TimeLib.cpp @@ -0,0 +1,329 @@ +/* + time.c - low level time and date functions + Copyright (c) Michael Margolis 2009-2014 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + 1.0 6 Jan 2010 - initial release + 1.1 12 Feb 2010 - fixed leap year calculation error + 1.2 1 Nov 2010 - fixed setTime bug (thanks to Korman for this) + 1.3 24 Mar 2012 - many edits by Paul Stoffregen: fixed timeStatus() to update + status, updated examples for Arduino 1.0, fixed ARM + compatibility issues, added TimeArduinoDue and TimeTeensy3 + examples, add error checking and messages to RTC examples, + add examples to DS1307RTC library. + 1.4 5 Sep 2014 - compatibility with Arduino 1.5.7 +*/ + +#include + +#include "TimeLib.h" + +static tmElements_t tm; // a cache of time elements +static time_t cacheTime; // the time the cache was updated +static uint32_t syncInterval = 300; // time sync will be attempted after this many seconds + +void refreshCache(time_t t) { + if (t != cacheTime) { + breakTime(t, tm); + cacheTime = t; + } +} + +int hour() { // the hour now + return hour(now()); +} + +int hour(time_t t) { // the hour for the given time + refreshCache(t); + return tm.Hour; +} + +int hourFormat12() { // the hour now in 12 hour format + return hourFormat12(now()); +} + +int hourFormat12(time_t t) { // the hour for the given time in 12 hour format + refreshCache(t); + if( tm.Hour == 0 ) + return 12; // 12 midnight + else if( tm.Hour > 12) + return tm.Hour - 12 ; + else + return tm.Hour ; +} + +uint8_t isAM() { // returns true if time now is AM + return !isPM(now()); +} + +uint8_t isAM(time_t t) { // returns true if given time is AM + return !isPM(t); +} + +uint8_t isPM() { // returns true if PM + return isPM(now()); +} + +uint8_t isPM(time_t t) { // returns true if PM + return (hour(t) >= 12); +} + +int minute() { + return minute(now()); +} + +int minute(time_t t) { // the minute for the given time + refreshCache(t); + return tm.Minute; +} + +int second() { + return second(now()); +} + +int second(time_t t) { // the second for the given time + refreshCache(t); + return tm.Second; +} + +int day(){ + return(day(now())); +} + +int day(time_t t) { // the day for the given time (0-6) + refreshCache(t); + return tm.Day; +} + +int weekday() { // Sunday is day 1 + return weekday(now()); +} + +int weekday(time_t t) { + refreshCache(t); + return tm.Wday; +} + +int month(){ + return month(now()); +} + +int month(time_t t) { // the month for the given time + refreshCache(t); + return tm.Month; +} + +int year() { // as in Processing, the full four digit year: (2009, 2010 etc) + return year(now()); +} + +int year(time_t t) { // the year for the given time + refreshCache(t); + return tmYearToCalendar(tm.Year); +} + +const String timeString() +{ + return timeString(now()); +} + +const String timeString(time_t t) +{ + char line[30]; + sprintf(line, "%02d:%02d:%02d", hour(t), minute(t), second(t)); + return String(line); +} + +/*============================================================================*/ +/* functions to convert to and from system time */ +/* These are for interfacing with time services and are not normally needed in a sketch */ + +// leap year calculator expects year argument as years offset from 1970 +#define LEAP_YEAR(Y) ( ((1970+(Y))>0) && !((1970+(Y))%4) && ( ((1970+(Y))%100) || !((1970+(Y))%400) ) ) + +static const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; // API starts months from 1, this array starts from 0 + +void breakTime(time_t timeInput, tmElements_t &tm){ +// break the given time_t into time components +// this is a more compact version of the C library localtime function +// note that year is offset from 1970 !!! + + uint8_t year; + uint8_t month, monthLength; + uint32_t time; + unsigned long days; + + time = (uint32_t)timeInput; + tm.Second = time % 60; + time /= 60; // now it is minutes + tm.Minute = time % 60; + time /= 60; // now it is hours + tm.Hour = time % 24; + time /= 24; // now it is days + tm.Wday = ((time + 4) % 7) + 1; // Sunday is day 1 + + year = 0; + days = 0; + while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) { + year++; + } + tm.Year = year; // year is offset from 1970 + + days -= LEAP_YEAR(year) ? 366 : 365; + time -= days; // now it is days in this year, starting at 0 + + days=0; + month=0; + monthLength=0; + for (month=0; month<12; month++) { + if (month==1) { // february + if (LEAP_YEAR(year)) { + monthLength=29; + } else { + monthLength=28; + } + } else { + monthLength = monthDays[month]; + } + + if (time >= monthLength) { + time -= monthLength; + } else { + break; + } + } + tm.Month = month + 1; // jan is month 1 + tm.Day = time + 1; // day of month +} + +time_t makeTime(const tmElements_t &tm){ +// assemble time elements into time_t +// note year argument is offset from 1970 (see macros in time.h to convert to other formats) +// previous version used full four digit year (or digits since 2000),i.e. 2009 was 2009 or 9 + + int i; + uint32_t seconds; + + // seconds from 1970 till 1 jan 00:00:00 of the given year + seconds= tm.Year*(SECS_PER_DAY * 365); + for (i = 0; i < tm.Year; i++) { + if (LEAP_YEAR(i)) { + seconds += SECS_PER_DAY; // add extra days for leap years + } + } + + // add days for this year, months start from 1 + for (i = 1; i < tm.Month; i++) { + if ( (i == 2) && LEAP_YEAR(tm.Year)) { + seconds += SECS_PER_DAY * 29; + } else { + seconds += SECS_PER_DAY * monthDays[i-1]; //monthDay array starts from 0 + } + } + seconds+= (tm.Day-1) * SECS_PER_DAY; + seconds+= tm.Hour * SECS_PER_HOUR; + seconds+= tm.Minute * SECS_PER_MIN; + seconds+= tm.Second; + return (time_t)seconds; +} +/*=====================================================*/ +/* Low level system time functions */ + +static uint32_t sysTime = 0; +static uint32_t prevMillis = 0; +static uint32_t nextSyncTime = 0; +static timeStatus_t Status = timeNotSet; + +getExternalTime getTimePtr; // pointer to external sync function +//setExternalTime setTimePtr; // not used in this version + +#ifdef TIME_DRIFT_INFO // define this to get drift data +time_t sysUnsyncedTime = 0; // the time sysTime unadjusted by sync +#endif + + +time_t now() { + // calculate number of seconds passed since last call to now() + while (millis() - prevMillis >= 1000) { + // millis() and prevMillis are both unsigned ints thus the subtraction will always be the absolute value of the difference + sysTime++; + prevMillis += 1000; +#ifdef TIME_DRIFT_INFO + sysUnsyncedTime++; // this can be compared to the synced time to measure long term drift +#endif + } + if (nextSyncTime <= sysTime) { + if (getTimePtr != 0) { + time_t t = getTimePtr(); + if (t != 0) { + setTime(t); + } else { + nextSyncTime = sysTime + syncInterval; + Status = (Status == timeNotSet) ? timeNotSet : timeNeedsSync; + } + } + } + return (time_t)sysTime; +} + +void setTime(time_t t) { +#ifdef TIME_DRIFT_INFO + if(sysUnsyncedTime == 0) + sysUnsyncedTime = t; // store the time of the first call to set a valid Time +#endif + + sysTime = (uint32_t)t; + nextSyncTime = (uint32_t)t + syncInterval; + Status = timeSet; + prevMillis = millis(); // restart counting from now (thanks to Korman for this fix) +} + +void setTime(int hr,int min,int sec,int dy, int mnth, int yr){ + // year can be given as full four digit year or two digts (2010 or 10 for 2010); + //it is converted to years since 1970 + if( yr > 99) + yr = yr - 1970; + else + yr += 30; + tm.Year = yr; + tm.Month = mnth; + tm.Day = dy; + tm.Hour = hr; + tm.Minute = min; + tm.Second = sec; + setTime(makeTime(tm)); +} + +void adjustTime(long adjustment) { + sysTime += adjustment; +} + +// indicates if time has been set and recently synchronized +timeStatus_t timeStatus() { + now(); // required to actually update the status + return Status; +} + +void setSyncProvider( getExternalTime getTimeFunction){ + getTimePtr = getTimeFunction; + nextSyncTime = sysTime; + now(); // this will sync the clock +} + +void setSyncInterval(time_t interval){ // set the number of seconds between re-sync + syncInterval = (uint32_t)interval; + nextSyncTime = sysTime + syncInterval; +} diff --git a/lib/TimeLib/TimeLib.h b/lib/TimeLib/TimeLib.h new file mode 100644 index 0000000..b624542 --- /dev/null +++ b/lib/TimeLib/TimeLib.h @@ -0,0 +1,126 @@ +/* + time.h - low level time and date functions +*/ + +/* + July 3 2011 - fixed elapsedSecsThisWeek macro (thanks Vincent Valdy for this) + - fixed daysToTime_t macro (thanks maniacbug) +*/ + +#ifndef _Time_h +#define _Time_h + +#include + +typedef enum {timeNotSet, timeNeedsSync, timeSet +} timeStatus_t ; + +typedef enum { + dowInvalid, dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday +} timeDayOfWeek_t; + +typedef enum { + tmSecond, tmMinute, tmHour, tmWday, tmDay,tmMonth, tmYear, tmNbrFields +} tmByteFields; + +typedef struct { + uint8_t Second; + uint8_t Minute; + uint8_t Hour; + uint8_t Wday; // day of week, sunday is day 1 + uint8_t Day; + uint8_t Month; + uint8_t Year; // offset from 1970; +} tmElements_t, TimeElements, *tmElementsPtr_t; + +//convenience macros to convert to and from tm years +#define tmYearToCalendar(Y) ((Y) + 1970) // full four digit year +#define CalendarYrToTm(Y) ((Y) - 1970) +#define tmYearToY2k(Y) ((Y) - 30) // offset is from 2000 +#define y2kYearToTm(Y) ((Y) + 30) + +typedef time_t(*getExternalTime)(); +//typedef void (*setExternalTime)(const time_t); // not used in this version + + +/*==============================================================================*/ +/* Useful Constants */ +#define SECS_PER_MIN ((time_t)(60UL)) +#define SECS_PER_HOUR ((time_t)(3600UL)) +#define SECS_PER_DAY ((time_t)(SECS_PER_HOUR * 24UL)) +#define DAYS_PER_WEEK ((time_t)(7UL)) +#define SECS_PER_WEEK ((time_t)(SECS_PER_DAY * DAYS_PER_WEEK)) +#define SECS_PER_YEAR ((time_t)(SECS_PER_DAY * 365UL)) // TODO: ought to handle leap years +#define SECS_YR_2000 ((time_t)(946684800UL)) // the time at the start of y2k + +/* Useful Macros for getting elapsed time */ +#define numberOfSeconds(_time_) ((_time_) % SECS_PER_MIN) +#define numberOfMinutes(_time_) (((_time_) / SECS_PER_MIN) % SECS_PER_MIN) +#define numberOfHours(_time_) (((_time_) % SECS_PER_DAY) / SECS_PER_HOUR) +#define dayOfWeek(_time_) ((((_time_) / SECS_PER_DAY + 4) % DAYS_PER_WEEK)+1) // 1 = Sunday +#define elapsedDays(_time_) ((_time_) / SECS_PER_DAY) // this is number of days since Jan 1 1970 +#define elapsedSecsToday(_time_) ((_time_) % SECS_PER_DAY) // the number of seconds since last midnight +// The following macros are used in calculating alarms and assume the clock is set to a date later than Jan 1 1971 +// Always set the correct time before setting alarms +#define previousMidnight(_time_) (((_time_) / SECS_PER_DAY) * SECS_PER_DAY) // time at the start of the given day +#define nextMidnight(_time_) (previousMidnight(_time_) + SECS_PER_DAY) // time at the end of the given day +#define elapsedSecsThisWeek(_time_) (elapsedSecsToday(_time_) + ((dayOfWeek(_time_)-1) * SECS_PER_DAY)) // note that week starts on day 1 +#define previousSunday(_time_) ((_time_) - elapsedSecsThisWeek(_time_)) // time at the start of the week for the given time +#define nextSunday(_time_) (previousSunday(_time_)+SECS_PER_WEEK) // time at the end of the week for the given time + + +/* Useful Macros for converting elapsed time to a time_t */ +#define minutesToTime_t ((M)) ( (M) * SECS_PER_MIN) +#define hoursToTime_t ((H)) ( (H) * SECS_PER_HOUR) +#define daysToTime_t ((D)) ( (D) * SECS_PER_DAY) // fixed on Jul 22 2011 +#define weeksToTime_t ((W)) ( (W) * SECS_PER_WEEK) + +/*============================================================================*/ +/* time and date functions */ +int hour(); // the hour now +int hour(time_t t); // the hour for the given time +int hourFormat12(); // the hour now in 12 hour format +int hourFormat12(time_t t); // the hour for the given time in 12 hour format +uint8_t isAM(); // returns true if time now is AM +uint8_t isAM(time_t t); // returns true the given time is AM +uint8_t isPM(); // returns true if time now is PM +uint8_t isPM(time_t t); // returns true the given time is PM +int minute(); // the minute now +int minute(time_t t); // the minute for the given time +int second(); // the second now +int second(time_t t); // the second for the given time +int day(); // the day now +int day(time_t t); // the day for the given time +int weekday(); // the weekday now (Sunday is day 1) +int weekday(time_t t); // the weekday for the given time +int month(); // the month now (Jan is month 1) +int month(time_t t); // the month for the given time +int year(); // the full four digit year: (2009, 2010 etc) +int year(time_t t); // the year for the given time + +const String timeString(); +const String timeString(time_t t); + +time_t now(); // return the current time as seconds since Jan 1 1970 +void setTime(time_t t); +void setTime(int hr,int min,int sec,int day, int month, int yr); +void adjustTime(long adjustment); + +/* date strings */ +#define dt_MAX_STRING_LEN 9 // length of longest date string (excluding terminating null) +const String monthStr(uint8_t month); +const String dayStr(uint8_t day); +const String monthShortStr(uint8_t month); +const String dayShortStr(uint8_t day); + +/* time sync functions */ +timeStatus_t timeStatus(); // indicates if time has been set and recently synchronized +void setSyncProvider( getExternalTime getTimeFunction); // identify the external time provider +void setSyncInterval(time_t interval); // set the number of seconds between re-sync + +/* low level functions to convert to and from system time */ +void breakTime(time_t time, tmElements_t &tm); // break time_t into elements +time_t makeTime(const tmElements_t &tm); // convert time elements into time_t + +#endif /* _Time_h */ + diff --git a/lib/TimeLib/TimeLibString.cpp b/lib/TimeLib/TimeLibString.cpp new file mode 100644 index 0000000..49bb0e8 --- /dev/null +++ b/lib/TimeLib/TimeLibString.cpp @@ -0,0 +1,56 @@ +/* DateStrings.cpp + * Definitions for date strings for use with the Time library + * + * Updated for Arduino 1.5.7 18 July 2014 + * + * No memory is consumed in the sketch if your code does not call any of the string methods + * You can change the text of the strings, make sure the short strings are each exactly 3 characters + * the long strings can be any length up to the constant dt_MAX_STRING_LEN defined in TimeLib.h + * + */ + +#include +#include "TimeLib.h" + +const String monthNames[] = +{ + "Error", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" +}; + +const String monthStr(uint8_t month) +{ + return monthNames[month]; +} + + +const String monthShortNames[] = +{ + "Err", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +const String monthShortStr(uint8_t month) +{ + return monthShortNames[month]; +} + + +const String dayNames[] = +{ + "Err", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" +}; + +const String dayStr(uint8_t day) +{ + return dayNames[day]; +} + + +const String dayShortNames[] = +{ + "Err", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; + +const String dayShortStr(uint8_t day) +{ + return dayShortNames[day]; +} diff --git a/lib/common b/lib/common deleted file mode 160000 index 285c641..0000000 --- a/lib/common +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 285c641c628e803e54d847d65165a7dbbbe271df diff --git a/platformio.ini b/platformio.ini index e3808e9..03fd44c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -4,14 +4,12 @@ framework = arduino lib_ldf_mode = deep+ monitor_speed = 115200 lib_deps = - arduino-libraries/NTPClient @ 3.1.0 adafruit/Adafruit GFX Library @ 1.7.5 adafruit/Adafruit SSD1306 @ 2.4.0 bblanchon/ArduinoJson @ 6.17.0 lewisxhe/AXP202X_Library @ 1.1.2 - sandeepmistry/LoRa @ 0.7.2 peterus/APRS-Decoder-Lib @ 0.0.5 - peterus/APRS-IS-Lib @ 0.0.7 + peterus/esp-logger @ 0.0.1 peterus/ESP-FTP-Server-Lib @ 0.9.5 check_tool = cppcheck check_flags = diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index f01ac92..93f20a6 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -1,65 +1,37 @@ #include -#include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include "logger.h" +#include +#include "SignalSlot.h" #include "BoardFinder.h" #include "LoRa_APRS.h" -#include "pins.h" #include "display.h" -#include "project_configuration.h" - -#ifdef NO_GLOBAL_INSTANCES -HardwareSerial Serial(0); -ArduinoOTAClass ArduinoOTA; -#endif - #include "power_management.h" -PowerManagement powerManagement; +#include "project_configuration.h" +#include "connection.h" -portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; -hw_timer_t * timer = NULL; -volatile uint secondsSinceLastAPRSISBeacon = 0; -volatile uint secondsSinceStartup = 0; -volatile uint secondsSinceDisplay = 0; +HardwareSerial Serial(0); -WiFiMulti WiFiMulti; -WiFiUDP ntpUDP; -NTPClient * timeClient; -FTPServer ftpServer; -Configuration * Config; +std::shared_ptr OTA; +std::shared_ptr powerManagement; +std::shared_ptr WiFiMulti; +std::shared_ptr ntpClient; +std::shared_ptr ftpServer; +std::shared_ptr userConfig; std::shared_ptr boardConfig; -APRS_IS * aprs_is = 0; -LoRa_APRS * lora_aprs; +std::shared_ptr aprs_is; +std::shared_ptr lora_aprs; std::shared_ptr BeaconMsg; -volatile bool eth_connected = false; - String create_lat_aprs(double lat); String create_long_aprs(double lng); -void setup_eth(); -void setup_wifi(); +std::shared_ptr setup_lora(); -void load_config(); -void setup_wifi(); -void setup_ota(); -void setup_lora(); -void setup_ntp(); -void setup_aprs_is(); -void setup_timer(); -void setup_ftp(); - -std::map> lastMessages; +PrintMessageToConsole printMessageConsole; +bool ethEnabled = false; // cppcheck-suppress unusedFunction void setup() @@ -69,22 +41,31 @@ void setup() delay(500); ProjectConfigurationManagement confmg; - Config = confmg.readConfiguration(); + userConfig = confmg.readConfiguration(); - BoardFinder finder; - boardConfig = finder.getBoardConfig(Config->board); + std::list> boardConfigs; + boardConfigs.push_back(std::shared_ptr(new BoardConfig("TTGO_LORA32_V1", eTTGO_LORA32_V1, 4, 15, 0x3C, 0, 5, 19, 27, 18, 14, 26))); + boardConfigs.push_back(std::shared_ptr(new BoardConfig("TTGO_LORA32_V2", eTTGO_LORA32_V2, 21, 22, 0x3C, 0, 5, 19, 27, 18, 14, 26, true))); + boardConfigs.push_back(std::shared_ptr(new BoardConfig("TTGO_T_Beam_V0_7", eTTGO_T_Beam_V0_7, 21, 22, 0x3C, 0, 5, 19, 27, 18, 14, 26, true))); + boardConfigs.push_back(std::shared_ptr(new BoardConfig("TTGO_T_Beam_V1_0", eTTGO_T_Beam_V1_0, 21, 22, 0x3C, 0, 5, 19, 27, 18, 14, 26, true, true))); + boardConfigs.push_back(std::shared_ptr(new BoardConfig("ETH_BOARD", eETH_BOARD, 33, 32, 0x3C, 0, 14, 2, 15, 12, 4, 36))); + boardConfigs.push_back(std::shared_ptr(new BoardConfig("TRACKERD", eTRACKERD, 5, 4, 0x3C, 0, 18, 19, 23, 16, 14, 26))); + boardConfigs.push_back(std::shared_ptr(new BoardConfig("HELTEC_WIFI_LORA_32_V1", eHELTEC_WIFI_LORA_32_V1, 4, 15, 0x3C, 16, 5, 19, 27, 18, 14, 26))); + boardConfigs.push_back(std::shared_ptr(new BoardConfig("HELTEC_WIFI_LORA_32_V2", eHELTEC_WIFI_LORA_32_V2, 4, 15, 0x3C, 16, 5, 19, 27, 18, 14, 26))); + + BoardFinder finder(boardConfigs); + boardConfig = finder.getBoardConfig(userConfig->board); if(boardConfig == 0) { boardConfig = finder.searchBoardConfig(); if(boardConfig == 0) { logPrintlnE("Board config not set and search failed!"); - while (true) - { - } + while(true) + {} } - Config->board = boardConfig->Name; - confmg.writeConfiguration(Config); + userConfig->board = boardConfig->Name; + confmg.writeConfiguration(userConfig); logPrintlnI("will restart board now!"); ESP.restart(); } @@ -96,7 +77,8 @@ void setup() { TwoWire wire(0); wire.begin(boardConfig->OledSda, boardConfig->OledScl); - if (!powerManagement.begin(wire)) + std::shared_ptr powerManagement = std::shared_ptr(new PowerManagement); + if (!powerManagement->begin(wire)) { logPrintlnI("AXP192 init done!"); } @@ -104,9 +86,9 @@ void setup() { logPrintlnE("AXP192 init failed!"); } - powerManagement.activateLoRa(); - powerManagement.activateOLED(); - powerManagement.deactivateGPS(); + powerManagement->activateLoRa(); + powerManagement->activateOLED(); + powerManagement->deactivateGPS(); } logPrintlnW("LoRa APRS iGate by OE5BPA (Peter Buchegger)"); @@ -114,107 +96,76 @@ void setup() setup_display(boardConfig); show_display("OE5BPA", "LoRa APRS iGate", "by Peter Buchegger", "20.49.0-dev", 3000); - load_config(); - setup_lora(); - timeClient = new NTPClient(ntpUDP, Config->ntpServer.c_str()); + load_config(boardConfig); + lora_aprs = setup_lora(); if(boardConfig->Type == eETH_BOARD) { setup_eth(); - setup_ota(); - setup_ntp(); - setup_ftp(); - setup_aprs_is(); + ethEnabled = true; } - else - { - if(Config->wifi.active) - { - setup_wifi(); - setup_ota(); - setup_ntp(); - setup_ftp(); - } - else - { - // make sure wifi and bt is off if we don't need it: - WiFi.mode(WIFI_OFF); - btStop(); - } - if(Config->aprs_is.active) setup_aprs_is(); - } - setup_timer(); + WiFiMulti = setup_wifi(userConfig); + OTA = setup_ota(userConfig); + ntpClient = setup_ntp(userConfig); + ftpServer = setup_ftp(userConfig); + aprs_is = std::shared_ptr(new APRS_IS(userConfig->callsign, userConfig->aprs_is.password , "ESP32-APRS-IS", "0.1")); - if(Config->display.overwritePin != 0) + if(userConfig->display.overwritePin != 0) { - pinMode(Config->display.overwritePin, INPUT); - pinMode(Config->display.overwritePin, INPUT_PULLUP); + pinMode(userConfig->display.overwritePin, INPUT); + pinMode(userConfig->display.overwritePin, INPUT_PULLUP); } + logPrintlnD("connect objects..."); + lora_aprs->connectSlot(&printMessageConsole); + lora_aprs->connectSlot(aprs_is.get()); + delay(500); logPrintlnI("setup done..."); - secondsSinceDisplay = 0; } // cppcheck-suppress unusedFunction void loop() { - static bool display_is_on = true; - if(Config->display.overwritePin != 0 && !digitalRead(Config->display.overwritePin)) + static bool beacon_aprs_is = true; + if(userConfig->ftp.active) { - secondsSinceDisplay = 0; - display_is_on = true; - setup_display(boardConfig); - } else - if(!Config->display.alwaysOn && secondsSinceDisplay > Config->display.timeout && display_is_on) - { - turn_off_display(); - display_is_on = false; - } - - static bool beacon_aprs_is = Config->aprs_is.active && Config->aprs_is.beacon; - - if(Config->aprs_is.active && Config->aprs_is.beacon && secondsSinceLastAPRSISBeacon >= (Config->aprs_is.beaconTimeout*60)) - { - portENTER_CRITICAL(&timerMux); - secondsSinceLastAPRSISBeacon -= (Config->aprs_is.beaconTimeout*60); - portEXIT_CRITICAL(&timerMux); - beacon_aprs_is = true; - } - - if(Config->ftp.active) - { - ftpServer.handle(); + ftpServer->handle(); static bool configWasOpen = false; - if(configWasOpen && ftpServer.countConnections() == 0) + if(configWasOpen && ftpServer->countConnections() == 0) { logPrintlnW("Maybe the config has been changed via FTP, lets restart now to get the new config..."); Serial.println(); ESP.restart(); } - if(ftpServer.countConnections() > 0) + if(ftpServer->countConnections() > 0) { configWasOpen = true; } } - if(Config->wifi.active || eth_connected) ArduinoOTA.handle(); - if(Config->wifi.active && WiFiMulti.run() != WL_CONNECTED) + const uint8_t wifi_status = WiFiMulti->run(); + if(!ethEnabled && wifi_status != WL_CONNECTED) { - setup_display(boardConfig); secondsSinceDisplay = 0; display_is_on = true; logPrintlnE("WiFi not connected!"); show_display("ERROR", "WiFi not connected!"); delay(1000); return; } - if((eth_connected && !aprs_is->connected()) || (Config->aprs_is.active && !aprs_is->connected())) + + OTA->handle(); + if(ntpClient->update()) + { + setTime(ntpClient->getEpochTime()); + } + + if(!aprs_is->connected()) { - setup_display(boardConfig); secondsSinceDisplay = 0; display_is_on = true; logPrintI("connecting to APRS-IS server: "); - logPrintI(Config->aprs_is.server); + logPrintI(userConfig->aprs_is.server); logPrintI(" on port: "); - logPrintlnI(String(Config->aprs_is.port)); + logPrintlnI(String(userConfig->aprs_is.port)); show_display("INFO", "Connecting to APRS-IS server"); - if(!aprs_is->connect(Config->aprs_is.server, Config->aprs_is.port)) + if(!aprs_is->connect(userConfig->aprs_is.server, userConfig->aprs_is.port)) { logPrintlnE("Connection failed."); logPrintlnI("Waiting 5 seconds before retrying..."); @@ -224,274 +175,48 @@ void loop() } logPrintlnI("Connected to APRS-IS server!"); } - if(Config->aprs_is.active && aprs_is->available() > 0) - { - String str = aprs_is->getMessage(); - logPrintD("[" + timeClient->getFormattedTime() + "] "); - logPrintlnD(str); - } - if(lora_aprs->hasMessage()) - { - std::shared_ptr msg = lora_aprs->getMessage(); - setup_display(boardConfig); secondsSinceDisplay = 0; display_is_on = true; - show_display(Config->callsign, timeClient->getFormattedTime() + " LoRa", "RSSI: " + String(lora_aprs->packetRssi()) + ", SNR: " + String(lora_aprs->packetSnr()), msg->toString()); - logPrintD("[" + timeClient->getFormattedTime() + "] "); - logPrintD(" Received packet '"); - logPrintD(msg->toString()); - logPrintD("' with RSSI "); - logPrintD(String(lora_aprs->packetRssi())); - logPrintD(" and SNR "); - logPrintlnD(String(lora_aprs->packetSnr())); - - if(Config->aprs_is.active) - { - aprs_is->sendMessage(msg->encode()); - } - } - if(beacon_aprs_is) + aprs_is->getAPRSMessage(); + lora_aprs->checkMessage(); + + if(false) //beacon_aprs_is { beacon_aprs_is = false; - setup_display(boardConfig); secondsSinceDisplay = 0; display_is_on = true; - show_display(Config->callsign, "Beacon to APRS-IS Server..."); - logPrintD("[" + timeClient->getFormattedTime() + "] "); + show_display(userConfig->callsign, "Beacon to APRS-IS Server..."); + logPrintD("[" + ntpClient->getFormattedTime() + "] "); logPrintlnD(BeaconMsg->encode()); aprs_is->sendMessage(BeaconMsg); - show_display(Config->callsign, "Standby..."); + show_display(userConfig->callsign, "Standby..."); } } -void load_config() +std::shared_ptr setup_lora() { - ProjectConfigurationManagement confmg; - Config = confmg.readConfiguration(); - if(Config->callsign == "NOCALL-10") - { - logPrintlnE("You have to change your settings in 'data/is-cfg.json' and upload it via \"Upload File System image\"!"); - show_display("ERROR", "You have to change your settings in 'data/is-cfg.json' and upload it via \"Upload File System image\"!"); - while (true) - {} - } - - if(boardConfig->Type != eETH_BOARD && Config->aprs_is.active && !Config->wifi.active) - { - logPrintlnE("You have to activate Wifi for APRS IS to work, please check your settings!"); - show_display("ERROR", "You have to activate Wifi for APRS IS to work, please check your settings!"); - while (true) - {} - } - - if(KEY_BUILTIN != 0 && Config->display.overwritePin == 0) - { - Config->display.overwritePin = KEY_BUILTIN; - } - logPrintlnI("Configuration loaded!"); -} - -void WiFiEvent(WiFiEvent_t event) -{ - switch (event) { - case SYSTEM_EVENT_ETH_START: - logPrintlnI("ETH Started"); - ETH.setHostname("esp32-ethernet"); - break; - case SYSTEM_EVENT_ETH_CONNECTED: - logPrintlnI("ETH Connected"); - break; - case SYSTEM_EVENT_ETH_GOT_IP: - logPrintI("ETH MAC: "); - logPrintI(ETH.macAddress()); - logPrintI(", IPv4: "); - logPrintI(ETH.localIP().toString()); - if (ETH.fullDuplex()) { - logPrintI(", FULL_DUPLEX"); - } - logPrintI(", "); - logPrintI(String(ETH.linkSpeed())); - logPrintlnI("Mbps"); - eth_connected = true; - break; - case SYSTEM_EVENT_ETH_DISCONNECTED: - logPrintlnW("ETH Disconnected"); - eth_connected = false; - break; - case SYSTEM_EVENT_ETH_STOP: - logPrintlnW("ETH Stopped"); - eth_connected = false; - break; - default: - break; - } -} - -void setup_eth() -{ - WiFi.onEvent(WiFiEvent); - - #define ETH_POWER_PIN -1 - #define ETH_TYPE ETH_PHY_LAN8720 - #define ETH_ADDR 0 - #define ETH_MDC_PIN 23 - #define ETH_MDIO_PIN 18 - #define ETH_NRST 5 - #define ETH_CLK ETH_CLOCK_GPIO17_OUT // TTGO PoE V1.0 - //#define ETH_CLK ETH_CLOCK_GPIO0_OUT // TTGO PoE V1.2 - - pinMode(ETH_NRST, OUTPUT); - digitalWrite(ETH_NRST, 0); - delay(200); - digitalWrite(ETH_NRST, 1); - delay(200); - digitalWrite(ETH_NRST, 0); - delay(200); - digitalWrite(ETH_NRST, 1); - - ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK); - while(!eth_connected) - { - sleep(1); - } -} - -void setup_wifi() -{ - WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); - WiFi.setHostname(Config->callsign.c_str()); - for(Configuration::Wifi::AP ap : Config->wifi.APs) - { - logPrintD("Looking for AP: "); - logPrintlnD(ap.SSID); - WiFiMulti.addAP(ap.SSID.c_str(), ap.password.c_str()); - } - logPrintlnI("Waiting for WiFi"); - show_display("INFO", "Waiting for WiFi"); - while(WiFiMulti.run() != WL_CONNECTED) - { - show_display("INFO", "Waiting for WiFi", "...."); - delay(500); - } - logPrintlnI("WiFi connected"); - logPrintD("IP address: "); - logPrintlnD(WiFi.localIP().toString()); - show_display("INFO", "WiFi connected", "IP: ", WiFi.localIP().toString(), 2000); -} - -void setup_ota() -{ - ArduinoOTA - .onStart([]() - { - String type; - if (ArduinoOTA.getCommand() == U_FLASH) - type = "sketch"; - else // U_SPIFFS - type = "filesystem"; - Serial.println("Start updating " + type); - show_display("OTA UPDATE", "Start update", type); - }) - .onEnd([]() - { - Serial.println(); - Serial.println("End"); - }) - .onProgress([](unsigned int progress, unsigned int total) - { - Serial.print("Progress: "); - Serial.print(progress / (total / 100)); - Serial.println("%"); - show_display("OTA UPDATE", "Progress: ", String(progress / (total / 100)) + "%"); - }) - .onError([](ota_error_t error) { - Serial.print("Error["); - Serial.print(error); - Serial.print("]: "); - if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); - else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); - else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); - else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); - else if (error == OTA_END_ERROR) Serial.println("End Failed"); - }); - ArduinoOTA.setHostname(Config->callsign.c_str()); - ArduinoOTA.begin(); - logPrintlnI("OTA init done!"); -} - -void setup_lora() -{ - lora_aprs = new LoRa_APRS(boardConfig); - if (!lora_aprs->begin(lora_aprs->getRxFrequency())) + std::shared_ptr lora_aprs = std::shared_ptr(new LoRa_APRS(boardConfig)); + if(!lora_aprs->begin(lora_aprs->getRxFrequency())) { logPrintlnE("Starting LoRa failed!"); show_display("ERROR", "Starting LoRa failed!"); - while (1); + while(true); } - lora_aprs->setRxFrequency(Config->lora.frequencyRx); - lora_aprs->setTxFrequency(Config->lora.frequencyTx); - lora_aprs->setTxPower(Config->lora.power); - lora_aprs->setSpreadingFactor(Config->lora.spreadingFactor); - lora_aprs->setSignalBandwidth(Config->lora.signalBandwidth); - lora_aprs->setCodingRate4(Config->lora.codingRate4); + lora_aprs->setRxFrequency(userConfig->lora.frequencyRx); + lora_aprs->setTxFrequency(userConfig->lora.frequencyTx); + lora_aprs->setTxPower(userConfig->lora.power); + lora_aprs->setSpreadingFactor(userConfig->lora.spreadingFactor); + lora_aprs->setSignalBandwidth(userConfig->lora.signalBandwidth); + lora_aprs->setCodingRate4(userConfig->lora.codingRate4); lora_aprs->enableCrc(); logPrintlnI("LoRa init done!"); show_display("INFO", "LoRa init done!", 2000); BeaconMsg = std::shared_ptr(new APRSMessage()); - BeaconMsg->setSource(Config->callsign); + BeaconMsg->setSource(userConfig->callsign); BeaconMsg->setDestination("APLG0"); - String lat = create_lat_aprs(Config->beacon.positionLatitude); - String lng = create_long_aprs(Config->beacon.positionLongitude); - BeaconMsg->getAPRSBody()->setData(String("=") + lat + "I" + lng + "&" + Config->beacon.message); -} + String lat = create_lat_aprs(userConfig->beacon.positionLatitude); + String lng = create_long_aprs(userConfig->beacon.positionLongitude); + BeaconMsg->getAPRSBody()->setData(String("=") + lat + "I" + lng + "&" + userConfig->beacon.message); -void setup_ntp() -{ - timeClient->begin(); - while(!timeClient->forceUpdate()) - { - logPrintlnW("NTP Client force update issue! Waiting 1 sek..."); - show_display("WARN", "NTP Client force update issue! Waiting 1 sek...", 1000); - } - logPrintlnI("NTP Client init done!"); - show_display("INFO", "NTP Client init done!", 2000); -} - -void setup_aprs_is() -{ - aprs_is = new APRS_IS(Config->callsign, Config->aprs_is.password , "ESP32-APRS-IS", "0.1"); -} - -void IRAM_ATTR onTimer() -{ - portENTER_CRITICAL_ISR(&timerMux); - secondsSinceLastAPRSISBeacon++; - secondsSinceStartup++; - secondsSinceDisplay++; - portEXIT_CRITICAL_ISR(&timerMux); -} - -void setup_timer() -{ - timer = timerBegin(0, 80, true); - timerAlarmWrite(timer, 1000000, true); - timerAttachInterrupt(timer, &onTimer, true); - timerAlarmEnable(timer); -} - -void setup_ftp() -{ - if(!Config->ftp.active) - { - return; - } - for(Configuration::Ftp::User user : Config->ftp.users) - { - logPrintD("Adding user to FTP Server: "); - logPrintlnD(user.name); - ftpServer.addUser(user.name, user.password); - } - ftpServer.addFilesystem("SPIFFS", &SPIFFS); - ftpServer.begin(); - logPrintlnI("FTP Server init done!"); + return lora_aprs; } String create_lat_aprs(double lat) diff --git a/src/connection.cpp b/src/connection.cpp new file mode 100644 index 0000000..f294ee6 --- /dev/null +++ b/src/connection.cpp @@ -0,0 +1,183 @@ + +#include +#include +#include +#include +#include + +#include "connection.h" + +volatile bool eth_connected = false; + +static void WiFiEvent(WiFiEvent_t event) +{ + switch (event) { + case SYSTEM_EVENT_ETH_START: + logPrintlnI("ETH Started"); + ETH.setHostname("esp32-ethernet"); + break; + case SYSTEM_EVENT_ETH_CONNECTED: + logPrintlnI("ETH Connected"); + break; + case SYSTEM_EVENT_ETH_GOT_IP: + logPrintI("ETH MAC: "); + logPrintI(ETH.macAddress()); + logPrintI(", IPv4: "); + logPrintI(ETH.localIP().toString()); + if (ETH.fullDuplex()) { + logPrintI(", FULL_DUPLEX"); + } + logPrintI(", "); + logPrintI(String(ETH.linkSpeed())); + logPrintlnI("Mbps"); + eth_connected = true; + break; + case SYSTEM_EVENT_ETH_DISCONNECTED: + logPrintlnW("ETH Disconnected"); + eth_connected = false; + break; + case SYSTEM_EVENT_ETH_STOP: + logPrintlnW("ETH Stopped"); + eth_connected = false; + break; + default: + break; + } +} + +bool isEthConnected() +{ + return eth_connected; +} + +void setup_eth() +{ + WiFi.onEvent(WiFiEvent); + + #define ETH_POWER_PIN -1 + #define ETH_TYPE ETH_PHY_LAN8720 + #define ETH_ADDR 0 + #define ETH_MDC_PIN 23 + #define ETH_MDIO_PIN 18 + #define ETH_NRST 5 + #define ETH_CLK ETH_CLOCK_GPIO17_OUT // TTGO PoE V1.0 + //#define ETH_CLK ETH_CLOCK_GPIO0_OUT // TTGO PoE V1.2 + + pinMode(ETH_NRST, OUTPUT); + digitalWrite(ETH_NRST, 0); + delay(200); + digitalWrite(ETH_NRST, 1); + delay(200); + digitalWrite(ETH_NRST, 0); + delay(200); + digitalWrite(ETH_NRST, 1); + + ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK); + while(!eth_connected) + { + sleep(1); + } +} + +std::shared_ptr setup_wifi(std::shared_ptr config) +{ + WiFi.onEvent(WiFiEvent); + //WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); + WiFi.setHostname(config->callsign.c_str()); + std::shared_ptr wiFiMulti = std::shared_ptr(new WiFiMulti());; + for(Configuration::Wifi::AP ap : config->wifi.APs) + { + logPrintD("Looking for AP: "); + logPrintlnD(ap.SSID); + wiFiMulti->addAP(ap.SSID.c_str(), ap.password.c_str()); + } + logPrintlnI("Waiting for WiFi"); + //show_display("INFO", "Waiting for WiFi"); + while(wiFiMulti->run() != WL_CONNECTED) + { + //show_display("INFO", "Waiting for WiFi", "...."); + delay(500); + } + logPrintlnI("WiFi connected"); + logPrintD("IP address: "); + logPrintlnD(WiFi.localIP().toString()); + //show_display("INFO", "WiFi connected", "IP: ", WiFi.localIP().toString(), 2000); + return wiFiMulti; +} + +std::shared_ptr setup_ota(std::shared_ptr config) +{ + std::shared_ptr ota = std::shared_ptr(new ArduinoOTAClass()); + ota->onStart([&]() + { + String type; + if (ota->getCommand() == U_FLASH) + type = "sketch"; + else // U_SPIFFS + type = "filesystem"; + logPrintlnI("Start updating " + type); + //show_display("OTA UPDATE", "Start update", type); + }) + .onEnd([]() + { + logPrintlnI(""); + logPrintlnI("OTA End"); + }) + .onProgress([](unsigned int progress, unsigned int total) + { + logPrintI("Progress: "); + logPrintI(String(progress / (total / 100))); + logPrintlnI("%"); + //show_display("OTA UPDATE", "Progress: ", String(progress / (total / 100)) + "%"); + }) + .onError([](ota_error_t error) + { + logPrintE("Error["); + logPrintE(String(error)); + logPrintE("]: "); + if (error == OTA_AUTH_ERROR) logPrintlnE("Auth Failed"); + else if (error == OTA_BEGIN_ERROR) logPrintlnE("Begin Failed"); + else if (error == OTA_CONNECT_ERROR) logPrintlnE("Connect Failed"); + else if (error == OTA_RECEIVE_ERROR) logPrintlnE("Receive Failed"); + else if (error == OTA_END_ERROR) logPrintlnE("End Failed"); + }); + ota->setHostname(config->callsign.c_str()); + ota->begin(); + logPrintlnI("OTA init done!"); + return ota; +} + +std::shared_ptr setup_ntp(std::shared_ptr config) +{ + std::shared_ptr ntpClient = std::shared_ptr(new NTPClient(config->ntpServer.c_str())); + ntpClient->begin(); + while(!ntpClient->forceUpdate()) + { + logPrintlnW("NTP Client force update issue! Waiting 1 sek..."); + logPrintlnD(ntpClient->getFormattedTime()); + //show_display("WARN", "NTP Client force update issue! Waiting 1 sek...", 1000); + sleep(1); + } + setTime(ntpClient->getEpochTime()); + logPrintlnI("NTP Client init done!"); + //show_display("INFO", "NTP Client init done!", 2000); + return ntpClient; +} + +std::shared_ptr setup_ftp(std::shared_ptr config) +{ + std::shared_ptr ftpServer = std::shared_ptr(new FTPServer()); + if(config->ftp.active) + { + for(Configuration::Ftp::User user : config->ftp.users) + { + logPrintD("Adding user to FTP Server: "); + logPrintlnD(user.name); + ftpServer->addUser(user.name, user.password); + } + ftpServer->addFilesystem("SPIFFS", &SPIFFS); + ftpServer->begin(); + logPrintlnI("FTP Server init done!"); + } + return ftpServer; +} diff --git a/src/connection.h b/src/connection.h new file mode 100644 index 0000000..2ef9880 --- /dev/null +++ b/src/connection.h @@ -0,0 +1,19 @@ + +#ifndef CONNECTION_H_ +#define CONNECTION_H_ + +#include +#include +#include +#include +#include +#include "project_configuration.h" + +bool isEthConnected(); +void setup_eth(); +std::shared_ptr setup_wifi(std::shared_ptr config); +std::shared_ptr setup_ota(std::shared_ptr config); +std::shared_ptr setup_ntp(std::shared_ptr config); +std::shared_ptr setup_ftp(std::shared_ptr config); + +#endif diff --git a/src/display.cpp b/src/display.cpp new file mode 100644 index 0000000..ba54c22 --- /dev/null +++ b/src/display.cpp @@ -0,0 +1,142 @@ + +#include +#include +#include + +#include "BoardFinder.h" +#include "display.h" +#include "logger.h" + +Adafruit_SSD1306 * display = 0; +TwoWire * wire = 0; + +void setup_display(std::shared_ptr boardConfig) +{ + if(display == 0) + { + wire = new TwoWire(0); + wire->begin(boardConfig->OledSda, boardConfig->OledScl); + if(boardConfig->OledReset > 0) + { + display = new Adafruit_SSD1306(128, 64, wire, boardConfig->OledReset); + logPrintlnI("with reset"); + } + else + { + display = new Adafruit_SSD1306(128, 64, wire); + logPrintlnI("with NO reset"); + } + } + if(!display->begin(SSD1306_SWITCHCAPVCC, boardConfig->OledAddr, false, false)) + { + logPrintlnE("SSD1306 allocation failed"); + while (1); + } + logPrintlnI("Display init done!"); +} + +void turn_off_display() +{ + display->ssd1306_command(SSD1306_DISPLAYOFF); +} + +void show_display(String header, int wait) +{ + display->clearDisplay(); + display->setTextColor(WHITE); + display->setTextSize(2); + display->setCursor(0,0); + display->println(header); + display->display(); + delay(wait); +} + +void show_display(String header, String line1, int wait) +{ + display->clearDisplay(); + display->setTextColor(WHITE); + display->setTextSize(2); + display->setCursor(0,0); + display->println(header); + display->setTextSize(1); + display->setCursor(0,16); + display->println(line1); + display->display(); + delay(wait); +} + +void show_display(String header, String line1, String line2, int wait) +{ + display->clearDisplay(); + display->setTextColor(WHITE); + display->setTextSize(2); + display->setCursor(0,0); + display->println(header); + display->setTextSize(1); + display->setCursor(0,16); + display->println(line1); + display->setCursor(0,26); + display->println(line2); + display->display(); + delay(wait); +} + +void show_display(String header, String line1, String line2, String line3, int wait) +{ + display->clearDisplay(); + display->setTextColor(WHITE); + display->setTextSize(2); + display->setCursor(0,0); + display->println(header); + display->setTextSize(1); + display->setCursor(0,16); + display->println(line1); + display->setCursor(0,26); + display->println(line2); + display->setCursor(0,36); + display->println(line3); + display->display(); + delay(wait); +} + +void show_display(String header, String line1, String line2, String line3, String line4, int wait) +{ + display->clearDisplay(); + display->setTextColor(WHITE); + display->setTextSize(2); + display->setCursor(0,0); + display->println(header); + display->setTextSize(1); + display->setCursor(0,16); + display->println(line1); + display->setCursor(0,26); + display->println(line2); + display->setCursor(0,36); + display->println(line3); + display->setCursor(0,46); + display->println(line4); + display->display(); + delay(wait); +} + +void show_display(String header, String line1, String line2, String line3, String line4, String line5, int wait) +{ + display->clearDisplay(); + display->setTextColor(WHITE); + display->setTextSize(2); + display->setCursor(0,0); + display->println(header); + display->setTextSize(1); + display->setCursor(0,16); + display->println(line1); + display->setCursor(0,26); + display->println(line2); + display->setCursor(0,36); + display->println(line3); + display->setCursor(0,46); + display->println(line4); + display->setCursor(0,56); + display->println(line5); + display->display(); + delay(wait); +} diff --git a/src/display.h b/src/display.h new file mode 100644 index 0000000..f89c431 --- /dev/null +++ b/src/display.h @@ -0,0 +1,47 @@ + +#ifndef DISPLAY_H_ +#define DISPLAY_H_ + +void setup_display(std::shared_ptr boardConfig); +void turn_off_display(); + +void show_display(String header, int wait = 0); +void show_display(String header, String line1, int wait = 0); +void show_display(String header, String line1, String line2, int wait = 0); +void show_display(String header, String line1, String line2, String line3, int wait = 0); +void show_display(String header, String line1, String line2, String line3, String line4, int wait = 0); +void show_display(String header, String line1, String line2, String line3, String line4, String line5, int wait = 0); + +#include +#include "SignalSlot.h" +#include "TimeLib.h" +#include "logger.h" + +class PrintMessageToConsole : public Slot1>, public Slot3, int, float> +{ +public: + void action(std::shared_ptr msg, int rssi, float snr) override + { + //setup_display(boardConfig); secondsSinceDisplay = 0; //display_is_on = true; + //show_display(Config->callsign, timeClient->getFormattedTime() + " LoRa", "RSSI: " + String(lora_aprs->packetRssi()) + ", SNR: " + String(lora_aprs->packetSnr()), elem->toString()); + logPrintD("[" + timeString() + "] "); + logPrintD("Received packet '"); + logPrintD(msg->toString()); + logPrintD("' with RSSI "); + logPrintD(String(rssi)); + logPrintD(" and SNR "); + logPrintlnD(String(snr)); + } + + void action(std::shared_ptr msg) override + { + //setup_display(boardConfig); secondsSinceDisplay = 0; //display_is_on = true; + //show_display(Config->callsign, timeClient->getFormattedTime() + " LoRa", "RSSI: " + String(lora_aprs->packetRssi()) + ", SNR: " + String(lora_aprs->packetSnr()), elem->toString()); + logPrintD("[" + timeString() + "] "); + logPrintD("Received packet '"); + logPrintD(msg->toString()); + logPrintD("'"); + } +}; + +#endif diff --git a/src/project_configuration.cpp b/src/project_configuration.cpp index dd8be2f..5b1175f 100644 --- a/src/project_configuration.cpp +++ b/src/project_configuration.cpp @@ -3,13 +3,12 @@ #include "project_configuration.h" #include "logger.h" -Configuration * ProjectConfigurationManagement::readProjectConfiguration(DynamicJsonDocument & data) +std::shared_ptr ProjectConfigurationManagement::readProjectConfiguration(DynamicJsonDocument & data) { - Configuration * conf = new Configuration; + std::shared_ptr conf = std::shared_ptr(new Configuration); if(data.containsKey("callsign")) conf->callsign = data["callsign"].as(); - conf->wifi.active = data["wifi"]["active"] | false; JsonArray aps = data["wifi"]["AP"].as(); for(JsonVariant v : aps) { @@ -22,7 +21,6 @@ Configuration * ProjectConfigurationManagement::readProjectConfiguration(Dynamic conf->beacon.message = data["beacon"]["message"].as(); conf->beacon.positionLatitude = data["beacon"]["position"]["latitude"] | 0.0; conf->beacon.positionLongitude = data["beacon"]["position"]["longitude"] | 0.0; - conf->aprs_is.active = data["aprs_is"]["active"] | false; if(data.containsKey("aprs_is") && data["aprs_is"].containsKey("password")) conf->aprs_is.password = data["aprs_is"]["password"].as(); if(data.containsKey("aprs_is") && data["aprs_is"].containsKey("server")) @@ -66,10 +64,9 @@ Configuration * ProjectConfigurationManagement::readProjectConfiguration(Dynamic return conf; } -void ProjectConfigurationManagement::writeProjectConfiguration(Configuration * conf, DynamicJsonDocument & data) +void ProjectConfigurationManagement::writeProjectConfiguration(std::shared_ptr conf, DynamicJsonDocument & data) { data["callsign"] = conf->callsign; - data["wifi"]["active"] = conf->wifi.active; JsonArray aps = data["wifi"].createNestedArray("AP"); for(Configuration::Wifi::AP ap : conf->wifi.APs) { @@ -80,7 +77,6 @@ void ProjectConfigurationManagement::writeProjectConfiguration(Configuration * c data["beacon"]["message"] = conf->beacon.message; data["beacon"]["position"]["latitude"] = conf->beacon.positionLatitude; data["beacon"]["position"]["longitude"] = conf->beacon.positionLongitude; - data["aprs_is"]["active"] = conf->aprs_is.active; data["aprs_is"]["password"] = conf->aprs_is.password; data["aprs_is"]["server"] = conf->aprs_is.server; data["aprs_is"]["port"] = conf->aprs_is.port; @@ -107,3 +103,23 @@ void ProjectConfigurationManagement::writeProjectConfiguration(Configuration * c data["board"] = conf->board; } + +std::shared_ptr load_config(std::shared_ptr boardConfig) +{ + ProjectConfigurationManagement confmg; + std::shared_ptr config = confmg.readConfiguration(); + if(config->callsign == "NOCALL-10") + { + logPrintlnE("You have to change your settings in 'data/is-cfg.json' and upload it via \"Upload File System image\"!"); + //show_display("ERROR", "You have to change your settings in 'data/is-cfg.json' and upload it via \"Upload File System image\"!"); + while (true) + {} + } + + /*if(KEY_BUILTIN != 0 && Config->display.overwritePin == 0) + { + Config->display.overwritePin = KEY_BUILTIN; + }*/ + logPrintlnI("Configuration loaded!"); + return config; +} diff --git a/src/project_configuration.h b/src/project_configuration.h index b9c4d5d..42a91d0 100644 --- a/src/project_configuration.h +++ b/src/project_configuration.h @@ -2,6 +2,7 @@ #define PROJECT_CONFIGURATION_H_ #include "configuration.h" +#include "BoardFinder.h" class Configuration { @@ -16,9 +17,8 @@ public: String password; }; - Wifi() : active(false) {} + Wifi() {} - bool active; std::list APs; }; @@ -35,9 +35,8 @@ public: class APRS_IS { public: - APRS_IS() : active(false), server("euro.aprs2.net"), port(14580), beacon(true), beaconTimeout(15) {} + APRS_IS() : server("euro.aprs2.net"), port(14580), beacon(true), beaconTimeout(15) {} - bool active; String password; String server; int port; @@ -104,8 +103,10 @@ public: virtual ~ProjectConfigurationManagement() {} private: - virtual Configuration * readProjectConfiguration(DynamicJsonDocument & data) override; - virtual void writeProjectConfiguration(Configuration * conf, DynamicJsonDocument & data) override; + virtual std::shared_ptr readProjectConfiguration(DynamicJsonDocument & data) override; + virtual void writeProjectConfiguration(std::shared_ptr conf, DynamicJsonDocument & data) override; }; +std::shared_ptr load_config(std::shared_ptr boardConfig); + #endif From 47a44551451dc77a6915fc28bf763b775bc12719 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sat, 2 Jan 2021 23:22:52 +0100 Subject: [PATCH 20/60] update --- data/is-cfg.json | 9 ++++----- lib/APRS-IS/APRS-IS.cpp | 24 +++++++++++++++++++++--- src/LoRa_APRS_iGate.cpp | 13 +++++-------- src/connection.cpp | 20 ++++++++++++++++++++ src/connection.h | 1 + src/project_configuration.cpp | 12 +++++------- src/project_configuration.h | 9 ++++----- 7 files changed, 60 insertions(+), 28 deletions(-) diff --git a/data/is-cfg.json b/data/is-cfg.json index a9fc508..5a2ee13 100644 --- a/data/is-cfg.json +++ b/data/is-cfg.json @@ -13,15 +13,14 @@ { "latitude":0.000000, "longitude":0.000000 - } + }, + "timeout":15 }, "aprs_is": { - "password":"", + "passcode":"", "server":"euro.aprs2.net", - "port":14580, - "beacon":true, - "beacon_timeout":15 + "port":14580 }, "lora": { diff --git a/lib/APRS-IS/APRS-IS.cpp b/lib/APRS-IS/APRS-IS.cpp index 5b50d94..2dce9cc 100644 --- a/lib/APRS-IS/APRS-IS.cpp +++ b/lib/APRS-IS/APRS-IS.cpp @@ -24,8 +24,21 @@ bool APRS_IS::connect_(const String & server, const int port, const String & log return false; } sendMessage(login_line); - // TODO: implement check if auth was successfull! - //while(!available()); + while(true) + { + String line = _client.readStringUntil('\n'); + if(line.indexOf("logresp") != -1) + { + if(line.indexOf("unverified") == -1) + { + return true; + } + else + { + return false; + } + } + } return true; } @@ -81,7 +94,12 @@ std::shared_ptr APRS_IS::getAPRSMessage() { line = _client.readStringUntil('\n'); } - if(line.length() == 0 || line.startsWith("#")) + if(line.startsWith("#")) + { + //logPrintlnD(line); + return 0; + } + if(line.length() == 0) { return 0; } diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index 93f20a6..8c7ae9c 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -107,7 +107,7 @@ void setup() OTA = setup_ota(userConfig); ntpClient = setup_ntp(userConfig); ftpServer = setup_ftp(userConfig); - aprs_is = std::shared_ptr(new APRS_IS(userConfig->callsign, userConfig->aprs_is.password , "ESP32-APRS-IS", "0.1")); + aprs_is = setup_aprs_is(userConfig); if(userConfig->display.overwritePin != 0) { @@ -126,7 +126,6 @@ void setup() // cppcheck-suppress unusedFunction void loop() { - static bool beacon_aprs_is = true; if(userConfig->ftp.active) { ftpServer->handle(); @@ -160,10 +159,7 @@ void loop() if(!aprs_is->connected()) { - logPrintI("connecting to APRS-IS server: "); - logPrintI(userConfig->aprs_is.server); - logPrintI(" on port: "); - logPrintlnI(String(userConfig->aprs_is.port)); + logPrintI("connecting to APRS-IS server..."); show_display("INFO", "Connecting to APRS-IS server"); if(!aprs_is->connect(userConfig->aprs_is.server, userConfig->aprs_is.port)) { @@ -179,14 +175,15 @@ void loop() aprs_is->getAPRSMessage(); lora_aprs->checkMessage(); - if(false) //beacon_aprs_is + static time_t beacon_next_time = 0; + if(beacon_next_time < now()) { - beacon_aprs_is = false; show_display(userConfig->callsign, "Beacon to APRS-IS Server..."); logPrintD("[" + ntpClient->getFormattedTime() + "] "); logPrintlnD(BeaconMsg->encode()); aprs_is->sendMessage(BeaconMsg); show_display(userConfig->callsign, "Standby..."); + beacon_next_time = now() + userConfig->beacon.timeout * 60UL; } } diff --git a/src/connection.cpp b/src/connection.cpp index f294ee6..189d2c1 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "connection.h" @@ -181,3 +182,22 @@ std::shared_ptr setup_ftp(std::shared_ptr config) } return ftpServer; } + +std::shared_ptr setup_aprs_is(std::shared_ptr config) +{ + std::shared_ptr aprs_is = std::shared_ptr(new APRS_IS(config->callsign, config->aprs_is.passcode , "ESP32-APRS-IS", "0.1")); + logPrintI("connecting to APRS-IS server: "); + logPrintI(config->aprs_is.server); + logPrintI(" on port: "); + logPrintlnI(String(config->aprs_is.port)); + //show_display("INFO", "Connecting to APRS-IS server"); + while(!aprs_is->connect(config->aprs_is.server, config->aprs_is.port)) + { + logPrintlnE("Connection failed."); + logPrintlnI("Waiting 1 seconds before retrying..."); + //show_display("ERROR", "Server connection failed!", "waiting 5 sec"); + delay(1000); + } + logPrintlnI("Connected to APRS-IS server!"); + return aprs_is; +} diff --git a/src/connection.h b/src/connection.h index 2ef9880..fe24aeb 100644 --- a/src/connection.h +++ b/src/connection.h @@ -15,5 +15,6 @@ std::shared_ptr setup_wifi(std::shared_ptr config); std::shared_ptr setup_ota(std::shared_ptr config); std::shared_ptr setup_ntp(std::shared_ptr config); std::shared_ptr setup_ftp(std::shared_ptr config); +std::shared_ptr setup_aprs_is(std::shared_ptr config); #endif diff --git a/src/project_configuration.cpp b/src/project_configuration.cpp index 5b1175f..ffb98d8 100644 --- a/src/project_configuration.cpp +++ b/src/project_configuration.cpp @@ -21,13 +21,12 @@ std::shared_ptr ProjectConfigurationManagement::readProjectConfig conf->beacon.message = data["beacon"]["message"].as(); conf->beacon.positionLatitude = data["beacon"]["position"]["latitude"] | 0.0; conf->beacon.positionLongitude = data["beacon"]["position"]["longitude"] | 0.0; - if(data.containsKey("aprs_is") && data["aprs_is"].containsKey("password")) - conf->aprs_is.password = data["aprs_is"]["password"].as(); + conf->beacon.timeout = data["beacon"]["timeout"] | 15; + if(data.containsKey("aprs_is") && data["aprs_is"].containsKey("passcode")) + conf->aprs_is.passcode = data["aprs_is"]["passcode"].as(); if(data.containsKey("aprs_is") && data["aprs_is"].containsKey("server")) conf->aprs_is.server = data["aprs_is"]["server"].as(); conf->aprs_is.port = data["aprs_is"]["port"] | 14580; - conf->aprs_is.beacon = data["aprs_is"]["beacon"] | true; - conf->aprs_is.beaconTimeout = data["aprs_is"]["beacon_timeout"] | 15; conf->lora.frequencyRx = data["lora"]["frequency_rx"] | 433775000; conf->lora.frequencyTx = data["lora"]["frequency_tx"] | 433775000; @@ -77,11 +76,10 @@ void ProjectConfigurationManagement::writeProjectConfiguration(std::shared_ptrbeacon.message; data["beacon"]["position"]["latitude"] = conf->beacon.positionLatitude; data["beacon"]["position"]["longitude"] = conf->beacon.positionLongitude; - data["aprs_is"]["password"] = conf->aprs_is.password; + data["beacon"]["timeout"] = conf->beacon.timeout; + data["aprs_is"]["passcode"] = conf->aprs_is.passcode; data["aprs_is"]["server"] = conf->aprs_is.server; data["aprs_is"]["port"] = conf->aprs_is.port; - data["aprs_is"]["beacon"] = conf->aprs_is.beacon; - data["aprs_is"]["beacon_timeout"] = conf->aprs_is.beaconTimeout; data["lora"]["frequency_rx"] = conf->lora.frequencyRx; data["lora"]["frequency_tx"] = conf->lora.frequencyTx; data["lora"]["power"] = conf->lora.power; diff --git a/src/project_configuration.h b/src/project_configuration.h index 42a91d0..adb47d7 100644 --- a/src/project_configuration.h +++ b/src/project_configuration.h @@ -25,23 +25,22 @@ public: class Beacon { public: - Beacon() : message("LoRa iGATE & Digi, Info: github.com/peterus/LoRa_APRS_iGate"), positionLatitude(0.0), positionLongitude(0.0) {} + Beacon() : message("LoRa iGATE & Digi, Info: github.com/peterus/LoRa_APRS_iGate"), positionLatitude(0.0), positionLongitude(0.0), timeout(15) {} String message; double positionLatitude; double positionLongitude; + int timeout; }; class APRS_IS { public: - APRS_IS() : server("euro.aprs2.net"), port(14580), beacon(true), beaconTimeout(15) {} + APRS_IS() : server("euro.aprs2.net"), port(14580) {} - String password; + String passcode; String server; int port; - bool beacon; - int beaconTimeout; }; class LoRa From 32a201b9803b6a26f78aa6192d4c3a400db25b04 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sun, 3 Jan 2021 00:15:08 +0100 Subject: [PATCH 21/60] cppcheck fixes --- .github/workflows/build_check.yml | 2 +- lib/BoardFinder/BoardFinder.cpp | 4 ++-- lib/BoardFinder/BoardFinder.h | 4 ++-- lib/NTPClient/NTPClient.h | 6 +++--- src/display.cpp | 20 ++++++++++++-------- src/display.h | 8 ++++---- 6 files changed, 24 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build_check.yml b/.github/workflows/build_check.yml index b9fec7c..c22d292 100644 --- a/.github/workflows/build_check.yml +++ b/.github/workflows/build_check.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/checkout@v2 with: submodules: 'recursive' - - run: platformio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high --skip-packages --flags "--suppress=*:*.pio\* --inline-suppr lib/common/src" -v + - run: platformio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high --skip-packages --flags "--suppress=*:*.pio\* --inline-suppr" -v PlatformIO-Build: runs-on: ubuntu-latest diff --git a/lib/BoardFinder/BoardFinder.cpp b/lib/BoardFinder/BoardFinder.cpp index 39e0ca0..8b91cb5 100644 --- a/lib/BoardFinder/BoardFinder.cpp +++ b/lib/BoardFinder/BoardFinder.cpp @@ -15,9 +15,9 @@ BoardConfig::BoardConfig( { } -BoardFinder::BoardFinder(std::list> boardConfigs) +BoardFinder::BoardFinder(std::list> & boardConfigs) + : _boardConfigs(boardConfigs) { - _boardConfigs = boardConfigs; } std::shared_ptr BoardFinder::searchBoardConfig() diff --git a/lib/BoardFinder/BoardFinder.h b/lib/BoardFinder/BoardFinder.h index 45b9243..4dbe435 100644 --- a/lib/BoardFinder/BoardFinder.h +++ b/lib/BoardFinder/BoardFinder.h @@ -23,7 +23,7 @@ enum BoardType class BoardConfig { public: - BoardConfig( + explicit BoardConfig( String name, BoardType type, uint8_t oledsda, uint8_t oledscl, uint8_t oledaddr, uint8_t oledreset, uint8_t lorasck, uint8_t loramiso, uint8_t loramosi, uint8_t loracs, uint8_t lorareset, uint8_t lorairq, @@ -51,7 +51,7 @@ public: class BoardFinder { public: - BoardFinder(std::list> boardConfigs); + explicit BoardFinder(std::list> & boardConfigs); std::shared_ptr searchBoardConfig(); diff --git a/lib/NTPClient/NTPClient.h b/lib/NTPClient/NTPClient.h index 1407c68..b528023 100644 --- a/lib/NTPClient/NTPClient.h +++ b/lib/NTPClient/NTPClient.h @@ -28,11 +28,11 @@ class NTPClient { public: NTPClient(); - NTPClient(long timeOffset); - NTPClient(const char* poolServerName); + explicit NTPClient(long timeOffset); + explicit NTPClient(const char* poolServerName); NTPClient(const char* poolServerName, long timeOffset); NTPClient(const char* poolServerName, long timeOffset, unsigned long updateInterval); - NTPClient(IPAddress poolServerIP); + explicit NTPClient(IPAddress poolServerIP); NTPClient(IPAddress poolServerIP, long timeOffset); NTPClient(IPAddress poolServerIP, long timeOffset, unsigned long updateInterval); diff --git a/src/display.cpp b/src/display.cpp index ba54c22..59c266f 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -10,6 +10,7 @@ Adafruit_SSD1306 * display = 0; TwoWire * wire = 0; +// cppcheck-suppress unusedFunction void setup_display(std::shared_ptr boardConfig) { if(display == 0) @@ -35,12 +36,12 @@ void setup_display(std::shared_ptr boardConfig) logPrintlnI("Display init done!"); } -void turn_off_display() +/*void turn_off_display() { display->ssd1306_command(SSD1306_DISPLAYOFF); -} +}*/ -void show_display(String header, int wait) +/*void show_display(String header, int wait) { display->clearDisplay(); display->setTextColor(WHITE); @@ -49,8 +50,9 @@ void show_display(String header, int wait) display->println(header); display->display(); delay(wait); -} +}*/ +// cppcheck-suppress unusedFunction void show_display(String header, String line1, int wait) { display->clearDisplay(); @@ -65,6 +67,7 @@ void show_display(String header, String line1, int wait) delay(wait); } +// cppcheck-suppress unusedFunction void show_display(String header, String line1, String line2, int wait) { display->clearDisplay(); @@ -81,6 +84,7 @@ void show_display(String header, String line1, String line2, int wait) delay(wait); } +// cppcheck-suppress unusedFunction void show_display(String header, String line1, String line2, String line3, int wait) { display->clearDisplay(); @@ -99,7 +103,7 @@ void show_display(String header, String line1, String line2, String line3, int w delay(wait); } -void show_display(String header, String line1, String line2, String line3, String line4, int wait) +/*void show_display(String header, String line1, String line2, String line3, String line4, int wait) { display->clearDisplay(); display->setTextColor(WHITE); @@ -117,9 +121,9 @@ void show_display(String header, String line1, String line2, String line3, Strin display->println(line4); display->display(); delay(wait); -} +}*/ -void show_display(String header, String line1, String line2, String line3, String line4, String line5, int wait) +/*void show_display(String header, String line1, String line2, String line3, String line4, String line5, int wait) { display->clearDisplay(); display->setTextColor(WHITE); @@ -139,4 +143,4 @@ void show_display(String header, String line1, String line2, String line3, Strin display->println(line5); display->display(); delay(wait); -} +}*/ diff --git a/src/display.h b/src/display.h index f89c431..7ebfd92 100644 --- a/src/display.h +++ b/src/display.h @@ -3,14 +3,14 @@ #define DISPLAY_H_ void setup_display(std::shared_ptr boardConfig); -void turn_off_display(); +//void turn_off_display(); -void show_display(String header, int wait = 0); +//void show_display(String header, int wait = 0); void show_display(String header, String line1, int wait = 0); void show_display(String header, String line1, String line2, int wait = 0); void show_display(String header, String line1, String line2, String line3, int wait = 0); -void show_display(String header, String line1, String line2, String line3, String line4, int wait = 0); -void show_display(String header, String line1, String line2, String line3, String line4, String line5, int wait = 0); +//void show_display(String header, String line1, String line2, String line3, String line4, int wait = 0); +//void show_display(String header, String line1, String line2, String line3, String line4, String line5, int wait = 0); #include #include "SignalSlot.h" From ec43e615357c10904551220d10d1af22803d48fe Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sun, 3 Jan 2021 22:43:35 +0100 Subject: [PATCH 22/60] add task manager, still missing: message queue for tasks --- lib/APRS-IS/APRS-IS.cpp | 3 + lib/ConfigurationManagement/configuration.h | 1 + lib/TaskManager/TaskManager.cpp | 53 +++++ lib/TaskManager/TaskManager.h | 41 ++++ src/LoRa_APRS_iGate.cpp | 147 +++----------- src/TaskAprsIs.cpp | 68 +++++++ src/TaskAprsIs.h | 25 +++ src/TaskEth.cpp | 86 +++++++++ src/TaskEth.h | 18 ++ src/TaskFTP.cpp | 52 +++++ src/TaskFTP.h | 20 ++ src/TaskLora.cpp | 45 +++++ src/TaskLora.h | 22 +++ src/TaskNTP.cpp | 41 ++++ src/TaskNTP.h | 20 ++ src/TaskOTA.cpp | 60 ++++++ src/TaskOTA.h | 20 ++ src/TaskWifi.cpp | 51 +++++ src/TaskWifi.h | 20 ++ src/connection.cpp | 203 -------------------- src/connection.h | 20 -- 21 files changed, 673 insertions(+), 343 deletions(-) create mode 100644 lib/TaskManager/TaskManager.cpp create mode 100644 lib/TaskManager/TaskManager.h create mode 100644 src/TaskAprsIs.cpp create mode 100644 src/TaskAprsIs.h create mode 100644 src/TaskEth.cpp create mode 100644 src/TaskEth.h create mode 100644 src/TaskFTP.cpp create mode 100644 src/TaskFTP.h create mode 100644 src/TaskLora.cpp create mode 100644 src/TaskLora.h create mode 100644 src/TaskNTP.cpp create mode 100644 src/TaskNTP.h create mode 100644 src/TaskOTA.cpp create mode 100644 src/TaskOTA.h create mode 100644 src/TaskWifi.cpp create mode 100644 src/TaskWifi.h delete mode 100644 src/connection.cpp delete mode 100644 src/connection.h diff --git a/lib/APRS-IS/APRS-IS.cpp b/lib/APRS-IS/APRS-IS.cpp index 2dce9cc..17c95cd 100644 --- a/lib/APRS-IS/APRS-IS.cpp +++ b/lib/APRS-IS/APRS-IS.cpp @@ -1,3 +1,4 @@ +#include #include "APRS-IS.h" APRS_IS::APRS_IS(const String & user, const String & passcode, const String & tool_name, const String & version) @@ -21,6 +22,7 @@ bool APRS_IS::connect_(const String & server, const int port, const String & log { if(!_client.connect(server.c_str(), port)) { + logPrintlnE("Something went wrong on connecting! Is the server reachable?"); return false; } sendMessage(login_line); @@ -35,6 +37,7 @@ bool APRS_IS::connect_(const String & server, const int port, const String & log } else { + logPrintlnE("User can not be verified with passcode!"); return false; } } diff --git a/lib/ConfigurationManagement/configuration.h b/lib/ConfigurationManagement/configuration.h index 0e22b10..35719a7 100644 --- a/lib/ConfigurationManagement/configuration.h +++ b/lib/ConfigurationManagement/configuration.h @@ -2,6 +2,7 @@ #define CONFIGURATION_H_ #include +#include #include #include diff --git a/lib/TaskManager/TaskManager.cpp b/lib/TaskManager/TaskManager.cpp new file mode 100644 index 0000000..2043208 --- /dev/null +++ b/lib/TaskManager/TaskManager.cpp @@ -0,0 +1,53 @@ +#include +#include "TaskManager.h" + +TaskManager::TaskManager() +{ +} + +void TaskManager::addTask(std::shared_ptr task) +{ + _tasks.push_back(task); +} + +std::shared_ptr TaskManager::getTask(String & name) +{ + for(std::shared_ptr & elem : _tasks) + { + if(elem->getName() == name) + { + return elem; + } + } + return 0; +} + +bool TaskManager::setup(std::shared_ptr config) +{ + logPrintlnV("will setup all tasks..."); + for(std::shared_ptr & elem : _tasks) + { + logPrintW("call setup from "); + logPrintlnW(elem->getName()); + if(!elem->setup(config)) + { + return false; + } + } + return true; +} + +bool TaskManager::loop(std::shared_ptr config) +{ + //logPrintlnD("will loop all tasks..."); + for(std::shared_ptr & elem : _tasks) + { + //logPrintD("call loop from "); + //logPrintlnD(elem->getName()); + if(!elem->loop(config)) + { + return false; + } + } + return true; +} \ No newline at end of file diff --git a/lib/TaskManager/TaskManager.h b/lib/TaskManager/TaskManager.h new file mode 100644 index 0000000..bbead2b --- /dev/null +++ b/lib/TaskManager/TaskManager.h @@ -0,0 +1,41 @@ +#ifndef TASK_MANAGER_H_ +#define TASK_MANAGER_H_ + +#include +#include +#include +#include + +class Task +{ +public: + Task(String & name) : _name(name) {} + Task(const char * name) : _name(name) {} + virtual ~Task() {} + + String getName() const { return _name; } + + virtual bool setup(std::shared_ptr config) = 0; + virtual bool loop(std::shared_ptr config) = 0; + +private: + String _name; +}; + +class TaskManager +{ +public: + TaskManager(); + + void addTask(std::shared_ptr task); + std::shared_ptr getTask(String & name); + + bool setup(std::shared_ptr config); + bool loop(std::shared_ptr config); + +private: + std::list> _tasks; + +}; + +#endif diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index 8c7ae9c..2f57d00 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -2,36 +2,30 @@ #include #include - #include -#include "SignalSlot.h" + +#include + #include "BoardFinder.h" -#include "LoRa_APRS.h" #include "display.h" #include "power_management.h" #include "project_configuration.h" -#include "connection.h" -HardwareSerial Serial(0); - -std::shared_ptr OTA; -std::shared_ptr powerManagement; -std::shared_ptr WiFiMulti; -std::shared_ptr ntpClient; -std::shared_ptr ftpServer; -std::shared_ptr userConfig; -std::shared_ptr boardConfig; -std::shared_ptr aprs_is; -std::shared_ptr lora_aprs; -std::shared_ptr BeaconMsg; +#include "TaskAprsIs.h" +#include "TaskEth.h" +#include "TaskFTP.h" +#include "TaskLora.h" +#include "TaskNTP.h" +#include "TaskOTA.h" +#include "TaskWifi.h" String create_lat_aprs(double lat); String create_long_aprs(double lng); -std::shared_ptr setup_lora(); - -PrintMessageToConsole printMessageConsole; -bool ethEnabled = false; +std::shared_ptr userConfig; +std::shared_ptr boardConfig; +TaskManager taskManager; +HardwareSerial Serial(0); // cppcheck-suppress unusedFunction void setup() @@ -97,17 +91,21 @@ void setup() show_display("OE5BPA", "LoRa APRS iGate", "by Peter Buchegger", "20.49.0-dev", 3000); load_config(boardConfig); - lora_aprs = setup_lora(); + + std::shared_ptr lora_task = std::shared_ptr(new LoraTask()); + lora_task->setup(userConfig, boardConfig); + taskManager.addTask(lora_task); if(boardConfig->Type == eETH_BOARD) { - setup_eth(); - ethEnabled = true; + taskManager.addTask(std::shared_ptr(new EthTask())); } - WiFiMulti = setup_wifi(userConfig); - OTA = setup_ota(userConfig); - ntpClient = setup_ntp(userConfig); - ftpServer = setup_ftp(userConfig); - aprs_is = setup_aprs_is(userConfig); + taskManager.addTask(std::shared_ptr(new WifiTask())); + taskManager.addTask(std::shared_ptr(new OTATask())); + taskManager.addTask(std::shared_ptr(new NTPTask())); + taskManager.addTask(std::shared_ptr(new FTPTask())); + taskManager.addTask(std::shared_ptr(new AprsIsTask())); + + taskManager.setup(userConfig); if(userConfig->display.overwritePin != 0) { @@ -115,10 +113,6 @@ void setup() pinMode(userConfig->display.overwritePin, INPUT_PULLUP); } - logPrintlnD("connect objects..."); - lora_aprs->connectSlot(&printMessageConsole); - lora_aprs->connectSlot(aprs_is.get()); - delay(500); logPrintlnI("setup done..."); } @@ -126,94 +120,7 @@ void setup() // cppcheck-suppress unusedFunction void loop() { - if(userConfig->ftp.active) - { - ftpServer->handle(); - static bool configWasOpen = false; - if(configWasOpen && ftpServer->countConnections() == 0) - { - logPrintlnW("Maybe the config has been changed via FTP, lets restart now to get the new config..."); - Serial.println(); - ESP.restart(); - } - if(ftpServer->countConnections() > 0) - { - configWasOpen = true; - } - } - - const uint8_t wifi_status = WiFiMulti->run(); - if(!ethEnabled && wifi_status != WL_CONNECTED) - { - logPrintlnE("WiFi not connected!"); - show_display("ERROR", "WiFi not connected!"); - delay(1000); - return; - } - - OTA->handle(); - if(ntpClient->update()) - { - setTime(ntpClient->getEpochTime()); - } - - if(!aprs_is->connected()) - { - logPrintI("connecting to APRS-IS server..."); - show_display("INFO", "Connecting to APRS-IS server"); - if(!aprs_is->connect(userConfig->aprs_is.server, userConfig->aprs_is.port)) - { - logPrintlnE("Connection failed."); - logPrintlnI("Waiting 5 seconds before retrying..."); - show_display("ERROR", "Server connection failed!", "waiting 5 sec"); - delay(5000); - return; - } - logPrintlnI("Connected to APRS-IS server!"); - } - - aprs_is->getAPRSMessage(); - lora_aprs->checkMessage(); - - static time_t beacon_next_time = 0; - if(beacon_next_time < now()) - { - show_display(userConfig->callsign, "Beacon to APRS-IS Server..."); - logPrintD("[" + ntpClient->getFormattedTime() + "] "); - logPrintlnD(BeaconMsg->encode()); - aprs_is->sendMessage(BeaconMsg); - show_display(userConfig->callsign, "Standby..."); - beacon_next_time = now() + userConfig->beacon.timeout * 60UL; - } -} - -std::shared_ptr setup_lora() -{ - std::shared_ptr lora_aprs = std::shared_ptr(new LoRa_APRS(boardConfig)); - if(!lora_aprs->begin(lora_aprs->getRxFrequency())) - { - logPrintlnE("Starting LoRa failed!"); - show_display("ERROR", "Starting LoRa failed!"); - while(true); - } - lora_aprs->setRxFrequency(userConfig->lora.frequencyRx); - lora_aprs->setTxFrequency(userConfig->lora.frequencyTx); - lora_aprs->setTxPower(userConfig->lora.power); - lora_aprs->setSpreadingFactor(userConfig->lora.spreadingFactor); - lora_aprs->setSignalBandwidth(userConfig->lora.signalBandwidth); - lora_aprs->setCodingRate4(userConfig->lora.codingRate4); - lora_aprs->enableCrc(); - logPrintlnI("LoRa init done!"); - show_display("INFO", "LoRa init done!", 2000); - - BeaconMsg = std::shared_ptr(new APRSMessage()); - BeaconMsg->setSource(userConfig->callsign); - BeaconMsg->setDestination("APLG0"); - String lat = create_lat_aprs(userConfig->beacon.positionLatitude); - String lng = create_long_aprs(userConfig->beacon.positionLongitude); - BeaconMsg->getAPRSBody()->setData(String("=") + lat + "I" + lng + "&" + userConfig->beacon.message); - - return lora_aprs; + taskManager.loop(userConfig); } String create_lat_aprs(double lat) diff --git a/src/TaskAprsIs.cpp b/src/TaskAprsIs.cpp new file mode 100644 index 0000000..f962c78 --- /dev/null +++ b/src/TaskAprsIs.cpp @@ -0,0 +1,68 @@ +#include +#include +#include "project_configuration.h" +#include "TaskAprsIs.h" + +String create_lat_aprs(double lat); +String create_long_aprs(double lng); + +AprsIsTask::AprsIsTask() + : Task("AprsIsTask") +{ +} + +AprsIsTask::~AprsIsTask() +{ +} + +bool AprsIsTask::setup(std::shared_ptr config) +{ + _aprs_is = std::shared_ptr(new APRS_IS(config->callsign, config->aprs_is.passcode , "ESP32-APRS-IS", "0.1")); + connect(config); + + _beaconMsg = std::shared_ptr(new APRSMessage()); + _beaconMsg->setSource(config->callsign); + _beaconMsg->setDestination("APLG0"); + String lat = create_lat_aprs(config->beacon.positionLatitude); + String lng = create_long_aprs(config->beacon.positionLongitude); + _beaconMsg->getAPRSBody()->setData(String("=") + lat + "I" + lng + "&" + config->beacon.message); + + return true; +} + +bool AprsIsTask::loop(std::shared_ptr config) +{ + if(!_aprs_is->connected()) + { + connect(config); + } + _aprs_is->getAPRSMessage(); + + if(_beacon_next_time < now()) + { + //show_display(userConfig->callsign, "Beacon to APRS-IS Server..."); + logPrintD("[" + timeString() + "] "); + logPrintlnD(_beaconMsg->encode()); + _aprs_is->sendMessage(_beaconMsg); + //show_display(userConfig->callsign, "Standby..."); + _beacon_next_time = now() + config->beacon.timeout * 60UL; + } + return true; +} + +void AprsIsTask::connect(std::shared_ptr config) +{ + logPrintI("connecting to APRS-IS server: "); + logPrintI(config->aprs_is.server); + logPrintI(" on port: "); + logPrintlnI(String(config->aprs_is.port)); + //show_display("INFO", "Connecting to APRS-IS server"); + while(!_aprs_is->connect(config->aprs_is.server, config->aprs_is.port)) + { + logPrintlnE("Connection failed."); + logPrintlnI("Waiting 1 seconds before retrying..."); + //show_display("ERROR", "Server connection failed!", "waiting 5 sec"); + delay(1000); + } + logPrintlnI("Connected to APRS-IS server!"); +} diff --git a/src/TaskAprsIs.h b/src/TaskAprsIs.h new file mode 100644 index 0000000..cc9d413 --- /dev/null +++ b/src/TaskAprsIs.h @@ -0,0 +1,25 @@ +#ifndef TASK_APRS_IS_H_ +#define TASK_APRS_IS_H_ + +#include +#include +#include + +class AprsIsTask : public Task +{ +public: + AprsIsTask(); + virtual ~AprsIsTask(); + + virtual bool setup(std::shared_ptr config) override; + virtual bool loop(std::shared_ptr config) override; + +private: + std::shared_ptr _aprs_is; + std::shared_ptr _beaconMsg; + time_t _beacon_next_time; + + void connect(std::shared_ptr config); +}; + +#endif diff --git a/src/TaskEth.cpp b/src/TaskEth.cpp new file mode 100644 index 0000000..ad6d231 --- /dev/null +++ b/src/TaskEth.cpp @@ -0,0 +1,86 @@ +#include +#include +#include +#include "TaskEth.h" + +volatile bool eth_connected = false; + +static void WiFiEvent(WiFiEvent_t event) +{ + switch (event) { + case SYSTEM_EVENT_ETH_START: + logPrintlnI("ETH Started"); + ETH.setHostname("esp32-ethernet"); + break; + case SYSTEM_EVENT_ETH_CONNECTED: + logPrintlnI("ETH Connected"); + break; + case SYSTEM_EVENT_ETH_GOT_IP: + logPrintI("ETH MAC: "); + logPrintI(ETH.macAddress()); + logPrintI(", IPv4: "); + logPrintI(ETH.localIP().toString()); + if (ETH.fullDuplex()) { + logPrintI(", FULL_DUPLEX"); + } + logPrintI(", "); + logPrintI(String(ETH.linkSpeed())); + logPrintlnI("Mbps"); + eth_connected = true; + break; + case SYSTEM_EVENT_ETH_DISCONNECTED: + logPrintlnW("ETH Disconnected"); + eth_connected = false; + break; + case SYSTEM_EVENT_ETH_STOP: + logPrintlnW("ETH Stopped"); + eth_connected = false; + break; + default: + break; + } +} + +EthTask::EthTask() + : Task("EthTask") +{ +} + +EthTask::~EthTask() +{ +} + +bool EthTask::setup(std::shared_ptr config) +{ + WiFi.onEvent(WiFiEvent); + + #define ETH_POWER_PIN -1 + #define ETH_TYPE ETH_PHY_LAN8720 + #define ETH_ADDR 0 + #define ETH_MDC_PIN 23 + #define ETH_MDIO_PIN 18 + #define ETH_NRST 5 + #define ETH_CLK ETH_CLOCK_GPIO17_OUT // TTGO PoE V1.0 + //#define ETH_CLK ETH_CLOCK_GPIO0_OUT // TTGO PoE V1.2 + + pinMode(ETH_NRST, OUTPUT); + digitalWrite(ETH_NRST, 0); + delay(200); + digitalWrite(ETH_NRST, 1); + delay(200); + digitalWrite(ETH_NRST, 0); + delay(200); + digitalWrite(ETH_NRST, 1); + + ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK); + while(!eth_connected) + { + sleep(1); + } + return true; +} + +bool EthTask::loop(std::shared_ptr config) +{ + return true; +} diff --git a/src/TaskEth.h b/src/TaskEth.h new file mode 100644 index 0000000..ca684aa --- /dev/null +++ b/src/TaskEth.h @@ -0,0 +1,18 @@ +#ifndef TASK_ETH_H_ +#define TASK_ETH_H_ + +#include + +class EthTask : public Task +{ +public: + EthTask(); + virtual ~EthTask(); + + virtual bool setup(std::shared_ptr config) override; + virtual bool loop(std::shared_ptr config) override; + +private: +}; + +#endif diff --git a/src/TaskFTP.cpp b/src/TaskFTP.cpp new file mode 100644 index 0000000..b28e29e --- /dev/null +++ b/src/TaskFTP.cpp @@ -0,0 +1,52 @@ +#include +#include +#include +#include "project_configuration.h" +#include "TaskFTP.h" + +FTPTask::FTPTask() + : Task("FTPTask") +{ +} + +FTPTask::~FTPTask() +{ +} + +bool FTPTask::setup(std::shared_ptr config) +{ + _ftpServer = std::shared_ptr(new FTPServer()); + if(config->ftp.active) + { + for(Configuration::Ftp::User user : config->ftp.users) + { + logPrintD("Adding user to FTP Server: "); + logPrintlnD(user.name); + _ftpServer->addUser(user.name, user.password); + } + _ftpServer->addFilesystem("SPIFFS", &SPIFFS); + _ftpServer->begin(); + logPrintlnI("FTP Server init done!"); + } + return true; +} + +bool FTPTask::loop(std::shared_ptr config) +{ + if(config->ftp.active) + { + _ftpServer->handle(); + static bool configWasOpen = false; + if(configWasOpen && _ftpServer->countConnections() == 0) + { + logPrintlnW("Maybe the config has been changed via FTP, lets restart now to get the new config..."); + logPrintlnW(""); + ESP.restart(); + } + if(_ftpServer->countConnections() > 0) + { + configWasOpen = true; + } + } + return true; +} diff --git a/src/TaskFTP.h b/src/TaskFTP.h new file mode 100644 index 0000000..5db9edc --- /dev/null +++ b/src/TaskFTP.h @@ -0,0 +1,20 @@ +#ifndef TASK_FTP_H_ +#define TASK_FTP_H_ + +#include +#include + +class FTPTask : public Task +{ +public: + FTPTask(); + virtual ~FTPTask(); + + virtual bool setup(std::shared_ptr config) override; + virtual bool loop(std::shared_ptr config) override; + +private: + std::shared_ptr _ftpServer; +}; + +#endif diff --git a/src/TaskLora.cpp b/src/TaskLora.cpp new file mode 100644 index 0000000..556c2ec --- /dev/null +++ b/src/TaskLora.cpp @@ -0,0 +1,45 @@ +#include +#include "project_configuration.h" +#include "TaskLora.h" + +LoraTask::LoraTask() + : Task("LoraTask") +{ +} + +LoraTask::~LoraTask() +{ +} + +bool LoraTask::setup(std::shared_ptr config) +{ + return true; +} + +bool LoraTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) +{ + _lora_aprs = std::shared_ptr(new LoRa_APRS(boardConfig)); + if(!_lora_aprs->begin(_lora_aprs->getRxFrequency())) + { + logPrintlnE("Starting LoRa failed!"); + //show_display("ERROR", "Starting LoRa failed!"); + while(true); + } + _lora_aprs->setRxFrequency(config->lora.frequencyRx); + _lora_aprs->setTxFrequency(config->lora.frequencyTx); + _lora_aprs->setTxPower(config->lora.power); + _lora_aprs->setSpreadingFactor(config->lora.spreadingFactor); + _lora_aprs->setSignalBandwidth(config->lora.signalBandwidth); + _lora_aprs->setCodingRate4(config->lora.codingRate4); + _lora_aprs->enableCrc(); + logPrintlnI("LoRa init done!"); + //show_display("INFO", "LoRa init done!", 2000); + + return true; +} + +bool LoraTask::loop(std::shared_ptr config) +{ + _lora_aprs->checkMessage(); + return true; +} diff --git a/src/TaskLora.h b/src/TaskLora.h new file mode 100644 index 0000000..b6410eb --- /dev/null +++ b/src/TaskLora.h @@ -0,0 +1,22 @@ +#ifndef TASK_LORA_H_ +#define TASK_LORA_H_ + +#include +#include +#include + +class LoraTask : public Task +{ +public: + LoraTask(); + virtual ~LoraTask(); + + virtual bool setup(std::shared_ptr config) override; + virtual bool loop(std::shared_ptr config) override; + bool setup(std::shared_ptr config, std::shared_ptr boardConfig); + +private: + std::shared_ptr _lora_aprs; +}; + +#endif diff --git a/src/TaskNTP.cpp b/src/TaskNTP.cpp new file mode 100644 index 0000000..294bceb --- /dev/null +++ b/src/TaskNTP.cpp @@ -0,0 +1,41 @@ +#include +#include +#include "project_configuration.h" +#include "TaskNTP.h" + +NTPTask::NTPTask() + : Task("NTPTask") +{ +} + +NTPTask::~NTPTask() +{ +} + +bool NTPTask::setup(std::shared_ptr config) +{ + _ntpClient = std::shared_ptr(new NTPClient(config->ntpServer.c_str())); + _ntpClient->begin(); + while(!_ntpClient->forceUpdate()) + { + logPrintlnW("NTP Client force update issue! Waiting 1 sek..."); + logPrintlnD(_ntpClient->getFormattedTime()); + //show_display("WARN", "NTP Client force update issue! Waiting 1 sek...", 1000); + sleep(1); + } + setTime(_ntpClient->getEpochTime()); + logPrintI("Current time: "); + logPrintlnI(_ntpClient->getFormattedTime()); + logPrintlnI("NTP Client init done!"); + //show_display("INFO", "NTP Client init done!", 2000); + return true; +} + +bool NTPTask::loop(std::shared_ptr config) +{ + if(_ntpClient->update()) + { + setTime(_ntpClient->getEpochTime()); + } + return true; +} diff --git a/src/TaskNTP.h b/src/TaskNTP.h new file mode 100644 index 0000000..e05a89f --- /dev/null +++ b/src/TaskNTP.h @@ -0,0 +1,20 @@ +#ifndef TASK_NTP_H_ +#define TASK_NTP_H_ + +#include +#include + +class NTPTask : public Task +{ +public: + NTPTask(); + virtual ~NTPTask(); + + virtual bool setup(std::shared_ptr config) override; + virtual bool loop(std::shared_ptr config) override; + +private: + std::shared_ptr _ntpClient; +}; + +#endif diff --git a/src/TaskOTA.cpp b/src/TaskOTA.cpp new file mode 100644 index 0000000..5d96a62 --- /dev/null +++ b/src/TaskOTA.cpp @@ -0,0 +1,60 @@ +#include +#include "project_configuration.h" +#include "TaskOTA.h" + +OTATask::OTATask() + : Task("OTATask") +{ +} + +OTATask::~OTATask() +{ +} + +bool OTATask::setup(std::shared_ptr config) +{ + _ota = std::shared_ptr(new ArduinoOTAClass()); + _ota->onStart([&]() + { + String type; + if (_ota->getCommand() == U_FLASH) + type = "sketch"; + else // U_SPIFFS + type = "filesystem"; + logPrintlnI("Start updating " + type); + //show_display("OTA UPDATE", "Start update", type); + }) + .onEnd([]() + { + logPrintlnI(""); + logPrintlnI("OTA End"); + }) + .onProgress([](unsigned int progress, unsigned int total) + { + logPrintI("Progress: "); + logPrintI(String(progress / (total / 100))); + logPrintlnI("%"); + //show_display("OTA UPDATE", "Progress: ", String(progress / (total / 100)) + "%"); + }) + .onError([](ota_error_t error) + { + logPrintE("Error["); + logPrintE(String(error)); + logPrintE("]: "); + if (error == OTA_AUTH_ERROR) logPrintlnE("Auth Failed"); + else if (error == OTA_BEGIN_ERROR) logPrintlnE("Begin Failed"); + else if (error == OTA_CONNECT_ERROR) logPrintlnE("Connect Failed"); + else if (error == OTA_RECEIVE_ERROR) logPrintlnE("Receive Failed"); + else if (error == OTA_END_ERROR) logPrintlnE("End Failed"); + }); + _ota->setHostname(config->callsign.c_str()); + _ota->begin(); + logPrintlnI("OTA init done!"); + return true; +} + +bool OTATask::loop(std::shared_ptr config) +{ + _ota->handle(); + return true; +} diff --git a/src/TaskOTA.h b/src/TaskOTA.h new file mode 100644 index 0000000..e36fb29 --- /dev/null +++ b/src/TaskOTA.h @@ -0,0 +1,20 @@ +#ifndef TASK_OTA_H_ +#define TASK_OTA_H_ + +#include +#include + +class OTATask : public Task +{ +public: + OTATask(); + virtual ~OTATask(); + + virtual bool setup(std::shared_ptr config) override; + virtual bool loop(std::shared_ptr config) override; + +private: + std::shared_ptr _ota; +}; + +#endif diff --git a/src/TaskWifi.cpp b/src/TaskWifi.cpp new file mode 100644 index 0000000..297248c --- /dev/null +++ b/src/TaskWifi.cpp @@ -0,0 +1,51 @@ +#include +#include +#include "project_configuration.h" +#include "TaskWifi.h" + +WifiTask::WifiTask() + : Task("WifiTask") +{ +} + +WifiTask::~WifiTask() +{ +} + +bool WifiTask::setup(std::shared_ptr config) +{ + //WiFi.onEvent(WiFiEvent); + //WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); + WiFi.setHostname(config->callsign.c_str()); + _wiFiMulti = std::shared_ptr(new WiFiMulti());; + for(Configuration::Wifi::AP ap : config->wifi.APs) + { + logPrintD("Looking for AP: "); + logPrintlnD(ap.SSID); + _wiFiMulti->addAP(ap.SSID.c_str(), ap.password.c_str()); + } + logPrintlnI("Waiting for WiFi"); + //show_display("INFO", "Waiting for WiFi"); + while(_wiFiMulti->run() != WL_CONNECTED) + { + //show_display("INFO", "Waiting for WiFi", "...."); + delay(500); + } + logPrintlnI("WiFi connected"); + logPrintD("IP address: "); + logPrintlnD(WiFi.localIP().toString()); + //show_display("INFO", "WiFi connected", "IP: ", WiFi.localIP().toString(), 2000); + return true; +} + +bool WifiTask::loop(std::shared_ptr config) +{ + const uint8_t wifi_status = _wiFiMulti->run(); + if(wifi_status != WL_CONNECTED) + { + logPrintlnE("WiFi not connected!"); + //show_display("ERROR", "WiFi not connected!"); + delay(1000); + } + return true; +} diff --git a/src/TaskWifi.h b/src/TaskWifi.h new file mode 100644 index 0000000..15cd050 --- /dev/null +++ b/src/TaskWifi.h @@ -0,0 +1,20 @@ +#ifndef TASK_WIFI_H_ +#define TASK_WIFI_H_ + +#include +#include + +class WifiTask : public Task +{ +public: + WifiTask(); + virtual ~WifiTask(); + + virtual bool setup(std::shared_ptr config) override; + virtual bool loop(std::shared_ptr config) override; + +private: + std::shared_ptr _wiFiMulti; +}; + +#endif diff --git a/src/connection.cpp b/src/connection.cpp deleted file mode 100644 index 189d2c1..0000000 --- a/src/connection.cpp +++ /dev/null @@ -1,203 +0,0 @@ - -#include -#include -#include -#include -#include -#include - -#include "connection.h" - -volatile bool eth_connected = false; - -static void WiFiEvent(WiFiEvent_t event) -{ - switch (event) { - case SYSTEM_EVENT_ETH_START: - logPrintlnI("ETH Started"); - ETH.setHostname("esp32-ethernet"); - break; - case SYSTEM_EVENT_ETH_CONNECTED: - logPrintlnI("ETH Connected"); - break; - case SYSTEM_EVENT_ETH_GOT_IP: - logPrintI("ETH MAC: "); - logPrintI(ETH.macAddress()); - logPrintI(", IPv4: "); - logPrintI(ETH.localIP().toString()); - if (ETH.fullDuplex()) { - logPrintI(", FULL_DUPLEX"); - } - logPrintI(", "); - logPrintI(String(ETH.linkSpeed())); - logPrintlnI("Mbps"); - eth_connected = true; - break; - case SYSTEM_EVENT_ETH_DISCONNECTED: - logPrintlnW("ETH Disconnected"); - eth_connected = false; - break; - case SYSTEM_EVENT_ETH_STOP: - logPrintlnW("ETH Stopped"); - eth_connected = false; - break; - default: - break; - } -} - -bool isEthConnected() -{ - return eth_connected; -} - -void setup_eth() -{ - WiFi.onEvent(WiFiEvent); - - #define ETH_POWER_PIN -1 - #define ETH_TYPE ETH_PHY_LAN8720 - #define ETH_ADDR 0 - #define ETH_MDC_PIN 23 - #define ETH_MDIO_PIN 18 - #define ETH_NRST 5 - #define ETH_CLK ETH_CLOCK_GPIO17_OUT // TTGO PoE V1.0 - //#define ETH_CLK ETH_CLOCK_GPIO0_OUT // TTGO PoE V1.2 - - pinMode(ETH_NRST, OUTPUT); - digitalWrite(ETH_NRST, 0); - delay(200); - digitalWrite(ETH_NRST, 1); - delay(200); - digitalWrite(ETH_NRST, 0); - delay(200); - digitalWrite(ETH_NRST, 1); - - ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK); - while(!eth_connected) - { - sleep(1); - } -} - -std::shared_ptr setup_wifi(std::shared_ptr config) -{ - WiFi.onEvent(WiFiEvent); - //WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); - WiFi.setHostname(config->callsign.c_str()); - std::shared_ptr wiFiMulti = std::shared_ptr(new WiFiMulti());; - for(Configuration::Wifi::AP ap : config->wifi.APs) - { - logPrintD("Looking for AP: "); - logPrintlnD(ap.SSID); - wiFiMulti->addAP(ap.SSID.c_str(), ap.password.c_str()); - } - logPrintlnI("Waiting for WiFi"); - //show_display("INFO", "Waiting for WiFi"); - while(wiFiMulti->run() != WL_CONNECTED) - { - //show_display("INFO", "Waiting for WiFi", "...."); - delay(500); - } - logPrintlnI("WiFi connected"); - logPrintD("IP address: "); - logPrintlnD(WiFi.localIP().toString()); - //show_display("INFO", "WiFi connected", "IP: ", WiFi.localIP().toString(), 2000); - return wiFiMulti; -} - -std::shared_ptr setup_ota(std::shared_ptr config) -{ - std::shared_ptr ota = std::shared_ptr(new ArduinoOTAClass()); - ota->onStart([&]() - { - String type; - if (ota->getCommand() == U_FLASH) - type = "sketch"; - else // U_SPIFFS - type = "filesystem"; - logPrintlnI("Start updating " + type); - //show_display("OTA UPDATE", "Start update", type); - }) - .onEnd([]() - { - logPrintlnI(""); - logPrintlnI("OTA End"); - }) - .onProgress([](unsigned int progress, unsigned int total) - { - logPrintI("Progress: "); - logPrintI(String(progress / (total / 100))); - logPrintlnI("%"); - //show_display("OTA UPDATE", "Progress: ", String(progress / (total / 100)) + "%"); - }) - .onError([](ota_error_t error) - { - logPrintE("Error["); - logPrintE(String(error)); - logPrintE("]: "); - if (error == OTA_AUTH_ERROR) logPrintlnE("Auth Failed"); - else if (error == OTA_BEGIN_ERROR) logPrintlnE("Begin Failed"); - else if (error == OTA_CONNECT_ERROR) logPrintlnE("Connect Failed"); - else if (error == OTA_RECEIVE_ERROR) logPrintlnE("Receive Failed"); - else if (error == OTA_END_ERROR) logPrintlnE("End Failed"); - }); - ota->setHostname(config->callsign.c_str()); - ota->begin(); - logPrintlnI("OTA init done!"); - return ota; -} - -std::shared_ptr setup_ntp(std::shared_ptr config) -{ - std::shared_ptr ntpClient = std::shared_ptr(new NTPClient(config->ntpServer.c_str())); - ntpClient->begin(); - while(!ntpClient->forceUpdate()) - { - logPrintlnW("NTP Client force update issue! Waiting 1 sek..."); - logPrintlnD(ntpClient->getFormattedTime()); - //show_display("WARN", "NTP Client force update issue! Waiting 1 sek...", 1000); - sleep(1); - } - setTime(ntpClient->getEpochTime()); - logPrintlnI("NTP Client init done!"); - //show_display("INFO", "NTP Client init done!", 2000); - return ntpClient; -} - -std::shared_ptr setup_ftp(std::shared_ptr config) -{ - std::shared_ptr ftpServer = std::shared_ptr(new FTPServer()); - if(config->ftp.active) - { - for(Configuration::Ftp::User user : config->ftp.users) - { - logPrintD("Adding user to FTP Server: "); - logPrintlnD(user.name); - ftpServer->addUser(user.name, user.password); - } - ftpServer->addFilesystem("SPIFFS", &SPIFFS); - ftpServer->begin(); - logPrintlnI("FTP Server init done!"); - } - return ftpServer; -} - -std::shared_ptr setup_aprs_is(std::shared_ptr config) -{ - std::shared_ptr aprs_is = std::shared_ptr(new APRS_IS(config->callsign, config->aprs_is.passcode , "ESP32-APRS-IS", "0.1")); - logPrintI("connecting to APRS-IS server: "); - logPrintI(config->aprs_is.server); - logPrintI(" on port: "); - logPrintlnI(String(config->aprs_is.port)); - //show_display("INFO", "Connecting to APRS-IS server"); - while(!aprs_is->connect(config->aprs_is.server, config->aprs_is.port)) - { - logPrintlnE("Connection failed."); - logPrintlnI("Waiting 1 seconds before retrying..."); - //show_display("ERROR", "Server connection failed!", "waiting 5 sec"); - delay(1000); - } - logPrintlnI("Connected to APRS-IS server!"); - return aprs_is; -} diff --git a/src/connection.h b/src/connection.h deleted file mode 100644 index fe24aeb..0000000 --- a/src/connection.h +++ /dev/null @@ -1,20 +0,0 @@ - -#ifndef CONNECTION_H_ -#define CONNECTION_H_ - -#include -#include -#include -#include -#include -#include "project_configuration.h" - -bool isEthConnected(); -void setup_eth(); -std::shared_ptr setup_wifi(std::shared_ptr config); -std::shared_ptr setup_ota(std::shared_ptr config); -std::shared_ptr setup_ntp(std::shared_ptr config); -std::shared_ptr setup_ftp(std::shared_ptr config); -std::shared_ptr setup_aprs_is(std::shared_ptr config); - -#endif From d29982a0c92ac535b5b2519e22606cbf24aeefa4 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sun, 3 Jan 2021 22:57:42 +0100 Subject: [PATCH 23/60] update cppcheck --- .github/workflows/build_check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_check.yml b/.github/workflows/build_check.yml index c22d292..36adeb1 100644 --- a/.github/workflows/build_check.yml +++ b/.github/workflows/build_check.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/checkout@v2 with: submodules: 'recursive' - - run: platformio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high --skip-packages --flags "--suppress=*:*.pio\* --inline-suppr" -v + - run: platformio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high --skip-packages --flags "--suppress=*:*.pio\* --inline-suppr lib/APRS-IS lib/BoardFinder lib/ConfigurationManagement lib/PowerManagement lib/SignalSlot lib/TaskManager" -v PlatformIO-Build: runs-on: ubuntu-latest From 33e766a5ac889f237dfd9e07d73fc97e139f4d03 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Mon, 4 Jan 2021 23:10:23 +0100 Subject: [PATCH 24/60] add TaskQueue and many other stuff :) --- lib/APRS-IS/APRS-IS.cpp | 8 +-- lib/APRS-IS/APRS-IS.h | 4 +- lib/LoRa_APRS/LoRa_APRS.cpp | 6 -- lib/LoRa_APRS/LoRa_APRS.h | 5 +- lib/SignalSlot/SignalSlot.h | 116 -------------------------------- lib/TaskManager/TaskManager.cpp | 6 +- lib/TaskManager/TaskManager.h | 21 ++++-- lib/TaskManager/TaskQueue.h | 33 +++++++++ platformio.ini | 2 +- src/LoRa_APRS_iGate.cpp | 21 +++--- src/Task.h | 12 ++++ src/TaskAprsIs.cpp | 11 ++- src/TaskAprsIs.h | 4 +- src/TaskEth.cpp | 5 +- src/TaskEth.h | 2 +- src/TaskFTP.cpp | 5 +- src/TaskFTP.h | 2 +- src/TaskLora.cpp | 25 +++++-- src/TaskLora.h | 3 +- src/TaskNTP.cpp | 5 +- src/TaskNTP.h | 2 +- src/TaskOTA.cpp | 5 +- src/TaskOTA.h | 2 +- src/TaskWifi.cpp | 5 +- src/TaskWifi.h | 2 +- src/display.h | 5 +- 26 files changed, 131 insertions(+), 186 deletions(-) delete mode 100644 lib/SignalSlot/SignalSlot.h create mode 100644 lib/TaskManager/TaskQueue.h create mode 100644 src/Task.h diff --git a/lib/APRS-IS/APRS-IS.cpp b/lib/APRS-IS/APRS-IS.cpp index 17c95cd..af34a7c 100644 --- a/lib/APRS-IS/APRS-IS.cpp +++ b/lib/APRS-IS/APRS-IS.cpp @@ -66,15 +66,10 @@ bool APRS_IS::sendMessage(const std::shared_ptr message) { return false; } - _client.println(message->encode()); + _client.println(message->encode() + "\n"); return true; } -void APRS_IS::action(std::shared_ptr elem, int rssi, float snr) -{ - sendMessage(elem); -} - int APRS_IS::available() { return _client.available(); @@ -108,6 +103,5 @@ std::shared_ptr APRS_IS::getAPRSMessage() } std::shared_ptr msg = std::shared_ptr(new APRSMessage()); msg->decode(line); - emit(msg); return msg; } diff --git a/lib/APRS-IS/APRS-IS.h b/lib/APRS-IS/APRS-IS.h index a7df11f..256df1e 100644 --- a/lib/APRS-IS/APRS-IS.h +++ b/lib/APRS-IS/APRS-IS.h @@ -2,11 +2,10 @@ #ifndef APRS_IS_Lib_h_ #define APRS_IS_Lib_h_ -#include #include #include -class APRS_IS : public Signal1>, public Slot3, int, float> +class APRS_IS { public: APRS_IS(const String & user, const String & passcode, const String & tool_name, const String & version); @@ -18,7 +17,6 @@ public: bool sendMessage(const String & message); bool sendMessage(const std::shared_ptr message); - void action(std::shared_ptr msg, int rssi, float snr) override; int available(); diff --git a/lib/LoRa_APRS/LoRa_APRS.cpp b/lib/LoRa_APRS/LoRa_APRS.cpp index 8f8a5a2..2deb45f 100644 --- a/lib/LoRa_APRS/LoRa_APRS.cpp +++ b/lib/LoRa_APRS/LoRa_APRS.cpp @@ -34,7 +34,6 @@ bool LoRa_APRS::checkMessage() } _LastReceivedMsg = std::shared_ptr(new APRSMessage()); _LastReceivedMsg->decode(str); - emit(_LastReceivedMsg, packetRssi(), packetSnr()); return true; } @@ -80,8 +79,3 @@ long LoRa_APRS::getTxFrequency() const { return _TxFrequency; } - -void LoRa_APRS::action(const std::shared_ptr elem) -{ - sendMessage(elem); -} diff --git a/lib/LoRa_APRS/LoRa_APRS.h b/lib/LoRa_APRS/LoRa_APRS.h index 71bad11..1991528 100644 --- a/lib/LoRa_APRS/LoRa_APRS.h +++ b/lib/LoRa_APRS/LoRa_APRS.h @@ -5,7 +5,6 @@ #include #include #include -#include #define LORA_RX_FREQUENCY (433775000) #define LORA_TX_FREQUENCY (433900000) @@ -13,7 +12,7 @@ #define LORA_SIGNAL_BANDWIDTH (125E3) #define LORA_CODING_RATE4 (5) -class LoRa_APRS : public LoRaClass, public Slot1>, public Signal3, int, float> +class LoRa_APRS : public LoRaClass { public: explicit LoRa_APRS(std::shared_ptr boardConfig); @@ -29,8 +28,6 @@ public: void setTxFrequency(long frequency); long getTxFrequency() const; - void action(const std::shared_ptr elem) override; - private: std::shared_ptr _LastReceivedMsg; long _RxFrequency; diff --git a/lib/SignalSlot/SignalSlot.h b/lib/SignalSlot/SignalSlot.h deleted file mode 100644 index 28c92b5..0000000 --- a/lib/SignalSlot/SignalSlot.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef SIGNAL_SLOT_H_ -#define SIGNAL_SLOT_H_ - -#include - -class Slot0 -{ -public: - virtual void action() = 0; -}; - -template -class Slot1 -{ -public: - virtual void action(T elem1) = 0; -}; - -template -class Slot2 -{ -public: - virtual void action(T elem1, H elem2) = 0; -}; - -template -class Slot3 -{ -public: - virtual void action(T elem1, H elem2, K elem3) = 0; -}; - -class Signal0 -{ -public: - void emit() - { - for(Slot0 * slot: _slots) - { - slot->action(); - } - } - - void connectSlot(Slot0 * slot) - { - _slots.push_back(slot); - } - -private: - std::list _slots; -}; - -template -class Signal1 -{ -public: - void emit(T elem1) - { - for(Slot1 * slot: _slots) - { - slot->action(elem1); - } - } - - void connectSlot(Slot1 * slot) - { - _slots.push_back(slot); - } - -private: - std::list *> _slots; -}; - -template -class Signal2 -{ -public: - void emit(T elem1, H elem2) - { - for(Slot2 * slot: _slots) - { - slot->action(elem1, elem2); - } - } - - void connectSlot(Slot2 * slot) - { - _slots.push_back(slot); - } - -private: - std::list *> _slots; -}; - -template -class Signal3 -{ -public: - void emit(T elem1, H elem2, K elem3) - { - for(Slot3 * slot: _slots) - { - slot->action(elem1, elem2, elem3); - } - } - - void connectSlot(Slot3 * slot) - { - _slots.push_back(slot); - } - -private: - std::list *> _slots; -}; - -#endif diff --git a/lib/TaskManager/TaskManager.cpp b/lib/TaskManager/TaskManager.cpp index 2043208..216712d 100644 --- a/lib/TaskManager/TaskManager.cpp +++ b/lib/TaskManager/TaskManager.cpp @@ -10,7 +10,7 @@ void TaskManager::addTask(std::shared_ptr task) _tasks.push_back(task); } -std::shared_ptr TaskManager::getTask(String & name) +std::shared_ptr TaskManager::getTask(const char * name) { for(std::shared_ptr & elem : _tasks) { @@ -22,14 +22,14 @@ std::shared_ptr TaskManager::getTask(String & name) return 0; } -bool TaskManager::setup(std::shared_ptr config) +bool TaskManager::setup(std::shared_ptr config, std::shared_ptr boardConfig) { logPrintlnV("will setup all tasks..."); for(std::shared_ptr & elem : _tasks) { logPrintW("call setup from "); logPrintlnW(elem->getName()); - if(!elem->setup(config)) + if(!elem->setup(config, boardConfig)) { return false; } diff --git a/lib/TaskManager/TaskManager.h b/lib/TaskManager/TaskManager.h index bbead2b..1894f9f 100644 --- a/lib/TaskManager/TaskManager.h +++ b/lib/TaskManager/TaskManager.h @@ -5,6 +5,9 @@ #include #include #include +#include + +#include "TaskQueue.h" class Task { @@ -15,7 +18,7 @@ public: String getName() const { return _name; } - virtual bool setup(std::shared_ptr config) = 0; + virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) = 0; virtual bool loop(std::shared_ptr config) = 0; private: @@ -25,17 +28,27 @@ private: class TaskManager { public: - TaskManager(); + + static TaskManager & instance() + { + static TaskManager _instance; + return _instance; + } + + ~TaskManager() {} void addTask(std::shared_ptr task); - std::shared_ptr getTask(String & name); + std::shared_ptr getTask(const char * name); - bool setup(std::shared_ptr config); + bool setup(std::shared_ptr config, std::shared_ptr boardConfig); bool loop(std::shared_ptr config); private: std::list> _tasks; + TaskManager(); + TaskManager(const TaskManager &); + TaskManager & operator = (const TaskManager &); }; #endif diff --git a/lib/TaskManager/TaskQueue.h b/lib/TaskManager/TaskQueue.h new file mode 100644 index 0000000..258e0de --- /dev/null +++ b/lib/TaskManager/TaskQueue.h @@ -0,0 +1,33 @@ +#ifndef TASK_QUEUE_H_ +#define TASK_QUEUE_H_ + +#include + +template +class TaskQueue +{ +public: + TaskQueue() {} + + void addElement(T elem) + { + _elements.push_back(elem); + } + + T getElement() + { + T elem = _elements.front(); + _elements.pop_front(); + return elem; + } + + bool empty() const + { + return _elements.empty(); + } + +private: + std::list _elements; +}; + +#endif diff --git a/platformio.ini b/platformio.ini index 03fd44c..7f00833 100644 --- a/platformio.ini +++ b/platformio.ini @@ -8,7 +8,7 @@ lib_deps = adafruit/Adafruit SSD1306 @ 2.4.0 bblanchon/ArduinoJson @ 6.17.0 lewisxhe/AXP202X_Library @ 1.1.2 - peterus/APRS-Decoder-Lib @ 0.0.5 + peterus/APRS-Decoder-Lib @ 0.0.6 peterus/esp-logger @ 0.0.1 peterus/ESP-FTP-Server-Lib @ 0.9.5 check_tool = cppcheck diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index 2f57d00..ca69df7 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -24,7 +24,6 @@ String create_long_aprs(double lng); std::shared_ptr userConfig; std::shared_ptr boardConfig; -TaskManager taskManager; HardwareSerial Serial(0); // cppcheck-suppress unusedFunction @@ -92,20 +91,18 @@ void setup() load_config(boardConfig); - std::shared_ptr lora_task = std::shared_ptr(new LoraTask()); - lora_task->setup(userConfig, boardConfig); - taskManager.addTask(lora_task); + TaskManager::instance().addTask(std::shared_ptr(new LoraTask())); if(boardConfig->Type == eETH_BOARD) { - taskManager.addTask(std::shared_ptr(new EthTask())); + TaskManager::instance().addTask(std::shared_ptr(new EthTask())); } - taskManager.addTask(std::shared_ptr(new WifiTask())); - taskManager.addTask(std::shared_ptr(new OTATask())); - taskManager.addTask(std::shared_ptr(new NTPTask())); - taskManager.addTask(std::shared_ptr(new FTPTask())); - taskManager.addTask(std::shared_ptr(new AprsIsTask())); + TaskManager::instance().addTask(std::shared_ptr(new WifiTask())); + TaskManager::instance().addTask(std::shared_ptr(new OTATask())); + TaskManager::instance().addTask(std::shared_ptr(new NTPTask())); + TaskManager::instance().addTask(std::shared_ptr(new FTPTask())); + TaskManager::instance().addTask(std::shared_ptr(new AprsIsTask())); - taskManager.setup(userConfig); + TaskManager::instance().setup(userConfig, boardConfig); if(userConfig->display.overwritePin != 0) { @@ -120,7 +117,7 @@ void setup() // cppcheck-suppress unusedFunction void loop() { - taskManager.loop(userConfig); + TaskManager::instance().loop(userConfig); } String create_lat_aprs(double lat) diff --git a/src/Task.h b/src/Task.h new file mode 100644 index 0000000..770b84e --- /dev/null +++ b/src/Task.h @@ -0,0 +1,12 @@ +#ifndef TASK_H_ +#define TASK_H_ + +#define TASK_APRS_IS "AprsIsTask" +#define TASK_ETH "EthTask" +#define TASK_FTP "FTPTask" +#define TASK_LORA "LoraTask" +#define TASK_NTP "NTPTask" +#define TASK_OTA "OTATask" +#define TASK_WIFI "WifiTask" + +#endif diff --git a/src/TaskAprsIs.cpp b/src/TaskAprsIs.cpp index f962c78..2961358 100644 --- a/src/TaskAprsIs.cpp +++ b/src/TaskAprsIs.cpp @@ -2,12 +2,13 @@ #include #include "project_configuration.h" #include "TaskAprsIs.h" +#include "Task.h" String create_lat_aprs(double lat); String create_long_aprs(double lng); AprsIsTask::AprsIsTask() - : Task("AprsIsTask") + : Task(TASK_APRS_IS), _beacon_next_time(0) { } @@ -15,7 +16,7 @@ AprsIsTask::~AprsIsTask() { } -bool AprsIsTask::setup(std::shared_ptr config) +bool AprsIsTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { _aprs_is = std::shared_ptr(new APRS_IS(config->callsign, config->aprs_is.passcode , "ESP32-APRS-IS", "0.1")); connect(config); @@ -38,6 +39,12 @@ bool AprsIsTask::loop(std::shared_ptr config) } _aprs_is->getAPRSMessage(); + if(!inputQueue.empty()) + { + std::shared_ptr msg = inputQueue.getElement(); + _aprs_is->sendMessage(msg); + } + if(_beacon_next_time < now()) { //show_display(userConfig->callsign, "Beacon to APRS-IS Server..."); diff --git a/src/TaskAprsIs.h b/src/TaskAprsIs.h index cc9d413..3b393b4 100644 --- a/src/TaskAprsIs.h +++ b/src/TaskAprsIs.h @@ -11,9 +11,11 @@ public: AprsIsTask(); virtual ~AprsIsTask(); - virtual bool setup(std::shared_ptr config) override; + virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; virtual bool loop(std::shared_ptr config) override; + TaskQueue> inputQueue; + private: std::shared_ptr _aprs_is; std::shared_ptr _beaconMsg; diff --git a/src/TaskEth.cpp b/src/TaskEth.cpp index ad6d231..201ff96 100644 --- a/src/TaskEth.cpp +++ b/src/TaskEth.cpp @@ -2,6 +2,7 @@ #include #include #include "TaskEth.h" +#include "Task.h" volatile bool eth_connected = false; @@ -42,7 +43,7 @@ static void WiFiEvent(WiFiEvent_t event) } EthTask::EthTask() - : Task("EthTask") + : Task(TASK_ETH) { } @@ -50,7 +51,7 @@ EthTask::~EthTask() { } -bool EthTask::setup(std::shared_ptr config) +bool EthTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { WiFi.onEvent(WiFiEvent); diff --git a/src/TaskEth.h b/src/TaskEth.h index ca684aa..a814495 100644 --- a/src/TaskEth.h +++ b/src/TaskEth.h @@ -9,7 +9,7 @@ public: EthTask(); virtual ~EthTask(); - virtual bool setup(std::shared_ptr config) override; + virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; virtual bool loop(std::shared_ptr config) override; private: diff --git a/src/TaskFTP.cpp b/src/TaskFTP.cpp index b28e29e..0ddf27b 100644 --- a/src/TaskFTP.cpp +++ b/src/TaskFTP.cpp @@ -3,9 +3,10 @@ #include #include "project_configuration.h" #include "TaskFTP.h" +#include "Task.h" FTPTask::FTPTask() - : Task("FTPTask") + : Task(TASK_FTP) { } @@ -13,7 +14,7 @@ FTPTask::~FTPTask() { } -bool FTPTask::setup(std::shared_ptr config) +bool FTPTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { _ftpServer = std::shared_ptr(new FTPServer()); if(config->ftp.active) diff --git a/src/TaskFTP.h b/src/TaskFTP.h index 5db9edc..5bb83d2 100644 --- a/src/TaskFTP.h +++ b/src/TaskFTP.h @@ -10,7 +10,7 @@ public: FTPTask(); virtual ~FTPTask(); - virtual bool setup(std::shared_ptr config) override; + virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; virtual bool loop(std::shared_ptr config) override; private: diff --git a/src/TaskLora.cpp b/src/TaskLora.cpp index 556c2ec..0f515c9 100644 --- a/src/TaskLora.cpp +++ b/src/TaskLora.cpp @@ -1,9 +1,12 @@ #include +#include #include "project_configuration.h" #include "TaskLora.h" +#include "TaskAprsIs.h" +#include "Task.h" LoraTask::LoraTask() - : Task("LoraTask") + : Task(TASK_LORA) { } @@ -11,11 +14,6 @@ LoraTask::~LoraTask() { } -bool LoraTask::setup(std::shared_ptr config) -{ - return true; -} - bool LoraTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { _lora_aprs = std::shared_ptr(new LoRa_APRS(boardConfig)); @@ -40,6 +38,19 @@ bool LoraTask::setup(std::shared_ptr config, std::shared_ptr config) { - _lora_aprs->checkMessage(); + if(_lora_aprs->checkMessage()) + { + std::shared_ptr msg = _lora_aprs->getMessage(); + //msg->getAPRSBody()->setData(msg->getAPRSBody()->getData() + " 123"); + logPrintD("[" + timeString() + "] "); + logPrintD("Received packet '"); + logPrintD(msg->toString()); + logPrintD("' with RSSI "); + logPrintD(String(_lora_aprs->packetRssi())); + logPrintD(" and SNR "); + logPrintlnD(String(_lora_aprs->packetSnr())); + std::shared_ptr is_thread = std::static_pointer_cast(TaskManager::instance().getTask(TASK_APRS_IS)); + is_thread->inputQueue.addElement(msg); + } return true; } diff --git a/src/TaskLora.h b/src/TaskLora.h index b6410eb..c0a02be 100644 --- a/src/TaskLora.h +++ b/src/TaskLora.h @@ -11,9 +11,8 @@ public: LoraTask(); virtual ~LoraTask(); - virtual bool setup(std::shared_ptr config) override; + virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; virtual bool loop(std::shared_ptr config) override; - bool setup(std::shared_ptr config, std::shared_ptr boardConfig); private: std::shared_ptr _lora_aprs; diff --git a/src/TaskNTP.cpp b/src/TaskNTP.cpp index 294bceb..3da2af0 100644 --- a/src/TaskNTP.cpp +++ b/src/TaskNTP.cpp @@ -2,9 +2,10 @@ #include #include "project_configuration.h" #include "TaskNTP.h" +#include "Task.h" NTPTask::NTPTask() - : Task("NTPTask") + : Task(TASK_NTP) { } @@ -12,7 +13,7 @@ NTPTask::~NTPTask() { } -bool NTPTask::setup(std::shared_ptr config) +bool NTPTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { _ntpClient = std::shared_ptr(new NTPClient(config->ntpServer.c_str())); _ntpClient->begin(); diff --git a/src/TaskNTP.h b/src/TaskNTP.h index e05a89f..c5895b6 100644 --- a/src/TaskNTP.h +++ b/src/TaskNTP.h @@ -10,7 +10,7 @@ public: NTPTask(); virtual ~NTPTask(); - virtual bool setup(std::shared_ptr config) override; + virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; virtual bool loop(std::shared_ptr config) override; private: diff --git a/src/TaskOTA.cpp b/src/TaskOTA.cpp index 5d96a62..f4b5b64 100644 --- a/src/TaskOTA.cpp +++ b/src/TaskOTA.cpp @@ -1,9 +1,10 @@ #include #include "project_configuration.h" #include "TaskOTA.h" +#include "Task.h" OTATask::OTATask() - : Task("OTATask") + : Task(TASK_OTA) { } @@ -11,7 +12,7 @@ OTATask::~OTATask() { } -bool OTATask::setup(std::shared_ptr config) +bool OTATask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { _ota = std::shared_ptr(new ArduinoOTAClass()); _ota->onStart([&]() diff --git a/src/TaskOTA.h b/src/TaskOTA.h index e36fb29..4700132 100644 --- a/src/TaskOTA.h +++ b/src/TaskOTA.h @@ -10,7 +10,7 @@ public: OTATask(); virtual ~OTATask(); - virtual bool setup(std::shared_ptr config) override; + virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; virtual bool loop(std::shared_ptr config) override; private: diff --git a/src/TaskWifi.cpp b/src/TaskWifi.cpp index 297248c..1266074 100644 --- a/src/TaskWifi.cpp +++ b/src/TaskWifi.cpp @@ -2,9 +2,10 @@ #include #include "project_configuration.h" #include "TaskWifi.h" +#include "Task.h" WifiTask::WifiTask() - : Task("WifiTask") + : Task(TASK_WIFI) { } @@ -12,7 +13,7 @@ WifiTask::~WifiTask() { } -bool WifiTask::setup(std::shared_ptr config) +bool WifiTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { //WiFi.onEvent(WiFiEvent); //WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); diff --git a/src/TaskWifi.h b/src/TaskWifi.h index 15cd050..c6b67bf 100644 --- a/src/TaskWifi.h +++ b/src/TaskWifi.h @@ -10,7 +10,7 @@ public: WifiTask(); virtual ~WifiTask(); - virtual bool setup(std::shared_ptr config) override; + virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; virtual bool loop(std::shared_ptr config) override; private: diff --git a/src/display.h b/src/display.h index 7ebfd92..4bd7530 100644 --- a/src/display.h +++ b/src/display.h @@ -13,11 +13,10 @@ void show_display(String header, String line1, String line2, String line3, int w //void show_display(String header, String line1, String line2, String line3, String line4, String line5, int wait = 0); #include -#include "SignalSlot.h" #include "TimeLib.h" #include "logger.h" -class PrintMessageToConsole : public Slot1>, public Slot3, int, float> +/*class PrintMessageToConsole : public Slot1>, public Slot3, int, float> { public: void action(std::shared_ptr msg, int rssi, float snr) override @@ -42,6 +41,6 @@ public: logPrintD(msg->toString()); logPrintD("'"); } -}; +};*/ #endif From 6b895debc5439a040868aabfb44a884c80231998 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Mon, 4 Jan 2021 23:11:14 +0100 Subject: [PATCH 25/60] cppcheck update --- .github/workflows/build_check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_check.yml b/.github/workflows/build_check.yml index 36adeb1..9a453a8 100644 --- a/.github/workflows/build_check.yml +++ b/.github/workflows/build_check.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/checkout@v2 with: submodules: 'recursive' - - run: platformio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high --skip-packages --flags "--suppress=*:*.pio\* --inline-suppr lib/APRS-IS lib/BoardFinder lib/ConfigurationManagement lib/PowerManagement lib/SignalSlot lib/TaskManager" -v + - run: platformio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high --skip-packages --flags "--suppress=*:*.pio\* --inline-suppr lib/APRS-IS lib/BoardFinder lib/ConfigurationManagement lib/PowerManagement lib/TaskManager" -v PlatformIO-Build: runs-on: ubuntu-latest From 629138c54c701cccc097c44cb2a9ce087689c877 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Tue, 5 Jan 2021 22:18:15 +0100 Subject: [PATCH 26/60] fixing extern lib --- src/TaskAprsIs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TaskAprsIs.cpp b/src/TaskAprsIs.cpp index 2961358..b79f091 100644 --- a/src/TaskAprsIs.cpp +++ b/src/TaskAprsIs.cpp @@ -26,7 +26,7 @@ bool AprsIsTask::setup(std::shared_ptr config, std::shared_ptrsetDestination("APLG0"); String lat = create_lat_aprs(config->beacon.positionLatitude); String lng = create_long_aprs(config->beacon.positionLongitude); - _beaconMsg->getAPRSBody()->setData(String("=") + lat + "I" + lng + "&" + config->beacon.message); + _beaconMsg->getBody()->setData(String("=") + lat + "I" + lng + "&" + config->beacon.message); return true; } From ef0b705d31e5a5ecab2f62e7d277060dfd3a33b6 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Tue, 5 Jan 2021 23:57:59 +0100 Subject: [PATCH 27/60] move conect function into loop function --- src/TaskAprsIs.cpp | 13 ++++++------- src/TaskAprsIs.h | 2 +- src/TaskFTP.cpp | 9 ++++++--- src/TaskFTP.h | 1 + src/TaskLora.cpp | 8 +++++++- src/TaskLora.h | 2 ++ src/TaskNTP.cpp | 22 ++++++++-------------- src/TaskNTP.h | 1 + src/TaskOTA.cpp | 9 ++++++--- src/TaskOTA.h | 1 + src/TaskWifi.cpp | 17 +++-------------- 11 files changed, 42 insertions(+), 43 deletions(-) diff --git a/src/TaskAprsIs.cpp b/src/TaskAprsIs.cpp index b79f091..8044293 100644 --- a/src/TaskAprsIs.cpp +++ b/src/TaskAprsIs.cpp @@ -19,7 +19,6 @@ AprsIsTask::~AprsIsTask() bool AprsIsTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { _aprs_is = std::shared_ptr(new APRS_IS(config->callsign, config->aprs_is.passcode , "ESP32-APRS-IS", "0.1")); - connect(config); _beaconMsg = std::shared_ptr(new APRSMessage()); _beaconMsg->setSource(config->callsign); @@ -35,8 +34,9 @@ bool AprsIsTask::loop(std::shared_ptr config) { if(!_aprs_is->connected()) { - connect(config); + return connect(config); } + _aprs_is->getAPRSMessage(); if(!inputQueue.empty()) @@ -57,19 +57,18 @@ bool AprsIsTask::loop(std::shared_ptr config) return true; } -void AprsIsTask::connect(std::shared_ptr config) +bool AprsIsTask::connect(std::shared_ptr config) { logPrintI("connecting to APRS-IS server: "); logPrintI(config->aprs_is.server); logPrintI(" on port: "); logPrintlnI(String(config->aprs_is.port)); //show_display("INFO", "Connecting to APRS-IS server"); - while(!_aprs_is->connect(config->aprs_is.server, config->aprs_is.port)) + if(!_aprs_is->connect(config->aprs_is.server, config->aprs_is.port)) { logPrintlnE("Connection failed."); - logPrintlnI("Waiting 1 seconds before retrying..."); - //show_display("ERROR", "Server connection failed!", "waiting 5 sec"); - delay(1000); + return false; } logPrintlnI("Connected to APRS-IS server!"); + return true; } diff --git a/src/TaskAprsIs.h b/src/TaskAprsIs.h index 3b393b4..4c99e0c 100644 --- a/src/TaskAprsIs.h +++ b/src/TaskAprsIs.h @@ -21,7 +21,7 @@ private: std::shared_ptr _beaconMsg; time_t _beacon_next_time; - void connect(std::shared_ptr config); + bool connect(std::shared_ptr config); }; #endif diff --git a/src/TaskFTP.cpp b/src/TaskFTP.cpp index 0ddf27b..7ac0e85 100644 --- a/src/TaskFTP.cpp +++ b/src/TaskFTP.cpp @@ -6,7 +6,7 @@ #include "Task.h" FTPTask::FTPTask() - : Task(TASK_FTP) + : Task(TASK_FTP), _beginCalled(false) { } @@ -26,8 +26,6 @@ bool FTPTask::setup(std::shared_ptr config, std::shared_ptraddUser(user.name, user.password); } _ftpServer->addFilesystem("SPIFFS", &SPIFFS); - _ftpServer->begin(); - logPrintlnI("FTP Server init done!"); } return true; } @@ -36,6 +34,11 @@ bool FTPTask::loop(std::shared_ptr config) { if(config->ftp.active) { + if(!_beginCalled) + { + _ftpServer->begin(); + _beginCalled = true; + } _ftpServer->handle(); static bool configWasOpen = false; if(configWasOpen && _ftpServer->countConnections() == 0) diff --git a/src/TaskFTP.h b/src/TaskFTP.h index 5bb83d2..716424c 100644 --- a/src/TaskFTP.h +++ b/src/TaskFTP.h @@ -15,6 +15,7 @@ public: private: std::shared_ptr _ftpServer; + bool _beginCalled; }; #endif diff --git a/src/TaskLora.cpp b/src/TaskLora.cpp index 0f515c9..7424c46 100644 --- a/src/TaskLora.cpp +++ b/src/TaskLora.cpp @@ -30,7 +30,6 @@ bool LoraTask::setup(std::shared_ptr config, std::shared_ptrsetSignalBandwidth(config->lora.signalBandwidth); _lora_aprs->setCodingRate4(config->lora.codingRate4); _lora_aprs->enableCrc(); - logPrintlnI("LoRa init done!"); //show_display("INFO", "LoRa init done!", 2000); return true; @@ -52,5 +51,12 @@ bool LoraTask::loop(std::shared_ptr config) std::shared_ptr is_thread = std::static_pointer_cast(TaskManager::instance().getTask(TASK_APRS_IS)); is_thread->inputQueue.addElement(msg); } + + if(!inputQueue.empty()) + { + std::shared_ptr msg = inputQueue.getElement(); + _lora_aprs->sendMessage(msg); + } + return true; } diff --git a/src/TaskLora.h b/src/TaskLora.h index c0a02be..db2201d 100644 --- a/src/TaskLora.h +++ b/src/TaskLora.h @@ -14,6 +14,8 @@ public: virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; virtual bool loop(std::shared_ptr config) override; + TaskQueue> inputQueue; + private: std::shared_ptr _lora_aprs; }; diff --git a/src/TaskNTP.cpp b/src/TaskNTP.cpp index 3da2af0..972877c 100644 --- a/src/TaskNTP.cpp +++ b/src/TaskNTP.cpp @@ -5,7 +5,7 @@ #include "Task.h" NTPTask::NTPTask() - : Task(TASK_NTP) + : Task(TASK_NTP), _beginCalled(false) { } @@ -16,27 +16,21 @@ NTPTask::~NTPTask() bool NTPTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { _ntpClient = std::shared_ptr(new NTPClient(config->ntpServer.c_str())); - _ntpClient->begin(); - while(!_ntpClient->forceUpdate()) - { - logPrintlnW("NTP Client force update issue! Waiting 1 sek..."); - logPrintlnD(_ntpClient->getFormattedTime()); - //show_display("WARN", "NTP Client force update issue! Waiting 1 sek...", 1000); - sleep(1); - } - setTime(_ntpClient->getEpochTime()); - logPrintI("Current time: "); - logPrintlnI(_ntpClient->getFormattedTime()); - logPrintlnI("NTP Client init done!"); - //show_display("INFO", "NTP Client init done!", 2000); return true; } bool NTPTask::loop(std::shared_ptr config) { + if(!_beginCalled) + { + _ntpClient->begin(); + _beginCalled = true; + } if(_ntpClient->update()) { setTime(_ntpClient->getEpochTime()); + logPrintI("Current time: "); + logPrintlnI(_ntpClient->getFormattedTime()); } return true; } diff --git a/src/TaskNTP.h b/src/TaskNTP.h index c5895b6..ef5240b 100644 --- a/src/TaskNTP.h +++ b/src/TaskNTP.h @@ -15,6 +15,7 @@ public: private: std::shared_ptr _ntpClient; + bool _beginCalled; }; #endif diff --git a/src/TaskOTA.cpp b/src/TaskOTA.cpp index f4b5b64..17ac831 100644 --- a/src/TaskOTA.cpp +++ b/src/TaskOTA.cpp @@ -4,7 +4,7 @@ #include "Task.h" OTATask::OTATask() - : Task(TASK_OTA) + : Task(TASK_OTA), _beginCalled(false) { } @@ -49,13 +49,16 @@ bool OTATask::setup(std::shared_ptr config, std::shared_ptrsetHostname(config->callsign.c_str()); - _ota->begin(); - logPrintlnI("OTA init done!"); return true; } bool OTATask::loop(std::shared_ptr config) { + if(!_beginCalled) + { + _ota->begin(); + _beginCalled = true; + } _ota->handle(); return true; } diff --git a/src/TaskOTA.h b/src/TaskOTA.h index 4700132..f9aa88f 100644 --- a/src/TaskOTA.h +++ b/src/TaskOTA.h @@ -15,6 +15,7 @@ public: private: std::shared_ptr _ota; + bool _beginCalled; }; #endif diff --git a/src/TaskWifi.cpp b/src/TaskWifi.cpp index 1266074..1936ae2 100644 --- a/src/TaskWifi.cpp +++ b/src/TaskWifi.cpp @@ -16,7 +16,6 @@ WifiTask::~WifiTask() bool WifiTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { //WiFi.onEvent(WiFiEvent); - //WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); WiFi.setHostname(config->callsign.c_str()); _wiFiMulti = std::shared_ptr(new WiFiMulti());; for(Configuration::Wifi::AP ap : config->wifi.APs) @@ -25,17 +24,6 @@ bool WifiTask::setup(std::shared_ptr config, std::shared_ptraddAP(ap.SSID.c_str(), ap.password.c_str()); } - logPrintlnI("Waiting for WiFi"); - //show_display("INFO", "Waiting for WiFi"); - while(_wiFiMulti->run() != WL_CONNECTED) - { - //show_display("INFO", "Waiting for WiFi", "...."); - delay(500); - } - logPrintlnI("WiFi connected"); - logPrintD("IP address: "); - logPrintlnD(WiFi.localIP().toString()); - //show_display("INFO", "WiFi connected", "IP: ", WiFi.localIP().toString(), 2000); return true; } @@ -45,8 +33,9 @@ bool WifiTask::loop(std::shared_ptr config) if(wifi_status != WL_CONNECTED) { logPrintlnE("WiFi not connected!"); - //show_display("ERROR", "WiFi not connected!"); - delay(1000); + return false; } + //logPrintD("IP address: "); + //logPrintlnD(WiFi.localIP().toString()); return true; } From bab37b9647aa3ff1fbaec2da5981360a05358f70 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Wed, 6 Jan 2021 00:21:27 +0100 Subject: [PATCH 28/60] adding ip printput --- src/TaskWifi.cpp | 11 ++++++++--- src/TaskWifi.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/TaskWifi.cpp b/src/TaskWifi.cpp index 1936ae2..40368df 100644 --- a/src/TaskWifi.cpp +++ b/src/TaskWifi.cpp @@ -5,7 +5,7 @@ #include "Task.h" WifiTask::WifiTask() - : Task(TASK_WIFI) + : Task(TASK_WIFI), _oldWifiStatus(WL_IDLE_STATUS) { } @@ -33,9 +33,14 @@ bool WifiTask::loop(std::shared_ptr config) if(wifi_status != WL_CONNECTED) { logPrintlnE("WiFi not connected!"); + _oldWifiStatus = wifi_status; return false; } - //logPrintD("IP address: "); - //logPrintlnD(WiFi.localIP().toString()); + else if(wifi_status != _oldWifiStatus) + { + logPrintD("IP address: "); + logPrintlnD(WiFi.localIP().toString()); + _oldWifiStatus = wifi_status; + } return true; } diff --git a/src/TaskWifi.h b/src/TaskWifi.h index c6b67bf..24b2a13 100644 --- a/src/TaskWifi.h +++ b/src/TaskWifi.h @@ -15,6 +15,7 @@ public: private: std::shared_ptr _wiFiMulti; + uint8_t _oldWifiStatus; }; #endif From b0345cceed9d504886e361c52c6ec031d9b0cd92 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sat, 9 Jan 2021 13:36:49 +0100 Subject: [PATCH 29/60] cppcheck fix --- .github/workflows/build_check.yml | 2 +- lib/ConfigurationManagement/configuration.h | 2 ++ lib/{LoRa_APRS => LoRa}/LoRa.cpp | 0 lib/{LoRa_APRS => LoRa}/LoRa.h | 0 platformio.ini | 2 +- 5 files changed, 4 insertions(+), 2 deletions(-) rename lib/{LoRa_APRS => LoRa}/LoRa.cpp (100%) rename lib/{LoRa_APRS => LoRa}/LoRa.h (100%) diff --git a/.github/workflows/build_check.yml b/.github/workflows/build_check.yml index 9a453a8..2b8f6f6 100644 --- a/.github/workflows/build_check.yml +++ b/.github/workflows/build_check.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/checkout@v2 with: submodules: 'recursive' - - run: platformio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high --skip-packages --flags "--suppress=*:*.pio\* --inline-suppr lib/APRS-IS lib/BoardFinder lib/ConfigurationManagement lib/PowerManagement lib/TaskManager" -v + - run: platformio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high --skip-packages PlatformIO-Build: runs-on: ubuntu-latest diff --git a/lib/ConfigurationManagement/configuration.h b/lib/ConfigurationManagement/configuration.h index 35719a7..5c66303 100644 --- a/lib/ConfigurationManagement/configuration.h +++ b/lib/ConfigurationManagement/configuration.h @@ -5,7 +5,9 @@ #include #include +#ifndef CPPCHECK #include +#endif class Configuration; diff --git a/lib/LoRa_APRS/LoRa.cpp b/lib/LoRa/LoRa.cpp similarity index 100% rename from lib/LoRa_APRS/LoRa.cpp rename to lib/LoRa/LoRa.cpp diff --git a/lib/LoRa_APRS/LoRa.h b/lib/LoRa/LoRa.h similarity index 100% rename from lib/LoRa_APRS/LoRa.h rename to lib/LoRa/LoRa.h diff --git a/platformio.ini b/platformio.ini index 7f00833..c2a2ebe 100644 --- a/platformio.ini +++ b/platformio.ini @@ -13,7 +13,7 @@ lib_deps = peterus/ESP-FTP-Server-Lib @ 0.9.5 check_tool = cppcheck check_flags = - cppcheck: --suppress=*:*.pio\* --inline-suppr lib/common/src + cppcheck: --suppress=*:*.pio\* --inline-suppr -DCPPCHECK --force lib -ilib/TimeLib -ilib/LoRa -ilib/NTPClient monitor_flags = --raw # activate for OTA Update, use the CALLSIGN from is-cfg.json as upload_port: #upload_protocol = espota From 8b2e8f3c149a3c980a1c2cc658e15e6b8ccae445 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sat, 9 Jan 2021 13:38:48 +0100 Subject: [PATCH 30/60] some task management updates --- lib/TaskManager/TaskManager.h | 15 ++++++++------- src/Task.cpp | 26 ++++++++++++++++++++++++++ src/Task.h | 16 ++++++++++++++++ src/TaskAprsIs.cpp | 5 +---- src/TaskEth.cpp | 2 +- src/TaskFTP.cpp | 2 +- src/TaskLora.cpp | 4 +--- src/TaskNTP.cpp | 2 +- src/TaskOTA.cpp | 4 +--- src/TaskWifi.cpp | 2 +- 10 files changed, 57 insertions(+), 21 deletions(-) create mode 100644 src/Task.cpp diff --git a/lib/TaskManager/TaskManager.h b/lib/TaskManager/TaskManager.h index 1894f9f..5f4cb89 100644 --- a/lib/TaskManager/TaskManager.h +++ b/lib/TaskManager/TaskManager.h @@ -12,28 +12,29 @@ class Task { public: - Task(String & name) : _name(name) {} - Task(const char * name) : _name(name) {} + Task(String & name, int taskId) : _name(name), _taskId(taskId) {} + Task(const char * name, int taskId) : _name(name), _taskId(taskId) {} virtual ~Task() {} String getName() const { return _name; } + int getTaskId() const { return _taskId; } virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) = 0; virtual bool loop(std::shared_ptr config) = 0; private: String _name; + int _taskId; }; class TaskManager { public: - static TaskManager & instance() - { - static TaskManager _instance; - return _instance; - } + { + static TaskManager _instance; + return _instance; + } ~TaskManager() {} diff --git a/src/Task.cpp b/src/Task.cpp new file mode 100644 index 0000000..fd3d9db --- /dev/null +++ b/src/Task.cpp @@ -0,0 +1,26 @@ +#include "Task.h" + +char const * const getTaskName(TaskNames task) +{ + switch (task) + { + case TaskDisplay: + return "Display"; + case TaskAprsIs: + return "APRS-IS"; + case TaskEth: + return "ETH"; + case TaskFtp: + return "FTP"; + case TaskLora: + return "LORA"; + case TaskNtp: + return "NTP"; + case TaskOta: + return "OTA"; + case TaskWifi: + return "WIFI"; + default: + return "error"; + } +} diff --git a/src/Task.h b/src/Task.h index 770b84e..14b0c5d 100644 --- a/src/Task.h +++ b/src/Task.h @@ -1,6 +1,22 @@ #ifndef TASK_H_ #define TASK_H_ +enum TaskNames +{ + TaskDisplay, + TaskAprsIs, + TaskEth, + TaskFtp, + TaskLora, + TaskNtp, + TaskOta, + TaskWifi, + TaskSize, +}; + +char const * const getTaskName(TaskNames task); + +#define TASK_DISPLAY "DisplayTask" #define TASK_APRS_IS "AprsIsTask" #define TASK_ETH "EthTask" #define TASK_FTP "FTPTask" diff --git a/src/TaskAprsIs.cpp b/src/TaskAprsIs.cpp index 8044293..39c1302 100644 --- a/src/TaskAprsIs.cpp +++ b/src/TaskAprsIs.cpp @@ -8,7 +8,7 @@ String create_lat_aprs(double lat); String create_long_aprs(double lng); AprsIsTask::AprsIsTask() - : Task(TASK_APRS_IS), _beacon_next_time(0) + : Task(TASK_APRS_IS, TaskAprsIs), _beacon_next_time(0) { } @@ -47,11 +47,9 @@ bool AprsIsTask::loop(std::shared_ptr config) if(_beacon_next_time < now()) { - //show_display(userConfig->callsign, "Beacon to APRS-IS Server..."); logPrintD("[" + timeString() + "] "); logPrintlnD(_beaconMsg->encode()); _aprs_is->sendMessage(_beaconMsg); - //show_display(userConfig->callsign, "Standby..."); _beacon_next_time = now() + config->beacon.timeout * 60UL; } return true; @@ -63,7 +61,6 @@ bool AprsIsTask::connect(std::shared_ptr config) logPrintI(config->aprs_is.server); logPrintI(" on port: "); logPrintlnI(String(config->aprs_is.port)); - //show_display("INFO", "Connecting to APRS-IS server"); if(!_aprs_is->connect(config->aprs_is.server, config->aprs_is.port)) { logPrintlnE("Connection failed."); diff --git a/src/TaskEth.cpp b/src/TaskEth.cpp index 201ff96..a112217 100644 --- a/src/TaskEth.cpp +++ b/src/TaskEth.cpp @@ -43,7 +43,7 @@ static void WiFiEvent(WiFiEvent_t event) } EthTask::EthTask() - : Task(TASK_ETH) + : Task(TASK_ETH, TaskEth) { } diff --git a/src/TaskFTP.cpp b/src/TaskFTP.cpp index 7ac0e85..4a6eea6 100644 --- a/src/TaskFTP.cpp +++ b/src/TaskFTP.cpp @@ -6,7 +6,7 @@ #include "Task.h" FTPTask::FTPTask() - : Task(TASK_FTP), _beginCalled(false) + : Task(TASK_FTP, TaskFtp), _beginCalled(false) { } diff --git a/src/TaskLora.cpp b/src/TaskLora.cpp index 7424c46..cdac7ef 100644 --- a/src/TaskLora.cpp +++ b/src/TaskLora.cpp @@ -6,7 +6,7 @@ #include "Task.h" LoraTask::LoraTask() - : Task(TASK_LORA) + : Task(TASK_LORA, TaskLora) { } @@ -20,7 +20,6 @@ bool LoraTask::setup(std::shared_ptr config, std::shared_ptrbegin(_lora_aprs->getRxFrequency())) { logPrintlnE("Starting LoRa failed!"); - //show_display("ERROR", "Starting LoRa failed!"); while(true); } _lora_aprs->setRxFrequency(config->lora.frequencyRx); @@ -30,7 +29,6 @@ bool LoraTask::setup(std::shared_ptr config, std::shared_ptrsetSignalBandwidth(config->lora.signalBandwidth); _lora_aprs->setCodingRate4(config->lora.codingRate4); _lora_aprs->enableCrc(); - //show_display("INFO", "LoRa init done!", 2000); return true; } diff --git a/src/TaskNTP.cpp b/src/TaskNTP.cpp index 972877c..a4993ac 100644 --- a/src/TaskNTP.cpp +++ b/src/TaskNTP.cpp @@ -5,7 +5,7 @@ #include "Task.h" NTPTask::NTPTask() - : Task(TASK_NTP), _beginCalled(false) + : Task(TASK_NTP, TaskNtp), _beginCalled(false) { } diff --git a/src/TaskOTA.cpp b/src/TaskOTA.cpp index 17ac831..d569011 100644 --- a/src/TaskOTA.cpp +++ b/src/TaskOTA.cpp @@ -4,7 +4,7 @@ #include "Task.h" OTATask::OTATask() - : Task(TASK_OTA), _beginCalled(false) + : Task(TASK_OTA, TaskOta), _beginCalled(false) { } @@ -23,7 +23,6 @@ bool OTATask::setup(std::shared_ptr config, std::shared_ptr config, std::shared_ptr Date: Tue, 19 Jan 2021 23:12:55 +0100 Subject: [PATCH 31/60] add display stuff --- .github/workflows/build_check.yml | 2 +- lib/Display/Display.cpp | 46 ++ lib/Display/Display.h | 43 + lib/Display/OLEDDisplay.cpp | 1045 +++++++++++++++++++++++ lib/Display/OLEDDisplay.h | 343 ++++++++ lib/Display/OLEDDisplayFonts.h | 1274 +++++++++++++++++++++++++++++ lib/Display/OLEDDisplayUi.cpp | 471 +++++++++++ lib/Display/OLEDDisplayUi.h | 308 +++++++ lib/Display/SSD1306.h | 195 +++++ platformio.ini | 5 +- src/LoRa_APRS_iGate.cpp | 8 +- src/TaskDisplay.cpp | 30 + src/TaskDisplay.h | 20 + src/display.cpp | 146 ---- src/display.h | 46 -- 15 files changed, 3783 insertions(+), 199 deletions(-) create mode 100644 lib/Display/Display.cpp create mode 100644 lib/Display/Display.h create mode 100644 lib/Display/OLEDDisplay.cpp create mode 100644 lib/Display/OLEDDisplay.h create mode 100644 lib/Display/OLEDDisplayFonts.h create mode 100644 lib/Display/OLEDDisplayUi.cpp create mode 100644 lib/Display/OLEDDisplayUi.h create mode 100644 lib/Display/SSD1306.h create mode 100644 src/TaskDisplay.cpp create mode 100644 src/TaskDisplay.h delete mode 100644 src/display.cpp delete mode 100644 src/display.h diff --git a/.github/workflows/build_check.yml b/.github/workflows/build_check.yml index 2b8f6f6..3fb5e36 100644 --- a/.github/workflows/build_check.yml +++ b/.github/workflows/build_check.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/checkout@v2 with: submodules: 'recursive' - - run: platformio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high --skip-packages + - run: platformio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high PlatformIO-Build: runs-on: ubuntu-latest diff --git a/lib/Display/Display.cpp b/lib/Display/Display.cpp new file mode 100644 index 0000000..86a4fd0 --- /dev/null +++ b/lib/Display/Display.cpp @@ -0,0 +1,46 @@ +#include +#include "Display.h" + +Display::Display() +{ +} + +void Display::setup(std::shared_ptr boardConfig) +{ + _disp = std::shared_ptr(new SSD1306Wire(boardConfig->OledAddr, boardConfig->OledSda, boardConfig->OledScl)); + _ui = std::shared_ptr(new OLEDDisplayUi(_disp.get())); + + static std::array frames; + frames[0] = drawStatusPage; + frames[1] = drawStatusPage; + _ui->setFrames(frames.data(), frames.size()); + + _ui->setTargetFPS(15); + _ui->setFrameAnimation(SLIDE_LEFT); + _ui->init(); + _disp->flipScreenVertically(); +} + +void Display::setTaskStatus(const String & task, const String & status) +{ + _taskStatus.insert(std::pair(task, status)); +} + +void Display::update() +{ + _ui->update(); +} + +void Display::drawStatusPage(OLEDDisplay * display, OLEDDisplayUiState * state, int16_t x, int16_t y) +{ + //logPrintlnD("blib"); + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->setFont(ArialMT_Plain_10); + display->drawString(0 + x, 10 + y, "Arial 10"); + + display->setFont(ArialMT_Plain_16); + display->drawString(0 + x, 20 + y, "Arial 16"); + + display->setFont(ArialMT_Plain_24); + display->drawString(0 + x, 34 + y, "Arial 24"); +} diff --git a/lib/Display/Display.h b/lib/Display/Display.h new file mode 100644 index 0000000..b0f3a11 --- /dev/null +++ b/lib/Display/Display.h @@ -0,0 +1,43 @@ +#ifndef DISPLAY_H_ +#define DISPLAY_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +class Display +{ +public: + static Display & instance() + { + static Display _instance; + return _instance; + } + + ~Display() {} + + void setup(std::shared_ptr boardConfig); + + void setTaskStatus(const String & task, const String & status); + + void update(); + +private: + std::shared_ptr _disp; + std::shared_ptr _ui; + + static void drawStatusPage(OLEDDisplay * display, OLEDDisplayUiState * state, int16_t x, int16_t y); + + std::map _taskStatus; + + Display(); + Display(const Display &); + Display & operator = (const Display &); +}; + +#endif diff --git a/lib/Display/OLEDDisplay.cpp b/lib/Display/OLEDDisplay.cpp new file mode 100644 index 0000000..c047962 --- /dev/null +++ b/lib/Display/OLEDDisplay.cpp @@ -0,0 +1,1045 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn + * Copyright (c) 2018 by Fabrice Weinberg + * Copyright (c) 2019 by Helmut Tschemernjak - www.radioshuttle.de + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ThingPulse invests considerable time and money to develop these open source libraries. + * Please support us by buying our products (and not the clones) from + * https://thingpulse.com + * + */ + + /* + * TODO Helmut + * - test/finish dislplay.printf() on mbed-os + * - Finish _putc with drawLogBuffer when running display + */ + +#include "OLEDDisplay.h" + +OLEDDisplay::OLEDDisplay() { + + displayWidth = 128; + displayHeight = 64; + displayBufferSize = displayWidth * displayHeight / 8; + color = WHITE; + geometry = GEOMETRY_128_64; + textAlignment = TEXT_ALIGN_LEFT; + fontData = ArialMT_Plain_10; + fontTableLookupFunction = DefaultFontTableLookup; + buffer = NULL; +#ifdef OLEDDISPLAY_DOUBLE_BUFFER + buffer_back = NULL; +#endif +} + +OLEDDisplay::~OLEDDisplay() { + end(); +} + +bool OLEDDisplay::allocateBuffer() { + + logBufferSize = 0; + logBufferFilled = 0; + logBufferLine = 0; + logBufferMaxLines = 0; + logBuffer = NULL; + + if (!this->connect()) { + DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Can't establish connection to display\n"); + return false; + } + + if(this->buffer==NULL) { + this->buffer = (uint8_t*) malloc((sizeof(uint8_t) * displayBufferSize) + BufferOffset); + this->buffer += BufferOffset; + + if(!this->buffer) { + DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Not enough memory to create display\n"); + return false; + } + } + + #ifdef OLEDDISPLAY_DOUBLE_BUFFER + if(this->buffer_back==NULL) { + this->buffer_back = (uint8_t*) malloc((sizeof(uint8_t) * displayBufferSize) + BufferOffset); + this->buffer_back += BufferOffset; + + if(!this->buffer_back) { + DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Not enough memory to create back buffer\n"); + free(this->buffer - BufferOffset); + return false; + } + } + #endif + + return true; +} + +bool OLEDDisplay::init() { + + BufferOffset = getBufferOffset(); + + if(!allocateBuffer()) { + return false; + } + + sendInitCommands(); + resetDisplay(); + + return true; +} + +void OLEDDisplay::end() { + if (this->buffer) { free(this->buffer - BufferOffset); this->buffer = NULL; } + #ifdef OLEDDISPLAY_DOUBLE_BUFFER + if (this->buffer_back) { free(this->buffer_back - BufferOffset); this->buffer_back = NULL; } + #endif + if (this->logBuffer != NULL) { free(this->logBuffer); this->logBuffer = NULL; } +} + +void OLEDDisplay::resetDisplay(void) { + clear(); + #ifdef OLEDDISPLAY_DOUBLE_BUFFER + memset(buffer_back, 1, displayBufferSize); + #endif + display(); +} + +void OLEDDisplay::setColor(OLEDDISPLAY_COLOR color) { + this->color = color; +} + +OLEDDISPLAY_COLOR OLEDDisplay::getColor() { + return this->color; +} + +void OLEDDisplay::setPixel(int16_t x, int16_t y) { + if (x >= 0 && x < this->width() && y >= 0 && y < this->height()) { + switch (color) { + case WHITE: buffer[x + (y / 8) * this->width()] |= (1 << (y & 7)); break; + case BLACK: buffer[x + (y / 8) * this->width()] &= ~(1 << (y & 7)); break; + case INVERSE: buffer[x + (y / 8) * this->width()] ^= (1 << (y & 7)); break; + } + } +} + +void OLEDDisplay::setPixelColor(int16_t x, int16_t y, OLEDDISPLAY_COLOR color) { + if (x >= 0 && x < this->width() && y >= 0 && y < this->height()) { + switch (color) { + case WHITE: buffer[x + (y / 8) * this->width()] |= (1 << (y & 7)); break; + case BLACK: buffer[x + (y / 8) * this->width()] &= ~(1 << (y & 7)); break; + case INVERSE: buffer[x + (y / 8) * this->width()] ^= (1 << (y & 7)); break; + } + } +} + +void OLEDDisplay::clearPixel(int16_t x, int16_t y) { + if (x >= 0 && x < this->width() && y >= 0 && y < this->height()) { + switch (color) { + case BLACK: buffer[x + (y >> 3) * this->width()] |= (1 << (y & 7)); break; + case WHITE: buffer[x + (y >> 3) * this->width()] &= ~(1 << (y & 7)); break; + case INVERSE: buffer[x + (y >> 3) * this->width()] ^= (1 << (y & 7)); break; + } + } +} + + +// Bresenham's algorithm - thx wikipedia and Adafruit_GFX +void OLEDDisplay::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1) { + int16_t steep = abs(y1 - y0) > abs(x1 - x0); + if (steep) { + _swap_int16_t(x0, y0); + _swap_int16_t(x1, y1); + } + + if (x0 > x1) { + _swap_int16_t(x0, x1); + _swap_int16_t(y0, y1); + } + + int16_t dx, dy; + dx = x1 - x0; + dy = abs(y1 - y0); + + int16_t err = dx / 2; + int16_t ystep; + + if (y0 < y1) { + ystep = 1; + } else { + ystep = -1; + } + + for (; x0<=x1; x0++) { + if (steep) { + setPixel(y0, x0); + } else { + setPixel(x0, y0); + } + err -= dy; + if (err < 0) { + y0 += ystep; + err += dx; + } + } +} + +void OLEDDisplay::drawRect(int16_t x, int16_t y, int16_t width, int16_t height) { + drawHorizontalLine(x, y, width); + drawVerticalLine(x, y, height); + drawVerticalLine(x + width - 1, y, height); + drawHorizontalLine(x, y + height - 1, width); +} + +void OLEDDisplay::fillRect(int16_t xMove, int16_t yMove, int16_t width, int16_t height) { + for (int16_t x = xMove; x < xMove + width; x++) { + drawVerticalLine(x, yMove, height); + } +} + +void OLEDDisplay::drawCircle(int16_t x0, int16_t y0, int16_t radius) { + int16_t x = 0, y = radius; + int16_t dp = 1 - radius; + do { + if (dp < 0) + dp = dp + (x++) * 2 + 3; + else + dp = dp + (x++) * 2 - (y--) * 2 + 5; + + setPixel(x0 + x, y0 + y); //For the 8 octants + setPixel(x0 - x, y0 + y); + setPixel(x0 + x, y0 - y); + setPixel(x0 - x, y0 - y); + setPixel(x0 + y, y0 + x); + setPixel(x0 - y, y0 + x); + setPixel(x0 + y, y0 - x); + setPixel(x0 - y, y0 - x); + + } while (x < y); + + setPixel(x0 + radius, y0); + setPixel(x0, y0 + radius); + setPixel(x0 - radius, y0); + setPixel(x0, y0 - radius); +} + +void OLEDDisplay::drawCircleQuads(int16_t x0, int16_t y0, int16_t radius, uint8_t quads) { + int16_t x = 0, y = radius; + int16_t dp = 1 - radius; + while (x < y) { + if (dp < 0) + dp = dp + (x++) * 2 + 3; + else + dp = dp + (x++) * 2 - (y--) * 2 + 5; + if (quads & 0x1) { + setPixel(x0 + x, y0 - y); + setPixel(x0 + y, y0 - x); + } + if (quads & 0x2) { + setPixel(x0 - y, y0 - x); + setPixel(x0 - x, y0 - y); + } + if (quads & 0x4) { + setPixel(x0 - y, y0 + x); + setPixel(x0 - x, y0 + y); + } + if (quads & 0x8) { + setPixel(x0 + x, y0 + y); + setPixel(x0 + y, y0 + x); + } + } + if (quads & 0x1 && quads & 0x8) { + setPixel(x0 + radius, y0); + } + if (quads & 0x4 && quads & 0x8) { + setPixel(x0, y0 + radius); + } + if (quads & 0x2 && quads & 0x4) { + setPixel(x0 - radius, y0); + } + if (quads & 0x1 && quads & 0x2) { + setPixel(x0, y0 - radius); + } +} + + +void OLEDDisplay::fillCircle(int16_t x0, int16_t y0, int16_t radius) { + int16_t x = 0, y = radius; + int16_t dp = 1 - radius; + do { + if (dp < 0) + dp = dp + (x++) * 2 + 3; + else + dp = dp + (x++) * 2 - (y--) * 2 + 5; + + drawHorizontalLine(x0 - x, y0 - y, 2*x); + drawHorizontalLine(x0 - x, y0 + y, 2*x); + drawHorizontalLine(x0 - y, y0 - x, 2*y); + drawHorizontalLine(x0 - y, y0 + x, 2*y); + + + } while (x < y); + drawHorizontalLine(x0 - radius, y0, 2 * radius); + +} + +void OLEDDisplay::drawHorizontalLine(int16_t x, int16_t y, int16_t length) { + if (y < 0 || y >= this->height()) { return; } + + if (x < 0) { + length += x; + x = 0; + } + + if ( (x + length) > this->width()) { + length = (this->width() - x); + } + + if (length <= 0) { return; } + + uint8_t * bufferPtr = buffer; + bufferPtr += (y >> 3) * this->width(); + bufferPtr += x; + + uint8_t drawBit = 1 << (y & 7); + + switch (color) { + case WHITE: while (length--) { + *bufferPtr++ |= drawBit; + }; break; + case BLACK: drawBit = ~drawBit; while (length--) { + *bufferPtr++ &= drawBit; + }; break; + case INVERSE: while (length--) { + *bufferPtr++ ^= drawBit; + }; break; + } +} + +void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) { + if (x < 0 || x >= this->width()) return; + + if (y < 0) { + length += y; + y = 0; + } + + if ( (y + length) > this->height()) { + length = (this->height() - y); + } + + if (length <= 0) return; + + + uint8_t yOffset = y & 7; + uint8_t drawBit; + uint8_t *bufferPtr = buffer; + + bufferPtr += (y >> 3) * this->width(); + bufferPtr += x; + + if (yOffset) { + yOffset = 8 - yOffset; + drawBit = ~(0xFF >> (yOffset)); + + if (length < yOffset) { + drawBit &= (0xFF >> (yOffset - length)); + } + + switch (color) { + case WHITE: *bufferPtr |= drawBit; break; + case BLACK: *bufferPtr &= ~drawBit; break; + case INVERSE: *bufferPtr ^= drawBit; break; + } + + if (length < yOffset) return; + + length -= yOffset; + bufferPtr += this->width(); + } + + if (length >= 8) { + switch (color) { + case WHITE: + case BLACK: + drawBit = (color == WHITE) ? 0xFF : 0x00; + do { + *bufferPtr = drawBit; + bufferPtr += this->width(); + length -= 8; + } while (length >= 8); + break; + case INVERSE: + do { + *bufferPtr = ~(*bufferPtr); + bufferPtr += this->width(); + length -= 8; + } while (length >= 8); + break; + } + } + + if (length > 0) { + drawBit = (1 << (length & 7)) - 1; + switch (color) { + case WHITE: *bufferPtr |= drawBit; break; + case BLACK: *bufferPtr &= ~drawBit; break; + case INVERSE: *bufferPtr ^= drawBit; break; + } + } +} + +void OLEDDisplay::drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t progress) { + uint16_t radius = height / 2; + uint16_t xRadius = x + radius; + uint16_t yRadius = y + radius; + uint16_t doubleRadius = 2 * radius; + uint16_t innerRadius = radius - 2; + + setColor(WHITE); + drawCircleQuads(xRadius, yRadius, radius, 0b00000110); + drawHorizontalLine(xRadius, y, width - doubleRadius + 1); + drawHorizontalLine(xRadius, y + height, width - doubleRadius + 1); + drawCircleQuads(x + width - radius, yRadius, radius, 0b00001001); + + uint16_t maxProgressWidth = (width - doubleRadius + 1) * progress / 100; + + fillCircle(xRadius, yRadius, innerRadius); + fillRect(xRadius + 1, y + 2, maxProgressWidth, height - 3); + fillCircle(xRadius + maxProgressWidth, yRadius, innerRadius); +} + +void OLEDDisplay::drawFastImage(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const uint8_t *image) { + drawInternal(xMove, yMove, width, height, image, 0, 0); +} + +void OLEDDisplay::drawXbm(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const uint8_t *xbm) { + int16_t widthInXbm = (width + 7) / 8; + uint8_t data = 0; + + for(int16_t y = 0; y < height; y++) { + for(int16_t x = 0; x < width; x++ ) { + if (x & 7) { + data >>= 1; // Move a bit + } else { // Read new data every 8 bit + data = pgm_read_byte(xbm + (x / 8) + y * widthInXbm); + } + // if there is a bit draw it + if (data & 0x01) { + setPixel(xMove + x, yMove + y); + } + } + } +} + +void OLEDDisplay::drawIco16x16(int16_t xMove, int16_t yMove, const char *ico, bool inverse) { + uint16_t data; + + for(int16_t y = 0; y < 16; y++) { + data = pgm_read_byte(ico + (y << 1)) + (pgm_read_byte(ico + (y << 1) + 1) << 8); + for(int16_t x = 0; x < 16; x++ ) { + if ((data & 0x01) ^ inverse) { + setPixelColor(xMove + x, yMove + y, WHITE); + } else { + setPixelColor(xMove + x, yMove + y, BLACK); + } + data >>= 1; // Move a bit + } + } +} + +void OLEDDisplay::drawStringInternal(int16_t xMove, int16_t yMove, char* text, uint16_t textLength, uint16_t textWidth) { + uint8_t textHeight = pgm_read_byte(fontData + HEIGHT_POS); + uint8_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS); + uint16_t sizeOfJumpTable = pgm_read_byte(fontData + CHAR_NUM_POS) * JUMPTABLE_BYTES; + + uint16_t cursorX = 0; + uint16_t cursorY = 0; + + switch (textAlignment) { + case TEXT_ALIGN_CENTER_BOTH: + yMove -= textHeight >> 1; + // Fallthrough + case TEXT_ALIGN_CENTER: + xMove -= textWidth >> 1; // divide by 2 + break; + case TEXT_ALIGN_RIGHT: + xMove -= textWidth; + break; + case TEXT_ALIGN_LEFT: + break; + } + + // Don't draw anything if it is not on the screen. + if (xMove + textWidth < 0 || xMove > this->width() ) {return;} + if (yMove + textHeight < 0 || yMove > this->width() ) {return;} + + for (uint16_t j = 0; j < textLength; j++) { + int16_t xPos = xMove + cursorX; + int16_t yPos = yMove + cursorY; + + uint8_t code = text[j]; + if (code >= firstChar) { + uint8_t charCode = code - firstChar; + + // 4 Bytes per char code + uint8_t msbJumpToChar = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES ); // MSB \ JumpAddress + uint8_t lsbJumpToChar = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_LSB); // LSB / + uint8_t charByteSize = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_SIZE); // Size + uint8_t currentCharWidth = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_WIDTH); // Width + + // Test if the char is drawable + if (!(msbJumpToChar == 255 && lsbJumpToChar == 255)) { + // Get the position of the char data + uint16_t charDataPosition = JUMPTABLE_START + sizeOfJumpTable + ((msbJumpToChar << 8) + lsbJumpToChar); + drawInternal(xPos, yPos, currentCharWidth, textHeight, fontData, charDataPosition, charByteSize); + } + + cursorX += currentCharWidth; + } + } +} + + +void OLEDDisplay::drawString(int16_t xMove, int16_t yMove, String strUser) { + uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS); + + // char* text must be freed! + char* text = utf8ascii(strUser); + + uint16_t yOffset = 0; + // If the string should be centered vertically too + // we need to now how heigh the string is. + if (textAlignment == TEXT_ALIGN_CENTER_BOTH) { + uint16_t lb = 0; + // Find number of linebreaks in text + for (uint16_t i=0;text[i] != 0; i++) { + lb += (text[i] == 10); + } + // Calculate center + yOffset = (lb * lineHeight) / 2; + } + + uint16_t line = 0; + char* textPart = strtok(text,"\n"); + while (textPart != NULL) { + uint16_t length = strlen(textPart); + drawStringInternal(xMove, yMove - yOffset + (line++) * lineHeight, textPart, length, getStringWidth(textPart, length)); + textPart = strtok(NULL, "\n"); + } + free(text); +} + +void OLEDDisplay::drawStringf( int16_t x, int16_t y, char* buffer, String format, ... ) +{ + va_list myargs; + va_start(myargs, format); + vsprintf(buffer, format.c_str(), myargs); + va_end(myargs); + drawString( x, y, buffer ); +} + +void OLEDDisplay::drawStringMaxWidth(int16_t xMove, int16_t yMove, uint16_t maxLineWidth, String strUser) { + uint16_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS); + uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS); + + char* text = utf8ascii(strUser); + + uint16_t length = strlen(text); + uint16_t lastDrawnPos = 0; + uint16_t lineNumber = 0; + uint16_t strWidth = 0; + + uint16_t preferredBreakpoint = 0; + uint16_t widthAtBreakpoint = 0; + + for (uint16_t i = 0; i < length; i++) { + strWidth += pgm_read_byte(fontData + JUMPTABLE_START + (text[i] - firstChar) * JUMPTABLE_BYTES + JUMPTABLE_WIDTH); + + // Always try to break on a space or dash + if (text[i] == ' ' || text[i]== '-') { + preferredBreakpoint = i; + widthAtBreakpoint = strWidth; + } + + if (strWidth >= maxLineWidth) { + if (preferredBreakpoint == 0) { + preferredBreakpoint = i; + widthAtBreakpoint = strWidth; + } + drawStringInternal(xMove, yMove + (lineNumber++) * lineHeight , &text[lastDrawnPos], preferredBreakpoint - lastDrawnPos, widthAtBreakpoint); + lastDrawnPos = preferredBreakpoint + 1; + // It is possible that we did not draw all letters to i so we need + // to account for the width of the chars from `i - preferredBreakpoint` + // by calculating the width we did not draw yet. + strWidth = strWidth - widthAtBreakpoint; + preferredBreakpoint = 0; + } + } + + // Draw last part if needed + if (lastDrawnPos < length) { + drawStringInternal(xMove, yMove + lineNumber * lineHeight , &text[lastDrawnPos], length - lastDrawnPos, getStringWidth(&text[lastDrawnPos], length - lastDrawnPos)); + } + + free(text); +} + +uint16_t OLEDDisplay::getStringWidth(const char* text, uint16_t length) { + uint16_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS); + + uint16_t stringWidth = 0; + uint16_t maxWidth = 0; + + while (length--) { + stringWidth += pgm_read_byte(fontData + JUMPTABLE_START + (text[length] - firstChar) * JUMPTABLE_BYTES + JUMPTABLE_WIDTH); + if (text[length] == 10) { + maxWidth = max(maxWidth, stringWidth); + stringWidth = 0; + } + } + + return max(maxWidth, stringWidth); +} + +uint16_t OLEDDisplay::getStringWidth(String strUser) { + char* text = utf8ascii(strUser); + uint16_t length = strlen(text); + uint16_t width = getStringWidth(text, length); + free(text); + return width; +} + +void OLEDDisplay::setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT textAlignment) { + this->textAlignment = textAlignment; +} + +void OLEDDisplay::setFont(const uint8_t *fontData) { + this->fontData = fontData; +} + +void OLEDDisplay::displayOn(void) { + sendCommand(DISPLAYON); +} + +void OLEDDisplay::displayOff(void) { + sendCommand(DISPLAYOFF); +} + +void OLEDDisplay::invertDisplay(void) { + sendCommand(INVERTDISPLAY); +} + +void OLEDDisplay::normalDisplay(void) { + sendCommand(NORMALDISPLAY); +} + +void OLEDDisplay::setContrast(uint8_t contrast, uint8_t precharge, uint8_t comdetect) { + sendCommand(SETPRECHARGE); //0xD9 + sendCommand(precharge); //0xF1 default, to lower the contrast, put 1-1F + sendCommand(SETCONTRAST); + sendCommand(contrast); // 0-255 + sendCommand(SETVCOMDETECT); //0xDB, (additionally needed to lower the contrast) + sendCommand(comdetect); //0x40 default, to lower the contrast, put 0 + sendCommand(DISPLAYALLON_RESUME); + sendCommand(NORMALDISPLAY); + sendCommand(DISPLAYON); +} + +void OLEDDisplay::setBrightness(uint8_t brightness) { + uint8_t contrast = brightness; + if (brightness < 128) { + // Magic values to get a smooth/ step-free transition + contrast = brightness * 1.171; + } else { + contrast = brightness * 1.171 - 43; + } + + uint8_t precharge = 241; + if (brightness == 0) { + precharge = 0; + } + uint8_t comdetect = brightness / 8; + + setContrast(contrast, precharge, comdetect); +} + +void OLEDDisplay::resetOrientation() { + sendCommand(SEGREMAP); + sendCommand(COMSCANINC); //Reset screen rotation or mirroring +} + +void OLEDDisplay::flipScreenVertically() { + sendCommand(SEGREMAP | 0x01); + sendCommand(COMSCANDEC); //Rotate screen 180 Deg +} + +void OLEDDisplay::mirrorScreen() { + sendCommand(SEGREMAP); + sendCommand(COMSCANDEC); //Mirror screen +} + +void OLEDDisplay::clear(void) { + memset(buffer, 0, displayBufferSize); +} + +void OLEDDisplay::drawLogBuffer(uint16_t xMove, uint16_t yMove) { + uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS); + // Always align left + setTextAlignment(TEXT_ALIGN_LEFT); + + // State values + uint16_t length = 0; + uint16_t line = 0; + uint16_t lastPos = 0; + + for (uint16_t i=0;ilogBufferFilled;i++){ + // Everytime we have a \n print + if (this->logBuffer[i] == 10) { + length++; + // Draw string on line `line` from lastPos to length + // Passing 0 as the lenght because we are in TEXT_ALIGN_LEFT + drawStringInternal(xMove, yMove + (line++) * lineHeight, &this->logBuffer[lastPos], length, 0); + // Remember last pos + lastPos = i; + // Reset length + length = 0; + } else { + // Count chars until next linebreak + length++; + } + } + // Draw the remaining string + if (length > 0) { + drawStringInternal(xMove, yMove + line * lineHeight, &this->logBuffer[lastPos], length, 0); + } +} + +uint16_t OLEDDisplay::getWidth(void) { + return displayWidth; +} + +uint16_t OLEDDisplay::getHeight(void) { + return displayHeight; +} + +bool OLEDDisplay::setLogBuffer(uint16_t lines, uint16_t chars){ + if (logBuffer != NULL) free(logBuffer); + uint16_t size = lines * chars; + if (size > 0) { + this->logBufferLine = 0; // Lines printed + this->logBufferFilled = 0; // Nothing stored yet + this->logBufferMaxLines = lines; // Lines max printable + this->logBufferSize = size; // Total number of characters the buffer can hold + this->logBuffer = (char *) malloc(size * sizeof(uint8_t)); + if(!this->logBuffer) { + DEBUG_OLEDDISPLAY("[OLEDDISPLAY][setLogBuffer] Not enough memory to create log buffer\n"); + return false; + } + } + return true; +} + +size_t OLEDDisplay::write(uint8_t c) { + if (this->logBufferSize > 0) { + // Don't waste space on \r\n line endings, dropping \r + if (c == 13) return 1; + + // convert UTF-8 character to font table index + c = (this->fontTableLookupFunction)(c); + // drop unknown character + if (c == 0) return 1; + + bool maxLineNotReached = this->logBufferLine < this->logBufferMaxLines; + bool bufferNotFull = this->logBufferFilled < this->logBufferSize; + + // Can we write to the buffer? + if (bufferNotFull && maxLineNotReached) { + this->logBuffer[logBufferFilled] = c; + this->logBufferFilled++; + // Keep track of lines written + if (c == 10) this->logBufferLine++; + } else { + // Max line number is reached + if (!maxLineNotReached) this->logBufferLine--; + + // Find the end of the first line + uint16_t firstLineEnd = 0; + for (uint16_t i=0;ilogBufferFilled;i++) { + if (this->logBuffer[i] == 10){ + // Include last char too + firstLineEnd = i + 1; + break; + } + } + // If there was a line ending + if (firstLineEnd > 0) { + // Calculate the new logBufferFilled value + this->logBufferFilled = logBufferFilled - firstLineEnd; + // Now we move the lines infront of the buffer + memcpy(this->logBuffer, &this->logBuffer[firstLineEnd], logBufferFilled); + } else { + // Let's reuse the buffer if it was full + if (!bufferNotFull) { + this->logBufferFilled = 0; + }// else { + // Nothing to do here + //} + } + write(c); + } + } + // We are always writing all uint8_t to the buffer + return 1; +} + +size_t OLEDDisplay::write(const char* str) { + if (str == NULL) return 0; + size_t length = strlen(str); + for (size_t i = 0; i < length; i++) { + write(str[i]); + } + return length; +} + +#ifdef __MBED__ +int OLEDDisplay::_putc(int c) { + + if (!fontData) + return 1; + if (!logBufferSize) { + uint8_t textHeight = pgm_read_byte(fontData + HEIGHT_POS); + uint16_t lines = this->displayHeight / textHeight; + uint16_t chars = 2 * (this->displayWidth / textHeight); + + if (this->displayHeight % textHeight) + lines++; + if (this->displayWidth % textHeight) + chars++; + setLogBuffer(lines, chars); + } + + return this->write((uint8_t)c); +} +#endif + +// Private functions +void OLEDDisplay::setGeometry(OLEDDISPLAY_GEOMETRY g, uint16_t width, uint16_t height) { + this->geometry = g; + + switch (g) { + case GEOMETRY_128_64: + this->displayWidth = 128; + this->displayHeight = 64; + break; + case GEOMETRY_128_32: + this->displayWidth = 128; + this->displayHeight = 32; + break; + case GEOMETRY_64_48: + this->displayWidth = 64; + this->displayHeight = 48; + break; + case GEOMETRY_64_32: + this->displayWidth = 64; + this->displayHeight = 32; + break; + case GEOMETRY_RAWMODE: + this->displayWidth = width > 0 ? width : 128; + this->displayHeight = height > 0 ? height : 64; + break; + } + this->displayBufferSize = displayWidth * displayHeight / 8; +} + +void OLEDDisplay::sendInitCommands(void) { + if (geometry == GEOMETRY_RAWMODE) + return; + sendCommand(DISPLAYOFF); + sendCommand(SETDISPLAYCLOCKDIV); + sendCommand(0xF0); // Increase speed of the display max ~96Hz + sendCommand(SETMULTIPLEX); + sendCommand(this->height() - 1); + sendCommand(SETDISPLAYOFFSET); + sendCommand(0x00); + if(geometry == GEOMETRY_64_32) + sendCommand(0x00); + else + sendCommand(SETSTARTLINE); + sendCommand(CHARGEPUMP); + sendCommand(0x14); + sendCommand(MEMORYMODE); + sendCommand(0x00); + sendCommand(SEGREMAP); + sendCommand(COMSCANINC); + sendCommand(SETCOMPINS); + + if (geometry == GEOMETRY_128_64 || geometry == GEOMETRY_64_48 || geometry == GEOMETRY_64_32) { + sendCommand(0x12); + } else if (geometry == GEOMETRY_128_32) { + sendCommand(0x02); + } + + sendCommand(SETCONTRAST); + + if (geometry == GEOMETRY_128_64 || geometry == GEOMETRY_64_48 || geometry == GEOMETRY_64_32) { + sendCommand(0xCF); + } else if (geometry == GEOMETRY_128_32) { + sendCommand(0x8F); + } + + sendCommand(SETPRECHARGE); + sendCommand(0xF1); + sendCommand(SETVCOMDETECT); //0xDB, (additionally needed to lower the contrast) + sendCommand(0x40); //0x40 default, to lower the contrast, put 0 + sendCommand(DISPLAYALLON_RESUME); + sendCommand(NORMALDISPLAY); + sendCommand(0x2e); // stop scroll + sendCommand(DISPLAYON); +} + +void inline OLEDDisplay::drawInternal(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const uint8_t *data, uint16_t offset, uint16_t bytesInData) { + if (width < 0 || height < 0) return; + if (yMove + height < 0 || yMove > this->height()) return; + if (xMove + width < 0 || xMove > this->width()) return; + + uint8_t rasterHeight = 1 + ((height - 1) >> 3); // fast ceil(height / 8.0) + int8_t yOffset = yMove & 7; + + bytesInData = bytesInData == 0 ? width * rasterHeight : bytesInData; + + int16_t initYMove = yMove; + int8_t initYOffset = yOffset; + + + for (uint16_t i = 0; i < bytesInData; i++) { + + // Reset if next horizontal drawing phase is started. + if ( i % rasterHeight == 0) { + yMove = initYMove; + yOffset = initYOffset; + } + + uint8_t currentByte = pgm_read_byte(data + offset + i); + + int16_t xPos = xMove + (i / rasterHeight); + int16_t yPos = ((yMove >> 3) + (i % rasterHeight)) * this->width(); + +// int16_t yScreenPos = yMove + yOffset; + int16_t dataPos = xPos + yPos; + + if (dataPos >= 0 && dataPos < displayBufferSize && + xPos >= 0 && xPos < this->width() ) { + + if (yOffset >= 0) { + switch (this->color) { + case WHITE: buffer[dataPos] |= currentByte << yOffset; break; + case BLACK: buffer[dataPos] &= ~(currentByte << yOffset); break; + case INVERSE: buffer[dataPos] ^= currentByte << yOffset; break; + } + + if (dataPos < (displayBufferSize - this->width())) { + switch (this->color) { + case WHITE: buffer[dataPos + this->width()] |= currentByte >> (8 - yOffset); break; + case BLACK: buffer[dataPos + this->width()] &= ~(currentByte >> (8 - yOffset)); break; + case INVERSE: buffer[dataPos + this->width()] ^= currentByte >> (8 - yOffset); break; + } + } + } else { + // Make new offset position + yOffset = -yOffset; + + switch (this->color) { + case WHITE: buffer[dataPos] |= currentByte >> yOffset; break; + case BLACK: buffer[dataPos] &= ~(currentByte >> yOffset); break; + case INVERSE: buffer[dataPos] ^= currentByte >> yOffset; break; + } + + // Prepare for next iteration by moving one block up + yMove -= 8; + + // and setting the new yOffset + yOffset = 8 - yOffset; + } +#ifndef __MBED__ + yield(); +#endif + } + } +} + +// You need to free the char! +char* OLEDDisplay::utf8ascii(String str) { + uint16_t k = 0; + uint16_t length = str.length() + 1; + + // Copy the string into a char array + char* s = (char*) malloc(length * sizeof(char)); + if(!s) { + DEBUG_OLEDDISPLAY("[OLEDDISPLAY][utf8ascii] Can't allocate another char array. Drop support for UTF-8.\n"); + return (char*) str.c_str(); + } + str.toCharArray(s, length); + + length--; + + for (uint16_t i=0; i < length; i++) { + char c = (this->fontTableLookupFunction)(s[i]); + if (c!=0) { + s[k++]=c; + } + } + + s[k]=0; + + // This will leak 's' be sure to free it in the calling function. + return s; +} + +void OLEDDisplay::setFontTableLookupFunction(FontTableLookupFunction function) { + this->fontTableLookupFunction = function; +} + + +char DefaultFontTableLookup(const uint8_t ch) { + // UTF-8 to font table index converter + // Code form http://playground.arduino.cc/Main/Utf8ascii + static uint8_t LASTCHAR; + + if (ch < 128) { // Standard ASCII-set 0..0x7F handling + LASTCHAR = 0; + return ch; + } + + uint8_t last = LASTCHAR; // get last char + LASTCHAR = ch; + + switch (last) { // conversion depnding on first UTF8-character + case 0xC2: return (uint8_t) ch; + case 0xC3: return (uint8_t) (ch | 0xC0); + case 0x82: if (ch == 0xAC) return (uint8_t) 0x80; // special case Euro-symbol + } + + return (uint8_t) 0; // otherwise: return zero, if character has to be ignored +} diff --git a/lib/Display/OLEDDisplay.h b/lib/Display/OLEDDisplay.h new file mode 100644 index 0000000..80e4882 --- /dev/null +++ b/lib/Display/OLEDDisplay.h @@ -0,0 +1,343 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn + * Copyright (c) 2018 by Fabrice Weinberg + * Copyright (c) 2019 by Helmut Tschemernjak - www.radioshuttle.de + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ThingPulse invests considerable time and money to develop these open source libraries. + * Please support us by buying our products (and not the clones) from + * https://thingpulse.com + * + */ + +#ifndef OLEDDISPLAY_h +#define OLEDDISPLAY_h + +#include +#include "OLEDDisplayFonts.h" + +//#define DEBUG_OLEDDISPLAY(...) Serial.printf( __VA_ARGS__ ) +//#define DEBUG_OLEDDISPLAY(...) dprintf("%s", __VA_ARGS__ ) + +#ifndef DEBUG_OLEDDISPLAY +#define DEBUG_OLEDDISPLAY(...) +#endif + +// Use DOUBLE BUFFERING by default +#ifndef OLEDDISPLAY_REDUCE_MEMORY +#define OLEDDISPLAY_DOUBLE_BUFFER +#endif + +// Header Values +#define JUMPTABLE_BYTES 4 + +#define JUMPTABLE_LSB 1 +#define JUMPTABLE_SIZE 2 +#define JUMPTABLE_WIDTH 3 +#define JUMPTABLE_START 4 + +#define WIDTH_POS 0 +#define HEIGHT_POS 1 +#define FIRST_CHAR_POS 2 +#define CHAR_NUM_POS 3 + + +// Display commands +#define CHARGEPUMP 0x8D +#define COLUMNADDR 0x21 +#define COMSCANDEC 0xC8 +#define COMSCANINC 0xC0 +#define DISPLAYALLON 0xA5 +#define DISPLAYALLON_RESUME 0xA4 +#define DISPLAYOFF 0xAE +#define DISPLAYON 0xAF +#define EXTERNALVCC 0x1 +#define INVERTDISPLAY 0xA7 +#define MEMORYMODE 0x20 +#define NORMALDISPLAY 0xA6 +#define PAGEADDR 0x22 +#define SEGREMAP 0xA0 +#define SETCOMPINS 0xDA +#define SETCONTRAST 0x81 +#define SETDISPLAYCLOCKDIV 0xD5 +#define SETDISPLAYOFFSET 0xD3 +#define SETHIGHCOLUMN 0x10 +#define SETLOWCOLUMN 0x00 +#define SETMULTIPLEX 0xA8 +#define SETPRECHARGE 0xD9 +#define SETSEGMENTREMAP 0xA1 +#define SETSTARTLINE 0x40 +#define SETVCOMDETECT 0xDB +#define SWITCHCAPVCC 0x2 + +#ifndef _swap_int16_t +#define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; } +#endif + +enum OLEDDISPLAY_COLOR { + BLACK = 0, + WHITE = 1, + INVERSE = 2 +}; + +enum OLEDDISPLAY_TEXT_ALIGNMENT { + TEXT_ALIGN_LEFT = 0, + TEXT_ALIGN_RIGHT = 1, + TEXT_ALIGN_CENTER = 2, + TEXT_ALIGN_CENTER_BOTH = 3 +}; + + +enum OLEDDISPLAY_GEOMETRY { + GEOMETRY_128_64 = 0, + GEOMETRY_128_32 = 1, + GEOMETRY_64_48 = 2, + GEOMETRY_64_32 = 3, + GEOMETRY_RAWMODE = 4 +}; + +enum HW_I2C { + I2C_ONE, + I2C_TWO +}; + +typedef char (*FontTableLookupFunction)(const uint8_t ch); +char DefaultFontTableLookup(const uint8_t ch); + +class OLEDDisplay : public Print { + + public: + OLEDDisplay(); + virtual ~OLEDDisplay(); + + uint16_t width(void) const { return displayWidth; }; + uint16_t height(void) const { return displayHeight; }; + + // Use this to resume after a deep sleep without resetting the display (what init() would do). + // Returns true if connection to the display was established and the buffer allocated, false otherwise. + bool allocateBuffer(); + + // Allocates the buffer and initializes the driver & display. Resets the display! + // Returns false if buffer allocation failed, true otherwise. + bool init(); + + // Free the memory used by the display + void end(); + + // Cycle through the initialization + void resetDisplay(void); + + /* Drawing functions */ + // Sets the color of all pixel operations + void setColor(OLEDDISPLAY_COLOR color); + + // Returns the current color. + OLEDDISPLAY_COLOR getColor(); + + // Draw a pixel at given position + void setPixel(int16_t x, int16_t y); + + // Draw a pixel at given position and color + void setPixelColor(int16_t x, int16_t y, OLEDDISPLAY_COLOR color); + + // Clear a pixel at given position FIXME: INVERSE is untested with this function + void clearPixel(int16_t x, int16_t y); + + // Draw a line from position 0 to position 1 + void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1); + + // Draw the border of a rectangle at the given location + void drawRect(int16_t x, int16_t y, int16_t width, int16_t height); + + // Fill the rectangle + void fillRect(int16_t x, int16_t y, int16_t width, int16_t height); + + // Draw the border of a circle + void drawCircle(int16_t x, int16_t y, int16_t radius); + + // Draw all Quadrants specified in the quads bit mask + void drawCircleQuads(int16_t x0, int16_t y0, int16_t radius, uint8_t quads); + + // Fill circle + void fillCircle(int16_t x, int16_t y, int16_t radius); + + // Draw a line horizontally + void drawHorizontalLine(int16_t x, int16_t y, int16_t length); + + // Draw a line vertically + void drawVerticalLine(int16_t x, int16_t y, int16_t length); + + // Draws a rounded progress bar with the outer dimensions given by width and height. Progress is + // a unsigned byte value between 0 and 100 + void drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t progress); + + // Draw a bitmap in the internal image format + void drawFastImage(int16_t x, int16_t y, int16_t width, int16_t height, const uint8_t *image); + + // Draw a XBM + void drawXbm(int16_t x, int16_t y, int16_t width, int16_t height, const uint8_t *xbm); + + // Draw icon 16x16 xbm format + void drawIco16x16(int16_t x, int16_t y, const char *ico, bool inverse = false); + + /* Text functions */ + + // Draws a string at the given location + void drawString(int16_t x, int16_t y, String text); + + // Draws a formatted string (like printf) at the given location + void drawStringf(int16_t x, int16_t y, char* buffer, String format, ... ); + + // Draws a String with a maximum width at the given location. + // If the given String is wider than the specified width + // The text will be wrapped to the next line at a space or dash + void drawStringMaxWidth(int16_t x, int16_t y, uint16_t maxLineWidth, String text); + + // Returns the width of the const char* with the current + // font settings + uint16_t getStringWidth(const char* text, uint16_t length); + + // Convencience method for the const char version + uint16_t getStringWidth(String text); + + // Specifies relative to which anchor point + // the text is rendered. Available constants: + // TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER_BOTH + void setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT textAlignment); + + // Sets the current font. Available default fonts + // ArialMT_Plain_10, ArialMT_Plain_16, ArialMT_Plain_24 + void setFont(const uint8_t *fontData); + + // Set the function that will convert utf-8 to font table index + void setFontTableLookupFunction(FontTableLookupFunction function); + + /* Display functions */ + + // Turn the display on + void displayOn(void); + + // Turn the display offs + void displayOff(void); + + // Inverted display mode + void invertDisplay(void); + + // Normal display mode + void normalDisplay(void); + + // Set display contrast + // really low brightness & contrast: contrast = 10, precharge = 5, comdetect = 0 + // normal brightness & contrast: contrast = 100 + void setContrast(uint8_t contrast, uint8_t precharge = 241, uint8_t comdetect = 64); + + // Convenience method to access + void setBrightness(uint8_t); + + // Reset display rotation or mirroring + void resetOrientation(); + + // Turn the display upside down + void flipScreenVertically(); + + // Mirror the display (to be used in a mirror or as a projector) + void mirrorScreen(); + + // Write the buffer to the display memory + virtual void display(void) = 0; + + // Clear the local pixel buffer + void clear(void); + + // Log buffer implementation + + // This will define the lines and characters you can + // print to the screen. When you exeed the buffer size (lines * chars) + // the output may be truncated due to the size constraint. + bool setLogBuffer(uint16_t lines, uint16_t chars); + + // Draw the log buffer at position (x, y) + void drawLogBuffer(uint16_t x, uint16_t y); + + // Get screen geometry + uint16_t getWidth(void); + uint16_t getHeight(void); + + // Implement needed function to be compatible with Print class + size_t write(uint8_t c); + size_t write(const char* s); + + + uint8_t *buffer; + + #ifdef OLEDDISPLAY_DOUBLE_BUFFER + uint8_t *buffer_back; + #endif + + protected: + + OLEDDISPLAY_GEOMETRY geometry; + + uint16_t displayWidth; + uint16_t displayHeight; + uint16_t displayBufferSize; + + // Set the correct height, width and buffer for the geometry + void setGeometry(OLEDDISPLAY_GEOMETRY g, uint16_t width = 0, uint16_t height = 0); + + OLEDDISPLAY_TEXT_ALIGNMENT textAlignment; + OLEDDISPLAY_COLOR color; + + const uint8_t *fontData; + + // State values for logBuffer + uint16_t logBufferSize; + uint16_t logBufferFilled; + uint16_t logBufferLine; + uint16_t logBufferMaxLines; + char *logBuffer; + + + // the header size of the buffer used, e.g. for the SPI command header + int BufferOffset; + virtual int getBufferOffset(void) = 0; + + // Send a command to the display (low level function) + virtual void sendCommand(uint8_t com) {(void)com;}; + + // Connect to the display + virtual bool connect() { return false; }; + + // Send all the init commands + void sendInitCommands(); + + // converts utf8 characters to extended ascii + char* utf8ascii(String s); + + void inline drawInternal(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const uint8_t *data, uint16_t offset, uint16_t bytesInData) __attribute__((always_inline)); + + void drawStringInternal(int16_t xMove, int16_t yMove, char* text, uint16_t textLength, uint16_t textWidth); + + FontTableLookupFunction fontTableLookupFunction; +}; + +#endif diff --git a/lib/Display/OLEDDisplayFonts.h b/lib/Display/OLEDDisplayFonts.h new file mode 100644 index 0000000..3544edb --- /dev/null +++ b/lib/Display/OLEDDisplayFonts.h @@ -0,0 +1,1274 @@ +#ifndef OLEDDISPLAYFONTS_h +#define OLEDDISPLAYFONTS_h + +const uint8_t ArialMT_Plain_10[] PROGMEM = { + 0x0A, // Width: 10 + 0x0D, // Height: 13 + 0x20, // First Char: 32 + 0xE0, // Numbers of Chars: 224 + + // Jump Table: + 0xFF, 0xFF, 0x00, 0x03, // 32:65535 + 0x00, 0x00, 0x04, 0x03, // 33:0 + 0x00, 0x04, 0x05, 0x04, // 34:4 + 0x00, 0x09, 0x09, 0x06, // 35:9 + 0x00, 0x12, 0x0A, 0x06, // 36:18 + 0x00, 0x1C, 0x10, 0x09, // 37:28 + 0x00, 0x2C, 0x0E, 0x07, // 38:44 + 0x00, 0x3A, 0x01, 0x02, // 39:58 + 0x00, 0x3B, 0x06, 0x03, // 40:59 + 0x00, 0x41, 0x06, 0x03, // 41:65 + 0x00, 0x47, 0x05, 0x04, // 42:71 + 0x00, 0x4C, 0x09, 0x06, // 43:76 + 0x00, 0x55, 0x04, 0x03, // 44:85 + 0x00, 0x59, 0x03, 0x03, // 45:89 + 0x00, 0x5C, 0x04, 0x03, // 46:92 + 0x00, 0x60, 0x05, 0x03, // 47:96 + 0x00, 0x65, 0x0A, 0x06, // 48:101 + 0x00, 0x6F, 0x08, 0x06, // 49:111 + 0x00, 0x77, 0x0A, 0x06, // 50:119 + 0x00, 0x81, 0x0A, 0x06, // 51:129 + 0x00, 0x8B, 0x0B, 0x06, // 52:139 + 0x00, 0x96, 0x0A, 0x06, // 53:150 + 0x00, 0xA0, 0x0A, 0x06, // 54:160 + 0x00, 0xAA, 0x09, 0x06, // 55:170 + 0x00, 0xB3, 0x0A, 0x06, // 56:179 + 0x00, 0xBD, 0x0A, 0x06, // 57:189 + 0x00, 0xC7, 0x04, 0x03, // 58:199 + 0x00, 0xCB, 0x04, 0x03, // 59:203 + 0x00, 0xCF, 0x0A, 0x06, // 60:207 + 0x00, 0xD9, 0x09, 0x06, // 61:217 + 0x00, 0xE2, 0x09, 0x06, // 62:226 + 0x00, 0xEB, 0x0B, 0x06, // 63:235 + 0x00, 0xF6, 0x14, 0x0A, // 64:246 + 0x01, 0x0A, 0x0E, 0x07, // 65:266 + 0x01, 0x18, 0x0C, 0x07, // 66:280 + 0x01, 0x24, 0x0C, 0x07, // 67:292 + 0x01, 0x30, 0x0B, 0x07, // 68:304 + 0x01, 0x3B, 0x0C, 0x07, // 69:315 + 0x01, 0x47, 0x09, 0x06, // 70:327 + 0x01, 0x50, 0x0D, 0x08, // 71:336 + 0x01, 0x5D, 0x0C, 0x07, // 72:349 + 0x01, 0x69, 0x04, 0x03, // 73:361 + 0x01, 0x6D, 0x08, 0x05, // 74:365 + 0x01, 0x75, 0x0E, 0x07, // 75:373 + 0x01, 0x83, 0x0C, 0x06, // 76:387 + 0x01, 0x8F, 0x10, 0x08, // 77:399 + 0x01, 0x9F, 0x0C, 0x07, // 78:415 + 0x01, 0xAB, 0x0E, 0x08, // 79:427 + 0x01, 0xB9, 0x0B, 0x07, // 80:441 + 0x01, 0xC4, 0x0E, 0x08, // 81:452 + 0x01, 0xD2, 0x0C, 0x07, // 82:466 + 0x01, 0xDE, 0x0C, 0x07, // 83:478 + 0x01, 0xEA, 0x0B, 0x06, // 84:490 + 0x01, 0xF5, 0x0C, 0x07, // 85:501 + 0x02, 0x01, 0x0D, 0x07, // 86:513 + 0x02, 0x0E, 0x11, 0x09, // 87:526 + 0x02, 0x1F, 0x0E, 0x07, // 88:543 + 0x02, 0x2D, 0x0D, 0x07, // 89:557 + 0x02, 0x3A, 0x0C, 0x06, // 90:570 + 0x02, 0x46, 0x06, 0x03, // 91:582 + 0x02, 0x4C, 0x06, 0x03, // 92:588 + 0x02, 0x52, 0x04, 0x03, // 93:594 + 0x02, 0x56, 0x09, 0x05, // 94:598 + 0x02, 0x5F, 0x0C, 0x06, // 95:607 + 0x02, 0x6B, 0x03, 0x03, // 96:619 + 0x02, 0x6E, 0x0A, 0x06, // 97:622 + 0x02, 0x78, 0x0A, 0x06, // 98:632 + 0x02, 0x82, 0x0A, 0x05, // 99:642 + 0x02, 0x8C, 0x0A, 0x06, // 100:652 + 0x02, 0x96, 0x0A, 0x06, // 101:662 + 0x02, 0xA0, 0x05, 0x03, // 102:672 + 0x02, 0xA5, 0x0A, 0x06, // 103:677 + 0x02, 0xAF, 0x0A, 0x06, // 104:687 + 0x02, 0xB9, 0x04, 0x02, // 105:697 + 0x02, 0xBD, 0x04, 0x02, // 106:701 + 0x02, 0xC1, 0x08, 0x05, // 107:705 + 0x02, 0xC9, 0x04, 0x02, // 108:713 + 0x02, 0xCD, 0x10, 0x08, // 109:717 + 0x02, 0xDD, 0x0A, 0x06, // 110:733 + 0x02, 0xE7, 0x0A, 0x06, // 111:743 + 0x02, 0xF1, 0x0A, 0x06, // 112:753 + 0x02, 0xFB, 0x0A, 0x06, // 113:763 + 0x03, 0x05, 0x05, 0x03, // 114:773 + 0x03, 0x0A, 0x08, 0x05, // 115:778 + 0x03, 0x12, 0x06, 0x03, // 116:786 + 0x03, 0x18, 0x0A, 0x06, // 117:792 + 0x03, 0x22, 0x09, 0x05, // 118:802 + 0x03, 0x2B, 0x0E, 0x07, // 119:811 + 0x03, 0x39, 0x0A, 0x05, // 120:825 + 0x03, 0x43, 0x09, 0x05, // 121:835 + 0x03, 0x4C, 0x0A, 0x05, // 122:844 + 0x03, 0x56, 0x06, 0x03, // 123:854 + 0x03, 0x5C, 0x04, 0x03, // 124:860 + 0x03, 0x60, 0x05, 0x03, // 125:864 + 0x03, 0x65, 0x09, 0x06, // 126:869 + 0xFF, 0xFF, 0x00, 0x00, // 127:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 128:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 129:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 130:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 131:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 132:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 133:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 134:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 135:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 136:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 137:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 138:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 139:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 140:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 141:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 142:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 143:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 144:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 145:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 146:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 147:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 148:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 149:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 150:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 151:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 152:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 153:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 154:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 155:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 156:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 157:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 158:65535 + 0xFF, 0xFF, 0x00, 0x0A, // 159:65535 + 0xFF, 0xFF, 0x00, 0x03, // 160:65535 + 0x03, 0x6E, 0x04, 0x03, // 161:878 + 0x03, 0x72, 0x0A, 0x06, // 162:882 + 0x03, 0x7C, 0x0C, 0x06, // 163:892 + 0x03, 0x88, 0x0A, 0x06, // 164:904 + 0x03, 0x92, 0x0A, 0x06, // 165:914 + 0x03, 0x9C, 0x04, 0x03, // 166:924 + 0x03, 0xA0, 0x0A, 0x06, // 167:928 + 0x03, 0xAA, 0x05, 0x03, // 168:938 + 0x03, 0xAF, 0x0D, 0x07, // 169:943 + 0x03, 0xBC, 0x07, 0x04, // 170:956 + 0x03, 0xC3, 0x0A, 0x06, // 171:963 + 0x03, 0xCD, 0x09, 0x06, // 172:973 + 0x03, 0xD6, 0x03, 0x03, // 173:982 + 0x03, 0xD9, 0x0D, 0x07, // 174:985 + 0x03, 0xE6, 0x0B, 0x06, // 175:998 + 0x03, 0xF1, 0x07, 0x04, // 176:1009 + 0x03, 0xF8, 0x0A, 0x05, // 177:1016 + 0x04, 0x02, 0x05, 0x03, // 178:1026 + 0x04, 0x07, 0x05, 0x03, // 179:1031 + 0x04, 0x0C, 0x05, 0x03, // 180:1036 + 0x04, 0x11, 0x0A, 0x06, // 181:1041 + 0x04, 0x1B, 0x09, 0x05, // 182:1051 + 0x04, 0x24, 0x03, 0x03, // 183:1060 + 0x04, 0x27, 0x06, 0x03, // 184:1063 + 0x04, 0x2D, 0x05, 0x03, // 185:1069 + 0x04, 0x32, 0x07, 0x04, // 186:1074 + 0x04, 0x39, 0x0A, 0x06, // 187:1081 + 0x04, 0x43, 0x10, 0x08, // 188:1091 + 0x04, 0x53, 0x10, 0x08, // 189:1107 + 0x04, 0x63, 0x10, 0x08, // 190:1123 + 0x04, 0x73, 0x0A, 0x06, // 191:1139 + 0x04, 0x7D, 0x0E, 0x07, // 192:1149 + 0x04, 0x8B, 0x0E, 0x07, // 193:1163 + 0x04, 0x99, 0x0E, 0x07, // 194:1177 + 0x04, 0xA7, 0x0E, 0x07, // 195:1191 + 0x04, 0xB5, 0x0E, 0x07, // 196:1205 + 0x04, 0xC3, 0x0E, 0x07, // 197:1219 + 0x04, 0xD1, 0x12, 0x0A, // 198:1233 + 0x04, 0xE3, 0x0C, 0x07, // 199:1251 + 0x04, 0xEF, 0x0C, 0x07, // 200:1263 + 0x04, 0xFB, 0x0C, 0x07, // 201:1275 + 0x05, 0x07, 0x0C, 0x07, // 202:1287 + 0x05, 0x13, 0x0C, 0x07, // 203:1299 + 0x05, 0x1F, 0x05, 0x03, // 204:1311 + 0x05, 0x24, 0x04, 0x03, // 205:1316 + 0x05, 0x28, 0x04, 0x03, // 206:1320 + 0x05, 0x2C, 0x05, 0x03, // 207:1324 + 0x05, 0x31, 0x0B, 0x07, // 208:1329 + 0x05, 0x3C, 0x0C, 0x07, // 209:1340 + 0x05, 0x48, 0x0E, 0x08, // 210:1352 + 0x05, 0x56, 0x0E, 0x08, // 211:1366 + 0x05, 0x64, 0x0E, 0x08, // 212:1380 + 0x05, 0x72, 0x0E, 0x08, // 213:1394 + 0x05, 0x80, 0x0E, 0x08, // 214:1408 + 0x05, 0x8E, 0x0A, 0x06, // 215:1422 + 0x05, 0x98, 0x0D, 0x08, // 216:1432 + 0x05, 0xA5, 0x0C, 0x07, // 217:1445 + 0x05, 0xB1, 0x0C, 0x07, // 218:1457 + 0x05, 0xBD, 0x0C, 0x07, // 219:1469 + 0x05, 0xC9, 0x0C, 0x07, // 220:1481 + 0x05, 0xD5, 0x0D, 0x07, // 221:1493 + 0x05, 0xE2, 0x0B, 0x07, // 222:1506 + 0x05, 0xED, 0x0C, 0x06, // 223:1517 + 0x05, 0xF9, 0x0A, 0x06, // 224:1529 + 0x06, 0x03, 0x0A, 0x06, // 225:1539 + 0x06, 0x0D, 0x0A, 0x06, // 226:1549 + 0x06, 0x17, 0x0A, 0x06, // 227:1559 + 0x06, 0x21, 0x0A, 0x06, // 228:1569 + 0x06, 0x2B, 0x0A, 0x06, // 229:1579 + 0x06, 0x35, 0x10, 0x09, // 230:1589 + 0x06, 0x45, 0x0A, 0x05, // 231:1605 + 0x06, 0x4F, 0x0A, 0x06, // 232:1615 + 0x06, 0x59, 0x0A, 0x06, // 233:1625 + 0x06, 0x63, 0x0A, 0x06, // 234:1635 + 0x06, 0x6D, 0x0A, 0x06, // 235:1645 + 0x06, 0x77, 0x05, 0x03, // 236:1655 + 0x06, 0x7C, 0x04, 0x03, // 237:1660 + 0x06, 0x80, 0x05, 0x03, // 238:1664 + 0x06, 0x85, 0x05, 0x03, // 239:1669 + 0x06, 0x8A, 0x0A, 0x06, // 240:1674 + 0x06, 0x94, 0x0A, 0x06, // 241:1684 + 0x06, 0x9E, 0x0A, 0x06, // 242:1694 + 0x06, 0xA8, 0x0A, 0x06, // 243:1704 + 0x06, 0xB2, 0x0A, 0x06, // 244:1714 + 0x06, 0xBC, 0x0A, 0x06, // 245:1724 + 0x06, 0xC6, 0x0A, 0x06, // 246:1734 + 0x06, 0xD0, 0x09, 0x05, // 247:1744 + 0x06, 0xD9, 0x0A, 0x06, // 248:1753 + 0x06, 0xE3, 0x0A, 0x06, // 249:1763 + 0x06, 0xED, 0x0A, 0x06, // 250:1773 + 0x06, 0xF7, 0x0A, 0x06, // 251:1783 + 0x07, 0x01, 0x0A, 0x06, // 252:1793 + 0x07, 0x0B, 0x09, 0x05, // 253:1803 + 0x07, 0x14, 0x0A, 0x06, // 254:1812 + 0x07, 0x1E, 0x09, 0x05, // 255:1822 + + // Font Data: + 0x00,0x00,0xF8,0x02, // 33 + 0x38,0x00,0x00,0x00,0x38, // 34 + 0xA0,0x03,0xE0,0x00,0xB8,0x03,0xE0,0x00,0xB8, // 35 + 0x30,0x01,0x28,0x02,0xF8,0x07,0x48,0x02,0x90,0x01, // 36 + 0x00,0x00,0x30,0x00,0x48,0x00,0x30,0x03,0xC0,0x00,0xB0,0x01,0x48,0x02,0x80,0x01, // 37 + 0x80,0x01,0x50,0x02,0x68,0x02,0xA8,0x02,0x18,0x01,0x80,0x03,0x80,0x02, // 38 + 0x38, // 39 + 0xE0,0x03,0x10,0x04,0x08,0x08, // 40 + 0x08,0x08,0x10,0x04,0xE0,0x03, // 41 + 0x28,0x00,0x18,0x00,0x28, // 42 + 0x40,0x00,0x40,0x00,0xF0,0x01,0x40,0x00,0x40, // 43 + 0x00,0x00,0x00,0x06, // 44 + 0x80,0x00,0x80, // 45 + 0x00,0x00,0x00,0x02, // 46 + 0x00,0x03,0xE0,0x00,0x18, // 47 + 0xF0,0x01,0x08,0x02,0x08,0x02,0x08,0x02,0xF0,0x01, // 48 + 0x00,0x00,0x20,0x00,0x10,0x00,0xF8,0x03, // 49 + 0x10,0x02,0x08,0x03,0x88,0x02,0x48,0x02,0x30,0x02, // 50 + 0x10,0x01,0x08,0x02,0x48,0x02,0x48,0x02,0xB0,0x01, // 51 + 0xC0,0x00,0xA0,0x00,0x90,0x00,0x88,0x00,0xF8,0x03,0x80, // 52 + 0x60,0x01,0x38,0x02,0x28,0x02,0x28,0x02,0xC8,0x01, // 53 + 0xF0,0x01,0x28,0x02,0x28,0x02,0x28,0x02,0xD0,0x01, // 54 + 0x08,0x00,0x08,0x03,0xC8,0x00,0x38,0x00,0x08, // 55 + 0xB0,0x01,0x48,0x02,0x48,0x02,0x48,0x02,0xB0,0x01, // 56 + 0x70,0x01,0x88,0x02,0x88,0x02,0x88,0x02,0xF0,0x01, // 57 + 0x00,0x00,0x20,0x02, // 58 + 0x00,0x00,0x20,0x06, // 59 + 0x00,0x00,0x40,0x00,0xA0,0x00,0xA0,0x00,0x10,0x01, // 60 + 0xA0,0x00,0xA0,0x00,0xA0,0x00,0xA0,0x00,0xA0, // 61 + 0x00,0x00,0x10,0x01,0xA0,0x00,0xA0,0x00,0x40, // 62 + 0x10,0x00,0x08,0x00,0x08,0x00,0xC8,0x02,0x48,0x00,0x30, // 63 + 0x00,0x00,0xC0,0x03,0x30,0x04,0xD0,0x09,0x28,0x0A,0x28,0x0A,0xC8,0x0B,0x68,0x0A,0x10,0x05,0xE0,0x04, // 64 + 0x00,0x02,0xC0,0x01,0xB0,0x00,0x88,0x00,0xB0,0x00,0xC0,0x01,0x00,0x02, // 65 + 0x00,0x00,0xF8,0x03,0x48,0x02,0x48,0x02,0x48,0x02,0xF0,0x01, // 66 + 0x00,0x00,0xF0,0x01,0x08,0x02,0x08,0x02,0x08,0x02,0x10,0x01, // 67 + 0x00,0x00,0xF8,0x03,0x08,0x02,0x08,0x02,0x10,0x01,0xE0, // 68 + 0x00,0x00,0xF8,0x03,0x48,0x02,0x48,0x02,0x48,0x02,0x48,0x02, // 69 + 0x00,0x00,0xF8,0x03,0x48,0x00,0x48,0x00,0x08, // 70 + 0x00,0x00,0xE0,0x00,0x10,0x01,0x08,0x02,0x48,0x02,0x50,0x01,0xC0, // 71 + 0x00,0x00,0xF8,0x03,0x40,0x00,0x40,0x00,0x40,0x00,0xF8,0x03, // 72 + 0x00,0x00,0xF8,0x03, // 73 + 0x00,0x03,0x00,0x02,0x00,0x02,0xF8,0x01, // 74 + 0x00,0x00,0xF8,0x03,0x80,0x00,0x60,0x00,0x90,0x00,0x08,0x01,0x00,0x02, // 75 + 0x00,0x00,0xF8,0x03,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02, // 76 + 0x00,0x00,0xF8,0x03,0x30,0x00,0xC0,0x01,0x00,0x02,0xC0,0x01,0x30,0x00,0xF8,0x03, // 77 + 0x00,0x00,0xF8,0x03,0x30,0x00,0x40,0x00,0x80,0x01,0xF8,0x03, // 78 + 0x00,0x00,0xF0,0x01,0x08,0x02,0x08,0x02,0x08,0x02,0x08,0x02,0xF0,0x01, // 79 + 0x00,0x00,0xF8,0x03,0x48,0x00,0x48,0x00,0x48,0x00,0x30, // 80 + 0x00,0x00,0xF0,0x01,0x08,0x02,0x08,0x02,0x08,0x03,0x08,0x03,0xF0,0x02, // 81 + 0x00,0x00,0xF8,0x03,0x48,0x00,0x48,0x00,0xC8,0x00,0x30,0x03, // 82 + 0x00,0x00,0x30,0x01,0x48,0x02,0x48,0x02,0x48,0x02,0x90,0x01, // 83 + 0x00,0x00,0x08,0x00,0x08,0x00,0xF8,0x03,0x08,0x00,0x08, // 84 + 0x00,0x00,0xF8,0x01,0x00,0x02,0x00,0x02,0x00,0x02,0xF8,0x01, // 85 + 0x08,0x00,0x70,0x00,0x80,0x01,0x00,0x02,0x80,0x01,0x70,0x00,0x08, // 86 + 0x18,0x00,0xE0,0x01,0x00,0x02,0xF0,0x01,0x08,0x00,0xF0,0x01,0x00,0x02,0xE0,0x01,0x18, // 87 + 0x00,0x02,0x08,0x01,0x90,0x00,0x60,0x00,0x90,0x00,0x08,0x01,0x00,0x02, // 88 + 0x08,0x00,0x10,0x00,0x20,0x00,0xC0,0x03,0x20,0x00,0x10,0x00,0x08, // 89 + 0x08,0x03,0x88,0x02,0xC8,0x02,0x68,0x02,0x38,0x02,0x18,0x02, // 90 + 0x00,0x00,0xF8,0x0F,0x08,0x08, // 91 + 0x18,0x00,0xE0,0x00,0x00,0x03, // 92 + 0x08,0x08,0xF8,0x0F, // 93 + 0x40,0x00,0x30,0x00,0x08,0x00,0x30,0x00,0x40, // 94 + 0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08, // 95 + 0x08,0x00,0x10, // 96 + 0x00,0x00,0x00,0x03,0xA0,0x02,0xA0,0x02,0xE0,0x03, // 97 + 0x00,0x00,0xF8,0x03,0x20,0x02,0x20,0x02,0xC0,0x01, // 98 + 0x00,0x00,0xC0,0x01,0x20,0x02,0x20,0x02,0x40,0x01, // 99 + 0x00,0x00,0xC0,0x01,0x20,0x02,0x20,0x02,0xF8,0x03, // 100 + 0x00,0x00,0xC0,0x01,0xA0,0x02,0xA0,0x02,0xC0,0x02, // 101 + 0x20,0x00,0xF0,0x03,0x28, // 102 + 0x00,0x00,0xC0,0x05,0x20,0x0A,0x20,0x0A,0xE0,0x07, // 103 + 0x00,0x00,0xF8,0x03,0x20,0x00,0x20,0x00,0xC0,0x03, // 104 + 0x00,0x00,0xE8,0x03, // 105 + 0x00,0x08,0xE8,0x07, // 106 + 0xF8,0x03,0x80,0x00,0xC0,0x01,0x20,0x02, // 107 + 0x00,0x00,0xF8,0x03, // 108 + 0x00,0x00,0xE0,0x03,0x20,0x00,0x20,0x00,0xE0,0x03,0x20,0x00,0x20,0x00,0xC0,0x03, // 109 + 0x00,0x00,0xE0,0x03,0x20,0x00,0x20,0x00,0xC0,0x03, // 110 + 0x00,0x00,0xC0,0x01,0x20,0x02,0x20,0x02,0xC0,0x01, // 111 + 0x00,0x00,0xE0,0x0F,0x20,0x02,0x20,0x02,0xC0,0x01, // 112 + 0x00,0x00,0xC0,0x01,0x20,0x02,0x20,0x02,0xE0,0x0F, // 113 + 0x00,0x00,0xE0,0x03,0x20, // 114 + 0x40,0x02,0xA0,0x02,0xA0,0x02,0x20,0x01, // 115 + 0x20,0x00,0xF8,0x03,0x20,0x02, // 116 + 0x00,0x00,0xE0,0x01,0x00,0x02,0x00,0x02,0xE0,0x03, // 117 + 0x20,0x00,0xC0,0x01,0x00,0x02,0xC0,0x01,0x20, // 118 + 0xE0,0x01,0x00,0x02,0xC0,0x01,0x20,0x00,0xC0,0x01,0x00,0x02,0xE0,0x01, // 119 + 0x20,0x02,0x40,0x01,0x80,0x00,0x40,0x01,0x20,0x02, // 120 + 0x20,0x00,0xC0,0x09,0x00,0x06,0xC0,0x01,0x20, // 121 + 0x20,0x02,0x20,0x03,0xA0,0x02,0x60,0x02,0x20,0x02, // 122 + 0x80,0x00,0x78,0x0F,0x08,0x08, // 123 + 0x00,0x00,0xF8,0x0F, // 124 + 0x08,0x08,0x78,0x0F,0x80, // 125 + 0xC0,0x00,0x40,0x00,0xC0,0x00,0x80,0x00,0xC0, // 126 + 0x00,0x00,0xA0,0x0F, // 161 + 0x00,0x00,0xC0,0x01,0xA0,0x0F,0x78,0x02,0x40,0x01, // 162 + 0x40,0x02,0x70,0x03,0xC8,0x02,0x48,0x02,0x08,0x02,0x10,0x02, // 163 + 0x00,0x00,0xE0,0x01,0x20,0x01,0x20,0x01,0xE0,0x01, // 164 + 0x48,0x01,0x70,0x01,0xC0,0x03,0x70,0x01,0x48,0x01, // 165 + 0x00,0x00,0x38,0x0F, // 166 + 0xD0,0x04,0x28,0x09,0x48,0x09,0x48,0x0A,0x90,0x05, // 167 + 0x08,0x00,0x00,0x00,0x08, // 168 + 0xE0,0x00,0x10,0x01,0x48,0x02,0xA8,0x02,0xA8,0x02,0x10,0x01,0xE0, // 169 + 0x68,0x00,0x68,0x00,0x68,0x00,0x78, // 170 + 0x00,0x00,0x80,0x01,0x40,0x02,0x80,0x01,0x40,0x02, // 171 + 0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0xE0, // 172 + 0x80,0x00,0x80, // 173 + 0xE0,0x00,0x10,0x01,0xE8,0x02,0x68,0x02,0xC8,0x02,0x10,0x01,0xE0, // 174 + 0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02, // 175 + 0x00,0x00,0x38,0x00,0x28,0x00,0x38, // 176 + 0x40,0x02,0x40,0x02,0xF0,0x03,0x40,0x02,0x40,0x02, // 177 + 0x48,0x00,0x68,0x00,0x58, // 178 + 0x48,0x00,0x58,0x00,0x68, // 179 + 0x00,0x00,0x10,0x00,0x08, // 180 + 0x00,0x00,0xE0,0x0F,0x00,0x02,0x00,0x02,0xE0,0x03, // 181 + 0x70,0x00,0xF8,0x0F,0x08,0x00,0xF8,0x0F,0x08, // 182 + 0x00,0x00,0x40, // 183 + 0x00,0x00,0x00,0x14,0x00,0x18, // 184 + 0x00,0x00,0x10,0x00,0x78, // 185 + 0x30,0x00,0x48,0x00,0x48,0x00,0x30, // 186 + 0x00,0x00,0x40,0x02,0x80,0x01,0x40,0x02,0x80,0x01, // 187 + 0x00,0x00,0x10,0x02,0x78,0x01,0xC0,0x00,0x20,0x01,0x90,0x01,0xC8,0x03,0x00,0x01, // 188 + 0x00,0x00,0x10,0x02,0x78,0x01,0x80,0x00,0x60,0x00,0x50,0x02,0x48,0x03,0xC0,0x02, // 189 + 0x48,0x00,0x58,0x00,0x68,0x03,0x80,0x00,0x60,0x01,0x90,0x01,0xC8,0x03,0x00,0x01, // 190 + 0x00,0x00,0x00,0x06,0x00,0x09,0xA0,0x09,0x00,0x04, // 191 + 0x00,0x02,0xC0,0x01,0xB0,0x00,0x89,0x00,0xB2,0x00,0xC0,0x01,0x00,0x02, // 192 + 0x00,0x02,0xC0,0x01,0xB0,0x00,0x8A,0x00,0xB1,0x00,0xC0,0x01,0x00,0x02, // 193 + 0x00,0x02,0xC0,0x01,0xB2,0x00,0x89,0x00,0xB2,0x00,0xC0,0x01,0x00,0x02, // 194 + 0x00,0x02,0xC2,0x01,0xB1,0x00,0x8A,0x00,0xB1,0x00,0xC0,0x01,0x00,0x02, // 195 + 0x00,0x02,0xC0,0x01,0xB2,0x00,0x88,0x00,0xB2,0x00,0xC0,0x01,0x00,0x02, // 196 + 0x00,0x02,0xC0,0x01,0xBE,0x00,0x8A,0x00,0xBE,0x00,0xC0,0x01,0x00,0x02, // 197 + 0x00,0x03,0xC0,0x00,0xE0,0x00,0x98,0x00,0x88,0x00,0xF8,0x03,0x48,0x02,0x48,0x02,0x48,0x02, // 198 + 0x00,0x00,0xF0,0x01,0x08,0x02,0x08,0x16,0x08,0x1A,0x10,0x01, // 199 + 0x00,0x00,0xF8,0x03,0x49,0x02,0x4A,0x02,0x48,0x02,0x48,0x02, // 200 + 0x00,0x00,0xF8,0x03,0x48,0x02,0x4A,0x02,0x49,0x02,0x48,0x02, // 201 + 0x00,0x00,0xFA,0x03,0x49,0x02,0x4A,0x02,0x48,0x02,0x48,0x02, // 202 + 0x00,0x00,0xF8,0x03,0x4A,0x02,0x48,0x02,0x4A,0x02,0x48,0x02, // 203 + 0x00,0x00,0xF9,0x03,0x02, // 204 + 0x02,0x00,0xF9,0x03, // 205 + 0x01,0x00,0xFA,0x03, // 206 + 0x02,0x00,0xF8,0x03,0x02, // 207 + 0x40,0x00,0xF8,0x03,0x48,0x02,0x48,0x02,0x10,0x01,0xE0, // 208 + 0x00,0x00,0xFA,0x03,0x31,0x00,0x42,0x00,0x81,0x01,0xF8,0x03, // 209 + 0x00,0x00,0xF0,0x01,0x08,0x02,0x09,0x02,0x0A,0x02,0x08,0x02,0xF0,0x01, // 210 + 0x00,0x00,0xF0,0x01,0x08,0x02,0x0A,0x02,0x09,0x02,0x08,0x02,0xF0,0x01, // 211 + 0x00,0x00,0xF0,0x01,0x08,0x02,0x0A,0x02,0x09,0x02,0x0A,0x02,0xF0,0x01, // 212 + 0x00,0x00,0xF0,0x01,0x0A,0x02,0x09,0x02,0x0A,0x02,0x09,0x02,0xF0,0x01, // 213 + 0x00,0x00,0xF0,0x01,0x0A,0x02,0x08,0x02,0x0A,0x02,0x08,0x02,0xF0,0x01, // 214 + 0x10,0x01,0xA0,0x00,0xE0,0x00,0xA0,0x00,0x10,0x01, // 215 + 0x00,0x00,0xF0,0x02,0x08,0x03,0xC8,0x02,0x28,0x02,0x18,0x03,0xE8, // 216 + 0x00,0x00,0xF8,0x01,0x01,0x02,0x02,0x02,0x00,0x02,0xF8,0x01, // 217 + 0x00,0x00,0xF8,0x01,0x02,0x02,0x01,0x02,0x00,0x02,0xF8,0x01, // 218 + 0x00,0x00,0xF8,0x01,0x02,0x02,0x01,0x02,0x02,0x02,0xF8,0x01, // 219 + 0x00,0x00,0xF8,0x01,0x02,0x02,0x00,0x02,0x02,0x02,0xF8,0x01, // 220 + 0x08,0x00,0x10,0x00,0x20,0x00,0xC2,0x03,0x21,0x00,0x10,0x00,0x08, // 221 + 0x00,0x00,0xF8,0x03,0x10,0x01,0x10,0x01,0x10,0x01,0xE0, // 222 + 0x00,0x00,0xF0,0x03,0x08,0x01,0x48,0x02,0xB0,0x02,0x80,0x01, // 223 + 0x00,0x00,0x00,0x03,0xA4,0x02,0xA8,0x02,0xE0,0x03, // 224 + 0x00,0x00,0x00,0x03,0xA8,0x02,0xA4,0x02,0xE0,0x03, // 225 + 0x00,0x00,0x00,0x03,0xA8,0x02,0xA4,0x02,0xE8,0x03, // 226 + 0x00,0x00,0x08,0x03,0xA4,0x02,0xA8,0x02,0xE4,0x03, // 227 + 0x00,0x00,0x00,0x03,0xA8,0x02,0xA0,0x02,0xE8,0x03, // 228 + 0x00,0x00,0x00,0x03,0xAE,0x02,0xAA,0x02,0xEE,0x03, // 229 + 0x00,0x00,0x40,0x03,0xA0,0x02,0xA0,0x02,0xC0,0x01,0xA0,0x02,0xA0,0x02,0xC0,0x02, // 230 + 0x00,0x00,0xC0,0x01,0x20,0x16,0x20,0x1A,0x40,0x01, // 231 + 0x00,0x00,0xC0,0x01,0xA4,0x02,0xA8,0x02,0xC0,0x02, // 232 + 0x00,0x00,0xC0,0x01,0xA8,0x02,0xA4,0x02,0xC0,0x02, // 233 + 0x00,0x00,0xC0,0x01,0xA8,0x02,0xA4,0x02,0xC8,0x02, // 234 + 0x00,0x00,0xC0,0x01,0xA8,0x02,0xA0,0x02,0xC8,0x02, // 235 + 0x00,0x00,0xE4,0x03,0x08, // 236 + 0x08,0x00,0xE4,0x03, // 237 + 0x08,0x00,0xE4,0x03,0x08, // 238 + 0x08,0x00,0xE0,0x03,0x08, // 239 + 0x00,0x00,0xC0,0x01,0x28,0x02,0x38,0x02,0xE0,0x01, // 240 + 0x00,0x00,0xE8,0x03,0x24,0x00,0x28,0x00,0xC4,0x03, // 241 + 0x00,0x00,0xC0,0x01,0x24,0x02,0x28,0x02,0xC0,0x01, // 242 + 0x00,0x00,0xC0,0x01,0x28,0x02,0x24,0x02,0xC0,0x01, // 243 + 0x00,0x00,0xC0,0x01,0x28,0x02,0x24,0x02,0xC8,0x01, // 244 + 0x00,0x00,0xC8,0x01,0x24,0x02,0x28,0x02,0xC4,0x01, // 245 + 0x00,0x00,0xC0,0x01,0x28,0x02,0x20,0x02,0xC8,0x01, // 246 + 0x40,0x00,0x40,0x00,0x50,0x01,0x40,0x00,0x40, // 247 + 0x00,0x00,0xC0,0x02,0xA0,0x03,0x60,0x02,0xA0,0x01, // 248 + 0x00,0x00,0xE0,0x01,0x04,0x02,0x08,0x02,0xE0,0x03, // 249 + 0x00,0x00,0xE0,0x01,0x08,0x02,0x04,0x02,0xE0,0x03, // 250 + 0x00,0x00,0xE8,0x01,0x04,0x02,0x08,0x02,0xE0,0x03, // 251 + 0x00,0x00,0xE0,0x01,0x08,0x02,0x00,0x02,0xE8,0x03, // 252 + 0x20,0x00,0xC0,0x09,0x08,0x06,0xC4,0x01,0x20, // 253 + 0x00,0x00,0xF8,0x0F,0x20,0x02,0x20,0x02,0xC0,0x01, // 254 + 0x20,0x00,0xC8,0x09,0x00,0x06,0xC8,0x01,0x20 // 255 +}; + +const uint8_t ArialMT_Plain_16[] PROGMEM = { + 0x10, // Width: 16 + 0x13, // Height: 19 + 0x20, // First Char: 32 + 0xE0, // Numbers of Chars: 224 + + // Jump Table: + 0xFF, 0xFF, 0x00, 0x04, // 32:65535 + 0x00, 0x00, 0x08, 0x04, // 33:0 + 0x00, 0x08, 0x0D, 0x06, // 34:8 + 0x00, 0x15, 0x1A, 0x09, // 35:21 + 0x00, 0x2F, 0x17, 0x09, // 36:47 + 0x00, 0x46, 0x26, 0x0E, // 37:70 + 0x00, 0x6C, 0x1D, 0x0B, // 38:108 + 0x00, 0x89, 0x04, 0x03, // 39:137 + 0x00, 0x8D, 0x0C, 0x05, // 40:141 + 0x00, 0x99, 0x0B, 0x05, // 41:153 + 0x00, 0xA4, 0x0D, 0x06, // 42:164 + 0x00, 0xB1, 0x17, 0x09, // 43:177 + 0x00, 0xC8, 0x09, 0x04, // 44:200 + 0x00, 0xD1, 0x0B, 0x05, // 45:209 + 0x00, 0xDC, 0x08, 0x04, // 46:220 + 0x00, 0xE4, 0x0A, 0x04, // 47:228 + 0x00, 0xEE, 0x17, 0x09, // 48:238 + 0x01, 0x05, 0x11, 0x09, // 49:261 + 0x01, 0x16, 0x17, 0x09, // 50:278 + 0x01, 0x2D, 0x17, 0x09, // 51:301 + 0x01, 0x44, 0x17, 0x09, // 52:324 + 0x01, 0x5B, 0x17, 0x09, // 53:347 + 0x01, 0x72, 0x17, 0x09, // 54:370 + 0x01, 0x89, 0x16, 0x09, // 55:393 + 0x01, 0x9F, 0x17, 0x09, // 56:415 + 0x01, 0xB6, 0x17, 0x09, // 57:438 + 0x01, 0xCD, 0x05, 0x04, // 58:461 + 0x01, 0xD2, 0x06, 0x04, // 59:466 + 0x01, 0xD8, 0x17, 0x09, // 60:472 + 0x01, 0xEF, 0x17, 0x09, // 61:495 + 0x02, 0x06, 0x17, 0x09, // 62:518 + 0x02, 0x1D, 0x16, 0x09, // 63:541 + 0x02, 0x33, 0x2F, 0x10, // 64:563 + 0x02, 0x62, 0x1D, 0x0B, // 65:610 + 0x02, 0x7F, 0x1D, 0x0B, // 66:639 + 0x02, 0x9C, 0x20, 0x0C, // 67:668 + 0x02, 0xBC, 0x20, 0x0C, // 68:700 + 0x02, 0xDC, 0x1D, 0x0B, // 69:732 + 0x02, 0xF9, 0x19, 0x0A, // 70:761 + 0x03, 0x12, 0x20, 0x0C, // 71:786 + 0x03, 0x32, 0x1D, 0x0C, // 72:818 + 0x03, 0x4F, 0x05, 0x04, // 73:847 + 0x03, 0x54, 0x14, 0x08, // 74:852 + 0x03, 0x68, 0x1D, 0x0B, // 75:872 + 0x03, 0x85, 0x17, 0x09, // 76:901 + 0x03, 0x9C, 0x23, 0x0D, // 77:924 + 0x03, 0xBF, 0x1D, 0x0C, // 78:959 + 0x03, 0xDC, 0x20, 0x0C, // 79:988 + 0x03, 0xFC, 0x1C, 0x0B, // 80:1020 + 0x04, 0x18, 0x20, 0x0C, // 81:1048 + 0x04, 0x38, 0x1D, 0x0C, // 82:1080 + 0x04, 0x55, 0x1D, 0x0B, // 83:1109 + 0x04, 0x72, 0x19, 0x0A, // 84:1138 + 0x04, 0x8B, 0x1D, 0x0C, // 85:1163 + 0x04, 0xA8, 0x1C, 0x0B, // 86:1192 + 0x04, 0xC4, 0x2B, 0x0F, // 87:1220 + 0x04, 0xEF, 0x20, 0x0B, // 88:1263 + 0x05, 0x0F, 0x19, 0x0B, // 89:1295 + 0x05, 0x28, 0x1A, 0x0A, // 90:1320 + 0x05, 0x42, 0x0C, 0x04, // 91:1346 + 0x05, 0x4E, 0x0B, 0x04, // 92:1358 + 0x05, 0x59, 0x09, 0x04, // 93:1369 + 0x05, 0x62, 0x14, 0x08, // 94:1378 + 0x05, 0x76, 0x1B, 0x09, // 95:1398 + 0x05, 0x91, 0x07, 0x05, // 96:1425 + 0x05, 0x98, 0x17, 0x09, // 97:1432 + 0x05, 0xAF, 0x17, 0x09, // 98:1455 + 0x05, 0xC6, 0x14, 0x08, // 99:1478 + 0x05, 0xDA, 0x17, 0x09, // 100:1498 + 0x05, 0xF1, 0x17, 0x09, // 101:1521 + 0x06, 0x08, 0x0A, 0x04, // 102:1544 + 0x06, 0x12, 0x17, 0x09, // 103:1554 + 0x06, 0x29, 0x14, 0x09, // 104:1577 + 0x06, 0x3D, 0x05, 0x04, // 105:1597 + 0x06, 0x42, 0x06, 0x04, // 106:1602 + 0x06, 0x48, 0x17, 0x08, // 107:1608 + 0x06, 0x5F, 0x05, 0x04, // 108:1631 + 0x06, 0x64, 0x23, 0x0D, // 109:1636 + 0x06, 0x87, 0x14, 0x09, // 110:1671 + 0x06, 0x9B, 0x17, 0x09, // 111:1691 + 0x06, 0xB2, 0x17, 0x09, // 112:1714 + 0x06, 0xC9, 0x18, 0x09, // 113:1737 + 0x06, 0xE1, 0x0D, 0x05, // 114:1761 + 0x06, 0xEE, 0x14, 0x08, // 115:1774 + 0x07, 0x02, 0x0B, 0x04, // 116:1794 + 0x07, 0x0D, 0x14, 0x09, // 117:1805 + 0x07, 0x21, 0x13, 0x08, // 118:1825 + 0x07, 0x34, 0x1F, 0x0C, // 119:1844 + 0x07, 0x53, 0x14, 0x08, // 120:1875 + 0x07, 0x67, 0x13, 0x08, // 121:1895 + 0x07, 0x7A, 0x14, 0x08, // 122:1914 + 0x07, 0x8E, 0x0F, 0x05, // 123:1934 + 0x07, 0x9D, 0x06, 0x04, // 124:1949 + 0x07, 0xA3, 0x0E, 0x05, // 125:1955 + 0x07, 0xB1, 0x17, 0x09, // 126:1969 + 0xFF, 0xFF, 0x00, 0x00, // 127:65535 + 0xFF, 0xFF, 0x00, 0x10, // 128:65535 + 0xFF, 0xFF, 0x00, 0x10, // 129:65535 + 0xFF, 0xFF, 0x00, 0x10, // 130:65535 + 0xFF, 0xFF, 0x00, 0x10, // 131:65535 + 0xFF, 0xFF, 0x00, 0x10, // 132:65535 + 0xFF, 0xFF, 0x00, 0x10, // 133:65535 + 0xFF, 0xFF, 0x00, 0x10, // 134:65535 + 0xFF, 0xFF, 0x00, 0x10, // 135:65535 + 0xFF, 0xFF, 0x00, 0x10, // 136:65535 + 0xFF, 0xFF, 0x00, 0x10, // 137:65535 + 0xFF, 0xFF, 0x00, 0x10, // 138:65535 + 0xFF, 0xFF, 0x00, 0x10, // 139:65535 + 0xFF, 0xFF, 0x00, 0x10, // 140:65535 + 0xFF, 0xFF, 0x00, 0x10, // 141:65535 + 0xFF, 0xFF, 0x00, 0x10, // 142:65535 + 0xFF, 0xFF, 0x00, 0x10, // 143:65535 + 0xFF, 0xFF, 0x00, 0x10, // 144:65535 + 0xFF, 0xFF, 0x00, 0x10, // 145:65535 + 0xFF, 0xFF, 0x00, 0x10, // 146:65535 + 0xFF, 0xFF, 0x00, 0x10, // 147:65535 + 0xFF, 0xFF, 0x00, 0x10, // 148:65535 + 0xFF, 0xFF, 0x00, 0x10, // 149:65535 + 0xFF, 0xFF, 0x00, 0x10, // 150:65535 + 0xFF, 0xFF, 0x00, 0x10, // 151:65535 + 0xFF, 0xFF, 0x00, 0x10, // 152:65535 + 0xFF, 0xFF, 0x00, 0x10, // 153:65535 + 0xFF, 0xFF, 0x00, 0x10, // 154:65535 + 0xFF, 0xFF, 0x00, 0x10, // 155:65535 + 0xFF, 0xFF, 0x00, 0x10, // 156:65535 + 0xFF, 0xFF, 0x00, 0x10, // 157:65535 + 0xFF, 0xFF, 0x00, 0x10, // 158:65535 + 0xFF, 0xFF, 0x00, 0x10, // 159:65535 + 0xFF, 0xFF, 0x00, 0x04, // 160:65535 + 0x07, 0xC8, 0x09, 0x05, // 161:1992 + 0x07, 0xD1, 0x17, 0x09, // 162:2001 + 0x07, 0xE8, 0x17, 0x09, // 163:2024 + 0x07, 0xFF, 0x14, 0x09, // 164:2047 + 0x08, 0x13, 0x1A, 0x09, // 165:2067 + 0x08, 0x2D, 0x06, 0x04, // 166:2093 + 0x08, 0x33, 0x17, 0x09, // 167:2099 + 0x08, 0x4A, 0x07, 0x05, // 168:2122 + 0x08, 0x51, 0x23, 0x0C, // 169:2129 + 0x08, 0x74, 0x0E, 0x06, // 170:2164 + 0x08, 0x82, 0x14, 0x09, // 171:2178 + 0x08, 0x96, 0x17, 0x09, // 172:2198 + 0x08, 0xAD, 0x0B, 0x05, // 173:2221 + 0x08, 0xB8, 0x23, 0x0C, // 174:2232 + 0x08, 0xDB, 0x19, 0x09, // 175:2267 + 0x08, 0xF4, 0x0D, 0x06, // 176:2292 + 0x09, 0x01, 0x17, 0x09, // 177:2305 + 0x09, 0x18, 0x0E, 0x05, // 178:2328 + 0x09, 0x26, 0x0D, 0x05, // 179:2342 + 0x09, 0x33, 0x0A, 0x05, // 180:2355 + 0x09, 0x3D, 0x17, 0x09, // 181:2365 + 0x09, 0x54, 0x19, 0x09, // 182:2388 + 0x09, 0x6D, 0x08, 0x05, // 183:2413 + 0x09, 0x75, 0x0C, 0x05, // 184:2421 + 0x09, 0x81, 0x0B, 0x05, // 185:2433 + 0x09, 0x8C, 0x0D, 0x06, // 186:2444 + 0x09, 0x99, 0x17, 0x09, // 187:2457 + 0x09, 0xB0, 0x26, 0x0D, // 188:2480 + 0x09, 0xD6, 0x26, 0x0D, // 189:2518 + 0x09, 0xFC, 0x26, 0x0D, // 190:2556 + 0x0A, 0x22, 0x1A, 0x0A, // 191:2594 + 0x0A, 0x3C, 0x1D, 0x0B, // 192:2620 + 0x0A, 0x59, 0x1D, 0x0B, // 193:2649 + 0x0A, 0x76, 0x1D, 0x0B, // 194:2678 + 0x0A, 0x93, 0x1D, 0x0B, // 195:2707 + 0x0A, 0xB0, 0x1D, 0x0B, // 196:2736 + 0x0A, 0xCD, 0x1D, 0x0B, // 197:2765 + 0x0A, 0xEA, 0x2C, 0x10, // 198:2794 + 0x0B, 0x16, 0x20, 0x0C, // 199:2838 + 0x0B, 0x36, 0x1D, 0x0B, // 200:2870 + 0x0B, 0x53, 0x1D, 0x0B, // 201:2899 + 0x0B, 0x70, 0x1D, 0x0B, // 202:2928 + 0x0B, 0x8D, 0x1D, 0x0B, // 203:2957 + 0x0B, 0xAA, 0x05, 0x04, // 204:2986 + 0x0B, 0xAF, 0x07, 0x04, // 205:2991 + 0x0B, 0xB6, 0x0A, 0x04, // 206:2998 + 0x0B, 0xC0, 0x07, 0x04, // 207:3008 + 0x0B, 0xC7, 0x20, 0x0C, // 208:3015 + 0x0B, 0xE7, 0x1D, 0x0C, // 209:3047 + 0x0C, 0x04, 0x20, 0x0C, // 210:3076 + 0x0C, 0x24, 0x20, 0x0C, // 211:3108 + 0x0C, 0x44, 0x20, 0x0C, // 212:3140 + 0x0C, 0x64, 0x20, 0x0C, // 213:3172 + 0x0C, 0x84, 0x20, 0x0C, // 214:3204 + 0x0C, 0xA4, 0x17, 0x09, // 215:3236 + 0x0C, 0xBB, 0x20, 0x0C, // 216:3259 + 0x0C, 0xDB, 0x1D, 0x0C, // 217:3291 + 0x0C, 0xF8, 0x1D, 0x0C, // 218:3320 + 0x0D, 0x15, 0x1D, 0x0C, // 219:3349 + 0x0D, 0x32, 0x1D, 0x0C, // 220:3378 + 0x0D, 0x4F, 0x19, 0x0B, // 221:3407 + 0x0D, 0x68, 0x1D, 0x0B, // 222:3432 + 0x0D, 0x85, 0x17, 0x0A, // 223:3461 + 0x0D, 0x9C, 0x17, 0x09, // 224:3484 + 0x0D, 0xB3, 0x17, 0x09, // 225:3507 + 0x0D, 0xCA, 0x17, 0x09, // 226:3530 + 0x0D, 0xE1, 0x17, 0x09, // 227:3553 + 0x0D, 0xF8, 0x17, 0x09, // 228:3576 + 0x0E, 0x0F, 0x17, 0x09, // 229:3599 + 0x0E, 0x26, 0x29, 0x0E, // 230:3622 + 0x0E, 0x4F, 0x14, 0x08, // 231:3663 + 0x0E, 0x63, 0x17, 0x09, // 232:3683 + 0x0E, 0x7A, 0x17, 0x09, // 233:3706 + 0x0E, 0x91, 0x17, 0x09, // 234:3729 + 0x0E, 0xA8, 0x17, 0x09, // 235:3752 + 0x0E, 0xBF, 0x05, 0x04, // 236:3775 + 0x0E, 0xC4, 0x07, 0x04, // 237:3780 + 0x0E, 0xCB, 0x0A, 0x04, // 238:3787 + 0x0E, 0xD5, 0x07, 0x04, // 239:3797 + 0x0E, 0xDC, 0x17, 0x09, // 240:3804 + 0x0E, 0xF3, 0x14, 0x09, // 241:3827 + 0x0F, 0x07, 0x17, 0x09, // 242:3847 + 0x0F, 0x1E, 0x17, 0x09, // 243:3870 + 0x0F, 0x35, 0x17, 0x09, // 244:3893 + 0x0F, 0x4C, 0x17, 0x09, // 245:3916 + 0x0F, 0x63, 0x17, 0x09, // 246:3939 + 0x0F, 0x7A, 0x17, 0x09, // 247:3962 + 0x0F, 0x91, 0x17, 0x0A, // 248:3985 + 0x0F, 0xA8, 0x14, 0x09, // 249:4008 + 0x0F, 0xBC, 0x14, 0x09, // 250:4028 + 0x0F, 0xD0, 0x14, 0x09, // 251:4048 + 0x0F, 0xE4, 0x14, 0x09, // 252:4068 + 0x0F, 0xF8, 0x13, 0x08, // 253:4088 + 0x10, 0x0B, 0x17, 0x09, // 254:4107 + 0x10, 0x22, 0x13, 0x08, // 255:4130 + + // Font Data: + 0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x5F, // 33 + 0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78, // 34 + 0x80,0x08,0x00,0x80,0x78,0x00,0xC0,0x0F,0x00,0xB8,0x08,0x00,0x80,0x08,0x00,0x80,0x78,0x00,0xC0,0x0F,0x00,0xB8,0x08,0x00,0x80,0x08, // 35 + 0x00,0x00,0x00,0xE0,0x10,0x00,0x10,0x21,0x00,0x08,0x41,0x00,0xFC,0xFF,0x00,0x08,0x42,0x00,0x10,0x22,0x00,0x20,0x1C, // 36 + 0x00,0x00,0x00,0xF0,0x00,0x00,0x08,0x01,0x00,0x08,0x01,0x00,0x08,0x61,0x00,0xF0,0x18,0x00,0x00,0x06,0x00,0xC0,0x01,0x00,0x30,0x3C,0x00,0x08,0x42,0x00,0x00,0x42,0x00,0x00,0x42,0x00,0x00,0x3C, // 37 + 0x00,0x00,0x00,0x00,0x1C,0x00,0x70,0x22,0x00,0x88,0x41,0x00,0x08,0x43,0x00,0x88,0x44,0x00,0x70,0x28,0x00,0x00,0x10,0x00,0x00,0x28,0x00,0x00,0x44, // 38 + 0x00,0x00,0x00,0x78, // 39 + 0x00,0x00,0x00,0x80,0x3F,0x00,0x70,0xC0,0x01,0x08,0x00,0x02, // 40 + 0x00,0x00,0x00,0x08,0x00,0x02,0x70,0xC0,0x01,0x80,0x3F, // 41 + 0x10,0x00,0x00,0xD0,0x00,0x00,0x38,0x00,0x00,0xD0,0x00,0x00,0x10, // 42 + 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0xC0,0x1F,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x02, // 43 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x01, // 44 + 0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08, // 45 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40, // 46 + 0x00,0x60,0x00,0x00,0x1E,0x00,0xE0,0x01,0x00,0x18, // 47 + 0x00,0x00,0x00,0xE0,0x1F,0x00,0x10,0x20,0x00,0x08,0x40,0x00,0x08,0x40,0x00,0x08,0x40,0x00,0x10,0x20,0x00,0xE0,0x1F, // 48 + 0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x20,0x00,0x00,0x10,0x00,0x00,0xF8,0x7F, // 49 + 0x00,0x00,0x00,0x20,0x40,0x00,0x10,0x60,0x00,0x08,0x50,0x00,0x08,0x48,0x00,0x08,0x44,0x00,0x10,0x43,0x00,0xE0,0x40, // 50 + 0x00,0x00,0x00,0x20,0x10,0x00,0x10,0x20,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x88,0x41,0x00,0xF0,0x22,0x00,0x00,0x1C, // 51 + 0x00,0x0C,0x00,0x00,0x0A,0x00,0x00,0x09,0x00,0xC0,0x08,0x00,0x20,0x08,0x00,0x10,0x08,0x00,0xF8,0x7F,0x00,0x00,0x08, // 52 + 0x00,0x00,0x00,0xC0,0x11,0x00,0xB8,0x20,0x00,0x88,0x40,0x00,0x88,0x40,0x00,0x88,0x40,0x00,0x08,0x21,0x00,0x08,0x1E, // 53 + 0x00,0x00,0x00,0xE0,0x1F,0x00,0x10,0x21,0x00,0x88,0x40,0x00,0x88,0x40,0x00,0x88,0x40,0x00,0x10,0x21,0x00,0x20,0x1E, // 54 + 0x00,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x78,0x00,0x08,0x07,0x00,0xC8,0x00,0x00,0x28,0x00,0x00,0x18, // 55 + 0x00,0x00,0x00,0x60,0x1C,0x00,0x90,0x22,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x90,0x22,0x00,0x60,0x1C, // 56 + 0x00,0x00,0x00,0xE0,0x11,0x00,0x10,0x22,0x00,0x08,0x44,0x00,0x08,0x44,0x00,0x08,0x44,0x00,0x10,0x22,0x00,0xE0,0x1F, // 57 + 0x00,0x00,0x00,0x40,0x40, // 58 + 0x00,0x00,0x00,0x40,0xC0,0x01, // 59 + 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x05,0x00,0x00,0x05,0x00,0x80,0x08,0x00,0x80,0x08,0x00,0x80,0x08,0x00,0x40,0x10, // 60 + 0x00,0x00,0x00,0x80,0x08,0x00,0x80,0x08,0x00,0x80,0x08,0x00,0x80,0x08,0x00,0x80,0x08,0x00,0x80,0x08,0x00,0x80,0x08, // 61 + 0x00,0x00,0x00,0x40,0x10,0x00,0x80,0x08,0x00,0x80,0x08,0x00,0x80,0x08,0x00,0x00,0x05,0x00,0x00,0x05,0x00,0x00,0x02, // 62 + 0x00,0x00,0x00,0x60,0x00,0x00,0x10,0x00,0x00,0x08,0x00,0x00,0x08,0x5C,0x00,0x08,0x02,0x00,0x10,0x01,0x00,0xE0, // 63 + 0x00,0x00,0x00,0x00,0x3F,0x00,0xC0,0x40,0x00,0x20,0x80,0x00,0x10,0x1E,0x01,0x10,0x21,0x01,0x88,0x40,0x02,0x48,0x40,0x02,0x48,0x40,0x02,0x48,0x20,0x02,0x88,0x7C,0x02,0xC8,0x43,0x02,0x10,0x40,0x02,0x10,0x20,0x01,0x60,0x10,0x01,0x80,0x8F, // 64 + 0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x1C,0x00,0x80,0x07,0x00,0x70,0x04,0x00,0x08,0x04,0x00,0x70,0x04,0x00,0x80,0x07,0x00,0x00,0x1C,0x00,0x00,0x60, // 65 + 0x00,0x00,0x00,0xF8,0x7F,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x90,0x22,0x00,0x60,0x1C, // 66 + 0x00,0x00,0x00,0xC0,0x0F,0x00,0x20,0x10,0x00,0x10,0x20,0x00,0x08,0x40,0x00,0x08,0x40,0x00,0x08,0x40,0x00,0x08,0x40,0x00,0x08,0x40,0x00,0x10,0x20,0x00,0x20,0x10, // 67 + 0x00,0x00,0x00,0xF8,0x7F,0x00,0x08,0x40,0x00,0x08,0x40,0x00,0x08,0x40,0x00,0x08,0x40,0x00,0x08,0x40,0x00,0x08,0x40,0x00,0x10,0x20,0x00,0x20,0x10,0x00,0xC0,0x0F, // 68 + 0x00,0x00,0x00,0xF8,0x7F,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x40, // 69 + 0x00,0x00,0x00,0xF8,0x7F,0x00,0x08,0x02,0x00,0x08,0x02,0x00,0x08,0x02,0x00,0x08,0x02,0x00,0x08,0x02,0x00,0x08,0x02,0x00,0x08, // 70 + 0x00,0x00,0x00,0xC0,0x0F,0x00,0x20,0x10,0x00,0x10,0x20,0x00,0x08,0x40,0x00,0x08,0x40,0x00,0x08,0x42,0x00,0x08,0x42,0x00,0x10,0x22,0x00,0x20,0x12,0x00,0x00,0x0E, // 71 + 0x00,0x00,0x00,0xF8,0x7F,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0xF8,0x7F, // 72 + 0x00,0x00,0x00,0xF8,0x7F, // 73 + 0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0xF8,0x3F, // 74 + 0x00,0x00,0x00,0xF8,0x7F,0x00,0x00,0x04,0x00,0x00,0x02,0x00,0x00,0x01,0x00,0x80,0x03,0x00,0x40,0x04,0x00,0x20,0x18,0x00,0x10,0x20,0x00,0x08,0x40, // 75 + 0x00,0x00,0x00,0xF8,0x7F,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x40, // 76 + 0x00,0x00,0x00,0xF8,0x7F,0x00,0x30,0x00,0x00,0xC0,0x00,0x00,0x00,0x03,0x00,0x00,0x1C,0x00,0x00,0x60,0x00,0x00,0x1C,0x00,0x00,0x03,0x00,0xC0,0x00,0x00,0x30,0x00,0x00,0xF8,0x7F, // 77 + 0x00,0x00,0x00,0xF8,0x7F,0x00,0x10,0x00,0x00,0x60,0x00,0x00,0x80,0x00,0x00,0x00,0x03,0x00,0x00,0x04,0x00,0x00,0x18,0x00,0x00,0x20,0x00,0xF8,0x7F, // 78 + 0x00,0x00,0x00,0xC0,0x0F,0x00,0x20,0x10,0x00,0x10,0x20,0x00,0x08,0x40,0x00,0x08,0x40,0x00,0x08,0x40,0x00,0x08,0x40,0x00,0x10,0x20,0x00,0x20,0x10,0x00,0xC0,0x0F, // 79 + 0x00,0x00,0x00,0xF8,0x7F,0x00,0x08,0x02,0x00,0x08,0x02,0x00,0x08,0x02,0x00,0x08,0x02,0x00,0x08,0x02,0x00,0x08,0x02,0x00,0x10,0x01,0x00,0xE0, // 80 + 0x00,0x00,0x00,0xC0,0x0F,0x00,0x20,0x10,0x00,0x10,0x20,0x00,0x08,0x40,0x00,0x08,0x40,0x00,0x08,0x50,0x00,0x08,0x50,0x00,0x10,0x20,0x00,0x20,0x70,0x00,0xC0,0x4F, // 81 + 0x00,0x00,0x00,0xF8,0x7F,0x00,0x08,0x02,0x00,0x08,0x02,0x00,0x08,0x02,0x00,0x08,0x02,0x00,0x08,0x06,0x00,0x08,0x1A,0x00,0x10,0x21,0x00,0xE0,0x40, // 82 + 0x00,0x00,0x00,0x60,0x10,0x00,0x90,0x20,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x42,0x00,0x08,0x42,0x00,0x10,0x22,0x00,0x20,0x1C, // 83 + 0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0xF8,0x7F,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08, // 84 + 0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x20,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x20,0x00,0xF8,0x1F, // 85 + 0x00,0x00,0x00,0x18,0x00,0x00,0xE0,0x00,0x00,0x00,0x07,0x00,0x00,0x18,0x00,0x00,0x60,0x00,0x00,0x18,0x00,0x00,0x07,0x00,0xE0,0x00,0x00,0x18, // 86 + 0x18,0x00,0x00,0xE0,0x01,0x00,0x00,0x1E,0x00,0x00,0x60,0x00,0x00,0x1C,0x00,0x80,0x03,0x00,0x70,0x00,0x00,0x08,0x00,0x00,0x70,0x00,0x00,0x80,0x03,0x00,0x00,0x1C,0x00,0x00,0x60,0x00,0x00,0x1E,0x00,0xE0,0x01,0x00,0x18, // 87 + 0x00,0x40,0x00,0x08,0x20,0x00,0x10,0x10,0x00,0x60,0x0C,0x00,0x80,0x02,0x00,0x00,0x01,0x00,0x80,0x02,0x00,0x60,0x0C,0x00,0x10,0x10,0x00,0x08,0x20,0x00,0x00,0x40, // 88 + 0x08,0x00,0x00,0x30,0x00,0x00,0x40,0x00,0x00,0x80,0x01,0x00,0x00,0x7E,0x00,0x80,0x01,0x00,0x40,0x00,0x00,0x30,0x00,0x00,0x08, // 89 + 0x00,0x40,0x00,0x08,0x60,0x00,0x08,0x58,0x00,0x08,0x44,0x00,0x08,0x43,0x00,0x88,0x40,0x00,0x68,0x40,0x00,0x18,0x40,0x00,0x08,0x40, // 90 + 0x00,0x00,0x00,0xF8,0xFF,0x03,0x08,0x00,0x02,0x08,0x00,0x02, // 91 + 0x18,0x00,0x00,0xE0,0x01,0x00,0x00,0x1E,0x00,0x00,0x60, // 92 + 0x08,0x00,0x02,0x08,0x00,0x02,0xF8,0xFF,0x03, // 93 + 0x00,0x01,0x00,0xC0,0x00,0x00,0x30,0x00,0x00,0x08,0x00,0x00,0x30,0x00,0x00,0xC0,0x00,0x00,0x00,0x01, // 94 + 0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x02, // 95 + 0x00,0x00,0x00,0x08,0x00,0x00,0x10, // 96 + 0x00,0x00,0x00,0x00,0x39,0x00,0x80,0x44,0x00,0x40,0x44,0x00,0x40,0x44,0x00,0x40,0x42,0x00,0x40,0x22,0x00,0x80,0x7F, // 97 + 0x00,0x00,0x00,0xF8,0x7F,0x00,0x80,0x20,0x00,0x40,0x40,0x00,0x40,0x40,0x00,0x40,0x40,0x00,0x80,0x20,0x00,0x00,0x1F, // 98 + 0x00,0x00,0x00,0x00,0x1F,0x00,0x80,0x20,0x00,0x40,0x40,0x00,0x40,0x40,0x00,0x40,0x40,0x00,0x80,0x20, // 99 + 0x00,0x00,0x00,0x00,0x1F,0x00,0x80,0x20,0x00,0x40,0x40,0x00,0x40,0x40,0x00,0x40,0x40,0x00,0x80,0x20,0x00,0xF8,0x7F, // 100 + 0x00,0x00,0x00,0x00,0x1F,0x00,0x80,0x24,0x00,0x40,0x44,0x00,0x40,0x44,0x00,0x40,0x44,0x00,0x80,0x24,0x00,0x00,0x17, // 101 + 0x40,0x00,0x00,0xF0,0x7F,0x00,0x48,0x00,0x00,0x48, // 102 + 0x00,0x00,0x00,0x00,0x1F,0x01,0x80,0x20,0x02,0x40,0x40,0x02,0x40,0x40,0x02,0x40,0x40,0x02,0x80,0x20,0x01,0xC0,0xFF, // 103 + 0x00,0x00,0x00,0xF8,0x7F,0x00,0x80,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x80,0x7F, // 104 + 0x00,0x00,0x00,0xC8,0x7F, // 105 + 0x00,0x00,0x02,0xC8,0xFF,0x01, // 106 + 0x00,0x00,0x00,0xF8,0x7F,0x00,0x00,0x08,0x00,0x00,0x04,0x00,0x00,0x06,0x00,0x00,0x19,0x00,0x80,0x20,0x00,0x40,0x40, // 107 + 0x00,0x00,0x00,0xF8,0x7F, // 108 + 0x00,0x00,0x00,0xC0,0x7F,0x00,0x80,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x80,0x7F,0x00,0x80,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x80,0x7F, // 109 + 0x00,0x00,0x00,0xC0,0x7F,0x00,0x80,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x80,0x7F, // 110 + 0x00,0x00,0x00,0x00,0x1F,0x00,0x80,0x20,0x00,0x40,0x40,0x00,0x40,0x40,0x00,0x40,0x40,0x00,0x80,0x20,0x00,0x00,0x1F, // 111 + 0x00,0x00,0x00,0xC0,0xFF,0x03,0x80,0x20,0x00,0x40,0x40,0x00,0x40,0x40,0x00,0x40,0x40,0x00,0x80,0x20,0x00,0x00,0x1F, // 112 + 0x00,0x00,0x00,0x00,0x1F,0x00,0x80,0x20,0x00,0x40,0x40,0x00,0x40,0x40,0x00,0x40,0x40,0x00,0x80,0x20,0x00,0xC0,0xFF,0x03, // 113 + 0x00,0x00,0x00,0xC0,0x7F,0x00,0x80,0x00,0x00,0x40,0x00,0x00,0x40, // 114 + 0x00,0x00,0x00,0x80,0x23,0x00,0x40,0x44,0x00,0x40,0x44,0x00,0x40,0x44,0x00,0x40,0x44,0x00,0x80,0x38, // 115 + 0x40,0x00,0x00,0xF0,0x7F,0x00,0x40,0x40,0x00,0x40,0x40, // 116 + 0x00,0x00,0x00,0xC0,0x3F,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x20,0x00,0xC0,0x7F, // 117 + 0xC0,0x00,0x00,0x00,0x03,0x00,0x00,0x1C,0x00,0x00,0x60,0x00,0x00,0x1C,0x00,0x00,0x03,0x00,0xC0, // 118 + 0xC0,0x00,0x00,0x00,0x1F,0x00,0x00,0x60,0x00,0x00,0x1C,0x00,0x00,0x03,0x00,0xC0,0x00,0x00,0x00,0x03,0x00,0x00,0x1C,0x00,0x00,0x60,0x00,0x00,0x1F,0x00,0xC0, // 119 + 0x40,0x40,0x00,0x80,0x20,0x00,0x00,0x1B,0x00,0x00,0x04,0x00,0x00,0x1B,0x00,0x80,0x20,0x00,0x40,0x40, // 120 + 0xC0,0x01,0x00,0x00,0x06,0x02,0x00,0x38,0x02,0x00,0xE0,0x01,0x00,0x38,0x00,0x00,0x07,0x00,0xC0, // 121 + 0x40,0x40,0x00,0x40,0x60,0x00,0x40,0x58,0x00,0x40,0x44,0x00,0x40,0x43,0x00,0xC0,0x40,0x00,0x40,0x40, // 122 + 0x00,0x04,0x00,0x00,0x04,0x00,0xF0,0xFB,0x01,0x08,0x00,0x02,0x08,0x00,0x02, // 123 + 0x00,0x00,0x00,0xF8,0xFF,0x03, // 124 + 0x08,0x00,0x02,0x08,0x00,0x02,0xF0,0xFB,0x01,0x00,0x04,0x00,0x00,0x04, // 125 + 0x00,0x02,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x01, // 126 + 0x00,0x00,0x00,0x00,0x00,0x00,0x40,0xFF,0x03, // 161 + 0x00,0x00,0x00,0x00,0x1F,0x00,0x80,0x20,0x03,0x40,0xF0,0x00,0x40,0x4E,0x00,0xC0,0x41,0x00,0xB8,0x20,0x00,0x00,0x11, // 162 + 0x00,0x41,0x00,0xE0,0x31,0x00,0x10,0x2F,0x00,0x08,0x21,0x00,0x08,0x21,0x00,0x08,0x40,0x00,0x10,0x40,0x00,0x20,0x20, // 163 + 0x00,0x00,0x00,0x40,0x0B,0x00,0x80,0x04,0x00,0x40,0x08,0x00,0x40,0x08,0x00,0x80,0x04,0x00,0x40,0x0B, // 164 + 0x08,0x0A,0x00,0x10,0x0A,0x00,0x60,0x0A,0x00,0x80,0x0B,0x00,0x00,0x7E,0x00,0x80,0x0B,0x00,0x60,0x0A,0x00,0x10,0x0A,0x00,0x08,0x0A, // 165 + 0x00,0x00,0x00,0xF8,0xF1,0x03, // 166 + 0x00,0x86,0x00,0x70,0x09,0x01,0xC8,0x10,0x02,0x88,0x10,0x02,0x08,0x21,0x02,0x08,0x61,0x02,0x30,0xD2,0x01,0x00,0x0C, // 167 + 0x08,0x00,0x00,0x00,0x00,0x00,0x08, // 168 + 0xC0,0x0F,0x00,0x20,0x10,0x00,0x10,0x20,0x00,0xC8,0x47,0x00,0x28,0x48,0x00,0x28,0x48,0x00,0x28,0x48,0x00,0x28,0x48,0x00,0x48,0x44,0x00,0x10,0x20,0x00,0x20,0x10,0x00,0xC0,0x0F, // 169 + 0xD0,0x00,0x00,0x48,0x01,0x00,0x28,0x01,0x00,0x28,0x01,0x00,0xF0,0x01, // 170 + 0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x1B,0x00,0x80,0x20,0x00,0x00,0x04,0x00,0x00,0x1B,0x00,0x80,0x20, // 171 + 0x00,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x0F, // 172 + 0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08, // 173 + 0xC0,0x0F,0x00,0x20,0x10,0x00,0x10,0x20,0x00,0xE8,0x4F,0x00,0x28,0x41,0x00,0x28,0x41,0x00,0x28,0x43,0x00,0x28,0x45,0x00,0xC8,0x48,0x00,0x10,0x20,0x00,0x20,0x10,0x00,0xC0,0x0F, // 174 + 0x04,0x00,0x00,0x04,0x00,0x00,0x04,0x00,0x00,0x04,0x00,0x00,0x04,0x00,0x00,0x04,0x00,0x00,0x04,0x00,0x00,0x04,0x00,0x00,0x04, // 175 + 0x00,0x00,0x00,0x30,0x00,0x00,0x48,0x00,0x00,0x48,0x00,0x00,0x30, // 176 + 0x00,0x00,0x00,0x00,0x41,0x00,0x00,0x41,0x00,0x00,0x41,0x00,0xE0,0x4F,0x00,0x00,0x41,0x00,0x00,0x41,0x00,0x00,0x41, // 177 + 0x10,0x01,0x00,0x88,0x01,0x00,0x48,0x01,0x00,0x48,0x01,0x00,0x30,0x01, // 178 + 0x90,0x00,0x00,0x08,0x01,0x00,0x08,0x01,0x00,0x28,0x01,0x00,0xD8, // 179 + 0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x08, // 180 + 0x00,0x00,0x00,0xC0,0xFF,0x03,0x00,0x20,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x20,0x00,0xC0,0x7F, // 181 + 0xF0,0x00,0x00,0xF8,0x00,0x00,0xF8,0x01,0x00,0xF8,0x01,0x00,0xF8,0xFF,0x03,0x08,0x00,0x00,0x08,0x00,0x00,0xF8,0xFF,0x03,0x08, // 182 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02, // 183 + 0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x80,0x02,0x00,0x00,0x03, // 184 + 0x00,0x00,0x00,0x10,0x00,0x00,0x08,0x00,0x00,0xF8,0x01, // 185 + 0xF0,0x00,0x00,0x08,0x01,0x00,0x08,0x01,0x00,0x08,0x01,0x00,0xF0, // 186 + 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x20,0x00,0x00,0x1B,0x00,0x00,0x04,0x00,0x80,0x20,0x00,0x00,0x1B,0x00,0x00,0x04, // 187 + 0x00,0x00,0x00,0x10,0x00,0x00,0x08,0x40,0x00,0xF8,0x21,0x00,0x00,0x10,0x00,0x00,0x0C,0x00,0x00,0x02,0x00,0x80,0x01,0x00,0x40,0x30,0x00,0x30,0x28,0x00,0x08,0x24,0x00,0x00,0x7E,0x00,0x00,0x20, // 188 + 0x00,0x00,0x00,0x10,0x00,0x00,0x08,0x40,0x00,0xF8,0x31,0x00,0x00,0x08,0x00,0x00,0x04,0x00,0x00,0x03,0x00,0x80,0x00,0x00,0x60,0x44,0x00,0x10,0x62,0x00,0x08,0x52,0x00,0x00,0x52,0x00,0x00,0x4C, // 189 + 0x90,0x00,0x00,0x08,0x01,0x00,0x08,0x41,0x00,0x28,0x21,0x00,0xD8,0x18,0x00,0x00,0x04,0x00,0x00,0x03,0x00,0x80,0x00,0x00,0x40,0x30,0x00,0x30,0x28,0x00,0x08,0x24,0x00,0x00,0x7E,0x00,0x00,0x20, // 190 + 0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x10,0x01,0x00,0x08,0x02,0x40,0x07,0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x01,0x00,0xC0, // 191 + 0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x1C,0x00,0x80,0x07,0x00,0x71,0x04,0x00,0x0A,0x04,0x00,0x70,0x04,0x00,0x80,0x07,0x00,0x00,0x1C,0x00,0x00,0x60, // 192 + 0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x1C,0x00,0x80,0x07,0x00,0x70,0x04,0x00,0x0A,0x04,0x00,0x71,0x04,0x00,0x80,0x07,0x00,0x00,0x1C,0x00,0x00,0x60, // 193 + 0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x1C,0x00,0x80,0x07,0x00,0x72,0x04,0x00,0x09,0x04,0x00,0x71,0x04,0x00,0x82,0x07,0x00,0x00,0x1C,0x00,0x00,0x60, // 194 + 0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x1C,0x00,0x80,0x07,0x00,0x72,0x04,0x00,0x09,0x04,0x00,0x72,0x04,0x00,0x81,0x07,0x00,0x00,0x1C,0x00,0x00,0x60, // 195 + 0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x1C,0x00,0x80,0x07,0x00,0x72,0x04,0x00,0x08,0x04,0x00,0x72,0x04,0x00,0x80,0x07,0x00,0x00,0x1C,0x00,0x00,0x60, // 196 + 0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x1C,0x00,0x80,0x07,0x00,0x7E,0x04,0x00,0x0A,0x04,0x00,0x7E,0x04,0x00,0x80,0x07,0x00,0x00,0x1C,0x00,0x00,0x60, // 197 + 0x00,0x60,0x00,0x00,0x18,0x00,0x00,0x06,0x00,0x80,0x05,0x00,0x60,0x04,0x00,0x18,0x04,0x00,0x08,0x04,0x00,0x08,0x04,0x00,0xF8,0x7F,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x41, // 198 + 0x00,0x00,0x00,0xC0,0x0F,0x00,0x20,0x10,0x00,0x10,0x20,0x00,0x08,0x40,0x00,0x08,0x40,0x02,0x08,0xC0,0x02,0x08,0x40,0x03,0x08,0x40,0x00,0x10,0x20,0x00,0x20,0x10, // 199 + 0x00,0x00,0x00,0xF8,0x7F,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x09,0x41,0x00,0x0A,0x41,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x40, // 200 + 0x00,0x00,0x00,0xF8,0x7F,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x0A,0x41,0x00,0x09,0x41,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x40, // 201 + 0x00,0x00,0x00,0xF8,0x7F,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x0A,0x41,0x00,0x09,0x41,0x00,0x09,0x41,0x00,0x0A,0x41,0x00,0x08,0x41,0x00,0x08,0x40, // 202 + 0x00,0x00,0x00,0xF8,0x7F,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x0A,0x41,0x00,0x08,0x41,0x00,0x0A,0x41,0x00,0x08,0x41,0x00,0x08,0x41,0x00,0x08,0x40, // 203 + 0x01,0x00,0x00,0xFA,0x7F, // 204 + 0x00,0x00,0x00,0xFA,0x7F,0x00,0x01, // 205 + 0x02,0x00,0x00,0xF9,0x7F,0x00,0x01,0x00,0x00,0x02, // 206 + 0x02,0x00,0x00,0xF8,0x7F,0x00,0x02, // 207 + 0x00,0x02,0x00,0xF8,0x7F,0x00,0x08,0x42,0x00,0x08,0x42,0x00,0x08,0x42,0x00,0x08,0x42,0x00,0x08,0x40,0x00,0x08,0x40,0x00,0x10,0x20,0x00,0x20,0x10,0x00,0xC0,0x0F, // 208 + 0x00,0x00,0x00,0xF8,0x7F,0x00,0x10,0x00,0x00,0x60,0x00,0x00,0x82,0x00,0x00,0x01,0x03,0x00,0x02,0x04,0x00,0x01,0x18,0x00,0x00,0x20,0x00,0xF8,0x7F, // 209 + 0x00,0x00,0x00,0xC0,0x0F,0x00,0x20,0x10,0x00,0x10,0x20,0x00,0x08,0x40,0x00,0x09,0x40,0x00,0x0A,0x40,0x00,0x08,0x40,0x00,0x10,0x20,0x00,0x20,0x10,0x00,0xC0,0x0F, // 210 + 0x00,0x00,0x00,0xC0,0x0F,0x00,0x20,0x10,0x00,0x10,0x20,0x00,0x08,0x40,0x00,0x0A,0x40,0x00,0x09,0x40,0x00,0x08,0x40,0x00,0x10,0x20,0x00,0x20,0x10,0x00,0xC0,0x0F, // 211 + 0x00,0x00,0x00,0xC0,0x0F,0x00,0x20,0x10,0x00,0x10,0x20,0x00,0x0A,0x40,0x00,0x09,0x40,0x00,0x09,0x40,0x00,0x0A,0x40,0x00,0x10,0x20,0x00,0x20,0x10,0x00,0xC0,0x0F, // 212 + 0x00,0x00,0x00,0xC0,0x0F,0x00,0x20,0x10,0x00,0x10,0x20,0x00,0x0A,0x40,0x00,0x09,0x40,0x00,0x0A,0x40,0x00,0x09,0x40,0x00,0x10,0x20,0x00,0x20,0x10,0x00,0xC0,0x0F, // 213 + 0x00,0x00,0x00,0xC0,0x0F,0x00,0x20,0x10,0x00,0x10,0x20,0x00,0x08,0x40,0x00,0x0A,0x40,0x00,0x08,0x40,0x00,0x0A,0x40,0x00,0x10,0x20,0x00,0x20,0x10,0x00,0xC0,0x0F, // 214 + 0x00,0x00,0x00,0x40,0x10,0x00,0x80,0x08,0x00,0x00,0x05,0x00,0x00,0x07,0x00,0x00,0x05,0x00,0x80,0x08,0x00,0x40,0x10, // 215 + 0x00,0x00,0x00,0xC0,0x4F,0x00,0x20,0x30,0x00,0x10,0x30,0x00,0x08,0x4C,0x00,0x08,0x42,0x00,0x08,0x41,0x00,0xC8,0x40,0x00,0x30,0x20,0x00,0x30,0x10,0x00,0xC8,0x0F, // 216 + 0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x20,0x00,0x00,0x40,0x00,0x01,0x40,0x00,0x02,0x40,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x20,0x00,0xF8,0x1F, // 217 + 0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x20,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x02,0x40,0x00,0x01,0x40,0x00,0x00,0x40,0x00,0x00,0x20,0x00,0xF8,0x1F, // 218 + 0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x20,0x00,0x00,0x40,0x00,0x02,0x40,0x00,0x01,0x40,0x00,0x01,0x40,0x00,0x02,0x40,0x00,0x00,0x20,0x00,0xF8,0x1F, // 219 + 0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x20,0x00,0x00,0x40,0x00,0x02,0x40,0x00,0x00,0x40,0x00,0x02,0x40,0x00,0x00,0x40,0x00,0x00,0x20,0x00,0xF8,0x1F, // 220 + 0x08,0x00,0x00,0x30,0x00,0x00,0x40,0x00,0x00,0x80,0x01,0x00,0x02,0x7E,0x00,0x81,0x01,0x00,0x40,0x00,0x00,0x30,0x00,0x00,0x08, // 221 + 0x00,0x00,0x00,0xF8,0x7F,0x00,0x20,0x10,0x00,0x20,0x10,0x00,0x20,0x10,0x00,0x20,0x10,0x00,0x20,0x10,0x00,0x20,0x10,0x00,0x40,0x08,0x00,0x80,0x07, // 222 + 0x00,0x00,0x00,0xE0,0x7F,0x00,0x10,0x00,0x00,0x08,0x20,0x00,0x88,0x43,0x00,0x70,0x42,0x00,0x00,0x44,0x00,0x00,0x38, // 223 + 0x00,0x00,0x00,0x00,0x39,0x00,0x80,0x44,0x00,0x40,0x44,0x00,0x48,0x44,0x00,0x50,0x42,0x00,0x40,0x22,0x00,0x80,0x7F, // 224 + 0x00,0x00,0x00,0x00,0x39,0x00,0x80,0x44,0x00,0x40,0x44,0x00,0x50,0x44,0x00,0x48,0x42,0x00,0x40,0x22,0x00,0x80,0x7F, // 225 + 0x00,0x00,0x00,0x00,0x39,0x00,0x80,0x44,0x00,0x50,0x44,0x00,0x48,0x44,0x00,0x48,0x42,0x00,0x50,0x22,0x00,0x80,0x7F, // 226 + 0x00,0x00,0x00,0x00,0x39,0x00,0x80,0x44,0x00,0x50,0x44,0x00,0x48,0x44,0x00,0x50,0x42,0x00,0x48,0x22,0x00,0x80,0x7F, // 227 + 0x00,0x00,0x00,0x00,0x39,0x00,0x80,0x44,0x00,0x50,0x44,0x00,0x40,0x44,0x00,0x50,0x42,0x00,0x40,0x22,0x00,0x80,0x7F, // 228 + 0x00,0x00,0x00,0x00,0x39,0x00,0x80,0x44,0x00,0x5C,0x44,0x00,0x54,0x44,0x00,0x5C,0x42,0x00,0x40,0x22,0x00,0x80,0x7F, // 229 + 0x00,0x00,0x00,0x00,0x39,0x00,0x80,0x44,0x00,0x40,0x44,0x00,0x40,0x44,0x00,0x40,0x42,0x00,0x40,0x22,0x00,0x80,0x3F,0x00,0x80,0x24,0x00,0x40,0x44,0x00,0x40,0x44,0x00,0x40,0x44,0x00,0x80,0x24,0x00,0x00,0x17, // 230 + 0x00,0x00,0x00,0x00,0x1F,0x00,0x80,0x20,0x00,0x40,0x40,0x02,0x40,0xC0,0x02,0x40,0x40,0x03,0x80,0x20, // 231 + 0x00,0x00,0x00,0x00,0x1F,0x00,0x80,0x24,0x00,0x48,0x44,0x00,0x50,0x44,0x00,0x40,0x44,0x00,0x80,0x24,0x00,0x00,0x17, // 232 + 0x00,0x00,0x00,0x00,0x1F,0x00,0x80,0x24,0x00,0x40,0x44,0x00,0x50,0x44,0x00,0x48,0x44,0x00,0x80,0x24,0x00,0x00,0x17, // 233 + 0x00,0x00,0x00,0x00,0x1F,0x00,0x80,0x24,0x00,0x50,0x44,0x00,0x48,0x44,0x00,0x48,0x44,0x00,0x90,0x24,0x00,0x00,0x17, // 234 + 0x00,0x00,0x00,0x00,0x1F,0x00,0x80,0x24,0x00,0x50,0x44,0x00,0x40,0x44,0x00,0x50,0x44,0x00,0x80,0x24,0x00,0x00,0x17, // 235 + 0x08,0x00,0x00,0xD0,0x7F, // 236 + 0x00,0x00,0x00,0xD0,0x7F,0x00,0x08, // 237 + 0x10,0x00,0x00,0xC8,0x7F,0x00,0x08,0x00,0x00,0x10, // 238 + 0x10,0x00,0x00,0xC0,0x7F,0x00,0x10, // 239 + 0x00,0x00,0x00,0x00,0x1F,0x00,0xA0,0x20,0x00,0x68,0x40,0x00,0x58,0x40,0x00,0x70,0x40,0x00,0xE8,0x20,0x00,0x00,0x1F, // 240 + 0x00,0x00,0x00,0xC0,0x7F,0x00,0x90,0x00,0x00,0x48,0x00,0x00,0x50,0x00,0x00,0x48,0x00,0x00,0x80,0x7F, // 241 + 0x00,0x00,0x00,0x00,0x1F,0x00,0x80,0x20,0x00,0x48,0x40,0x00,0x50,0x40,0x00,0x40,0x40,0x00,0x80,0x20,0x00,0x00,0x1F, // 242 + 0x00,0x00,0x00,0x00,0x1F,0x00,0x80,0x20,0x00,0x40,0x40,0x00,0x50,0x40,0x00,0x48,0x40,0x00,0x80,0x20,0x00,0x00,0x1F, // 243 + 0x00,0x00,0x00,0x00,0x1F,0x00,0x80,0x20,0x00,0x50,0x40,0x00,0x48,0x40,0x00,0x48,0x40,0x00,0x90,0x20,0x00,0x00,0x1F, // 244 + 0x00,0x00,0x00,0x00,0x1F,0x00,0x80,0x20,0x00,0x50,0x40,0x00,0x48,0x40,0x00,0x50,0x40,0x00,0x88,0x20,0x00,0x00,0x1F, // 245 + 0x00,0x00,0x00,0x00,0x1F,0x00,0x80,0x20,0x00,0x50,0x40,0x00,0x40,0x40,0x00,0x50,0x40,0x00,0x80,0x20,0x00,0x00,0x1F, // 246 + 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x80,0x0A,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x02, // 247 + 0x00,0x00,0x00,0x00,0x5F,0x00,0x80,0x30,0x00,0x40,0x48,0x00,0x40,0x44,0x00,0x40,0x42,0x00,0x80,0x21,0x00,0x40,0x1F, // 248 + 0x00,0x00,0x00,0xC0,0x3F,0x00,0x00,0x40,0x00,0x08,0x40,0x00,0x10,0x40,0x00,0x00,0x20,0x00,0xC0,0x7F, // 249 + 0x00,0x00,0x00,0xC0,0x3F,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x10,0x40,0x00,0x08,0x20,0x00,0xC0,0x7F, // 250 + 0x00,0x00,0x00,0xC0,0x3F,0x00,0x10,0x40,0x00,0x08,0x40,0x00,0x08,0x40,0x00,0x10,0x20,0x00,0xC0,0x7F, // 251 + 0x00,0x00,0x00,0xD0,0x3F,0x00,0x00,0x40,0x00,0x10,0x40,0x00,0x00,0x40,0x00,0x00,0x20,0x00,0xC0,0x7F, // 252 + 0xC0,0x01,0x00,0x00,0x06,0x02,0x00,0x38,0x02,0x10,0xE0,0x01,0x08,0x38,0x00,0x00,0x07,0x00,0xC0, // 253 + 0x00,0x00,0x00,0xF8,0xFF,0x03,0x80,0x20,0x00,0x40,0x40,0x00,0x40,0x40,0x00,0x40,0x40,0x00,0x80,0x20,0x00,0x00,0x1F, // 254 + 0xC0,0x01,0x00,0x00,0x06,0x02,0x10,0x38,0x02,0x00,0xE0,0x01,0x10,0x38,0x00,0x00,0x07,0x00,0xC0 // 255 +}; +const uint8_t ArialMT_Plain_24[] PROGMEM = { + 0x18, // Width: 24 + 0x1C, // Height: 28 + 0x20, // First Char: 32 + 0xE0, // Numbers of Chars: 224 + + // Jump Table: + 0xFF, 0xFF, 0x00, 0x07, // 32:65535 + 0x00, 0x00, 0x13, 0x07, // 33:0 + 0x00, 0x13, 0x1A, 0x09, // 34:19 + 0x00, 0x2D, 0x33, 0x0D, // 35:45 + 0x00, 0x60, 0x2F, 0x0D, // 36:96 + 0x00, 0x8F, 0x4F, 0x15, // 37:143 + 0x00, 0xDE, 0x3B, 0x10, // 38:222 + 0x01, 0x19, 0x0A, 0x05, // 39:281 + 0x01, 0x23, 0x1C, 0x08, // 40:291 + 0x01, 0x3F, 0x1B, 0x08, // 41:319 + 0x01, 0x5A, 0x21, 0x09, // 42:346 + 0x01, 0x7B, 0x32, 0x0E, // 43:379 + 0x01, 0xAD, 0x10, 0x07, // 44:429 + 0x01, 0xBD, 0x1B, 0x08, // 45:445 + 0x01, 0xD8, 0x0F, 0x07, // 46:472 + 0x01, 0xE7, 0x19, 0x07, // 47:487 + 0x02, 0x00, 0x2F, 0x0D, // 48:512 + 0x02, 0x2F, 0x23, 0x0D, // 49:559 + 0x02, 0x52, 0x2F, 0x0D, // 50:594 + 0x02, 0x81, 0x2F, 0x0D, // 51:641 + 0x02, 0xB0, 0x2F, 0x0D, // 52:688 + 0x02, 0xDF, 0x2F, 0x0D, // 53:735 + 0x03, 0x0E, 0x2F, 0x0D, // 54:782 + 0x03, 0x3D, 0x2D, 0x0D, // 55:829 + 0x03, 0x6A, 0x2F, 0x0D, // 56:874 + 0x03, 0x99, 0x2F, 0x0D, // 57:921 + 0x03, 0xC8, 0x0F, 0x07, // 58:968 + 0x03, 0xD7, 0x10, 0x07, // 59:983 + 0x03, 0xE7, 0x2F, 0x0E, // 60:999 + 0x04, 0x16, 0x2F, 0x0E, // 61:1046 + 0x04, 0x45, 0x2E, 0x0E, // 62:1093 + 0x04, 0x73, 0x2E, 0x0D, // 63:1139 + 0x04, 0xA1, 0x5B, 0x18, // 64:1185 + 0x04, 0xFC, 0x3B, 0x10, // 65:1276 + 0x05, 0x37, 0x3B, 0x10, // 66:1335 + 0x05, 0x72, 0x3F, 0x11, // 67:1394 + 0x05, 0xB1, 0x3F, 0x11, // 68:1457 + 0x05, 0xF0, 0x3B, 0x10, // 69:1520 + 0x06, 0x2B, 0x35, 0x0F, // 70:1579 + 0x06, 0x60, 0x43, 0x13, // 71:1632 + 0x06, 0xA3, 0x3B, 0x11, // 72:1699 + 0x06, 0xDE, 0x0F, 0x07, // 73:1758 + 0x06, 0xED, 0x27, 0x0C, // 74:1773 + 0x07, 0x14, 0x3F, 0x10, // 75:1812 + 0x07, 0x53, 0x2F, 0x0D, // 76:1875 + 0x07, 0x82, 0x43, 0x14, // 77:1922 + 0x07, 0xC5, 0x3B, 0x11, // 78:1989 + 0x08, 0x00, 0x47, 0x13, // 79:2048 + 0x08, 0x47, 0x3A, 0x10, // 80:2119 + 0x08, 0x81, 0x47, 0x13, // 81:2177 + 0x08, 0xC8, 0x3F, 0x11, // 82:2248 + 0x09, 0x07, 0x3B, 0x10, // 83:2311 + 0x09, 0x42, 0x35, 0x0F, // 84:2370 + 0x09, 0x77, 0x3B, 0x11, // 85:2423 + 0x09, 0xB2, 0x39, 0x10, // 86:2482 + 0x09, 0xEB, 0x59, 0x17, // 87:2539 + 0x0A, 0x44, 0x3B, 0x10, // 88:2628 + 0x0A, 0x7F, 0x3D, 0x10, // 89:2687 + 0x0A, 0xBC, 0x37, 0x0F, // 90:2748 + 0x0A, 0xF3, 0x14, 0x07, // 91:2803 + 0x0B, 0x07, 0x1B, 0x07, // 92:2823 + 0x0B, 0x22, 0x18, 0x07, // 93:2850 + 0x0B, 0x3A, 0x2A, 0x0B, // 94:2874 + 0x0B, 0x64, 0x34, 0x0D, // 95:2916 + 0x0B, 0x98, 0x11, 0x08, // 96:2968 + 0x0B, 0xA9, 0x2F, 0x0D, // 97:2985 + 0x0B, 0xD8, 0x33, 0x0D, // 98:3032 + 0x0C, 0x0B, 0x2B, 0x0C, // 99:3083 + 0x0C, 0x36, 0x2F, 0x0D, // 100:3126 + 0x0C, 0x65, 0x2F, 0x0D, // 101:3173 + 0x0C, 0x94, 0x1A, 0x07, // 102:3220 + 0x0C, 0xAE, 0x2F, 0x0D, // 103:3246 + 0x0C, 0xDD, 0x2F, 0x0D, // 104:3293 + 0x0D, 0x0C, 0x0F, 0x05, // 105:3340 + 0x0D, 0x1B, 0x10, 0x05, // 106:3355 + 0x0D, 0x2B, 0x2F, 0x0C, // 107:3371 + 0x0D, 0x5A, 0x0F, 0x05, // 108:3418 + 0x0D, 0x69, 0x47, 0x14, // 109:3433 + 0x0D, 0xB0, 0x2F, 0x0D, // 110:3504 + 0x0D, 0xDF, 0x2F, 0x0D, // 111:3551 + 0x0E, 0x0E, 0x33, 0x0D, // 112:3598 + 0x0E, 0x41, 0x30, 0x0D, // 113:3649 + 0x0E, 0x71, 0x1E, 0x08, // 114:3697 + 0x0E, 0x8F, 0x2B, 0x0C, // 115:3727 + 0x0E, 0xBA, 0x1B, 0x07, // 116:3770 + 0x0E, 0xD5, 0x2F, 0x0D, // 117:3797 + 0x0F, 0x04, 0x2A, 0x0C, // 118:3844 + 0x0F, 0x2E, 0x42, 0x11, // 119:3886 + 0x0F, 0x70, 0x2B, 0x0C, // 120:3952 + 0x0F, 0x9B, 0x2A, 0x0C, // 121:3995 + 0x0F, 0xC5, 0x2B, 0x0C, // 122:4037 + 0x0F, 0xF0, 0x1C, 0x08, // 123:4080 + 0x10, 0x0C, 0x10, 0x06, // 124:4108 + 0x10, 0x1C, 0x1B, 0x08, // 125:4124 + 0x10, 0x37, 0x32, 0x0E, // 126:4151 + 0xFF, 0xFF, 0x00, 0x00, // 127:65535 + 0xFF, 0xFF, 0x00, 0x18, // 128:65535 + 0xFF, 0xFF, 0x00, 0x18, // 129:65535 + 0xFF, 0xFF, 0x00, 0x18, // 130:65535 + 0xFF, 0xFF, 0x00, 0x18, // 131:65535 + 0xFF, 0xFF, 0x00, 0x18, // 132:65535 + 0xFF, 0xFF, 0x00, 0x18, // 133:65535 + 0xFF, 0xFF, 0x00, 0x18, // 134:65535 + 0xFF, 0xFF, 0x00, 0x18, // 135:65535 + 0xFF, 0xFF, 0x00, 0x18, // 136:65535 + 0xFF, 0xFF, 0x00, 0x18, // 137:65535 + 0xFF, 0xFF, 0x00, 0x18, // 138:65535 + 0xFF, 0xFF, 0x00, 0x18, // 139:65535 + 0xFF, 0xFF, 0x00, 0x18, // 140:65535 + 0xFF, 0xFF, 0x00, 0x18, // 141:65535 + 0xFF, 0xFF, 0x00, 0x18, // 142:65535 + 0xFF, 0xFF, 0x00, 0x18, // 143:65535 + 0xFF, 0xFF, 0x00, 0x18, // 144:65535 + 0xFF, 0xFF, 0x00, 0x18, // 145:65535 + 0xFF, 0xFF, 0x00, 0x18, // 146:65535 + 0xFF, 0xFF, 0x00, 0x18, // 147:65535 + 0xFF, 0xFF, 0x00, 0x18, // 148:65535 + 0xFF, 0xFF, 0x00, 0x18, // 149:65535 + 0xFF, 0xFF, 0x00, 0x18, // 150:65535 + 0xFF, 0xFF, 0x00, 0x18, // 151:65535 + 0xFF, 0xFF, 0x00, 0x18, // 152:65535 + 0xFF, 0xFF, 0x00, 0x18, // 153:65535 + 0xFF, 0xFF, 0x00, 0x18, // 154:65535 + 0xFF, 0xFF, 0x00, 0x18, // 155:65535 + 0xFF, 0xFF, 0x00, 0x18, // 156:65535 + 0xFF, 0xFF, 0x00, 0x18, // 157:65535 + 0xFF, 0xFF, 0x00, 0x18, // 158:65535 + 0xFF, 0xFF, 0x00, 0x18, // 159:65535 + 0xFF, 0xFF, 0x00, 0x07, // 160:65535 + 0x10, 0x69, 0x14, 0x08, // 161:4201 + 0x10, 0x7D, 0x2B, 0x0D, // 162:4221 + 0x10, 0xA8, 0x2F, 0x0D, // 163:4264 + 0x10, 0xD7, 0x33, 0x0D, // 164:4311 + 0x11, 0x0A, 0x31, 0x0D, // 165:4362 + 0x11, 0x3B, 0x10, 0x06, // 166:4411 + 0x11, 0x4B, 0x2F, 0x0D, // 167:4427 + 0x11, 0x7A, 0x19, 0x08, // 168:4474 + 0x11, 0x93, 0x46, 0x12, // 169:4499 + 0x11, 0xD9, 0x1A, 0x09, // 170:4569 + 0x11, 0xF3, 0x27, 0x0D, // 171:4595 + 0x12, 0x1A, 0x2F, 0x0E, // 172:4634 + 0x12, 0x49, 0x1B, 0x08, // 173:4681 + 0x12, 0x64, 0x46, 0x12, // 174:4708 + 0x12, 0xAA, 0x31, 0x0D, // 175:4778 + 0x12, 0xDB, 0x1E, 0x0A, // 176:4827 + 0x12, 0xF9, 0x33, 0x0D, // 177:4857 + 0x13, 0x2C, 0x1A, 0x08, // 178:4908 + 0x13, 0x46, 0x1A, 0x08, // 179:4934 + 0x13, 0x60, 0x19, 0x08, // 180:4960 + 0x13, 0x79, 0x2F, 0x0E, // 181:4985 + 0x13, 0xA8, 0x31, 0x0D, // 182:5032 + 0x13, 0xD9, 0x12, 0x08, // 183:5081 + 0x13, 0xEB, 0x18, 0x08, // 184:5099 + 0x14, 0x03, 0x16, 0x08, // 185:5123 + 0x14, 0x19, 0x1E, 0x09, // 186:5145 + 0x14, 0x37, 0x2E, 0x0D, // 187:5175 + 0x14, 0x65, 0x4F, 0x14, // 188:5221 + 0x14, 0xB4, 0x4B, 0x14, // 189:5300 + 0x14, 0xFF, 0x4B, 0x14, // 190:5375 + 0x15, 0x4A, 0x33, 0x0F, // 191:5450 + 0x15, 0x7D, 0x3B, 0x10, // 192:5501 + 0x15, 0xB8, 0x3B, 0x10, // 193:5560 + 0x15, 0xF3, 0x3B, 0x10, // 194:5619 + 0x16, 0x2E, 0x3B, 0x10, // 195:5678 + 0x16, 0x69, 0x3B, 0x10, // 196:5737 + 0x16, 0xA4, 0x3B, 0x10, // 197:5796 + 0x16, 0xDF, 0x5B, 0x18, // 198:5855 + 0x17, 0x3A, 0x3F, 0x11, // 199:5946 + 0x17, 0x79, 0x3B, 0x10, // 200:6009 + 0x17, 0xB4, 0x3B, 0x10, // 201:6068 + 0x17, 0xEF, 0x3B, 0x10, // 202:6127 + 0x18, 0x2A, 0x3B, 0x10, // 203:6186 + 0x18, 0x65, 0x11, 0x07, // 204:6245 + 0x18, 0x76, 0x11, 0x07, // 205:6262 + 0x18, 0x87, 0x15, 0x07, // 206:6279 + 0x18, 0x9C, 0x15, 0x07, // 207:6300 + 0x18, 0xB1, 0x3F, 0x11, // 208:6321 + 0x18, 0xF0, 0x3B, 0x11, // 209:6384 + 0x19, 0x2B, 0x47, 0x13, // 210:6443 + 0x19, 0x72, 0x47, 0x13, // 211:6514 + 0x19, 0xB9, 0x47, 0x13, // 212:6585 + 0x1A, 0x00, 0x47, 0x13, // 213:6656 + 0x1A, 0x47, 0x47, 0x13, // 214:6727 + 0x1A, 0x8E, 0x2B, 0x0E, // 215:6798 + 0x1A, 0xB9, 0x47, 0x13, // 216:6841 + 0x1B, 0x00, 0x3B, 0x11, // 217:6912 + 0x1B, 0x3B, 0x3B, 0x11, // 218:6971 + 0x1B, 0x76, 0x3B, 0x11, // 219:7030 + 0x1B, 0xB1, 0x3B, 0x11, // 220:7089 + 0x1B, 0xEC, 0x3D, 0x10, // 221:7148 + 0x1C, 0x29, 0x3A, 0x10, // 222:7209 + 0x1C, 0x63, 0x37, 0x0F, // 223:7267 + 0x1C, 0x9A, 0x2F, 0x0D, // 224:7322 + 0x1C, 0xC9, 0x2F, 0x0D, // 225:7369 + 0x1C, 0xF8, 0x2F, 0x0D, // 226:7416 + 0x1D, 0x27, 0x2F, 0x0D, // 227:7463 + 0x1D, 0x56, 0x2F, 0x0D, // 228:7510 + 0x1D, 0x85, 0x2F, 0x0D, // 229:7557 + 0x1D, 0xB4, 0x53, 0x15, // 230:7604 + 0x1E, 0x07, 0x2B, 0x0C, // 231:7687 + 0x1E, 0x32, 0x2F, 0x0D, // 232:7730 + 0x1E, 0x61, 0x2F, 0x0D, // 233:7777 + 0x1E, 0x90, 0x2F, 0x0D, // 234:7824 + 0x1E, 0xBF, 0x2F, 0x0D, // 235:7871 + 0x1E, 0xEE, 0x11, 0x07, // 236:7918 + 0x1E, 0xFF, 0x11, 0x07, // 237:7935 + 0x1F, 0x10, 0x15, 0x07, // 238:7952 + 0x1F, 0x25, 0x15, 0x07, // 239:7973 + 0x1F, 0x3A, 0x2F, 0x0D, // 240:7994 + 0x1F, 0x69, 0x2F, 0x0D, // 241:8041 + 0x1F, 0x98, 0x2F, 0x0D, // 242:8088 + 0x1F, 0xC7, 0x2F, 0x0D, // 243:8135 + 0x1F, 0xF6, 0x2F, 0x0D, // 244:8182 + 0x20, 0x25, 0x2F, 0x0D, // 245:8229 + 0x20, 0x54, 0x2F, 0x0D, // 246:8276 + 0x20, 0x83, 0x32, 0x0D, // 247:8323 + 0x20, 0xB5, 0x33, 0x0F, // 248:8373 + 0x20, 0xE8, 0x2F, 0x0D, // 249:8424 + 0x21, 0x17, 0x2F, 0x0D, // 250:8471 + 0x21, 0x46, 0x2F, 0x0D, // 251:8518 + 0x21, 0x75, 0x2F, 0x0D, // 252:8565 + 0x21, 0xA4, 0x2A, 0x0C, // 253:8612 + 0x21, 0xCE, 0x2F, 0x0D, // 254:8654 + 0x21, 0xFD, 0x2A, 0x0C, // 255:8701 + + // Font Data: + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x33,0x00,0xE0,0xFF,0x33, // 33 + 0x00,0x00,0x00,0x00,0xE0,0x07,0x00,0x00,0xE0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x07,0x00,0x00,0xE0,0x07, // 34 + 0x00,0x0C,0x03,0x00,0x00,0x0C,0x33,0x00,0x00,0x0C,0x3F,0x00,0x00,0xFC,0x0F,0x00,0x80,0xFF,0x03,0x00,0xE0,0x0F,0x03,0x00,0x60,0x0C,0x33,0x00,0x00,0x0C,0x3F,0x00,0x00,0xFC,0x0F,0x00,0x80,0xFF,0x03,0x00,0xE0,0x0F,0x03,0x00,0x60,0x0C,0x03,0x00,0x00,0x0C,0x03, // 35 + 0x00,0x00,0x00,0x00,0x80,0x07,0x06,0x00,0xC0,0x0F,0x1E,0x00,0xC0,0x18,0x1C,0x00,0x60,0x18,0x38,0x00,0x60,0x30,0x30,0x00,0xF0,0xFF,0xFF,0x00,0x60,0x30,0x30,0x00,0x60,0x60,0x38,0x00,0xC0,0x60,0x18,0x00,0xC0,0xC1,0x1F,0x00,0x00,0x81,0x07, // 36 + 0x00,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0xC0,0x1F,0x00,0x00,0x60,0x30,0x00,0x00,0x20,0x20,0x00,0x00,0x20,0x20,0x20,0x00,0x60,0x30,0x38,0x00,0xC0,0x1F,0x1E,0x00,0x80,0x8F,0x0F,0x00,0x00,0xC0,0x03,0x00,0x00,0xF0,0x00,0x00,0x00,0x3C,0x00,0x00,0x00,0x8F,0x0F,0x00,0xC0,0xC3,0x1F,0x00,0xE0,0x60,0x30,0x00,0x20,0x20,0x20,0x00,0x00,0x20,0x20,0x00,0x00,0x60,0x30,0x00,0x00,0xC0,0x1F,0x00,0x00,0x80,0x0F, // 37 + 0x00,0x00,0x00,0x00,0x00,0x80,0x07,0x00,0x00,0xC0,0x0F,0x00,0x80,0xE3,0x1C,0x00,0xC0,0x77,0x38,0x00,0xE0,0x3C,0x30,0x00,0x60,0x38,0x30,0x00,0x60,0x78,0x30,0x00,0xE0,0xEC,0x38,0x00,0xC0,0x8F,0x1B,0x00,0x80,0x03,0x1F,0x00,0x00,0x00,0x0F,0x00,0x00,0xC0,0x1F,0x00,0x00,0xC0,0x38,0x00,0x00,0x00,0x10, // 38 + 0x00,0x00,0x00,0x00,0xE0,0x07,0x00,0x00,0xE0,0x07, // 39 + 0x00,0x00,0x00,0x00,0x00,0xF0,0x0F,0x00,0x00,0xFE,0x7F,0x00,0x80,0x0F,0xF0,0x01,0xC0,0x01,0x80,0x03,0x60,0x00,0x00,0x06,0x20,0x00,0x00,0x04, // 40 + 0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x04,0x60,0x00,0x00,0x06,0xC0,0x01,0x80,0x03,0x80,0x0F,0xF0,0x01,0x00,0xFE,0x7F,0x00,0x00,0xF0,0x0F, // 41 + 0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x04,0x00,0x00,0x80,0x0F,0x00,0x00,0xE0,0x03,0x00,0x00,0xE0,0x03,0x00,0x00,0x80,0x0F,0x00,0x00,0x80,0x04,0x00,0x00,0x80, // 42 + 0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0xFF,0x0F,0x00,0x00,0xFF,0x0F,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60, // 43 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x03,0x00,0x00,0xF0,0x01, // 44 + 0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01, // 45 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30, // 46 + 0x00,0x00,0x30,0x00,0x00,0x00,0x3E,0x00,0x00,0xE0,0x0F,0x00,0x00,0xFC,0x01,0x00,0x80,0x3F,0x00,0x00,0xE0,0x03,0x00,0x00,0x60, // 47 + 0x00,0x00,0x00,0x00,0x00,0xFE,0x03,0x00,0x80,0xFF,0x0F,0x00,0xC0,0x01,0x1C,0x00,0xE0,0x00,0x38,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0xE0,0x00,0x38,0x00,0xC0,0x01,0x1C,0x00,0x80,0xFF,0x0F,0x00,0x00,0xFE,0x03, // 48 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x03,0x00,0x00,0x80,0x01,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F, // 49 + 0x00,0x00,0x00,0x00,0x00,0x03,0x30,0x00,0xC0,0x03,0x38,0x00,0xC0,0x00,0x3C,0x00,0x60,0x00,0x36,0x00,0x60,0x00,0x33,0x00,0x60,0x80,0x31,0x00,0x60,0xC0,0x30,0x00,0x60,0x60,0x30,0x00,0xC0,0x30,0x30,0x00,0xC0,0x1F,0x30,0x00,0x00,0x0F,0x30, // 50 + 0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x00,0xC0,0x01,0x0E,0x00,0xC0,0x00,0x1C,0x00,0x60,0x00,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0xC0,0x38,0x30,0x00,0xC0,0x6F,0x18,0x00,0x80,0xC7,0x0F,0x00,0x00,0x80,0x07, // 51 + 0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x00,0xC0,0x03,0x00,0x00,0xF0,0x03,0x00,0x00,0x3C,0x03,0x00,0x00,0x0E,0x03,0x00,0x80,0x07,0x03,0x00,0xC0,0x01,0x03,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03, // 52 + 0x00,0x00,0x00,0x00,0x00,0x30,0x06,0x00,0x80,0x3F,0x0E,0x00,0xE0,0x1F,0x18,0x00,0x60,0x08,0x30,0x00,0x60,0x0C,0x30,0x00,0x60,0x0C,0x30,0x00,0x60,0x0C,0x30,0x00,0x60,0x0C,0x30,0x00,0x60,0x18,0x1C,0x00,0x60,0xF0,0x0F,0x00,0x00,0xE0,0x03, // 53 + 0x00,0x00,0x00,0x00,0x00,0xFC,0x03,0x00,0x80,0xFF,0x0F,0x00,0xC0,0x63,0x1C,0x00,0xC0,0x30,0x38,0x00,0x60,0x18,0x30,0x00,0x60,0x18,0x30,0x00,0x60,0x18,0x30,0x00,0x60,0x18,0x30,0x00,0xE0,0x30,0x18,0x00,0xC0,0xF1,0x0F,0x00,0x80,0xC1,0x07, // 54 + 0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x3C,0x00,0x60,0x80,0x3F,0x00,0x60,0xE0,0x03,0x00,0x60,0x78,0x00,0x00,0x60,0x0E,0x00,0x00,0x60,0x03,0x00,0x00,0xE0,0x01,0x00,0x00,0x60, // 55 + 0x00,0x00,0x00,0x00,0x00,0x80,0x07,0x00,0x80,0xC7,0x1F,0x00,0xC0,0x6F,0x18,0x00,0xE0,0x38,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0xE0,0x38,0x30,0x00,0xC0,0x6F,0x18,0x00,0x80,0xC7,0x1F,0x00,0x00,0x80,0x07, // 56 + 0x00,0x00,0x00,0x00,0x00,0x1F,0x0C,0x00,0x80,0x7F,0x1C,0x00,0xC0,0x61,0x38,0x00,0x60,0xC0,0x30,0x00,0x60,0xC0,0x30,0x00,0x60,0xC0,0x30,0x00,0x60,0xC0,0x30,0x00,0x60,0x60,0x18,0x00,0xC0,0x31,0x1E,0x00,0x80,0xFF,0x0F,0x00,0x00,0xFE,0x01, // 57 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x30,0x00,0x00,0x06,0x30, // 58 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x30,0x03,0x00,0x06,0xF0,0x01, // 59 + 0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0xD8,0x00,0x00,0x00,0xD8,0x00,0x00,0x00,0x8C,0x01,0x00,0x00,0x8C,0x01,0x00,0x00,0x04,0x01,0x00,0x00,0x06,0x03,0x00,0x00,0x06,0x03,0x00,0x00,0x03,0x06, // 60 + 0x00,0x00,0x00,0x00,0x00,0x8C,0x01,0x00,0x00,0x8C,0x01,0x00,0x00,0x8C,0x01,0x00,0x00,0x8C,0x01,0x00,0x00,0x8C,0x01,0x00,0x00,0x8C,0x01,0x00,0x00,0x8C,0x01,0x00,0x00,0x8C,0x01,0x00,0x00,0x8C,0x01,0x00,0x00,0x8C,0x01,0x00,0x00,0x8C,0x01, // 61 + 0x00,0x00,0x00,0x00,0x00,0x03,0x06,0x00,0x00,0x06,0x03,0x00,0x00,0x06,0x03,0x00,0x00,0x04,0x01,0x00,0x00,0x8C,0x01,0x00,0x00,0x8C,0x01,0x00,0x00,0xD8,0x00,0x00,0x00,0xD8,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x20, // 62 + 0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x80,0x03,0x00,0x00,0xC0,0x01,0x00,0x00,0xE0,0x00,0x00,0x00,0x60,0x80,0x33,0x00,0x60,0xC0,0x33,0x00,0x60,0xE0,0x00,0x00,0x60,0x30,0x00,0x00,0xC0,0x38,0x00,0x00,0xC0,0x1F,0x00,0x00,0x00,0x07, // 63 + 0x00,0x00,0x00,0x00,0x00,0xE0,0x0F,0x00,0x00,0xF8,0x3F,0x00,0x00,0x1E,0xF0,0x00,0x00,0x07,0xC0,0x01,0x80,0xC3,0x87,0x01,0xC0,0xF1,0x9F,0x03,0xC0,0x38,0x18,0x03,0xC0,0x0C,0x30,0x03,0x60,0x0E,0x30,0x06,0x60,0x06,0x30,0x06,0x60,0x06,0x18,0x06,0x60,0x06,0x0C,0x06,0x60,0x0C,0x1E,0x06,0x60,0xF8,0x3F,0x06,0xE0,0xFE,0x31,0x06,0xC0,0x0E,0x30,0x06,0xC0,0x01,0x18,0x03,0x80,0x03,0x1C,0x03,0x00,0x07,0x8F,0x01,0x00,0xFE,0x87,0x01,0x00,0xF8,0xC1,0x00,0x00,0x00,0x40, // 64 + 0x00,0x00,0x30,0x00,0x00,0x00,0x3E,0x00,0x00,0x80,0x0F,0x00,0x00,0xF0,0x03,0x00,0x00,0xFE,0x01,0x00,0x80,0x8F,0x01,0x00,0xE0,0x83,0x01,0x00,0x60,0x80,0x01,0x00,0xE0,0x83,0x01,0x00,0x80,0x8F,0x01,0x00,0x00,0xFE,0x01,0x00,0x00,0xF0,0x03,0x00,0x00,0x80,0x0F,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x30, // 65 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0xC0,0x78,0x30,0x00,0xC0,0xFF,0x18,0x00,0x80,0xC7,0x1F,0x00,0x00,0x80,0x07, // 66 + 0x00,0x00,0x00,0x00,0x00,0xFC,0x01,0x00,0x00,0xFF,0x07,0x00,0x80,0x07,0x0F,0x00,0xC0,0x01,0x1C,0x00,0xC0,0x00,0x18,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0xC0,0x00,0x18,0x00,0xC0,0x01,0x1C,0x00,0x80,0x03,0x0F,0x00,0x00,0x02,0x03, // 67 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0xE0,0x00,0x18,0x00,0xC0,0x01,0x1C,0x00,0x80,0x03,0x0E,0x00,0x00,0xFF,0x07,0x00,0x00,0xFC,0x01, // 68 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x00,0x30, // 69 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x60,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x60, // 70 + 0x00,0x00,0x00,0x00,0x00,0xFC,0x01,0x00,0x00,0xFF,0x07,0x00,0x80,0x07,0x0F,0x00,0xC0,0x01,0x1C,0x00,0xC0,0x00,0x18,0x00,0xE0,0x00,0x18,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x60,0x30,0x00,0x60,0x60,0x30,0x00,0xE0,0x60,0x38,0x00,0xC0,0x60,0x18,0x00,0xC0,0x61,0x18,0x00,0x80,0xE3,0x0F,0x00,0x00,0xE2,0x0F, // 71 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F, // 72 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F, // 73 + 0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x38,0x00,0xE0,0xFF,0x1F,0x00,0xE0,0xFF,0x0F, // 74 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x00,0xE0,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0xE7,0x01,0x00,0x80,0x83,0x07,0x00,0xC0,0x01,0x0F,0x00,0xE0,0x00,0x1E,0x00,0x60,0x00,0x38,0x00,0x20,0x00,0x30,0x00,0x00,0x00,0x20, // 75 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30, // 76 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0x01,0x00,0x00,0xC0,0x0F,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0xE0,0x07,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x3F,0x00,0x00,0xE0,0x07,0x00,0x00,0xFE,0x00,0x00,0xC0,0x0F,0x00,0x00,0xE0,0x01,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F, // 77 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0xC0,0x01,0x00,0x00,0x80,0x03,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x3C,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0xE0,0x01,0x00,0x00,0x80,0x03,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x1C,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F, // 78 + 0x00,0x00,0x00,0x00,0x00,0xFC,0x01,0x00,0x00,0xFF,0x07,0x00,0x80,0x07,0x0F,0x00,0xC0,0x01,0x1C,0x00,0xC0,0x00,0x18,0x00,0xE0,0x00,0x38,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0xE0,0x00,0x38,0x00,0xC0,0x00,0x18,0x00,0xC0,0x01,0x1C,0x00,0x80,0x07,0x0F,0x00,0x00,0xFF,0x07,0x00,0x00,0xFC,0x01, // 79 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x60,0x60,0x00,0x00,0x60,0x60,0x00,0x00,0x60,0x60,0x00,0x00,0x60,0x60,0x00,0x00,0x60,0x60,0x00,0x00,0x60,0x60,0x00,0x00,0x60,0x60,0x00,0x00,0x60,0x60,0x00,0x00,0xC0,0x30,0x00,0x00,0xC0,0x3F,0x00,0x00,0x00,0x0F, // 80 + 0x00,0x00,0x00,0x00,0x00,0xFC,0x01,0x00,0x00,0xFF,0x07,0x00,0x80,0x07,0x0F,0x00,0xC0,0x01,0x0C,0x00,0xC0,0x00,0x18,0x00,0xE0,0x00,0x18,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x36,0x00,0x60,0x00,0x36,0x00,0xE0,0x00,0x3C,0x00,0xC0,0x00,0x1C,0x00,0xC0,0x01,0x1C,0x00,0x80,0x07,0x3F,0x00,0x00,0xFF,0x77,0x00,0x00,0xFC,0x61, // 81 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x60,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0x70,0x00,0x00,0x60,0xF0,0x00,0x00,0x60,0xF0,0x03,0x00,0x60,0xB0,0x07,0x00,0xE0,0x18,0x1F,0x00,0xC0,0x1F,0x3C,0x00,0x80,0x0F,0x30,0x00,0x00,0x00,0x20, // 82 + 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x07,0x0F,0x00,0xC0,0x1F,0x1C,0x00,0xC0,0x18,0x18,0x00,0x60,0x38,0x38,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x70,0x30,0x00,0xC0,0x60,0x18,0x00,0xC0,0xE1,0x18,0x00,0x80,0xC3,0x0F,0x00,0x00,0x83,0x07, // 83 + 0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60, // 84 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x03,0x00,0xE0,0xFF,0x0F,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x1C,0x00,0xE0,0xFF,0x0F,0x00,0xE0,0xFF,0x03, // 85 + 0x20,0x00,0x00,0x00,0xE0,0x01,0x00,0x00,0xC0,0x0F,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0xF8,0x01,0x00,0x00,0xC0,0x0F,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x3E,0x00,0x00,0xC0,0x0F,0x00,0x00,0xF8,0x01,0x00,0x00,0x3E,0x00,0x00,0xC0,0x0F,0x00,0x00,0xE0,0x01,0x00,0x00,0x20, // 86 + 0x60,0x00,0x00,0x00,0xE0,0x07,0x00,0x00,0x80,0xFF,0x00,0x00,0x00,0xF8,0x0F,0x00,0x00,0x80,0x3F,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x3F,0x00,0x00,0xE0,0x0F,0x00,0x00,0xFC,0x01,0x00,0x80,0x1F,0x00,0x00,0xE0,0x03,0x00,0x00,0x60,0x00,0x00,0x00,0xE0,0x03,0x00,0x00,0x80,0x1F,0x00,0x00,0x00,0xFC,0x01,0x00,0x00,0xE0,0x0F,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x30,0x00,0x00,0x80,0x3F,0x00,0x00,0xF8,0x0F,0x00,0x80,0xFF,0x00,0x00,0xE0,0x07,0x00,0x00,0x60, // 87 + 0x00,0x00,0x20,0x00,0x20,0x00,0x30,0x00,0x60,0x00,0x3C,0x00,0xE0,0x01,0x1E,0x00,0xC0,0x83,0x07,0x00,0x00,0xCF,0x03,0x00,0x00,0xFE,0x01,0x00,0x00,0x38,0x00,0x00,0x00,0xFE,0x01,0x00,0x00,0xCF,0x03,0x00,0xC0,0x03,0x07,0x00,0xE0,0x01,0x1E,0x00,0x60,0x00,0x3C,0x00,0x20,0x00,0x30,0x00,0x00,0x00,0x20, // 88 + 0x20,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0xC0,0x01,0x00,0x00,0x80,0x03,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x3C,0x00,0x00,0x00,0xF0,0x3F,0x00,0x00,0xF0,0x3F,0x00,0x00,0x3C,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x07,0x00,0x00,0xC0,0x03,0x00,0x00,0xE0,0x01,0x00,0x00,0x60,0x00,0x00,0x00,0x20, // 89 + 0x00,0x00,0x30,0x00,0x60,0x00,0x38,0x00,0x60,0x00,0x3C,0x00,0x60,0x00,0x37,0x00,0x60,0x80,0x33,0x00,0x60,0xC0,0x31,0x00,0x60,0xE0,0x30,0x00,0x60,0x38,0x30,0x00,0x60,0x1C,0x30,0x00,0x60,0x0E,0x30,0x00,0x60,0x07,0x30,0x00,0xE0,0x01,0x30,0x00,0xE0,0x00,0x30,0x00,0x60,0x00,0x30, // 90 + 0x00,0x00,0x00,0x00,0xE0,0xFF,0xFF,0x07,0xE0,0xFF,0xFF,0x07,0x60,0x00,0x00,0x06,0x60,0x00,0x00,0x06, // 91 + 0x60,0x00,0x00,0x00,0xE0,0x03,0x00,0x00,0x80,0x3F,0x00,0x00,0x00,0xFC,0x01,0x00,0x00,0xE0,0x0F,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x30, // 92 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x06,0x60,0x00,0x00,0x06,0xE0,0xFF,0xFF,0x07,0xE0,0xFF,0xFF,0x07, // 93 + 0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x1F,0x00,0x00,0xC0,0x07,0x00,0x00,0xE0,0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0xC0,0x07,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x20, // 94 + 0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06, // 95 + 0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0x80, // 96 + 0x00,0x00,0x00,0x00,0x00,0x18,0x0E,0x00,0x00,0x1C,0x1F,0x00,0x00,0x8C,0x39,0x00,0x00,0x86,0x31,0x00,0x00,0x86,0x31,0x00,0x00,0xC6,0x30,0x00,0x00,0xC6,0x18,0x00,0x00,0xCE,0x0C,0x00,0x00,0xFC,0x1F,0x00,0x00,0xF8,0x3F,0x00,0x00,0x00,0x20, // 97 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x00,0x18,0x0C,0x00,0x00,0x0C,0x18,0x00,0x00,0x06,0x30,0x00,0x00,0x06,0x30,0x00,0x00,0x06,0x30,0x00,0x00,0x0E,0x38,0x00,0x00,0x1C,0x1C,0x00,0x00,0xF8,0x0F,0x00,0x00,0xE0,0x03, // 98 + 0x00,0x00,0x00,0x00,0x00,0xF0,0x07,0x00,0x00,0xF8,0x0F,0x00,0x00,0x1C,0x1C,0x00,0x00,0x0E,0x38,0x00,0x00,0x06,0x30,0x00,0x00,0x06,0x30,0x00,0x00,0x06,0x30,0x00,0x00,0x0E,0x38,0x00,0x00,0x1C,0x1C,0x00,0x00,0x18,0x0C, // 99 + 0x00,0x00,0x00,0x00,0x00,0xE0,0x03,0x00,0x00,0xF8,0x0F,0x00,0x00,0x1C,0x1C,0x00,0x00,0x0E,0x38,0x00,0x00,0x06,0x30,0x00,0x00,0x06,0x30,0x00,0x00,0x06,0x30,0x00,0x00,0x0C,0x18,0x00,0x00,0x18,0x0C,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F, // 100 + 0x00,0x00,0x00,0x00,0x00,0xE0,0x07,0x00,0x00,0xF8,0x0F,0x00,0x00,0xDC,0x1C,0x00,0x00,0xCE,0x38,0x00,0x00,0xC6,0x30,0x00,0x00,0xC6,0x30,0x00,0x00,0xC6,0x30,0x00,0x00,0xCE,0x38,0x00,0x00,0xDC,0x18,0x00,0x00,0xF8,0x0C,0x00,0x00,0xF0,0x04, // 101 + 0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0xC0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x60,0x06,0x00,0x00,0x60,0x06,0x00,0x00,0x60,0x06, // 102 + 0x00,0x00,0x00,0x00,0x00,0xE0,0x83,0x01,0x00,0xF8,0x8F,0x03,0x00,0x1C,0x1C,0x07,0x00,0x0E,0x38,0x06,0x00,0x06,0x30,0x06,0x00,0x06,0x30,0x06,0x00,0x06,0x30,0x06,0x00,0x0C,0x18,0x07,0x00,0x18,0x8C,0x03,0x00,0xFE,0xFF,0x01,0x00,0xFE,0xFF, // 103 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x00,0x18,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0xFC,0x3F,0x00,0x00,0xF8,0x3F, // 104 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0xFE,0x3F,0x00,0x60,0xFE,0x3F, // 105 + 0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x60,0xFE,0xFF,0x07,0x60,0xFE,0xFF,0x03, // 106 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x00,0xC0,0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0xF0,0x01,0x00,0x00,0x98,0x07,0x00,0x00,0x0C,0x0E,0x00,0x00,0x06,0x3C,0x00,0x00,0x02,0x30,0x00,0x00,0x00,0x20, // 107 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F, // 108 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x3F,0x00,0x00,0xFE,0x3F,0x00,0x00,0x0C,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0xFC,0x3F,0x00,0x00,0xF8,0x3F,0x00,0x00,0x0C,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0xFC,0x3F,0x00,0x00,0xF8,0x3F, // 109 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x3F,0x00,0x00,0xFE,0x3F,0x00,0x00,0x18,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0xFC,0x3F,0x00,0x00,0xF8,0x3F, // 110 + 0x00,0x00,0x00,0x00,0x00,0xF0,0x07,0x00,0x00,0xF8,0x0F,0x00,0x00,0x1C,0x1C,0x00,0x00,0x0E,0x38,0x00,0x00,0x06,0x30,0x00,0x00,0x06,0x30,0x00,0x00,0x06,0x30,0x00,0x00,0x0E,0x38,0x00,0x00,0x1C,0x1C,0x00,0x00,0xF8,0x0F,0x00,0x00,0xF0,0x07, // 111 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFF,0x07,0x00,0xFE,0xFF,0x07,0x00,0x18,0x0C,0x00,0x00,0x0C,0x18,0x00,0x00,0x06,0x30,0x00,0x00,0x06,0x30,0x00,0x00,0x06,0x30,0x00,0x00,0x0E,0x38,0x00,0x00,0x1C,0x1C,0x00,0x00,0xF8,0x0F,0x00,0x00,0xE0,0x03, // 112 + 0x00,0x00,0x00,0x00,0x00,0xE0,0x03,0x00,0x00,0xF8,0x0F,0x00,0x00,0x1C,0x1C,0x00,0x00,0x0E,0x38,0x00,0x00,0x06,0x30,0x00,0x00,0x06,0x30,0x00,0x00,0x06,0x30,0x00,0x00,0x0C,0x18,0x00,0x00,0x18,0x0C,0x00,0x00,0xFE,0xFF,0x07,0x00,0xFE,0xFF,0x07, // 113 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x3F,0x00,0x00,0xFE,0x3F,0x00,0x00,0x0C,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06, // 114 + 0x00,0x00,0x00,0x00,0x00,0x38,0x0C,0x00,0x00,0x7C,0x1C,0x00,0x00,0xEE,0x38,0x00,0x00,0xC6,0x30,0x00,0x00,0xC6,0x30,0x00,0x00,0xC6,0x31,0x00,0x00,0xC6,0x31,0x00,0x00,0x8E,0x39,0x00,0x00,0x9C,0x1F,0x00,0x00,0x18,0x0F, // 115 + 0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0xC0,0xFF,0x1F,0x00,0xE0,0xFF,0x3F,0x00,0x00,0x06,0x30,0x00,0x00,0x06,0x30,0x00,0x00,0x06,0x30, // 116 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x0F,0x00,0x00,0xFE,0x1F,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x0C,0x00,0x00,0xFE,0x3F,0x00,0x00,0xFE,0x3F, // 117 + 0x00,0x06,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0xC0,0x07,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x1F,0x00,0x00,0xC0,0x07,0x00,0x00,0xF8,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x06, // 118 + 0x00,0x0E,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0xF0,0x03,0x00,0x00,0x80,0x1F,0x00,0x00,0x00,0x38,0x00,0x00,0x80,0x1F,0x00,0x00,0xE0,0x03,0x00,0x00,0x7C,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0xE0,0x03,0x00,0x00,0x80,0x1F,0x00,0x00,0x00,0x38,0x00,0x00,0x80,0x1F,0x00,0x00,0xF0,0x03,0x00,0x00,0x7E,0x00,0x00,0x00,0x0E, // 119 + 0x00,0x02,0x20,0x00,0x00,0x06,0x30,0x00,0x00,0x1E,0x3C,0x00,0x00,0x38,0x0E,0x00,0x00,0xF0,0x07,0x00,0x00,0xC0,0x01,0x00,0x00,0xE0,0x07,0x00,0x00,0x38,0x0E,0x00,0x00,0x1C,0x3C,0x00,0x00,0x0E,0x30,0x00,0x00,0x02,0x20, // 120 + 0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x7E,0x00,0x06,0x00,0xF0,0x01,0x06,0x00,0x80,0x0F,0x07,0x00,0x00,0xFE,0x03,0x00,0x00,0xFC,0x00,0x00,0xC0,0x1F,0x00,0x00,0xF8,0x03,0x00,0x00,0x3E,0x00,0x00,0x00,0x06, // 121 + 0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x06,0x3C,0x00,0x00,0x06,0x3E,0x00,0x00,0x06,0x37,0x00,0x00,0xC6,0x33,0x00,0x00,0xE6,0x30,0x00,0x00,0x76,0x30,0x00,0x00,0x3E,0x30,0x00,0x00,0x1E,0x30,0x00,0x00,0x06,0x30, // 122 + 0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x00,0x00,0xC0,0x03,0x00,0xC0,0x7F,0xFE,0x03,0xE0,0x3F,0xFC,0x07,0x60,0x00,0x00,0x06,0x60,0x00,0x00,0x06, // 123 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0xFF,0x0F,0xE0,0xFF,0xFF,0x0F, // 124 + 0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x06,0x60,0x00,0x00,0x06,0xE0,0x3F,0xFC,0x07,0xC0,0x7F,0xFF,0x03,0x00,0xC0,0x03,0x00,0x00,0x80,0x01, // 125 + 0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0x60, // 126 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE6,0xFF,0x07,0x00,0xE6,0xFF,0x07, // 161 + 0x00,0x00,0x00,0x00,0x00,0xE0,0x07,0x00,0x00,0xF8,0x0F,0x00,0x00,0x1C,0x9C,0x07,0x00,0x0E,0x78,0x00,0x00,0x06,0x3F,0x00,0x00,0xF6,0x30,0x00,0x00,0x0E,0x30,0x00,0xE0,0x0D,0x1C,0x00,0x00,0x1C,0x0E,0x00,0x00,0x10,0x06, // 162 + 0x00,0x60,0x10,0x00,0x00,0x60,0x38,0x00,0x00,0x7F,0x1C,0x00,0xC0,0xFF,0x1F,0x00,0xE0,0xE0,0x19,0x00,0x60,0x60,0x18,0x00,0x60,0x60,0x18,0x00,0x60,0x60,0x30,0x00,0xE0,0x00,0x30,0x00,0xC0,0x01,0x30,0x00,0x80,0x01,0x38,0x00,0x00,0x00,0x10, // 163 + 0x00,0x00,0x00,0x00,0x00,0x02,0x04,0x00,0x00,0xF7,0x0E,0x00,0x00,0xFE,0x07,0x00,0x00,0x0C,0x03,0x00,0x00,0x06,0x06,0x00,0x00,0x06,0x06,0x00,0x00,0x06,0x06,0x00,0x00,0x06,0x06,0x00,0x00,0x0C,0x03,0x00,0x00,0xFE,0x07,0x00,0x00,0xF7,0x0E,0x00,0x00,0x02,0x04, // 164 + 0xE0,0x60,0x06,0x00,0xC0,0x61,0x06,0x00,0x80,0x67,0x06,0x00,0x00,0x7E,0x06,0x00,0x00,0x7C,0x06,0x00,0x00,0xF0,0x3F,0x00,0x00,0xF0,0x3F,0x00,0x00,0x7C,0x06,0x00,0x00,0x7E,0x06,0x00,0x80,0x67,0x06,0x00,0xC0,0x61,0x06,0x00,0xE0,0x60,0x06,0x00,0x20, // 165 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x7F,0xF8,0x0F,0xE0,0x7F,0xF8,0x0F, // 166 + 0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x80,0xF3,0xC1,0x00,0xC0,0x1F,0xC3,0x03,0xE0,0x0C,0x07,0x03,0x60,0x1C,0x06,0x06,0x60,0x18,0x0C,0x06,0x60,0x30,0x1C,0x06,0xE0,0x70,0x38,0x07,0xC0,0xE1,0xF4,0x03,0x80,0xC1,0xE7,0x01,0x00,0x80,0x03, // 167 + 0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60, // 168 + 0x00,0xF8,0x00,0x00,0x00,0xFE,0x03,0x00,0x00,0x07,0x07,0x00,0x80,0x01,0x0C,0x00,0xC0,0x79,0x1C,0x00,0xC0,0xFE,0x19,0x00,0x60,0x86,0x31,0x00,0x60,0x03,0x33,0x00,0x60,0x03,0x33,0x00,0x60,0x03,0x33,0x00,0x60,0x03,0x33,0x00,0x60,0x87,0x33,0x00,0xC0,0x86,0x19,0x00,0xC0,0x85,0x1C,0x00,0x80,0x01,0x0C,0x00,0x00,0x07,0x07,0x00,0x00,0xFE,0x03,0x00,0x00,0xF8, // 169 + 0x00,0x00,0x00,0x00,0xC0,0x1C,0x00,0x00,0xE0,0x3E,0x00,0x00,0x60,0x32,0x00,0x00,0x60,0x32,0x00,0x00,0xE0,0x3F,0x00,0x00,0xC0,0x3F, // 170 + 0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0xE0,0x03,0x00,0x00,0x78,0x0F,0x00,0x00,0x1C,0x1C,0x00,0x00,0x84,0x10,0x00,0x00,0xE0,0x03,0x00,0x00,0x78,0x0F,0x00,0x00,0x1C,0x1C,0x00,0x00,0x04,0x10, // 171 + 0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0xFC,0x01,0x00,0x00,0xFC,0x01, // 172 + 0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01, // 173 + 0x00,0xF8,0x00,0x00,0x00,0xFE,0x03,0x00,0x00,0x07,0x07,0x00,0x80,0x01,0x0C,0x00,0xC0,0x01,0x1C,0x00,0xC0,0xFE,0x1B,0x00,0x60,0xFE,0x33,0x00,0x60,0x66,0x30,0x00,0x60,0x66,0x30,0x00,0x60,0xE6,0x30,0x00,0x60,0xFE,0x31,0x00,0x60,0x3C,0x33,0x00,0xC0,0x00,0x1A,0x00,0xC0,0x01,0x1C,0x00,0x80,0x01,0x0C,0x00,0x00,0x07,0x07,0x00,0x00,0xFE,0x03,0x00,0x00,0xF8, // 174 + 0x0C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0C, // 175 + 0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x00,0x40,0x04,0x00,0x00,0x20,0x08,0x00,0x00,0x20,0x08,0x00,0x00,0x20,0x08,0x00,0x00,0x40,0x04,0x00,0x00,0x80,0x03, // 176 + 0x00,0x00,0x00,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0xFF,0x3F,0x00,0x00,0xFF,0x3F,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0x30, // 177 + 0x40,0x20,0x00,0x00,0x60,0x30,0x00,0x00,0x20,0x38,0x00,0x00,0x20,0x2C,0x00,0x00,0x20,0x26,0x00,0x00,0xE0,0x23,0x00,0x00,0xC0,0x21, // 178 + 0x40,0x10,0x00,0x00,0x60,0x30,0x00,0x00,0x20,0x20,0x00,0x00,0x20,0x22,0x00,0x00,0x20,0x22,0x00,0x00,0xE0,0x3D,0x00,0x00,0xC0,0x1D, // 179 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x20, // 180 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFF,0x07,0x00,0xFE,0xFF,0x07,0x00,0x00,0x1C,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x1C,0x00,0x00,0xFE,0x3F,0x00,0x00,0xFE,0x3F, // 181 + 0x00,0x0F,0x00,0x00,0xC0,0x3F,0x00,0x00,0xC0,0x3F,0x00,0x00,0xE0,0x7F,0x00,0x00,0xE0,0x7F,0x00,0x00,0xE0,0xFF,0xFF,0x07,0xE0,0xFF,0xFF,0x07,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0xE0,0xFF,0xFF,0x07,0xE0,0xFF,0xFF,0x07,0x60,0x00,0x00,0x00,0x60, // 182 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60, // 183 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0xC0,0x02,0x00,0x00,0x80,0x03,0x00,0x00,0x00,0x01, // 184 + 0x00,0x00,0x00,0x00,0x80,0x01,0x00,0x00,0xC0,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0xE0,0x3F,0x00,0x00,0xE0,0x3F, // 185 + 0x00,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0xC0,0x1F,0x00,0x00,0xE0,0x38,0x00,0x00,0x60,0x30,0x00,0x00,0xE0,0x38,0x00,0x00,0xC0,0x1F,0x00,0x00,0x80,0x0F, // 186 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x00,0x00,0x1C,0x1C,0x00,0x00,0x78,0x0F,0x00,0x00,0xE0,0x03,0x00,0x00,0x84,0x10,0x00,0x00,0x1C,0x1C,0x00,0x00,0x78,0x0F,0x00,0x00,0xE0,0x03,0x00,0x00,0x80, // 187 + 0x00,0x00,0x00,0x00,0x80,0x01,0x00,0x00,0xC0,0x00,0x00,0x00,0xC0,0x00,0x20,0x00,0xE0,0x3F,0x38,0x00,0xE0,0x3F,0x1C,0x00,0x00,0x00,0x0E,0x00,0x00,0x80,0x03,0x00,0x00,0xC0,0x01,0x00,0x00,0xE0,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x07,0x0C,0x00,0xC0,0x01,0x0E,0x00,0xE0,0x80,0x0B,0x00,0x60,0xC0,0x08,0x00,0x00,0xE0,0x3F,0x00,0x00,0xE0,0x3F,0x00,0x00,0x00,0x08, // 188 + 0x00,0x00,0x00,0x00,0x80,0x01,0x00,0x00,0xC0,0x00,0x00,0x00,0xC0,0x00,0x20,0x00,0xE0,0x3F,0x30,0x00,0xE0,0x3F,0x1C,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x07,0x00,0x00,0xC0,0x01,0x00,0x00,0xE0,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x4E,0x20,0x00,0x00,0x67,0x30,0x00,0xC0,0x21,0x38,0x00,0xE0,0x20,0x2C,0x00,0x60,0x20,0x26,0x00,0x00,0xE0,0x27,0x00,0x00,0xC0,0x21, // 189 + 0x40,0x10,0x00,0x00,0x60,0x30,0x00,0x00,0x20,0x20,0x00,0x00,0x20,0x22,0x20,0x00,0x20,0x22,0x30,0x00,0xE0,0x3D,0x38,0x00,0xC0,0x1D,0x0E,0x00,0x00,0x00,0x07,0x00,0x00,0x80,0x03,0x00,0x00,0xE0,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x0E,0x0C,0x00,0x00,0x07,0x0E,0x00,0x80,0x83,0x0B,0x00,0xE0,0xC0,0x08,0x00,0x60,0xE0,0x3F,0x00,0x20,0xE0,0x3F,0x00,0x00,0x00,0x08, // 190 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0xF8,0x03,0x00,0x00,0x1E,0x03,0x00,0x00,0x07,0x07,0x00,0xE6,0x03,0x06,0x00,0xE6,0x01,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x07,0x00,0x00,0x80,0x03,0x00,0x00,0xC0,0x01,0x00,0x00,0xC0, // 191 + 0x00,0x00,0x30,0x00,0x00,0x00,0x3E,0x00,0x00,0x80,0x0F,0x00,0x00,0xF0,0x03,0x00,0x00,0xFE,0x01,0x00,0x82,0x8F,0x01,0x00,0xE6,0x83,0x01,0x00,0x6E,0x80,0x01,0x00,0xE8,0x83,0x01,0x00,0x80,0x8F,0x01,0x00,0x00,0xFE,0x01,0x00,0x00,0xF0,0x03,0x00,0x00,0x80,0x0F,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x30, // 192 + 0x00,0x00,0x30,0x00,0x00,0x00,0x3E,0x00,0x00,0x80,0x0F,0x00,0x00,0xF0,0x03,0x00,0x00,0xFE,0x01,0x00,0x80,0x8F,0x01,0x00,0xE8,0x83,0x01,0x00,0x6E,0x80,0x01,0x00,0xE6,0x83,0x01,0x00,0x82,0x8F,0x01,0x00,0x00,0xFE,0x01,0x00,0x00,0xF0,0x03,0x00,0x00,0x80,0x0F,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x30, // 193 + 0x00,0x00,0x30,0x00,0x00,0x00,0x3E,0x00,0x00,0x80,0x0F,0x00,0x00,0xF0,0x03,0x00,0x00,0xFE,0x01,0x00,0x88,0x8F,0x01,0x00,0xEC,0x83,0x01,0x00,0x66,0x80,0x01,0x00,0xE6,0x83,0x01,0x00,0x8C,0x8F,0x01,0x00,0x08,0xFE,0x01,0x00,0x00,0xF0,0x03,0x00,0x00,0x80,0x0F,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x30, // 194 + 0x00,0x00,0x30,0x00,0x00,0x00,0x3E,0x00,0x00,0x80,0x0F,0x00,0x00,0xF0,0x03,0x00,0x0C,0xFE,0x01,0x00,0x8E,0x8F,0x01,0x00,0xE6,0x83,0x01,0x00,0x66,0x80,0x01,0x00,0xEC,0x83,0x01,0x00,0x8C,0x8F,0x01,0x00,0x0E,0xFE,0x01,0x00,0x06,0xF0,0x03,0x00,0x00,0x80,0x0F,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x30, // 195 + 0x00,0x00,0x30,0x00,0x00,0x00,0x3E,0x00,0x00,0x80,0x0F,0x00,0x00,0xF0,0x03,0x00,0x00,0xFE,0x01,0x00,0x8C,0x8F,0x01,0x00,0xEC,0x83,0x01,0x00,0x60,0x80,0x01,0x00,0xE0,0x83,0x01,0x00,0x8C,0x8F,0x01,0x00,0x0C,0xFE,0x01,0x00,0x00,0xF0,0x03,0x00,0x00,0x80,0x0F,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x30, // 196 + 0x00,0x00,0x30,0x00,0x00,0x00,0x3E,0x00,0x00,0x80,0x0F,0x00,0x00,0xF0,0x03,0x00,0x00,0xFE,0x01,0x00,0x9C,0x8F,0x01,0x00,0xE2,0x83,0x01,0x00,0x62,0x80,0x01,0x00,0xE2,0x83,0x01,0x00,0x9C,0x8F,0x01,0x00,0x00,0xFE,0x01,0x00,0x00,0xF0,0x03,0x00,0x00,0x80,0x0F,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x30, // 197 + 0x00,0x00,0x30,0x00,0x00,0x00,0x3C,0x00,0x00,0x00,0x0F,0x00,0x00,0xC0,0x03,0x00,0x00,0xF0,0x01,0x00,0x00,0xBC,0x01,0x00,0x00,0x8F,0x01,0x00,0xC0,0x83,0x01,0x00,0xE0,0x80,0x01,0x00,0x60,0x80,0x01,0x00,0x60,0x80,0x01,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x00,0x30, // 198 + 0x00,0x00,0x00,0x00,0x00,0xFC,0x01,0x00,0x00,0xFF,0x07,0x00,0x80,0x07,0x0F,0x00,0xC0,0x01,0x1C,0x00,0xC0,0x00,0x18,0x00,0x60,0x00,0x30,0x02,0x60,0x00,0x30,0x02,0x60,0x00,0xF0,0x02,0x60,0x00,0xB0,0x03,0x60,0x00,0x30,0x01,0x60,0x00,0x30,0x00,0xC0,0x00,0x18,0x00,0xC0,0x01,0x1C,0x00,0x80,0x03,0x0F,0x00,0x00,0x02,0x03, // 199 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x62,0x30,0x30,0x00,0x66,0x30,0x30,0x00,0x6E,0x30,0x30,0x00,0x68,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x00,0x30, // 200 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x68,0x30,0x30,0x00,0x6E,0x30,0x30,0x00,0x66,0x30,0x30,0x00,0x62,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x00,0x30, // 201 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x68,0x30,0x30,0x00,0x6C,0x30,0x30,0x00,0x66,0x30,0x30,0x00,0x66,0x30,0x30,0x00,0x6C,0x30,0x30,0x00,0x68,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x00,0x30, // 202 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x6C,0x30,0x30,0x00,0x6C,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x6C,0x30,0x30,0x00,0x6C,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x00,0x30, // 203 + 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0xE6,0xFF,0x3F,0x00,0xEE,0xFF,0x3F,0x00,0x08, // 204 + 0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0xEE,0xFF,0x3F,0x00,0xE6,0xFF,0x3F,0x00,0x02, // 205 + 0x08,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0xE6,0xFF,0x3F,0x00,0xE6,0xFF,0x3F,0x00,0x0C,0x00,0x00,0x00,0x08, // 206 + 0x0C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x0C,0x00,0x00,0x00,0x0C, // 207 + 0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x30,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0xE0,0x00,0x18,0x00,0xC0,0x01,0x1C,0x00,0x80,0x03,0x0E,0x00,0x00,0xFF,0x07,0x00,0x00,0xFC,0x01, // 208 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0xC0,0x01,0x00,0x00,0x8C,0x03,0x00,0x00,0x0E,0x0E,0x00,0x00,0x06,0x3C,0x00,0x00,0x06,0x70,0x00,0x00,0x0C,0xE0,0x01,0x00,0x0C,0x80,0x03,0x00,0x0E,0x00,0x0F,0x00,0x06,0x00,0x1C,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F, // 209 + 0x00,0x00,0x00,0x00,0x00,0xFC,0x01,0x00,0x00,0xFF,0x07,0x00,0x80,0x07,0x0F,0x00,0xC0,0x01,0x1C,0x00,0xC0,0x00,0x18,0x00,0xE0,0x00,0x38,0x00,0x62,0x00,0x30,0x00,0x66,0x00,0x30,0x00,0x6E,0x00,0x30,0x00,0x68,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0xE0,0x00,0x38,0x00,0xC0,0x00,0x18,0x00,0xC0,0x01,0x1C,0x00,0x80,0x07,0x0F,0x00,0x00,0xFF,0x07,0x00,0x00,0xFC,0x01, // 210 + 0x00,0x00,0x00,0x00,0x00,0xFC,0x01,0x00,0x00,0xFF,0x07,0x00,0x80,0x07,0x0F,0x00,0xC0,0x01,0x1C,0x00,0xC0,0x00,0x18,0x00,0xE0,0x00,0x38,0x00,0x60,0x00,0x30,0x00,0x68,0x00,0x30,0x00,0x6E,0x00,0x30,0x00,0x66,0x00,0x30,0x00,0x62,0x00,0x30,0x00,0xE0,0x00,0x38,0x00,0xC0,0x00,0x18,0x00,0xC0,0x01,0x1C,0x00,0x80,0x07,0x0F,0x00,0x00,0xFF,0x07,0x00,0x00,0xFC,0x01, // 211 + 0x00,0x00,0x00,0x00,0x00,0xFC,0x01,0x00,0x00,0xFF,0x07,0x00,0x80,0x07,0x0F,0x00,0xC0,0x01,0x1C,0x00,0xC0,0x00,0x18,0x00,0xE0,0x00,0x38,0x00,0x68,0x00,0x30,0x00,0x6C,0x00,0x30,0x00,0x66,0x00,0x30,0x00,0x66,0x00,0x30,0x00,0x6C,0x00,0x30,0x00,0xE8,0x00,0x38,0x00,0xC0,0x00,0x18,0x00,0xC0,0x01,0x1C,0x00,0x80,0x07,0x0F,0x00,0x00,0xFF,0x07,0x00,0x00,0xFC,0x01, // 212 + 0x00,0x00,0x00,0x00,0x00,0xFC,0x01,0x00,0x00,0xFF,0x07,0x00,0x80,0x07,0x0F,0x00,0xC0,0x01,0x1C,0x00,0xCC,0x00,0x18,0x00,0xEE,0x00,0x38,0x00,0x66,0x00,0x30,0x00,0x66,0x00,0x30,0x00,0x6C,0x00,0x30,0x00,0x6C,0x00,0x30,0x00,0x6E,0x00,0x30,0x00,0xE6,0x00,0x38,0x00,0xC0,0x00,0x18,0x00,0xC0,0x01,0x1C,0x00,0x80,0x07,0x0F,0x00,0x00,0xFF,0x07,0x00,0x00,0xFC,0x01, // 213 + 0x00,0x00,0x00,0x00,0x00,0xFC,0x01,0x00,0x00,0xFF,0x07,0x00,0x80,0x07,0x0F,0x00,0xC0,0x01,0x1C,0x00,0xC0,0x00,0x18,0x00,0xE0,0x00,0x38,0x00,0x6C,0x00,0x30,0x00,0x6C,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x6C,0x00,0x30,0x00,0xEC,0x00,0x38,0x00,0xC0,0x00,0x18,0x00,0xC0,0x01,0x1C,0x00,0x80,0x07,0x0F,0x00,0x00,0xFF,0x07,0x00,0x00,0xFC,0x01, // 214 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x03,0x00,0x00,0x8E,0x03,0x00,0x00,0xDC,0x01,0x00,0x00,0xF8,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0xDC,0x01,0x00,0x00,0x8E,0x03,0x00,0x00,0x06,0x03, // 215 + 0x00,0x00,0x00,0x00,0x00,0xFC,0x21,0x00,0x00,0xFF,0x77,0x00,0x80,0x07,0x3F,0x00,0xC0,0x01,0x1E,0x00,0xC0,0x00,0x1F,0x00,0xE0,0x80,0x3B,0x00,0x60,0xC0,0x31,0x00,0x60,0xE0,0x30,0x00,0x60,0x70,0x30,0x00,0x60,0x38,0x30,0x00,0x60,0x1C,0x30,0x00,0xE0,0x0E,0x38,0x00,0xC0,0x07,0x18,0x00,0xC0,0x03,0x1C,0x00,0xE0,0x07,0x0F,0x00,0x70,0xFF,0x07,0x00,0x20,0xFC,0x01, // 216 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x03,0x00,0xE0,0xFF,0x0F,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x38,0x00,0x02,0x00,0x30,0x00,0x06,0x00,0x30,0x00,0x0E,0x00,0x30,0x00,0x08,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x1C,0x00,0xE0,0xFF,0x0F,0x00,0xE0,0xFF,0x03, // 217 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x03,0x00,0xE0,0xFF,0x0F,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x30,0x00,0x08,0x00,0x30,0x00,0x0E,0x00,0x30,0x00,0x06,0x00,0x30,0x00,0x02,0x00,0x30,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x1C,0x00,0xE0,0xFF,0x0F,0x00,0xE0,0xFF,0x03, // 218 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x03,0x00,0xE0,0xFF,0x0F,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x38,0x00,0x08,0x00,0x30,0x00,0x0C,0x00,0x30,0x00,0x06,0x00,0x30,0x00,0x06,0x00,0x30,0x00,0x0C,0x00,0x30,0x00,0x08,0x00,0x38,0x00,0x00,0x00,0x1C,0x00,0xE0,0xFF,0x0F,0x00,0xE0,0xFF,0x03, // 219 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x03,0x00,0xE0,0xFF,0x0F,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x38,0x00,0x0C,0x00,0x30,0x00,0x0C,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x0C,0x00,0x30,0x00,0x0C,0x00,0x38,0x00,0x00,0x00,0x1C,0x00,0xE0,0xFF,0x0F,0x00,0xE0,0xFF,0x03, // 220 + 0x20,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0xC0,0x01,0x00,0x00,0x80,0x03,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x3C,0x00,0x00,0x08,0xF0,0x3F,0x00,0x0E,0xF0,0x3F,0x00,0x06,0x3C,0x00,0x00,0x02,0x1E,0x00,0x00,0x00,0x07,0x00,0x00,0xC0,0x03,0x00,0x00,0xE0,0x01,0x00,0x00,0x60,0x00,0x00,0x00,0x20, // 221 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x3F,0x00,0xE0,0xFF,0x3F,0x00,0x00,0x03,0x06,0x00,0x00,0x03,0x06,0x00,0x00,0x03,0x06,0x00,0x00,0x03,0x06,0x00,0x00,0x03,0x06,0x00,0x00,0x03,0x06,0x00,0x00,0x03,0x06,0x00,0x00,0x03,0x07,0x00,0x00,0x86,0x03,0x00,0x00,0xFE,0x01,0x00,0x00,0xF8, // 222 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xFF,0x3F,0x00,0xC0,0xFF,0x3F,0x00,0xC0,0x00,0x00,0x00,0x60,0x00,0x08,0x00,0x60,0x00,0x1C,0x00,0x60,0x00,0x38,0x00,0xE0,0x78,0x30,0x00,0xC0,0x7F,0x30,0x00,0x80,0xC7,0x30,0x00,0x00,0x80,0x39,0x00,0x00,0x80,0x1F,0x00,0x00,0x00,0x0F, // 223 + 0x00,0x00,0x00,0x00,0x00,0x18,0x0E,0x00,0x00,0x1C,0x1F,0x00,0x00,0x8C,0x39,0x00,0x20,0x86,0x31,0x00,0x60,0x86,0x31,0x00,0xE0,0xC6,0x30,0x00,0x80,0xC6,0x18,0x00,0x00,0xCE,0x0C,0x00,0x00,0xFC,0x1F,0x00,0x00,0xF8,0x3F,0x00,0x00,0x00,0x20, // 224 + 0x00,0x00,0x00,0x00,0x00,0x18,0x0E,0x00,0x00,0x1C,0x1F,0x00,0x00,0x8C,0x39,0x00,0x00,0x86,0x31,0x00,0x80,0x86,0x31,0x00,0xE0,0xC6,0x30,0x00,0x60,0xC6,0x18,0x00,0x20,0xCE,0x0C,0x00,0x00,0xFC,0x1F,0x00,0x00,0xF8,0x3F,0x00,0x00,0x00,0x20, // 225 + 0x00,0x00,0x00,0x00,0x00,0x18,0x0E,0x00,0x00,0x1C,0x1F,0x00,0x80,0x8C,0x39,0x00,0xC0,0x86,0x31,0x00,0x60,0x86,0x31,0x00,0x60,0xC6,0x30,0x00,0xC0,0xC6,0x18,0x00,0x80,0xCE,0x0C,0x00,0x00,0xFC,0x1F,0x00,0x00,0xF8,0x3F,0x00,0x00,0x00,0x20, // 226 + 0x00,0x00,0x00,0x00,0x00,0x18,0x0E,0x00,0xC0,0x1C,0x1F,0x00,0xE0,0x8C,0x39,0x00,0x60,0x86,0x31,0x00,0x60,0x86,0x31,0x00,0xC0,0xC6,0x30,0x00,0xC0,0xC6,0x18,0x00,0xE0,0xCE,0x0C,0x00,0x60,0xFC,0x1F,0x00,0x00,0xF8,0x3F,0x00,0x00,0x00,0x20, // 227 + 0x00,0x00,0x00,0x00,0x00,0x18,0x0E,0x00,0x00,0x1C,0x1F,0x00,0xC0,0x8C,0x39,0x00,0xC0,0x86,0x31,0x00,0x00,0x86,0x31,0x00,0x00,0xC6,0x30,0x00,0xC0,0xC6,0x18,0x00,0xC0,0xCE,0x0C,0x00,0x00,0xFC,0x1F,0x00,0x00,0xF8,0x3F,0x00,0x00,0x00,0x20, // 228 + 0x00,0x00,0x00,0x00,0x00,0x18,0x0E,0x00,0x00,0x1C,0x1F,0x00,0x00,0x8C,0x39,0x00,0x70,0x86,0x31,0x00,0x88,0x86,0x31,0x00,0x88,0xC6,0x30,0x00,0x88,0xC6,0x18,0x00,0x70,0xCE,0x0C,0x00,0x00,0xFC,0x1F,0x00,0x00,0xF8,0x3F,0x00,0x00,0x00,0x20, // 229 + 0x00,0x00,0x00,0x00,0x00,0x10,0x0F,0x00,0x00,0x9C,0x1F,0x00,0x00,0xCC,0x39,0x00,0x00,0xC6,0x30,0x00,0x00,0xC6,0x30,0x00,0x00,0xC6,0x30,0x00,0x00,0xC6,0x30,0x00,0x00,0x66,0x18,0x00,0x00,0x6E,0x1C,0x00,0x00,0xFC,0x0F,0x00,0x00,0xFC,0x1F,0x00,0x00,0xCC,0x1C,0x00,0x00,0xCE,0x38,0x00,0x00,0xC6,0x30,0x00,0x00,0xC6,0x30,0x00,0x00,0xC6,0x30,0x00,0x00,0xC6,0x30,0x00,0x00,0xCC,0x18,0x00,0x00,0xF8,0x0C,0x00,0x00,0xE0,0x04, // 230 + 0x00,0x00,0x00,0x00,0x00,0xF0,0x07,0x00,0x00,0xF8,0x0F,0x00,0x00,0x1C,0x1C,0x00,0x00,0x0E,0x38,0x02,0x00,0x06,0x30,0x02,0x00,0x06,0xF0,0x02,0x00,0x06,0xB0,0x03,0x00,0x0E,0x38,0x01,0x00,0x1C,0x1C,0x00,0x00,0x18,0x0C, // 231 + 0x00,0x00,0x00,0x00,0x00,0xE0,0x07,0x00,0x00,0xF8,0x0F,0x00,0x00,0xDC,0x1C,0x00,0x20,0xCE,0x38,0x00,0x60,0xC6,0x30,0x00,0xE0,0xC6,0x30,0x00,0x80,0xC6,0x30,0x00,0x00,0xCE,0x38,0x00,0x00,0xDC,0x18,0x00,0x00,0xF8,0x0C,0x00,0x00,0xF0,0x04, // 232 + 0x00,0x00,0x00,0x00,0x00,0xE0,0x07,0x00,0x00,0xF8,0x0F,0x00,0x00,0xDC,0x1C,0x00,0x00,0xCE,0x38,0x00,0x80,0xC6,0x30,0x00,0xE0,0xC6,0x30,0x00,0x60,0xC6,0x30,0x00,0x20,0xCE,0x38,0x00,0x00,0xDC,0x18,0x00,0x00,0xF8,0x0C,0x00,0x00,0xF0,0x04, // 233 + 0x00,0x00,0x00,0x00,0x00,0xE0,0x07,0x00,0x00,0xF8,0x0F,0x00,0x00,0xDC,0x1C,0x00,0x80,0xCE,0x38,0x00,0xC0,0xC6,0x30,0x00,0x60,0xC6,0x30,0x00,0x60,0xC6,0x30,0x00,0xC0,0xCE,0x38,0x00,0x80,0xDC,0x18,0x00,0x00,0xF8,0x0C,0x00,0x00,0xF0,0x04, // 234 + 0x00,0x00,0x00,0x00,0x00,0xE0,0x07,0x00,0x00,0xF8,0x0F,0x00,0x00,0xDC,0x1C,0x00,0xC0,0xCE,0x38,0x00,0xC0,0xC6,0x30,0x00,0x00,0xC6,0x30,0x00,0x00,0xC6,0x30,0x00,0xC0,0xCE,0x38,0x00,0xC0,0xDC,0x18,0x00,0x00,0xF8,0x0C,0x00,0x00,0xF0,0x04, // 235 + 0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x60,0xFE,0x3F,0x00,0xE0,0xFE,0x3F,0x00,0x80, // 236 + 0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0xE0,0xFE,0x3F,0x00,0x60,0xFE,0x3F,0x00,0x20, // 237 + 0x80,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x60,0xFE,0x3F,0x00,0x60,0xFE,0x3F,0x00,0xC0,0x00,0x00,0x00,0x80, // 238 + 0xC0,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0xFE,0x3F,0x00,0x00,0xFE,0x3F,0x00,0xC0,0x00,0x00,0x00,0xC0, // 239 + 0x00,0x00,0x00,0x00,0x00,0xF0,0x07,0x00,0x00,0xF8,0x0F,0x00,0x00,0x1D,0x1C,0x00,0xA0,0x0F,0x38,0x00,0xA0,0x06,0x30,0x00,0xE0,0x06,0x30,0x00,0xC0,0x06,0x30,0x00,0xC0,0x0F,0x38,0x00,0x20,0x1F,0x1C,0x00,0x00,0xFC,0x0F,0x00,0x00,0xE0,0x07, // 240 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x3F,0x00,0xC0,0xFE,0x3F,0x00,0xE0,0x18,0x00,0x00,0x60,0x0C,0x00,0x00,0x60,0x06,0x00,0x00,0xC0,0x06,0x00,0x00,0xC0,0x06,0x00,0x00,0xE0,0x0E,0x00,0x00,0x60,0xFC,0x3F,0x00,0x00,0xF8,0x3F, // 241 + 0x00,0x00,0x00,0x00,0x00,0xF0,0x07,0x00,0x00,0xF8,0x0F,0x00,0x00,0x1C,0x1C,0x00,0x20,0x0E,0x38,0x00,0x60,0x06,0x30,0x00,0xE0,0x06,0x30,0x00,0x80,0x06,0x30,0x00,0x00,0x0E,0x38,0x00,0x00,0x1C,0x1C,0x00,0x00,0xF8,0x0F,0x00,0x00,0xF0,0x07, // 242 + 0x00,0x00,0x00,0x00,0x00,0xF0,0x07,0x00,0x00,0xF8,0x0F,0x00,0x00,0x1C,0x1C,0x00,0x00,0x0E,0x38,0x00,0x80,0x06,0x30,0x00,0xE0,0x06,0x30,0x00,0x60,0x06,0x30,0x00,0x20,0x0E,0x38,0x00,0x00,0x1C,0x1C,0x00,0x00,0xF8,0x0F,0x00,0x00,0xF0,0x07, // 243 + 0x00,0x00,0x00,0x00,0x00,0xF0,0x07,0x00,0x00,0xF8,0x0F,0x00,0x00,0x1C,0x1C,0x00,0x80,0x0E,0x38,0x00,0xC0,0x06,0x30,0x00,0x60,0x06,0x30,0x00,0x60,0x06,0x30,0x00,0xC0,0x0E,0x38,0x00,0x80,0x1C,0x1C,0x00,0x00,0xF8,0x0F,0x00,0x00,0xF0,0x07, // 244 + 0x00,0x00,0x00,0x00,0x00,0xF0,0x07,0x00,0x00,0xF8,0x0F,0x00,0xC0,0x1C,0x1C,0x00,0xE0,0x0E,0x38,0x00,0x60,0x06,0x30,0x00,0x60,0x06,0x30,0x00,0xC0,0x06,0x30,0x00,0xC0,0x0E,0x38,0x00,0xE0,0x1C,0x1C,0x00,0x60,0xF8,0x0F,0x00,0x00,0xF0,0x07, // 245 + 0x00,0x00,0x00,0x00,0x00,0xF0,0x07,0x00,0x00,0xF8,0x0F,0x00,0x00,0x1C,0x1C,0x00,0xC0,0x0E,0x38,0x00,0xC0,0x06,0x30,0x00,0x00,0x06,0x30,0x00,0x00,0x06,0x30,0x00,0xC0,0x0E,0x38,0x00,0xC0,0x1C,0x1C,0x00,0x00,0xF8,0x0F,0x00,0x00,0xF0,0x07, // 246 + 0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0xB6,0x01,0x00,0x00,0xB6,0x01,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30, // 247 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x67,0x00,0x00,0xF8,0x7F,0x00,0x00,0x1C,0x1C,0x00,0x00,0x0E,0x3F,0x00,0x00,0x86,0x33,0x00,0x00,0xE6,0x31,0x00,0x00,0x76,0x30,0x00,0x00,0x3E,0x38,0x00,0x00,0x1C,0x1C,0x00,0x00,0xFF,0x0F,0x00,0x00,0xF3,0x07, // 248 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x0F,0x00,0x00,0xFE,0x1F,0x00,0x20,0x00,0x38,0x00,0x60,0x00,0x30,0x00,0xE0,0x00,0x30,0x00,0x80,0x00,0x30,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x0C,0x00,0x00,0xFE,0x3F,0x00,0x00,0xFE,0x3F, // 249 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x0F,0x00,0x00,0xFE,0x1F,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x30,0x00,0x80,0x00,0x30,0x00,0xE0,0x00,0x30,0x00,0x60,0x00,0x18,0x00,0x20,0x00,0x0C,0x00,0x00,0xFE,0x3F,0x00,0x00,0xFE,0x3F, // 250 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x0F,0x00,0x00,0xFE,0x1F,0x00,0x80,0x00,0x38,0x00,0xC0,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0xC0,0x00,0x18,0x00,0x80,0x00,0x0C,0x00,0x00,0xFE,0x3F,0x00,0x00,0xFE,0x3F, // 251 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x0F,0x00,0x00,0xFE,0x1F,0x00,0xC0,0x00,0x38,0x00,0xC0,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0xC0,0x00,0x18,0x00,0xC0,0x00,0x0C,0x00,0x00,0xFE,0x3F,0x00,0x00,0xFE,0x3F, // 252 + 0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x7E,0x00,0x06,0x00,0xF0,0x01,0x06,0x00,0x80,0x0F,0x07,0x80,0x00,0xFE,0x03,0xE0,0x00,0xFC,0x00,0x60,0xC0,0x1F,0x00,0x20,0xF8,0x03,0x00,0x00,0x3E,0x00,0x00,0x00,0x06, // 253 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0xFF,0x07,0xE0,0xFF,0xFF,0x07,0x00,0x1C,0x18,0x00,0x00,0x06,0x30,0x00,0x00,0x06,0x30,0x00,0x00,0x06,0x30,0x00,0x00,0x0E,0x38,0x00,0x00,0x1C,0x1C,0x00,0x00,0xF8,0x0F,0x00,0x00,0xF0,0x03, // 254 + 0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x7E,0x00,0x06,0xC0,0xF0,0x01,0x06,0xC0,0x80,0x0F,0x07,0x00,0x00,0xFE,0x03,0x00,0x00,0xFC,0x00,0xC0,0xC0,0x1F,0x00,0xC0,0xF8,0x03,0x00,0x00,0x3E,0x00,0x00,0x00,0x06 // 255 +}; +#endif diff --git a/lib/Display/OLEDDisplayUi.cpp b/lib/Display/OLEDDisplayUi.cpp new file mode 100644 index 0000000..778a2e7 --- /dev/null +++ b/lib/Display/OLEDDisplayUi.cpp @@ -0,0 +1,471 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn + * Copyright (c) 2018 by Fabrice Weinberg + * Copyright (c) 2019 by Helmut Tschemernjak - www.radioshuttle.de + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ThingPulse invests considerable time and money to develop these open source libraries. + * Please support us by buying our products (and not the clones) from + * https://thingpulse.com + * + */ + +#include "OLEDDisplayUi.h" + +void LoadingDrawDefault(OLEDDisplay *display, LoadingStage* stage, uint8_t progress) { + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->setFont(ArialMT_Plain_10); + display->drawString(64, 18, stage->process); + display->drawProgressBar(4, 32, 120, 8, progress); +}; + + +OLEDDisplayUi::OLEDDisplayUi(OLEDDisplay *display) { + this->display = display; + + indicatorPosition = BOTTOM; + indicatorDirection = LEFT_RIGHT; + activeSymbol = ANIMATION_activeSymbol; + inactiveSymbol = ANIMATION_inactiveSymbol; + frameAnimationDirection = SLIDE_RIGHT; + lastTransitionDirection = 1; + frameCount = 0; + nextFrameNumber = -1; + overlayCount = 0; + indicatorDrawState = 1; + loadingDrawFunction = LoadingDrawDefault; + updateInterval = 33; + state.lastUpdate = 0; + state.ticksSinceLastStateSwitch = 0; + state.frameState = FIXED; + state.currentFrame = 0; + state.frameTransitionDirection = 1; + state.isIndicatorDrawen = true; + state.manuelControll = false; + state.userData = NULL; + shouldDrawIndicators = true; + autoTransition = true; + setTimePerFrame(5000); + setTimePerTransition(500); +} + +void OLEDDisplayUi::init() { + this->display->init(); +} + +void OLEDDisplayUi::setTargetFPS(uint8_t fps){ + this->updateInterval = ((float) 1.0 / (float) fps) * 1000; + + this->ticksPerFrame = timePerFrame / updateInterval; + this->ticksPerTransition = timePerTransition / updateInterval; +} + +// -/------ Automatic controll ------\- + +void OLEDDisplayUi::enableAutoTransition(){ + this->autoTransition = true; +} +void OLEDDisplayUi::disableAutoTransition(){ + this->autoTransition = false; +} +void OLEDDisplayUi::setAutoTransitionForwards(){ + this->state.frameTransitionDirection = 1; + this->lastTransitionDirection = 1; +} +void OLEDDisplayUi::setAutoTransitionBackwards(){ + this->state.frameTransitionDirection = -1; + this->lastTransitionDirection = -1; +} +void OLEDDisplayUi::setTimePerFrame(uint16_t time){ + this->timePerFrame = time; + this->ticksPerFrame = timePerFrame / updateInterval; +} +void OLEDDisplayUi::setTimePerTransition(uint16_t time){ + this->timePerTransition = time; + this->ticksPerTransition = timePerTransition / updateInterval; +} + +// -/------ Customize indicator position and style -------\- +void OLEDDisplayUi::enableIndicator(){ + this->state.isIndicatorDrawen = true; +} + +void OLEDDisplayUi::disableIndicator(){ + this->state.isIndicatorDrawen = false; +} + +void OLEDDisplayUi::enableAllIndicators(){ + this->shouldDrawIndicators = true; +} + +void OLEDDisplayUi::disableAllIndicators(){ + this->shouldDrawIndicators = false; +} + +void OLEDDisplayUi::setIndicatorPosition(IndicatorPosition pos) { + this->indicatorPosition = pos; +} +void OLEDDisplayUi::setIndicatorDirection(IndicatorDirection dir) { + this->indicatorDirection = dir; +} +void OLEDDisplayUi::setActiveSymbol(const uint8_t* symbol) { + this->activeSymbol = symbol; +} +void OLEDDisplayUi::setInactiveSymbol(const uint8_t* symbol) { + this->inactiveSymbol = symbol; +} + + +// -/----- Frame settings -----\- +void OLEDDisplayUi::setFrameAnimation(AnimationDirection dir) { + this->frameAnimationDirection = dir; +} +void OLEDDisplayUi::setFrames(FrameCallback* frameFunctions, uint8_t frameCount) { + this->frameFunctions = frameFunctions; + this->frameCount = frameCount; + this->resetState(); +} + +// -/----- Overlays ------\- +void OLEDDisplayUi::setOverlays(OverlayCallback* overlayFunctions, uint8_t overlayCount){ + this->overlayFunctions = overlayFunctions; + this->overlayCount = overlayCount; +} + +// -/----- Loading Process -----\- + +void OLEDDisplayUi::setLoadingDrawFunction(LoadingDrawFunction loadingDrawFunction) { + this->loadingDrawFunction = loadingDrawFunction; +} + +void OLEDDisplayUi::runLoadingProcess(LoadingStage* stages, uint8_t stagesCount) { + uint8_t progress = 0; + uint8_t increment = 100 / stagesCount; + + for (uint8_t i = 0; i < stagesCount; i++) { + display->clear(); + this->loadingDrawFunction(this->display, &stages[i], progress); + display->display(); + + stages[i].callback(); + + progress += increment; + yield(); + } + + display->clear(); + this->loadingDrawFunction(this->display, &stages[stagesCount-1], progress); + display->display(); + + delay(150); +} + +// -/----- Manuel control -----\- +void OLEDDisplayUi::nextFrame() { + if (this->state.frameState != IN_TRANSITION) { + this->state.manuelControll = true; + this->state.frameState = IN_TRANSITION; + this->state.ticksSinceLastStateSwitch = 0; + this->lastTransitionDirection = this->state.frameTransitionDirection; + this->state.frameTransitionDirection = 1; + } +} +void OLEDDisplayUi::previousFrame() { + if (this->state.frameState != IN_TRANSITION) { + this->state.manuelControll = true; + this->state.frameState = IN_TRANSITION; + this->state.ticksSinceLastStateSwitch = 0; + this->lastTransitionDirection = this->state.frameTransitionDirection; + this->state.frameTransitionDirection = -1; + } +} + +void OLEDDisplayUi::switchToFrame(uint8_t frame) { + if (frame >= this->frameCount) return; + this->state.ticksSinceLastStateSwitch = 0; + if (frame == this->state.currentFrame) return; + this->state.frameState = FIXED; + this->state.currentFrame = frame; + this->state.isIndicatorDrawen = true; +} + +void OLEDDisplayUi::transitionToFrame(uint8_t frame) { + if (frame >= this->frameCount) return; + this->state.ticksSinceLastStateSwitch = 0; + if (frame == this->state.currentFrame) return; + this->nextFrameNumber = frame; + this->lastTransitionDirection = this->state.frameTransitionDirection; + this->state.manuelControll = true; + this->state.frameState = IN_TRANSITION; + this->state.frameTransitionDirection = frame < this->state.currentFrame ? -1 : 1; +} + + +// -/----- State information -----\- +OLEDDisplayUiState* OLEDDisplayUi::getUiState(){ + return &this->state; +} + +int16_t OLEDDisplayUi::update(){ +#ifdef ARDUINO + unsigned long frameStart = millis(); +#elif __MBED__ + Timer t; + t.start(); + unsigned long frameStart = t.read_ms(); +#else +#error "Unkown operating system" +#endif + int32_t timeBudget = this->updateInterval - (frameStart - this->state.lastUpdate); + if ( timeBudget <= 0) { + // Implement frame skipping to ensure time budget is keept + if (this->autoTransition && this->state.lastUpdate != 0) this->state.ticksSinceLastStateSwitch += ceil((double)-timeBudget / (double)this->updateInterval); + + this->state.lastUpdate = frameStart; + this->tick(); + } +#ifdef ARDUINO + return this->updateInterval - (millis() - frameStart); +#elif __MBED__ + return this->updateInterval - (t.read_ms() - frameStart); +#else +#error "Unkown operating system" +#endif +} + + +void OLEDDisplayUi::tick() { + this->state.ticksSinceLastStateSwitch++; + + switch (this->state.frameState) { + case IN_TRANSITION: + if (this->state.ticksSinceLastStateSwitch >= this->ticksPerTransition){ + this->state.frameState = FIXED; + this->state.currentFrame = getNextFrameNumber(); + this->state.ticksSinceLastStateSwitch = 0; + this->nextFrameNumber = -1; + } + break; + case FIXED: + // Revert manuelControll + if (this->state.manuelControll) { + this->state.frameTransitionDirection = this->lastTransitionDirection; + this->state.manuelControll = false; + } + if (this->state.ticksSinceLastStateSwitch >= this->ticksPerFrame){ + if (this->autoTransition){ + this->state.frameState = IN_TRANSITION; + } + this->state.ticksSinceLastStateSwitch = 0; + } + break; + } + + this->display->clear(); + this->drawFrame(); + if (shouldDrawIndicators) { + this->drawIndicator(); + } + this->drawOverlays(); + this->display->display(); +} + +void OLEDDisplayUi::resetState() { + this->state.lastUpdate = 0; + this->state.ticksSinceLastStateSwitch = 0; + this->state.frameState = FIXED; + this->state.currentFrame = 0; + this->state.isIndicatorDrawen = true; +} + +void OLEDDisplayUi::drawFrame(){ + switch (this->state.frameState){ + case IN_TRANSITION: { + float progress = 0.f; + if (this->ticksPerTransition > 0u) { + progress = (float) this->state.ticksSinceLastStateSwitch / (float) this->ticksPerTransition; + } + int16_t x = 0, y = 0, x1 = 0, y1 = 0; + switch(this->frameAnimationDirection){ + case SLIDE_LEFT: + x = -this->display->width() * progress; + y = 0; + x1 = x + this->display->width(); + y1 = 0; + break; + case SLIDE_RIGHT: + x = this->display->width() * progress; + y = 0; + x1 = x - this->display->width(); + y1 = 0; + break; + case SLIDE_UP: + x = 0; + y = -this->display->height() * progress; + x1 = 0; + y1 = y + this->display->height(); + break; + case SLIDE_DOWN: + default: + x = 0; + y = this->display->height() * progress; + x1 = 0; + y1 = y - this->display->height(); + break; + } + + // Invert animation if direction is reversed. + int8_t dir = this->state.frameTransitionDirection >= 0 ? 1 : -1; + x *= dir; y *= dir; x1 *= dir; y1 *= dir; + + bool drawenCurrentFrame; + + + // Prope each frameFunction for the indicator Drawen state + this->enableIndicator(); + (this->frameFunctions[this->state.currentFrame])(this->display, &this->state, x, y); + drawenCurrentFrame = this->state.isIndicatorDrawen; + + this->enableIndicator(); + (this->frameFunctions[this->getNextFrameNumber()])(this->display, &this->state, x1, y1); + + // Build up the indicatorDrawState + if (drawenCurrentFrame && !this->state.isIndicatorDrawen) { + // Drawen now but not next + this->indicatorDrawState = 2; + } else if (!drawenCurrentFrame && this->state.isIndicatorDrawen) { + // Not drawen now but next + this->indicatorDrawState = 1; + } else if (!drawenCurrentFrame && !this->state.isIndicatorDrawen) { + // Not drawen in both frames + this->indicatorDrawState = 3; + } + + // If the indicator isn't draw in the current frame + // reflect it in state.isIndicatorDrawen + if (!drawenCurrentFrame) this->state.isIndicatorDrawen = false; + + break; + } + case FIXED: + // Always assume that the indicator is drawn! + // And set indicatorDrawState to "not known yet" + this->indicatorDrawState = 0; + this->enableIndicator(); + (this->frameFunctions[this->state.currentFrame])(this->display, &this->state, 0, 0); + break; + } +} + +void OLEDDisplayUi::drawIndicator() { + + // Only draw if the indicator is invisible + // for both frames or + // the indiactor is shown and we are IN_TRANSITION + if (this->indicatorDrawState == 3 || (!this->state.isIndicatorDrawen && this->state.frameState != IN_TRANSITION)) { + return; + } + + uint8_t posOfHighlightFrame = 0; + float indicatorFadeProgress = 0; + + // if the indicator needs to be slided in we want to + // highlight the next frame in the transition + uint8_t frameToHighlight = this->indicatorDrawState == 1 ? this->getNextFrameNumber() : this->state.currentFrame; + + // Calculate the frame that needs to be highlighted + // based on the Direction the indiactor is drawn + switch (this->indicatorDirection){ + case LEFT_RIGHT: + posOfHighlightFrame = frameToHighlight; + break; + case RIGHT_LEFT: + default: + posOfHighlightFrame = this->frameCount - frameToHighlight; + break; + } + + switch (this->indicatorDrawState) { + case 1: // Indicator was not drawn in this frame but will be in next + // Slide IN + indicatorFadeProgress = 1 - ((float) this->state.ticksSinceLastStateSwitch / (float) this->ticksPerTransition); + break; + case 2: // Indicator was drawn in this frame but not in next + // Slide OUT + indicatorFadeProgress = ((float) this->state.ticksSinceLastStateSwitch / (float) this->ticksPerTransition); + break; + } + + //Space between indicators - reduce for small screen sizes + uint16_t indicatorSpacing = 12; + if (this->display->getHeight() < 64 && (this->indicatorPosition == RIGHT || this->indicatorPosition == LEFT)) { + indicatorSpacing = 6; + } + + uint16_t frameStartPos = (indicatorSpacing * frameCount / 2); + const uint8_t *image; + + uint16_t x = 0,y = 0; + + + for (uint8_t i = 0; i < this->frameCount; i++) { + + switch (this->indicatorPosition){ + case TOP: + y = 0 - (8 * indicatorFadeProgress); + x = (this->display->width() / 2) - frameStartPos + 12 * i; + break; + case BOTTOM: + y = (this->display->height() - 8) + (8 * indicatorFadeProgress); + x = (this->display->width() / 2) - frameStartPos + 12 * i; + break; + case RIGHT: + x = (this->display->width() - 8) + (8 * indicatorFadeProgress); + y = (this->display->height() / 2) - frameStartPos + 2 + 12 * i; + break; + case LEFT: + default: + x = 0 - (8 * indicatorFadeProgress); + y = (this->display->height() / 2) - frameStartPos + 2 + indicatorSpacing * i; + break; + } + + if (posOfHighlightFrame == i) { + image = this->activeSymbol; + } else { + image = this->inactiveSymbol; + } + + this->display->drawFastImage(x, y, 8, 8, image); + } +} + +void OLEDDisplayUi::drawOverlays() { + for (uint8_t i=0;ioverlayCount;i++){ + (this->overlayFunctions[i])(this->display, &this->state); + } +} + +uint8_t OLEDDisplayUi::getNextFrameNumber(){ + if (this->nextFrameNumber != -1) return this->nextFrameNumber; + return (this->state.currentFrame + this->frameCount + this->state.frameTransitionDirection) % this->frameCount; +} diff --git a/lib/Display/OLEDDisplayUi.h b/lib/Display/OLEDDisplayUi.h new file mode 100644 index 0000000..abba761 --- /dev/null +++ b/lib/Display/OLEDDisplayUi.h @@ -0,0 +1,308 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn + * Copyright (c) 2018 by Fabrice Weinberg + * Copyright (c) 2019 by Helmut Tschemernjak - www.radioshuttle.de + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ThingPulse invests considerable time and money to develop these open source libraries. + * Please support us by buying our products (and not the clones) from + * https://thingpulse.com + * + */ + +#ifndef OLEDDISPLAYUI_h +#define OLEDDISPLAYUI_h + +#include +#include "OLEDDisplay.h" + +//#define DEBUG_OLEDDISPLAYUI(...) Serial.printf( __VA_ARGS__ ) + +#ifndef DEBUG_OLEDDISPLAYUI +#define DEBUG_OLEDDISPLAYUI(...) +#endif + +enum AnimationDirection { + SLIDE_UP, + SLIDE_DOWN, + SLIDE_LEFT, + SLIDE_RIGHT +}; + +enum IndicatorPosition { + TOP, + RIGHT, + BOTTOM, + LEFT +}; + +enum IndicatorDirection { + LEFT_RIGHT, + RIGHT_LEFT +}; + +enum FrameState { + IN_TRANSITION, + FIXED +}; + + +const uint8_t ANIMATION_activeSymbol[] PROGMEM = { + 0x00, 0x18, 0x3c, 0x7e, 0x7e, 0x3c, 0x18, 0x00 +}; + +const uint8_t ANIMATION_inactiveSymbol[] PROGMEM = { + 0x00, 0x0, 0x0, 0x18, 0x18, 0x0, 0x0, 0x00 +}; + + +// Structure of the UiState +struct OLEDDisplayUiState { + uint64_t lastUpdate; + uint16_t ticksSinceLastStateSwitch; + + FrameState frameState; + uint8_t currentFrame; + + bool isIndicatorDrawen; + + // Normal = 1, Inverse = -1; + int8_t frameTransitionDirection; + + bool manuelControll; + + // Custom data that can be used by the user + void* userData; +}; + +struct LoadingStage { + const char* process; + void (*callback)(); +}; + +typedef void (*FrameCallback)(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y); +typedef void (*OverlayCallback)(OLEDDisplay *display, OLEDDisplayUiState* state); +typedef void (*LoadingDrawFunction)(OLEDDisplay *display, LoadingStage* stage, uint8_t progress); + +class OLEDDisplayUi { + private: + OLEDDisplay *display; + + // Symbols for the Indicator + IndicatorPosition indicatorPosition; + IndicatorDirection indicatorDirection; + + const uint8_t* activeSymbol; + const uint8_t* inactiveSymbol; + + bool shouldDrawIndicators; + + // Values for the Frames + AnimationDirection frameAnimationDirection; + + int8_t lastTransitionDirection; + + uint16_t ticksPerFrame; // ~ 5000ms at 30 FPS + uint16_t ticksPerTransition; // ~ 500ms at 30 FPS + + bool autoTransition; + + FrameCallback* frameFunctions; + uint8_t frameCount; + + // Internally used to transition to a specific frame + int8_t nextFrameNumber; + + // Values for Overlays + OverlayCallback* overlayFunctions; + uint8_t overlayCount; + + // Will the Indicator be drawen + // 3 Not drawn in both frames + // 2 Drawn this frame but not next + // 1 Not drown this frame but next + // 0 Not known yet + uint8_t indicatorDrawState; + + // Loading screen + LoadingDrawFunction loadingDrawFunction; + + // UI State + OLEDDisplayUiState state; + + // Bookeeping for update + uint16_t updateInterval = 33; + + uint16_t timePerFrame; + uint16_t timePerTransition; + + uint8_t getNextFrameNumber(); + void drawIndicator(); + void drawFrame(); + void drawOverlays(); + void tick(); + void resetState(); + + public: + + OLEDDisplayUi(OLEDDisplay *display); + + /** + * Initialise the display + */ + void init(); + + /** + * Configure the internal used target FPS + */ + void setTargetFPS(uint8_t fps); + + // Automatic Controll + /** + * Enable automatic transition to next frame after the some time can be configured with `setTimePerFrame` and `setTimePerTransition`. + */ + void enableAutoTransition(); + + /** + * Disable automatic transition to next frame. + */ + void disableAutoTransition(); + + /** + * Set the direction if the automatic transitioning + */ + void setAutoTransitionForwards(); + void setAutoTransitionBackwards(); + + /** + * Set the approx. time a frame is displayed + */ + void setTimePerFrame(uint16_t time); + + /** + * Set the approx. time a transition will take + */ + void setTimePerTransition(uint16_t time); + + // Customize indicator position and style + + /** + * Draw the indicator. + * This is the defaut state for all frames if + * the indicator was hidden on the previous frame + * it will be slided in. + */ + void enableIndicator(); + + /** + * Don't draw the indicator. + * This will slide out the indicator + * when transitioning to the next frame. + */ + void disableIndicator(); + + /** + * Enable drawing of indicators + */ + void enableAllIndicators(); + + /** + * Disable draw of indicators. + */ + void disableAllIndicators(); + + /** + * Set the position of the indicator bar. + */ + void setIndicatorPosition(IndicatorPosition pos); + + /** + * Set the direction of the indicator bar. Defining the order of frames ASCENDING / DESCENDING + */ + void setIndicatorDirection(IndicatorDirection dir); + + /** + * Set the symbol to indicate an active frame in the indicator bar. + */ + void setActiveSymbol(const uint8_t* symbol); + + /** + * Set the symbol to indicate an inactive frame in the indicator bar. + */ + void setInactiveSymbol(const uint8_t* symbol); + + + // Frame settings + + /** + * Configure what animation is used to transition from one frame to another + */ + void setFrameAnimation(AnimationDirection dir); + + /** + * Add frame drawing functions + */ + void setFrames(FrameCallback* frameFunctions, uint8_t frameCount); + + // Overlay + + /** + * Add overlays drawing functions that are draw independent of the Frames + */ + void setOverlays(OverlayCallback* overlayFunctions, uint8_t overlayCount); + + + // Loading animation + /** + * Set the function that will draw each step + * in the loading animation + */ + void setLoadingDrawFunction(LoadingDrawFunction loadingFunction); + + + /** + * Run the loading process + */ + void runLoadingProcess(LoadingStage* stages, uint8_t stagesCount); + + + // Manual Control + void nextFrame(); + void previousFrame(); + + /** + * Switch without transition to frame `frame`. + */ + void switchToFrame(uint8_t frame); + + /** + * Transition to frame `frame`, when the `frame` number is bigger than the current + * frame the forward animation will be used, otherwise the backwards animation is used. + */ + void transitionToFrame(uint8_t frame); + + // State Info + OLEDDisplayUiState* getUiState(); + + int16_t update(); +}; +#endif diff --git a/lib/Display/SSD1306.h b/lib/Display/SSD1306.h new file mode 100644 index 0000000..4d0d4e1 --- /dev/null +++ b/lib/Display/SSD1306.h @@ -0,0 +1,195 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn + * Copyright (c) 2018 by Fabrice Weinberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ThingPulse invests considerable time and money to develop these open source libraries. + * Please support us by buying our products (and not the clones) from + * https://thingpulse.com + * + */ + +#ifndef SSD1306_h +#define SSD1306_h + +#include "OLEDDisplay.h" +#include +#include + +//-------------------------------------- + +class SSD1306Wire : public OLEDDisplay { + private: + uint8_t _address; + int _sda; + int _scl; + bool _doI2cAutoInit = false; + TwoWire* _wire = NULL; + int _frequency; + + public: + + /** + * Create and initialize the Display using Wire library + * + * Beware for retro-compatibility default values are provided for all parameters see below. + * Please note that if you don't wan't SD1306Wire to initialize and change frequency speed ot need to + * ensure -1 value are specified for all 3 parameters. This can be usefull to control TwoWire with multiple + * device on the same bus. + * + * @param _address I2C Display address + * @param _sda I2C SDA pin number, default to -1 to skip Wire begin call + * @param _scl I2C SCL pin number, default to -1 (only SDA = -1 is considered to skip Wire begin call) + * @param g display geometry dafault to generic GEOMETRY_128_64, see OLEDDISPLAY_GEOMETRY definition for other options + * @param _i2cBus on ESP32 with 2 I2C HW buses, I2C_ONE for 1st Bus, I2C_TWO fot 2nd bus, default I2C_ONE + * @param _frequency for Frequency by default Let's use ~700khz if ESP8266 is in 160Mhz mode, this will be limited to ~400khz if the ESP8266 in 80Mhz mode + */ + SSD1306Wire(uint8_t _address, int _sda = -1, int _scl = -1, OLEDDISPLAY_GEOMETRY g = GEOMETRY_128_64, HW_I2C _i2cBus = I2C_ONE, int _frequency = 700000) { + setGeometry(g); + + this->_address = _address; + this->_sda = _sda; + this->_scl = _scl; + this->_wire = (_i2cBus==I2C_ONE) ? &Wire : &Wire1; + this->_frequency = _frequency; + } + + bool connect() { + // On ESP32 arduino, -1 means 'don't change pins', someone else has called begin for us. + if(this->_sda != -1) + _wire->begin(this->_sda, this->_scl); + // Let's use ~700khz if ESP8266 is in 160Mhz mode + // this will be limited to ~400khz if the ESP8266 in 80Mhz mode. + if(this->_frequency != -1) + _wire->setClock(this->_frequency); + return true; + } + + void display(void) { + initI2cIfNeccesary(); + const int x_offset = (128 - this->width()) / 2; + #ifdef OLEDDISPLAY_DOUBLE_BUFFER + uint8_t minBoundY = UINT8_MAX; + uint8_t maxBoundY = 0; + + uint8_t minBoundX = UINT8_MAX; + uint8_t maxBoundX = 0; + uint8_t x, y; + + // Calculate the Y bounding box of changes + // and copy buffer[pos] to buffer_back[pos]; + for (y = 0; y < (this->height() / 8); y++) { + for (x = 0; x < this->width(); x++) { + uint16_t pos = x + y * this->width(); + if (buffer[pos] != buffer_back[pos]) { + minBoundY = std::min(minBoundY, y); + maxBoundY = std::max(maxBoundY, y); + minBoundX = std::min(minBoundX, x); + maxBoundX = std::max(maxBoundX, x); + } + buffer_back[pos] = buffer[pos]; + } + yield(); + } + + // If the minBoundY wasn't updated + // we can savely assume that buffer_back[pos] == buffer[pos] + // holdes true for all values of pos + + if (minBoundY == UINT8_MAX) return; + + sendCommand(COLUMNADDR); + sendCommand(x_offset + minBoundX); + sendCommand(x_offset + maxBoundX); + + sendCommand(PAGEADDR); + sendCommand(minBoundY); + sendCommand(maxBoundY); + + byte k = 0; + for (y = minBoundY; y <= maxBoundY; y++) { + for (x = minBoundX; x <= maxBoundX; x++) { + if (k == 0) { + _wire->beginTransmission(_address); + _wire->write(0x40); + } + + _wire->write(buffer[x + y * this->width()]); + k++; + if (k == 16) { + _wire->endTransmission(); + k = 0; + } + } + yield(); + } + + if (k != 0) { + _wire->endTransmission(); + } + #else + + sendCommand(COLUMNADDR); + sendCommand(x_offset); + sendCommand(x_offset + (this->width() - 1)); + + sendCommand(PAGEADDR); + sendCommand(0x0); + + for (uint16_t i=0; i < displayBufferSize; i++) { + _wire->beginTransmission(this->_address); + _wire->write(0x40); + for (uint8_t x = 0; x < 16; x++) { + _wire->write(buffer[i]); + i++; + } + i--; + _wire->endTransmission(); + } + #endif + } + + void setI2cAutoInit(bool doI2cAutoInit) { + _doI2cAutoInit = doI2cAutoInit; + } + + private: + int getBufferOffset(void) { + return 0; + } + inline void sendCommand(uint8_t command) __attribute__((always_inline)){ + initI2cIfNeccesary(); + _wire->beginTransmission(_address); + _wire->write(0x80); + _wire->write(command); + _wire->endTransmission(); + } + + void initI2cIfNeccesary() { + if (_doI2cAutoInit) { + _wire->begin(this->_sda, this->_scl); + } + } + +}; + +#endif diff --git a/platformio.ini b/platformio.ini index c2a2ebe..b0ed3a5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -4,8 +4,6 @@ framework = arduino lib_ldf_mode = deep+ monitor_speed = 115200 lib_deps = - adafruit/Adafruit GFX Library @ 1.7.5 - adafruit/Adafruit SSD1306 @ 2.4.0 bblanchon/ArduinoJson @ 6.17.0 lewisxhe/AXP202X_Library @ 1.1.2 peterus/APRS-Decoder-Lib @ 0.0.6 @@ -13,7 +11,8 @@ lib_deps = peterus/ESP-FTP-Server-Lib @ 0.9.5 check_tool = cppcheck check_flags = - cppcheck: --suppress=*:*.pio\* --inline-suppr -DCPPCHECK --force lib -ilib/TimeLib -ilib/LoRa -ilib/NTPClient + cppcheck: --suppress=*:*.pio\* --inline-suppr -DCPPCHECK --force lib -ilib/TimeLib -ilib/LoRa -ilib/NTPClient -ilib/Display +check_skip_packages = yes monitor_flags = --raw # activate for OTA Update, use the CALLSIGN from is-cfg.json as upload_port: #upload_protocol = espota diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index ca69df7..d1af131 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -7,11 +7,12 @@ #include #include "BoardFinder.h" -#include "display.h" +//#include "display.h" #include "power_management.h" #include "project_configuration.h" #include "TaskAprsIs.h" +#include "TaskDisplay.h" #include "TaskEth.h" #include "TaskFTP.h" #include "TaskLora.h" @@ -86,11 +87,12 @@ void setup() logPrintlnW("LoRa APRS iGate by OE5BPA (Peter Buchegger)"); logPrintlnW("Version: 20.49.0-dev"); - setup_display(boardConfig); - show_display("OE5BPA", "LoRa APRS iGate", "by Peter Buchegger", "20.49.0-dev", 3000); + //setup_display(boardConfig); + //show_display("OE5BPA", "LoRa APRS iGate", "by Peter Buchegger", "20.49.0-dev", 3000); load_config(boardConfig); + TaskManager::instance().addTask(std::shared_ptr(new DisplayTask())); TaskManager::instance().addTask(std::shared_ptr(new LoraTask())); if(boardConfig->Type == eETH_BOARD) { diff --git a/src/TaskDisplay.cpp b/src/TaskDisplay.cpp new file mode 100644 index 0000000..89f4045 --- /dev/null +++ b/src/TaskDisplay.cpp @@ -0,0 +1,30 @@ +#include +#include +#include "project_configuration.h" +#include "TaskDisplay.h" +#include "Task.h" + +DisplayTask::DisplayTask() + : Task(TASK_DISPLAY, TaskDisplay), _beginCalled(false) +{ +} + +DisplayTask::~DisplayTask() +{ +} + +bool DisplayTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) +{ + Display::instance().setup(boardConfig); + return true; +} + +bool DisplayTask::loop(std::shared_ptr config) +{ + if(!_beginCalled) + { + _beginCalled = true; + } + Display::instance().update(); + return true; +} diff --git a/src/TaskDisplay.h b/src/TaskDisplay.h new file mode 100644 index 0000000..05fffc1 --- /dev/null +++ b/src/TaskDisplay.h @@ -0,0 +1,20 @@ +#ifndef TASK_DISPLAY_H_ +#define TASK_DISPLAY_H_ + +#include +#include + +class DisplayTask : public Task +{ +public: + DisplayTask(); + virtual ~DisplayTask(); + + virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; + virtual bool loop(std::shared_ptr config) override; + +private: + bool _beginCalled; +}; + +#endif diff --git a/src/display.cpp b/src/display.cpp deleted file mode 100644 index 59c266f..0000000 --- a/src/display.cpp +++ /dev/null @@ -1,146 +0,0 @@ - -#include -#include -#include - -#include "BoardFinder.h" -#include "display.h" -#include "logger.h" - -Adafruit_SSD1306 * display = 0; -TwoWire * wire = 0; - -// cppcheck-suppress unusedFunction -void setup_display(std::shared_ptr boardConfig) -{ - if(display == 0) - { - wire = new TwoWire(0); - wire->begin(boardConfig->OledSda, boardConfig->OledScl); - if(boardConfig->OledReset > 0) - { - display = new Adafruit_SSD1306(128, 64, wire, boardConfig->OledReset); - logPrintlnI("with reset"); - } - else - { - display = new Adafruit_SSD1306(128, 64, wire); - logPrintlnI("with NO reset"); - } - } - if(!display->begin(SSD1306_SWITCHCAPVCC, boardConfig->OledAddr, false, false)) - { - logPrintlnE("SSD1306 allocation failed"); - while (1); - } - logPrintlnI("Display init done!"); -} - -/*void turn_off_display() -{ - display->ssd1306_command(SSD1306_DISPLAYOFF); -}*/ - -/*void show_display(String header, int wait) -{ - display->clearDisplay(); - display->setTextColor(WHITE); - display->setTextSize(2); - display->setCursor(0,0); - display->println(header); - display->display(); - delay(wait); -}*/ - -// cppcheck-suppress unusedFunction -void show_display(String header, String line1, int wait) -{ - display->clearDisplay(); - display->setTextColor(WHITE); - display->setTextSize(2); - display->setCursor(0,0); - display->println(header); - display->setTextSize(1); - display->setCursor(0,16); - display->println(line1); - display->display(); - delay(wait); -} - -// cppcheck-suppress unusedFunction -void show_display(String header, String line1, String line2, int wait) -{ - display->clearDisplay(); - display->setTextColor(WHITE); - display->setTextSize(2); - display->setCursor(0,0); - display->println(header); - display->setTextSize(1); - display->setCursor(0,16); - display->println(line1); - display->setCursor(0,26); - display->println(line2); - display->display(); - delay(wait); -} - -// cppcheck-suppress unusedFunction -void show_display(String header, String line1, String line2, String line3, int wait) -{ - display->clearDisplay(); - display->setTextColor(WHITE); - display->setTextSize(2); - display->setCursor(0,0); - display->println(header); - display->setTextSize(1); - display->setCursor(0,16); - display->println(line1); - display->setCursor(0,26); - display->println(line2); - display->setCursor(0,36); - display->println(line3); - display->display(); - delay(wait); -} - -/*void show_display(String header, String line1, String line2, String line3, String line4, int wait) -{ - display->clearDisplay(); - display->setTextColor(WHITE); - display->setTextSize(2); - display->setCursor(0,0); - display->println(header); - display->setTextSize(1); - display->setCursor(0,16); - display->println(line1); - display->setCursor(0,26); - display->println(line2); - display->setCursor(0,36); - display->println(line3); - display->setCursor(0,46); - display->println(line4); - display->display(); - delay(wait); -}*/ - -/*void show_display(String header, String line1, String line2, String line3, String line4, String line5, int wait) -{ - display->clearDisplay(); - display->setTextColor(WHITE); - display->setTextSize(2); - display->setCursor(0,0); - display->println(header); - display->setTextSize(1); - display->setCursor(0,16); - display->println(line1); - display->setCursor(0,26); - display->println(line2); - display->setCursor(0,36); - display->println(line3); - display->setCursor(0,46); - display->println(line4); - display->setCursor(0,56); - display->println(line5); - display->display(); - delay(wait); -}*/ diff --git a/src/display.h b/src/display.h deleted file mode 100644 index 4bd7530..0000000 --- a/src/display.h +++ /dev/null @@ -1,46 +0,0 @@ - -#ifndef DISPLAY_H_ -#define DISPLAY_H_ - -void setup_display(std::shared_ptr boardConfig); -//void turn_off_display(); - -//void show_display(String header, int wait = 0); -void show_display(String header, String line1, int wait = 0); -void show_display(String header, String line1, String line2, int wait = 0); -void show_display(String header, String line1, String line2, String line3, int wait = 0); -//void show_display(String header, String line1, String line2, String line3, String line4, int wait = 0); -//void show_display(String header, String line1, String line2, String line3, String line4, String line5, int wait = 0); - -#include -#include "TimeLib.h" -#include "logger.h" - -/*class PrintMessageToConsole : public Slot1>, public Slot3, int, float> -{ -public: - void action(std::shared_ptr msg, int rssi, float snr) override - { - //setup_display(boardConfig); secondsSinceDisplay = 0; //display_is_on = true; - //show_display(Config->callsign, timeClient->getFormattedTime() + " LoRa", "RSSI: " + String(lora_aprs->packetRssi()) + ", SNR: " + String(lora_aprs->packetSnr()), elem->toString()); - logPrintD("[" + timeString() + "] "); - logPrintD("Received packet '"); - logPrintD(msg->toString()); - logPrintD("' with RSSI "); - logPrintD(String(rssi)); - logPrintD(" and SNR "); - logPrintlnD(String(snr)); - } - - void action(std::shared_ptr msg) override - { - //setup_display(boardConfig); secondsSinceDisplay = 0; //display_is_on = true; - //show_display(Config->callsign, timeClient->getFormattedTime() + " LoRa", "RSSI: " + String(lora_aprs->packetRssi()) + ", SNR: " + String(lora_aprs->packetSnr()), elem->toString()); - logPrintD("[" + timeString() + "] "); - logPrintD("Received packet '"); - logPrintD(msg->toString()); - logPrintD("'"); - } -};*/ - -#endif From 6375c1fc13e6d4e1ffda47ee9f8b7e500b7b304a Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Wed, 20 Jan 2021 00:31:02 +0100 Subject: [PATCH 32/60] update --- lib/Display/OLEDDisplayUi.h | 2 +- lib/Display/SSD1306.h | 10 +++++----- lib/TaskManager/TaskManager.cpp | 15 ++++++++------- src/Task.cpp | 4 ++-- src/Task.h | 2 +- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/lib/Display/OLEDDisplayUi.h b/lib/Display/OLEDDisplayUi.h index abba761..2b45147 100644 --- a/lib/Display/OLEDDisplayUi.h +++ b/lib/Display/OLEDDisplayUi.h @@ -164,7 +164,7 @@ class OLEDDisplayUi { public: - OLEDDisplayUi(OLEDDisplay *display); + explicit OLEDDisplayUi(OLEDDisplay *display); /** * Initialise the display diff --git a/lib/Display/SSD1306.h b/lib/Display/SSD1306.h index 4d0d4e1..b0ac1be 100644 --- a/lib/Display/SSD1306.h +++ b/lib/Display/SSD1306.h @@ -63,7 +63,7 @@ class SSD1306Wire : public OLEDDisplay { * @param _i2cBus on ESP32 with 2 I2C HW buses, I2C_ONE for 1st Bus, I2C_TWO fot 2nd bus, default I2C_ONE * @param _frequency for Frequency by default Let's use ~700khz if ESP8266 is in 160Mhz mode, this will be limited to ~400khz if the ESP8266 in 80Mhz mode */ - SSD1306Wire(uint8_t _address, int _sda = -1, int _scl = -1, OLEDDISPLAY_GEOMETRY g = GEOMETRY_128_64, HW_I2C _i2cBus = I2C_ONE, int _frequency = 700000) { + explicit SSD1306Wire(uint8_t _address, int _sda = -1, int _scl = -1, OLEDDISPLAY_GEOMETRY g = GEOMETRY_128_64, HW_I2C _i2cBus = I2C_ONE, int _frequency = 700000) { setGeometry(g); this->_address = _address; @@ -73,7 +73,7 @@ class SSD1306Wire : public OLEDDisplay { this->_frequency = _frequency; } - bool connect() { + bool connect() override { // On ESP32 arduino, -1 means 'don't change pins', someone else has called begin for us. if(this->_sda != -1) _wire->begin(this->_sda, this->_scl); @@ -84,7 +84,7 @@ class SSD1306Wire : public OLEDDisplay { return true; } - void display(void) { + void display(void) override { initI2cIfNeccesary(); const int x_offset = (128 - this->width()) / 2; #ifdef OLEDDISPLAY_DOUBLE_BUFFER @@ -173,10 +173,10 @@ class SSD1306Wire : public OLEDDisplay { } private: - int getBufferOffset(void) { + int getBufferOffset(void) override { return 0; } - inline void sendCommand(uint8_t command) __attribute__((always_inline)){ + inline void sendCommand(uint8_t command) __attribute__((always_inline)) override { initI2cIfNeccesary(); _wire->beginTransmission(_address); _wire->write(0x80); diff --git a/lib/TaskManager/TaskManager.cpp b/lib/TaskManager/TaskManager.cpp index 216712d..8f52e6c 100644 --- a/lib/TaskManager/TaskManager.cpp +++ b/lib/TaskManager/TaskManager.cpp @@ -12,14 +12,15 @@ void TaskManager::addTask(std::shared_ptr task) std::shared_ptr TaskManager::getTask(const char * name) { - for(std::shared_ptr & elem : _tasks) + std::_List_iterator> elem = std::find_if(_tasks.begin(), _tasks.end(), [&](std::shared_ptr task) { - if(elem->getName() == name) - { - return elem; - } + return task->getName() == name; + }); + if(elem == _tasks.end()) + { + return 0; } - return 0; + return *elem; } bool TaskManager::setup(std::shared_ptr config, std::shared_ptr boardConfig) @@ -50,4 +51,4 @@ bool TaskManager::loop(std::shared_ptr config) } } return true; -} \ No newline at end of file +} diff --git a/src/Task.cpp b/src/Task.cpp index fd3d9db..6acb4df 100644 --- a/src/Task.cpp +++ b/src/Task.cpp @@ -1,6 +1,6 @@ #include "Task.h" -char const * const getTaskName(TaskNames task) +/*char const * const getTaskName(TaskNames task) { switch (task) { @@ -23,4 +23,4 @@ char const * const getTaskName(TaskNames task) default: return "error"; } -} +}*/ diff --git a/src/Task.h b/src/Task.h index 14b0c5d..149ee27 100644 --- a/src/Task.h +++ b/src/Task.h @@ -14,7 +14,7 @@ enum TaskNames TaskSize, }; -char const * const getTaskName(TaskNames task); +//char const * const getTaskName(TaskNames task); #define TASK_DISPLAY "DisplayTask" #define TASK_APRS_IS "AprsIsTask" From 3585af057adf63761f557043e74254d0e28e40d9 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Wed, 20 Jan 2021 00:44:56 +0100 Subject: [PATCH 33/60] Update SSD1306.h --- lib/Display/SSD1306.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Display/SSD1306.h b/lib/Display/SSD1306.h index b0ac1be..923faef 100644 --- a/lib/Display/SSD1306.h +++ b/lib/Display/SSD1306.h @@ -176,7 +176,7 @@ class SSD1306Wire : public OLEDDisplay { int getBufferOffset(void) override { return 0; } - inline void sendCommand(uint8_t command) __attribute__((always_inline)) override { + inline void sendCommand(uint8_t command) override __attribute__((always_inline)) { initI2cIfNeccesary(); _wire->beginTransmission(_address); _wire->write(0x80); From 5eec516fb95b27fcf58a828de1419538ef31e43e Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sat, 30 Jan 2021 22:47:24 +0100 Subject: [PATCH 34/60] adding display support and many other stuff --- backup/OLEDDisplay.cpp | 1045 ++++++++++++++++++ backup/OLEDDisplay.h | 343 ++++++ {lib/Display => backup}/OLEDDisplayFonts.h | 0 {lib/Display => backup}/OLEDDisplayUi.cpp | 0 {lib/Display => backup}/OLEDDisplayUi.h | 0 backup/SSD1306.h | 195 ++++ lib/Display/Bitmap.cpp | 401 +++++++ lib/Display/Bitmap.h | 56 + lib/Display/Display.cpp | 97 +- lib/Display/Display.h | 41 +- lib/Display/FontConfig.cpp | 67 ++ lib/Display/FontConfig.h | 57 + lib/Display/Fonts/FontDesc.h | 18 + lib/Display/Fonts/HoloLens_12.h | 284 +++++ lib/Display/Fonts/HoloLens_20.h | 656 ++++++++++++ lib/Display/Fonts/Roboto_12.h | 371 +++++++ lib/Display/Fonts/Terminal_11.h | 381 +++++++ lib/Display/Fonts/Terminal_8.h | 163 +++ lib/Display/OLEDDisplay.cpp | 1111 +++----------------- lib/Display/OLEDDisplay.h | 306 +----- lib/Display/SSD1306.cpp | 42 + lib/Display/SSD1306.h | 165 +-- {src => lib/TaskManager}/TaskDisplay.cpp | 11 +- {src => lib/TaskManager}/TaskDisplay.h | 3 - lib/TaskManager/TaskManager.cpp | 47 + lib/TaskManager/TaskManager.h | 33 +- platformio.ini | 4 +- src/LoRa_APRS_iGate.cpp | 23 +- src/Task.h | 4 +- src/TaskAprsIs.cpp | 14 +- src/TaskFTP.cpp | 48 +- src/TaskLora.cpp | 4 + src/TaskNTP.cpp | 2 + src/TaskOTA.cpp | 1 + src/TaskWifi.cpp | 5 + 35 files changed, 4519 insertions(+), 1479 deletions(-) create mode 100644 backup/OLEDDisplay.cpp create mode 100644 backup/OLEDDisplay.h rename {lib/Display => backup}/OLEDDisplayFonts.h (100%) rename {lib/Display => backup}/OLEDDisplayUi.cpp (100%) rename {lib/Display => backup}/OLEDDisplayUi.h (100%) create mode 100644 backup/SSD1306.h create mode 100644 lib/Display/Bitmap.cpp create mode 100644 lib/Display/Bitmap.h create mode 100644 lib/Display/FontConfig.cpp create mode 100644 lib/Display/FontConfig.h create mode 100644 lib/Display/Fonts/FontDesc.h create mode 100644 lib/Display/Fonts/HoloLens_12.h create mode 100644 lib/Display/Fonts/HoloLens_20.h create mode 100644 lib/Display/Fonts/Roboto_12.h create mode 100644 lib/Display/Fonts/Terminal_11.h create mode 100644 lib/Display/Fonts/Terminal_8.h create mode 100644 lib/Display/SSD1306.cpp rename {src => lib/TaskManager}/TaskDisplay.cpp (64%) rename {src => lib/TaskManager}/TaskDisplay.h (92%) diff --git a/backup/OLEDDisplay.cpp b/backup/OLEDDisplay.cpp new file mode 100644 index 0000000..ddc3e98 --- /dev/null +++ b/backup/OLEDDisplay.cpp @@ -0,0 +1,1045 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn + * Copyright (c) 2018 by Fabrice Weinberg + * Copyright (c) 2019 by Helmut Tschemernjak - www.radioshuttle.de + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ThingPulse invests considerable time and money to develop these open source libraries. + * Please support us by buying our products (and not the clones) from + * https://thingpulse.com + * + */ + + /* + * TODO Helmut + * - test/finish dislplay.printf() on mbed-os + * - Finish _putc with drawLogBuffer when running display + */ + +#include "OLEDDisplay.h" + +OLEDDisplay::OLEDDisplay() { + + displayWidth = 128; + displayHeight = 64; + displayBufferSize = displayWidth * displayHeight / 8; + color = WHITE; + geometry = GEOMETRY_128_64; + textAlignment = TEXT_ALIGN_LEFT; + fontData = ArialMT_Plain_10; + fontTableLookupFunction = DefaultFontTableLookup; + buffer = NULL; +#ifdef OLEDDISPLAY_DOUBLE_BUFFER + buffer_back = NULL; +#endif +} + +OLEDDisplay::~OLEDDisplay() { + end(); +} + +bool OLEDDisplay::allocateBuffer() { + + logBufferSize = 0; + logBufferFilled = 0; + logBufferLine = 0; + logBufferMaxLines = 0; + logBuffer = NULL; + + if (!this->connect()) { + DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Can't establish connection to display\n"); + return false; + } + + if(this->buffer==NULL) { + this->buffer = (uint8_t*) malloc((sizeof(uint8_t) * displayBufferSize) + BufferOffset); + this->buffer += BufferOffset; + + if(!this->buffer) { + DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Not enough memory to create display\n"); + return false; + } + } + + #ifdef OLEDDISPLAY_DOUBLE_BUFFER + if(this->buffer_back==NULL) { + this->buffer_back = (uint8_t*) malloc((sizeof(uint8_t) * displayBufferSize) + BufferOffset); + this->buffer_back += BufferOffset; + + if(!this->buffer_back) { + DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Not enough memory to create back buffer\n"); + free(this->buffer - BufferOffset); + return false; + } + } + #endif + + return true; +} + +bool OLEDDisplay::init() { + + BufferOffset = getBufferOffset(); + + if(!allocateBuffer()) { + return false; + } + + sendInitCommands(); + resetDisplay(); + + return true; +} + +void OLEDDisplay::end() { + if (this->buffer) { free(this->buffer - BufferOffset); this->buffer = NULL; } + #ifdef OLEDDISPLAY_DOUBLE_BUFFER + if (this->buffer_back) { free(this->buffer_back - BufferOffset); this->buffer_back = NULL; } + #endif + if (this->logBuffer != NULL) { free(this->logBuffer); this->logBuffer = NULL; } +} + +void OLEDDisplay::resetDisplay(void) { + clear(); + #ifdef OLEDDISPLAY_DOUBLE_BUFFER + memset(buffer_back, 1, displayBufferSize); + #endif + display(); +} + +void OLEDDisplay::setColor(OLEDDISPLAY_COLOR color) { + this->color = color; +} + +OLEDDISPLAY_COLOR OLEDDisplay::getColor() { + return this->color; +} + +void OLEDDisplay::setPixel(int16_t x, int16_t y) { + if (x >= 0 && x < this->width() && y >= 0 && y < this->height()) { + switch (color) { + case WHITE: buffer[x + (y / 8) * this->width()] |= (1 << (y & 7)); break; + case BLACK: buffer[x + (y / 8) * this->width()] &= ~(1 << (y & 7)); break; + case INVERSE: buffer[x + (y / 8) * this->width()] ^= (1 << (y & 7)); break; + } + } +} + +void OLEDDisplay::setPixelColor(int16_t x, int16_t y, OLEDDISPLAY_COLOR color) { + if (x >= 0 && x < this->width() && y >= 0 && y < this->height()) { + switch (color) { + case WHITE: buffer[x + (y / 8) * this->width()] |= (1 << (y & 7)); break; + case BLACK: buffer[x + (y / 8) * this->width()] &= ~(1 << (y & 7)); break; + case INVERSE: buffer[x + (y / 8) * this->width()] ^= (1 << (y & 7)); break; + } + } +} + +void OLEDDisplay::clearPixel(int16_t x, int16_t y) { + if (x >= 0 && x < this->width() && y >= 0 && y < this->height()) { + switch (color) { + case BLACK: buffer[x + (y >> 3) * this->width()] |= (1 << (y & 7)); break; + case WHITE: buffer[x + (y >> 3) * this->width()] &= ~(1 << (y & 7)); break; + case INVERSE: buffer[x + (y >> 3) * this->width()] ^= (1 << (y & 7)); break; + } + } +} + + +// Bresenham's algorithm - thx wikipedia and Adafruit_GFX +void OLEDDisplay::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1) { + int16_t steep = abs(y1 - y0) > abs(x1 - x0); + if (steep) { + _swap_int16_t(x0, y0); + _swap_int16_t(x1, y1); + } + + if (x0 > x1) { + _swap_int16_t(x0, x1); + _swap_int16_t(y0, y1); + } + + int16_t dx, dy; + dx = x1 - x0; + dy = abs(y1 - y0); + + int16_t err = dx / 2; + int16_t ystep; + + if (y0 < y1) { + ystep = 1; + } else { + ystep = -1; + } + + for (; x0<=x1; x0++) { + if (steep) { + setPixel(y0, x0); + } else { + setPixel(x0, y0); + } + err -= dy; + if (err < 0) { + y0 += ystep; + err += dx; + } + } +} + +void OLEDDisplay::drawRect(int16_t x, int16_t y, int16_t width, int16_t height) { + drawHorizontalLine(x, y, width); + drawVerticalLine(x, y, height); + drawVerticalLine(x + width - 1, y, height); + drawHorizontalLine(x, y + height - 1, width); +} + +void OLEDDisplay::fillRect(int16_t xMove, int16_t yMove, int16_t width, int16_t height) { + for (int16_t x = xMove; x < xMove + width; x++) { + drawVerticalLine(x, yMove, height); + } +} + +void OLEDDisplay::drawCircle(int16_t x0, int16_t y0, int16_t radius) { + int16_t x = 0, y = radius; + int16_t dp = 1 - radius; + do { + if (dp < 0) + dp = dp + (x++) * 2 + 3; + else + dp = dp + (x++) * 2 - (y--) * 2 + 5; + + setPixel(x0 + x, y0 + y); //For the 8 octants + setPixel(x0 - x, y0 + y); + setPixel(x0 + x, y0 - y); + setPixel(x0 - x, y0 - y); + setPixel(x0 + y, y0 + x); + setPixel(x0 - y, y0 + x); + setPixel(x0 + y, y0 - x); + setPixel(x0 - y, y0 - x); + + } while (x < y); + + setPixel(x0 + radius, y0); + setPixel(x0, y0 + radius); + setPixel(x0 - radius, y0); + setPixel(x0, y0 - radius); +} + +void OLEDDisplay::drawCircleQuads(int16_t x0, int16_t y0, int16_t radius, uint8_t quads) { + int16_t x = 0, y = radius; + int16_t dp = 1 - radius; + while (x < y) { + if (dp < 0) + dp = dp + (x++) * 2 + 3; + else + dp = dp + (x++) * 2 - (y--) * 2 + 5; + if (quads & 0x1) { + setPixel(x0 + x, y0 - y); + setPixel(x0 + y, y0 - x); + } + if (quads & 0x2) { + setPixel(x0 - y, y0 - x); + setPixel(x0 - x, y0 - y); + } + if (quads & 0x4) { + setPixel(x0 - y, y0 + x); + setPixel(x0 - x, y0 + y); + } + if (quads & 0x8) { + setPixel(x0 + x, y0 + y); + setPixel(x0 + y, y0 + x); + } + } + if (quads & 0x1 && quads & 0x8) { + setPixel(x0 + radius, y0); + } + if (quads & 0x4 && quads & 0x8) { + setPixel(x0, y0 + radius); + } + if (quads & 0x2 && quads & 0x4) { + setPixel(x0 - radius, y0); + } + if (quads & 0x1 && quads & 0x2) { + setPixel(x0, y0 - radius); + } +} + + +void OLEDDisplay::fillCircle(int16_t x0, int16_t y0, int16_t radius) { + int16_t x = 0, y = radius; + int16_t dp = 1 - radius; + do { + if (dp < 0) + dp = dp + (x++) * 2 + 3; + else + dp = dp + (x++) * 2 - (y--) * 2 + 5; + + drawHorizontalLine(x0 - x, y0 - y, 2*x); + drawHorizontalLine(x0 - x, y0 + y, 2*x); + drawHorizontalLine(x0 - y, y0 - x, 2*y); + drawHorizontalLine(x0 - y, y0 + x, 2*y); + + + } while (x < y); + drawHorizontalLine(x0 - radius, y0, 2 * radius); + +} + +void OLEDDisplay::drawHorizontalLine(int16_t x, int16_t y, int16_t length) { + if (y < 0 || y >= this->height()) { return; } + + if (x < 0) { + length += x; + x = 0; + } + + if ( (x + length) > this->width()) { + length = (this->width() - x); + } + + if (length <= 0) { return; } + + uint8_t * bufferPtr = buffer; + bufferPtr += (y >> 3) * this->width(); + bufferPtr += x; + + uint8_t drawBit = 1 << (y & 7); + + switch (color) { + case WHITE: while (length--) { + *bufferPtr++ |= drawBit; + }; break; + case BLACK: drawBit = ~drawBit; while (length--) { + *bufferPtr++ &= drawBit; + }; break; + case INVERSE: while (length--) { + *bufferPtr++ ^= drawBit; + }; break; + } +} + +void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) { + if (x < 0 || x >= this->width()) return; + + if (y < 0) { + length += y; + y = 0; + } + + if ( (y + length) > this->height()) { + length = (this->height() - y); + } + + if (length <= 0) return; + + + uint8_t yOffset = y & 7; + uint8_t drawBit; + uint8_t *bufferPtr = buffer; + + bufferPtr += (y >> 3) * this->width(); + bufferPtr += x; + + if (yOffset) { + yOffset = 8 - yOffset; + drawBit = ~(0xFF >> (yOffset)); + + if (length < yOffset) { + drawBit &= (0xFF >> (yOffset - length)); + } + + switch (color) { + case WHITE: *bufferPtr |= drawBit; break; + case BLACK: *bufferPtr &= ~drawBit; break; + case INVERSE: *bufferPtr ^= drawBit; break; + } + + if (length < yOffset) return; + + length -= yOffset; + bufferPtr += this->width(); + } + + if (length >= 8) { + switch (color) { + case WHITE: + case BLACK: + drawBit = (color == WHITE) ? 0xFF : 0x00; + do { + *bufferPtr = drawBit; + bufferPtr += this->width(); + length -= 8; + } while (length >= 8); + break; + case INVERSE: + do { + *bufferPtr = ~(*bufferPtr); + bufferPtr += this->width(); + length -= 8; + } while (length >= 8); + break; + } + } + + if (length > 0) { + drawBit = (1 << (length & 7)) - 1; + switch (color) { + case WHITE: *bufferPtr |= drawBit; break; + case BLACK: *bufferPtr &= ~drawBit; break; + case INVERSE: *bufferPtr ^= drawBit; break; + } + } +} + +void OLEDDisplay::drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t progress) { + uint16_t radius = height / 2; + uint16_t xRadius = x + radius; + uint16_t yRadius = y + radius; + uint16_t doubleRadius = 2 * radius; + uint16_t innerRadius = radius - 2; + + setColor(WHITE); + drawCircleQuads(xRadius, yRadius, radius, 0b00000110); + drawHorizontalLine(xRadius, y, width - doubleRadius + 1); + drawHorizontalLine(xRadius, y + height, width - doubleRadius + 1); + drawCircleQuads(x + width - radius, yRadius, radius, 0b00001001); + + uint16_t maxProgressWidth = (width - doubleRadius + 1) * progress / 100; + + fillCircle(xRadius, yRadius, innerRadius); + fillRect(xRadius + 1, y + 2, maxProgressWidth, height - 3); + fillCircle(xRadius + maxProgressWidth, yRadius, innerRadius); +} + +void OLEDDisplay::drawFastImage(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const uint8_t *image) { + drawInternal(xMove, yMove, width, height, image, 0, 0); +} + +void OLEDDisplay::drawXbm(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const uint8_t *xbm) { + int16_t widthInXbm = (width + 7) / 8; + uint8_t data = 0; + + for(int16_t y = 0; y < height; y++) { + for(int16_t x = 0; x < width; x++ ) { + if (x & 7) { + data >>= 1; // Move a bit + } else { // Read new data every 8 bit + data = pgm_read_byte(xbm + (x / 8) + y * widthInXbm); + } + // if there is a bit draw it + if (data & 0x01) { + setPixel(xMove + x, yMove + y); + } + } + } +} + +void OLEDDisplay::drawIco16x16(int16_t xMove, int16_t yMove, const char *ico, bool inverse) { + uint16_t data; + + for(int16_t y = 0; y < 16; y++) { + data = pgm_read_byte(ico + (y << 1)) + (pgm_read_byte(ico + (y << 1) + 1) << 8); + for(int16_t x = 0; x < 16; x++ ) { + if ((data & 0x01) ^ inverse) { + setPixelColor(xMove + x, yMove + y, WHITE); + } else { + setPixelColor(xMove + x, yMove + y, BLACK); + } + data >>= 1; // Move a bit + } + } +} + +void OLEDDisplay::drawStringInternal(int16_t xMove, int16_t yMove, char* text, uint16_t textLength, uint16_t textWidth) { + uint8_t textHeight = pgm_read_byte(fontData + HEIGHT_POS); + uint8_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS); + uint16_t sizeOfJumpTable = pgm_read_byte(fontData + CHAR_NUM_POS) * JUMPTABLE_BYTES; + + uint16_t cursorX = 0; + uint16_t cursorY = 0; + + switch (textAlignment) { + case TEXT_ALIGN_CENTER_BOTH: + yMove -= textHeight >> 1; + // Fallthrough + case TEXT_ALIGN_CENTER: + xMove -= textWidth >> 1; // divide by 2 + break; + case TEXT_ALIGN_RIGHT: + xMove -= textWidth; + break; + case TEXT_ALIGN_LEFT: + break; + } + + // Don't draw anything if it is not on the screen. + if (xMove + textWidth < 0 || xMove > this->width() ) {return;} + if (yMove + textHeight < 0 || yMove > this->width() ) {return;} + + for (uint16_t j = 0; j < textLength; j++) { + int16_t xPos = xMove + cursorX; + int16_t yPos = yMove + cursorY; + + uint8_t code = text[j]; + if (code >= firstChar) { + uint8_t charCode = code - firstChar; + + // 4 Bytes per char code + uint8_t msbJumpToChar = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES ); // MSB \ JumpAddress + uint8_t lsbJumpToChar = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_LSB); // LSB / + uint8_t charByteSize = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_SIZE); // Size + uint8_t currentCharWidth = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_WIDTH); // Width + + // Test if the char is drawable + if (!(msbJumpToChar == 255 && lsbJumpToChar == 255)) { + // Get the position of the char data + uint16_t charDataPosition = JUMPTABLE_START + sizeOfJumpTable + ((msbJumpToChar << 8) + lsbJumpToChar); + drawInternal(xPos, yPos, currentCharWidth, textHeight, fontData, charDataPosition, charByteSize); + } + + cursorX += currentCharWidth; + } + } +} + + +void OLEDDisplay::drawString(int16_t xMove, int16_t yMove, String strUser) { + uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS); + + // char* text must be freed! + char* text = utf8ascii(strUser); + + uint16_t yOffset = 0; + // If the string should be centered vertically too + // we need to now how heigh the string is. + if (textAlignment == TEXT_ALIGN_CENTER_BOTH) { + uint16_t lb = 0; + // Find number of linebreaks in text + for (uint16_t i=0;text[i] != 0; i++) { + lb += (text[i] == 10); + } + // Calculate center + yOffset = (lb * lineHeight) / 2; + } + + uint16_t line = 0; + char* textPart = strtok(text,"\n"); + while (textPart != NULL) { + uint16_t length = strlen(textPart); + drawStringInternal(xMove, yMove - yOffset + (line++) * lineHeight, textPart, length, getStringWidth(textPart, length)); + textPart = strtok(NULL, "\n"); + } + free(text); +} + +void OLEDDisplay::drawStringf( int16_t x, int16_t y, char* buffer, String format, ... ) +{ + va_list myargs; + va_start(myargs, format); + vsprintf(buffer, format.c_str(), myargs); + va_end(myargs); + drawString( x, y, buffer ); +} + +void OLEDDisplay::drawStringMaxWidth(int16_t xMove, int16_t yMove, uint16_t maxLineWidth, String strUser) { + uint16_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS); + uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS); + + char* text = utf8ascii(strUser); + + uint16_t length = strlen(text); + uint16_t lastDrawnPos = 0; + uint16_t lineNumber = 0; + uint16_t strWidth = 0; + + uint16_t preferredBreakpoint = 0; + uint16_t widthAtBreakpoint = 0; + + for (uint16_t i = 0; i < length; i++) { + strWidth += pgm_read_byte(fontData + JUMPTABLE_START + (text[i] - firstChar) * JUMPTABLE_BYTES + JUMPTABLE_WIDTH); + + // Always try to break on a space or dash + if (text[i] == ' ' || text[i]== '-') { + preferredBreakpoint = i; + widthAtBreakpoint = strWidth; + } + + if (strWidth >= maxLineWidth) { + if (preferredBreakpoint == 0) { + preferredBreakpoint = i; + widthAtBreakpoint = strWidth; + } + drawStringInternal(xMove, yMove + (lineNumber++) * lineHeight , &text[lastDrawnPos], preferredBreakpoint - lastDrawnPos, widthAtBreakpoint); + lastDrawnPos = preferredBreakpoint + 1; + // It is possible that we did not draw all letters to i so we need + // to account for the width of the chars from `i - preferredBreakpoint` + // by calculating the width we did not draw yet. + strWidth = strWidth - widthAtBreakpoint; + preferredBreakpoint = 0; + } + } + + // Draw last part if needed + if (lastDrawnPos < length) { + drawStringInternal(xMove, yMove + lineNumber * lineHeight , &text[lastDrawnPos], length - lastDrawnPos, getStringWidth(&text[lastDrawnPos], length - lastDrawnPos)); + } + + free(text); +} + +uint16_t OLEDDisplay::getStringWidth(const char* text, uint16_t length) { + uint16_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS); + + uint16_t stringWidth = 0; + uint16_t maxWidth = 0; + + while (length--) { + stringWidth += pgm_read_byte(fontData + JUMPTABLE_START + (text[length] - firstChar) * JUMPTABLE_BYTES + JUMPTABLE_WIDTH); + if (text[length] == 10) { + maxWidth = max(maxWidth, stringWidth); + stringWidth = 0; + } + } + + return max(maxWidth, stringWidth); +} + +uint16_t OLEDDisplay::getStringWidth(String strUser) { + char* text = utf8ascii(strUser); + uint16_t length = strlen(text); + uint16_t width = getStringWidth(text, length); + free(text); + return width; +} + +void OLEDDisplay::setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT textAlignment) { + this->textAlignment = textAlignment; +} + +void OLEDDisplay::setFont(const uint8_t *fontData) { + this->fontData = fontData; +} + +void OLEDDisplay::displayOn(void) { + sendCommand(DISPLAYON); +} + +void OLEDDisplay::displayOff(void) { + sendCommand(DISPLAYOFF); +} + +void OLEDDisplay::invertDisplay(void) { + sendCommand(INVERTDISPLAY); +} + +void OLEDDisplay::normalDisplay(void) { + sendCommand(NORMALDISPLAY); +} + +void OLEDDisplay::setContrast(uint8_t contrast, uint8_t precharge, uint8_t comdetect) { + sendCommand(SETPRECHARGE); //0xD9 + sendCommand(precharge); //0xF1 default, to lower the contrast, put 1-1F + sendCommand(SETCONTRAST); + sendCommand(contrast); // 0-255 + sendCommand(SETVCOMDETECT); //0xDB, (additionally needed to lower the contrast) + sendCommand(comdetect); //0x40 default, to lower the contrast, put 0 + sendCommand(DISPLAYALLON_RESUME); + sendCommand(NORMALDISPLAY); + sendCommand(DISPLAYON); +} + +void OLEDDisplay::setBrightness(uint8_t brightness) { + uint8_t contrast = brightness; + if (brightness < 128) { + // Magic values to get a smooth/ step-free transition + contrast = brightness * 1.171; + } else { + contrast = brightness * 1.171 - 43; + } + + uint8_t precharge = 241; + if (brightness == 0) { + precharge = 0; + } + uint8_t comdetect = brightness / 8; + + setContrast(contrast, precharge, comdetect); +} + +void OLEDDisplay::resetOrientation() { + sendCommand(SEGREMAP); + sendCommand(COMSCANINC); //Reset screen rotation or mirroring +} + +void OLEDDisplay::flipScreenVertically() { + sendCommand(SEGREMAP | 0x01); + sendCommand(COMSCANDEC); //Rotate screen 180 Deg +} + +void OLEDDisplay::mirrorScreen() { + sendCommand(SEGREMAP); + sendCommand(COMSCANDEC); //Mirror screen +} + +void OLEDDisplay::clear(void) { + memset(buffer, 0, displayBufferSize); +} + +void OLEDDisplay::drawLogBuffer(uint16_t xMove, uint16_t yMove) { + uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS); + // Always align left + setTextAlignment(TEXT_ALIGN_LEFT); + + // State values + uint16_t length = 0; + uint16_t line = 0; + uint16_t lastPos = 0; + + for (uint16_t i=0;ilogBufferFilled;i++){ + // Everytime we have a \n print + if (this->logBuffer[i] == 10) { + length++; + // Draw string on line `line` from lastPos to length + // Passing 0 as the lenght because we are in TEXT_ALIGN_LEFT + drawStringInternal(xMove, yMove + (line++) * lineHeight, &this->logBuffer[lastPos], length, 0); + // Remember last pos + lastPos = i; + // Reset length + length = 0; + } else { + // Count chars until next linebreak + length++; + } + } + // Draw the remaining string + if (length > 0) { + drawStringInternal(xMove, yMove + line * lineHeight, &this->logBuffer[lastPos], length, 0); + } +} + +uint16_t OLEDDisplay::getWidth(void) { + return displayWidth; +} + +uint16_t OLEDDisplay::getHeight(void) { + return displayHeight; +} + +bool OLEDDisplay::setLogBuffer(uint16_t lines, uint16_t chars){ + if (logBuffer != NULL) free(logBuffer); + uint16_t size = lines * chars; + if (size > 0) { + this->logBufferLine = 0; // Lines printed + this->logBufferFilled = 0; // Nothing stored yet + this->logBufferMaxLines = lines; // Lines max printable + this->logBufferSize = size; // Total number of characters the buffer can hold + this->logBuffer = (char *) malloc(size * sizeof(uint8_t)); + if(!this->logBuffer) { + DEBUG_OLEDDISPLAY("[OLEDDISPLAY][setLogBuffer] Not enough memory to create log buffer\n"); + return false; + } + } + return true; +} + +size_t OLEDDisplay::write(uint8_t c) { + if (this->logBufferSize > 0) { + // Don't waste space on \r\n line endings, dropping \r + if (c == 13) return 1; + + // convert UTF-8 character to font table index + c = (this->fontTableLookupFunction)(c); + // drop unknown character + if (c == 0) return 1; + + bool maxLineNotReached = this->logBufferLine < this->logBufferMaxLines; + bool bufferNotFull = this->logBufferFilled < this->logBufferSize; + + // Can we write to the buffer? + if (bufferNotFull && maxLineNotReached) { + this->logBuffer[logBufferFilled] = c; + this->logBufferFilled++; + // Keep track of lines written + if (c == 10) this->logBufferLine++; + } else { + // Max line number is reached + if (!maxLineNotReached) this->logBufferLine--; + + // Find the end of the first line + uint16_t firstLineEnd = 0; + for (uint16_t i=0;ilogBufferFilled;i++) { + if (this->logBuffer[i] == 10){ + // Include last char too + firstLineEnd = i + 1; + break; + } + } + // If there was a line ending + if (firstLineEnd > 0) { + // Calculate the new logBufferFilled value + this->logBufferFilled = logBufferFilled - firstLineEnd; + // Now we move the lines infront of the buffer + memcpy(this->logBuffer, &this->logBuffer[firstLineEnd], logBufferFilled); + } else { + // Let's reuse the buffer if it was full + if (!bufferNotFull) { + this->logBufferFilled = 0; + }// else { + // Nothing to do here + //} + } + write(c); + } + } + // We are always writing all uint8_t to the buffer + return 1; +} + +size_t OLEDDisplay::write(const char* str) { + if (str == NULL) return 0; + size_t length = strlen(str); + for (size_t i = 0; i < length; i++) { + write(str[i]); + } + return length; +} + +#ifdef __MBED__ +int OLEDDisplay::_putc(int c) { + + if (!fontData) + return 1; + if (!logBufferSize) { + uint8_t textHeight = pgm_read_byte(fontData + HEIGHT_POS); + uint16_t lines = this->displayHeight / textHeight; + uint16_t chars = 2 * (this->displayWidth / textHeight); + + if (this->displayHeight % textHeight) + lines++; + if (this->displayWidth % textHeight) + chars++; + setLogBuffer(lines, chars); + } + + return this->write((uint8_t)c); +} +#endif + +// Private functions +void OLEDDisplay::setGeometry(OLEDDISPLAY_GEOMETRY g, uint16_t width, uint16_t height) { + this->geometry = g; + + switch (g) { + case GEOMETRY_128_64: + this->displayWidth = 128; + this->displayHeight = 64; + break; + case GEOMETRY_128_32: + this->displayWidth = 128; + this->displayHeight = 32; + break; + case GEOMETRY_64_48: + this->displayWidth = 64; + this->displayHeight = 48; + break; + case GEOMETRY_64_32: + this->displayWidth = 64; + this->displayHeight = 32; + break; + case GEOMETRY_RAWMODE: + this->displayWidth = width > 0 ? width : 128; + this->displayHeight = height > 0 ? height : 64; + break; + } + this->displayBufferSize = displayWidth * displayHeight / 8; +} + +void OLEDDisplay::sendInitCommands(void) { + if (geometry == GEOMETRY_RAWMODE) + return; + sendCommand(DISPLAYOFF); + sendCommand(SETDISPLAYCLOCKDIV); + sendCommand(0xF0); // Increase speed of the display max ~96Hz + sendCommand(SETMULTIPLEX); + sendCommand(this->height() - 1); + sendCommand(SETDISPLAYOFFSET); + sendCommand(0x00); + if(geometry == GEOMETRY_64_32) + sendCommand(0x00); + else + sendCommand(SETSTARTLINE); + sendCommand(CHARGEPUMP); + sendCommand(0x14); + sendCommand(MEMORYMODE); + sendCommand(0x00); + sendCommand(SEGREMAP); + sendCommand(COMSCANINC); + sendCommand(SETCOMPINS); + + if (geometry == GEOMETRY_128_64 || geometry == GEOMETRY_64_48 || geometry == GEOMETRY_64_32) { + sendCommand(0x12); + } else if (geometry == GEOMETRY_128_32) { + sendCommand(0x02); + } + + sendCommand(SETCONTRAST); + + if (geometry == GEOMETRY_128_64 || geometry == GEOMETRY_64_48 || geometry == GEOMETRY_64_32) { + sendCommand(0xCF); + } else if (geometry == GEOMETRY_128_32) { + sendCommand(0x8F); + } + + sendCommand(SETPRECHARGE); + sendCommand(0xF1); + sendCommand(SETVCOMDETECT); //0xDB, (additionally needed to lower the contrast) + sendCommand(0x40); //0x40 default, to lower the contrast, put 0 + sendCommand(DISPLAYALLON_RESUME); + sendCommand(NORMALDISPLAY); + sendCommand(0x2e); // stop scroll + sendCommand(DISPLAYON); +} + +void OLEDDisplay::drawInternal(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const uint8_t *data, uint16_t offset, uint16_t bytesInData) { + if (width < 0 || height < 0) return; + if (yMove + height < 0 || yMove > this->height()) return; + if (xMove + width < 0 || xMove > this->width()) return; + + uint8_t rasterHeight = 1 + ((height - 1) >> 3); // fast ceil(height / 8.0) + int8_t yOffset = yMove & 7; + + bytesInData = bytesInData == 0 ? width * rasterHeight : bytesInData; + + int16_t initYMove = yMove; + int8_t initYOffset = yOffset; + + + for (uint16_t i = 0; i < bytesInData; i++) { + + // Reset if next horizontal drawing phase is started. + if ( i % rasterHeight == 0) { + yMove = initYMove; + yOffset = initYOffset; + } + + uint8_t currentByte = pgm_read_byte(data + offset + i); + + int16_t xPos = xMove + (i / rasterHeight); + int16_t yPos = ((yMove >> 3) + (i % rasterHeight)) * this->width(); + +// int16_t yScreenPos = yMove + yOffset; + int16_t dataPos = xPos + yPos; + + if (dataPos >= 0 && dataPos < displayBufferSize && + xPos >= 0 && xPos < this->width() ) { + + if (yOffset >= 0) { + switch (this->color) { + case WHITE: buffer[dataPos] |= currentByte << yOffset; break; + case BLACK: buffer[dataPos] &= ~(currentByte << yOffset); break; + case INVERSE: buffer[dataPos] ^= currentByte << yOffset; break; + } + + if (dataPos < (displayBufferSize - this->width())) { + switch (this->color) { + case WHITE: buffer[dataPos + this->width()] |= currentByte >> (8 - yOffset); break; + case BLACK: buffer[dataPos + this->width()] &= ~(currentByte >> (8 - yOffset)); break; + case INVERSE: buffer[dataPos + this->width()] ^= currentByte >> (8 - yOffset); break; + } + } + } else { + // Make new offset position + yOffset = -yOffset; + + switch (this->color) { + case WHITE: buffer[dataPos] |= currentByte >> yOffset; break; + case BLACK: buffer[dataPos] &= ~(currentByte >> yOffset); break; + case INVERSE: buffer[dataPos] ^= currentByte >> yOffset; break; + } + + // Prepare for next iteration by moving one block up + yMove -= 8; + + // and setting the new yOffset + yOffset = 8 - yOffset; + } +#ifndef __MBED__ + yield(); +#endif + } + } +} + +// You need to free the char! +char* OLEDDisplay::utf8ascii(String str) { + uint16_t k = 0; + uint16_t length = str.length() + 1; + + // Copy the string into a char array + char* s = (char*) malloc(length * sizeof(char)); + if(!s) { + DEBUG_OLEDDISPLAY("[OLEDDISPLAY][utf8ascii] Can't allocate another char array. Drop support for UTF-8.\n"); + return (char*) str.c_str(); + } + str.toCharArray(s, length); + + length--; + + for (uint16_t i=0; i < length; i++) { + char c = (this->fontTableLookupFunction)(s[i]); + if (c!=0) { + s[k++]=c; + } + } + + s[k]=0; + + // This will leak 's' be sure to free it in the calling function. + return s; +} + +void OLEDDisplay::setFontTableLookupFunction(FontTableLookupFunction function) { + this->fontTableLookupFunction = function; +} + + +char DefaultFontTableLookup(const uint8_t ch) { + // UTF-8 to font table index converter + // Code form http://playground.arduino.cc/Main/Utf8ascii + static uint8_t LASTCHAR; + + if (ch < 128) { // Standard ASCII-set 0..0x7F handling + LASTCHAR = 0; + return ch; + } + + uint8_t last = LASTCHAR; // get last char + LASTCHAR = ch; + + switch (last) { // conversion depnding on first UTF8-character + case 0xC2: return (uint8_t) ch; + case 0xC3: return (uint8_t) (ch | 0xC0); + case 0x82: if (ch == 0xAC) return (uint8_t) 0x80; // special case Euro-symbol + } + + return (uint8_t) 0; // otherwise: return zero, if character has to be ignored +} diff --git a/backup/OLEDDisplay.h b/backup/OLEDDisplay.h new file mode 100644 index 0000000..76687b5 --- /dev/null +++ b/backup/OLEDDisplay.h @@ -0,0 +1,343 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn + * Copyright (c) 2018 by Fabrice Weinberg + * Copyright (c) 2019 by Helmut Tschemernjak - www.radioshuttle.de + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ThingPulse invests considerable time and money to develop these open source libraries. + * Please support us by buying our products (and not the clones) from + * https://thingpulse.com + * + */ + +#ifndef OLEDDISPLAY_h +#define OLEDDISPLAY_h + +#include +#include "OLEDDisplayFonts.h" + +//#define DEBUG_OLEDDISPLAY(...) Serial.printf( __VA_ARGS__ ) +//#define DEBUG_OLEDDISPLAY(...) dprintf("%s", __VA_ARGS__ ) + +#ifndef DEBUG_OLEDDISPLAY +#define DEBUG_OLEDDISPLAY(...) +#endif + +// Use DOUBLE BUFFERING by default +#ifndef OLEDDISPLAY_REDUCE_MEMORY +#define OLEDDISPLAY_DOUBLE_BUFFER +#endif + +// Header Values +#define JUMPTABLE_BYTES 4 + +#define JUMPTABLE_LSB 1 +#define JUMPTABLE_SIZE 2 +#define JUMPTABLE_WIDTH 3 +#define JUMPTABLE_START 4 + +#define WIDTH_POS 0 +#define HEIGHT_POS 1 +#define FIRST_CHAR_POS 2 +#define CHAR_NUM_POS 3 + + +// Display commands +#define CHARGEPUMP 0x8D +#define COLUMNADDR 0x21 +#define COMSCANDEC 0xC8 +#define COMSCANINC 0xC0 +#define DISPLAYALLON 0xA5 +#define DISPLAYALLON_RESUME 0xA4 +#define DISPLAYOFF 0xAE +#define DISPLAYON 0xAF +#define EXTERNALVCC 0x1 +#define INVERTDISPLAY 0xA7 +#define MEMORYMODE 0x20 +#define NORMALDISPLAY 0xA6 +#define PAGEADDR 0x22 +#define SEGREMAP 0xA0 +#define SETCOMPINS 0xDA +#define SETCONTRAST 0x81 +#define SETDISPLAYCLOCKDIV 0xD5 +#define SETDISPLAYOFFSET 0xD3 +#define SETHIGHCOLUMN 0x10 +#define SETLOWCOLUMN 0x00 +#define SETMULTIPLEX 0xA8 +#define SETPRECHARGE 0xD9 +#define SETSEGMENTREMAP 0xA1 +#define SETSTARTLINE 0x40 +#define SETVCOMDETECT 0xDB +#define SWITCHCAPVCC 0x2 + +#ifndef _swap_int16_t +#define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; } +#endif + +enum OLEDDISPLAY_COLOR { + BLACK = 0, + WHITE = 1, + INVERSE = 2 +}; + +enum OLEDDISPLAY_TEXT_ALIGNMENT { + TEXT_ALIGN_LEFT = 0, + TEXT_ALIGN_RIGHT = 1, + TEXT_ALIGN_CENTER = 2, + TEXT_ALIGN_CENTER_BOTH = 3 +}; + + +enum OLEDDISPLAY_GEOMETRY { + GEOMETRY_128_64 = 0, + GEOMETRY_128_32 = 1, + GEOMETRY_64_48 = 2, + GEOMETRY_64_32 = 3, + GEOMETRY_RAWMODE = 4 +}; + +enum HW_I2C { + I2C_ONE, + I2C_TWO +}; + +typedef char (*FontTableLookupFunction)(const uint8_t ch); +char DefaultFontTableLookup(const uint8_t ch); + +class OLEDDisplay : public Print { + + public: + OLEDDisplay(); + virtual ~OLEDDisplay(); + + uint16_t width(void) const { return displayWidth; }; + uint16_t height(void) const { return displayHeight; }; + + // Use this to resume after a deep sleep without resetting the display (what init() would do). + // Returns true if connection to the display was established and the buffer allocated, false otherwise. + bool allocateBuffer(); + + // Allocates the buffer and initializes the driver & display. Resets the display! + // Returns false if buffer allocation failed, true otherwise. + bool init(); + + // Free the memory used by the display + void end(); + + // Cycle through the initialization + void resetDisplay(void); + + /* Drawing functions */ + // Sets the color of all pixel operations + void setColor(OLEDDISPLAY_COLOR color); + + // Returns the current color. + OLEDDISPLAY_COLOR getColor(); + + // Draw a pixel at given position + void setPixel(int16_t x, int16_t y); + + // Draw a pixel at given position and color + void setPixelColor(int16_t x, int16_t y, OLEDDISPLAY_COLOR color); + + // Clear a pixel at given position FIXME: INVERSE is untested with this function + void clearPixel(int16_t x, int16_t y); + + // Draw a line from position 0 to position 1 + void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1); + + // Draw the border of a rectangle at the given location + void drawRect(int16_t x, int16_t y, int16_t width, int16_t height); + + // Fill the rectangle + void fillRect(int16_t x, int16_t y, int16_t width, int16_t height); + + // Draw the border of a circle + void drawCircle(int16_t x, int16_t y, int16_t radius); + + // Draw all Quadrants specified in the quads bit mask + void drawCircleQuads(int16_t x0, int16_t y0, int16_t radius, uint8_t quads); + + // Fill circle + void fillCircle(int16_t x, int16_t y, int16_t radius); + + // Draw a line horizontally + void drawHorizontalLine(int16_t x, int16_t y, int16_t length); + + // Draw a line vertically + void drawVerticalLine(int16_t x, int16_t y, int16_t length); + + // Draws a rounded progress bar with the outer dimensions given by width and height. Progress is + // a unsigned byte value between 0 and 100 + void drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t progress); + + // Draw a bitmap in the internal image format + void drawFastImage(int16_t x, int16_t y, int16_t width, int16_t height, const uint8_t *image); + + // Draw a XBM + void drawXbm(int16_t x, int16_t y, int16_t width, int16_t height, const uint8_t *xbm); + + // Draw icon 16x16 xbm format + void drawIco16x16(int16_t x, int16_t y, const char *ico, bool inverse = false); + + /* Text functions */ + + // Draws a string at the given location + void drawString(int16_t x, int16_t y, String text); + + // Draws a formatted string (like printf) at the given location + void drawStringf(int16_t x, int16_t y, char* buffer, String format, ... ); + + // Draws a String with a maximum width at the given location. + // If the given String is wider than the specified width + // The text will be wrapped to the next line at a space or dash + void drawStringMaxWidth(int16_t x, int16_t y, uint16_t maxLineWidth, String text); + + // Returns the width of the const char* with the current + // font settings + uint16_t getStringWidth(const char* text, uint16_t length); + + // Convencience method for the const char version + uint16_t getStringWidth(String text); + + // Specifies relative to which anchor point + // the text is rendered. Available constants: + // TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER_BOTH + void setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT textAlignment); + + // Sets the current font. Available default fonts + // ArialMT_Plain_10, ArialMT_Plain_16, ArialMT_Plain_24 + void setFont(const uint8_t *fontData); + + // Set the function that will convert utf-8 to font table index + void setFontTableLookupFunction(FontTableLookupFunction function); + + /* Display functions */ + + // Turn the display on + void displayOn(void); + + // Turn the display offs + void displayOff(void); + + // Inverted display mode + void invertDisplay(void); + + // Normal display mode + void normalDisplay(void); + + // Set display contrast + // really low brightness & contrast: contrast = 10, precharge = 5, comdetect = 0 + // normal brightness & contrast: contrast = 100 + void setContrast(uint8_t contrast, uint8_t precharge = 241, uint8_t comdetect = 64); + + // Convenience method to access + void setBrightness(uint8_t); + + // Reset display rotation or mirroring + void resetOrientation(); + + // Turn the display upside down + void flipScreenVertically(); + + // Mirror the display (to be used in a mirror or as a projector) + void mirrorScreen(); + + // Write the buffer to the display memory + virtual void display(void) = 0; + + // Clear the local pixel buffer + void clear(void); + + // Log buffer implementation + + // This will define the lines and characters you can + // print to the screen. When you exeed the buffer size (lines * chars) + // the output may be truncated due to the size constraint. + bool setLogBuffer(uint16_t lines, uint16_t chars); + + // Draw the log buffer at position (x, y) + void drawLogBuffer(uint16_t x, uint16_t y); + + // Get screen geometry + uint16_t getWidth(void); + uint16_t getHeight(void); + + // Implement needed function to be compatible with Print class + size_t write(uint8_t c); + size_t write(const char* s); + + + uint8_t *buffer; + + #ifdef OLEDDISPLAY_DOUBLE_BUFFER + uint8_t *buffer_back; + #endif + + protected: + + OLEDDISPLAY_GEOMETRY geometry; + + uint16_t displayWidth; + uint16_t displayHeight; + uint16_t displayBufferSize; + + // Set the correct height, width and buffer for the geometry + void setGeometry(OLEDDISPLAY_GEOMETRY g, uint16_t width = 0, uint16_t height = 0); + + OLEDDISPLAY_TEXT_ALIGNMENT textAlignment; + OLEDDISPLAY_COLOR color; + + const uint8_t *fontData; + + // State values for logBuffer + uint16_t logBufferSize; + uint16_t logBufferFilled; + uint16_t logBufferLine; + uint16_t logBufferMaxLines; + char *logBuffer; + + + // the header size of the buffer used, e.g. for the SPI command header + int BufferOffset; + virtual int getBufferOffset(void) = 0; + + // Send a command to the display (low level function) + virtual void sendCommand(uint8_t com) {(void)com;}; + + // Connect to the display + virtual bool connect() { return false; }; + + // Send all the init commands + void sendInitCommands(); + + // converts utf8 characters to extended ascii + char* utf8ascii(String s); + + void drawInternal(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const uint8_t *data, uint16_t offset, uint16_t bytesInData); + + void drawStringInternal(int16_t xMove, int16_t yMove, char* text, uint16_t textLength, uint16_t textWidth); + + FontTableLookupFunction fontTableLookupFunction; +}; + +#endif diff --git a/lib/Display/OLEDDisplayFonts.h b/backup/OLEDDisplayFonts.h similarity index 100% rename from lib/Display/OLEDDisplayFonts.h rename to backup/OLEDDisplayFonts.h diff --git a/lib/Display/OLEDDisplayUi.cpp b/backup/OLEDDisplayUi.cpp similarity index 100% rename from lib/Display/OLEDDisplayUi.cpp rename to backup/OLEDDisplayUi.cpp diff --git a/lib/Display/OLEDDisplayUi.h b/backup/OLEDDisplayUi.h similarity index 100% rename from lib/Display/OLEDDisplayUi.h rename to backup/OLEDDisplayUi.h diff --git a/backup/SSD1306.h b/backup/SSD1306.h new file mode 100644 index 0000000..923faef --- /dev/null +++ b/backup/SSD1306.h @@ -0,0 +1,195 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn + * Copyright (c) 2018 by Fabrice Weinberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ThingPulse invests considerable time and money to develop these open source libraries. + * Please support us by buying our products (and not the clones) from + * https://thingpulse.com + * + */ + +#ifndef SSD1306_h +#define SSD1306_h + +#include "OLEDDisplay.h" +#include +#include + +//-------------------------------------- + +class SSD1306Wire : public OLEDDisplay { + private: + uint8_t _address; + int _sda; + int _scl; + bool _doI2cAutoInit = false; + TwoWire* _wire = NULL; + int _frequency; + + public: + + /** + * Create and initialize the Display using Wire library + * + * Beware for retro-compatibility default values are provided for all parameters see below. + * Please note that if you don't wan't SD1306Wire to initialize and change frequency speed ot need to + * ensure -1 value are specified for all 3 parameters. This can be usefull to control TwoWire with multiple + * device on the same bus. + * + * @param _address I2C Display address + * @param _sda I2C SDA pin number, default to -1 to skip Wire begin call + * @param _scl I2C SCL pin number, default to -1 (only SDA = -1 is considered to skip Wire begin call) + * @param g display geometry dafault to generic GEOMETRY_128_64, see OLEDDISPLAY_GEOMETRY definition for other options + * @param _i2cBus on ESP32 with 2 I2C HW buses, I2C_ONE for 1st Bus, I2C_TWO fot 2nd bus, default I2C_ONE + * @param _frequency for Frequency by default Let's use ~700khz if ESP8266 is in 160Mhz mode, this will be limited to ~400khz if the ESP8266 in 80Mhz mode + */ + explicit SSD1306Wire(uint8_t _address, int _sda = -1, int _scl = -1, OLEDDISPLAY_GEOMETRY g = GEOMETRY_128_64, HW_I2C _i2cBus = I2C_ONE, int _frequency = 700000) { + setGeometry(g); + + this->_address = _address; + this->_sda = _sda; + this->_scl = _scl; + this->_wire = (_i2cBus==I2C_ONE) ? &Wire : &Wire1; + this->_frequency = _frequency; + } + + bool connect() override { + // On ESP32 arduino, -1 means 'don't change pins', someone else has called begin for us. + if(this->_sda != -1) + _wire->begin(this->_sda, this->_scl); + // Let's use ~700khz if ESP8266 is in 160Mhz mode + // this will be limited to ~400khz if the ESP8266 in 80Mhz mode. + if(this->_frequency != -1) + _wire->setClock(this->_frequency); + return true; + } + + void display(void) override { + initI2cIfNeccesary(); + const int x_offset = (128 - this->width()) / 2; + #ifdef OLEDDISPLAY_DOUBLE_BUFFER + uint8_t minBoundY = UINT8_MAX; + uint8_t maxBoundY = 0; + + uint8_t minBoundX = UINT8_MAX; + uint8_t maxBoundX = 0; + uint8_t x, y; + + // Calculate the Y bounding box of changes + // and copy buffer[pos] to buffer_back[pos]; + for (y = 0; y < (this->height() / 8); y++) { + for (x = 0; x < this->width(); x++) { + uint16_t pos = x + y * this->width(); + if (buffer[pos] != buffer_back[pos]) { + minBoundY = std::min(minBoundY, y); + maxBoundY = std::max(maxBoundY, y); + minBoundX = std::min(minBoundX, x); + maxBoundX = std::max(maxBoundX, x); + } + buffer_back[pos] = buffer[pos]; + } + yield(); + } + + // If the minBoundY wasn't updated + // we can savely assume that buffer_back[pos] == buffer[pos] + // holdes true for all values of pos + + if (minBoundY == UINT8_MAX) return; + + sendCommand(COLUMNADDR); + sendCommand(x_offset + minBoundX); + sendCommand(x_offset + maxBoundX); + + sendCommand(PAGEADDR); + sendCommand(minBoundY); + sendCommand(maxBoundY); + + byte k = 0; + for (y = minBoundY; y <= maxBoundY; y++) { + for (x = minBoundX; x <= maxBoundX; x++) { + if (k == 0) { + _wire->beginTransmission(_address); + _wire->write(0x40); + } + + _wire->write(buffer[x + y * this->width()]); + k++; + if (k == 16) { + _wire->endTransmission(); + k = 0; + } + } + yield(); + } + + if (k != 0) { + _wire->endTransmission(); + } + #else + + sendCommand(COLUMNADDR); + sendCommand(x_offset); + sendCommand(x_offset + (this->width() - 1)); + + sendCommand(PAGEADDR); + sendCommand(0x0); + + for (uint16_t i=0; i < displayBufferSize; i++) { + _wire->beginTransmission(this->_address); + _wire->write(0x40); + for (uint8_t x = 0; x < 16; x++) { + _wire->write(buffer[i]); + i++; + } + i--; + _wire->endTransmission(); + } + #endif + } + + void setI2cAutoInit(bool doI2cAutoInit) { + _doI2cAutoInit = doI2cAutoInit; + } + + private: + int getBufferOffset(void) override { + return 0; + } + inline void sendCommand(uint8_t command) override __attribute__((always_inline)) { + initI2cIfNeccesary(); + _wire->beginTransmission(_address); + _wire->write(0x80); + _wire->write(command); + _wire->endTransmission(); + } + + void initI2cIfNeccesary() { + if (_doI2cAutoInit) { + _wire->begin(this->_sda, this->_scl); + } + } + +}; + +#endif diff --git a/lib/Display/Bitmap.cpp b/lib/Display/Bitmap.cpp new file mode 100644 index 0000000..b8374b5 --- /dev/null +++ b/lib/Display/Bitmap.cpp @@ -0,0 +1,401 @@ +#include "Bitmap.h" +#include "OLEDDisplay.h" +#include "FontConfig.h" +//#include "OLEDDisplayFonts.h" + +Bitmap::Bitmap(uint width, uint height) + : _width(width), _height(height), _buffer(0) +{ + allocateBuffer(); +} + +Bitmap::Bitmap(OLEDDisplay * display) + : _width(display->getWidth()), _height(display->getHeight()), _buffer(0) +{ + allocateBuffer(); +} + +Bitmap::~Bitmap() +{ + if(_buffer != 0) + { + delete _buffer; + } +} + +uint Bitmap::getWidth() const +{ + return _width; +} + +uint Bitmap::getHeight() const +{ + return _height; +} + +void Bitmap::setPixel(int x, int y) +{ + if(x >= 0 && x < _width && y >= 0 && y < _height) + { + _buffer[x + (y / 8) * _width] |= (1 << (y % 8)); + } +} + +void Bitmap::clearPixel(int x, int y) +{ + if(x >= 0 && x < _width && y >= 0 && y < _height) + { + _buffer[x + (y / 8) * _width] &= ~(1 << (y % 8)); + } +} + +bool Bitmap::getPixel(int x, int y) const +{ + if(x >= 0 && x < _width && y >= 0 && y < _height) + { + return _buffer[x + (y / 8) * _width] & (1 << (y % 8)); + } + return false; +} + +void Bitmap::clear() +{ + memset(_buffer, 0, _width * _height / 8); +} + +void Bitmap::drawLine(int x0, int y0, int x1, int y1) +{ + int dx = abs(x1 - x0); + int dy = abs(y1 - y0); + int sx = x0 < x1 ? 1 : -1; + int sy = y0 < y1 ? 1 : -1; + int err = (dx > dy ? dx : -dy) / 2; + int e2; + + while(true) + { + setPixel(x0, y0); + if(x0 == x1 && y0 == y1) + break; + + e2 = err; + if(e2 > -dx) + { + err -= dy; + x0 += sx; + } + if(e2 < dy) + { + err += dx; + y0 += sy; + } + } +} + +void Bitmap::drawHorizontalLine(int x, int y, int length) +{ + if(y < 0 || y >= _height) + { + return; + } + + for(int i = 0; i < length; i++) + { + setPixel(x + i, y); + } +} + +void Bitmap::drawVerticalLine(int x, int y, int length) +{ + if (x < 0 || x >= _width) + { + return; + } + + for(int i = 0; i < length; i++) + { + setPixel(x, y + i); + } +} + +void Bitmap::drawRect(int x, int y, int width, int height) +{ + drawHorizontalLine(x, y, width); + drawVerticalLine(x, y, height); + drawVerticalLine(x + width - 1, y, height); + drawHorizontalLine(x, y + height - 1, width); +} + +void Bitmap::fillRect(int x, int y, int width, int height) +{ + for (int i = 0; i < width; i++) + { + drawVerticalLine(x + i, y, height); + } +} + +void Bitmap::drawCircle(int x0, int y0, int radius) +{ + int x = 0; + int y = radius; + int dp = 1 - radius; + + do + { + if (dp < 0) + { + dp = dp + (x++) * 2 + 3; + } + else + { + dp = dp + (x++) * 2 - (y--) * 2 + 5; + } + + setPixel(x0 + x, y0 + y); //For the 8 octants + setPixel(x0 - x, y0 + y); + setPixel(x0 + x, y0 - y); + setPixel(x0 - x, y0 - y); + setPixel(x0 + y, y0 + x); + setPixel(x0 - y, y0 + x); + setPixel(x0 + y, y0 - x); + setPixel(x0 - y, y0 - x); + } + while (x < y); + + setPixel(x0 + radius, y0); + setPixel(x0, y0 + radius); + setPixel(x0 - radius, y0); + setPixel(x0, y0 - radius); +} + +void Bitmap::fillCircle(int x0, int y0, int radius) +{ + int x = 0; + int y = radius; + int dp = 1 - radius; + + do + { + if (dp < 0) + { + dp = dp + (x++) * 2 + 3; + } + else + { + dp = dp + (x++) * 2 - (y--) * 2 + 5; + } + + drawHorizontalLine(x0 - x, y0 - y, 2 * x); + drawHorizontalLine(x0 - x, y0 + y, 2 * x); + drawHorizontalLine(x0 - y, y0 - x, 2 * y); + drawHorizontalLine(x0 - y, y0 + x, 2 * y); + } + while (x < y); + + drawHorizontalLine(x0 - radius, y0, 2 * radius); +} + +void Bitmap::drawCircleQuads(int x0, int y0, int radius, int quads) +{ + int x = 0; + int y = radius; + int dp = 1 - radius; + + while (x < y) + { + if (dp < 0) + { + dp = dp + (x++) * 2 + 3; + } + else + { + dp = dp + (x++) * 2 - (y--) * 2 + 5; + } + + if (quads & 0x1) + { + setPixel(x0 + x, y0 - y); + setPixel(x0 + y, y0 - x); + } + if (quads & 0x2) + { + setPixel(x0 - y, y0 - x); + setPixel(x0 - x, y0 - y); + } + if (quads & 0x4) + { + setPixel(x0 - y, y0 + x); + setPixel(x0 - x, y0 + y); + } + if (quads & 0x8) + { + setPixel(x0 + x, y0 + y); + setPixel(x0 + y, y0 + x); + } + } + if (quads & 0x1 && quads & 0x8) + { + setPixel(x0 + radius, y0); + } + if (quads & 0x4 && quads & 0x8) + { + setPixel(x0, y0 + radius); + } + if (quads & 0x2 && quads & 0x4) + { + setPixel(x0 - radius, y0); + } + if (quads & 0x1 && quads & 0x2) + { + setPixel(x0, y0 - radius); + } +} + +void Bitmap::drawProgressBar(int x, int y, int width, int height, int progress) +{ + int radius = height / 2; + int xRadius = x + radius; + int yRadius = y + radius; + int doubleRadius = 2 * radius; + int innerRadius = radius - 2; + + drawCircleQuads(xRadius, yRadius, radius, 0b00000110); + drawHorizontalLine(xRadius, y, width - doubleRadius + 1); + drawHorizontalLine(xRadius, y + height, width - doubleRadius + 1); + drawCircleQuads(x + width - radius, yRadius, radius, 0b00001001); + + uint16_t maxProgressWidth = (width - doubleRadius + 1) * progress / 100; + + fillCircle(xRadius, yRadius, innerRadius); + fillRect(xRadius + 1, y + 2, maxProgressWidth, height - 3); + fillCircle(xRadius + maxProgressWidth, yRadius, innerRadius); +} + +int Bitmap::drawChar(int x, int y, char c) +{ + fontDesc_t const * font = getSystemFont(); + + if(c == ' ') + { + return x + font->widthInPixel * 4 / 10; + } + + unsigned char cu = (unsigned char)c; + if(cu < font->firstChar || cu > font->lastChar) + { + cu = '?'; + } + + int firstPixelBitPos = 0; + for(int i = 0; i < (cu - font->firstChar); i++) + { + firstPixelBitPos = firstPixelBitPos + font->pData[i]; + } + firstPixelBitPos = firstPixelBitPos * font->heightInPixel; + + unsigned char const * pDataStart = &(font->pData[font->lastChar - font->firstChar + 1]); + const int top = y; + const int widthInPixel = font->pData[cu - font->firstChar]; + for(int i = 0; i < widthInPixel * font->heightInPixel; i++ ) + { + int bytePos = firstPixelBitPos / 8; + int bitPos = firstPixelBitPos % 8; + + if(pDataStart[bytePos] & ( 1 << bitPos)) + { + setPixel(x, y); + } + else + { + clearPixel(x, y); + } + + firstPixelBitPos++; + y++; + if(y == top + font->heightInPixel) + { + y = top; + x++; + } + } + + return x + FONT_CHAR_SPACING; +} + +int Bitmap::drawString(int x, int y, String text) +{ + int next_x = x; + for(int i = 0; i < text.length(); i++) + { + next_x = drawChar(next_x, y, text[i]); + } + return next_x; +} + +void Bitmap::drawStringf(int x, int y, char * buffer, String format, ... ) +{ + va_list myargs; + va_start(myargs, format); + vsprintf(buffer, format.c_str(), myargs); + va_end(myargs); + drawString(x, y, buffer); +} + +int Bitmap::drawStringLF(int x, int y, String text) +{ + fontDesc_t const * font = getSystemFont(); + int next_x = x; + for(int i = 0; i < text.length(); i++) + { + if(next_x + font->widthInPixel > _width) + { + next_x = 0; + y += font->heightInPixel; + } + next_x = drawChar(next_x, y, text[i]); + } + return next_x; +} + +void Bitmap::drawStringLFf(int x, int y, char * buffer, String format, ... ) +{ + va_list myargs; + va_start(myargs, format); + vsprintf(buffer, format.c_str(), myargs); + va_end(myargs); + drawStringLF(x, y, buffer); +} + +/*void Bitmap::drawBitmap(int x, int y, const Bitmap & bitmap) +{ + if(_width < x + bitmap.getWidth() || _height < y + bitmap.getHeight()) + { + return; + } + + for(int _x = 0; _x < bitmap.getWidth(); _x++) + { + for(int _y = 0; _y < bitmap.getHeight(); _y++) + { + if(bitmap.getPixel(_x, _y)) + { + // _buffer[x + (y / 8) * _width] |= (1 << (y % 8)); + // return _buffer[x + (y / 8) * _width] & (1 << (y % 8)); + Serial.print(_x); + Serial.print(" "); + Serial.println(_y); + setPixel(x + _x, y + _y); + } + else + { + clearPixel(x + _x, y + _y); + } + } + } +}*/ + +void Bitmap::allocateBuffer() +{ + _buffer = new uint8_t[_width * _height / 8]; + clear(); +} diff --git a/lib/Display/Bitmap.h b/lib/Display/Bitmap.h new file mode 100644 index 0000000..962aa05 --- /dev/null +++ b/lib/Display/Bitmap.h @@ -0,0 +1,56 @@ +#ifndef BITMAP_H_ +#define BITMAP_H_ + +#include +#include + +class OLEDDisplay; + +class Bitmap +{ +public: + Bitmap(uint width, uint height); + Bitmap(OLEDDisplay * display); + virtual ~Bitmap(); + + uint getWidth() const; + uint getHeight() const; + + void setPixel(int x, int y); + void clearPixel(int x, int y); + bool getPixel(int x, int y) const; + void clear(); + + void drawLine(int x0, int y0, int x1, int y1); + void drawHorizontalLine(int x, int y, int length); + void drawVerticalLine(int x, int y, int length); + + void drawRect(int x, int y, int width, int height); + void fillRect(int x, int y, int width, int height); + + void drawCircle(int x0, int y0, int radius); + void fillCircle(int x0, int y0, int radius); + void drawCircleQuads(int x0, int y0, int radius, int quads); + + void drawProgressBar(int x, int y, int width, int height, int progress); + + int drawChar(int x, int y, char c); + int drawString(int x, int y, String text); + void drawStringf(int x, int y, char * buffer, String format, ... ); + int drawStringLF(int x, int y, String text); + void drawStringLFf(int x, int y, char * buffer, String format, ... ); + + //void drawBitmap(int x, int y, const Bitmap & bitmap); + +private: + const uint _width; + const uint _height; + + uint8_t * _buffer; + + void allocateBuffer(); + + friend class SSD1306; +}; + +#endif diff --git a/lib/Display/Display.cpp b/lib/Display/Display.cpp index 86a4fd0..65ad3dd 100644 --- a/lib/Display/Display.cpp +++ b/lib/Display/Display.cpp @@ -1,46 +1,85 @@ #include #include "Display.h" +#include Display::Display() + : _disp(0), _statusFrame(0), _nextFrameTime(0) { } void Display::setup(std::shared_ptr boardConfig) { - _disp = std::shared_ptr(new SSD1306Wire(boardConfig->OledAddr, boardConfig->OledSda, boardConfig->OledScl)); - _ui = std::shared_ptr(new OLEDDisplayUi(_disp.get())); - - static std::array frames; - frames[0] = drawStatusPage; - frames[1] = drawStatusPage; - _ui->setFrames(frames.data(), frames.size()); - - _ui->setTargetFPS(15); - _ui->setFrameAnimation(SLIDE_LEFT); - _ui->init(); - _disp->flipScreenVertically(); -} - -void Display::setTaskStatus(const String & task, const String & status) -{ - _taskStatus.insert(std::pair(task, status)); + if(boardConfig->OledReset != 0) + { + pinMode(boardConfig->OledReset, OUTPUT); + digitalWrite(boardConfig->OledReset, HIGH); + delay(1); + digitalWrite(boardConfig->OledReset, LOW); + delay(10); + digitalWrite(boardConfig->OledReset, HIGH); + } + Wire.begin(boardConfig->OledSda, boardConfig->OledScl); + _disp = std::shared_ptr(new SSD1306(&Wire, boardConfig->OledAddr)); + + Bitmap bitmap(_disp->getWidth(), _disp->getHeight()); + _disp->display(&bitmap); } void Display::update() { - _ui->update(); + if(_statusFrame->isPrio()) + { + Bitmap bitmap(_disp.get()); + _statusFrame->drawStatusPage(bitmap); + _disp->display(&bitmap); + return; + } + + if(_nextFrameTime > now()) + { + return; + } + + if(_frames.size() > 0) + { + std::shared_ptr frame = *_frames.begin(); + Bitmap bitmap(_disp.get()); + frame->drawStatusPage(bitmap); + _disp->display(&bitmap); + _frames.pop_front(); + _nextFrameTime = now() + 15; + } + else + { + Bitmap bitmap(_disp.get()); + _statusFrame->drawStatusPage(bitmap); + _disp->display(&bitmap); + } } -void Display::drawStatusPage(OLEDDisplay * display, OLEDDisplayUiState * state, int16_t x, int16_t y) +void Display::addFrame(std::shared_ptr frame) { - //logPrintlnD("blib"); - display->setTextAlignment(TEXT_ALIGN_LEFT); - display->setFont(ArialMT_Plain_10); - display->drawString(0 + x, 10 + y, "Arial 10"); - - display->setFont(ArialMT_Plain_16); - display->drawString(0 + x, 20 + y, "Arial 16"); - - display->setFont(ArialMT_Plain_24); - display->drawString(0 + x, 34 + y, "Arial 24"); + _frames.push_back(frame); +} + +void Display::setStatusFrame(std::shared_ptr frame) +{ + _statusFrame = frame; +} + +void Display::showSpashScreen(String firmwareTitle, String version) +{ + Bitmap bitmap(_disp.get()); + bitmap.drawString( 0, 10, firmwareTitle); + bitmap.drawString( 0, 20, version); + bitmap.drawString( 0, 35, "by Peter Buchegger"); + bitmap.drawString(30, 45, "OE5BPA"); + _disp->display(&bitmap); +} + + +void TextFrame::drawStatusPage(Bitmap & bitmap) +{ + bitmap.drawString(0, 0, _header); + bitmap.drawStringLF(0, 10, _text); } diff --git a/lib/Display/Display.h b/lib/Display/Display.h index b0f3a11..a86fc8e 100644 --- a/lib/Display/Display.h +++ b/lib/Display/Display.h @@ -1,15 +1,25 @@ #ifndef DISPLAY_H_ #define DISPLAY_H_ -#include +#include #include #include #include #include +#include #include -#include #include +class StatusFrame; + +class DisplayFrame +{ +public: + DisplayFrame() {} + virtual ~DisplayFrame() {} + virtual void drawStatusPage(Bitmap & bitmap) = 0; +}; + class Display { public: @@ -22,22 +32,37 @@ public: ~Display() {} void setup(std::shared_ptr boardConfig); - - void setTaskStatus(const String & task, const String & status); - void update(); + void addFrame(std::shared_ptr frame); + + void setStatusFrame(std::shared_ptr frame); + + void showSpashScreen(String firmwareTitle, String version); + private: std::shared_ptr _disp; - std::shared_ptr _ui; - static void drawStatusPage(OLEDDisplay * display, OLEDDisplayUiState * state, int16_t x, int16_t y); + std::list> _frames; + std::shared_ptr _statusFrame; - std::map _taskStatus; + time_t _nextFrameTime; Display(); Display(const Display &); Display & operator = (const Display &); }; +class TextFrame : public DisplayFrame +{ +public: + TextFrame(String header, String text) : _header(header), _text(text) {} + virtual ~TextFrame() {} + void drawStatusPage(Bitmap & bitmap) override; + +private: + String _header; + String _text; +}; + #endif diff --git a/lib/Display/FontConfig.cpp b/lib/Display/FontConfig.cpp new file mode 100644 index 0000000..121b86b --- /dev/null +++ b/lib/Display/FontConfig.cpp @@ -0,0 +1,67 @@ +/*#include "Fonts/Amadeus_12.h" +#include "Fonts/Amadeus_20.h" +#include "Fonts/Amadeus_24.h" +#include "Fonts/Blue_12.h" +#include "Fonts/Blue_20.h" +#include "Fonts/Blue_24.h" +#include "Fonts/Burnstown_12.h" +#include "Fonts/Burnstown_20.h" +#include "Fonts/Burnstown_24.h" +#include "Fonts/Courier.h" +#include "Fonts/Courier_12.h" +#include "Fonts/Courier_20.h" +#include "Fonts/Courier_24.h" +#include "Fonts/Courier_40.h" +#include "Fonts/Cowboys_10.h" +#include "Fonts/Cowboys_12.h" +#include "Fonts/Cowboys_20.h" +#include "Fonts/Cowboys_24.h" +#include "Fonts/FixedSys_11.h" +#include "Fonts/Gabriola_12.h" +#include "Fonts/Gabriola_20.h" +#include "Fonts/Gabriola_24.h"*/ +#include "Fonts/HoloLens_12.h" +#include "Fonts/HoloLens_20.h" +/*#include "Fonts/Mickey_12.h" +#include "Fonts/Mickey_20.h" +#include "Fonts/Neuropol_12.h" +#include "Fonts/Neuropol_20.h" +#include "Fonts/Neuropol_24.h" +#include "Fonts/Open_12.h" +#include "Fonts/Open_20.h"*/ +#include "Fonts/Roboto_12.h" +/*#include "Fonts/Roboto_20.h" +#include "Fonts/Script_10.h" +#include "Fonts/Script_12.h" +#include "Fonts/Script_20.h" +#include "Fonts/Script_24.h" +#include "Fonts/Seaside_12.h" +#include "Fonts/Seaside_20.h" +#include "Fonts/Seaside_24.h" +#include "Fonts/Tahoma_10.h" +#include "Fonts/Tahoma_12.h" +#include "Fonts/Tahoma_20.h" +#include "Fonts/Tahoma_24.h"*/ +#include "Fonts/Terminal_8.h" +#include "Fonts/Terminal_11.h" +/*#include "Fonts/Times_12.h" +#include "Fonts/Times_20.h" +#include "Fonts/Times_24.h" +#include "Fonts/Trebuchet_10.h" +#include "Fonts/Trebuchet_12.h" +#include "Fonts/Trebuchet_20.h" +#include "Fonts/Trebuchet_24.h" +#include "Fonts/Verdana_10.h" +#include "Fonts/Verdana_12.h" +#include "Fonts/Verdana_20.h" +#include "Fonts/Verdana_24.h" +#include "Fonts/Waker_12.h" +#include "Fonts/Waker_20.h" +#include "Fonts/Waker_24.h"*/ + +#include "FontConfig.h" + +fontDesc_t const * getSystemFont() +{ + return &FONT; +} diff --git a/lib/Display/FontConfig.h b/lib/Display/FontConfig.h new file mode 100644 index 0000000..0008059 --- /dev/null +++ b/lib/Display/FontConfig.h @@ -0,0 +1,57 @@ +#ifndef FONT_CONFIG_H_ +#define FONT_CONFIG_H_ + +// make sure, the font is uncommented in fontConfig.c +// +// you do not need to worry about having too many fonts +// activated in fontConfig.c +// all fonts not referenced will be discarded by the linker +// + +// Note: since all of the fonts have been generated from TTF fonts +// we cannot guarantee a consistent character height. We get what we +// get when requesting a font height of 12 or 20. Some converted +// fonts are visually larger then others. +// You are invited to fix this by try and error in the conversion process. +// The idea is that 12 denotes the intended character height +// including "subscripts" (as in g, y, ...) +// Same for 20. +// Right now, 12 is some sort of small font, 20 is some sort of large font +// if this is not useful to you, then by all means convert your own fonts. +// +// Been there, done that. It is a pain in the ass. Good luck! (Seriously) + +// These fonts are good text fonts +// #define FONT Blue_12_Desc // elegant +// #define FONT Courier_12_Desc // der Klassiker, der immer geht +// #define FONT FixedSys_11_Desc // good allround font +// #define FONT Gabriola_12_Desc // schön, aber nicht besonders nützlich +// #define FONT Gabriola_20_Desc +//#define FONT HoloLens_12_Desc // kleine Schrift, gut zu lesen, elegant +//#define FONT HoloLens_20_Desc +// #define FONT Neuropol_12_Desc // modern, breite Buchstaben +//#define FONT Roboto_12_Desc // almost like Terminal, little bit more elegant +// #define FONT Open_12_Desc // kleine Schrift, gut lesbar, klassisch +// #define FONT Tahoma_10_Desc // gute allround Schrift, was fuers Grobe +#define FONT Terminal_8_Desc // if you need lots of space, still readable +//#define FONT Terminal_11_Desc // good allround font +// #define FONT Times_12_Desc // dazu braucht man nichts sagen, wirkt altbacken +// #define FONT Trebuchet_12_Desc // gute Schrift, wenn es etwas bold sein darf +// #define FONT Verdana_12_Desc // ausgewogen, gut lesbar, bolder als Trebuchet + +// These fonts are fancy fonts +// #define FONT Amadeus_12_Desc +// #define FONT Burnstown_12_Desc // rustikale Bretterschrift +// #define FONT Cowboys_10_Desc // ratatatata Bonanzaaaaa +// #define FONT Mickey_12_Desc // Nomen est omen in den Grossbuchstaben +// #define FONT Script_12_Desc // Schreibschrift +// #define FONT Seaside_12_Desc // Art D'eco +// #define FONT Waker_12_Desc // was fuer zb Halloween + +#define FONT_CHAR_SPACING 2 + +#include "Fonts/FontDesc.h" + +fontDesc_t const * getSystemFont(); + +#endif diff --git a/lib/Display/Fonts/FontDesc.h b/lib/Display/Fonts/FontDesc.h new file mode 100644 index 0000000..4e56b1e --- /dev/null +++ b/lib/Display/Fonts/FontDesc.h @@ -0,0 +1,18 @@ +#ifndef FONT_DESC_H +#define FONT_DESC_H + +#include + +struct fontDesc_t +{ + uint16_t totalSize; + uint8_t widthInPixel; + uint8_t heightInPixel; + uint8_t bitsPerPixel; + uint8_t firstChar; + uint8_t lastChar; + + unsigned char const * const pData; +}; + +#endif diff --git a/lib/Display/Fonts/HoloLens_12.h b/lib/Display/Fonts/HoloLens_12.h new file mode 100644 index 0000000..e82ec83 --- /dev/null +++ b/lib/Display/Fonts/HoloLens_12.h @@ -0,0 +1,284 @@ +/* + created with FontEditor written by H. Reddmann + HaReddmann at t-online dot de + + File Name : HoloLens_12.h + Date : 10.03.2019 + Font size in bytes : 0x0D64, 3428 + Font width : 13 + Font height : 17 + Font first char : 0x0B + Font last char : 0xFF + Font bits per pixel : 1 + Font is compressed : false + + The font data are defined as + + struct _FONT_ { + // common shared fields + uint16_t font_Size_in_Bytes_over_all_included_Size_it_self; + uint8_t font_Width_in_Pixel_for_fixed_drawing; + uint8_t font_Height_in_Pixel_for_all_Characters; + uint8_t font_Bits_per_Pixels; + // if MSB are set then font is a compressed font + uint8_t font_First_Char; + uint8_t font_Last_Char; + uint8_t font_Char_Widths[font_Last_Char - font_First_Char +1]; + // for each character the separate width in pixels, + // characters < 128 have an implicit virtual right empty row + // characters with font_Char_Widths[] == 0 are undefined + + // if compressed font then additional fields + uint8_t font_Byte_Padding; + // each Char in the table are aligned in size to this value + uint8_t font_RLE_Table[3]; + // Run Length Encoding Table for compression + uint8_t font_Char_Size_in_Bytes[font_Last_Char - font_First_Char +1]; + // for each char the size in (bytes / font_Byte_Padding) are stored, + // this get us the table to seek to the right beginning of each char + // in the font_data[]. + + // for compressed and uncompressed fonts + uint8_t font_data[]; + // bit field of all characters + } +*/ + +#include "FontDesc.h" + +#ifndef HoloLens_12_FONT_H +#define HoloLens_12_FONT_H + +#define HoloLens_12_WIDTH 13 +#define HoloLens_12_HEIGHT 17 + +static unsigned char const HoloLens_12_Bytes[] = { + 0x04, 0x0A, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x08, 0x06, 0x0A, 0x07, 0x02, 0x04, 0x04, 0x06, + 0x06, 0x03, 0x05, 0x02, 0x04, 0x06, 0x04, 0x06, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x02, + 0x03, 0x06, 0x06, 0x06, 0x06, 0x0B, 0x08, 0x07, 0x08, 0x08, 0x07, 0x07, 0x08, 0x08, 0x02, 0x06, + 0x08, 0x07, 0x0A, 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x08, 0x08, 0x08, 0x0C, 0x09, 0x08, 0x06, + 0x03, 0x04, 0x03, 0x06, 0x08, 0x03, 0x06, 0x06, 0x06, 0x06, 0x06, 0x04, 0x06, 0x06, 0x02, 0x03, + 0x06, 0x02, 0x0A, 0x06, 0x06, 0x06, 0x06, 0x04, 0x05, 0x04, 0x06, 0x06, 0x0A, 0x07, 0x06, 0x05, + 0x04, 0x02, 0x04, 0x07, 0x04, 0x07, 0x00, 0x04, 0x07, 0x06, 0x09, 0x06, 0x06, 0x04, 0x10, 0x08, + 0x04, 0x0C, 0x00, 0x07, 0x00, 0x00, 0x04, 0x04, 0x06, 0x06, 0x05, 0x07, 0x0D, 0x06, 0x0A, 0x06, + 0x04, 0x0B, 0x00, 0x06, 0x08, 0x00, 0x03, 0x07, 0x07, 0x07, 0x07, 0x03, 0x07, 0x04, 0x0A, 0x05, + 0x07, 0x07, 0x05, 0x0A, 0x07, 0x05, 0x07, 0x05, 0x05, 0x04, 0x08, 0x07, 0x03, 0x04, 0x04, 0x05, + 0x07, 0x0A, 0x0B, 0x0A, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0C, 0x09, 0x08, 0x08, 0x08, + 0x08, 0x03, 0x04, 0x04, 0x04, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x07, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x08, 0x09, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x0B, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x03, 0x04, 0x04, 0x04, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x06, 0x07, 0x06, + 0xE0, 0x7F, 0xC0, 0xFF, 0x80, 0x00, 0x01, 0x01, 0x02, 0xC0, 0x01, 0xC0, 0x03, 0xC0, 0x03, 0xC0, + 0x3F, 0x80, 0x7F, 0x00, 0xFF, 0x00, 0x3C, 0x00, 0xF0, 0x00, 0xC0, 0x03, 0x00, 0x07, 0xF8, 0x1F, + 0xF0, 0x3F, 0x20, 0x40, 0x40, 0x80, 0x80, 0xFF, 0x01, 0xFF, 0x03, 0x02, 0x04, 0x04, 0x08, 0xF8, + 0x1F, 0xF0, 0x3F, 0x20, 0x40, 0x40, 0x80, 0x80, 0xFF, 0x01, 0xFF, 0x03, 0x02, 0x04, 0x04, 0x08, + 0xF8, 0x1F, 0xF0, 0x3F, 0x20, 0x40, 0x40, 0x80, 0x80, 0xFF, 0x01, 0xFF, 0x03, 0x02, 0x04, 0x04, + 0x08, 0xF8, 0x1F, 0xF0, 0x3F, 0x20, 0x40, 0x40, 0x80, 0x80, 0xFF, 0x01, 0xFF, 0x03, 0x02, 0x04, + 0x04, 0x08, 0xF8, 0x1F, 0xF0, 0x3F, 0x20, 0x40, 0x40, 0x80, 0x80, 0xFF, 0x01, 0xFF, 0x03, 0x02, + 0x04, 0x04, 0x08, 0xF8, 0x1F, 0xF0, 0x3F, 0x20, 0x40, 0x40, 0x80, 0x80, 0xFF, 0x01, 0xFF, 0x03, + 0x02, 0x04, 0x04, 0x08, 0xF8, 0x1F, 0xF0, 0x3F, 0x20, 0x40, 0x40, 0x80, 0x80, 0xFF, 0x01, 0xFF, + 0x03, 0x02, 0x04, 0x04, 0x08, 0xF0, 0x17, 0xE0, 0x2F, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, + 0x0E, 0x00, 0x00, 0x01, 0x20, 0x0E, 0xC0, 0x1F, 0xE0, 0x3F, 0xC0, 0x7F, 0x80, 0x3F, 0x00, 0x47, + 0x00, 0x08, 0x00, 0x38, 0x02, 0xF8, 0x0C, 0xF8, 0x3F, 0xF0, 0x7F, 0xC0, 0x7C, 0x00, 0x71, 0x00, + 0x06, 0x00, 0x1E, 0x01, 0x24, 0x03, 0x78, 0x03, 0x60, 0x03, 0x00, 0x1B, 0x00, 0x7B, 0x00, 0x93, + 0x00, 0xE2, 0x01, 0x80, 0x01, 0x80, 0x03, 0xB0, 0x0F, 0xF0, 0x11, 0x20, 0x27, 0xC0, 0x7B, 0x00, + 0xF3, 0x00, 0x60, 0x01, 0x0E, 0x00, 0x1C, 0x00, 0xC0, 0x07, 0xE0, 0x3F, 0xE0, 0xE0, 0x40, 0x00, + 0x81, 0x00, 0x02, 0x07, 0x07, 0xFC, 0x07, 0xE0, 0x03, 0x10, 0x00, 0xA0, 0x00, 0xE0, 0x01, 0xC0, + 0x03, 0x00, 0x05, 0x00, 0x02, 0x00, 0x20, 0x00, 0x40, 0x00, 0xE0, 0x03, 0xC0, 0x07, 0x00, 0x02, + 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x02, 0x80, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x04, 0x00, 0x08, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x03, 0xF0, 0x07, 0xF8, 0x03, 0x30, 0x00, + 0xC0, 0x1F, 0xC0, 0x7F, 0x80, 0x80, 0x00, 0x01, 0x01, 0xFE, 0x03, 0xF8, 0x03, 0x10, 0x00, 0x20, + 0x00, 0xE0, 0x3F, 0xC0, 0x7F, 0x00, 0xC1, 0x00, 0xC3, 0x01, 0xC2, 0x02, 0xC4, 0x04, 0xF8, 0x08, + 0xE0, 0x10, 0x40, 0x10, 0xC0, 0x60, 0x80, 0x88, 0x00, 0x11, 0x01, 0xFE, 0x03, 0xB8, 0x03, 0x00, + 0x03, 0x00, 0x07, 0x80, 0x0B, 0x80, 0x13, 0x80, 0xFF, 0x00, 0xFF, 0x01, 0x80, 0x00, 0x7C, 0x02, + 0xF8, 0x0C, 0x90, 0x10, 0x20, 0x21, 0x40, 0x7E, 0x80, 0x78, 0x00, 0xFE, 0x00, 0xFE, 0x03, 0x64, + 0x04, 0x48, 0x08, 0xB0, 0x1F, 0x40, 0x1E, 0x40, 0x00, 0x80, 0xE0, 0x00, 0xF1, 0x01, 0x7A, 0x00, + 0x3C, 0x00, 0x18, 0x00, 0xE0, 0x0E, 0xE0, 0x3F, 0x40, 0x44, 0x80, 0x88, 0x00, 0xFF, 0x01, 0xDC, + 0x01, 0x78, 0x02, 0xF8, 0x0D, 0x10, 0x12, 0x20, 0x26, 0xC0, 0x7F, 0x00, 0x7F, 0x00, 0x08, 0x01, + 0x10, 0x02, 0x00, 0x08, 0x40, 0x18, 0x80, 0x10, 0x00, 0x02, 0x00, 0x0E, 0x00, 0x36, 0x00, 0x44, + 0x00, 0x8C, 0x01, 0x08, 0x02, 0x40, 0x01, 0x80, 0x02, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x14, 0x00, + 0x28, 0x00, 0x04, 0x01, 0x18, 0x03, 0x20, 0x02, 0xC0, 0x06, 0x00, 0x07, 0x00, 0x04, 0x00, 0x01, + 0x00, 0x03, 0x00, 0xC2, 0x02, 0xC4, 0x05, 0xF8, 0x00, 0xE0, 0x00, 0x00, 0x0F, 0x80, 0x7F, 0x00, + 0xC3, 0x00, 0x33, 0x03, 0xF2, 0x04, 0x24, 0x09, 0xC8, 0x13, 0xB0, 0x27, 0xC0, 0x48, 0x80, 0x1F, + 0x00, 0x3C, 0x00, 0x80, 0x01, 0xE0, 0x03, 0xF0, 0x01, 0x78, 0x02, 0xF0, 0x04, 0x80, 0x0F, 0x00, + 0x7C, 0x00, 0xC0, 0x00, 0xFF, 0x01, 0xFE, 0x03, 0x44, 0x04, 0x88, 0x08, 0x10, 0x11, 0xE0, 0x3F, + 0x80, 0x3B, 0x00, 0x3E, 0x00, 0xFE, 0x00, 0x06, 0x03, 0x04, 0x04, 0x08, 0x08, 0x30, 0x18, 0xC0, + 0x18, 0x00, 0x11, 0x80, 0xFF, 0x00, 0xFF, 0x01, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x30, 0x18, + 0xC0, 0x1F, 0x00, 0x1F, 0x80, 0xFF, 0x00, 0xFF, 0x01, 0x22, 0x02, 0x44, 0x04, 0x88, 0x08, 0x10, + 0x11, 0x20, 0x20, 0xC0, 0x7F, 0x80, 0xFF, 0x00, 0x11, 0x00, 0x22, 0x00, 0x44, 0x00, 0x88, 0x00, + 0x10, 0x00, 0x80, 0x0F, 0x80, 0x3F, 0x80, 0xC1, 0x00, 0x01, 0x01, 0x22, 0x02, 0x4C, 0x06, 0xB0, + 0x0F, 0x40, 0x1F, 0xE0, 0x3F, 0xC0, 0x7F, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, + 0xF8, 0x0F, 0xF0, 0x1F, 0xE0, 0x3F, 0xC0, 0x7F, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x00, 0x02, 0x00, + 0x04, 0xF8, 0x0F, 0xF0, 0x0F, 0xE0, 0x3F, 0xC0, 0x7F, 0x00, 0x0C, 0x00, 0x3C, 0x00, 0xCC, 0x00, + 0x0C, 0x03, 0x08, 0x0C, 0x00, 0x10, 0xE0, 0x3F, 0xC0, 0x7F, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x04, 0x00, 0x08, 0xF0, 0x1F, 0xE0, 0x3F, 0x00, 0x07, 0x00, 0x3C, 0x00, 0xE0, 0x00, + 0xC0, 0x01, 0xE0, 0x01, 0xE0, 0x00, 0xF0, 0x1F, 0xE0, 0x3F, 0xC0, 0x7F, 0x80, 0xFF, 0x00, 0x0E, + 0x00, 0x38, 0x00, 0xC0, 0x01, 0x00, 0x07, 0xF0, 0x1F, 0xE0, 0x3F, 0x00, 0x1F, 0x00, 0x7F, 0x00, + 0x83, 0x01, 0x02, 0x02, 0x04, 0x04, 0x18, 0x0C, 0xE0, 0x0F, 0x80, 0x0F, 0xC0, 0x7F, 0x80, 0xFF, + 0x00, 0x11, 0x00, 0x22, 0x00, 0x44, 0x00, 0x88, 0x00, 0xF0, 0x01, 0xC0, 0x01, 0x00, 0x1F, 0x00, + 0x7F, 0x00, 0x83, 0x01, 0x02, 0x02, 0x04, 0x05, 0x18, 0x0E, 0xE0, 0x1F, 0x80, 0x2F, 0xC0, 0x7F, + 0x80, 0xFF, 0x00, 0x11, 0x00, 0x22, 0x00, 0x44, 0x00, 0x88, 0x01, 0xF0, 0x1F, 0xC0, 0x39, 0x80, + 0x33, 0x80, 0xEF, 0x00, 0x11, 0x01, 0x22, 0x02, 0x44, 0x04, 0xB8, 0x0F, 0x60, 0x0E, 0x20, 0x00, + 0x40, 0x00, 0x80, 0x00, 0x00, 0xFF, 0x01, 0xFE, 0x03, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0xE0, + 0x0F, 0xC0, 0x3F, 0x00, 0xC0, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x06, 0xF8, 0x07, 0xF0, 0x07, + 0x60, 0x00, 0xC0, 0x07, 0x00, 0x3E, 0x00, 0xE0, 0x01, 0xC0, 0x03, 0xF0, 0x01, 0xF8, 0x00, 0x30, + 0x00, 0x60, 0x00, 0xC0, 0x07, 0x00, 0x3E, 0x00, 0xE0, 0x01, 0xC0, 0x03, 0xF0, 0x01, 0xE0, 0x03, + 0x00, 0x1E, 0x00, 0x3C, 0x00, 0x1F, 0x80, 0x0F, 0x00, 0x03, 0x00, 0x02, 0x02, 0x0C, 0x06, 0x30, + 0x06, 0xC0, 0x07, 0x00, 0x07, 0x00, 0x1F, 0x00, 0x63, 0x00, 0x83, 0x01, 0x02, 0x02, 0x0C, 0x00, + 0x38, 0x00, 0xC0, 0x00, 0x00, 0x3F, 0x00, 0x7E, 0x00, 0x06, 0x00, 0x07, 0x00, 0x06, 0x00, 0x04, + 0x06, 0x08, 0x0F, 0x10, 0x17, 0xA0, 0x23, 0xC0, 0x43, 0x80, 0x81, 0x00, 0xFF, 0x07, 0xFE, 0x0F, + 0x04, 0x10, 0x18, 0x00, 0xF0, 0x07, 0x80, 0x3F, 0x00, 0x60, 0x80, 0x00, 0x02, 0xFF, 0x07, 0xFE, + 0x0F, 0x10, 0x00, 0x30, 0x00, 0x30, 0x00, 0x60, 0x00, 0x80, 0x01, 0x00, 0x02, 0x00, 0x00, 0x04, + 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x02, 0x01, + 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x06, 0x80, 0x1E, 0x00, 0x25, 0x00, 0x4A, 0x00, 0xFC, 0x00, + 0xF0, 0x01, 0xFE, 0x03, 0xFC, 0x07, 0x40, 0x08, 0x80, 0x10, 0x00, 0x3F, 0x00, 0x3C, 0x00, 0x78, + 0x00, 0xF8, 0x01, 0x10, 0x02, 0x20, 0x04, 0xC0, 0x0C, 0x00, 0x09, 0x00, 0x1E, 0x00, 0x7E, 0x00, + 0x84, 0x00, 0x08, 0x01, 0xFE, 0x03, 0xFC, 0x07, 0x80, 0x07, 0x80, 0x1F, 0x00, 0x25, 0x00, 0x4A, + 0x00, 0xDC, 0x00, 0xB0, 0x00, 0x10, 0x00, 0xF8, 0x07, 0xF8, 0x0F, 0x90, 0x00, 0x00, 0x9E, 0x00, + 0x7E, 0x01, 0x84, 0x02, 0x08, 0x05, 0xF0, 0x0F, 0xE0, 0x0F, 0xF8, 0x0F, 0xF0, 0x1F, 0x00, 0x03, + 0x00, 0x02, 0x00, 0xFC, 0x00, 0xF0, 0x01, 0xF2, 0x03, 0xE4, 0x07, 0x00, 0x20, 0x90, 0x7F, 0x20, + 0x7F, 0xC0, 0x7F, 0x80, 0xFF, 0x00, 0x70, 0x00, 0xB0, 0x01, 0x20, 0x06, 0x00, 0x08, 0xF0, 0x1F, + 0xE0, 0x3F, 0x00, 0x7E, 0x00, 0xFC, 0x00, 0x18, 0x00, 0x10, 0x00, 0xE0, 0x07, 0x80, 0x0F, 0x80, + 0x01, 0x00, 0x01, 0x00, 0x7E, 0x00, 0xF8, 0x00, 0xF8, 0x01, 0xF0, 0x03, 0x60, 0x00, 0x40, 0x00, + 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x3C, 0x00, 0xFC, 0x00, 0x08, 0x01, 0x10, 0x02, 0xE0, 0x07, 0x80, + 0x07, 0x80, 0x7F, 0x00, 0xFF, 0x00, 0x42, 0x00, 0x84, 0x00, 0xF8, 0x01, 0xE0, 0x01, 0xC0, 0x03, + 0xC0, 0x0F, 0x80, 0x10, 0x00, 0x21, 0x00, 0xFE, 0x01, 0xFC, 0x03, 0xF8, 0x01, 0xF0, 0x03, 0x60, + 0x00, 0x40, 0x00, 0x00, 0x09, 0x00, 0x37, 0x00, 0x5A, 0x00, 0xEC, 0x00, 0x90, 0x00, 0x10, 0x00, + 0xF8, 0x03, 0xF0, 0x0F, 0x80, 0x10, 0x00, 0x1F, 0x00, 0x7E, 0x00, 0x80, 0x00, 0x80, 0x01, 0xF0, + 0x03, 0xE0, 0x07, 0xC0, 0x00, 0x80, 0x07, 0x00, 0x3C, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x18, 0x00, + 0x30, 0x00, 0xE0, 0x03, 0x00, 0x0F, 0x00, 0x1E, 0x00, 0x1F, 0x00, 0x3E, 0x00, 0xF0, 0x00, 0xE0, + 0x01, 0xF0, 0x01, 0x60, 0x00, 0x40, 0x08, 0x80, 0x19, 0x00, 0x1E, 0x00, 0x18, 0x00, 0x78, 0x00, + 0x98, 0x01, 0x10, 0x02, 0x60, 0x10, 0xC0, 0x33, 0x00, 0x3E, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0C, + 0x00, 0x88, 0x01, 0x90, 0x03, 0xA0, 0x05, 0xC0, 0x09, 0x80, 0x11, 0x00, 0x04, 0x80, 0xFF, 0x80, + 0xEF, 0x03, 0x01, 0x04, 0xFE, 0x0F, 0xFC, 0x1F, 0x08, 0x20, 0xF0, 0x7D, 0xC0, 0x7F, 0x00, 0x08, + 0x00, 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x30, 0x00, 0x20, 0x00, 0xC0, + 0x7F, 0x80, 0xFF, 0x00, 0xFF, 0x01, 0xFE, 0x03, 0xA0, 0x00, 0xF0, 0x07, 0xF0, 0x1F, 0x20, 0x25, + 0x40, 0x42, 0x80, 0xE3, 0x00, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x38, 0x00, 0x30, 0x00, + 0x80, 0x00, 0x00, 0x01, 0xF4, 0x03, 0xFE, 0x03, 0x3E, 0x00, 0x24, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x60, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x40, 0x00, + 0x80, 0x00, 0xE0, 0x1F, 0xC0, 0x3F, 0x00, 0x04, 0x00, 0x08, 0x00, 0x48, 0x00, 0x90, 0x00, 0xF8, + 0x07, 0xF0, 0x0F, 0x80, 0x04, 0x00, 0x09, 0x00, 0x01, 0x00, 0x03, 0x00, 0x06, 0x00, 0x08, 0x00, + 0x30, 0x00, 0xF0, 0x10, 0x20, 0x31, 0xC0, 0x3B, 0x00, 0x3B, 0x00, 0x1C, 0x00, 0x9C, 0x01, 0x8C, + 0x07, 0x08, 0x09, 0x00, 0x1E, 0x00, 0x18, 0x00, 0x30, 0x00, 0xF0, 0x00, 0x20, 0x01, 0xC0, 0x03, + 0x00, 0x03, 0x00, 0x00, 0xE0, 0x0C, 0xE0, 0x3B, 0x50, 0x44, 0xE0, 0x88, 0xC0, 0x11, 0x81, 0xEE, + 0x03, 0x98, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x1E, 0x00, 0x24, 0x00, 0x00, 0x00, 0x7C, 0x00, + 0xFC, 0x01, 0x0C, 0x06, 0x08, 0x08, 0x10, 0x10, 0x60, 0x30, 0xC0, 0x7F, 0x80, 0xFF, 0x00, 0x11, + 0x01, 0x22, 0x02, 0x04, 0x04, 0x00, 0x00, 0x10, 0x18, 0x28, 0x3C, 0x70, 0x5C, 0xE0, 0x8E, 0x40, + 0x0F, 0x01, 0x06, 0x02, 0x00, 0x00, 0x20, 0x00, 0x70, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x70, 0x00, 0xE0, 0x00, 0xC0, 0x01, 0x80, + 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x00, 0xC0, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, + 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x04, + 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x04, 0x00, 0x08, 0x40, 0x00, 0xC0, 0x00, 0x80, 0x01, 0x00, 0x03, 0x00, 0x06, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x80, 0x07, 0x00, 0x0F, 0x00, 0x1E, 0x00, 0x3C, 0x00, 0x70, 0x00, 0xE0, + 0x00, 0xE0, 0x01, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x90, 0x00, 0x72, 0x03, 0xAC, 0x05, 0xD8, 0x0E, + 0x10, 0x09, 0x00, 0x00, 0x00, 0x24, 0x00, 0x78, 0x00, 0x60, 0x00, 0x00, 0x00, 0xC0, 0x03, 0xC0, + 0x0F, 0x80, 0x10, 0x00, 0x21, 0x00, 0x7E, 0x00, 0xFC, 0x00, 0x28, 0x01, 0x50, 0x02, 0xE0, 0x06, + 0x80, 0x05, 0x00, 0x00, 0x00, 0x31, 0x40, 0x72, 0x80, 0xB5, 0x00, 0x3B, 0x01, 0x32, 0x02, 0x0C, + 0x00, 0x38, 0x00, 0xC8, 0x00, 0x10, 0x3F, 0x20, 0x7E, 0x40, 0x06, 0x00, 0x07, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x40, 0x3F, 0x80, 0x7E, 0x00, 0x00, 0x00, 0x3C, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF8, + 0x03, 0x70, 0x06, 0x80, 0x04, 0x00, 0x00, 0xC0, 0x32, 0xC0, 0x7F, 0x80, 0xBC, 0x00, 0x13, 0x01, + 0x24, 0x02, 0x00, 0x04, 0x00, 0x00, 0xA0, 0x0B, 0xC0, 0x1F, 0x00, 0x11, 0x00, 0x22, 0x00, 0xFE, + 0x00, 0x74, 0x01, 0x00, 0x00, 0xB8, 0x02, 0xF0, 0x05, 0x00, 0x3F, 0x00, 0x7E, 0x00, 0x2F, 0x00, + 0x56, 0x00, 0x00, 0x00, 0x7C, 0x1F, 0xF8, 0x3E, 0x00, 0x00, 0xC0, 0x46, 0xC0, 0x9F, 0x81, 0x64, + 0x02, 0x99, 0x04, 0xE6, 0x0F, 0x88, 0x0D, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x00, 0x00, + 0x3E, 0x00, 0xFE, 0x00, 0x76, 0x03, 0xF4, 0x05, 0x28, 0x0A, 0x50, 0x14, 0xA0, 0x28, 0xC0, 0x60, + 0x00, 0x7F, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x20, 0x01, 0xE8, 0x02, 0xF0, 0x05, 0xC0, 0x0B, 0x00, + 0x00, 0x00, 0x20, 0x00, 0xE0, 0x00, 0xE0, 0x03, 0xC0, 0x07, 0x80, 0x0D, 0x00, 0x11, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0xC0, 0x00, 0x80, 0x01, 0x00, 0x02, 0x00, + 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0xF8, 0x00, 0xF8, 0x03, 0x18, 0x0C, 0xD0, 0x17, + 0xA0, 0x2F, 0x40, 0x4D, 0x80, 0xBE, 0x00, 0xCB, 0x01, 0xFC, 0x01, 0xF0, 0x01, 0x02, 0x00, 0x04, + 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x70, 0x00, 0xE0, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x20, 0x02, 0xF0, 0x05, 0xE0, + 0x0B, 0x00, 0x11, 0x00, 0x22, 0x80, 0x04, 0x80, 0x0D, 0x00, 0x1D, 0x00, 0x2E, 0x00, 0x48, 0x00, + 0x50, 0x00, 0xB0, 0x01, 0xA0, 0x02, 0xC0, 0x07, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0C, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFE, 0x01, 0x80, 0x00, 0x00, 0x01, 0xF0, 0x03, + 0xE0, 0x07, 0x00, 0x08, 0xE0, 0x00, 0xE0, 0x03, 0xC0, 0xFF, 0x81, 0xFF, 0x03, 0xFF, 0x07, 0xFE, + 0x0F, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, + 0x00, 0x0C, 0x00, 0x00, 0x10, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0x00, 0x00, 0x00, 0x27, 0x00, 0x5F, + 0x00, 0xBE, 0x00, 0x38, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x36, 0x00, 0x7C, 0x00, 0xF8, 0x00, + 0xE0, 0x00, 0x80, 0x00, 0x08, 0x00, 0xF8, 0x00, 0xF0, 0x11, 0x00, 0x38, 0x00, 0x3C, 0x00, 0x1C, + 0x00, 0xCE, 0x00, 0xCE, 0x01, 0xC4, 0x07, 0x80, 0x0F, 0x20, 0x00, 0xE0, 0x03, 0xC0, 0x47, 0x00, + 0xE0, 0x00, 0xF0, 0x00, 0x70, 0x00, 0xB8, 0x04, 0xB8, 0x0D, 0x10, 0x1D, 0x00, 0x2E, 0x00, 0x48, + 0x00, 0x05, 0x00, 0x1B, 0x00, 0x2A, 0x02, 0x7C, 0x07, 0xD0, 0x07, 0x80, 0x03, 0xC0, 0x19, 0xC0, + 0x39, 0x80, 0xF8, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x3C, 0x80, 0x4E, 0x00, 0x8D, + 0x00, 0x80, 0x01, 0x00, 0x01, 0x80, 0x01, 0xE0, 0x03, 0xF1, 0x01, 0x7E, 0x02, 0xF8, 0x04, 0x80, + 0x0F, 0x00, 0x7C, 0x00, 0xC0, 0x00, 0x80, 0x01, 0xE0, 0x03, 0xF0, 0x01, 0x7C, 0x02, 0xFC, 0x04, + 0x88, 0x0F, 0x00, 0x7C, 0x00, 0xC0, 0x00, 0x80, 0x01, 0xE0, 0x03, 0xF2, 0x01, 0x7E, 0x02, 0xFC, + 0x04, 0x90, 0x0F, 0x00, 0x7C, 0x00, 0xC0, 0x00, 0x80, 0x01, 0xE1, 0x03, 0xF3, 0x01, 0x7E, 0x02, + 0xFC, 0x04, 0x98, 0x0F, 0x10, 0x7C, 0x00, 0xC0, 0x00, 0x80, 0x01, 0xE1, 0x03, 0xF2, 0x01, 0x78, + 0x02, 0xF0, 0x04, 0x90, 0x0F, 0x20, 0x7C, 0x00, 0xC0, 0x00, 0x80, 0x01, 0xE0, 0x03, 0xF1, 0x01, + 0x7F, 0x02, 0xFE, 0x04, 0x88, 0x0F, 0x00, 0x7C, 0x00, 0xC0, 0x00, 0x00, 0x01, 0x80, 0x03, 0x80, + 0x03, 0xC0, 0x01, 0xE0, 0x03, 0xE0, 0x04, 0xC0, 0x7F, 0x80, 0xFF, 0x00, 0x11, 0x01, 0x22, 0x02, + 0x44, 0x04, 0x08, 0x08, 0x00, 0x00, 0x80, 0x0F, 0x80, 0x3F, 0x80, 0xC1, 0x00, 0x01, 0x05, 0x02, + 0x0E, 0x0C, 0x1E, 0x30, 0x06, 0x40, 0x04, 0x00, 0x00, 0xC0, 0x7F, 0x80, 0xFF, 0x40, 0x11, 0x81, + 0x23, 0x02, 0x46, 0x04, 0x88, 0x08, 0x10, 0x10, 0x00, 0x00, 0xC0, 0x7F, 0x80, 0xFF, 0x00, 0x11, + 0x01, 0x23, 0x02, 0x47, 0x04, 0x8A, 0x08, 0x10, 0x10, 0x00, 0x00, 0xC0, 0x7F, 0x80, 0xFF, 0x80, + 0x11, 0x81, 0x23, 0x02, 0x47, 0x04, 0x8C, 0x08, 0x10, 0x10, 0x00, 0x00, 0xC0, 0x7F, 0xA0, 0xFF, + 0x40, 0x11, 0x01, 0x22, 0x02, 0x45, 0x04, 0x8A, 0x08, 0x10, 0x10, 0x08, 0x00, 0xF0, 0x7F, 0xC0, + 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x03, 0xFF, 0x07, 0x02, 0x00, 0x08, 0x00, 0xF8, 0x3F, 0xF0, 0x7F, + 0x40, 0x00, 0x40, 0x00, 0x80, 0xFE, 0x03, 0xFD, 0x07, 0x02, 0x00, 0x00, 0x01, 0xE0, 0x3F, 0xC0, + 0x7F, 0x80, 0x88, 0x00, 0x11, 0x01, 0x02, 0x02, 0x0C, 0x06, 0xF0, 0x07, 0xC0, 0x07, 0x00, 0x00, + 0xC0, 0x7F, 0xC0, 0xFF, 0xC0, 0x0E, 0x80, 0x39, 0x00, 0xC3, 0x01, 0x06, 0x07, 0xF4, 0x1F, 0xE0, + 0x3F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0xFE, 0x80, 0x06, 0x03, 0x07, 0x04, 0x0C, 0x08, 0x30, 0x18, + 0xC0, 0x1F, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x7C, 0x00, 0xFC, 0x01, 0x0C, 0x06, 0x0C, 0x08, 0x1C, + 0x10, 0x68, 0x30, 0x80, 0x3F, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xF8, 0x00, 0xF8, 0x03, 0x1C, 0x0C, + 0x1C, 0x10, 0x38, 0x20, 0xE0, 0x60, 0x00, 0x7F, 0x00, 0x7C, 0x00, 0x00, 0x00, 0xF0, 0x01, 0xF4, + 0x07, 0x3C, 0x18, 0x38, 0x20, 0x70, 0x40, 0xE0, 0xC1, 0x40, 0xFE, 0x00, 0xF8, 0x00, 0x00, 0x00, + 0xE0, 0x03, 0xE0, 0x0F, 0x68, 0x30, 0x50, 0x40, 0xA0, 0x80, 0x40, 0x83, 0x01, 0xFC, 0x01, 0xF0, + 0x01, 0x00, 0x00, 0x40, 0x04, 0x80, 0x0D, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x6C, 0x00, 0x88, 0x00, + 0x00, 0x00, 0xE0, 0x0B, 0xE0, 0x1F, 0x60, 0x3C, 0x40, 0x5C, 0x80, 0x8E, 0x00, 0x8F, 0x01, 0xFE, + 0x01, 0xF4, 0x01, 0x00, 0x00, 0xF0, 0x07, 0xE0, 0x1F, 0x10, 0x60, 0x60, 0x80, 0x80, 0x00, 0x01, + 0x00, 0x03, 0xFC, 0x03, 0xF8, 0x03, 0x00, 0x00, 0xE0, 0x0F, 0xC0, 0x3F, 0x00, 0xC0, 0x80, 0x00, + 0x81, 0x01, 0x02, 0x01, 0x06, 0xF8, 0x07, 0xF0, 0x07, 0x00, 0x00, 0xC0, 0x1F, 0x80, 0x7F, 0x80, + 0x80, 0x81, 0x01, 0x02, 0x03, 0x04, 0x04, 0x0C, 0xF0, 0x0F, 0xE0, 0x0F, 0x00, 0x00, 0x80, 0x3F, + 0x00, 0xFF, 0x80, 0x00, 0x03, 0x01, 0x04, 0x02, 0x08, 0x04, 0x18, 0xE0, 0x1F, 0xC0, 0x1F, 0x80, + 0x01, 0x00, 0x07, 0x00, 0x18, 0x00, 0xE2, 0x07, 0xC6, 0x0F, 0xC4, 0x00, 0xE0, 0x00, 0xC0, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0x01, 0xFE, 0x03, 0x10, 0x01, 0x20, 0x02, 0x40, 0x04, 0x80, 0x08, 0x00, + 0x1F, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xFC, 0x03, 0xFC, 0x07, 0xC8, 0x08, 0xF0, 0x13, 0xC0, 0x3C, + 0x00, 0x30, 0x00, 0x00, 0x00, 0xC0, 0x00, 0xD2, 0x03, 0xAC, 0x04, 0x50, 0x09, 0x80, 0x1F, 0x00, + 0x3E, 0x00, 0x00, 0x00, 0x60, 0x00, 0xE8, 0x01, 0x54, 0x02, 0xAC, 0x04, 0xC8, 0x0F, 0x00, 0x1F, + 0x00, 0x00, 0x00, 0x30, 0x00, 0xF5, 0x00, 0x2B, 0x01, 0x56, 0x02, 0xE8, 0x07, 0x80, 0x0F, 0x00, + 0x00, 0x40, 0x18, 0xC0, 0x7A, 0x80, 0x95, 0x00, 0x2B, 0x01, 0xF6, 0x03, 0xC4, 0x07, 0x00, 0x00, + 0x00, 0x0C, 0x40, 0x3D, 0x80, 0x4A, 0x00, 0x95, 0x00, 0xFA, 0x01, 0xE0, 0x03, 0x00, 0x00, 0x00, + 0x06, 0x90, 0x1E, 0x70, 0x25, 0xE0, 0x4A, 0x80, 0xFC, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x03, + 0x40, 0x0F, 0x80, 0x12, 0x00, 0x25, 0x00, 0x7E, 0x00, 0xFC, 0x00, 0x28, 0x01, 0x50, 0x02, 0xE0, + 0x06, 0x80, 0x05, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x7E, 0x01, 0x84, 0x03, 0x08, 0x07, 0x30, 0x03, + 0x40, 0x02, 0x00, 0x00, 0x00, 0x0F, 0x20, 0x3F, 0xC0, 0x4A, 0x00, 0x95, 0x00, 0xB8, 0x01, 0x60, + 0x01, 0x00, 0x00, 0x80, 0x07, 0x80, 0x1F, 0x40, 0x25, 0xC0, 0x4A, 0x80, 0xDC, 0x00, 0xB0, 0x00, + 0x00, 0x00, 0xC0, 0x03, 0xD0, 0x0F, 0xB0, 0x12, 0x60, 0x25, 0x80, 0x6E, 0x00, 0x58, 0x00, 0x00, + 0x00, 0xE0, 0x01, 0xE8, 0x07, 0x50, 0x09, 0xA0, 0x12, 0x40, 0x37, 0x00, 0x2C, 0x80, 0x00, 0x00, + 0xFB, 0x01, 0xF4, 0x03, 0x00, 0x00, 0xD0, 0x0F, 0xB0, 0x1F, 0x20, 0x00, 0x80, 0x00, 0x80, 0xFD, + 0x00, 0xFB, 0x01, 0x04, 0x00, 0x08, 0x00, 0xD0, 0x0F, 0xA0, 0x1F, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x00, 0xF5, 0x01, 0x2E, 0x02, 0x7C, 0x04, 0xE8, 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x80, 0x7E, + 0x80, 0xFD, 0x00, 0x1B, 0x00, 0x16, 0x00, 0xEC, 0x07, 0x88, 0x0F, 0x00, 0x00, 0x00, 0x1E, 0x40, + 0x7E, 0x80, 0x85, 0x00, 0x0A, 0x01, 0xF0, 0x03, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x3F, + 0x80, 0x42, 0x80, 0x85, 0x00, 0xF9, 0x01, 0xE0, 0x01, 0x00, 0x00, 0x80, 0x07, 0xA0, 0x1F, 0x60, + 0x21, 0xC0, 0x42, 0x00, 0xFD, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xC8, 0x03, 0xD8, 0x0F, 0xB0, 0x10, + 0x60, 0x21, 0xC0, 0x7E, 0x80, 0x78, 0x00, 0x00, 0x00, 0xE0, 0x01, 0xE8, 0x07, 0x50, 0x08, 0xA0, + 0x10, 0x40, 0x3F, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x50, 0x01, 0xA0, 0x02, + 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0xF8, 0x00, 0xF8, 0x01, 0xD0, 0x03, 0xE0, 0x05, 0xC0, + 0x0F, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x3E, 0x80, 0xFC, 0x00, 0x03, 0x01, 0x04, 0x03, 0xE0, 0x07, + 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x7E, 0x00, 0x81, 0x00, 0x83, 0x01, 0xF2, 0x03, 0xE0, + 0x07, 0x00, 0x00, 0x80, 0x0F, 0x40, 0x3F, 0xC0, 0x40, 0x80, 0xC1, 0x00, 0xFA, 0x01, 0xF0, 0x03, + 0x00, 0x00, 0xC0, 0x07, 0xA0, 0x1F, 0x40, 0x20, 0x80, 0x60, 0x00, 0xFD, 0x00, 0xF8, 0x01, 0x30, + 0x08, 0xE0, 0x19, 0x10, 0x1F, 0x30, 0x1E, 0x20, 0x0F, 0x00, 0x06, 0x00, 0x00, 0x00, 0xFF, 0x07, + 0xFE, 0x0F, 0x20, 0x04, 0x40, 0x08, 0x80, 0x1F, 0x00, 0x1E, 0x00, 0x06, 0x01, 0x3D, 0x03, 0xE2, + 0x03, 0xC4, 0x03, 0xE8, 0x01, 0xC0, 0x00, 0x00 +}; + +static struct fontDesc_t const HoloLens_12_Desc = { + sizeof(HoloLens_12_Bytes), // total Size + 13, // width in pixel + 17, // height in pixel + 1, // bits per pixel + 0x0B, // Code of first char + 0xFF, // Code of last char + HoloLens_12_Bytes // Data +}; + +#endif + diff --git a/lib/Display/Fonts/HoloLens_20.h b/lib/Display/Fonts/HoloLens_20.h new file mode 100644 index 0000000..9a28c09 --- /dev/null +++ b/lib/Display/Fonts/HoloLens_20.h @@ -0,0 +1,656 @@ +/* + created with FontEditor written by H. Reddmann + HaReddmann at t-online dot de + + File Name : HoloLens_20.h + Date : 10.03.2019 + Font size in bytes : 0x24B2, 9394 + Font width : 21 + Font height : 31 + Font first char : 0x0B + Font last char : 0xFF + Font bits per pixel : 1 + Font is compressed : false + + The font data are defined as + + struct _FONT_ { + // common shared fields + uint16_t font_Size_in_Bytes_over_all_included_Size_it_self; + uint8_t font_Width_in_Pixel_for_fixed_drawing; + uint8_t font_Height_in_Pixel_for_all_Characters; + uint8_t font_Bits_per_Pixels; + // if MSB are set then font is a compressed font + uint8_t font_First_Char; + uint8_t font_Last_Char; + uint8_t font_Char_Widths[font_Last_Char - font_First_Char +1]; + // for each character the separate width in pixels, + // characters < 128 have an implicit virtual right empty row + // characters with font_Char_Widths[] == 0 are undefined + + // if compressed font then additional fields + uint8_t font_Byte_Padding; + // each Char in the table are aligned in size to this value + uint8_t font_RLE_Table[3]; + // Run Length Encoding Table for compression + uint8_t font_Char_Size_in_Bytes[font_Last_Char - font_First_Char +1]; + // for each char the size in (bytes / font_Byte_Padding) are stored, + // this get us the table to seek to the right beginning of each char + // in the font_data[]. + + // for compressed and uncompressed fonts + uint8_t font_data[]; + // bit field of all characters + } +*/ + +#include "FontDesc.h" + +#ifndef HoloLens_20_FONT_H +#define HoloLens_20_FONT_H + +#define HoloLens_20_WIDTH 21 +#define HoloLens_20_HEIGHT 31 + +static unsigned char const HoloLens_20_Bytes[] = { + 0x06, 0x0D, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x0C, 0x0A, 0x11, 0x0B, 0x03, 0x06, 0x06, 0x08, + 0x0B, 0x03, 0x06, 0x03, 0x07, 0x0A, 0x06, 0x0A, 0x0A, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x03, + 0x03, 0x0B, 0x0B, 0x0B, 0x09, 0x13, 0x0E, 0x0B, 0x0D, 0x0C, 0x0B, 0x0B, 0x0D, 0x0C, 0x03, 0x09, + 0x0D, 0x0B, 0x0F, 0x0C, 0x0E, 0x0B, 0x0E, 0x0C, 0x0C, 0x0D, 0x0C, 0x0E, 0x14, 0x0E, 0x0D, 0x0A, + 0x05, 0x07, 0x05, 0x08, 0x0C, 0x05, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x05, 0x0A, 0x0A, 0x03, 0x04, + 0x0A, 0x03, 0x0F, 0x0A, 0x0A, 0x0A, 0x0A, 0x06, 0x09, 0x06, 0x0A, 0x0B, 0x0F, 0x0B, 0x0B, 0x09, + 0x07, 0x03, 0x07, 0x08, 0x06, 0x0B, 0x00, 0x05, 0x0B, 0x08, 0x0E, 0x09, 0x09, 0x07, 0x18, 0x0D, + 0x07, 0x13, 0x00, 0x0B, 0x00, 0x00, 0x05, 0x05, 0x08, 0x08, 0x08, 0x0B, 0x15, 0x08, 0x0F, 0x0A, + 0x07, 0x13, 0x00, 0x0A, 0x0D, 0x00, 0x05, 0x0B, 0x0B, 0x0B, 0x0C, 0x04, 0x0B, 0x08, 0x10, 0x07, + 0x0B, 0x0C, 0x07, 0x10, 0x0C, 0x07, 0x0C, 0x07, 0x07, 0x07, 0x0C, 0x0C, 0x04, 0x06, 0x06, 0x07, + 0x0B, 0x10, 0x11, 0x10, 0x0B, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x14, 0x0E, 0x0C, 0x0C, 0x0C, + 0x0C, 0x05, 0x06, 0x06, 0x06, 0x0D, 0x0D, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0B, 0x0F, 0x0D, 0x0D, + 0x0D, 0x0D, 0x0D, 0x0C, 0x0C, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x11, 0x0B, 0x0B, 0x0B, 0x0B, + 0x0B, 0x04, 0x06, 0x06, 0x06, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0C, 0x0B, 0x0B, 0x0B, + 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, + 0x00, 0xFE, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0x01, 0x80, 0x01, 0x80, 0x00, 0xC0, 0x00, 0x40, 0x00, + 0xE0, 0xFF, 0x3F, 0x00, 0xF0, 0xFF, 0x1F, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xF0, 0x01, 0x00, + 0x00, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x00, + 0xF8, 0x3F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, + 0xFC, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x7C, 0x00, 0xC0, 0xFF, 0x7F, 0x00, 0xE0, 0xFF, + 0x3F, 0x00, 0x30, 0x00, 0x10, 0x00, 0x18, 0x00, 0x08, 0x00, 0xFC, 0xFF, 0x07, 0x00, 0xFE, 0xFF, + 0x03, 0x00, 0xFF, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0x00, 0xC0, 0x00, 0x40, 0x00, 0x60, 0x00, 0x20, + 0x00, 0xF0, 0xFF, 0x1F, 0x00, 0xF8, 0xFF, 0x0F, 0x00, 0xFC, 0xFF, 0x07, 0x00, 0xFE, 0xFF, 0x03, + 0x00, 0x03, 0x00, 0x01, 0x80, 0x01, 0x80, 0x00, 0xC0, 0xFF, 0x7F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, + 0xF0, 0xFF, 0x1F, 0x00, 0xF8, 0xFF, 0x0F, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x06, 0x00, 0x02, 0x00, + 0xFF, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0x00, 0xC0, 0xFF, 0x7F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x30, + 0x00, 0x10, 0x00, 0x18, 0x00, 0x08, 0x00, 0xFC, 0xFF, 0x07, 0x00, 0xFE, 0xFF, 0x03, 0x00, 0xFF, + 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0x00, 0xC0, 0x00, 0x40, 0x00, 0x60, 0x00, 0x20, 0x00, 0xF0, 0xFF, + 0x1F, 0x00, 0xF8, 0xFF, 0x0F, 0x00, 0xFC, 0xFF, 0x07, 0x00, 0xFE, 0xFF, 0x03, 0x00, 0x03, 0x00, + 0x01, 0x80, 0x01, 0x80, 0x00, 0xC0, 0xFF, 0x7F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xF0, 0xFF, 0x1F, + 0x00, 0xF8, 0xFF, 0x0F, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x06, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x01, + 0x80, 0xFF, 0xFF, 0x00, 0xC0, 0xFF, 0x7F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x30, 0x00, 0x10, 0x00, + 0x18, 0x00, 0x08, 0x00, 0xFC, 0xFF, 0x07, 0x00, 0xFE, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0x01, 0x80, + 0xFF, 0xFF, 0x00, 0xC0, 0x00, 0x40, 0x00, 0x60, 0x00, 0x20, 0x00, 0xF0, 0xFF, 0x1F, 0x00, 0xF8, + 0xFF, 0x0F, 0x00, 0xFC, 0xFF, 0x07, 0x00, 0xFE, 0xFF, 0x03, 0x00, 0x03, 0x00, 0x01, 0x80, 0x01, + 0x80, 0x00, 0xC0, 0xFF, 0x7F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xF0, 0xFF, 0x1F, 0x00, 0xF8, 0xFF, + 0x0F, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x06, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x01, 0x80, 0xFF, 0xFF, + 0x00, 0xC0, 0xFF, 0x7F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x30, 0x00, 0x10, 0x00, 0x18, 0x00, 0x08, + 0x00, 0xFC, 0xFF, 0x07, 0x00, 0xFE, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0x00, + 0xC0, 0x00, 0x40, 0x00, 0x60, 0x00, 0x20, 0x00, 0xF0, 0xFF, 0x1F, 0x00, 0xF8, 0xFF, 0x0F, 0x00, + 0xF0, 0x7F, 0x06, 0x00, 0xF8, 0x3F, 0x03, 0x00, 0xFC, 0x9F, 0x01, 0x00, 0x3E, 0x00, 0x00, 0x00, + 0x1F, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF0, + 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC0, 0xD8, 0x01, 0x00, 0x60, 0xFF, 0x00, 0x00, 0xF8, + 0x7F, 0x00, 0x80, 0xFF, 0x07, 0x00, 0xC0, 0x9F, 0x1D, 0x00, 0xE0, 0xF6, 0x0F, 0x00, 0x80, 0xFF, + 0x07, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0xFC, 0x19, 0x00, 0x00, 0x6E, 0x0C, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x1E, 0x0C, 0x00, 0x80, 0x1F, 0x0E, 0x00, 0xE0, 0x1F, 0x0F, 0x00, 0x70, 0x0E, 0x07, + 0x00, 0xFE, 0xFF, 0x0F, 0x00, 0xFF, 0xFF, 0x07, 0x00, 0x0E, 0xE3, 0x00, 0x00, 0x8F, 0x7F, 0x00, + 0x00, 0xC7, 0x1F, 0x00, 0x00, 0xC3, 0x07, 0x00, 0x80, 0x07, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, + 0xF8, 0x07, 0x00, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x86, 0xE1, 0x00, 0x00, 0xFF, 0x38, 0x00, 0x00, + 0x3F, 0x07, 0x00, 0x00, 0xEF, 0x01, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xE7, 0x01, 0x00, 0xC0, + 0xF9, 0x01, 0x00, 0x38, 0xFE, 0x01, 0x00, 0x0E, 0xC3, 0x00, 0x00, 0x81, 0x61, 0x00, 0x00, 0xC0, + 0x3F, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xF8, + 0x01, 0x00, 0x78, 0xFE, 0x01, 0x00, 0xFE, 0xE3, 0x00, 0x00, 0xFF, 0x60, 0x00, 0x80, 0xF1, 0x31, + 0x00, 0xC0, 0xFF, 0x1D, 0x00, 0xE0, 0xE7, 0x07, 0x00, 0xE0, 0xF1, 0x07, 0x00, 0x00, 0xF8, 0x03, + 0x00, 0x00, 0x9C, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, + 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xFE, 0x1F, 0x00, 0xC0, 0xFF, 0x3F, 0x00, 0xF8, 0x01, 0x7E, 0x00, + 0x1C, 0x00, 0x38, 0x00, 0x02, 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, 0x80, 0x03, 0x00, 0x07, 0xC0, + 0x0F, 0xF0, 0x03, 0x80, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0x0F, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x18, + 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xC0, 0x07, + 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x60, 0x03, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xFE, 0x07, + 0x00, 0x00, 0xFF, 0x03, 0x00, 0x80, 0xFF, 0x01, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0xF8, 0x00, + 0x00, 0x00, 0x3C, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, + 0x7E, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0x7E, 0x00, 0x00, 0xC0, 0x07, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x80, 0xFF, 0x00, 0x00, 0xF0, 0xFF, 0x01, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0x1E, 0xF0, + 0x00, 0x00, 0x03, 0x60, 0x00, 0x80, 0x01, 0x30, 0x00, 0xC0, 0x03, 0x1E, 0x00, 0xE0, 0xFF, 0x0F, + 0x00, 0xE0, 0xFF, 0x03, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, + 0x00, 0x1C, 0x00, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0xC0, 0xFF, 0x1F, 0x00, 0xE0, 0xFF, 0x0F, 0x00, + 0xC0, 0x00, 0x06, 0x00, 0x70, 0x80, 0x03, 0x00, 0x3C, 0xE0, 0x01, 0x00, 0x0E, 0xF8, 0x00, 0x00, + 0x03, 0x6E, 0x00, 0x80, 0x81, 0x33, 0x00, 0xC0, 0xF1, 0x18, 0x00, 0xE0, 0x3F, 0x0C, 0x00, 0xE0, + 0x0F, 0x06, 0x00, 0xE0, 0x01, 0x03, 0x00, 0x30, 0x60, 0x00, 0x00, 0x1C, 0x70, 0x00, 0x00, 0x0F, + 0x78, 0x00, 0x80, 0x03, 0x38, 0x00, 0xC0, 0x30, 0x18, 0x00, 0x60, 0x18, 0x0C, 0x00, 0xF0, 0x1F, + 0x07, 0x00, 0xF0, 0xFF, 0x03, 0x00, 0xF0, 0xFE, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0xDE, 0x00, 0x00, 0x80, 0x67, 0x00, + 0x00, 0xF0, 0x31, 0x00, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0x7F, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x1E, 0x03, 0x00, 0xF0, 0x8F, 0x03, 0x00, + 0xF8, 0xC7, 0x03, 0x00, 0xBC, 0xC1, 0x01, 0x00, 0xC6, 0xC0, 0x00, 0x00, 0x63, 0x60, 0x00, 0x80, + 0x71, 0x38, 0x00, 0xC0, 0xF8, 0x1F, 0x00, 0x60, 0xF8, 0x07, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x80, + 0x7F, 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0xFC, 0x7F, 0x00, 0x00, 0xEF, 0x78, 0x00, 0x80, 0x31, + 0x30, 0x00, 0xC0, 0x18, 0x18, 0x00, 0xE0, 0x1C, 0x0E, 0x00, 0xF0, 0xFE, 0x07, 0x00, 0x70, 0xFE, + 0x01, 0x00, 0x30, 0x3E, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x01, 0x20, + 0x00, 0xC0, 0x00, 0x1E, 0x00, 0x60, 0xE0, 0x0F, 0x00, 0x30, 0xFC, 0x03, 0x00, 0xD8, 0x3F, 0x00, + 0x00, 0xFC, 0x03, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, + 0x00, 0xC7, 0x0F, 0x00, 0xC0, 0xFF, 0x0F, 0x00, 0xF0, 0x1F, 0x07, 0x00, 0x18, 0x0F, 0x03, 0x00, + 0x8C, 0x87, 0x01, 0x00, 0xFE, 0xE3, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x00, 0x8E, 0x1F, 0x00, 0x00, + 0x80, 0x07, 0x00, 0x00, 0x1F, 0x03, 0x00, 0xE0, 0x9F, 0x03, 0x00, 0xF8, 0xDF, 0x03, 0x00, 0x1C, + 0xCE, 0x01, 0x00, 0x06, 0xC6, 0x00, 0x00, 0x03, 0x73, 0x00, 0x80, 0xC7, 0x3D, 0x00, 0x80, 0xFF, + 0x0F, 0x00, 0xC0, 0xFF, 0x03, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x80, 0x81, + 0x01, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x60, 0x60, 0x02, 0x00, 0x30, 0xF0, 0x01, 0x00, 0x18, 0x78, + 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x0F, 0x00, + 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x38, 0x07, 0x00, 0x00, 0x0C, 0x03, 0x00, + 0x00, 0x86, 0x01, 0x00, 0x80, 0xC3, 0x01, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x80, 0x19, 0x00, 0x00, + 0xC0, 0x0C, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x30, 0x03, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, + 0xCC, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x80, 0x19, 0x00, 0x00, 0xC0, + 0x0C, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0E, 0x07, 0x00, 0x00, 0x86, + 0x01, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x80, 0x73, 0x00, 0x00, 0x80, 0x19, 0x00, 0x00, 0xC0, 0x0F, + 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x0E, 0xCE, 0x00, + 0x00, 0x83, 0x67, 0x00, 0x80, 0xE3, 0x33, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, + 0xC0, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x80, 0xFF, 0x03, 0x00, 0xF0, 0xFF, 0x03, 0x00, + 0x7C, 0xC0, 0x03, 0x00, 0x8F, 0x8F, 0x03, 0x80, 0xF1, 0x8F, 0x01, 0x60, 0xFC, 0x8F, 0x01, 0x30, + 0x0F, 0xC7, 0x00, 0x88, 0x03, 0x43, 0x00, 0xC4, 0xC0, 0x21, 0x00, 0xE2, 0xFC, 0x10, 0x00, 0xF1, + 0x7F, 0x08, 0x80, 0xF9, 0x3F, 0x04, 0xC0, 0xFC, 0x18, 0x03, 0xC0, 0x02, 0x8E, 0x01, 0xE0, 0xC1, + 0x43, 0x00, 0xE0, 0xFF, 0x01, 0x00, 0xE0, 0x7F, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x60, + 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xFC, 0x03, 0x00, 0xC0, 0x7F, 0x00, + 0x00, 0xF8, 0x37, 0x00, 0x00, 0x7C, 0x18, 0x00, 0x00, 0x3E, 0x0C, 0x00, 0x00, 0xFF, 0x06, 0x00, + 0x00, 0xFE, 0x03, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0xC0, 0x07, 0x00, + 0x00, 0x00, 0x03, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x80, + 0x61, 0x30, 0x00, 0xC0, 0x30, 0x18, 0x00, 0x60, 0x18, 0x0C, 0x00, 0x70, 0x0E, 0x06, 0x00, 0xF8, + 0x8F, 0x03, 0x00, 0xF8, 0xFF, 0x01, 0x00, 0x78, 0x7F, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0xF8, + 0x03, 0x00, 0x00, 0xFF, 0x07, 0x00, 0xC0, 0xFF, 0x07, 0x00, 0xE0, 0xC1, 0x03, 0x00, 0x38, 0x80, + 0x03, 0x00, 0x0C, 0x80, 0x01, 0x00, 0x06, 0xC0, 0x00, 0x00, 0x03, 0x60, 0x00, 0x80, 0x03, 0x38, + 0x00, 0xC0, 0x01, 0x1C, 0x00, 0xC0, 0x83, 0x07, 0x00, 0xC0, 0xC1, 0x01, 0x00, 0xC0, 0x60, 0x00, + 0x00, 0xFC, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x80, 0x01, 0x30, 0x00, + 0xC0, 0x00, 0x18, 0x00, 0x60, 0x00, 0x0C, 0x00, 0x30, 0x00, 0x06, 0x00, 0x38, 0x80, 0x03, 0x00, + 0x38, 0xE0, 0x00, 0x00, 0xFC, 0x7F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF8, 0x03, 0x00, 0xC0, + 0xFF, 0x1F, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0x18, 0x06, 0x03, 0x00, 0x0C, + 0x83, 0x01, 0x00, 0x86, 0xC1, 0x00, 0x00, 0xC3, 0x60, 0x00, 0x80, 0x61, 0x30, 0x00, 0xC0, 0x30, + 0x18, 0x00, 0x60, 0x18, 0x0C, 0x00, 0x30, 0x00, 0x06, 0x00, 0xF8, 0xFF, 0x03, 0x00, 0xFC, 0xFF, + 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x80, 0x61, 0x00, 0x00, 0xC0, 0x30, 0x00, + 0x00, 0x60, 0x18, 0x00, 0x00, 0x30, 0x0C, 0x00, 0x00, 0x18, 0x06, 0x00, 0x00, 0x0C, 0x03, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x80, 0xFF, 0x0F, 0x00, + 0xC0, 0x83, 0x07, 0x00, 0x70, 0x00, 0x07, 0x00, 0x18, 0x00, 0x03, 0x00, 0x0C, 0x86, 0x01, 0x00, + 0x06, 0xC3, 0x00, 0x00, 0x87, 0x71, 0x00, 0x80, 0xC3, 0x38, 0x00, 0x80, 0xE7, 0x1F, 0x00, 0x80, + 0xF3, 0x0F, 0x00, 0x80, 0xF9, 0x07, 0x00, 0xF8, 0xFF, 0x03, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0xFE, + 0xFF, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0xFE, 0xFF, + 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0xC0, 0xFF, 0x1F, 0x00, 0xE0, 0xFF, 0x0F, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xC0, 0x00, + 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x38, 0x00, 0xC0, 0xFF, 0x1F, 0x00, 0xE0, 0xFF, 0x07, 0x00, + 0xF0, 0xFF, 0x01, 0x00, 0xF8, 0xFF, 0x03, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, + 0xC0, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0xC0, + 0xF1, 0x00, 0x00, 0x70, 0xF0, 0x00, 0x00, 0x1C, 0xF0, 0x00, 0x00, 0x06, 0xE0, 0x00, 0x00, 0x01, + 0x60, 0x00, 0x00, 0x00, 0x20, 0x00, 0xC0, 0xFF, 0x1F, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0xF0, 0xFF, + 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, + 0x00, 0xF8, 0xFF, 0x03, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x7F, 0x00, 0x00, + 0x00, 0xFF, 0x01, 0x00, 0x00, 0xFC, 0x07, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xC0, 0x07, 0x00, + 0x00, 0xFC, 0x03, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0xFC, 0x07, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x80, + 0xFF, 0x3F, 0x00, 0xC0, 0xFF, 0x1F, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0xF8, + 0xFF, 0x03, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0x7C, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0xF8, + 0x00, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0xE0, 0x03, 0x00, 0xF8, 0xFF, + 0x03, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFE, 0x0F, + 0x00, 0x80, 0xFF, 0x0F, 0x00, 0xC0, 0x83, 0x07, 0x00, 0x70, 0x00, 0x07, 0x00, 0x18, 0x00, 0x03, + 0x00, 0x0C, 0x80, 0x01, 0x00, 0x06, 0xC0, 0x00, 0x00, 0x03, 0x60, 0x00, 0x80, 0x03, 0x38, 0x00, + 0x80, 0x07, 0x0F, 0x00, 0xC0, 0xFF, 0x07, 0x00, 0xC0, 0xFF, 0x01, 0x00, 0x80, 0x3F, 0x00, 0x00, + 0xFC, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x80, 0xC1, 0x00, 0x00, 0xC0, + 0x60, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x30, 0x18, 0x00, 0x00, 0x38, 0x0E, 0x00, 0x00, 0xFC, + 0x07, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0xFF, + 0x07, 0x00, 0xC0, 0xFF, 0x07, 0x00, 0xE0, 0xC1, 0x03, 0x00, 0x38, 0x80, 0x03, 0x00, 0x0C, 0x80, + 0x01, 0x00, 0x06, 0xC0, 0x00, 0x00, 0x03, 0x68, 0x00, 0x80, 0x01, 0x3E, 0x00, 0xC0, 0x01, 0x1F, + 0x00, 0xC0, 0x83, 0x07, 0x00, 0xE0, 0xFF, 0x07, 0x00, 0xE0, 0xFF, 0x07, 0x00, 0xC0, 0x1F, 0x03, + 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0xC0, 0x60, 0x00, 0x00, + 0x60, 0x30, 0x00, 0x00, 0x30, 0x18, 0x00, 0x00, 0x18, 0x1C, 0x00, 0x00, 0x0C, 0x1E, 0x00, 0x00, + 0x8E, 0x7F, 0x00, 0x00, 0xFF, 0x7E, 0x00, 0x00, 0x7F, 0x3C, 0x00, 0x00, 0x0F, 0x10, 0x00, 0x80, + 0x87, 0x01, 0x00, 0xE0, 0xC7, 0x03, 0x00, 0xF0, 0xE3, 0x01, 0x00, 0x9C, 0xC3, 0x01, 0x00, 0x86, + 0xE1, 0x00, 0x00, 0xC3, 0x60, 0x00, 0x80, 0x61, 0x30, 0x00, 0xC0, 0x70, 0x18, 0x00, 0xE0, 0x30, + 0x0E, 0x00, 0xE0, 0xF8, 0x03, 0x00, 0x70, 0xF8, 0x01, 0x00, 0x30, 0x78, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, + 0x00, 0xF0, 0xFF, 0x07, 0x00, 0xF8, 0xFF, 0x03, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, + 0xF0, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x01, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, + 0x00, 0x07, 0x00, 0xF8, 0xFF, 0x01, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0xFE, 0x1F, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0xFE, + 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x80, 0x7F, + 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0xF0, 0x01, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0xFF, 0x01, 0x00, + 0x00, 0xFE, 0x0F, 0x00, 0x00, 0xF0, 0x1F, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xFC, 0x07, 0x00, + 0xC0, 0xFF, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x80, + 0xFF, 0x01, 0x00, 0x00, 0xFE, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, + 0xFE, 0x03, 0x00, 0xF0, 0x7F, 0x00, 0x00, 0xFE, 0x03, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x40, 0x00, 0x10, 0x00, 0x60, 0x00, 0x0C, 0x00, 0x70, 0x00, 0x07, 0x00, 0xF0, 0xE0, + 0x01, 0x00, 0xF0, 0x78, 0x00, 0x00, 0xF0, 0x1E, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF0, 0x01, + 0x00, 0x00, 0xDE, 0x03, 0x00, 0x80, 0xC7, 0x03, 0x00, 0xE0, 0xC1, 0x03, 0x00, 0x38, 0x80, 0x03, + 0x00, 0x0C, 0x80, 0x01, 0x00, 0x02, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, + 0xC0, 0x07, 0x00, 0x00, 0xC0, 0x07, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x00, 0xFF, 0x03, 0x00, + 0x00, 0xFF, 0x01, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0xC0, + 0x07, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x80, 0x03, 0x00, 0x0C, + 0xE0, 0x01, 0x00, 0x06, 0xFC, 0x00, 0x00, 0x83, 0x6F, 0x00, 0x80, 0xE1, 0x33, 0x00, 0xC0, 0x7C, + 0x18, 0x00, 0x60, 0x1F, 0x0C, 0x00, 0xF0, 0x03, 0x06, 0x00, 0x78, 0x00, 0x03, 0x00, 0x1C, 0x80, + 0x01, 0x00, 0xFE, 0xFF, 0x1F, 0x00, 0xFF, 0xFF, 0x0F, 0x80, 0xFF, 0xFF, 0x07, 0xC0, 0x00, 0x00, + 0x03, 0x60, 0x00, 0x80, 0x01, 0x10, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xF8, 0x01, 0x00, + 0x00, 0xE0, 0x07, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x60, 0x00, 0x80, 0x01, 0x30, 0x00, 0xC0, 0x00, 0xF8, 0xFF, 0x7F, 0x00, 0xFC, 0xFF, 0x3F, 0x00, + 0xFE, 0xFF, 0x1F, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xE0, + 0x03, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x1E, 0x00, 0x00, 0x98, 0x1F, 0x00, 0x00, 0xEE, 0x0F, 0x00, + 0x00, 0x73, 0x06, 0x00, 0x80, 0x19, 0x03, 0x00, 0xC0, 0x8C, 0x01, 0x00, 0x60, 0xE6, 0x00, 0x00, + 0xF0, 0x7F, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0xF0, 0x1F, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0xF0, + 0xFF, 0x07, 0x00, 0xF8, 0xFF, 0x03, 0x00, 0xC0, 0xC1, 0x01, 0x00, 0x60, 0xC0, 0x00, 0x00, 0x30, + 0x60, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x07, 0x00, 0x00, 0xFC, + 0x01, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x80, 0xFF, 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x70, 0x70, + 0x00, 0x00, 0x18, 0x30, 0x00, 0x00, 0x0C, 0x18, 0x00, 0x00, 0x06, 0x0C, 0x00, 0x00, 0x07, 0x07, + 0x00, 0x00, 0x83, 0x01, 0x00, 0x00, 0x41, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xE0, 0x3F, 0x00, + 0x00, 0xF8, 0x3F, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x06, 0x0C, 0x00, 0x00, 0x03, 0x06, 0x00, + 0x80, 0x83, 0x03, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, + 0xE0, 0x0F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0x37, 0x07, 0x00, 0x80, + 0x19, 0x03, 0x00, 0xC0, 0x8C, 0x01, 0x00, 0xE0, 0xC6, 0x00, 0x00, 0xF0, 0x73, 0x00, 0x00, 0xF0, + 0x19, 0x00, 0x00, 0xF0, 0x04, 0x00, 0x00, 0x06, 0x00, 0x00, 0xE0, 0xFF, 0x07, 0x00, 0xF8, 0xFF, + 0x03, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0x66, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x06, 0x00, 0xF0, 0x1F, + 0x07, 0x00, 0xFC, 0x9F, 0x03, 0x00, 0x0E, 0x8E, 0x01, 0x00, 0x03, 0xC6, 0x00, 0x80, 0x01, 0x63, + 0x00, 0xC0, 0xC1, 0x39, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0xF8, 0xFF, 0x00, + 0xC0, 0xFF, 0x1F, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0x80, 0x03, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xF8, 0x3F, 0x00, 0x00, + 0xF8, 0x1F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x30, 0xFF, 0x07, 0x00, 0x98, 0xFF, 0x03, 0x00, 0xCC, + 0xFF, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0xF3, 0xFF, 0x0F, 0x80, 0xF9, 0xFF, 0x07, 0xC0, 0xFC, + 0xFF, 0x01, 0xE0, 0xFF, 0x0F, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0xF8, 0xFF, 0x03, 0x00, 0x00, 0x0E, + 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xE0, 0x1E, 0x00, 0x00, 0x38, 0x1E, 0x00, 0x00, 0x0C, 0x1E, + 0x00, 0x00, 0x02, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0xF8, 0xFF, 0x03, 0x00, 0xFC, 0xFF, 0x01, + 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x00, 0xF8, 0x3F, 0x00, 0x00, 0xFC, 0x1F, 0x00, + 0x00, 0x0E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xC0, 0xFF, 0x01, 0x00, + 0xE0, 0xFF, 0x00, 0x00, 0xE0, 0x7F, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x80, 0xFF, 0x03, 0x00, 0x80, 0xFF, 0x01, 0x00, 0xE0, + 0xFF, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x00, 0xF8, 0x3F, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xC0, 0xFF, 0x01, 0x00, 0xC0, 0xFF, + 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xFE, 0x0F, + 0x00, 0x00, 0x07, 0x07, 0x00, 0x80, 0x01, 0x03, 0x00, 0xC0, 0x80, 0x01, 0x00, 0xE0, 0xE0, 0x00, + 0x00, 0xF0, 0x7F, 0x00, 0x00, 0xF0, 0x1F, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFE, 0xFF, 0x01, + 0x00, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0xC0, 0xC1, 0x01, 0x00, 0x60, 0xC0, 0x00, 0x00, + 0x30, 0x60, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x07, 0x00, 0x00, + 0xFC, 0x01, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x80, 0xFF, 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x70, + 0x70, 0x00, 0x00, 0x18, 0x30, 0x00, 0x00, 0x0C, 0x18, 0x00, 0x00, 0x0E, 0x0E, 0x00, 0x00, 0xFF, + 0xFF, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0xC0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0xF0, 0x7F, + 0x00, 0x00, 0xF8, 0x3F, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x8F, 0x01, 0x00, 0x80, 0xC7, 0x00, 0x00, 0xE0, 0xE7, 0x00, 0x00, 0x30, 0x63, 0x00, + 0x00, 0x98, 0x31, 0x00, 0x00, 0xCC, 0x19, 0x00, 0x00, 0xCE, 0x0F, 0x00, 0x00, 0xE6, 0x03, 0x00, + 0x00, 0xE3, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xFC, 0x7F, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x00, + 0xFF, 0x3F, 0x00, 0x00, 0x0C, 0x18, 0x00, 0x00, 0x06, 0x0C, 0x00, 0x00, 0xFF, 0x01, 0x00, 0x80, + 0xFF, 0x01, 0x00, 0xC0, 0xFF, 0x01, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x80, 0xFF, + 0x03, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xE0, 0x0F, + 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0xFE, 0x00, + 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x7C, 0x00, 0x00, 0x00, 0xFE, 0x03, 0x00, 0x00, 0xFC, 0x07, 0x00, 0x00, 0xF0, 0x03, 0x00, + 0x00, 0xFF, 0x01, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, + 0xF0, 0x1F, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xFC, 0x07, 0x00, 0x80, 0xFF, 0x00, 0x00, 0xC0, + 0x07, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x18, 0x30, 0x00, 0x00, 0x3C, + 0x1E, 0x00, 0x00, 0xBC, 0x07, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x7F, + 0x00, 0x00, 0xC0, 0x7B, 0x00, 0x00, 0xF0, 0x78, 0x00, 0x00, 0x18, 0x30, 0x00, 0x00, 0x04, 0x10, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x80, 0x3F, 0x60, 0x00, 0x00, 0x7F, 0x38, + 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x7F, 0x00, 0x00, 0xF0, 0x07, 0x00, + 0x00, 0xFE, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xC0, 0xC0, 0x01, 0x00, + 0x60, 0xF0, 0x00, 0x00, 0x30, 0x7C, 0x00, 0x00, 0x18, 0x37, 0x00, 0x00, 0xCC, 0x19, 0x00, 0x00, + 0x76, 0x0C, 0x00, 0x00, 0x1F, 0x06, 0x00, 0x80, 0x07, 0x03, 0x00, 0xC0, 0x81, 0x01, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0xC0, 0xFF, 0xFF, 0x03, 0xE0, 0x1F, + 0xFF, 0x01, 0x30, 0x00, 0xC0, 0x00, 0x18, 0x00, 0x60, 0x00, 0xFC, 0xFF, 0x3F, 0x00, 0xFE, 0xFF, + 0x1F, 0x00, 0xFF, 0xFF, 0x0F, 0x80, 0x01, 0x00, 0x06, 0xC0, 0x00, 0x00, 0x03, 0xE0, 0x1F, 0xFF, + 0x01, 0xF0, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0x3F, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x0C, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0xC0, 0xFF, 0x1F, 0x00, 0x20, 0x00, 0x08, 0x00, 0xF0, + 0xFF, 0x07, 0x00, 0xF8, 0xFF, 0x03, 0x00, 0x80, 0x0D, 0x00, 0x00, 0xF0, 0x1F, 0x00, 0x00, 0xFE, + 0x3F, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0xC0, 0xD9, 0x1C, 0x00, 0x60, 0x6C, 0x0C, 0x00, 0x30, 0x06, + 0x06, 0x00, 0x38, 0x80, 0x03, 0x00, 0x7C, 0xF0, 0x01, 0x00, 0x3C, 0x78, 0x00, 0x00, 0x18, 0x0C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x1E, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0C, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x0C, 0xFC, 0x03, 0x00, 0xFE, 0xFF, 0x01, 0xE0, 0xFF, 0x3F, 0x00, + 0xF8, 0x7F, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, + 0x00, 0x0D, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x80, 0xFF, 0x07, 0x00, 0xC0, 0xFF, 0x03, 0x00, 0xE0, 0xFF, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, + 0x84, 0x00, 0x00, 0xC0, 0xFF, 0x03, 0x00, 0xE0, 0xFF, 0x01, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x40, + 0x08, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x80, 0x3F, 0x00, + 0x00, 0xC0, 0x18, 0x08, 0x00, 0x20, 0x08, 0x06, 0x00, 0x30, 0xC6, 0x03, 0x00, 0xF8, 0xF3, 0x00, + 0x00, 0xF8, 0x1E, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xBC, 0x0F, 0x00, + 0x80, 0xE7, 0x0F, 0x00, 0xE0, 0x31, 0x06, 0x00, 0x30, 0x08, 0x02, 0x00, 0x08, 0x8C, 0x01, 0x00, + 0x00, 0xFE, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, + 0x60, 0x0C, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x18, 0x03, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, + 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x06, 0x00, 0x80, 0x1F, 0x0F, 0x00, 0xC0, 0x8F, + 0x07, 0x00, 0x71, 0x0E, 0x07, 0x80, 0x19, 0x86, 0x03, 0xC0, 0x0D, 0x83, 0x01, 0xC0, 0x86, 0xC1, + 0x00, 0x70, 0xC3, 0x61, 0x00, 0x98, 0xC3, 0x38, 0x00, 0x84, 0xE3, 0x0F, 0x00, 0xC0, 0xE1, 0x07, + 0x00, 0xC0, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0E, 0x00, + 0x00, 0x80, 0x0F, 0x00, 0x00, 0xE0, 0x0E, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x08, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x00, 0xFC, 0x7F, 0x00, 0x00, + 0x0F, 0x78, 0x00, 0x80, 0x03, 0x38, 0x00, 0xC0, 0x00, 0x18, 0x00, 0x60, 0x00, 0x0C, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x78, 0xC0, 0x03, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFF, + 0x7F, 0x00, 0x80, 0x61, 0x30, 0x00, 0xC0, 0x30, 0x18, 0x00, 0x60, 0x18, 0x0C, 0x00, 0x30, 0x0C, + 0x06, 0x00, 0x18, 0x06, 0x03, 0x00, 0x0C, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x70, + 0x00, 0x80, 0x01, 0x3C, 0x00, 0xC4, 0x80, 0x1F, 0x00, 0x66, 0xF0, 0x0D, 0x00, 0x37, 0x7C, 0x06, + 0x00, 0x9B, 0x0F, 0x03, 0xC0, 0xED, 0x83, 0x01, 0x60, 0x7E, 0xC0, 0x00, 0x10, 0x0F, 0x60, 0x00, + 0x80, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, + 0xF0, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x0F, + 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, + 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x0F, 0x00, + 0x00, 0x80, 0x07, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0E, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0x00, + 0x00, 0xF0, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xFC, + 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xC0, 0x0F, + 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x00, + 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1E, 0x03, 0x00, 0x08, 0x8F, 0x01, 0x00, 0xCC, 0xCF, 0x01, 0x00, 0x6E, 0xC6, 0x00, + 0x00, 0x36, 0x63, 0x00, 0x80, 0x9B, 0x33, 0x00, 0xC0, 0x9C, 0x1F, 0x00, 0x20, 0xCC, 0x07, 0x00, + 0x00, 0xC6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x80, 0x31, 0x00, 0x00, + 0xC0, 0x1D, 0x00, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x80, 0xFF, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x70, + 0x70, 0x00, 0x00, 0x18, 0x30, 0x00, 0x00, 0x0C, 0x18, 0x00, 0x00, 0x06, 0x0C, 0x00, 0x00, 0x07, + 0x07, 0x00, 0x00, 0xFF, 0x01, 0x00, 0x80, 0xFF, 0x00, 0x00, 0xE0, 0x7F, 0x00, 0x00, 0x70, 0x73, + 0x00, 0x00, 0x98, 0x31, 0x00, 0x00, 0xCC, 0x18, 0x00, 0x00, 0x6E, 0x0C, 0x00, 0x00, 0x3F, 0x07, + 0x00, 0x00, 0x9F, 0x01, 0x00, 0x00, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x70, 0x00, + 0x80, 0x18, 0x3C, 0x00, 0xC0, 0x0C, 0x1F, 0x00, 0xE0, 0xC6, 0x0D, 0x00, 0x60, 0x73, 0x06, 0x00, + 0xB8, 0x1D, 0x03, 0x00, 0xCC, 0x87, 0x01, 0x00, 0xE2, 0xC1, 0x00, 0x00, 0x70, 0x60, 0x00, 0x80, + 0x01, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xE6, 0x03, 0x00, 0x00, 0xC3, + 0x07, 0x00, 0x80, 0x81, 0xFF, 0x01, 0x00, 0x80, 0xFF, 0x00, 0x60, 0xE0, 0x7F, 0x00, 0x30, 0x7C, + 0x00, 0x00, 0x98, 0x0F, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xFF, 0x0F, 0x00, 0x98, 0xFF, + 0x07, 0x00, 0xCC, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xFF, 0x01, + 0x00, 0xC0, 0xFF, 0x07, 0x00, 0xE0, 0xF0, 0x03, 0x00, 0x30, 0x7F, 0x00, 0x00, 0xF8, 0x33, 0x00, + 0x00, 0x3F, 0x18, 0x00, 0x80, 0x0F, 0x0E, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x82, 0x00, 0x00, + 0x00, 0x86, 0x01, 0x00, 0xF8, 0xE3, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x80, 0xFF, 0x1F, 0x00, 0xC0, + 0xE1, 0x0D, 0x00, 0x60, 0x30, 0x06, 0x00, 0x30, 0x18, 0x07, 0x00, 0x38, 0x0C, 0x03, 0x00, 0x3C, + 0x80, 0x01, 0x00, 0x1C, 0xE0, 0x00, 0x00, 0x0C, 0x70, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0xFE, + 0x07, 0x00, 0x00, 0xFF, 0x03, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x80, 0x73, 0x00, 0x00, 0xC0, 0x30, + 0x00, 0x00, 0xE0, 0x1C, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 0xFE, 0x07, + 0x00, 0x00, 0x02, 0x01, 0x00, 0x70, 0xD8, 0x00, 0x00, 0x78, 0x6C, 0x00, 0x00, 0xF8, 0x36, 0x00, + 0x00, 0xF0, 0x1B, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0xFC, 0x1F, 0x00, + 0x00, 0xBF, 0x01, 0x00, 0xE0, 0xDB, 0x00, 0x00, 0x78, 0x6C, 0x00, 0x00, 0x1C, 0x36, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7F, 0xF8, 0x07, 0xC0, 0x3F, 0xFC, 0x03, 0xE0, + 0x1F, 0xFE, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x70, 0x3F, 0x0C, 0x00, 0xFE, + 0x3F, 0x0E, 0x00, 0x7F, 0x3C, 0x0F, 0x80, 0x79, 0x1C, 0x06, 0xC0, 0x78, 0x1C, 0x03, 0xE0, 0x78, + 0xFE, 0x01, 0x60, 0xF8, 0x7F, 0x00, 0x30, 0xF8, 0x1C, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xC0, 0x07, 0x00, + 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x0E, 0x0E, 0x00, 0x80, 0x01, 0x0C, 0x00, 0x40, 0x7C, 0x04, 0x00, + 0x30, 0x7F, 0x06, 0x00, 0xC8, 0x7F, 0x02, 0x00, 0x64, 0x30, 0x01, 0x00, 0x12, 0x90, 0x00, 0x00, + 0x19, 0x4C, 0x00, 0x80, 0x0D, 0x36, 0x00, 0x80, 0x04, 0x09, 0x00, 0xC0, 0x00, 0x06, 0x00, 0xC0, + 0xC1, 0x01, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x64, 0x02, 0x00, 0x00, 0x7B, + 0x01, 0x00, 0x80, 0xBD, 0x00, 0x00, 0x40, 0x52, 0x00, 0x00, 0xE0, 0x2F, 0x00, 0x00, 0xF0, 0x17, + 0x00, 0x00, 0xF0, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0x78, 0x0F, 0x00, 0x00, 0x4C, 0x06, 0x00, 0x00, 0x72, 0x02, + 0x00, 0x00, 0xFE, 0x00, 0x00, 0x80, 0xF7, 0x00, 0x00, 0xC0, 0x60, 0x00, 0x00, 0x20, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0xF8, 0x01, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0xC0, 0x7F, + 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x0C, 0x60, 0x00, 0x00, 0xF2, 0x2F, 0x00, 0x80, 0xF9, 0x37, + 0x00, 0x40, 0xFC, 0x13, 0x00, 0x20, 0x22, 0x08, 0x00, 0x10, 0x71, 0x04, 0x00, 0x88, 0x7F, 0x02, + 0x00, 0xCC, 0xBF, 0x01, 0x00, 0xC4, 0x51, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x0E, 0x0E, 0x00, + 0x00, 0xFE, 0x03, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0xC0, 0x07, + 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x38, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x61, 0x00, 0x00, 0xC0, 0x30, 0x00, 0x00, 0x60, 0x18, + 0x00, 0x00, 0x30, 0x0C, 0x00, 0x80, 0xFF, 0x07, 0x00, 0xC0, 0xFF, 0x03, 0x00, 0xE0, 0xFF, 0x01, + 0x00, 0x00, 0xC3, 0x00, 0x00, 0x80, 0x61, 0x00, 0x00, 0xC0, 0x30, 0x00, 0x00, 0x60, 0x18, 0x00, + 0x40, 0x08, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x98, 0x03, 0x00, 0x00, 0xE4, 0x01, 0x00, 0x00, + 0xBE, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x60, + 0x0C, 0x00, 0x00, 0xB0, 0x06, 0x00, 0x00, 0x48, 0x02, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0xEE, + 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x07, 0x00, 0xFC, 0xFF, 0x03, 0x00, 0xFE, 0xFF, + 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xE0, 0x00, + 0x00, 0xF0, 0x7F, 0x00, 0x00, 0xF8, 0x3F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x00, 0x0C, 0x00, + 0xC0, 0x03, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x00, + 0xFF, 0xFF, 0x0F, 0x80, 0xFF, 0xFF, 0x07, 0xC0, 0xFF, 0xFF, 0x03, 0x60, 0x00, 0x00, 0x00, 0xF0, + 0xFF, 0xFF, 0x00, 0xF8, 0xFF, 0x7F, 0x00, 0xFC, 0xFF, 0x3F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x00, 0xF8, 0x03, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x3E, 0x01, 0x00, + 0x80, 0xBF, 0x00, 0x00, 0xC0, 0x5F, 0x00, 0x00, 0x20, 0x28, 0x00, 0x00, 0xF0, 0x17, 0x00, 0x00, + 0xF8, 0x0B, 0x00, 0x00, 0xF8, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, + 0x30, 0x18, 0x00, 0x00, 0x78, 0x0F, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x72, 0x02, 0x00, 0x00, + 0x93, 0x01, 0x00, 0x80, 0xF7, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xF8, 0x03, + 0x02, 0x00, 0xFC, 0x81, 0x01, 0x00, 0xFE, 0x60, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x38, 0x06, 0x00, 0x00, 0x86, 0x03, 0x00, 0xC0, 0x71, 0x01, + 0x00, 0x70, 0xFC, 0x01, 0x00, 0x0C, 0xFE, 0x00, 0x00, 0x03, 0x7F, 0x00, 0x80, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0xF8, 0x03, 0x03, 0x00, + 0xFC, 0xC1, 0x00, 0x00, 0xFE, 0x38, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x80, 0x23, 0x04, 0x00, 0xE0, 0x18, 0x03, 0x00, 0x18, + 0xCC, 0x01, 0x00, 0x06, 0xF2, 0x00, 0x00, 0x01, 0x5F, 0x00, 0x00, 0x80, 0x27, 0x00, 0x00, 0x80, + 0x11, 0x00, 0x40, 0x04, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x58, 0x03, 0x02, 0x00, 0x24, 0x81, + 0x01, 0x00, 0xFE, 0x60, 0x00, 0x00, 0x77, 0x1C, 0x00, 0x00, 0x1B, 0x07, 0x00, 0x00, 0xE0, 0x00, + 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x06, 0x03, 0x00, 0xC0, 0xC1, 0x01, 0x00, 0x70, 0xB8, 0x00, + 0x00, 0x0C, 0xFE, 0x00, 0x00, 0x03, 0x7F, 0x00, 0x80, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0xC0, 0x1F, 0x00, + 0x00, 0xF0, 0x1F, 0x00, 0x30, 0x3F, 0x0E, 0x00, 0x98, 0x0F, 0x06, 0x00, 0xCC, 0x81, 0x03, 0x00, + 0x00, 0xE0, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, + 0xF8, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x04, 0xFF, 0x01, 0x00, 0xE6, 0xDF, + 0x00, 0x00, 0xF7, 0x61, 0x00, 0x80, 0xFB, 0x30, 0x00, 0x00, 0xFD, 0x1B, 0x00, 0x00, 0xF8, 0x0F, + 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x0C, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xFC, 0x01, 0x00, 0xC0, 0x3F, 0x00, + 0x00, 0xFC, 0x07, 0x00, 0xA0, 0x7F, 0x03, 0x00, 0xDC, 0x87, 0x01, 0x00, 0xEE, 0xC3, 0x00, 0x00, + 0xF3, 0x6F, 0x00, 0x80, 0xE0, 0x3F, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, + 0x00, 0x7C, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, + 0xF0, 0x07, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xF1, 0x1F, 0x00, 0xC0, 0xFE, 0x0D, 0x00, 0x70, 0x1F, + 0x06, 0x00, 0x98, 0x0F, 0x03, 0x00, 0xDC, 0xBF, 0x01, 0x00, 0x8C, 0xFF, 0x00, 0x00, 0x04, 0xFE, + 0x01, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, + 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x08, 0xFC, 0x03, 0x00, 0xC6, 0x7F, 0x00, + 0x00, 0xF9, 0x37, 0x00, 0x80, 0x7D, 0x18, 0x00, 0xC0, 0x3E, 0x0C, 0x00, 0x40, 0xFF, 0x06, 0x00, + 0x30, 0xFE, 0x03, 0x00, 0x08, 0xF8, 0x07, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0xC0, 0x07, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, + 0xF0, 0x0F, 0x00, 0x18, 0xFF, 0x01, 0x00, 0xEC, 0xDF, 0x00, 0x00, 0xF6, 0x61, 0x00, 0x00, 0xF8, + 0x30, 0x00, 0x80, 0xFD, 0x1B, 0x00, 0xC0, 0xF8, 0x0F, 0x00, 0x60, 0xE0, 0x1F, 0x00, 0x00, 0x80, + 0x3F, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0xE0, + 0x03, 0x00, 0x00, 0xFC, 0x01, 0x00, 0xC0, 0x3F, 0x00, 0x00, 0xFC, 0x07, 0x00, 0xB0, 0x7F, 0x03, + 0x00, 0xFC, 0x87, 0x01, 0x00, 0xF2, 0xC3, 0x00, 0x00, 0xFF, 0x6F, 0x00, 0x00, 0xE3, 0x3F, 0x00, + 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0xF0, 0x01, 0x00, + 0x00, 0x3E, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0x3E, 0x03, 0x00, 0xC0, + 0x8F, 0x01, 0x00, 0xE0, 0xC1, 0x00, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0xF8, 0xFF, 0x03, 0x00, 0xFC, + 0xFF, 0x01, 0x00, 0x86, 0xC1, 0x00, 0x00, 0xC3, 0x60, 0x00, 0x80, 0x61, 0x30, 0x00, 0xC0, 0x30, + 0x18, 0x00, 0x60, 0x18, 0x0C, 0x00, 0x30, 0x0C, 0x06, 0x00, 0x18, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFF, 0x1F, 0x00, 0x80, 0x07, 0x0F, + 0x00, 0xE0, 0x00, 0x0E, 0x00, 0x30, 0x00, 0x46, 0x00, 0x18, 0x00, 0x2F, 0x00, 0x0C, 0x80, 0x1F, + 0x00, 0x0E, 0xE0, 0x0E, 0x00, 0x07, 0x70, 0x03, 0x00, 0x0F, 0x1E, 0x00, 0x00, 0x07, 0x0F, 0x00, + 0x00, 0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x03, 0x00, 0xFC, 0xFF, 0x01, 0x00, + 0xFE, 0xFF, 0x00, 0x10, 0xC3, 0x60, 0x00, 0x98, 0x61, 0x30, 0x00, 0xDC, 0x30, 0x18, 0x00, 0x6E, + 0x18, 0x0C, 0x00, 0x34, 0x0C, 0x06, 0x00, 0x18, 0x06, 0x03, 0x00, 0x0C, 0x83, 0x01, 0x00, 0x06, + 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0xC0, 0xFF, 0x1F, 0x00, 0xE0, 0xFF, + 0x0F, 0x00, 0x30, 0x0C, 0x06, 0x00, 0x1A, 0x06, 0x03, 0xC0, 0x0D, 0x83, 0x01, 0xE0, 0x86, 0xC1, + 0x00, 0x30, 0xC3, 0x60, 0x00, 0x88, 0x61, 0x30, 0x00, 0xC0, 0x30, 0x18, 0x00, 0x60, 0x00, 0x0C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x03, 0x00, 0xFC, 0xFF, 0x01, 0x80, 0xFE, 0xFF, 0x00, + 0x60, 0xC3, 0x60, 0x00, 0xB8, 0x61, 0x30, 0x00, 0xCC, 0x30, 0x18, 0x00, 0x6E, 0x18, 0x0C, 0x00, + 0x36, 0x0C, 0x06, 0x00, 0x1A, 0x06, 0x03, 0x00, 0x0C, 0x83, 0x01, 0x00, 0x06, 0xC0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0xC0, 0xFF, 0x1F, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0x36, + 0x0C, 0x06, 0x00, 0x1B, 0x06, 0x03, 0x80, 0x0D, 0x83, 0x01, 0x00, 0x86, 0xC1, 0x00, 0x60, 0xC3, + 0x60, 0x00, 0xB0, 0x61, 0x30, 0x00, 0xD8, 0x30, 0x18, 0x00, 0x60, 0x00, 0x0C, 0x00, 0x01, 0x00, + 0x00, 0x80, 0xF9, 0xFF, 0x03, 0xC0, 0xFD, 0xFF, 0x01, 0xE0, 0xFE, 0xFF, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xFF, 0x1F, 0x00, 0xEE, 0xFF, 0x0F, 0x00, 0xF7, 0xFF, 0x07, + 0x80, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x70, 0xFF, 0x7F, 0x00, + 0x98, 0xFF, 0x3F, 0x00, 0xDC, 0xFF, 0x1F, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x80, 0xFD, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x60, 0xFF, 0x7F, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0xF8, + 0xFF, 0x03, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0x86, 0xC1, 0x00, 0x00, 0xC3, 0x60, 0x00, 0x80, 0x61, + 0x30, 0x00, 0xC0, 0x00, 0x18, 0x00, 0xE0, 0x00, 0x0E, 0x00, 0xE0, 0x80, 0x03, 0x00, 0xF0, 0xFF, + 0x01, 0x00, 0xF0, 0x7F, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x3F, + 0x00, 0xC0, 0xFF, 0x1F, 0x00, 0xE8, 0xFF, 0x0F, 0x00, 0xE6, 0x03, 0x00, 0x00, 0xE1, 0x07, 0x00, + 0x80, 0xC1, 0x07, 0x00, 0xC0, 0x80, 0x0F, 0x00, 0x40, 0x80, 0x1F, 0x00, 0x30, 0x00, 0x1F, 0x00, + 0xC8, 0xFF, 0x1F, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC0, 0x1F, 0x00, 0x00, 0xF8, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x0F, 0x1E, 0x00, 0xC4, + 0x01, 0x1C, 0x00, 0x66, 0x00, 0x0C, 0x00, 0x37, 0x00, 0x06, 0x80, 0x1B, 0x00, 0x03, 0x00, 0x0D, + 0x80, 0x01, 0x00, 0x0E, 0xE0, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0xFF, 0x1F, 0x00, 0x00, 0xFF, + 0x07, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xF0, 0x7F, + 0x00, 0x00, 0xFC, 0x7F, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x80, 0x03, 0x38, 0x00, 0xD0, 0x00, 0x18, + 0x00, 0x6E, 0x00, 0x0C, 0x00, 0x37, 0x00, 0x06, 0x80, 0x19, 0x00, 0x03, 0x40, 0x1C, 0xC0, 0x01, + 0x00, 0x3C, 0x78, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0xFC, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, + 0x3C, 0x78, 0x00, 0x40, 0x07, 0x70, 0x00, 0xB0, 0x01, 0x30, 0x00, 0xDC, 0x00, 0x18, 0x00, 0x66, + 0x00, 0x0C, 0x00, 0x37, 0x00, 0x06, 0x00, 0x3B, 0x80, 0x03, 0x00, 0x79, 0xF0, 0x00, 0x00, 0xFC, + 0x7F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, + 0x00, 0x00, 0xC0, 0xFF, 0x01, 0x00, 0xF0, 0xFF, 0x01, 0x00, 0x79, 0xF0, 0x00, 0xC0, 0x0E, 0xE0, + 0x00, 0x20, 0x03, 0x60, 0x00, 0xB0, 0x01, 0x30, 0x00, 0xD8, 0x00, 0x18, 0x00, 0x68, 0x00, 0x0C, + 0x00, 0x76, 0x00, 0x07, 0x00, 0xF1, 0xE0, 0x01, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0x3F, 0x00, + 0x00, 0xF0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x80, 0xFF, 0x03, 0x00, + 0xE0, 0xFF, 0x03, 0x00, 0xF0, 0xE0, 0x01, 0x80, 0x1D, 0xC0, 0x01, 0xC0, 0x06, 0xC0, 0x00, 0x60, + 0x03, 0x60, 0x00, 0x80, 0x01, 0x30, 0x00, 0xD8, 0x00, 0x18, 0x00, 0xEC, 0x00, 0x0E, 0x00, 0xE6, + 0xC1, 0x03, 0x00, 0xF0, 0xFF, 0x01, 0x00, 0xF0, 0x7F, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x8E, 0x03, 0x00, 0x00, 0xEF, 0x01, 0x00, 0x00, 0x7F, + 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0x78, 0x0F, + 0x00, 0x00, 0x1C, 0x07, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x04, + 0x00, 0xE0, 0xFF, 0x03, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x3C, 0x78, 0x00, 0x00, 0x07, 0x76, 0x00, + 0x80, 0x81, 0x39, 0x00, 0xC0, 0x60, 0x18, 0x00, 0x60, 0x18, 0x0C, 0x00, 0x70, 0x06, 0x06, 0x00, + 0xB8, 0x81, 0x03, 0x00, 0x78, 0xF0, 0x00, 0x00, 0xFC, 0x7F, 0x00, 0x00, 0xFF, 0x1F, 0x00, 0x80, + 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x01, 0x00, 0xF0, 0xFF, 0x03, 0x00, 0xF8, + 0xFF, 0x01, 0x40, 0x00, 0xC0, 0x01, 0x60, 0x00, 0xC0, 0x00, 0x70, 0x00, 0x60, 0x00, 0x38, 0x00, + 0x30, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0E, 0x00, 0xF0, 0xFF, 0x03, 0x00, 0xF8, 0xFF, + 0x01, 0x00, 0xFC, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0x00, 0x80, 0xFF, 0x1F, + 0x00, 0xC0, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x04, 0x00, 0x06, 0x80, 0x03, 0x00, 0x03, + 0xC0, 0x01, 0x80, 0x01, 0x60, 0x00, 0xC0, 0x00, 0x10, 0x00, 0x70, 0x00, 0x80, 0xFF, 0x1F, 0x00, + 0xC0, 0xFF, 0x0F, 0x00, 0xE0, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, + 0xFC, 0xFF, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x40, 0x00, 0x70, 0x00, 0x30, 0x00, 0x30, 0x00, 0x1C, + 0x00, 0x18, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x06, 0x00, 0x03, 0x80, 0x03, 0x00, 0xFD, + 0xFF, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x00, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, + 0x03, 0x00, 0xE0, 0xFF, 0x07, 0x00, 0xF6, 0xFF, 0x03, 0x00, 0x03, 0x80, 0x03, 0x80, 0x01, 0x80, + 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x30, 0x00, 0x30, 0x00, 0x18, 0x00, 0x1C, + 0x00, 0xEC, 0xFF, 0x07, 0x00, 0xF0, 0xFF, 0x03, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x0C, 0x00, 0x00, + 0x00, 0x0E, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, + 0x08, 0xFC, 0x0F, 0x00, 0x07, 0xFC, 0x07, 0x80, 0x03, 0xFF, 0x03, 0xC0, 0xE0, 0x03, 0x00, 0x20, + 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0xF8, 0xFF, 0x03, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0x30, + 0x18, 0x00, 0x00, 0x18, 0x0C, 0x00, 0x00, 0x0C, 0x06, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0xC7, + 0x01, 0x00, 0x80, 0xFF, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFC, 0x7F, 0x00, 0x00, 0xFF, 0x3F, 0x00, 0xC0, 0xFF, 0x1F, 0x00, 0xE0, 0x00, 0x06, + 0x00, 0x30, 0x00, 0x07, 0x00, 0x18, 0x8F, 0x03, 0x00, 0xFC, 0x8F, 0x01, 0x00, 0xFE, 0xC7, 0x00, + 0x00, 0x1E, 0x7F, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xC4, 0x03, 0x00, 0x00, 0xF3, 0x03, 0x00, 0xC4, 0xFD, 0x01, 0x00, 0x66, 0xCE, 0x00, 0x00, + 0x37, 0x63, 0x00, 0x80, 0x9B, 0x31, 0x00, 0x00, 0xCD, 0x1C, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, + 0xFE, 0x07, 0x00, 0x00, 0xFE, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x78, 0x00, 0x00, 0x60, + 0x7E, 0x00, 0x00, 0xB8, 0x3F, 0x00, 0x00, 0xCC, 0x19, 0x00, 0x80, 0x66, 0x0C, 0x00, 0x70, 0x33, + 0x06, 0x00, 0xB8, 0x99, 0x03, 0x00, 0xCC, 0xFF, 0x01, 0x00, 0xC2, 0xFF, 0x00, 0x00, 0xC0, 0x7F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0F, 0x00, 0x00, 0xCC, 0x0F, 0x00, 0x40, 0xF7, 0x07, + 0x00, 0xB0, 0x39, 0x03, 0x00, 0xDC, 0x8C, 0x01, 0x00, 0x66, 0xC6, 0x00, 0x00, 0x37, 0x73, 0x00, + 0x00, 0xFB, 0x3F, 0x00, 0x00, 0xF9, 0x1F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE2, 0x01, 0x00, 0x80, 0xF9, 0x01, 0x00, 0xE8, 0xFE, 0x00, 0x00, 0x36, 0x67, 0x00, 0x00, + 0x99, 0x31, 0x00, 0x80, 0xCD, 0x18, 0x00, 0xC0, 0x66, 0x0E, 0x00, 0x40, 0xFF, 0x07, 0x00, 0x30, + 0xFF, 0x03, 0x00, 0x08, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x3C, 0x00, 0x00, 0x30, + 0x3F, 0x00, 0x80, 0xDD, 0x1F, 0x00, 0xC0, 0xE6, 0x0C, 0x00, 0x60, 0x33, 0x06, 0x00, 0x80, 0x19, + 0x03, 0x00, 0xD8, 0xCC, 0x01, 0x00, 0xEC, 0xFF, 0x00, 0x00, 0xE6, 0x7F, 0x00, 0x00, 0xE0, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x07, 0x00, 0x00, 0xE6, 0x07, 0x00, 0x80, 0xFB, 0x03, + 0x00, 0xCC, 0x9C, 0x01, 0x00, 0x6F, 0xC6, 0x00, 0x80, 0x34, 0x63, 0x00, 0xC0, 0x9B, 0x39, 0x00, + 0xC0, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 0xFC, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0xF1, 0x00, 0x00, 0xC0, 0xFC, 0x00, 0x00, 0x70, 0x7F, 0x00, 0x00, 0x98, 0x33, 0x00, 0x00, + 0xCC, 0x18, 0x00, 0x00, 0x66, 0x0E, 0x00, 0x00, 0xFF, 0x03, 0x00, 0x00, 0xFF, 0x01, 0x00, 0xC0, + 0xFF, 0x01, 0x00, 0xE0, 0xE6, 0x00, 0x00, 0x30, 0x63, 0x00, 0x00, 0x98, 0x31, 0x00, 0x00, 0xDC, + 0x18, 0x00, 0x00, 0x7E, 0x0E, 0x00, 0x00, 0x3E, 0x03, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0xF8, 0x3F, 0x00, 0x00, 0x1C, 0x1C, + 0x01, 0x00, 0x06, 0xBC, 0x00, 0x00, 0x03, 0x7E, 0x00, 0x80, 0x01, 0x3B, 0x00, 0xC0, 0xC1, 0x0D, + 0x00, 0xC0, 0x60, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, + 0x00, 0xFC, 0x07, 0x00, 0x10, 0xFF, 0x07, 0x00, 0x98, 0x9B, 0x03, 0x00, 0xDC, 0x8C, 0x01, 0x00, + 0x6E, 0xC6, 0x00, 0x00, 0x74, 0x63, 0x00, 0x00, 0xF8, 0x39, 0x00, 0x00, 0xF8, 0x0C, 0x00, 0x00, + 0x78, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x80, 0xFF, 0x00, 0x00, 0xE0, + 0xFF, 0x00, 0x00, 0x74, 0x73, 0x00, 0x80, 0x9B, 0x31, 0x00, 0xC0, 0xCD, 0x18, 0x00, 0x60, 0x6E, + 0x0C, 0x00, 0x10, 0x3F, 0x07, 0x00, 0x00, 0x9F, 0x01, 0x00, 0x00, 0x4F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xF0, 0x1F, 0x00, 0x00, 0xFD, 0x1F, 0x00, 0xC0, 0x6E, 0x0E, + 0x00, 0x70, 0x33, 0x06, 0x00, 0x98, 0x19, 0x03, 0x00, 0xDC, 0x8D, 0x01, 0x00, 0xEC, 0xE7, 0x00, + 0x00, 0xE4, 0x33, 0x00, 0x00, 0xE0, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x03, 0x00, + 0x60, 0xFE, 0x03, 0x00, 0xB0, 0xFF, 0x03, 0x00, 0xD8, 0xCD, 0x01, 0x00, 0x60, 0xC6, 0x00, 0x00, + 0x30, 0x63, 0x00, 0x00, 0xBB, 0x31, 0x00, 0x80, 0xFD, 0x1C, 0x00, 0xC0, 0x7C, 0x06, 0x00, 0x00, + 0x3C, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0xDC, 0xFF, 0x01, 0x00, 0xEE, 0xFF, 0x00, 0x00, 0xF4, + 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x1F, 0x00, 0xE0, 0xFE, 0x0F, 0x00, 0x70, 0xFF, + 0x07, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xF7, 0x7F, + 0x00, 0x80, 0xF9, 0x3F, 0x00, 0xC0, 0xFD, 0x1F, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0xD8, 0xFF, 0x01, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0xF6, 0x7F, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, + 0x00, 0xFF, 0x01, 0x00, 0xD4, 0xFF, 0x01, 0x00, 0xEA, 0xE0, 0x00, 0x00, 0x37, 0x60, 0x00, 0x80, + 0x1B, 0x30, 0x00, 0xC0, 0x1F, 0x1C, 0x00, 0xA0, 0xFF, 0x0F, 0x00, 0x90, 0xFF, 0x03, 0x00, 0x00, + 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0xF4, 0x7F, 0x00, 0x00, 0xFB, + 0x3F, 0x00, 0x80, 0x1C, 0x00, 0x00, 0xC0, 0x06, 0x00, 0x00, 0x60, 0x03, 0x00, 0x00, 0xA0, 0x03, + 0x00, 0x00, 0xD8, 0xFF, 0x01, 0x00, 0xC4, 0xFF, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFC, 0x07, 0x00, 0x10, 0xFF, 0x07, 0x00, 0x98, 0x83, 0x03, + 0x00, 0xDC, 0x80, 0x01, 0x00, 0x6E, 0xC0, 0x00, 0x00, 0x74, 0x70, 0x00, 0x00, 0xF8, 0x3F, 0x00, + 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, + 0x80, 0xFF, 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x74, 0x70, 0x00, 0x80, 0x1B, 0x30, 0x00, 0xC0, + 0x0D, 0x18, 0x00, 0x60, 0x0E, 0x0E, 0x00, 0x10, 0xFF, 0x07, 0x00, 0x00, 0xFF, 0x01, 0x00, 0x00, + 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xF0, 0x1F, 0x00, 0x00, 0xFD, + 0x1F, 0x00, 0xC0, 0x0E, 0x0E, 0x00, 0x70, 0x03, 0x06, 0x00, 0x98, 0x01, 0x03, 0x00, 0xDC, 0xC1, + 0x01, 0x00, 0xEC, 0xFF, 0x00, 0x00, 0xE4, 0x3F, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xF8, 0x03, 0x00, 0x40, 0xFE, 0x03, 0x00, 0xB0, 0xFF, 0x03, 0x00, 0xC8, 0xC1, 0x01, + 0x00, 0x6C, 0xC0, 0x00, 0x00, 0x36, 0x60, 0x00, 0x00, 0x3A, 0x38, 0x00, 0x80, 0xFD, 0x1F, 0x00, + 0x40, 0xFC, 0x07, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, + 0xCC, 0x7F, 0x00, 0x00, 0xF6, 0x7F, 0x00, 0x00, 0x3B, 0x38, 0x00, 0x00, 0x0C, 0x18, 0x00, 0x00, + 0x06, 0x0C, 0x00, 0x60, 0x07, 0x07, 0x00, 0xB0, 0xFF, 0x03, 0x00, 0x98, 0xFF, 0x00, 0x00, 0x80, + 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x80, 0x6D, 0x00, 0x00, 0xC0, 0x36, 0x00, 0x00, 0x60, 0x1B, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x02, 0x00, 0x80, 0xFF, 0x01, 0x00, 0xE0, 0xFF, 0x00, + 0x00, 0x70, 0x7C, 0x00, 0x00, 0x18, 0x37, 0x00, 0x00, 0xEC, 0x18, 0x00, 0x00, 0x3E, 0x0E, 0x00, + 0x00, 0xFF, 0x07, 0x00, 0x80, 0xFF, 0x01, 0x00, 0x40, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF0, 0x1F, 0x00, 0x00, 0xF8, 0x1F, 0x00, 0x40, 0xFC, 0x1F, 0x00, 0x60, 0x00, 0x0E, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x38, 0x00, 0x03, 0x00, 0x10, 0xC0, 0x01, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0xF0, + 0x7F, 0x00, 0x00, 0xF8, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x03, 0x00, 0x00, 0xFF, + 0x03, 0x00, 0x80, 0xFF, 0x03, 0x00, 0x10, 0xC0, 0x01, 0x00, 0x0E, 0xC0, 0x00, 0x00, 0x07, 0x60, + 0x00, 0x80, 0x01, 0x38, 0x00, 0x40, 0xFC, 0x1F, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0xFF, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0xE0, 0x7F, 0x00, 0x00, 0xF4, 0x7F, 0x00, + 0x00, 0x03, 0x38, 0x00, 0xC0, 0x01, 0x18, 0x00, 0x60, 0x00, 0x0C, 0x00, 0x70, 0x00, 0x07, 0x00, + 0xB0, 0xFF, 0x03, 0x00, 0xD0, 0xFF, 0x01, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0x0F, 0x00, 0x80, 0xFD, 0x0F, 0x00, 0xC0, 0xFE, 0x0F, 0x00, 0x60, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0C, 0xE0, 0x00, 0x00, 0xF6, 0x7F, 0x00, 0x00, 0xFB, + 0x3F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x80, 0x3F, + 0x60, 0x00, 0x00, 0x7F, 0x38, 0x00, 0x08, 0xFC, 0x1F, 0x00, 0x07, 0xF8, 0x03, 0x80, 0x03, 0x7F, + 0x00, 0xC0, 0xF0, 0x07, 0x00, 0x20, 0xFE, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x80, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x1F, 0x00, 0xFF, 0xFF, 0x0F, 0x80, 0xFF, 0xFF, 0x07, + 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x06, 0x0C, 0x00, 0x00, 0x03, 0x06, 0x00, 0x80, 0x83, 0x03, 0x00, + 0xC0, 0xFF, 0x01, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x7C, 0x00, 0x03, 0xC0, 0xFE, 0x80, 0x01, 0x60, 0xFC, 0xE1, 0x00, 0x30, 0xF0, 0x7F, 0x00, 0x00, + 0xE0, 0x0F, 0x00, 0x0C, 0xFC, 0x01, 0x00, 0xC6, 0x1F, 0x00, 0x00, 0xFB, 0x03, 0x00, 0x00, 0x7C, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00 +}; + +static struct fontDesc_t const HoloLens_20_Desc = { + sizeof(HoloLens_20_Bytes), // total Size + 21, // width in pixel + 31, // height in pixel + 1, // bits per pixel + 0x0B, // Code of first char + 0xFF, // Code of last char + HoloLens_20_Bytes // Data +}; + +#endif diff --git a/lib/Display/Fonts/Roboto_12.h b/lib/Display/Fonts/Roboto_12.h new file mode 100644 index 0000000..e88e216 --- /dev/null +++ b/lib/Display/Fonts/Roboto_12.h @@ -0,0 +1,371 @@ +/* + created with FontEditor written by H. Reddmann + HaReddmann at t-online dot de + + File Name : Roboto_12.h + Date : 12.03.2019 + Font size in bytes : 0x12EE, 4846 + Font width : 11 + Font height : 21 + Font first char : 0x01 + Font last char : 0xFF + Font bits per pixel : 1 + Font is compressed : false + + The font data are defined as + + struct _FONT_ { + // common shared fields + uint16_t font_Size_in_Bytes_over_all_included_Size_it_self; + uint8_t font_Width_in_Pixel_for_fixed_drawing; + uint8_t font_Height_in_Pixel_for_all_Characters; + uint8_t font_Bits_per_Pixels; + // if MSB are set then font is a compressed font + uint8_t font_First_Char; + uint8_t font_Last_Char; + uint8_t font_Char_Widths[font_Last_Char - font_First_Char +1]; + // for each character the separate width in pixels, + // characters < 128 have an implicit virtual right empty row + // characters with font_Char_Widths[] == 0 are undefined + + // if compressed font then additional fields + uint8_t font_Byte_Padding; + // each Char in the table are aligned in size to this value + uint8_t font_RLE_Table[3]; + // Run Length Encoding Table for compression + uint8_t font_Char_Size_in_Bytes[font_Last_Char - font_First_Char +1]; + // for each char the size in (bytes / font_Byte_Padding) are stored, + // this get us the table to seek to the right beginning of each char + // in the font_data[]. + + // for compressed and uncompressed fonts + uint8_t font_data[]; + // bit field of all characters + } +*/ + +#include "FontDesc.h" + +#ifndef Roboto_12_FONT_H +#define Roboto_12_FONT_H + +#define Roboto_12_WIDTH 11 +#define Roboto_12_HEIGHT 21 + +static unsigned char const Roboto_12_Bytes[] = { + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x05, 0x09, 0x08, 0x09, 0x09, 0x01, 0x04, 0x05, 0x08, 0x08, 0x03, 0x07, 0x03, 0x06, 0x08, + 0x05, 0x08, 0x08, 0x09, 0x08, 0x08, 0x08, 0x07, 0x07, 0x03, 0x04, 0x07, 0x08, 0x07, 0x08, 0x09, + 0x0A, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x06, 0x08, 0x09, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x09, 0x08, 0x08, 0x09, 0x08, 0x09, 0x09, 0x0A, 0x0A, 0x08, 0x04, 0x06, 0x04, 0x06, 0x07, 0x04, + 0x08, 0x08, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x07, 0x05, 0x08, 0x07, 0x08, 0x08, 0x08, 0x08, + 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x09, 0x08, 0x0A, 0x08, 0x06, 0x02, 0x05, 0x09, 0x05, 0x09, + 0x00, 0x06, 0x09, 0x08, 0x0A, 0x09, 0x09, 0x07, 0x09, 0x09, 0x07, 0x09, 0x00, 0x09, 0x00, 0x00, + 0x06, 0x06, 0x07, 0x08, 0x07, 0x09, 0x09, 0x07, 0x09, 0x09, 0x07, 0x09, 0x00, 0x09, 0x0A, 0x00, + 0x06, 0x09, 0x09, 0x09, 0x0A, 0x06, 0x09, 0x08, 0x09, 0x07, 0x08, 0x08, 0x09, 0x09, 0x08, 0x07, + 0x08, 0x07, 0x07, 0x07, 0x09, 0x08, 0x06, 0x06, 0x06, 0x08, 0x09, 0x0A, 0x0A, 0x0A, 0x09, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0A, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0A, 0x09, 0x0A, + 0xF8, 0xFF, 0x00, 0xFF, 0x1F, 0x20, 0x00, 0x02, 0x04, 0x40, 0x80, 0xFF, 0x0F, 0xF0, 0xFF, 0x01, + 0x00, 0x20, 0x00, 0xFF, 0x0C, 0xE0, 0x9F, 0x01, 0x3C, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x1E, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x0C, 0x00, 0x98, 0x01, 0x00, 0xFB, 0x01, 0xFC, 0x07, 0x80, + 0xCD, 0x04, 0x80, 0xFD, 0x00, 0xFE, 0x03, 0xC0, 0x66, 0x00, 0xC0, 0x00, 0x00, 0x08, 0x06, 0xC0, + 0xC7, 0x01, 0xFC, 0x31, 0x80, 0x31, 0x1C, 0x3C, 0x8E, 0x03, 0x8E, 0x19, 0x80, 0xF3, 0x03, 0x60, + 0x38, 0x00, 0x0E, 0x00, 0xE0, 0x03, 0x00, 0x6C, 0x08, 0x80, 0xCF, 0x00, 0xE0, 0x0E, 0x00, 0x60, + 0x0F, 0x00, 0x33, 0x03, 0x20, 0x66, 0x00, 0x80, 0x0F, 0x00, 0xF0, 0x00, 0x78, 0x3F, 0x80, 0x3F, + 0x06, 0x30, 0xCF, 0x00, 0xBE, 0x1F, 0x80, 0xC3, 0x01, 0x00, 0x7E, 0x00, 0xC0, 0x0D, 0x00, 0x00, + 0x01, 0x3C, 0x00, 0x00, 0xFC, 0x07, 0xE0, 0xFF, 0x03, 0x06, 0xE0, 0x60, 0x00, 0x30, 0x04, 0x00, + 0x82, 0x01, 0xE0, 0xE0, 0x01, 0x07, 0xF8, 0x7F, 0x00, 0xF8, 0x01, 0x00, 0x02, 0x00, 0x60, 0x04, + 0x00, 0xC8, 0x00, 0x60, 0x0F, 0x00, 0xFC, 0x00, 0x00, 0x7C, 0x00, 0x80, 0x0C, 0x00, 0x18, 0x00, + 0x00, 0x0C, 0x00, 0x80, 0x01, 0x00, 0x30, 0x00, 0xE0, 0x3F, 0x00, 0xFC, 0x07, 0x00, 0x18, 0x00, + 0x00, 0x03, 0x00, 0x60, 0x00, 0x00, 0x00, 0x07, 0x00, 0xF8, 0x00, 0x00, 0x03, 0x00, 0x06, 0x00, + 0xC0, 0x00, 0x00, 0x18, 0x00, 0x00, 0x03, 0x00, 0x60, 0x00, 0x00, 0x0C, 0x00, 0x80, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x70, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x03, 0x00, 0x7C, 0x00, 0xF0, 0x03, 0xE0, + 0x0F, 0x00, 0x3E, 0x00, 0xC0, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0xFE, 0x07, 0xE0, 0xD8, 0x01, 0x0C, + 0x31, 0x80, 0x11, 0x06, 0xF0, 0xFF, 0x00, 0xFC, 0x0F, 0x00, 0x3C, 0x00, 0x60, 0x00, 0x00, 0x0C, + 0x00, 0xC0, 0x00, 0x00, 0xF8, 0x3F, 0x80, 0xFF, 0x07, 0xE0, 0xC0, 0x00, 0x1C, 0x1C, 0xC0, 0xE0, + 0x03, 0x18, 0x6E, 0x00, 0xE3, 0x0C, 0xE0, 0x8F, 0x01, 0xF8, 0x30, 0x00, 0x00, 0x06, 0x60, 0x60, + 0x00, 0x0C, 0x1C, 0xC0, 0x18, 0x03, 0x18, 0x63, 0x00, 0x63, 0x0C, 0xE0, 0xFF, 0x01, 0x78, 0x1F, + 0x00, 0x80, 0x00, 0x00, 0x08, 0x00, 0x80, 0x03, 0x00, 0x7C, 0x00, 0xC0, 0x0D, 0x00, 0x8E, 0x01, + 0xE0, 0xFF, 0x01, 0xFC, 0x3F, 0x00, 0xC0, 0x00, 0x00, 0x18, 0x00, 0x70, 0x04, 0xC0, 0x9F, 0x01, + 0xB8, 0x61, 0x00, 0x33, 0x0C, 0x60, 0x86, 0x01, 0xCC, 0x3F, 0x80, 0xF1, 0x03, 0x00, 0x18, 0x00, + 0xF0, 0x07, 0x00, 0xFF, 0x01, 0x70, 0x61, 0x00, 0x33, 0x0C, 0x60, 0x86, 0x01, 0xCC, 0x3F, 0x00, + 0xF0, 0x03, 0x00, 0x18, 0x00, 0x06, 0x00, 0xC0, 0x00, 0x03, 0x18, 0x78, 0x00, 0xC3, 0x07, 0x60, + 0x3E, 0x00, 0xFC, 0x00, 0x80, 0x07, 0x00, 0x10, 0x00, 0x00, 0x38, 0x0F, 0x80, 0xFF, 0x03, 0x98, + 0x63, 0x00, 0x63, 0x0C, 0x60, 0x8C, 0x01, 0xFC, 0x3F, 0x00, 0xEF, 0x03, 0xC0, 0x07, 0x00, 0xFC, + 0x19, 0xC0, 0x30, 0x03, 0x18, 0x66, 0x00, 0xC3, 0x06, 0xC0, 0xFF, 0x00, 0xF0, 0x07, 0x00, 0x08, + 0x02, 0x80, 0xE3, 0x00, 0x70, 0x1C, 0x00, 0x04, 0x00, 0xC0, 0x81, 0x03, 0x38, 0x7C, 0x00, 0x80, + 0x01, 0x00, 0x03, 0x00, 0x70, 0x00, 0x00, 0x1E, 0x00, 0x40, 0x03, 0x00, 0xCC, 0x00, 0x80, 0x19, + 0x00, 0x18, 0x07, 0x00, 0x6C, 0x00, 0x80, 0x0D, 0x00, 0xB0, 0x01, 0x00, 0x36, 0x00, 0xC0, 0x06, + 0x00, 0xD8, 0x00, 0x00, 0x1B, 0x00, 0x60, 0x03, 0x00, 0xC3, 0x00, 0xC0, 0x0C, 0x00, 0x98, 0x01, + 0x00, 0x1B, 0x00, 0xC0, 0x03, 0x00, 0x78, 0x00, 0x00, 0x06, 0x00, 0x04, 0x00, 0xC0, 0x00, 0x00, + 0x1C, 0x00, 0x80, 0xE1, 0x06, 0x30, 0xDE, 0x00, 0xFE, 0x00, 0x80, 0x0F, 0x00, 0x60, 0x00, 0x00, + 0xE0, 0x00, 0x80, 0xFF, 0x00, 0x18, 0x18, 0x80, 0xF8, 0x06, 0x90, 0xD0, 0x00, 0x92, 0x19, 0x40, + 0x7E, 0x01, 0x10, 0x08, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3C, 0x00, 0xF0, 0x07, 0xE0, + 0x3F, 0x00, 0x3E, 0x06, 0xC0, 0xCF, 0x00, 0xE0, 0x1F, 0x00, 0xE0, 0x0F, 0x00, 0xE0, 0x01, 0x00, + 0x20, 0x80, 0xFF, 0x07, 0xF0, 0xFF, 0x00, 0xC6, 0x18, 0xC0, 0x18, 0x03, 0x18, 0x63, 0x00, 0x73, + 0x0C, 0xC0, 0xFF, 0x01, 0x70, 0x1E, 0x00, 0xFE, 0x01, 0xE0, 0x7F, 0x00, 0x06, 0x18, 0xC0, 0x00, + 0x03, 0x18, 0x60, 0x00, 0x07, 0x0E, 0xC0, 0xE1, 0x00, 0x30, 0x0C, 0x80, 0xFF, 0x07, 0xF0, 0xFF, + 0x00, 0x06, 0x18, 0xC0, 0x00, 0x03, 0x18, 0x60, 0x00, 0x0E, 0x07, 0xC0, 0xFF, 0x00, 0xE0, 0x07, + 0x80, 0xFF, 0x07, 0xF0, 0xFF, 0x00, 0xC6, 0x18, 0xC0, 0x18, 0x03, 0x18, 0x63, 0x00, 0x63, 0x0C, + 0x60, 0x8C, 0x01, 0x0C, 0x30, 0x80, 0xFF, 0x07, 0xF0, 0xFF, 0x00, 0xC6, 0x00, 0xC0, 0x18, 0x00, + 0x18, 0x03, 0x00, 0x63, 0x00, 0x60, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0xFE, 0x01, 0xE0, 0x7F, 0x00, + 0x0E, 0x1C, 0xC0, 0x00, 0x03, 0x18, 0x66, 0x00, 0xC7, 0x0C, 0xC0, 0xF9, 0x00, 0x30, 0x1F, 0x80, + 0xFF, 0x07, 0xF0, 0xFF, 0x00, 0xC0, 0x00, 0x00, 0x18, 0x00, 0x00, 0x03, 0x00, 0xFF, 0x0F, 0xE0, + 0xFF, 0x01, 0xFC, 0x3F, 0x80, 0x01, 0x06, 0x30, 0xC0, 0x00, 0xFE, 0x1F, 0xC0, 0xFF, 0x03, 0x18, + 0x60, 0x00, 0x03, 0x0C, 0x00, 0xE0, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x06, 0x00, 0xC0, 0x00, 0x00, + 0x18, 0xC0, 0xFF, 0x03, 0xF8, 0x3F, 0x00, 0xFF, 0x01, 0xE0, 0xFF, 0x01, 0xFC, 0x3F, 0x00, 0x70, + 0x00, 0x00, 0x07, 0x00, 0xF8, 0x03, 0x80, 0xF3, 0x01, 0x38, 0x78, 0x00, 0x03, 0x0C, 0x20, 0x00, + 0x01, 0xFC, 0x3F, 0x80, 0xFF, 0x07, 0x00, 0xC0, 0x00, 0x00, 0x18, 0x00, 0x00, 0x03, 0x00, 0x60, + 0x00, 0x00, 0x0C, 0x00, 0x80, 0x01, 0xFC, 0x3F, 0x80, 0xFF, 0x07, 0xF0, 0x01, 0x00, 0xF0, 0x01, + 0x00, 0x3F, 0x00, 0x78, 0x00, 0x00, 0xFF, 0x0F, 0xE0, 0xFF, 0x01, 0xFC, 0x3F, 0x80, 0xFF, 0x07, + 0xE0, 0x01, 0x00, 0xF0, 0x01, 0x00, 0xF0, 0x00, 0xF8, 0x7F, 0x00, 0xFF, 0x0F, 0xE0, 0xFF, 0x01, + 0xF0, 0x0F, 0x00, 0xFF, 0x03, 0x30, 0xC0, 0x00, 0x06, 0x18, 0xC0, 0x00, 0x03, 0x38, 0x70, 0x00, + 0xFE, 0x07, 0x00, 0x3F, 0x00, 0xFC, 0x3F, 0x80, 0xFF, 0x07, 0x30, 0x0C, 0x00, 0x86, 0x01, 0xC0, + 0x30, 0x00, 0x38, 0x07, 0x00, 0x7E, 0x00, 0x80, 0x07, 0x00, 0xF0, 0x0F, 0x00, 0xFF, 0x03, 0x30, + 0xC0, 0x00, 0x06, 0x18, 0xC0, 0x00, 0x03, 0x38, 0x70, 0x00, 0xFE, 0x1F, 0x80, 0x7F, 0x06, 0x00, + 0x40, 0x80, 0xFF, 0x07, 0xF0, 0xFF, 0x00, 0x86, 0x01, 0xC0, 0x30, 0x00, 0x18, 0x0E, 0x00, 0xE7, + 0x07, 0xC0, 0xEF, 0x01, 0xF0, 0x30, 0x00, 0x8E, 0x03, 0xE0, 0x73, 0x00, 0x66, 0x18, 0xC0, 0x18, + 0x03, 0x18, 0x63, 0x00, 0xE3, 0x0C, 0xC0, 0xF9, 0x00, 0x30, 0x1E, 0x80, 0x01, 0x00, 0x30, 0x00, + 0x00, 0x06, 0x00, 0xC0, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0xFF, 0x0F, 0x60, 0x00, 0x00, 0x0C, 0x00, + 0x80, 0x01, 0x00, 0xF0, 0x3F, 0x00, 0xFE, 0x0F, 0x00, 0x80, 0x03, 0x00, 0x60, 0x00, 0x00, 0x0C, + 0xE0, 0xFF, 0x01, 0xFC, 0x1F, 0x80, 0xFF, 0x00, 0x10, 0x00, 0x00, 0x1E, 0x00, 0xC0, 0x3F, 0x00, + 0xC0, 0x3F, 0x00, 0x80, 0x0F, 0x00, 0xFC, 0x01, 0xF0, 0x0F, 0x80, 0x1F, 0x00, 0x70, 0x00, 0x00, + 0x06, 0x00, 0xC0, 0xFF, 0x00, 0xE0, 0x7F, 0x00, 0xF0, 0x0F, 0xE0, 0x0F, 0x00, 0xFC, 0x0F, 0x00, + 0xE0, 0x07, 0xF0, 0xFF, 0x00, 0xFE, 0x00, 0x40, 0x00, 0x02, 0x18, 0x60, 0x00, 0x0F, 0x0F, 0xC0, + 0xFF, 0x00, 0xE0, 0x07, 0x00, 0xFC, 0x00, 0xE0, 0x7F, 0x00, 0x1E, 0x1E, 0xC0, 0x00, 0x03, 0x00, + 0x40, 0x00, 0x01, 0x00, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x3E, 0x00, 0x00, 0xFF, 0x00, 0xE0, + 0x1F, 0x00, 0x1F, 0x00, 0xF8, 0x00, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x0C, 0x38, 0x80, 0x81, + 0x07, 0x30, 0xFC, 0x00, 0xC6, 0x19, 0xC0, 0x1E, 0x03, 0xF8, 0x60, 0x00, 0x0F, 0x0C, 0x60, 0x80, + 0x01, 0xFF, 0xFF, 0xE1, 0xFF, 0x3F, 0x0C, 0x00, 0x86, 0x01, 0xC0, 0xC0, 0x00, 0x00, 0xF8, 0x00, + 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x86, 0xFF, 0xFF, + 0xF0, 0xFF, 0x1F, 0xFE, 0xFF, 0x03, 0x30, 0x00, 0x80, 0x07, 0x00, 0x1C, 0x00, 0x80, 0x07, 0x00, + 0xC0, 0x03, 0x00, 0x40, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x80, 0x01, 0x00, 0x30, 0x00, 0x00, 0x06, + 0x00, 0xC0, 0x00, 0x00, 0x18, 0x00, 0x00, 0x03, 0x02, 0x00, 0x40, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x02, 0x00, 0x00, 0xF6, 0x00, 0xE0, 0x3E, 0x00, 0x6C, 0x06, 0x80, 0xCD, 0x00, 0xB0, 0x19, 0x00, + 0xFE, 0x03, 0x80, 0x7F, 0x00, 0x00, 0x08, 0xE0, 0xFF, 0x01, 0xFC, 0x3F, 0x00, 0x18, 0x02, 0x80, + 0xC1, 0x00, 0x30, 0x18, 0x00, 0xDE, 0x03, 0x80, 0x3F, 0x00, 0xC0, 0x01, 0x00, 0x7C, 0x00, 0xC0, + 0x1F, 0x00, 0x1C, 0x07, 0x80, 0xC1, 0x00, 0x30, 0x18, 0x00, 0x8E, 0x03, 0x80, 0x31, 0x00, 0xE0, + 0x03, 0x00, 0xFF, 0x00, 0x60, 0x30, 0x00, 0x0C, 0x06, 0x80, 0xC1, 0x00, 0xFE, 0x1F, 0xC0, 0xFF, + 0x03, 0x00, 0x1F, 0x00, 0xF0, 0x07, 0x00, 0xDB, 0x01, 0x60, 0x33, 0x00, 0x6C, 0x06, 0x80, 0xCD, + 0x00, 0xE0, 0x0D, 0x00, 0x38, 0x01, 0xC0, 0x00, 0x00, 0x18, 0x00, 0xC0, 0xFF, 0x01, 0xFC, 0x3F, + 0xC0, 0x0D, 0x00, 0x98, 0x01, 0x00, 0x33, 0x00, 0x60, 0x00, 0x00, 0x00, 0x1F, 0x01, 0xF0, 0x77, + 0x00, 0xC7, 0x0D, 0x60, 0xB0, 0x01, 0x0C, 0x36, 0x00, 0xFF, 0x07, 0xF0, 0x7F, 0x00, 0xFE, 0x03, + 0xF8, 0x7F, 0x00, 0xFF, 0x0F, 0x00, 0x02, 0x00, 0x60, 0x00, 0x00, 0x0C, 0x00, 0x80, 0xFF, 0x00, + 0xE0, 0x1F, 0x00, 0xF8, 0x03, 0xC0, 0x60, 0x00, 0x18, 0x0C, 0x60, 0xFF, 0x01, 0xEC, 0x3F, 0x00, + 0x00, 0x06, 0x00, 0xC0, 0x00, 0x00, 0x18, 0x00, 0x06, 0x18, 0xC0, 0x00, 0x03, 0x19, 0x70, 0x60, + 0xFF, 0x07, 0xEC, 0x7F, 0x80, 0xFF, 0x07, 0xF0, 0xFF, 0x00, 0x80, 0x03, 0x00, 0x78, 0x00, 0x80, + 0x1F, 0x00, 0x38, 0x0F, 0x00, 0xC3, 0x01, 0x20, 0x20, 0x80, 0x01, 0x06, 0x30, 0xC0, 0x00, 0xFE, + 0x1F, 0xC0, 0xFF, 0x03, 0x00, 0x60, 0x00, 0x00, 0x0C, 0x00, 0x80, 0x01, 0xE0, 0x3F, 0x00, 0xF8, + 0x07, 0x80, 0x01, 0x00, 0xF0, 0x1F, 0x00, 0xFC, 0x03, 0xC0, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0xFE, + 0x01, 0xE0, 0x3F, 0x00, 0xFC, 0x07, 0x00, 0x01, 0x00, 0x30, 0x00, 0x00, 0x06, 0x00, 0xC0, 0x7F, + 0x00, 0xF0, 0x0F, 0x00, 0xFC, 0x01, 0x80, 0x0F, 0x00, 0xF8, 0x03, 0x80, 0xC1, 0x00, 0x30, 0x18, + 0x00, 0x06, 0x03, 0xC0, 0x71, 0x00, 0xF0, 0x07, 0x00, 0x38, 0x00, 0xE0, 0xFF, 0x01, 0xFC, 0x3F, + 0x00, 0x41, 0x00, 0x30, 0x18, 0x00, 0x06, 0x03, 0xC0, 0x7B, 0x00, 0xF0, 0x07, 0x00, 0x38, 0x00, + 0x80, 0x0F, 0x00, 0xFC, 0x03, 0x80, 0xE3, 0x00, 0x30, 0x18, 0x00, 0x06, 0x03, 0xC0, 0xFF, 0x03, + 0xF8, 0x7F, 0x00, 0xFF, 0x01, 0xE0, 0x3F, 0x00, 0x18, 0x00, 0x80, 0x01, 0x00, 0x30, 0x00, 0x00, + 0x06, 0x00, 0xC0, 0x00, 0x00, 0x60, 0x06, 0x00, 0xCE, 0x00, 0x60, 0x33, 0x00, 0x4C, 0x06, 0x80, + 0xC9, 0x00, 0x70, 0x1B, 0x00, 0xCC, 0x01, 0x00, 0x11, 0x00, 0x18, 0x00, 0x00, 0x03, 0x00, 0xF8, + 0x1F, 0x00, 0xFF, 0x07, 0x80, 0xC1, 0x00, 0x30, 0x18, 0x00, 0x06, 0x03, 0x00, 0x40, 0x00, 0xF8, + 0x03, 0x00, 0xFF, 0x01, 0x00, 0x38, 0x00, 0x00, 0x06, 0x00, 0xC0, 0x00, 0xF0, 0x0F, 0x00, 0xFE, + 0x03, 0xC0, 0x7F, 0x00, 0x38, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x07, 0x00, 0xF8, + 0x00, 0xE0, 0x07, 0x00, 0x1E, 0x00, 0xC0, 0x00, 0x00, 0x18, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x3F, + 0x00, 0xE0, 0x07, 0x80, 0x07, 0x00, 0xF0, 0x07, 0x00, 0x80, 0x03, 0xC0, 0x7F, 0x00, 0x78, 0x00, + 0x00, 0x01, 0x01, 0xE0, 0x38, 0x00, 0xB8, 0x03, 0x00, 0x3E, 0x00, 0xC0, 0x07, 0x00, 0xDE, 0x01, + 0xC0, 0x71, 0x00, 0x08, 0x08, 0x00, 0x01, 0x00, 0xE0, 0x00, 0x01, 0x7C, 0x30, 0x00, 0x3E, 0x07, + 0x00, 0x7F, 0x00, 0xE0, 0x03, 0x00, 0x1F, 0x00, 0xF8, 0x00, 0x00, 0x07, 0x00, 0x20, 0x00, 0x00, + 0x0C, 0x06, 0x80, 0xE1, 0x00, 0x30, 0x1F, 0x00, 0x76, 0x03, 0xC0, 0x67, 0x00, 0x78, 0x0C, 0x00, + 0x87, 0x01, 0x60, 0x30, 0x00, 0x60, 0x00, 0x00, 0x0C, 0x00, 0xF8, 0x1F, 0xC0, 0xCF, 0x0F, 0x1C, + 0x80, 0x03, 0x01, 0x20, 0xE0, 0xFF, 0x0F, 0xFC, 0xFF, 0xC1, 0x00, 0x30, 0xF0, 0xF3, 0x03, 0xFC, + 0x3F, 0x00, 0x30, 0x00, 0x00, 0x06, 0x00, 0x80, 0x00, 0x00, 0x1C, 0x00, 0x80, 0x01, 0x00, 0x30, + 0x00, 0x00, 0x0C, 0x00, 0x00, 0x03, 0x00, 0x60, 0x00, 0x00, 0x0E, 0x00, 0xC0, 0x00, 0xF0, 0xFF, + 0x00, 0xFE, 0x1F, 0x40, 0x00, 0x02, 0xF8, 0x7F, 0x00, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x80, 0x06, + 0x00, 0xF8, 0x01, 0xC0, 0xFF, 0x00, 0x7C, 0x3F, 0x80, 0x69, 0x06, 0x30, 0xCD, 0x00, 0x06, 0x18, + 0xC0, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, + 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x03, 0x18, 0x70, 0xF0, 0xFF, 0x0F, + 0xFE, 0x7F, 0x60, 0x0C, 0x00, 0x0C, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x10, 0x00, 0xC0, 0x07, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x0E, 0x00, 0xC0, 0x01, 0x00, 0x10, 0x00, 0x00, 0x07, 0x00, + 0xE0, 0x00, 0x00, 0x08, 0x00, 0x80, 0x03, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x60, + 0x00, 0x00, 0x0C, 0x00, 0xF0, 0xFF, 0x00, 0xFE, 0x1F, 0x00, 0x06, 0x00, 0xC0, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x00, 0x0C, 0x06, 0x80, 0xC1, 0x00, 0xFE, 0xFF, 0xC0, 0xFF, + 0x1F, 0xC0, 0x60, 0x00, 0x18, 0x0C, 0x00, 0x83, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x20, 0x00, + 0x00, 0x02, 0x00, 0xC0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x02, + 0x80, 0x2D, 0x01, 0xF0, 0xFB, 0x00, 0x6C, 0x1B, 0x00, 0xE4, 0x03, 0x40, 0x7C, 0x00, 0x84, 0x0D, + 0x00, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x8E, 0x03, 0xE2, 0x73, 0x40, 0x66, 0x18, 0xD0, 0x18, 0x03, + 0x1A, 0x63, 0x20, 0xE3, 0x0C, 0xC4, 0xF9, 0x00, 0x30, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x1F, 0x00, 0x30, 0x06, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x03, 0x70, 0xE0, 0x00, 0x06, 0x18, 0xC0, 0x00, 0x03, 0xF8, 0x7F, 0x00, 0xFF, 0x0F, 0x60, + 0x8C, 0x01, 0x8C, 0x31, 0x00, 0x00, 0x00, 0x30, 0xE0, 0x40, 0x06, 0x1E, 0xC8, 0xF0, 0x03, 0x1A, + 0x67, 0x40, 0x7B, 0x0C, 0xE4, 0x83, 0x81, 0x3C, 0x30, 0x80, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x07, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0xF8, 0x00, 0x00, 0x1E, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, + 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x78, 0x00, + 0x00, 0x0F, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x60, 0x00, 0x00, 0x0C, 0x00, + 0x80, 0x01, 0x00, 0x30, 0x00, 0x00, 0x06, 0x00, 0xC0, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x0C, 0x00, 0x80, 0x01, 0x00, 0x30, 0x00, 0x00, 0x06, 0x00, 0xC0, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x0C, 0x00, 0x80, 0x01, 0x00, 0x30, + 0x00, 0x00, 0x06, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xE0, 0x03, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x38, 0x00, 0x80, 0x01, 0x00, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xCC, 0x00, 0xC4, 0x19, 0x80, 0x6C, 0x06, 0xA0, 0xC9, 0x00, 0x34, 0x19, 0x40, 0x6E, + 0x03, 0x88, 0x39, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, + 0x00, 0xE0, 0x0E, 0x00, 0x70, 0x00, 0x00, 0x04, 0x00, 0xE0, 0x03, 0x00, 0xFE, 0x00, 0x60, 0x30, + 0x00, 0x0C, 0x06, 0x80, 0xFF, 0x00, 0xF0, 0x1F, 0x00, 0x36, 0x03, 0xC0, 0x67, 0x00, 0xF0, 0x0C, + 0x00, 0x00, 0x00, 0x60, 0x30, 0x80, 0x0C, 0x07, 0x90, 0xF9, 0x00, 0xB4, 0x1B, 0x80, 0x3E, 0x03, + 0xC8, 0x63, 0x00, 0x39, 0x0C, 0x00, 0x83, 0x01, 0x04, 0x00, 0x80, 0x03, 0x00, 0xF6, 0x01, 0xC0, + 0xF8, 0x00, 0x00, 0xFC, 0x03, 0x80, 0x7F, 0x60, 0x7C, 0x00, 0xEC, 0x03, 0x00, 0x0C, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x7F, 0x00, + 0xF7, 0x0F, 0x00, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x7F, 0x00, 0x70, 0x1C, 0x80, 0x07, 0x0F, 0xF0, + 0xE0, 0x01, 0x38, 0x0E, 0x00, 0xC6, 0x00, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0xF8, + 0x1F, 0x80, 0xFF, 0x03, 0x18, 0x63, 0x00, 0x63, 0x0C, 0x60, 0x8C, 0x01, 0x1C, 0x30, 0x00, 0x03, + 0x06, 0x00, 0x00, 0x00, 0xF0, 0x1F, 0x00, 0xDC, 0x01, 0xC0, 0x60, 0x00, 0x18, 0x0C, 0x00, 0x83, + 0x01, 0xC0, 0x38, 0x00, 0xFC, 0x07, 0x00, 0x5D, 0x00, 0x02, 0x00, 0xC0, 0xD1, 0x00, 0xF8, 0x1A, + 0x00, 0x7C, 0x03, 0x00, 0xFE, 0x01, 0xC0, 0x3F, 0x00, 0xBF, 0x01, 0xF0, 0x34, 0x00, 0x86, 0x06, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9F, 0x1F, + 0xF0, 0xF3, 0x03, 0x00, 0x00, 0x80, 0x77, 0x0C, 0xF0, 0x9F, 0x03, 0x33, 0x63, 0x60, 0xC6, 0x0C, + 0x8C, 0x99, 0x81, 0x31, 0x33, 0x60, 0xFE, 0x03, 0x88, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1F, 0x00, 0x10, 0x04, 0x00, 0x7D, 0x01, 0xA0, 0x28, 0x00, 0x14, 0x05, 0x80, + 0x94, 0x00, 0x20, 0x08, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0xEC, + 0x01, 0x80, 0x24, 0x00, 0x90, 0x06, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xE0, + 0x03, 0x00, 0xC6, 0x00, 0x40, 0x12, 0x00, 0xF0, 0x01, 0x00, 0x63, 0x00, 0x20, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x60, 0x00, 0x00, 0x0C, 0x00, 0x80, 0x01, 0x00, 0x30, 0x00, 0x00, 0x1E, + 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x18, 0x00, 0x00, 0x03, + 0x00, 0x60, 0x00, 0x00, 0x0C, 0x00, 0x80, 0x01, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x03, + 0x00, 0x82, 0x00, 0xA0, 0x2F, 0x00, 0x54, 0x04, 0x80, 0x9A, 0x00, 0x90, 0x14, 0x00, 0x04, 0x01, + 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x80, 0x01, 0x00, 0x30, 0x00, 0x00, + 0x06, 0x00, 0xC0, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x90, 0x00, 0x00, 0x12, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0C, 0x00, + 0x86, 0x01, 0xC0, 0x30, 0x00, 0xFF, 0x06, 0xE0, 0xDF, 0x00, 0x60, 0x18, 0x00, 0x0C, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x0C, 0x00, 0x9C, 0x01, 0x80, 0x39, 0x00, 0xB0, 0x06, 0x00, 0xCC, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x60, 0x0C, 0x00, 0xAC, 0x01, 0x80, 0x35, + 0x00, 0x70, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x60, 0x00, + 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x00, 0xFE, 0x1F, 0xC0, 0xFF, + 0x03, 0x00, 0x0C, 0x00, 0x80, 0x01, 0x00, 0x38, 0x00, 0xFC, 0x07, 0x80, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xF0, 0x03, 0x00, 0xFF, 0x00, 0xE0, 0x1F, 0x00, 0xFC, 0x03, 0x80, 0xFF, 0x07, + 0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x40, 0x03, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x0C, 0x00, 0x80, + 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0xCC, 0x00, 0x80, 0x10, 0x00, 0x10, + 0x02, 0x00, 0x7E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0xC0, + 0x1D, 0x00, 0xE0, 0x00, 0x00, 0x49, 0x00, 0xE0, 0x0E, 0x00, 0x70, 0x00, 0x00, 0x04, 0x00, 0x02, + 0x00, 0x40, 0x00, 0x00, 0xFC, 0x08, 0x00, 0xC0, 0x01, 0x00, 0x0E, 0x00, 0x70, 0x0C, 0x00, 0xC3, + 0x01, 0x00, 0x26, 0x00, 0xC0, 0x0F, 0x00, 0x80, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0xF0, 0x23, + 0x00, 0x00, 0x07, 0x00, 0x38, 0x00, 0xC0, 0x45, 0x00, 0xCC, 0x0C, 0x00, 0x48, 0x01, 0x00, 0x2F, + 0x00, 0x00, 0x04, 0x20, 0x01, 0x00, 0x66, 0x00, 0x40, 0x0A, 0x00, 0xF8, 0x11, 0x00, 0x92, 0x03, + 0x00, 0xDC, 0x00, 0xE0, 0x1C, 0x00, 0x66, 0x02, 0x00, 0xFC, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0xE0, 0x0F, 0x60, 0x8F, 0x01, 0xEC, 0x30, 0x00, 0x00, 0x07, + 0x00, 0x60, 0x00, 0x00, 0x04, 0x00, 0x40, 0x00, 0x00, 0x0F, 0x04, 0xFC, 0x81, 0xF8, 0x0F, 0xB0, + 0x8F, 0x01, 0xF4, 0x33, 0x00, 0xF8, 0x07, 0x00, 0xF8, 0x03, 0x00, 0x78, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x01, 0x00, 0x3C, 0x00, 0xF0, 0x07, 0xE0, 0x3F, 0x80, 0x3E, 0x06, 0xD8, 0xCF, 0x00, 0xE1, + 0x1F, 0x20, 0xE0, 0x0F, 0x00, 0xE0, 0x01, 0x00, 0x20, 0x00, 0x00, 0x04, 0x00, 0xF0, 0x80, 0xC0, + 0x1F, 0x90, 0xFF, 0x00, 0xF9, 0x18, 0x60, 0x3F, 0x03, 0x88, 0x7F, 0x00, 0x81, 0x3F, 0x00, 0x80, + 0x07, 0x00, 0x80, 0x00, 0x00, 0x10, 0x00, 0xC0, 0x03, 0x02, 0x7F, 0x60, 0xFE, 0x03, 0xEC, 0x63, + 0x80, 0xFD, 0x0C, 0x30, 0xFE, 0x01, 0x02, 0xFE, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x02, 0x00, 0x40, + 0x00, 0x00, 0x0F, 0x0C, 0xFC, 0x81, 0xF9, 0x0F, 0x80, 0x8F, 0x01, 0xF0, 0x33, 0xC0, 0xF8, 0x07, + 0x18, 0xF8, 0x03, 0x00, 0x78, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x3C, 0x00, 0xF0, 0x07, + 0xE6, 0x3F, 0x20, 0x3F, 0x06, 0xFC, 0xCF, 0x00, 0xE0, 0x1F, 0x00, 0xE0, 0x0F, 0x00, 0xE0, 0x01, + 0x00, 0x20, 0x00, 0x00, 0x04, 0x00, 0xF0, 0x00, 0xC0, 0x1F, 0x00, 0x7F, 0x00, 0xF8, 0x0C, 0x00, + 0xFF, 0x0F, 0xE0, 0xFF, 0x01, 0x8C, 0x31, 0x80, 0x31, 0x06, 0x00, 0x00, 0x00, 0xF8, 0x07, 0x80, + 0xFF, 0x01, 0x18, 0x60, 0x00, 0x03, 0x6C, 0x60, 0x80, 0x0F, 0x1C, 0x38, 0x00, 0x87, 0x03, 0xC0, + 0x30, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x03, 0xF9, 0x7F, 0x20, 0x63, 0x0C, 0x6C, 0x8C, 0x01, 0x8D, + 0x31, 0x80, 0x31, 0x06, 0x30, 0xC6, 0x00, 0x06, 0x18, 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0xFF, + 0x0F, 0x60, 0x8C, 0x01, 0x8D, 0x31, 0xB0, 0x31, 0x06, 0x32, 0xC6, 0x40, 0xC6, 0x18, 0xC0, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xE8, 0xFF, 0x01, 0x8D, 0x31, 0x90, 0x31, 0x06, 0x36, 0xC6, + 0x80, 0xC6, 0x18, 0xD0, 0x18, 0x03, 0x18, 0x60, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x81, 0xFD, 0x3F, + 0xB0, 0x31, 0x06, 0x30, 0xC6, 0x00, 0xC6, 0x18, 0xD8, 0x18, 0x03, 0x1B, 0x63, 0x00, 0x03, 0x0C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x06, 0x32, 0xC0, 0xC0, 0xFE, 0x1F, 0xD0, 0xFF, 0x03, + 0x18, 0x60, 0x00, 0x03, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x06, 0x30, 0xC0, 0x80, + 0xFE, 0x1F, 0xD8, 0xFF, 0x03, 0x19, 0x60, 0x20, 0x03, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, + 0x01, 0x06, 0x34, 0xC0, 0x40, 0xFE, 0x1F, 0xD8, 0xFF, 0x03, 0x1A, 0x60, 0x40, 0x03, 0x0C, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xB0, 0x01, 0x06, 0x36, 0xC0, 0x00, 0xFE, 0x1F, 0xC0, 0xFF, 0x03, 0x1B, + 0x60, 0x60, 0x03, 0x0C, 0x00, 0x0C, 0x00, 0xFC, 0x3F, 0x80, 0xFF, 0x07, 0x30, 0xC6, 0x00, 0xC6, + 0x18, 0xC0, 0x00, 0x03, 0x30, 0x30, 0x00, 0xFE, 0x07, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x80, 0xFF, + 0x07, 0xF4, 0xFF, 0xC0, 0x3C, 0x00, 0x18, 0x3E, 0x00, 0x03, 0x1E, 0x60, 0xFF, 0x0F, 0xE4, 0xFF, + 0x01, 0xFC, 0x3F, 0x00, 0x00, 0x00, 0xC0, 0x3F, 0x40, 0xFC, 0x0F, 0xC8, 0x00, 0x03, 0x1B, 0x60, + 0x40, 0x03, 0x0C, 0xE0, 0xC0, 0x01, 0xF8, 0x1F, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x07, + 0x80, 0xFF, 0x01, 0x18, 0x60, 0x40, 0x03, 0x0C, 0x6C, 0x80, 0x81, 0x1C, 0x38, 0x10, 0xFF, 0x03, + 0x80, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xF2, 0x3F, 0x40, 0x03, 0x0C, 0x64, 0x80, 0x81, + 0x0D, 0x30, 0xA0, 0x03, 0x07, 0xE4, 0x7F, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x40, + 0xFE, 0x07, 0x6C, 0x80, 0x81, 0x0D, 0x30, 0xB0, 0x01, 0x06, 0x76, 0xE0, 0x40, 0xFC, 0x0F, 0x00, + 0x7E, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x03, 0xCC, 0xFF, 0x80, 0x0D, 0x30, 0x80, 0x01, 0x06, 0x30, + 0xC0, 0xC0, 0x0E, 0x1C, 0x98, 0xFF, 0x01, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x70, + 0x0C, 0x00, 0xD8, 0x00, 0x00, 0x0E, 0x00, 0xE0, 0x01, 0x00, 0x6E, 0x00, 0xE0, 0x18, 0x00, 0x08, + 0x01, 0x00, 0x00, 0x01, 0xF0, 0x2F, 0x00, 0xFF, 0x03, 0x30, 0xF8, 0x00, 0xC6, 0x19, 0xC0, 0x0E, + 0x03, 0x78, 0x70, 0x00, 0xFF, 0x07, 0xA0, 0x7F, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x01, 0xF2, 0x7F, + 0x40, 0x00, 0x1C, 0x18, 0x00, 0x03, 0x02, 0x60, 0x00, 0xFF, 0x0F, 0xE0, 0xFF, 0x00, 0xFC, 0x07, + 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0xFE, 0x0F, 0x00, 0x80, 0x03, 0x02, 0x60, 0x60, 0x00, 0x0C, + 0xE4, 0xFF, 0x81, 0xFC, 0x1F, 0x80, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x07, 0xD0, 0xFF, 0x01, + 0x02, 0x70, 0x20, 0x00, 0x0C, 0x0C, 0x80, 0x01, 0xFD, 0x3F, 0xA0, 0xFF, 0x03, 0xF0, 0x1F, 0x00, + 0x00, 0x00, 0xC0, 0xFF, 0x00, 0xFB, 0x3F, 0x60, 0x00, 0x0E, 0x00, 0x80, 0x01, 0x00, 0x30, 0xB0, + 0xFF, 0x07, 0xF6, 0x7F, 0x00, 0xFE, 0x03, 0x40, 0x00, 0x00, 0x38, 0x00, 0x00, 0x1F, 0x00, 0x80, + 0x0F, 0x00, 0xC1, 0x3F, 0x30, 0xF8, 0x07, 0xC2, 0x07, 0x40, 0x3E, 0x00, 0xC0, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x01, 0xFC, 0x3F, 0x00, 0x86, 0x01, 0xC0, 0x30, 0x00, 0x18, + 0x06, 0x00, 0xE7, 0x00, 0xC0, 0x0F, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0xFF, + 0x07, 0x70, 0x00, 0x00, 0x06, 0x18, 0xC0, 0x1C, 0x03, 0xF8, 0x67, 0x00, 0xCE, 0x0F, 0x00, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x90, 0xFB, 0x00, 0xB2, 0x19, 0xC0, 0x36, 0x03, 0xD0, 0x66, + 0x00, 0xF8, 0x0F, 0x00, 0xFE, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x7B, 0x00, 0x70, 0x1F, + 0x00, 0x36, 0x03, 0xD0, 0x66, 0x00, 0xDB, 0x0C, 0x20, 0xFF, 0x01, 0xC4, 0x3F, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x60, 0x0F, 0x80, 0xEE, 0x03, 0xD0, 0x66, 0x00, 0xD9, 0x0C, 0x60, 0x9B, 0x01, + 0xE8, 0x3F, 0x00, 0xF9, 0x07, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x01, 0xD0, 0x7D, 0x00, + 0xDB, 0x0C, 0x60, 0x9B, 0x01, 0x6C, 0x33, 0x80, 0xFD, 0x07, 0x10, 0xFF, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x80, 0x3D, 0x00, 0xBB, 0x0F, 0x60, 0x9B, 0x01, 0x60, 0x33, 0x00, 0x6C, 0x06, 0xB0, + 0xFF, 0x00, 0xE6, 0x1F, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xB0, 0x07, 0x00, 0xF7, 0x01, 0x6C, + 0x33, 0x40, 0x6E, 0x06, 0xF8, 0xCD, 0x00, 0xF0, 0x1F, 0x00, 0xFC, 0x03, 0x00, 0x40, 0x00, 0x00, + 0x03, 0x00, 0xF3, 0x01, 0x60, 0x3F, 0x00, 0x6C, 0x06, 0x80, 0x7F, 0x00, 0xF0, 0x1F, 0x00, 0x36, + 0x03, 0xC0, 0x67, 0x00, 0xF0, 0x0C, 0x00, 0x00, 0x00, 0x80, 0x0F, 0x00, 0xF8, 0x03, 0x80, 0xE3, + 0x00, 0x30, 0xD8, 0x00, 0x06, 0x1F, 0xC0, 0x71, 0x00, 0x30, 0x06, 0x00, 0x00, 0x00, 0x80, 0x0F, + 0x80, 0xF8, 0x03, 0x90, 0xED, 0x00, 0xB6, 0x19, 0x80, 0x36, 0x03, 0xC0, 0x66, 0x00, 0xF0, 0x06, + 0x00, 0x9C, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x7F, 0x00, 0xB0, 0x1D, 0x80, 0x36, 0x03, + 0xD8, 0x66, 0x00, 0xD9, 0x0C, 0x20, 0xDE, 0x00, 0x80, 0x13, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, + 0xE4, 0x0F, 0x80, 0xB6, 0x03, 0xC8, 0x66, 0x00, 0xDB, 0x0C, 0x40, 0x9B, 0x01, 0xC8, 0x1B, 0x00, + 0x70, 0x02, 0x00, 0x00, 0x00, 0xC0, 0x07, 0xC0, 0xFC, 0x01, 0xD8, 0x76, 0x00, 0xD8, 0x0C, 0x00, + 0x9B, 0x01, 0x6C, 0x33, 0x80, 0x79, 0x03, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, + 0x60, 0x00, 0x19, 0x0C, 0x60, 0xFF, 0x01, 0xE8, 0x3F, 0x00, 0x00, 0x06, 0x00, 0xC0, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0C, 0x00, 0x83, 0x01, 0xE8, 0x3F, 0x80, 0xFD, + 0x07, 0x10, 0xC0, 0x00, 0x02, 0x18, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x83, + 0x01, 0x68, 0x30, 0x80, 0xFC, 0x07, 0xB0, 0xFF, 0x00, 0x04, 0x18, 0x80, 0x00, 0x03, 0x00, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x30, 0x80, 0x0D, 0x06, 0x80, 0xFF, 0x00, 0xF0, 0x1F, + 0xC0, 0x00, 0x03, 0x18, 0x60, 0x00, 0x00, 0x0C, 0x00, 0x30, 0x00, 0x80, 0x1F, 0x00, 0xF8, 0x07, + 0xE0, 0xC3, 0x00, 0x6E, 0x18, 0xC0, 0x0D, 0x03, 0xF0, 0x3F, 0x00, 0xFD, 0x07, 0x00, 0x1C, 0x00, + 0x00, 0x00, 0x00, 0xFC, 0x07, 0xA0, 0xFF, 0x00, 0x26, 0x00, 0xC0, 0x06, 0x00, 0xD8, 0x00, 0x00, + 0xFB, 0x0F, 0x20, 0xFE, 0x01, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0xE2, 0x0F, 0x40, + 0x06, 0x03, 0xD8, 0x60, 0x00, 0x1A, 0x0C, 0x00, 0xC7, 0x01, 0xC0, 0x1F, 0x00, 0xE0, 0x00, 0x00, + 0x00, 0x00, 0xC0, 0x07, 0x00, 0xFC, 0x01, 0xC0, 0x60, 0x00, 0x1A, 0x0C, 0x60, 0x83, 0x01, 0xE4, + 0x38, 0x80, 0xF8, 0x03, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x90, 0x3F, 0x00, 0x1A, + 0x0C, 0x20, 0x83, 0x01, 0x6C, 0x30, 0x00, 0x1D, 0x07, 0x20, 0x7F, 0x00, 0x80, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x1F, 0x00, 0xF2, 0x07, 0x60, 0x83, 0x01, 0x6C, 0x30, 0x80, 0x0D, 0x06, 0xB0, 0xE3, + 0x00, 0xE2, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x03, 0x60, 0xFE, 0x00, 0x6C, 0x30, + 0x00, 0x0C, 0x06, 0x80, 0xC1, 0x00, 0x76, 0x1C, 0xC0, 0xFC, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x03, 0x00, 0x60, 0x00, 0xC0, 0x6C, 0x00, 0x98, 0x0D, 0x00, 0x30, 0x00, + 0x00, 0x06, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0F, 0x00, 0xF8, 0x0F, 0x80, 0xE1, 0x00, + 0x30, 0x1F, 0x00, 0x1E, 0x03, 0xC0, 0x71, 0x00, 0xF4, 0x07, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, + 0xFC, 0x01, 0x90, 0xFF, 0x00, 0x02, 0x1C, 0xC0, 0x00, 0x03, 0x10, 0x60, 0x00, 0xF8, 0x07, 0x00, + 0xFF, 0x01, 0xE0, 0x3F, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x00, 0xF0, 0x1F, 0x00, 0x80, 0x03, 0x10, + 0x60, 0x00, 0x03, 0x0C, 0x20, 0xFF, 0x00, 0xE4, 0x3F, 0x00, 0xFC, 0x07, 0x00, 0x00, 0x00, 0xF0, + 0x07, 0x80, 0xFE, 0x03, 0x10, 0x70, 0x00, 0x01, 0x0C, 0x60, 0x80, 0x01, 0xE8, 0x1F, 0x00, 0xFD, + 0x07, 0x80, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0xD8, 0x7F, 0x00, 0x03, 0x0E, 0x00, 0x80, + 0x01, 0x00, 0x30, 0x80, 0xFD, 0x03, 0xB0, 0xFF, 0x00, 0xF0, 0x1F, 0x00, 0x02, 0x00, 0xC0, 0x01, + 0x02, 0xF8, 0x60, 0x00, 0x7C, 0x0E, 0x08, 0xFE, 0x80, 0xC1, 0x07, 0x10, 0x3E, 0x00, 0xF2, 0x01, + 0x00, 0x0E, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x0F, 0xFC, 0xFF, 0x01, 0x08, 0x02, + 0x80, 0xC1, 0x00, 0x30, 0x18, 0x00, 0xDE, 0x03, 0x80, 0x3F, 0x00, 0xC0, 0x01, 0x00, 0x01, 0x00, + 0xE0, 0x00, 0x81, 0x7D, 0x30, 0x30, 0x3E, 0x07, 0x00, 0x7F, 0x00, 0xE0, 0x03, 0x18, 0x1F, 0x00, + 0xFB, 0x00, 0x00, 0x07, 0x00, 0x20, 0x00, 0x00 +}; + +static struct fontDesc_t const Roboto_12_Desc = { + sizeof(Roboto_12_Bytes), // total Size + 11, // width in pixel + 21, // height in pixel + 1, // bits per pixel + 0x01, // Code of first char + 0xFF, // Code of last char + Roboto_12_Bytes // Data +}; + +#endif diff --git a/lib/Display/Fonts/Terminal_11.h b/lib/Display/Fonts/Terminal_11.h new file mode 100644 index 0000000..524671e --- /dev/null +++ b/lib/Display/Fonts/Terminal_11.h @@ -0,0 +1,381 @@ +/* + created with FontEditor written by H. Reddmann + HaReddmann at t-online dot de + + File Name : Terminal_11.h + Date : 29.06.2016 + Font size in bytes : 0x129C, 4764 + Font width : 11 + Font height : 18 + Font first char : 0x01 + Font last char : 0xFE + Font bits per pixel : 1 + Font is compressed : false + + The font data are defined as + + struct _FONT_ { + // common shared fields + uint16_t font_Size_in_Bytes_over_all_included_Size_it_self; + uint8_t font_Width_in_Pixel_for_fixed_drawing; + uint8_t font_Height_in_Pixel_for_all_Characters; + uint8_t font_Bits_per_Pixels; + // if MSB are set then font is a compressed font + uint8_t font_First_Char; + uint8_t font_Last_Char; + uint8_t font_Char_Widths[font_Last_Char - font_First_Char +1]; + // for each character the separate width in pixels, + // characters < 128 have an implicit virtual right empty row + // characters with font_Char_Widths[] == 0 are undefined + + // if compressed font then additional fields + uint8_t font_Byte_Padding; + // each Char in the table are aligned in size to this value + uint8_t font_RLE_Table[3]; + // Run Length Encoding Table for compression + uint8_t font_Char_Size_in_Bytes[font_Last_Char - font_First_Char +1]; + // for each char the size in (bytes / font_Byte_Padding) are stored, + // this get us the table to seek to the right beginning of each char + // in the font_data[]. + + // for compressed and uncompressed fonts + uint8_t font_data[]; + // bit field of all characters + } +*/ + +#include "FontDesc.h" + +#ifndef Terminal_11_FONT_H +#define Terminal_11_FONT_H + +#define Terminal_11_WIDTH 11 +#define Terminal_11_HEIGHT 18 + +/* +From FontDesc.h +struct fontDesc_t { + unsigned int totalSize; + unsigned char widthInPixel; + unsigned char heightInPixel; + unsigned char bitsPerPixel; + unsigned char firstChar; + unsigned char lastChar; + + unsigned char* pData; +}; +*/ + +static unsigned char const Terminal_11_Bytes[] = { + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x0A, 0x06, 0x0A, 0x09, 0x08, 0x06, 0x08, 0x07, 0x08, + 0x08, 0x06, 0x06, 0x08, 0x08, 0x08, 0x06, 0x06, 0x06, 0x08, 0x08, 0x07, 0x08, 0x08, 0x00, 0x00, + 0x04, 0x06, 0x08, 0x08, 0x08, 0x08, 0x02, 0x04, 0x04, 0x08, 0x08, 0x02, 0x08, 0x02, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x02, 0x02, 0x07, 0x08, 0x07, 0x08, 0x09, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x08, 0x04, 0x08, 0x0A, 0x02, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x06, 0x05, 0x08, 0x06, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x06, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x05, 0x02, 0x05, 0x08, 0x08, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x09, 0x09, 0x07, 0x09, 0x09, 0x08, + 0x09, 0x0A, 0x06, 0x06, 0x09, 0x09, 0x09, 0x09, 0x07, 0x07, 0x07, 0x07, 0x09, 0x09, 0x06, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x09, 0x09, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x09, 0x08, + 0x09, 0x09, 0x09, 0x09, 0x06, 0x08, 0x08, 0x08, 0x06, 0x0A, 0x0A, 0x0A, 0x06, 0x08, 0x0A, 0x09, + 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x07, 0x08, + 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x07, 0x08, 0x08, 0x06, 0x04, 0x06, 0x07, 0x07, + 0xF0, 0x3F, 0x20, 0x00, 0x41, 0x48, 0x08, 0x01, 0x22, 0x04, 0x88, 0x10, 0x12, 0x82, 0x00, 0x04, + 0xFC, 0x0F, 0xF0, 0x3F, 0xE0, 0xFF, 0xC1, 0xB7, 0x0F, 0xFF, 0x3D, 0xFC, 0xF7, 0xF0, 0xED, 0x83, + 0xFF, 0x07, 0xFC, 0x0F, 0xF8, 0x01, 0xF0, 0x3F, 0xC0, 0xFF, 0x03, 0xFE, 0x3F, 0xF8, 0xFF, 0xF0, + 0xFF, 0xC0, 0xFF, 0x00, 0x7E, 0x00, 0x00, 0x03, 0x00, 0x3F, 0x00, 0xFF, 0x03, 0xFF, 0x3F, 0xFC, + 0xFF, 0xC0, 0xFF, 0x00, 0xFC, 0x00, 0xC0, 0x00, 0x00, 0x03, 0x00, 0x1E, 0x82, 0x7B, 0x0E, 0xDF, + 0x3E, 0x7C, 0xFB, 0xE0, 0x9E, 0x03, 0x78, 0x08, 0xC0, 0x00, 0x80, 0x07, 0x00, 0x3F, 0x02, 0x7F, + 0x0E, 0xFF, 0x3F, 0xFC, 0xFF, 0xC0, 0x9F, 0x03, 0xFC, 0x08, 0xE0, 0x01, 0x00, 0x03, 0x00, 0x1E, + 0x00, 0x78, 0x00, 0xC0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0x7F, 0xF8, + 0xFF, 0xE1, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xF0, 0x00, 0x60, 0x06, + 0x80, 0x10, 0x00, 0x42, 0x00, 0x98, 0x01, 0xC0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0xFF, + 0xCF, 0xFC, 0xBF, 0xF7, 0xFF, 0xDE, 0xFF, 0x33, 0xFF, 0x1F, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, + 0xC0, 0x01, 0x80, 0x0F, 0x00, 0x63, 0x00, 0x04, 0x01, 0x18, 0x04, 0xF2, 0x18, 0x68, 0x3E, 0xE0, + 0x70, 0x80, 0x0F, 0x00, 0x1C, 0x00, 0xF8, 0x08, 0x30, 0x26, 0x40, 0xF0, 0x07, 0xC1, 0x1F, 0x8C, + 0x09, 0xE0, 0x23, 0x00, 0x07, 0x00, 0x00, 0x38, 0x00, 0xF0, 0xF0, 0xFF, 0x01, 0x0F, 0x00, 0x3C, + 0x00, 0x80, 0x07, 0x00, 0x80, 0x03, 0x00, 0x0F, 0xF8, 0x1F, 0x60, 0x02, 0xC0, 0x0C, 0x00, 0x99, + 0x03, 0x36, 0x0F, 0xFC, 0x1F, 0x00, 0x92, 0x00, 0xB0, 0x01, 0x40, 0x04, 0xC0, 0x71, 0x00, 0x44, + 0x00, 0xB0, 0x01, 0x20, 0x09, 0xE0, 0x0F, 0x80, 0x3F, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0x80, 0x03, + 0x00, 0x0E, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x38, 0x00, 0xE0, 0x00, + 0xC0, 0x07, 0x00, 0x1F, 0x00, 0xFE, 0x00, 0xF8, 0x03, 0x30, 0x30, 0x60, 0x80, 0xC1, 0xFF, 0x0F, + 0xFF, 0x3F, 0x18, 0x60, 0xC0, 0xC0, 0xC0, 0xFF, 0x0C, 0xFF, 0x33, 0x00, 0x00, 0x00, 0x00, 0xC0, + 0xFF, 0x0C, 0xFF, 0x33, 0xF8, 0x01, 0xF0, 0x0F, 0xC0, 0xFF, 0x0F, 0xFF, 0x3F, 0x04, 0x00, 0x10, + 0x00, 0xC0, 0xFF, 0x0F, 0xFF, 0x3F, 0x18, 0x60, 0xF0, 0x86, 0x43, 0x3F, 0x08, 0x99, 0x21, 0xC4, + 0x8C, 0x10, 0x7E, 0xC2, 0xB1, 0x0F, 0x06, 0x1C, 0x00, 0xF0, 0x00, 0xC0, 0x03, 0x00, 0x0F, 0x00, + 0x3C, 0x00, 0xF0, 0x00, 0xC0, 0x03, 0x00, 0x0F, 0x00, 0x3C, 0x30, 0x30, 0xE0, 0xC0, 0xC1, 0xFF, + 0x0F, 0xFF, 0x3F, 0x38, 0x70, 0xC0, 0xC0, 0x00, 0x03, 0x00, 0x0E, 0x00, 0xFC, 0xFF, 0xF0, 0xFF, + 0x83, 0x03, 0x00, 0x0C, 0x00, 0x00, 0x30, 0x00, 0xC0, 0xC1, 0xFF, 0x0F, 0xFF, 0x3F, 0x00, 0x70, + 0x00, 0xC0, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x00, 0x03, 0x00, 0x0C, 0x00, 0xFC, 0x00, 0xF0, 0x03, + 0x80, 0x07, 0x00, 0x0C, 0x00, 0x60, 0x00, 0xC0, 0x03, 0x80, 0x1F, 0x00, 0x7E, 0x00, 0x60, 0x00, + 0x80, 0x01, 0x00, 0x06, 0x00, 0x18, 0x00, 0x80, 0x03, 0x00, 0x0E, 0x00, 0x20, 0x00, 0x80, 0x00, + 0x00, 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x18, 0x00, 0xF0, 0x00, 0xE0, 0x07, 0x00, 0x06, 0x00, + 0x18, 0x00, 0xF8, 0x01, 0xC0, 0x03, 0x00, 0x06, 0x00, 0x30, 0x00, 0xF0, 0x00, 0xF0, 0x03, 0xF0, + 0x0F, 0xC0, 0x3F, 0x00, 0xFC, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0xE0, 0x03, 0xC0, 0xFF, 0x0C, 0xFF, + 0x33, 0xF8, 0x00, 0x70, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xC0, 0x01, + 0x00, 0x20, 0x01, 0xF8, 0x7F, 0xE0, 0xFF, 0x01, 0x48, 0x00, 0x20, 0x01, 0xF8, 0x7F, 0xE0, 0xFF, + 0x01, 0x48, 0x00, 0x38, 0x06, 0xF0, 0x38, 0x40, 0x86, 0xC0, 0xFF, 0x0F, 0xFF, 0x3F, 0x10, 0x26, + 0xC0, 0xF1, 0x00, 0xC6, 0x01, 0x1E, 0x30, 0xCC, 0x70, 0xE0, 0x71, 0x00, 0x70, 0x00, 0x70, 0x00, + 0x70, 0x78, 0x70, 0x30, 0x43, 0x80, 0x07, 0x1E, 0x1F, 0xCC, 0xC6, 0x10, 0x0E, 0x42, 0x38, 0x08, + 0xB3, 0x31, 0x78, 0x7C, 0x00, 0xB0, 0x01, 0x60, 0x0C, 0x0B, 0x00, 0x1C, 0x00, 0x80, 0x7F, 0xC0, + 0xFF, 0x8F, 0x07, 0x78, 0x02, 0x00, 0x09, 0x00, 0xE4, 0x01, 0x1E, 0xFF, 0x3F, 0xE0, 0x1F, 0x00, + 0x08, 0x00, 0xA8, 0x00, 0xE0, 0x03, 0x00, 0x07, 0x00, 0x1C, 0x00, 0xF8, 0x00, 0xA0, 0x02, 0x00, + 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x00, 0x80, 0x0F, 0x00, 0x3E, 0x00, 0x20, 0x00, 0x80, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x0B, 0x00, 0x1C, 0x80, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x20, + 0x00, 0x80, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x00, + 0x03, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0C, 0x00, + 0xC0, 0xFF, 0x80, 0xFF, 0x07, 0x03, 0x36, 0x04, 0x86, 0x10, 0x06, 0xC2, 0x06, 0x0C, 0xFE, 0x1F, + 0xF0, 0x3F, 0x40, 0x00, 0x02, 0x01, 0x08, 0x06, 0x20, 0xFC, 0xFF, 0xF0, 0xFF, 0x03, 0x00, 0x08, + 0x00, 0x20, 0x00, 0x80, 0xC0, 0x80, 0x83, 0x03, 0x0F, 0x03, 0x26, 0x04, 0x8C, 0x10, 0x18, 0xC2, + 0x30, 0x08, 0x7E, 0x20, 0xF0, 0x80, 0xC0, 0xC0, 0x80, 0x03, 0x07, 0x43, 0x30, 0x04, 0x81, 0x10, + 0x04, 0xC2, 0x10, 0x0C, 0xFE, 0x1F, 0xF0, 0x3E, 0x00, 0xF0, 0x00, 0xF8, 0x03, 0xFC, 0x08, 0x7C, + 0x20, 0x30, 0xF8, 0x03, 0xE0, 0x0F, 0x00, 0x08, 0x00, 0x20, 0xF0, 0xC3, 0xC0, 0x0F, 0x07, 0x21, + 0x30, 0x84, 0x80, 0x10, 0x02, 0x42, 0x18, 0x0C, 0xC1, 0x1F, 0x04, 0x3E, 0x00, 0xFE, 0x00, 0xFE, + 0x07, 0x5C, 0x30, 0x18, 0x81, 0x30, 0x04, 0x42, 0x30, 0x0C, 0x81, 0x1F, 0x04, 0x3C, 0x10, 0x00, + 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0xF0, 0x10, 0xF8, 0x43, 0xFC, 0x00, 0x7F, 0x00, 0x3C, 0x00, + 0xC0, 0xF1, 0x80, 0xEF, 0x07, 0xE3, 0x30, 0x04, 0x81, 0x10, 0x04, 0xC2, 0x38, 0x0C, 0xBE, 0x1F, + 0x70, 0x3C, 0xC0, 0x03, 0x82, 0x1F, 0x08, 0xC3, 0x20, 0x04, 0xC2, 0x10, 0x88, 0xC1, 0xA0, 0x03, + 0xFE, 0x07, 0xF0, 0x07, 0x00, 0x06, 0x03, 0x18, 0x0C, 0x60, 0xB0, 0x80, 0xC1, 0x01, 0x08, 0x00, + 0x70, 0x00, 0x60, 0x03, 0xC0, 0x18, 0x80, 0xC1, 0x00, 0x03, 0x06, 0x04, 0x10, 0x80, 0x04, 0x00, + 0x12, 0x00, 0x48, 0x00, 0x20, 0x01, 0x80, 0x04, 0x00, 0x12, 0x00, 0x48, 0x00, 0x20, 0x01, 0x10, + 0x40, 0xC0, 0x80, 0x01, 0x06, 0x03, 0x30, 0x06, 0x80, 0x0D, 0x00, 0x1C, 0x00, 0x20, 0x00, 0x06, + 0x00, 0x1C, 0x00, 0x30, 0x00, 0x40, 0xC0, 0x0C, 0xC1, 0x33, 0xCC, 0x03, 0xF0, 0x03, 0x80, 0x07, + 0x00, 0xFC, 0x0F, 0xF8, 0x7F, 0x30, 0x00, 0x43, 0x78, 0x08, 0xF1, 0x23, 0x44, 0x88, 0x30, 0x11, + 0x82, 0xFF, 0x0C, 0xFC, 0x13, 0xF0, 0xFF, 0xE0, 0xFF, 0xC3, 0x40, 0x00, 0x01, 0x01, 0x04, 0x04, + 0x30, 0x10, 0x80, 0xFF, 0x0F, 0xFC, 0x3F, 0xFC, 0xFF, 0xF0, 0xFF, 0x43, 0x10, 0x08, 0x41, 0x20, + 0x04, 0x81, 0x30, 0x0E, 0x83, 0xEF, 0x07, 0x1C, 0x0F, 0xF0, 0x3F, 0xE0, 0xFF, 0xC1, 0x00, 0x0C, + 0x01, 0x20, 0x04, 0x80, 0x30, 0x00, 0x83, 0x03, 0x07, 0x0C, 0x0C, 0xFC, 0xFF, 0xF0, 0xFF, 0x43, + 0x00, 0x08, 0x01, 0x20, 0x04, 0x80, 0x70, 0x80, 0x83, 0xFF, 0x07, 0xF8, 0x07, 0xFC, 0xFF, 0xF0, + 0xFF, 0x43, 0x10, 0x08, 0x41, 0x20, 0x04, 0x81, 0x10, 0x04, 0x42, 0x10, 0x08, 0x01, 0x20, 0xFC, + 0xFF, 0xF0, 0xFF, 0x43, 0x20, 0x00, 0x81, 0x00, 0x04, 0x02, 0x10, 0x08, 0x40, 0x20, 0x00, 0x01, + 0x00, 0xF0, 0x3F, 0xE0, 0xFF, 0xC1, 0x00, 0x0C, 0x01, 0x20, 0x04, 0x82, 0x30, 0x08, 0x83, 0xE3, + 0x07, 0x8C, 0x0F, 0xFC, 0xFF, 0xF0, 0xFF, 0x03, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, + 0xC0, 0xFF, 0x0F, 0xFF, 0x3F, 0x04, 0x80, 0x10, 0x00, 0x42, 0x00, 0x08, 0xFF, 0x3F, 0xFC, 0xFF, + 0x10, 0x00, 0x42, 0x00, 0x08, 0x01, 0x20, 0x00, 0x30, 0x00, 0xC0, 0x01, 0x00, 0x0C, 0x00, 0x20, + 0x00, 0x80, 0x00, 0x00, 0xC3, 0xFF, 0x07, 0xFF, 0x0F, 0xFC, 0xFF, 0xF0, 0xFF, 0x03, 0x30, 0x00, + 0xE0, 0x01, 0xE0, 0x1C, 0xC0, 0xE1, 0xC0, 0x03, 0x0F, 0x03, 0x30, 0xFC, 0xFF, 0xF0, 0xFF, 0x03, + 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x20, 0xFC, 0xFF, 0xF0, + 0xFF, 0x03, 0x1E, 0x00, 0xC0, 0x03, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0xFF, 0x0F, 0xFF, 0x3F, 0xFC, + 0xFF, 0xF0, 0xFF, 0x03, 0x07, 0x00, 0x70, 0x00, 0x00, 0x07, 0x00, 0x70, 0xC0, 0xFF, 0x0F, 0xFF, + 0x3F, 0xF0, 0x3F, 0xE0, 0xFF, 0xC1, 0x00, 0x0C, 0x01, 0x20, 0x04, 0x80, 0x30, 0x00, 0x83, 0xFF, + 0x07, 0xFC, 0x0F, 0xFC, 0xFF, 0xF0, 0xFF, 0x43, 0x20, 0x00, 0x81, 0x00, 0x04, 0x02, 0x30, 0x0C, + 0x80, 0x1F, 0x00, 0x3C, 0x00, 0xF0, 0x3F, 0xE0, 0xFF, 0xC1, 0x00, 0x0C, 0x01, 0x20, 0x04, 0x80, + 0x31, 0x00, 0x8F, 0xFF, 0x27, 0xFC, 0x0F, 0xFC, 0xFF, 0xF0, 0xFF, 0x43, 0x20, 0x00, 0x81, 0x00, + 0x04, 0x06, 0x30, 0xFC, 0x81, 0x9F, 0x0F, 0x3C, 0x20, 0xF0, 0x30, 0xE0, 0xC7, 0xC1, 0x18, 0x0C, + 0xE1, 0x20, 0x04, 0x87, 0x30, 0x18, 0x83, 0xE3, 0x07, 0x0C, 0x0F, 0x04, 0x00, 0x10, 0x00, 0x40, + 0x00, 0x00, 0xFF, 0x3F, 0xFC, 0xFF, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0xFC, 0x3F, 0xF0, + 0xFF, 0x01, 0x00, 0x0C, 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, 0xC3, 0xFF, 0x07, 0xFF, 0x0F, 0xFC, + 0x00, 0xF0, 0x1F, 0x00, 0xF0, 0x03, 0x00, 0x3C, 0x00, 0xF0, 0x00, 0xFC, 0xC0, 0x7F, 0x00, 0x3F, + 0x00, 0xFC, 0x07, 0xF0, 0xFF, 0x03, 0x80, 0x0F, 0xC0, 0x01, 0x00, 0x07, 0x00, 0xE0, 0xC3, 0xFF, + 0x0F, 0xFF, 0x01, 0x3C, 0xF0, 0xF0, 0xF3, 0x03, 0xFC, 0x00, 0xC0, 0x00, 0x00, 0x03, 0x00, 0x3F, + 0xC0, 0xCF, 0x0F, 0x0F, 0x3C, 0xFC, 0x00, 0xF0, 0x0F, 0x00, 0x70, 0x00, 0x80, 0x3F, 0x00, 0xFE, + 0x00, 0x1C, 0xC0, 0x3F, 0x00, 0x3F, 0x00, 0x04, 0xE0, 0x10, 0xE0, 0x43, 0xE0, 0x09, 0xC1, 0x21, + 0x84, 0x81, 0x90, 0x03, 0xC2, 0x07, 0x08, 0x07, 0x20, 0xFC, 0xFF, 0xF0, 0xFF, 0x43, 0x00, 0x08, + 0x01, 0x20, 0x0C, 0x00, 0xF0, 0x00, 0x00, 0x0F, 0x00, 0xF0, 0x00, 0x00, 0x0F, 0x00, 0xF0, 0x00, + 0x00, 0x0F, 0x00, 0x30, 0x04, 0x80, 0x10, 0x00, 0xC2, 0xFF, 0x0F, 0xFF, 0x3F, 0x10, 0x00, 0x40, + 0x00, 0x80, 0x01, 0x00, 0x03, 0x00, 0x0C, 0x00, 0x60, 0x00, 0x80, 0x01, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, + 0x80, 0x00, 0x00, 0x02, 0x00, 0xC8, 0x01, 0x00, 0x0B, 0x00, 0x00, 0x78, 0x00, 0xF4, 0x03, 0x48, + 0x08, 0x20, 0x21, 0x80, 0x84, 0x00, 0x12, 0x01, 0xF8, 0x0F, 0xC0, 0x3F, 0xFC, 0xFF, 0xF0, 0xFF, + 0x03, 0x10, 0x04, 0x20, 0x20, 0x80, 0x80, 0x00, 0x06, 0x03, 0xF0, 0x07, 0x80, 0x0F, 0x00, 0x3E, + 0x00, 0xFC, 0x01, 0x18, 0x0C, 0x20, 0x20, 0x80, 0x80, 0x00, 0x02, 0x02, 0x18, 0x0C, 0x40, 0x10, + 0x00, 0x3E, 0x00, 0xFC, 0x01, 0x18, 0x0C, 0x20, 0x20, 0x80, 0x80, 0x00, 0x04, 0xC1, 0xFF, 0x0F, + 0xFF, 0x3F, 0x00, 0x3E, 0x00, 0xFC, 0x01, 0x98, 0x0C, 0x20, 0x22, 0x80, 0x88, 0x00, 0x26, 0x02, + 0xF0, 0x0C, 0x80, 0x13, 0x80, 0x00, 0x00, 0x02, 0x80, 0xFF, 0x0F, 0xFF, 0x3F, 0x84, 0x00, 0x10, + 0x02, 0xC0, 0x08, 0x00, 0x02, 0x00, 0x00, 0x1E, 0x01, 0xFC, 0x04, 0x18, 0x36, 0x20, 0x90, 0x80, + 0x40, 0x02, 0x84, 0x0C, 0xF8, 0x1F, 0xE0, 0x3F, 0xFC, 0xFF, 0xF0, 0xFF, 0x03, 0x10, 0x00, 0x20, + 0x00, 0x80, 0x00, 0x00, 0x06, 0x00, 0xF0, 0x0F, 0x80, 0x3F, 0x80, 0x80, 0x00, 0x02, 0xC2, 0xF8, + 0x0F, 0xE3, 0x3F, 0x00, 0x80, 0x00, 0x00, 0x02, 0x00, 0x10, 0x20, 0xC0, 0x80, 0x00, 0x32, 0xFE, + 0xCF, 0xF8, 0x1F, 0xFF, 0x3F, 0xFC, 0xFF, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x0D, 0x00, 0x63, + 0x00, 0x06, 0x03, 0x08, 0x08, 0x01, 0x20, 0x04, 0x80, 0xF0, 0xFF, 0xC3, 0xFF, 0x0F, 0x00, 0x20, + 0x00, 0x80, 0x00, 0xFE, 0x03, 0xF8, 0x0F, 0x60, 0x00, 0x00, 0x7F, 0x00, 0xFC, 0x01, 0x18, 0x00, + 0xE0, 0x3F, 0x00, 0xFF, 0x00, 0xFE, 0x03, 0xF8, 0x0F, 0x40, 0x00, 0x80, 0x00, 0x00, 0x02, 0x00, + 0x18, 0x00, 0xC0, 0x3F, 0x00, 0xFE, 0x00, 0xF8, 0x00, 0xF0, 0x07, 0x60, 0x30, 0x80, 0x80, 0x00, + 0x02, 0x02, 0x18, 0x0C, 0xC0, 0x1F, 0x00, 0x3E, 0x00, 0xFE, 0x0F, 0xF8, 0x3F, 0x40, 0x10, 0x80, + 0x80, 0x00, 0x02, 0x02, 0x18, 0x0C, 0xC0, 0x1F, 0x00, 0x3E, 0x00, 0xF8, 0x00, 0xF0, 0x07, 0x20, + 0x20, 0x80, 0x80, 0x00, 0x02, 0x02, 0x10, 0x04, 0xE0, 0xFF, 0x80, 0xFF, 0x03, 0xFE, 0x03, 0xF8, + 0x0F, 0xC0, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x18, 0x00, 0x60, 0x00, 0x00, 0x01, 0x00, 0x0C, + 0x01, 0x78, 0x0C, 0x20, 0x21, 0x80, 0x8C, 0x00, 0x62, 0x02, 0x08, 0x09, 0x60, 0x3C, 0x00, 0x61, + 0x00, 0x02, 0x00, 0x08, 0x00, 0xFE, 0x1F, 0xF8, 0xFF, 0x00, 0x02, 0x02, 0x08, 0x08, 0xE0, 0x1F, + 0x80, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x40, 0x00, 0xFE, 0x03, 0xF8, 0x0F, + 0xE0, 0x03, 0x80, 0x1F, 0x00, 0xC0, 0x01, 0x00, 0x0C, 0x00, 0x30, 0x00, 0x70, 0x00, 0x7E, 0x00, + 0xF8, 0x00, 0xE0, 0x07, 0x80, 0xFF, 0x00, 0x80, 0x03, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0xE0, 0x00, + 0xFE, 0x03, 0xF8, 0x01, 0x60, 0x30, 0x80, 0xF7, 0x00, 0xD8, 0x00, 0xC0, 0x01, 0x00, 0x07, 0x00, + 0x36, 0x00, 0xDE, 0x03, 0x18, 0x0C, 0xE0, 0x83, 0x80, 0x3F, 0x02, 0xC0, 0x0D, 0x00, 0x1C, 0x00, + 0x30, 0x00, 0x70, 0x00, 0xFE, 0x00, 0xF8, 0x00, 0x20, 0x30, 0x80, 0xE0, 0x00, 0xC2, 0x02, 0x88, + 0x09, 0x20, 0x23, 0x80, 0x86, 0x00, 0x0E, 0x02, 0x18, 0x08, 0x80, 0x00, 0xF8, 0xFF, 0xF0, 0xF7, + 0x47, 0x00, 0x10, 0x01, 0x40, 0xFC, 0xFF, 0xF3, 0xFF, 0x4F, 0x00, 0x10, 0x01, 0x40, 0xFC, 0xFD, + 0xE1, 0xFF, 0x03, 0x20, 0x00, 0x02, 0x00, 0x08, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x02, 0x00, + 0x08, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0xE0, 0x3F, 0xE0, 0xFF, 0xC0, 0x01, 0xC3, 0x01, 0x0C, + 0x07, 0x30, 0x70, 0xC0, 0x80, 0xFF, 0x03, 0xF8, 0x0F, 0x00, 0x00, 0xF0, 0x3F, 0xE0, 0xFF, 0xC1, + 0x00, 0x0C, 0x01, 0xA0, 0x04, 0x80, 0x33, 0x00, 0x87, 0x03, 0x07, 0x0C, 0x0C, 0x00, 0x00, 0x00, + 0xFE, 0xC1, 0xF8, 0x0F, 0x03, 0x20, 0x00, 0x80, 0x00, 0x00, 0xC2, 0x00, 0x04, 0xE3, 0x3F, 0x80, + 0xFF, 0x00, 0x00, 0x00, 0xE0, 0x03, 0xC0, 0x1F, 0x80, 0xC9, 0x00, 0x22, 0x82, 0x88, 0x08, 0x63, + 0x22, 0x04, 0xCF, 0x10, 0x38, 0x01, 0x00, 0x00, 0x00, 0x1E, 0x00, 0xFD, 0x40, 0x12, 0x82, 0x49, + 0x08, 0x23, 0x21, 0x8C, 0x44, 0x60, 0xFE, 0x03, 0xF1, 0x0F, 0x00, 0x00, 0x00, 0x78, 0x30, 0xF4, + 0xC3, 0x48, 0x08, 0x20, 0x21, 0x80, 0x84, 0x30, 0x12, 0xC1, 0xF8, 0x0F, 0xC0, 0x3F, 0x00, 0x00, + 0x00, 0xE0, 0x01, 0xD0, 0x0F, 0x21, 0x21, 0x84, 0x84, 0x30, 0x12, 0x82, 0x48, 0x04, 0xE0, 0x3F, + 0x00, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x07, 0x40, 0x3F, 0x88, 0x84, 0x70, 0x12, 0x42, 0x49, 0x08, + 0x27, 0x11, 0x88, 0xFF, 0x00, 0xFC, 0x03, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x7F, 0x00, 0x06, 0x03, + 0x08, 0x28, 0x20, 0xE0, 0x80, 0x80, 0x01, 0x06, 0x03, 0x10, 0x04, 0x00, 0x00, 0x00, 0x3E, 0x00, + 0xFC, 0x01, 0x99, 0x0C, 0x26, 0x22, 0x8C, 0x88, 0x60, 0x26, 0x02, 0xF1, 0x0C, 0x80, 0x13, 0x00, + 0x00, 0x00, 0xF8, 0xC0, 0xF0, 0x07, 0x63, 0x32, 0x80, 0x88, 0x00, 0x22, 0xC2, 0x98, 0x08, 0xC3, + 0x33, 0x00, 0x4E, 0x00, 0x00, 0x00, 0xE0, 0x03, 0xC0, 0x1F, 0x84, 0xC9, 0x10, 0x22, 0xC2, 0x88, + 0x08, 0x62, 0x22, 0x00, 0xCF, 0x00, 0x38, 0x01, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x80, 0x30, 0x02, + 0x02, 0xF8, 0x0F, 0xE0, 0x3F, 0x0C, 0x80, 0x30, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x90, 0x80, + 0x60, 0x02, 0xC2, 0xF8, 0x0F, 0xE3, 0x3F, 0x18, 0x80, 0x40, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x84, 0x80, 0x10, 0x02, 0xC2, 0xF8, 0x0F, 0xE2, 0x3F, 0x00, 0x80, 0x00, 0x00, 0x02, 0x00, 0x00, + 0xC0, 0x3F, 0x8C, 0xFF, 0x30, 0x23, 0x00, 0x84, 0x00, 0x10, 0x02, 0xCC, 0x08, 0x30, 0xFE, 0x03, + 0xF0, 0x0F, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFE, 0x03, 0x8C, 0x00, 0x13, 0x02, 0x52, 0x08, 0x30, + 0x23, 0x00, 0xF8, 0x0F, 0xC0, 0x3F, 0x00, 0x00, 0x00, 0xFF, 0x03, 0xFC, 0x0F, 0x10, 0x21, 0x40, + 0x84, 0x20, 0x11, 0xC2, 0x44, 0x08, 0x11, 0x21, 0x44, 0x80, 0x00, 0x00, 0x00, 0x90, 0x07, 0x20, + 0x3F, 0x80, 0x84, 0x00, 0xFC, 0x03, 0xF8, 0x07, 0x20, 0x22, 0x80, 0x8F, 0x00, 0x3C, 0x01, 0x00, + 0x00, 0xF8, 0x3F, 0xF0, 0xFF, 0xE0, 0x10, 0xC0, 0xFF, 0x0F, 0xFF, 0x3F, 0x04, 0x82, 0x10, 0x08, + 0x42, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3E, 0x00, 0xFC, 0x01, 0x19, 0x0C, 0x26, 0x20, 0x8C, 0x80, + 0x60, 0x06, 0x03, 0xF1, 0x07, 0x80, 0x0F, 0x00, 0x00, 0x00, 0xF8, 0xC0, 0xF0, 0x07, 0x63, 0x30, + 0x80, 0x80, 0x00, 0x02, 0xC2, 0x18, 0x0C, 0xC3, 0x1F, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xE0, 0x03, + 0xC1, 0x1F, 0x84, 0xC1, 0x30, 0x02, 0x82, 0x08, 0x08, 0x60, 0x30, 0x00, 0x7F, 0x00, 0xF8, 0x00, + 0x00, 0x00, 0xE0, 0x1F, 0x80, 0xFF, 0x40, 0x00, 0x82, 0x01, 0x08, 0x03, 0x20, 0x18, 0x40, 0x40, + 0xFE, 0x03, 0xF8, 0x0F, 0x00, 0x00, 0x80, 0x7F, 0x10, 0xFE, 0x43, 0x00, 0x08, 0x03, 0x20, 0x08, + 0x80, 0x00, 0x00, 0x01, 0xF8, 0x0F, 0xE0, 0x3F, 0x00, 0x00, 0x00, 0x3E, 0xC8, 0xF8, 0x23, 0x03, + 0xCC, 0x00, 0xE0, 0x01, 0x80, 0xC3, 0x00, 0x07, 0xE3, 0x0F, 0x80, 0x0F, 0x00, 0x00, 0x00, 0xF0, + 0x03, 0xE3, 0x1F, 0xCC, 0xC0, 0x00, 0x01, 0x02, 0x04, 0x08, 0x33, 0x30, 0x8C, 0x7F, 0x00, 0xFC, + 0x00, 0x00, 0x00, 0xF0, 0x0F, 0xCC, 0x7F, 0x30, 0x00, 0x03, 0x00, 0x08, 0x00, 0x20, 0x0C, 0xC0, + 0x30, 0xFF, 0x01, 0xFC, 0x03, 0x00, 0x00, 0x00, 0xBE, 0x01, 0xFC, 0x07, 0x18, 0x0E, 0x20, 0x2F, + 0x80, 0x9E, 0x00, 0x0E, 0x03, 0xFC, 0x07, 0xB0, 0x0F, 0x00, 0x00, 0xC0, 0x09, 0x83, 0xFF, 0x0F, + 0xE3, 0x2F, 0x04, 0x82, 0x10, 0x08, 0x42, 0x20, 0x08, 0x03, 0x30, 0x08, 0x40, 0x00, 0x00, 0x00, + 0xFF, 0x1B, 0xFE, 0x7F, 0x0C, 0xF8, 0x10, 0x7E, 0x42, 0x7E, 0x08, 0x1F, 0x30, 0xFE, 0x7F, 0xD8, + 0xFF, 0x00, 0x00, 0x00, 0x18, 0x06, 0xE0, 0x1C, 0x00, 0x3F, 0x00, 0x78, 0x00, 0xE0, 0x01, 0xC0, + 0x0F, 0x80, 0x73, 0x00, 0x86, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x08, 0x10, 0x20, 0xFE, + 0xFF, 0xFC, 0xFF, 0x11, 0x04, 0x40, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x01, 0xD0, + 0x0F, 0x20, 0x21, 0x80, 0x84, 0x20, 0x12, 0xC2, 0x48, 0x04, 0xE1, 0x3F, 0x04, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x20, 0x80, 0x80, 0x20, 0xFE, 0xC3, 0xF8, 0x0F, 0x01, 0x20, 0x04, 0x00, + 0x00, 0x00, 0x00, 0xE0, 0x03, 0xC0, 0x1F, 0x80, 0xC1, 0x00, 0x02, 0x82, 0x08, 0x08, 0x63, 0x30, + 0x04, 0x7F, 0x10, 0xF8, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x80, 0xFF, 0x00, 0x00, 0x82, 0x00, 0x08, + 0x03, 0x20, 0x04, 0x40, 0x10, 0xFE, 0x03, 0xF8, 0x0F, 0x00, 0x00, 0x80, 0xFF, 0x00, 0xFE, 0x83, + 0x10, 0x00, 0x21, 0x00, 0x8C, 0x00, 0x20, 0x06, 0x40, 0xF0, 0x0F, 0x80, 0x3F, 0x00, 0x00, 0x00, + 0xFF, 0x03, 0xFC, 0x0F, 0x62, 0x00, 0x04, 0x03, 0x30, 0x18, 0x80, 0xC0, 0x00, 0xF1, 0x3F, 0xC0, + 0xFF, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x38, 0x01, 0x14, 0x05, 0x50, 0x14, 0x40, 0x51, 0x00, 0x45, + 0x01, 0xFC, 0x05, 0xE0, 0x17, 0x00, 0x00, 0x00, 0x1C, 0x01, 0xF8, 0x04, 0x30, 0x16, 0x40, 0x50, + 0x00, 0x41, 0x01, 0x8C, 0x05, 0xE0, 0x13, 0x00, 0x47, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xF0, + 0x03, 0xF0, 0x0C, 0xF3, 0x20, 0xCC, 0x80, 0x00, 0x00, 0x03, 0x00, 0x0E, 0x00, 0x18, 0xF0, 0x3F, + 0xE0, 0xFF, 0xC1, 0x00, 0x0C, 0xF1, 0x23, 0x44, 0x82, 0x10, 0x36, 0xC2, 0x00, 0x0C, 0xFE, 0x1F, + 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x00, + 0x00, 0x0E, 0x00, 0x38, 0x00, 0x00, 0x40, 0x08, 0x98, 0x3F, 0x18, 0x80, 0x18, 0x00, 0x18, 0x00, + 0x98, 0x18, 0x18, 0x51, 0x18, 0x24, 0x19, 0x60, 0x04, 0x00, 0x00, 0x21, 0x60, 0xFE, 0x60, 0x00, + 0x62, 0x00, 0x60, 0x00, 0x60, 0x18, 0x60, 0x58, 0x60, 0x90, 0x67, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC0, 0x07, 0xF3, 0x3F, 0xCC, 0xFF, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x3C, 0x00, 0x98, 0x01, 0x30, 0x0C, 0x00, 0x06, 0x00, 0x3C, 0x00, 0x98, 0x01, 0x30, + 0x0C, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x98, 0x01, 0xC0, 0x03, 0x00, 0x06, 0x00, 0xC3, 0x00, 0x98, + 0x01, 0xC0, 0x03, 0x00, 0x06, 0x08, 0x11, 0x02, 0x00, 0x20, 0x44, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x44, 0x08, 0x00, 0x80, 0x10, 0x21, 0xAA, 0xAA, 0x02, 0x00, 0x00, 0x00, 0x40, 0x55, 0x55, + 0x00, 0x00, 0xA8, 0xAA, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0xA5, 0xAA, 0x6A, + 0x55, 0x55, 0xAA, 0xAA, 0x56, 0x55, 0xA5, 0xAA, 0x6A, 0x55, 0x55, 0xAA, 0xAA, 0x56, 0x55, 0xA5, + 0xAA, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x03, + 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0xF0, 0xFF, 0x3F, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0xFE, 0x83, 0x8C, 0x00, 0x13, 0x02, 0x44, 0x08, 0x10, 0x23, 0x00, 0xF8, 0x0F, 0xC0, + 0x3F, 0x00, 0x00, 0x00, 0xFC, 0x03, 0xF8, 0x0F, 0x32, 0x02, 0x4C, 0x08, 0x18, 0x21, 0xC0, 0x8C, + 0x00, 0xE2, 0x3F, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xF0, 0x0F, 0xE0, 0x3F, 0xC4, 0x08, 0x10, 0x21, + 0xC0, 0x84, 0x00, 0x32, 0x02, 0x80, 0xFF, 0x00, 0xFC, 0x03, 0xFF, 0x03, 0xFE, 0x1F, 0x0C, 0xC0, + 0x10, 0x1E, 0x42, 0x84, 0x08, 0x21, 0x21, 0x0C, 0xC0, 0xE0, 0xFF, 0x01, 0xFF, 0x03, 0xA0, 0x00, + 0x80, 0x02, 0x00, 0x0A, 0x00, 0x28, 0xC0, 0xBF, 0xFF, 0x00, 0x00, 0xFC, 0xFF, 0x0F, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x3F, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x0A, 0x00, + 0x28, 0x00, 0xA0, 0x00, 0x80, 0x02, 0x00, 0xFA, 0x0F, 0x08, 0x00, 0xE0, 0xFF, 0x80, 0x02, 0x00, + 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x00, 0xFF, 0x02, 0x00, 0x08, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x3F, 0x00, 0xFF, 0x01, 0x04, 0x04, 0xFC, 0x7F, 0x40, 0x40, 0x00, 0xC7, 0x01, 0x18, + 0x03, 0x00, 0x00, 0x30, 0x00, 0xC0, 0x47, 0x01, 0x7C, 0x05, 0x80, 0xFF, 0x00, 0xFE, 0x03, 0x5F, + 0x01, 0x1F, 0x05, 0x0C, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, + 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x01, + 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, + 0x00, 0x01, 0x00, 0x04, 0xF0, 0x1F, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, + 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0xFF, 0x03, 0x04, 0x00, + 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xF0, 0xFF, 0x3F, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, + 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, + 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0xF0, 0xFF, + 0x3F, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xF4, + 0x83, 0x48, 0x08, 0x21, 0x21, 0x8C, 0x84, 0x20, 0x12, 0x41, 0xF8, 0x0F, 0xC0, 0x3F, 0x00, 0x00, + 0x00, 0xFC, 0x03, 0xF8, 0x0F, 0x32, 0x02, 0x44, 0x08, 0x30, 0x21, 0x80, 0x8C, 0x00, 0xE1, 0x3F, + 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x20, 0xC0, + 0xBF, 0x00, 0x80, 0x02, 0x00, 0x0A, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE0, 0xFF, 0x80, 0x00, 0x00, 0xFA, 0x0F, 0x28, 0x00, 0xA0, 0x00, 0x80, 0x02, 0x00, + 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x00, 0x80, 0x02, 0xFC, 0x0B, 0x00, 0x20, 0xC0, 0xBF, 0x00, 0x80, + 0x02, 0x00, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x00, 0x80, 0x02, 0x00, 0x0A, 0x00, 0x28, 0x00, 0xA0, + 0xFF, 0x80, 0x00, 0x00, 0xFA, 0x0F, 0x28, 0x00, 0xA0, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x0F, 0x00, 0xC0, 0xBF, 0xFF, 0x80, 0x02, 0x00, 0x0A, + 0x00, 0x28, 0x00, 0xA0, 0x00, 0x80, 0x02, 0x00, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x00, 0x80, 0x02, + 0x00, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x00, 0x80, 0x02, 0x00, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x00, + 0x80, 0x02, 0xFC, 0xFB, 0x0F, 0x00, 0xC0, 0xBF, 0xFF, 0x80, 0x02, 0x00, 0x0A, 0x00, 0x28, 0x00, + 0x00, 0x00, 0xD8, 0x37, 0xC0, 0x7F, 0x80, 0x01, 0x03, 0x02, 0x08, 0x08, 0x20, 0x60, 0xC0, 0x00, + 0xFF, 0x01, 0xF6, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x07, 0x3C, 0x3F, 0xB0, 0xCD, 0xC0, + 0x1C, 0x03, 0xE3, 0x0F, 0x0C, 0x1F, 0x00, 0x02, 0xF0, 0xFF, 0xC3, 0xFF, 0x0F, 0x81, 0x20, 0x04, + 0x80, 0x10, 0x00, 0xC2, 0x01, 0x0E, 0xFE, 0x1F, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0xF0, + 0x3F, 0x48, 0x84, 0x30, 0x11, 0x62, 0x44, 0x08, 0x13, 0x21, 0x48, 0x84, 0x00, 0x01, 0x02, 0x00, + 0x00, 0xF0, 0x3F, 0xC0, 0xFF, 0x30, 0x11, 0xC2, 0x44, 0x08, 0x10, 0x21, 0x4C, 0x84, 0x30, 0x11, + 0x02, 0x04, 0x08, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0xFF, 0x43, 0x44, 0x08, 0x11, 0x21, 0x4C, 0x84, + 0x20, 0x11, 0x02, 0x44, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7E, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0x00, 0x01, 0x82, 0xFC, 0x0F, + 0xF3, 0x3F, 0x44, 0x80, 0x10, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0x20, 0x01, 0xC2, + 0xFC, 0x8F, 0xF1, 0x3F, 0x4C, 0x80, 0x20, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0x30, + 0x01, 0xC2, 0xFC, 0x0F, 0xF0, 0x3F, 0x4C, 0x80, 0x30, 0x01, 0x02, 0x10, 0x00, 0x40, 0x00, 0x00, + 0x01, 0x00, 0x04, 0x00, 0x10, 0xC0, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0xF0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFE, 0x03, 0xF8, 0x0F, 0xE0, 0x3F, 0x80, 0xFF, 0x00, 0xFE, + 0x03, 0xF8, 0x0F, 0xE0, 0x3F, 0x80, 0xFF, 0x00, 0xFE, 0x03, 0xF8, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC0, 0xDF, 0x3F, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0x08, + 0x11, 0x20, 0xCC, 0xFF, 0x20, 0xFF, 0x03, 0x04, 0x08, 0x10, 0x20, 0xFF, 0x01, 0xFC, 0x07, 0xF0, + 0x1F, 0xC0, 0x7F, 0x00, 0xFF, 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x7F, 0x00, 0xFF, 0x01, 0xFC, + 0x07, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x80, 0x7F, 0x00, 0x03, 0x83, 0x04, 0x08, 0x13, 0x20, 0xC4, + 0xC0, 0x10, 0xFE, 0x01, 0xF0, 0x03, 0x00, 0x00, 0xF8, 0xFF, 0xF3, 0xFF, 0x4F, 0x10, 0x08, 0x41, + 0x20, 0x8C, 0x83, 0xE0, 0xFB, 0x03, 0xC7, 0x07, 0x00, 0x00, 0x00, 0x3F, 0x00, 0xFE, 0x81, 0x0C, + 0x0C, 0x13, 0x20, 0x46, 0x80, 0x30, 0x03, 0x83, 0xF8, 0x07, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0xFC, + 0x40, 0xF8, 0x07, 0x31, 0x30, 0x4C, 0x80, 0x20, 0x01, 0x02, 0x0C, 0x0C, 0xE0, 0x1F, 0x00, 0x3F, + 0x00, 0x00, 0x00, 0xE0, 0x03, 0xC2, 0x1F, 0x84, 0xC1, 0x30, 0x02, 0x82, 0x08, 0x08, 0x61, 0x30, + 0x00, 0x7F, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x88, 0x7F, 0x10, 0x03, 0xC3, 0x04, 0x08, + 0x12, 0x20, 0xC4, 0xC0, 0x00, 0xFE, 0x01, 0xF0, 0x03, 0x00, 0x00, 0x80, 0xFF, 0x03, 0xFE, 0x0F, + 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x80, 0x01, 0xF8, 0x0F, 0xE0, 0x3F, 0x00, 0x00, 0x80, + 0x00, 0x01, 0xFE, 0x07, 0xF8, 0x1F, 0x20, 0x49, 0x00, 0x24, 0x00, 0xF0, 0x00, 0x80, 0x01, 0x00, + 0x00, 0x40, 0x00, 0x02, 0xFF, 0x0F, 0xFC, 0x3F, 0x90, 0x90, 0x00, 0x42, 0x00, 0xF8, 0x01, 0xC0, + 0x03, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFC, 0x07, 0x00, 0x30, 0x08, 0x80, 0x30, 0x00, 0x42, 0x00, + 0x0C, 0xF1, 0x1F, 0xC0, 0x3F, 0x00, 0x00, 0x00, 0xFC, 0x03, 0xF0, 0x1F, 0x08, 0xC0, 0x30, 0x00, + 0x62, 0x00, 0x08, 0x03, 0x30, 0xC8, 0x7F, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xF0, 0x0F, 0xC4, 0x7F, + 0x10, 0x00, 0xC3, 0x00, 0x08, 0x02, 0x20, 0x00, 0xC0, 0x00, 0xFF, 0x01, 0xFC, 0x03, 0x00, 0x00, + 0x80, 0x0F, 0x02, 0xFE, 0x08, 0x00, 0x33, 0x02, 0x78, 0x0C, 0xE0, 0x10, 0xC0, 0x41, 0xF8, 0x03, + 0xE0, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x7C, 0x00, 0x80, 0x03, 0x08, 0xFC, 0x30, 0xF0, 0x43, + 0xE0, 0x00, 0xF1, 0x01, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x30, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x02, 0x40, 0x08, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x20, 0x01, 0x80, 0x04, 0x00, 0x12, 0x00, 0x48, 0x00, 0x20, 0x01, 0x00, 0x00, + 0x08, 0x02, 0xA6, 0x08, 0x86, 0x1D, 0x06, 0x00, 0x06, 0x00, 0x86, 0x01, 0x86, 0x05, 0x06, 0x79, + 0x06, 0x40, 0x00, 0x00, 0x80, 0x1F, 0x00, 0xFF, 0x00, 0xFC, 0xFF, 0xF0, 0xFF, 0x43, 0x00, 0x00, + 0x01, 0x00, 0xFC, 0xFF, 0xF0, 0xFF, 0x03, 0x00, 0x00, 0x06, 0x18, 0xBC, 0xE1, 0xD0, 0x0F, 0x42, + 0x66, 0x08, 0x31, 0x23, 0x84, 0x9F, 0x70, 0xEC, 0x83, 0x01, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x08, 0x00, 0x20, 0x00, 0xB0, 0x06, 0xC0, 0x1A, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x02, 0x00, 0x0C, 0x00, 0x30, 0x00, 0x00, + 0x00, 0x18, 0x00, 0xF0, 0x00, 0x60, 0x06, 0x80, 0x10, 0x00, 0x66, 0x00, 0xF0, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0x00, + 0x25, 0x00, 0xFC, 0x00, 0xA0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x00, 0xB0, 0x03, 0x40, + 0x0B, 0x00, 0x27, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, + 0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00 +}; + +static struct fontDesc_t const Terminal_11_Desc = { + sizeof(Terminal_11_Bytes)+7, // total Size + 11, // width in pixel + 18, // height in pixel + 1, // bits per pixel + 0x01, // Code of first char + 0xFE, // Code of last char + (unsigned char*)Terminal_11_Bytes // Data +}; + +#endif + diff --git a/lib/Display/Fonts/Terminal_8.h b/lib/Display/Fonts/Terminal_8.h new file mode 100644 index 0000000..735e731 --- /dev/null +++ b/lib/Display/Fonts/Terminal_8.h @@ -0,0 +1,163 @@ +/* + created with FontEditor written by H. Reddmann + HaReddmann at t-online dot de + + File Name : Terminal_8.h + Date : 08.10.2019 + Font size in bytes : 0x05E0, 1504 + Font width : 7 + Font height : 8 + Font first char : 0x01 + Font last char : 0xFE + Font bits per pixel : 1 + Font is compressed : false + + The font data are defined as + + struct _FONT_ { + // common shared fields + uint16_t font_Size_in_Bytes_over_all_included_Size_it_self; + uint8_t font_Width_in_Pixel_for_fixed_drawing; + uint8_t font_Height_in_Pixel_for_all_Characters; + uint8_t font_Bits_per_Pixels; + // if MSB are set then font is a compressed font + uint8_t font_First_Char; + uint8_t font_Last_Char; + uint8_t font_Char_Widths[font_Last_Char - font_First_Char +1]; + // for each character the separate width in pixels, + // characters < 128 have an implicit virtual right empty row + // characters with font_Char_Widths[] == 0 are undefined + + // if compressed font then additional fields + uint8_t font_Byte_Padding; + // each Char in the table are aligned in size to this value + uint8_t font_RLE_Table[3]; + // Run Length Encoding Table for compression + uint8_t font_Char_Size_in_Bytes[font_Last_Char - font_First_Char +1]; + // for each char the size in (bytes / font_Byte_Padding) are stored, + // this get us the table to seek to the right beginning of each char + // in the font_data[]. + + // for compressed and uncompressed fonts + uint8_t font_data[]; + // bit field of all characters + } +*/ + +#include "FontDesc.h" + +#ifndef Terminal_8_FONT_H +#define Terminal_8_FONT_H + +#define Terminal_8_WIDTH 7 +#define Terminal_8_HEIGHT 8 + +static unsigned char const Terminal_8_Bytes[] = { + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x02, 0x06, 0x04, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04, + 0x04, 0x05, 0x03, 0x05, 0x05, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, + 0x03, 0x05, 0x05, 0x04, 0x05, 0x05, 0x02, 0x02, 0x02, 0x05, 0x05, 0x02, 0x05, 0x02, 0x05, 0x05, + 0x03, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x02, 0x02, 0x04, 0x05, 0x04, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x03, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04, 0x03, 0x05, 0x03, 0x05, 0x06, 0x02, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x04, 0x05, 0x04, 0x02, 0x04, 0x04, 0x02, 0x05, 0x04, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x01, 0x04, 0x04, 0x05, 0x06, + 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x04, 0x04, 0x04, 0x04, 0x05, 0x06, 0x04, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x04, 0x05, 0x05, 0x05, 0x04, 0x06, 0x06, 0x06, 0x04, 0x05, 0x06, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x05, 0x04, 0x05, + 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x03, 0x03, 0x04, 0x04, 0x05, + 0x3E, 0x45, 0x51, 0x45, 0x3E, 0x3E, 0x6B, 0x6F, 0x6B, 0x3E, 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 0x18, + 0x3C, 0x7E, 0x3C, 0x18, 0x30, 0x36, 0x7F, 0x36, 0x30, 0x18, 0x5C, 0x7E, 0x5C, 0x18, 0x18, 0x18, + 0xFF, 0xFF, 0xE7, 0xE7, 0xFF, 0xFF, 0x3C, 0x24, 0x24, 0x3C, 0xFF, 0xC3, 0xDB, 0xDB, 0xC3, 0xFF, + 0x30, 0x48, 0x4A, 0x36, 0x0E, 0x06, 0x29, 0x79, 0x29, 0x06, 0x60, 0x70, 0x3F, 0x02, 0x04, 0x60, + 0x7E, 0x0A, 0x35, 0x3F, 0x2A, 0x1C, 0x36, 0x1C, 0x2A, 0x7F, 0x3E, 0x1C, 0x08, 0x08, 0x1C, 0x3E, + 0x7F, 0x14, 0x36, 0x7F, 0x36, 0x14, 0x5F, 0x00, 0x5F, 0x06, 0x09, 0x7F, 0x01, 0x7F, 0x22, 0x4D, + 0x55, 0x59, 0x22, 0x60, 0x60, 0x60, 0x60, 0x14, 0xB6, 0xFF, 0xB6, 0x14, 0x04, 0x06, 0x7F, 0x06, + 0x04, 0x10, 0x30, 0x7F, 0x30, 0x10, 0x08, 0x08, 0x3E, 0x1C, 0x08, 0x08, 0x1C, 0x3E, 0x08, 0x08, + 0x78, 0x40, 0x40, 0x40, 0x40, 0x08, 0x3E, 0x08, 0x3E, 0x08, 0x30, 0x3C, 0x3F, 0x3C, 0x30, 0x06, + 0x5F, 0x06, 0x07, 0x03, 0x00, 0x07, 0x03, 0x24, 0x7E, 0x24, 0x7E, 0x24, 0x24, 0x2B, 0x6A, 0x12, + 0x63, 0x13, 0x08, 0x64, 0x63, 0x36, 0x49, 0x56, 0x20, 0x50, 0x07, 0x03, 0x3E, 0x41, 0x41, 0x3E, + 0x08, 0x3E, 0x1C, 0x3E, 0x08, 0x08, 0x08, 0x3E, 0x08, 0x08, 0xE0, 0x60, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x60, 0x60, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x42, 0x7F, 0x40, + 0x62, 0x51, 0x49, 0x49, 0x46, 0x22, 0x49, 0x49, 0x49, 0x36, 0x18, 0x14, 0x12, 0x7F, 0x10, 0x2F, + 0x49, 0x49, 0x49, 0x31, 0x3C, 0x4A, 0x49, 0x49, 0x30, 0x01, 0x71, 0x09, 0x05, 0x03, 0x36, 0x49, + 0x49, 0x49, 0x36, 0x06, 0x49, 0x49, 0x29, 0x1E, 0x6C, 0x6C, 0xEC, 0x6C, 0x08, 0x14, 0x22, 0x41, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x41, 0x22, 0x14, 0x08, 0x02, 0x01, 0x59, 0x09, 0x06, 0x3E, 0x41, + 0x5D, 0x55, 0x1E, 0x7E, 0x11, 0x11, 0x11, 0x7E, 0x7F, 0x49, 0x49, 0x49, 0x36, 0x3E, 0x41, 0x41, + 0x41, 0x22, 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x49, 0x49, 0x49, 0x41, 0x7F, 0x09, 0x09, 0x09, + 0x01, 0x3E, 0x41, 0x49, 0x49, 0x7A, 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x41, 0x7F, 0x41, 0x30, 0x40, + 0x40, 0x40, 0x3F, 0x7F, 0x08, 0x14, 0x22, 0x41, 0x7F, 0x40, 0x40, 0x40, 0x40, 0x7F, 0x02, 0x04, + 0x02, 0x7F, 0x7F, 0x02, 0x04, 0x08, 0x7F, 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x09, 0x09, 0x09, + 0x06, 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x7F, 0x09, 0x09, 0x19, 0x66, 0x26, 0x49, 0x49, 0x49, 0x32, + 0x01, 0x01, 0x7F, 0x01, 0x01, 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x3F, + 0x40, 0x3C, 0x40, 0x3F, 0x63, 0x14, 0x08, 0x14, 0x63, 0x07, 0x08, 0x70, 0x08, 0x07, 0x71, 0x49, + 0x45, 0x43, 0x7F, 0x41, 0x41, 0x02, 0x04, 0x08, 0x10, 0x20, 0x41, 0x41, 0x7F, 0x04, 0x02, 0x01, + 0x02, 0x04, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x03, 0x07, 0x20, 0x54, 0x54, 0x54, 0x78, 0x7F, + 0x44, 0x44, 0x44, 0x38, 0x38, 0x44, 0x44, 0x44, 0x28, 0x38, 0x44, 0x44, 0x44, 0x7F, 0x38, 0x54, + 0x54, 0x54, 0x08, 0x08, 0x7E, 0x09, 0x09, 0x18, 0xA4, 0xA4, 0xA4, 0x7C, 0x7F, 0x04, 0x04, 0x78, + 0x7D, 0x40, 0x40, 0x80, 0x84, 0x7D, 0x7F, 0x10, 0x28, 0x44, 0x7F, 0x40, 0x7C, 0x04, 0x18, 0x04, + 0x78, 0x7C, 0x04, 0x04, 0x78, 0x38, 0x44, 0x44, 0x44, 0x38, 0xFC, 0x44, 0x44, 0x44, 0x38, 0x38, + 0x44, 0x44, 0x44, 0xFC, 0x44, 0x78, 0x44, 0x04, 0x08, 0x08, 0x54, 0x54, 0x54, 0x20, 0x04, 0x3E, + 0x44, 0x24, 0x3C, 0x40, 0x20, 0x7C, 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x3C, 0x60, 0x30, 0x60, 0x3C, + 0x6C, 0x10, 0x10, 0x6C, 0x9C, 0xA0, 0x60, 0x3C, 0x64, 0x54, 0x54, 0x4C, 0x08, 0x3E, 0x41, 0x41, + 0x77, 0x41, 0x41, 0x3E, 0x08, 0x02, 0x01, 0x02, 0x01, 0x3C, 0x26, 0x23, 0x26, 0x3C, 0x00, 0x1E, + 0xA1, 0xE1, 0x21, 0x12, 0x00, 0x3D, 0x40, 0x20, 0x7D, 0x00, 0x38, 0x54, 0x54, 0x55, 0x09, 0x00, + 0x20, 0x55, 0x55, 0x55, 0x78, 0x00, 0x20, 0x55, 0x54, 0x55, 0x78, 0x00, 0x20, 0x55, 0x55, 0x54, + 0x78, 0x00, 0x20, 0x57, 0x55, 0x57, 0x78, 0x00, 0x1C, 0xA2, 0xE2, 0x22, 0x14, 0x00, 0x38, 0x55, + 0x55, 0x55, 0x08, 0x00, 0x38, 0x55, 0x54, 0x55, 0x08, 0x00, 0x38, 0x55, 0x55, 0x54, 0x08, 0x00, + 0x00, 0x01, 0x7C, 0x41, 0x00, 0x00, 0x01, 0x7D, 0x41, 0x00, 0x00, 0x01, 0x7C, 0x40, 0x00, 0x70, + 0x29, 0x24, 0x29, 0x70, 0x00, 0x78, 0x2F, 0x25, 0x2F, 0x78, 0x00, 0x7C, 0x54, 0x54, 0x55, 0x45, + 0x00, 0x34, 0x54, 0x7C, 0x54, 0x58, 0x00, 0x7E, 0x09, 0x7F, 0x49, 0x49, 0x00, 0x38, 0x45, 0x45, + 0x39, 0x00, 0x38, 0x45, 0x44, 0x39, 0x00, 0x39, 0x45, 0x44, 0x38, 0x00, 0x3C, 0x41, 0x21, 0x7D, + 0x00, 0x3D, 0x41, 0x20, 0x7C, 0x00, 0x9C, 0xA1, 0x60, 0x3D, 0x00, 0x3D, 0x42, 0x42, 0x3D, 0x00, + 0x3C, 0x41, 0x40, 0x3D, 0x80, 0x70, 0x68, 0x58, 0x38, 0x04, 0x00, 0x48, 0x3E, 0x49, 0x49, 0x62, + 0x00, 0x7E, 0x61, 0x5D, 0x43, 0x3F, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x40, 0x88, 0x7E, + 0x09, 0x02, 0x00, 0x20, 0x54, 0x55, 0x55, 0x78, 0x00, 0x00, 0x00, 0x7D, 0x41, 0x00, 0x38, 0x44, + 0x45, 0x39, 0x00, 0x3C, 0x40, 0x21, 0x7D, 0x00, 0x7A, 0x09, 0x0A, 0x71, 0x00, 0x7A, 0x11, 0x22, + 0x79, 0x00, 0x08, 0x55, 0x55, 0x55, 0x5E, 0x00, 0x4E, 0x51, 0x51, 0x4E, 0x00, 0x30, 0x48, 0x4D, + 0x40, 0x20, 0x3E, 0x41, 0x5D, 0x4B, 0x55, 0x3E, 0x04, 0x04, 0x04, 0x04, 0x04, 0x1C, 0x00, 0x17, + 0x08, 0x4C, 0x6A, 0x50, 0x00, 0x17, 0x08, 0x34, 0x2A, 0x78, 0x00, 0x00, 0x30, 0x7D, 0x30, 0x00, + 0x08, 0x14, 0x00, 0x08, 0x14, 0x00, 0x14, 0x08, 0x00, 0x14, 0x08, 0x44, 0x11, 0x44, 0x11, 0x44, + 0x11, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xBB, 0xEE, 0xBB, 0xEE, 0xBB, 0xEE, 0x00, 0x00, 0x00, + 0xFF, 0x08, 0x08, 0x08, 0xFF, 0x00, 0x70, 0x28, 0x25, 0x29, 0x70, 0x00, 0x70, 0x29, 0x25, 0x29, + 0x70, 0x00, 0x70, 0x29, 0x25, 0x28, 0x70, 0x3E, 0x41, 0x5D, 0x55, 0x41, 0x3E, 0x0A, 0xFB, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x0A, 0xFA, 0x02, 0xFE, 0x0A, 0x0B, 0x08, 0x0F, 0x00, 0x18, 0x24, + 0x66, 0x24, 0x00, 0x29, 0x2A, 0x7C, 0x2A, 0x29, 0x08, 0x08, 0x08, 0xF8, 0x00, 0x00, 0x00, 0x0F, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x0F, 0x08, 0x08, 0x08, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x00, 0x00, + 0x00, 0xFF, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xFF, 0x08, 0x08, + 0x00, 0x20, 0x56, 0x55, 0x56, 0x79, 0x00, 0x70, 0x2A, 0x25, 0x2A, 0x71, 0x00, 0x0F, 0x08, 0x0B, + 0x0A, 0x0A, 0x00, 0xFE, 0x02, 0xFA, 0x0A, 0x0A, 0x0A, 0x0B, 0x08, 0x0B, 0x0A, 0x0A, 0x0A, 0xFA, + 0x02, 0xFA, 0x0A, 0x0A, 0x00, 0xFF, 0x00, 0xFB, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0A, 0xFB, 0x00, 0xFB, 0x0A, 0x0A, 0x00, 0x5D, 0x22, 0x22, 0x22, 0x5D, 0x00, 0x22, 0x55, 0x59, + 0x30, 0x00, 0x08, 0x7F, 0x49, 0x41, 0x3E, 0x00, 0x7C, 0x55, 0x55, 0x55, 0x44, 0x00, 0x7C, 0x55, + 0x54, 0x55, 0x44, 0x00, 0x7C, 0x55, 0x55, 0x54, 0x44, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x44, + 0x7D, 0x45, 0x00, 0x00, 0x45, 0x7D, 0x45, 0x00, 0x00, 0x45, 0x7C, 0x45, 0x08, 0x08, 0x08, 0x0F, + 0x00, 0x00, 0x00, 0xF8, 0x08, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x45, 0x7D, 0x44, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x00, 0x3C, 0x42, 0x43, 0x3D, 0x00, 0xFE, 0x4A, 0x4A, 0x34, 0x00, 0x3C, 0x43, 0x43, 0x3D, + 0x00, 0x3D, 0x43, 0x42, 0x3C, 0x00, 0x32, 0x49, 0x4A, 0x31, 0x00, 0x3A, 0x45, 0x46, 0x39, 0x00, + 0xFC, 0x20, 0x20, 0x1C, 0x00, 0xFE, 0xAA, 0x28, 0x10, 0x00, 0xFF, 0xA5, 0x24, 0x18, 0x00, 0x3C, + 0x40, 0x41, 0x3D, 0x00, 0x3C, 0x41, 0x41, 0x3D, 0x00, 0x3D, 0x41, 0x40, 0x3C, 0x00, 0x9C, 0xA0, + 0x61, 0x3D, 0x00, 0x04, 0x08, 0x71, 0x09, 0x04, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x07, + 0x03, 0x00, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x24, 0x2E, 0x24, 0x00, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x05, 0x17, 0x0A, 0x34, 0x2A, 0x78, 0x00, 0x06, 0x09, 0x7F, 0x01, 0x7F, 0x00, 0x22, 0x4D, + 0x55, 0x59, 0x22, 0x00, 0x08, 0x08, 0x2A, 0x08, 0x08, 0x00, 0x00, 0x08, 0x18, 0x18, 0x00, 0x06, + 0x09, 0x09, 0x06, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x02, 0x0F, 0x00, 0x09, + 0x0F, 0x05, 0x00, 0x09, 0x0D, 0x0A, 0x00, 0x3C, 0x3C, 0x3C, 0x3C +}; + +static struct fontDesc_t const Terminal_8_Desc = { + sizeof(Terminal_8_Bytes), // total Size + 7, // width in pixel + 8, // height in pixel + 1, // bits per pixel + 0x01, // Code of first char + 0xFE, // Code of last char + Terminal_8_Bytes // Data +}; + +#endif + diff --git a/lib/Display/OLEDDisplay.cpp b/lib/Display/OLEDDisplay.cpp index c047962..c5d0869 100644 --- a/lib/Display/OLEDDisplay.cpp +++ b/lib/Display/OLEDDisplay.cpp @@ -29,1017 +29,174 @@ * */ - /* - * TODO Helmut - * - test/finish dislplay.printf() on mbed-os - * - Finish _putc with drawLogBuffer when running display - */ - #include "OLEDDisplay.h" -OLEDDisplay::OLEDDisplay() { - - displayWidth = 128; - displayHeight = 64; - displayBufferSize = displayWidth * displayHeight / 8; - color = WHITE; - geometry = GEOMETRY_128_64; - textAlignment = TEXT_ALIGN_LEFT; - fontData = ArialMT_Plain_10; - fontTableLookupFunction = DefaultFontTableLookup; - buffer = NULL; -#ifdef OLEDDISPLAY_DOUBLE_BUFFER - buffer_back = NULL; -#endif -} - -OLEDDisplay::~OLEDDisplay() { - end(); -} - -bool OLEDDisplay::allocateBuffer() { - - logBufferSize = 0; - logBufferFilled = 0; - logBufferLine = 0; - logBufferMaxLines = 0; - logBuffer = NULL; - - if (!this->connect()) { - DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Can't establish connection to display\n"); - return false; - } - - if(this->buffer==NULL) { - this->buffer = (uint8_t*) malloc((sizeof(uint8_t) * displayBufferSize) + BufferOffset); - this->buffer += BufferOffset; - - if(!this->buffer) { - DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Not enough memory to create display\n"); - return false; - } - } - - #ifdef OLEDDISPLAY_DOUBLE_BUFFER - if(this->buffer_back==NULL) { - this->buffer_back = (uint8_t*) malloc((sizeof(uint8_t) * displayBufferSize) + BufferOffset); - this->buffer_back += BufferOffset; - - if(!this->buffer_back) { - DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Not enough memory to create back buffer\n"); - free(this->buffer - BufferOffset); - return false; - } - } - #endif - - return true; -} - -bool OLEDDisplay::init() { - - BufferOffset = getBufferOffset(); - - if(!allocateBuffer()) { - return false; - } - - sendInitCommands(); - resetDisplay(); - - return true; -} - -void OLEDDisplay::end() { - if (this->buffer) { free(this->buffer - BufferOffset); this->buffer = NULL; } - #ifdef OLEDDISPLAY_DOUBLE_BUFFER - if (this->buffer_back) { free(this->buffer_back - BufferOffset); this->buffer_back = NULL; } - #endif - if (this->logBuffer != NULL) { free(this->logBuffer); this->logBuffer = NULL; } -} - -void OLEDDisplay::resetDisplay(void) { - clear(); - #ifdef OLEDDISPLAY_DOUBLE_BUFFER - memset(buffer_back, 1, displayBufferSize); - #endif - display(); -} - -void OLEDDisplay::setColor(OLEDDISPLAY_COLOR color) { - this->color = color; -} - -OLEDDISPLAY_COLOR OLEDDisplay::getColor() { - return this->color; -} - -void OLEDDisplay::setPixel(int16_t x, int16_t y) { - if (x >= 0 && x < this->width() && y >= 0 && y < this->height()) { - switch (color) { - case WHITE: buffer[x + (y / 8) * this->width()] |= (1 << (y & 7)); break; - case BLACK: buffer[x + (y / 8) * this->width()] &= ~(1 << (y & 7)); break; - case INVERSE: buffer[x + (y / 8) * this->width()] ^= (1 << (y & 7)); break; - } - } -} - -void OLEDDisplay::setPixelColor(int16_t x, int16_t y, OLEDDISPLAY_COLOR color) { - if (x >= 0 && x < this->width() && y >= 0 && y < this->height()) { - switch (color) { - case WHITE: buffer[x + (y / 8) * this->width()] |= (1 << (y & 7)); break; - case BLACK: buffer[x + (y / 8) * this->width()] &= ~(1 << (y & 7)); break; - case INVERSE: buffer[x + (y / 8) * this->width()] ^= (1 << (y & 7)); break; - } - } -} - -void OLEDDisplay::clearPixel(int16_t x, int16_t y) { - if (x >= 0 && x < this->width() && y >= 0 && y < this->height()) { - switch (color) { - case BLACK: buffer[x + (y >> 3) * this->width()] |= (1 << (y & 7)); break; - case WHITE: buffer[x + (y >> 3) * this->width()] &= ~(1 << (y & 7)); break; - case INVERSE: buffer[x + (y >> 3) * this->width()] ^= (1 << (y & 7)); break; - } - } -} - - -// Bresenham's algorithm - thx wikipedia and Adafruit_GFX -void OLEDDisplay::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1) { - int16_t steep = abs(y1 - y0) > abs(x1 - x0); - if (steep) { - _swap_int16_t(x0, y0); - _swap_int16_t(x1, y1); - } - - if (x0 > x1) { - _swap_int16_t(x0, x1); - _swap_int16_t(y0, y1); - } - - int16_t dx, dy; - dx = x1 - x0; - dy = abs(y1 - y0); - - int16_t err = dx / 2; - int16_t ystep; - - if (y0 < y1) { - ystep = 1; - } else { - ystep = -1; - } - - for (; x0<=x1; x0++) { - if (steep) { - setPixel(y0, x0); - } else { - setPixel(x0, y0); - } - err -= dy; - if (err < 0) { - y0 += ystep; - err += dx; - } - } -} - -void OLEDDisplay::drawRect(int16_t x, int16_t y, int16_t width, int16_t height) { - drawHorizontalLine(x, y, width); - drawVerticalLine(x, y, height); - drawVerticalLine(x + width - 1, y, height); - drawHorizontalLine(x, y + height - 1, width); -} - -void OLEDDisplay::fillRect(int16_t xMove, int16_t yMove, int16_t width, int16_t height) { - for (int16_t x = xMove; x < xMove + width; x++) { - drawVerticalLine(x, yMove, height); - } -} - -void OLEDDisplay::drawCircle(int16_t x0, int16_t y0, int16_t radius) { - int16_t x = 0, y = radius; - int16_t dp = 1 - radius; - do { - if (dp < 0) - dp = dp + (x++) * 2 + 3; - else - dp = dp + (x++) * 2 - (y--) * 2 + 5; - - setPixel(x0 + x, y0 + y); //For the 8 octants - setPixel(x0 - x, y0 + y); - setPixel(x0 + x, y0 - y); - setPixel(x0 - x, y0 - y); - setPixel(x0 + y, y0 + x); - setPixel(x0 - y, y0 + x); - setPixel(x0 + y, y0 - x); - setPixel(x0 - y, y0 - x); - - } while (x < y); - - setPixel(x0 + radius, y0); - setPixel(x0, y0 + radius); - setPixel(x0 - radius, y0); - setPixel(x0, y0 - radius); -} - -void OLEDDisplay::drawCircleQuads(int16_t x0, int16_t y0, int16_t radius, uint8_t quads) { - int16_t x = 0, y = radius; - int16_t dp = 1 - radius; - while (x < y) { - if (dp < 0) - dp = dp + (x++) * 2 + 3; - else - dp = dp + (x++) * 2 - (y--) * 2 + 5; - if (quads & 0x1) { - setPixel(x0 + x, y0 - y); - setPixel(x0 + y, y0 - x); - } - if (quads & 0x2) { - setPixel(x0 - y, y0 - x); - setPixel(x0 - x, y0 - y); - } - if (quads & 0x4) { - setPixel(x0 - y, y0 + x); - setPixel(x0 - x, y0 + y); - } - if (quads & 0x8) { - setPixel(x0 + x, y0 + y); - setPixel(x0 + y, y0 + x); - } - } - if (quads & 0x1 && quads & 0x8) { - setPixel(x0 + radius, y0); - } - if (quads & 0x4 && quads & 0x8) { - setPixel(x0, y0 + radius); - } - if (quads & 0x2 && quads & 0x4) { - setPixel(x0 - radius, y0); - } - if (quads & 0x1 && quads & 0x2) { - setPixel(x0, y0 - radius); - } -} - - -void OLEDDisplay::fillCircle(int16_t x0, int16_t y0, int16_t radius) { - int16_t x = 0, y = radius; - int16_t dp = 1 - radius; - do { - if (dp < 0) - dp = dp + (x++) * 2 + 3; - else - dp = dp + (x++) * 2 - (y--) * 2 + 5; - - drawHorizontalLine(x0 - x, y0 - y, 2*x); - drawHorizontalLine(x0 - x, y0 + y, 2*x); - drawHorizontalLine(x0 - y, y0 - x, 2*y); - drawHorizontalLine(x0 - y, y0 + x, 2*y); - - - } while (x < y); - drawHorizontalLine(x0 - radius, y0, 2 * radius); - -} - -void OLEDDisplay::drawHorizontalLine(int16_t x, int16_t y, int16_t length) { - if (y < 0 || y >= this->height()) { return; } - - if (x < 0) { - length += x; - x = 0; - } - - if ( (x + length) > this->width()) { - length = (this->width() - x); - } - - if (length <= 0) { return; } - - uint8_t * bufferPtr = buffer; - bufferPtr += (y >> 3) * this->width(); - bufferPtr += x; - - uint8_t drawBit = 1 << (y & 7); - - switch (color) { - case WHITE: while (length--) { - *bufferPtr++ |= drawBit; - }; break; - case BLACK: drawBit = ~drawBit; while (length--) { - *bufferPtr++ &= drawBit; - }; break; - case INVERSE: while (length--) { - *bufferPtr++ ^= drawBit; - }; break; - } -} - -void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) { - if (x < 0 || x >= this->width()) return; - - if (y < 0) { - length += y; - y = 0; - } - - if ( (y + length) > this->height()) { - length = (this->height() - y); - } - - if (length <= 0) return; - - - uint8_t yOffset = y & 7; - uint8_t drawBit; - uint8_t *bufferPtr = buffer; - - bufferPtr += (y >> 3) * this->width(); - bufferPtr += x; - - if (yOffset) { - yOffset = 8 - yOffset; - drawBit = ~(0xFF >> (yOffset)); - - if (length < yOffset) { - drawBit &= (0xFF >> (yOffset - length)); - } - - switch (color) { - case WHITE: *bufferPtr |= drawBit; break; - case BLACK: *bufferPtr &= ~drawBit; break; - case INVERSE: *bufferPtr ^= drawBit; break; - } - - if (length < yOffset) return; - - length -= yOffset; - bufferPtr += this->width(); - } - - if (length >= 8) { - switch (color) { - case WHITE: - case BLACK: - drawBit = (color == WHITE) ? 0xFF : 0x00; - do { - *bufferPtr = drawBit; - bufferPtr += this->width(); - length -= 8; - } while (length >= 8); - break; - case INVERSE: - do { - *bufferPtr = ~(*bufferPtr); - bufferPtr += this->width(); - length -= 8; - } while (length >= 8); - break; - } - } - - if (length > 0) { - drawBit = (1 << (length & 7)) - 1; - switch (color) { - case WHITE: *bufferPtr |= drawBit; break; - case BLACK: *bufferPtr &= ~drawBit; break; - case INVERSE: *bufferPtr ^= drawBit; break; - } - } -} - -void OLEDDisplay::drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t progress) { - uint16_t radius = height / 2; - uint16_t xRadius = x + radius; - uint16_t yRadius = y + radius; - uint16_t doubleRadius = 2 * radius; - uint16_t innerRadius = radius - 2; - - setColor(WHITE); - drawCircleQuads(xRadius, yRadius, radius, 0b00000110); - drawHorizontalLine(xRadius, y, width - doubleRadius + 1); - drawHorizontalLine(xRadius, y + height, width - doubleRadius + 1); - drawCircleQuads(x + width - radius, yRadius, radius, 0b00001001); - - uint16_t maxProgressWidth = (width - doubleRadius + 1) * progress / 100; - - fillCircle(xRadius, yRadius, innerRadius); - fillRect(xRadius + 1, y + 2, maxProgressWidth, height - 3); - fillCircle(xRadius + maxProgressWidth, yRadius, innerRadius); -} - -void OLEDDisplay::drawFastImage(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const uint8_t *image) { - drawInternal(xMove, yMove, width, height, image, 0, 0); -} - -void OLEDDisplay::drawXbm(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const uint8_t *xbm) { - int16_t widthInXbm = (width + 7) / 8; - uint8_t data = 0; - - for(int16_t y = 0; y < height; y++) { - for(int16_t x = 0; x < width; x++ ) { - if (x & 7) { - data >>= 1; // Move a bit - } else { // Read new data every 8 bit - data = pgm_read_byte(xbm + (x / 8) + y * widthInXbm); - } - // if there is a bit draw it - if (data & 0x01) { - setPixel(xMove + x, yMove + y); - } - } - } -} - -void OLEDDisplay::drawIco16x16(int16_t xMove, int16_t yMove, const char *ico, bool inverse) { - uint16_t data; - - for(int16_t y = 0; y < 16; y++) { - data = pgm_read_byte(ico + (y << 1)) + (pgm_read_byte(ico + (y << 1) + 1) << 8); - for(int16_t x = 0; x < 16; x++ ) { - if ((data & 0x01) ^ inverse) { - setPixelColor(xMove + x, yMove + y, WHITE); - } else { - setPixelColor(xMove + x, yMove + y, BLACK); - } - data >>= 1; // Move a bit - } - } -} - -void OLEDDisplay::drawStringInternal(int16_t xMove, int16_t yMove, char* text, uint16_t textLength, uint16_t textWidth) { - uint8_t textHeight = pgm_read_byte(fontData + HEIGHT_POS); - uint8_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS); - uint16_t sizeOfJumpTable = pgm_read_byte(fontData + CHAR_NUM_POS) * JUMPTABLE_BYTES; - - uint16_t cursorX = 0; - uint16_t cursorY = 0; - - switch (textAlignment) { - case TEXT_ALIGN_CENTER_BOTH: - yMove -= textHeight >> 1; - // Fallthrough - case TEXT_ALIGN_CENTER: - xMove -= textWidth >> 1; // divide by 2 - break; - case TEXT_ALIGN_RIGHT: - xMove -= textWidth; - break; - case TEXT_ALIGN_LEFT: - break; - } - - // Don't draw anything if it is not on the screen. - if (xMove + textWidth < 0 || xMove > this->width() ) {return;} - if (yMove + textHeight < 0 || yMove > this->width() ) {return;} - - for (uint16_t j = 0; j < textLength; j++) { - int16_t xPos = xMove + cursorX; - int16_t yPos = yMove + cursorY; - - uint8_t code = text[j]; - if (code >= firstChar) { - uint8_t charCode = code - firstChar; - - // 4 Bytes per char code - uint8_t msbJumpToChar = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES ); // MSB \ JumpAddress - uint8_t lsbJumpToChar = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_LSB); // LSB / - uint8_t charByteSize = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_SIZE); // Size - uint8_t currentCharWidth = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_WIDTH); // Width - - // Test if the char is drawable - if (!(msbJumpToChar == 255 && lsbJumpToChar == 255)) { - // Get the position of the char data - uint16_t charDataPosition = JUMPTABLE_START + sizeOfJumpTable + ((msbJumpToChar << 8) + lsbJumpToChar); - drawInternal(xPos, yPos, currentCharWidth, textHeight, fontData, charDataPosition, charByteSize); - } - - cursorX += currentCharWidth; - } - } -} - - -void OLEDDisplay::drawString(int16_t xMove, int16_t yMove, String strUser) { - uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS); - - // char* text must be freed! - char* text = utf8ascii(strUser); - - uint16_t yOffset = 0; - // If the string should be centered vertically too - // we need to now how heigh the string is. - if (textAlignment == TEXT_ALIGN_CENTER_BOTH) { - uint16_t lb = 0; - // Find number of linebreaks in text - for (uint16_t i=0;text[i] != 0; i++) { - lb += (text[i] == 10); - } - // Calculate center - yOffset = (lb * lineHeight) / 2; - } - - uint16_t line = 0; - char* textPart = strtok(text,"\n"); - while (textPart != NULL) { - uint16_t length = strlen(textPart); - drawStringInternal(xMove, yMove - yOffset + (line++) * lineHeight, textPart, length, getStringWidth(textPart, length)); - textPart = strtok(NULL, "\n"); - } - free(text); -} - -void OLEDDisplay::drawStringf( int16_t x, int16_t y, char* buffer, String format, ... ) +OLEDDisplay::OLEDDisplay(OLEDDISPLAY_GEOMETRY g) + : _geometry(g) { - va_list myargs; - va_start(myargs, format); - vsprintf(buffer, format.c_str(), myargs); - va_end(myargs); - drawString( x, y, buffer ); } -void OLEDDisplay::drawStringMaxWidth(int16_t xMove, int16_t yMove, uint16_t maxLineWidth, String strUser) { - uint16_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS); - uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS); - - char* text = utf8ascii(strUser); - - uint16_t length = strlen(text); - uint16_t lastDrawnPos = 0; - uint16_t lineNumber = 0; - uint16_t strWidth = 0; - - uint16_t preferredBreakpoint = 0; - uint16_t widthAtBreakpoint = 0; - - for (uint16_t i = 0; i < length; i++) { - strWidth += pgm_read_byte(fontData + JUMPTABLE_START + (text[i] - firstChar) * JUMPTABLE_BYTES + JUMPTABLE_WIDTH); - - // Always try to break on a space or dash - if (text[i] == ' ' || text[i]== '-') { - preferredBreakpoint = i; - widthAtBreakpoint = strWidth; - } - - if (strWidth >= maxLineWidth) { - if (preferredBreakpoint == 0) { - preferredBreakpoint = i; - widthAtBreakpoint = strWidth; - } - drawStringInternal(xMove, yMove + (lineNumber++) * lineHeight , &text[lastDrawnPos], preferredBreakpoint - lastDrawnPos, widthAtBreakpoint); - lastDrawnPos = preferredBreakpoint + 1; - // It is possible that we did not draw all letters to i so we need - // to account for the width of the chars from `i - preferredBreakpoint` - // by calculating the width we did not draw yet. - strWidth = strWidth - widthAtBreakpoint; - preferredBreakpoint = 0; - } - } - - // Draw last part if needed - if (lastDrawnPos < length) { - drawStringInternal(xMove, yMove + lineNumber * lineHeight , &text[lastDrawnPos], length - lastDrawnPos, getStringWidth(&text[lastDrawnPos], length - lastDrawnPos)); - } - - free(text); +OLEDDisplay::~OLEDDisplay() +{ } -uint16_t OLEDDisplay::getStringWidth(const char* text, uint16_t length) { - uint16_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS); - - uint16_t stringWidth = 0; - uint16_t maxWidth = 0; - - while (length--) { - stringWidth += pgm_read_byte(fontData + JUMPTABLE_START + (text[length] - firstChar) * JUMPTABLE_BYTES + JUMPTABLE_WIDTH); - if (text[length] == 10) { - maxWidth = max(maxWidth, stringWidth); - stringWidth = 0; - } - } - - return max(maxWidth, stringWidth); +void OLEDDisplay::displayOn() +{ + sendCommand(DISPLAYON); } -uint16_t OLEDDisplay::getStringWidth(String strUser) { - char* text = utf8ascii(strUser); - uint16_t length = strlen(text); - uint16_t width = getStringWidth(text, length); - free(text); - return width; +void OLEDDisplay::displayOff() +{ + sendCommand(DISPLAYOFF); } -void OLEDDisplay::setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT textAlignment) { - this->textAlignment = textAlignment; +void OLEDDisplay::invertDisplay() +{ + sendCommand(INVERTDISPLAY); } -void OLEDDisplay::setFont(const uint8_t *fontData) { - this->fontData = fontData; +void OLEDDisplay::normalDisplay() +{ + sendCommand(NORMALDISPLAY); } -void OLEDDisplay::displayOn(void) { - sendCommand(DISPLAYON); +void OLEDDisplay::setContrast(uint8_t contrast, uint8_t precharge, uint8_t comdetect) +{ + sendCommand(SETPRECHARGE); //0xD9 + sendCommand(precharge); //0xF1 default, to lower the contrast, put 1-1F + sendCommand(SETCONTRAST); + sendCommand(contrast); // 0-255 + sendCommand(SETVCOMDETECT); //0xDB, (additionally needed to lower the contrast) + sendCommand(comdetect); //0x40 default, to lower the contrast, put 0 + sendCommand(DISPLAYALLON_RESUME); + sendCommand(NORMALDISPLAY); + sendCommand(DISPLAYON); } -void OLEDDisplay::displayOff(void) { - sendCommand(DISPLAYOFF); -} - -void OLEDDisplay::invertDisplay(void) { - sendCommand(INVERTDISPLAY); -} - -void OLEDDisplay::normalDisplay(void) { - sendCommand(NORMALDISPLAY); -} - -void OLEDDisplay::setContrast(uint8_t contrast, uint8_t precharge, uint8_t comdetect) { - sendCommand(SETPRECHARGE); //0xD9 - sendCommand(precharge); //0xF1 default, to lower the contrast, put 1-1F - sendCommand(SETCONTRAST); - sendCommand(contrast); // 0-255 - sendCommand(SETVCOMDETECT); //0xDB, (additionally needed to lower the contrast) - sendCommand(comdetect); //0x40 default, to lower the contrast, put 0 - sendCommand(DISPLAYALLON_RESUME); - sendCommand(NORMALDISPLAY); - sendCommand(DISPLAYON); -} - -void OLEDDisplay::setBrightness(uint8_t brightness) { - uint8_t contrast = brightness; - if (brightness < 128) { - // Magic values to get a smooth/ step-free transition - contrast = brightness * 1.171; - } else { - contrast = brightness * 1.171 - 43; - } - - uint8_t precharge = 241; - if (brightness == 0) { - precharge = 0; - } - uint8_t comdetect = brightness / 8; - - setContrast(contrast, precharge, comdetect); -} - -void OLEDDisplay::resetOrientation() { - sendCommand(SEGREMAP); - sendCommand(COMSCANINC); //Reset screen rotation or mirroring -} - -void OLEDDisplay::flipScreenVertically() { - sendCommand(SEGREMAP | 0x01); - sendCommand(COMSCANDEC); //Rotate screen 180 Deg -} - -void OLEDDisplay::mirrorScreen() { - sendCommand(SEGREMAP); - sendCommand(COMSCANDEC); //Mirror screen -} - -void OLEDDisplay::clear(void) { - memset(buffer, 0, displayBufferSize); -} - -void OLEDDisplay::drawLogBuffer(uint16_t xMove, uint16_t yMove) { - uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS); - // Always align left - setTextAlignment(TEXT_ALIGN_LEFT); - - // State values - uint16_t length = 0; - uint16_t line = 0; - uint16_t lastPos = 0; - - for (uint16_t i=0;ilogBufferFilled;i++){ - // Everytime we have a \n print - if (this->logBuffer[i] == 10) { - length++; - // Draw string on line `line` from lastPos to length - // Passing 0 as the lenght because we are in TEXT_ALIGN_LEFT - drawStringInternal(xMove, yMove + (line++) * lineHeight, &this->logBuffer[lastPos], length, 0); - // Remember last pos - lastPos = i; - // Reset length - length = 0; - } else { - // Count chars until next linebreak - length++; - } - } - // Draw the remaining string - if (length > 0) { - drawStringInternal(xMove, yMove + line * lineHeight, &this->logBuffer[lastPos], length, 0); - } -} - -uint16_t OLEDDisplay::getWidth(void) { - return displayWidth; -} - -uint16_t OLEDDisplay::getHeight(void) { - return displayHeight; -} - -bool OLEDDisplay::setLogBuffer(uint16_t lines, uint16_t chars){ - if (logBuffer != NULL) free(logBuffer); - uint16_t size = lines * chars; - if (size > 0) { - this->logBufferLine = 0; // Lines printed - this->logBufferFilled = 0; // Nothing stored yet - this->logBufferMaxLines = lines; // Lines max printable - this->logBufferSize = size; // Total number of characters the buffer can hold - this->logBuffer = (char *) malloc(size * sizeof(uint8_t)); - if(!this->logBuffer) { - DEBUG_OLEDDISPLAY("[OLEDDISPLAY][setLogBuffer] Not enough memory to create log buffer\n"); - return false; - } - } - return true; -} - -size_t OLEDDisplay::write(uint8_t c) { - if (this->logBufferSize > 0) { - // Don't waste space on \r\n line endings, dropping \r - if (c == 13) return 1; - - // convert UTF-8 character to font table index - c = (this->fontTableLookupFunction)(c); - // drop unknown character - if (c == 0) return 1; - - bool maxLineNotReached = this->logBufferLine < this->logBufferMaxLines; - bool bufferNotFull = this->logBufferFilled < this->logBufferSize; - - // Can we write to the buffer? - if (bufferNotFull && maxLineNotReached) { - this->logBuffer[logBufferFilled] = c; - this->logBufferFilled++; - // Keep track of lines written - if (c == 10) this->logBufferLine++; - } else { - // Max line number is reached - if (!maxLineNotReached) this->logBufferLine--; - - // Find the end of the first line - uint16_t firstLineEnd = 0; - for (uint16_t i=0;ilogBufferFilled;i++) { - if (this->logBuffer[i] == 10){ - // Include last char too - firstLineEnd = i + 1; - break; - } - } - // If there was a line ending - if (firstLineEnd > 0) { - // Calculate the new logBufferFilled value - this->logBufferFilled = logBufferFilled - firstLineEnd; - // Now we move the lines infront of the buffer - memcpy(this->logBuffer, &this->logBuffer[firstLineEnd], logBufferFilled); - } else { - // Let's reuse the buffer if it was full - if (!bufferNotFull) { - this->logBufferFilled = 0; - }// else { - // Nothing to do here - //} - } - write(c); - } - } - // We are always writing all uint8_t to the buffer - return 1; -} - -size_t OLEDDisplay::write(const char* str) { - if (str == NULL) return 0; - size_t length = strlen(str); - for (size_t i = 0; i < length; i++) { - write(str[i]); - } - return length; -} - -#ifdef __MBED__ -int OLEDDisplay::_putc(int c) { - - if (!fontData) - return 1; - if (!logBufferSize) { - uint8_t textHeight = pgm_read_byte(fontData + HEIGHT_POS); - uint16_t lines = this->displayHeight / textHeight; - uint16_t chars = 2 * (this->displayWidth / textHeight); - - if (this->displayHeight % textHeight) - lines++; - if (this->displayWidth % textHeight) - chars++; - setLogBuffer(lines, chars); +void OLEDDisplay::setBrightness(uint8_t brightness) +{ + uint8_t contrast = brightness; + if (brightness < 128) + { + // Magic values to get a smooth/ step-free transition + contrast = brightness * 1.171; + } + else + { + contrast = brightness * 1.171 - 43; } - return this->write((uint8_t)c); -} -#endif - -// Private functions -void OLEDDisplay::setGeometry(OLEDDISPLAY_GEOMETRY g, uint16_t width, uint16_t height) { - this->geometry = g; - - switch (g) { - case GEOMETRY_128_64: - this->displayWidth = 128; - this->displayHeight = 64; - break; - case GEOMETRY_128_32: - this->displayWidth = 128; - this->displayHeight = 32; - break; - case GEOMETRY_64_48: - this->displayWidth = 64; - this->displayHeight = 48; - break; - case GEOMETRY_64_32: - this->displayWidth = 64; - this->displayHeight = 32; - break; - case GEOMETRY_RAWMODE: - this->displayWidth = width > 0 ? width : 128; - this->displayHeight = height > 0 ? height : 64; - break; - } - this->displayBufferSize = displayWidth * displayHeight / 8; + uint8_t precharge = 241; + if (brightness == 0) + { + precharge = 0; + } + uint8_t comdetect = brightness / 8; + setContrast(contrast, precharge, comdetect); } -void OLEDDisplay::sendInitCommands(void) { - if (geometry == GEOMETRY_RAWMODE) - return; - sendCommand(DISPLAYOFF); - sendCommand(SETDISPLAYCLOCKDIV); - sendCommand(0xF0); // Increase speed of the display max ~96Hz - sendCommand(SETMULTIPLEX); - sendCommand(this->height() - 1); - sendCommand(SETDISPLAYOFFSET); - sendCommand(0x00); - if(geometry == GEOMETRY_64_32) - sendCommand(0x00); - else - sendCommand(SETSTARTLINE); - sendCommand(CHARGEPUMP); - sendCommand(0x14); - sendCommand(MEMORYMODE); - sendCommand(0x00); - sendCommand(SEGREMAP); - sendCommand(COMSCANINC); - sendCommand(SETCOMPINS); - - if (geometry == GEOMETRY_128_64 || geometry == GEOMETRY_64_48 || geometry == GEOMETRY_64_32) { - sendCommand(0x12); - } else if (geometry == GEOMETRY_128_32) { - sendCommand(0x02); - } - - sendCommand(SETCONTRAST); - - if (geometry == GEOMETRY_128_64 || geometry == GEOMETRY_64_48 || geometry == GEOMETRY_64_32) { - sendCommand(0xCF); - } else if (geometry == GEOMETRY_128_32) { - sendCommand(0x8F); - } - - sendCommand(SETPRECHARGE); - sendCommand(0xF1); - sendCommand(SETVCOMDETECT); //0xDB, (additionally needed to lower the contrast) - sendCommand(0x40); //0x40 default, to lower the contrast, put 0 - sendCommand(DISPLAYALLON_RESUME); - sendCommand(NORMALDISPLAY); - sendCommand(0x2e); // stop scroll - sendCommand(DISPLAYON); +void OLEDDisplay::resetOrientation() +{ + sendCommand(SEGREMAP); + sendCommand(COMSCANINC); } -void inline OLEDDisplay::drawInternal(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const uint8_t *data, uint16_t offset, uint16_t bytesInData) { - if (width < 0 || height < 0) return; - if (yMove + height < 0 || yMove > this->height()) return; - if (xMove + width < 0 || xMove > this->width()) return; - - uint8_t rasterHeight = 1 + ((height - 1) >> 3); // fast ceil(height / 8.0) - int8_t yOffset = yMove & 7; - - bytesInData = bytesInData == 0 ? width * rasterHeight : bytesInData; - - int16_t initYMove = yMove; - int8_t initYOffset = yOffset; - - - for (uint16_t i = 0; i < bytesInData; i++) { - - // Reset if next horizontal drawing phase is started. - if ( i % rasterHeight == 0) { - yMove = initYMove; - yOffset = initYOffset; - } - - uint8_t currentByte = pgm_read_byte(data + offset + i); - - int16_t xPos = xMove + (i / rasterHeight); - int16_t yPos = ((yMove >> 3) + (i % rasterHeight)) * this->width(); - -// int16_t yScreenPos = yMove + yOffset; - int16_t dataPos = xPos + yPos; - - if (dataPos >= 0 && dataPos < displayBufferSize && - xPos >= 0 && xPos < this->width() ) { - - if (yOffset >= 0) { - switch (this->color) { - case WHITE: buffer[dataPos] |= currentByte << yOffset; break; - case BLACK: buffer[dataPos] &= ~(currentByte << yOffset); break; - case INVERSE: buffer[dataPos] ^= currentByte << yOffset; break; - } - - if (dataPos < (displayBufferSize - this->width())) { - switch (this->color) { - case WHITE: buffer[dataPos + this->width()] |= currentByte >> (8 - yOffset); break; - case BLACK: buffer[dataPos + this->width()] &= ~(currentByte >> (8 - yOffset)); break; - case INVERSE: buffer[dataPos + this->width()] ^= currentByte >> (8 - yOffset); break; - } - } - } else { - // Make new offset position - yOffset = -yOffset; - - switch (this->color) { - case WHITE: buffer[dataPos] |= currentByte >> yOffset; break; - case BLACK: buffer[dataPos] &= ~(currentByte >> yOffset); break; - case INVERSE: buffer[dataPos] ^= currentByte >> yOffset; break; - } - - // Prepare for next iteration by moving one block up - yMove -= 8; - - // and setting the new yOffset - yOffset = 8 - yOffset; - } -#ifndef __MBED__ - yield(); -#endif - } - } +void OLEDDisplay::flipScreenVertically() +{ + sendCommand(SEGREMAP | 0x01); + sendCommand(COMSCANDEC); } -// You need to free the char! -char* OLEDDisplay::utf8ascii(String str) { - uint16_t k = 0; - uint16_t length = str.length() + 1; - - // Copy the string into a char array - char* s = (char*) malloc(length * sizeof(char)); - if(!s) { - DEBUG_OLEDDISPLAY("[OLEDDISPLAY][utf8ascii] Can't allocate another char array. Drop support for UTF-8.\n"); - return (char*) str.c_str(); - } - str.toCharArray(s, length); - - length--; - - for (uint16_t i=0; i < length; i++) { - char c = (this->fontTableLookupFunction)(s[i]); - if (c!=0) { - s[k++]=c; - } - } - - s[k]=0; - - // This will leak 's' be sure to free it in the calling function. - return s; +void OLEDDisplay::mirrorScreen() +{ + sendCommand(SEGREMAP); + sendCommand(COMSCANDEC); } -void OLEDDisplay::setFontTableLookupFunction(FontTableLookupFunction function) { - this->fontTableLookupFunction = function; +void OLEDDisplay::clear() +{ } +uint OLEDDisplay::getWidth() +{ + switch(_geometry) + { + case GEOMETRY_128_64: + case GEOMETRY_128_32: + return 128; + case GEOMETRY_64_48: + case GEOMETRY_64_32: + return 64; + } + return 0; +} -char DefaultFontTableLookup(const uint8_t ch) { - // UTF-8 to font table index converter - // Code form http://playground.arduino.cc/Main/Utf8ascii - static uint8_t LASTCHAR; +uint OLEDDisplay::getHeight() +{ + switch(_geometry) + { + case GEOMETRY_128_64: + return 64; + case GEOMETRY_64_48: + return 48; + case GEOMETRY_128_32: + case GEOMETRY_64_32: + return 32; + } + return 0; +} - if (ch < 128) { // Standard ASCII-set 0..0x7F handling - LASTCHAR = 0; - return ch; +void OLEDDisplay::sendInitCommands() +{ + sendCommand(DISPLAYOFF); + sendCommand(SETDISPLAYCLOCKDIV); + sendCommand(0xF0); // Increase speed of the display max ~96Hz + sendCommand(SETMULTIPLEX); + sendCommand(this->getHeight() - 1); + sendCommand(SETDISPLAYOFFSET); + sendCommand(0x00); + if(_geometry == GEOMETRY_64_32) + { + sendCommand(0x00); + } + else + { + sendCommand(SETSTARTLINE); + } + sendCommand(CHARGEPUMP); + sendCommand(0x14); + sendCommand(MEMORYMODE); + sendCommand(0x00); + sendCommand(SEGREMAP); + sendCommand(COMSCANINC); + sendCommand(SETCOMPINS); + + if (_geometry == GEOMETRY_128_64 || _geometry == GEOMETRY_64_48 || _geometry == GEOMETRY_64_32) + { + sendCommand(0x12); + } + else if (_geometry == GEOMETRY_128_32) + { + sendCommand(0x02); } - uint8_t last = LASTCHAR; // get last char - LASTCHAR = ch; + sendCommand(SETCONTRAST); - switch (last) { // conversion depnding on first UTF8-character - case 0xC2: return (uint8_t) ch; - case 0xC3: return (uint8_t) (ch | 0xC0); - case 0x82: if (ch == 0xAC) return (uint8_t) 0x80; // special case Euro-symbol + if (_geometry == GEOMETRY_128_64 || _geometry == GEOMETRY_64_48 || _geometry == GEOMETRY_64_32) + { + sendCommand(0xCF); + } + else if (_geometry == GEOMETRY_128_32) + { + sendCommand(0x8F); } - return (uint8_t) 0; // otherwise: return zero, if character has to be ignored + sendCommand(SETPRECHARGE); + sendCommand(0xF1); + sendCommand(SETVCOMDETECT); //0xDB, (additionally needed to lower the contrast) + sendCommand(0x40); //0x40 default, to lower the contrast, put 0 + sendCommand(DISPLAYALLON_RESUME); + sendCommand(NORMALDISPLAY); + sendCommand(0x2e); // stop scroll + sendCommand(DISPLAYON); } diff --git a/lib/Display/OLEDDisplay.h b/lib/Display/OLEDDisplay.h index 80e4882..44c0ada 100644 --- a/lib/Display/OLEDDisplay.h +++ b/lib/Display/OLEDDisplay.h @@ -33,33 +33,8 @@ #define OLEDDISPLAY_h #include -#include "OLEDDisplayFonts.h" - -//#define DEBUG_OLEDDISPLAY(...) Serial.printf( __VA_ARGS__ ) -//#define DEBUG_OLEDDISPLAY(...) dprintf("%s", __VA_ARGS__ ) - -#ifndef DEBUG_OLEDDISPLAY -#define DEBUG_OLEDDISPLAY(...) -#endif - -// Use DOUBLE BUFFERING by default -#ifndef OLEDDISPLAY_REDUCE_MEMORY -#define OLEDDISPLAY_DOUBLE_BUFFER -#endif - -// Header Values -#define JUMPTABLE_BYTES 4 - -#define JUMPTABLE_LSB 1 -#define JUMPTABLE_SIZE 2 -#define JUMPTABLE_WIDTH 3 -#define JUMPTABLE_START 4 - -#define WIDTH_POS 0 -#define HEIGHT_POS 1 -#define FIRST_CHAR_POS 2 -#define CHAR_NUM_POS 3 - +#include "Bitmap.h" +//#include "OLEDDisplayFonts.h" // Display commands #define CHARGEPUMP 0x8D @@ -89,255 +64,68 @@ #define SETVCOMDETECT 0xDB #define SWITCHCAPVCC 0x2 -#ifndef _swap_int16_t -#define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; } -#endif - -enum OLEDDISPLAY_COLOR { - BLACK = 0, - WHITE = 1, - INVERSE = 2 +enum OLEDDISPLAY_GEOMETRY +{ + GEOMETRY_128_64 = 0, + GEOMETRY_128_32 = 1, + GEOMETRY_64_48 = 2, + GEOMETRY_64_32 = 3 }; -enum OLEDDISPLAY_TEXT_ALIGNMENT { - TEXT_ALIGN_LEFT = 0, - TEXT_ALIGN_RIGHT = 1, - TEXT_ALIGN_CENTER = 2, - TEXT_ALIGN_CENTER_BOTH = 3 -}; +class OLEDDisplay +{ +public: + OLEDDisplay(OLEDDISPLAY_GEOMETRY g = GEOMETRY_128_64); + virtual ~OLEDDisplay(); + // Turn the display on + void displayOn(); -enum OLEDDISPLAY_GEOMETRY { - GEOMETRY_128_64 = 0, - GEOMETRY_128_32 = 1, - GEOMETRY_64_48 = 2, - GEOMETRY_64_32 = 3, - GEOMETRY_RAWMODE = 4 -}; + // Turn the display offs + void displayOff(); -enum HW_I2C { - I2C_ONE, - I2C_TWO -}; + // Inverted display mode + void invertDisplay(); -typedef char (*FontTableLookupFunction)(const uint8_t ch); -char DefaultFontTableLookup(const uint8_t ch); + // Normal display mode + void normalDisplay(); -class OLEDDisplay : public Print { + // Set display contrast + // really low brightness & contrast: contrast = 10, precharge = 5, comdetect = 0 + // normal brightness & contrast: contrast = 100 + void setContrast(uint8_t contrast, uint8_t precharge = 241, uint8_t comdetect = 64); - public: - OLEDDisplay(); - virtual ~OLEDDisplay(); + // Convenience method to access + void setBrightness(uint8_t brightness); - uint16_t width(void) const { return displayWidth; }; - uint16_t height(void) const { return displayHeight; }; + // Reset display rotation or mirroring + void resetOrientation(); - // Use this to resume after a deep sleep without resetting the display (what init() would do). - // Returns true if connection to the display was established and the buffer allocated, false otherwise. - bool allocateBuffer(); + // Turn the display upside down + void flipScreenVertically(); - // Allocates the buffer and initializes the driver & display. Resets the display! - // Returns false if buffer allocation failed, true otherwise. - bool init(); + // Mirror the display (to be used in a mirror or as a projector) + void mirrorScreen(); - // Free the memory used by the display - void end(); + // Write the buffer to the display memory + virtual void display(Bitmap * bitmap) = 0; - // Cycle through the initialization - void resetDisplay(void); + // Clear the local pixel buffer + void clear(); - /* Drawing functions */ - // Sets the color of all pixel operations - void setColor(OLEDDISPLAY_COLOR color); + // Get screen geometry + uint getWidth(); + uint getHeight(); - // Returns the current color. - OLEDDISPLAY_COLOR getColor(); +protected: + // Send all the init commands + void sendInitCommands(); - // Draw a pixel at given position - void setPixel(int16_t x, int16_t y); +private: + OLEDDISPLAY_GEOMETRY _geometry; - // Draw a pixel at given position and color - void setPixelColor(int16_t x, int16_t y, OLEDDISPLAY_COLOR color); - - // Clear a pixel at given position FIXME: INVERSE is untested with this function - void clearPixel(int16_t x, int16_t y); - - // Draw a line from position 0 to position 1 - void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1); - - // Draw the border of a rectangle at the given location - void drawRect(int16_t x, int16_t y, int16_t width, int16_t height); - - // Fill the rectangle - void fillRect(int16_t x, int16_t y, int16_t width, int16_t height); - - // Draw the border of a circle - void drawCircle(int16_t x, int16_t y, int16_t radius); - - // Draw all Quadrants specified in the quads bit mask - void drawCircleQuads(int16_t x0, int16_t y0, int16_t radius, uint8_t quads); - - // Fill circle - void fillCircle(int16_t x, int16_t y, int16_t radius); - - // Draw a line horizontally - void drawHorizontalLine(int16_t x, int16_t y, int16_t length); - - // Draw a line vertically - void drawVerticalLine(int16_t x, int16_t y, int16_t length); - - // Draws a rounded progress bar with the outer dimensions given by width and height. Progress is - // a unsigned byte value between 0 and 100 - void drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t progress); - - // Draw a bitmap in the internal image format - void drawFastImage(int16_t x, int16_t y, int16_t width, int16_t height, const uint8_t *image); - - // Draw a XBM - void drawXbm(int16_t x, int16_t y, int16_t width, int16_t height, const uint8_t *xbm); - - // Draw icon 16x16 xbm format - void drawIco16x16(int16_t x, int16_t y, const char *ico, bool inverse = false); - - /* Text functions */ - - // Draws a string at the given location - void drawString(int16_t x, int16_t y, String text); - - // Draws a formatted string (like printf) at the given location - void drawStringf(int16_t x, int16_t y, char* buffer, String format, ... ); - - // Draws a String with a maximum width at the given location. - // If the given String is wider than the specified width - // The text will be wrapped to the next line at a space or dash - void drawStringMaxWidth(int16_t x, int16_t y, uint16_t maxLineWidth, String text); - - // Returns the width of the const char* with the current - // font settings - uint16_t getStringWidth(const char* text, uint16_t length); - - // Convencience method for the const char version - uint16_t getStringWidth(String text); - - // Specifies relative to which anchor point - // the text is rendered. Available constants: - // TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER_BOTH - void setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT textAlignment); - - // Sets the current font. Available default fonts - // ArialMT_Plain_10, ArialMT_Plain_16, ArialMT_Plain_24 - void setFont(const uint8_t *fontData); - - // Set the function that will convert utf-8 to font table index - void setFontTableLookupFunction(FontTableLookupFunction function); - - /* Display functions */ - - // Turn the display on - void displayOn(void); - - // Turn the display offs - void displayOff(void); - - // Inverted display mode - void invertDisplay(void); - - // Normal display mode - void normalDisplay(void); - - // Set display contrast - // really low brightness & contrast: contrast = 10, precharge = 5, comdetect = 0 - // normal brightness & contrast: contrast = 100 - void setContrast(uint8_t contrast, uint8_t precharge = 241, uint8_t comdetect = 64); - - // Convenience method to access - void setBrightness(uint8_t); - - // Reset display rotation or mirroring - void resetOrientation(); - - // Turn the display upside down - void flipScreenVertically(); - - // Mirror the display (to be used in a mirror or as a projector) - void mirrorScreen(); - - // Write the buffer to the display memory - virtual void display(void) = 0; - - // Clear the local pixel buffer - void clear(void); - - // Log buffer implementation - - // This will define the lines and characters you can - // print to the screen. When you exeed the buffer size (lines * chars) - // the output may be truncated due to the size constraint. - bool setLogBuffer(uint16_t lines, uint16_t chars); - - // Draw the log buffer at position (x, y) - void drawLogBuffer(uint16_t x, uint16_t y); - - // Get screen geometry - uint16_t getWidth(void); - uint16_t getHeight(void); - - // Implement needed function to be compatible with Print class - size_t write(uint8_t c); - size_t write(const char* s); - - - uint8_t *buffer; - - #ifdef OLEDDISPLAY_DOUBLE_BUFFER - uint8_t *buffer_back; - #endif - - protected: - - OLEDDISPLAY_GEOMETRY geometry; - - uint16_t displayWidth; - uint16_t displayHeight; - uint16_t displayBufferSize; - - // Set the correct height, width and buffer for the geometry - void setGeometry(OLEDDISPLAY_GEOMETRY g, uint16_t width = 0, uint16_t height = 0); - - OLEDDISPLAY_TEXT_ALIGNMENT textAlignment; - OLEDDISPLAY_COLOR color; - - const uint8_t *fontData; - - // State values for logBuffer - uint16_t logBufferSize; - uint16_t logBufferFilled; - uint16_t logBufferLine; - uint16_t logBufferMaxLines; - char *logBuffer; - - - // the header size of the buffer used, e.g. for the SPI command header - int BufferOffset; - virtual int getBufferOffset(void) = 0; - - // Send a command to the display (low level function) - virtual void sendCommand(uint8_t com) {(void)com;}; - - // Connect to the display - virtual bool connect() { return false; }; - - // Send all the init commands - void sendInitCommands(); - - // converts utf8 characters to extended ascii - char* utf8ascii(String s); - - void inline drawInternal(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const uint8_t *data, uint16_t offset, uint16_t bytesInData) __attribute__((always_inline)); - - void drawStringInternal(int16_t xMove, int16_t yMove, char* text, uint16_t textLength, uint16_t textWidth); - - FontTableLookupFunction fontTableLookupFunction; + // Send a command to the display (low level function) + virtual void sendCommand(uint8_t com) = 0; }; #endif diff --git a/lib/Display/SSD1306.cpp b/lib/Display/SSD1306.cpp new file mode 100644 index 0000000..869d18c --- /dev/null +++ b/lib/Display/SSD1306.cpp @@ -0,0 +1,42 @@ +#include "SSD1306.h" + +SSD1306::SSD1306(TwoWire * wire, uint8_t address, OLEDDISPLAY_GEOMETRY g) + : OLEDDisplay(g), _wire(wire), _address(address) +{ + sendInitCommands(); +} + +SSD1306::~SSD1306() +{ +} + +void SSD1306::display(Bitmap * bitmap) +{ + sendCommand(PAGEADDR); + sendCommand(0x0); + sendCommand(0xFF); + + sendCommand(COLUMNADDR); + sendCommand(0x0); + sendCommand(getWidth() - 1); + + for (int i = 0; i < getWidth() * getHeight() / 8; ) + { + Wire.beginTransmission(_address); + Wire.write(0x40); + for (uint8_t x = 0; x < 16; x++) + { + Wire.write(bitmap->_buffer[i]); + i++; + } + Wire.endTransmission(); + } +} + +void SSD1306::sendCommand(uint8_t command) +{ + _wire->beginTransmission(_address); + _wire->write(0x80); + _wire->write(command); + _wire->endTransmission(); +} diff --git a/lib/Display/SSD1306.h b/lib/Display/SSD1306.h index 923faef..fe4b1d5 100644 --- a/lib/Display/SSD1306.h +++ b/lib/Display/SSD1306.h @@ -33,163 +33,22 @@ #include "OLEDDisplay.h" #include -#include -//-------------------------------------- +class SSD1306 : public OLEDDisplay +{ +public: + SSD1306(TwoWire * wire, uint8_t address, OLEDDISPLAY_GEOMETRY g = GEOMETRY_128_64); + virtual ~SSD1306(); -class SSD1306Wire : public OLEDDisplay { - private: - uint8_t _address; - int _sda; - int _scl; - bool _doI2cAutoInit = false; - TwoWire* _wire = NULL; - int _frequency; + virtual void display(Bitmap * bitmap) override; - public: - - /** - * Create and initialize the Display using Wire library - * - * Beware for retro-compatibility default values are provided for all parameters see below. - * Please note that if you don't wan't SD1306Wire to initialize and change frequency speed ot need to - * ensure -1 value are specified for all 3 parameters. This can be usefull to control TwoWire with multiple - * device on the same bus. - * - * @param _address I2C Display address - * @param _sda I2C SDA pin number, default to -1 to skip Wire begin call - * @param _scl I2C SCL pin number, default to -1 (only SDA = -1 is considered to skip Wire begin call) - * @param g display geometry dafault to generic GEOMETRY_128_64, see OLEDDISPLAY_GEOMETRY definition for other options - * @param _i2cBus on ESP32 with 2 I2C HW buses, I2C_ONE for 1st Bus, I2C_TWO fot 2nd bus, default I2C_ONE - * @param _frequency for Frequency by default Let's use ~700khz if ESP8266 is in 160Mhz mode, this will be limited to ~400khz if the ESP8266 in 80Mhz mode - */ - explicit SSD1306Wire(uint8_t _address, int _sda = -1, int _scl = -1, OLEDDISPLAY_GEOMETRY g = GEOMETRY_128_64, HW_I2C _i2cBus = I2C_ONE, int _frequency = 700000) { - setGeometry(g); - - this->_address = _address; - this->_sda = _sda; - this->_scl = _scl; - this->_wire = (_i2cBus==I2C_ONE) ? &Wire : &Wire1; - this->_frequency = _frequency; - } - - bool connect() override { - // On ESP32 arduino, -1 means 'don't change pins', someone else has called begin for us. - if(this->_sda != -1) - _wire->begin(this->_sda, this->_scl); - // Let's use ~700khz if ESP8266 is in 160Mhz mode - // this will be limited to ~400khz if the ESP8266 in 80Mhz mode. - if(this->_frequency != -1) - _wire->setClock(this->_frequency); - return true; - } - - void display(void) override { - initI2cIfNeccesary(); - const int x_offset = (128 - this->width()) / 2; - #ifdef OLEDDISPLAY_DOUBLE_BUFFER - uint8_t minBoundY = UINT8_MAX; - uint8_t maxBoundY = 0; - - uint8_t minBoundX = UINT8_MAX; - uint8_t maxBoundX = 0; - uint8_t x, y; - - // Calculate the Y bounding box of changes - // and copy buffer[pos] to buffer_back[pos]; - for (y = 0; y < (this->height() / 8); y++) { - for (x = 0; x < this->width(); x++) { - uint16_t pos = x + y * this->width(); - if (buffer[pos] != buffer_back[pos]) { - minBoundY = std::min(minBoundY, y); - maxBoundY = std::max(maxBoundY, y); - minBoundX = std::min(minBoundX, x); - maxBoundX = std::max(maxBoundX, x); - } - buffer_back[pos] = buffer[pos]; - } - yield(); - } - - // If the minBoundY wasn't updated - // we can savely assume that buffer_back[pos] == buffer[pos] - // holdes true for all values of pos - - if (minBoundY == UINT8_MAX) return; - - sendCommand(COLUMNADDR); - sendCommand(x_offset + minBoundX); - sendCommand(x_offset + maxBoundX); - - sendCommand(PAGEADDR); - sendCommand(minBoundY); - sendCommand(maxBoundY); - - byte k = 0; - for (y = minBoundY; y <= maxBoundY; y++) { - for (x = minBoundX; x <= maxBoundX; x++) { - if (k == 0) { - _wire->beginTransmission(_address); - _wire->write(0x40); - } - - _wire->write(buffer[x + y * this->width()]); - k++; - if (k == 16) { - _wire->endTransmission(); - k = 0; - } - } - yield(); - } - - if (k != 0) { - _wire->endTransmission(); - } - #else - - sendCommand(COLUMNADDR); - sendCommand(x_offset); - sendCommand(x_offset + (this->width() - 1)); - - sendCommand(PAGEADDR); - sendCommand(0x0); - - for (uint16_t i=0; i < displayBufferSize; i++) { - _wire->beginTransmission(this->_address); - _wire->write(0x40); - for (uint8_t x = 0; x < 16; x++) { - _wire->write(buffer[i]); - i++; - } - i--; - _wire->endTransmission(); - } - #endif - } - - void setI2cAutoInit(bool doI2cAutoInit) { - _doI2cAutoInit = doI2cAutoInit; - } - - private: - int getBufferOffset(void) override { - return 0; - } - inline void sendCommand(uint8_t command) override __attribute__((always_inline)) { - initI2cIfNeccesary(); - _wire->beginTransmission(_address); - _wire->write(0x80); - _wire->write(command); - _wire->endTransmission(); - } - - void initI2cIfNeccesary() { - if (_doI2cAutoInit) { - _wire->begin(this->_sda, this->_scl); - } - } +private: + TwoWire * _wire = NULL; + uint8_t _address; + bool _doI2cAutoInit = false; + int _frequency; + virtual void sendCommand(uint8_t command) override; }; #endif diff --git a/src/TaskDisplay.cpp b/lib/TaskManager/TaskDisplay.cpp similarity index 64% rename from src/TaskDisplay.cpp rename to lib/TaskManager/TaskDisplay.cpp index 89f4045..af99345 100644 --- a/src/TaskDisplay.cpp +++ b/lib/TaskManager/TaskDisplay.cpp @@ -1,11 +1,9 @@ #include #include -#include "project_configuration.h" #include "TaskDisplay.h" -#include "Task.h" DisplayTask::DisplayTask() - : Task(TASK_DISPLAY, TaskDisplay), _beginCalled(false) + : Task("DisplayTask", 0) { } @@ -16,15 +14,14 @@ DisplayTask::~DisplayTask() bool DisplayTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { Display::instance().setup(boardConfig); + std::shared_ptr statusFrame = std::shared_ptr(new StatusFrame(TaskManager::instance().getTasks())); + Display::instance().setStatusFrame(statusFrame); + _stateInfo = ""; return true; } bool DisplayTask::loop(std::shared_ptr config) { - if(!_beginCalled) - { - _beginCalled = true; - } Display::instance().update(); return true; } diff --git a/src/TaskDisplay.h b/lib/TaskManager/TaskDisplay.h similarity index 92% rename from src/TaskDisplay.h rename to lib/TaskManager/TaskDisplay.h index 05fffc1..0d1ce2b 100644 --- a/src/TaskDisplay.h +++ b/lib/TaskManager/TaskDisplay.h @@ -12,9 +12,6 @@ public: virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; virtual bool loop(std::shared_ptr config) override; - -private: - bool _beginCalled; }; #endif diff --git a/lib/TaskManager/TaskManager.cpp b/lib/TaskManager/TaskManager.cpp index 8f52e6c..1bf6d07 100644 --- a/lib/TaskManager/TaskManager.cpp +++ b/lib/TaskManager/TaskManager.cpp @@ -1,5 +1,6 @@ #include #include "TaskManager.h" +#include TaskManager::TaskManager() { @@ -23,6 +24,11 @@ std::shared_ptr TaskManager::getTask(const char * name) return *elem; } +std::list> TaskManager::getTasks() +{ + return _tasks; +} + bool TaskManager::setup(std::shared_ptr config, std::shared_ptr boardConfig) { logPrintlnV("will setup all tasks..."); @@ -52,3 +58,44 @@ bool TaskManager::loop(std::shared_ptr config) } return true; } + +void StatusFrame::drawStatusPage(Bitmap & bitmap) +{ + int y = 0; + for(std::shared_ptr task : _tasks) + { + int x = bitmap.drawString(0, y, (task->getName()).substring(0, task->getName().indexOf("Task"))); + x = bitmap.drawString(x, y, ": "); + if(task->getStateInfo() == "") + { + switch (task->getState()) + { + case Error: + bitmap.drawString(x, y, "Error"); + break; + case Warning: + bitmap.drawString(x, y, "Warning"); + default: + break; + } + bitmap.drawString(x, y, "Okay"); + } + else + { + bitmap.drawString(x, y, task->getStateInfo()); + } + y += getSystemFont()->heightInPixel; + } +} + +bool StatusFrame::isPrio() const +{ + for(std::shared_ptr task : _tasks) + { + if(task->getState() != Okay) + { + return true; + } + } + return false; +} diff --git a/lib/TaskManager/TaskManager.h b/lib/TaskManager/TaskManager.h index 5f4cb89..65befbf 100644 --- a/lib/TaskManager/TaskManager.h +++ b/lib/TaskManager/TaskManager.h @@ -6,22 +6,37 @@ #include #include #include +#include #include "TaskQueue.h" +enum TaskDisplayState +{ + Error, + Warning, + Okay, +}; + class Task { public: - Task(String & name, int taskId) : _name(name), _taskId(taskId) {} - Task(const char * name, int taskId) : _name(name), _taskId(taskId) {} + Task(String & name, int taskId) : _state(Okay), _stateInfo("Booting"), _name(name), _taskId(taskId) {} + Task(const char * name, int taskId) : _state(Okay), _stateInfo("Booting"), _name(name), _taskId(taskId) {} virtual ~Task() {} String getName() const { return _name; } int getTaskId() const { return _taskId; } + TaskDisplayState getState() const { return _state; } + String getStateInfo() const { return _stateInfo; } + virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) = 0; virtual bool loop(std::shared_ptr config) = 0; +protected: + TaskDisplayState _state; + String _stateInfo; + private: String _name; int _taskId; @@ -40,6 +55,7 @@ public: void addTask(std::shared_ptr task); std::shared_ptr getTask(const char * name); + std::list> getTasks(); bool setup(std::shared_ptr config, std::shared_ptr boardConfig); bool loop(std::shared_ptr config); @@ -52,4 +68,17 @@ private: TaskManager & operator = (const TaskManager &); }; +class StatusFrame : public DisplayFrame +{ +public: + StatusFrame(std::list> tasks) : _tasks(tasks) {} + virtual ~StatusFrame() {} + void drawStatusPage(Bitmap & bitmap) override; + + bool isPrio() const; + +private: + std::list> _tasks; +}; + #endif diff --git a/platformio.ini b/platformio.ini index b0ed3a5..f53dc1f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -3,6 +3,7 @@ platform = espressif32 @ 2.1.0 framework = arduino lib_ldf_mode = deep+ monitor_speed = 115200 +monitor_filters = esp32_exception_decoder lib_deps = bblanchon/ArduinoJson @ 6.17.0 lewisxhe/AXP202X_Library @ 1.1.2 @@ -13,7 +14,7 @@ check_tool = cppcheck check_flags = cppcheck: --suppress=*:*.pio\* --inline-suppr -DCPPCHECK --force lib -ilib/TimeLib -ilib/LoRa -ilib/NTPClient -ilib/Display check_skip_packages = yes -monitor_flags = --raw +#monitor_flags = --raw # activate for OTA Update, use the CALLSIGN from is-cfg.json as upload_port: #upload_protocol = espota #upload_port = .local @@ -22,3 +23,4 @@ monitor_flags = --raw [env:lora_board] board = esp32doit-devkit-v1 build_flags = -Werror -Wall -DNO_GLOBAL_INSTANCES +build_type = debug diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index d1af131..56069b2 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -20,6 +20,8 @@ #include "TaskOTA.h" #include "TaskWifi.h" +#define VERSION "20.49.0-dev" + String create_lat_aprs(double lat); String create_long_aprs(double lng); @@ -33,6 +35,8 @@ void setup() Serial.begin(115200); Logger::instance().setSerial(&Serial); delay(500); + logPrintlnW("LoRa APRS iGate by OE5BPA (Peter Buchegger)"); + logPrintlnW("Version: " VERSION); ProjectConfigurationManagement confmg; userConfig = confmg.readConfiguration(); @@ -69,10 +73,9 @@ void setup() if(boardConfig->Type == eTTGO_T_Beam_V1_0) { - TwoWire wire(0); - wire.begin(boardConfig->OledSda, boardConfig->OledScl); + Wire.begin(boardConfig->OledSda, boardConfig->OledScl); std::shared_ptr powerManagement = std::shared_ptr(new PowerManagement); - if (!powerManagement->begin(wire)) + if (!powerManagement->begin(Wire)) { logPrintlnI("AXP192 init done!"); } @@ -85,11 +88,6 @@ void setup() powerManagement->deactivateGPS(); } - logPrintlnW("LoRa APRS iGate by OE5BPA (Peter Buchegger)"); - logPrintlnW("Version: 20.49.0-dev"); - //setup_display(boardConfig); - //show_display("OE5BPA", "LoRa APRS iGate", "by Peter Buchegger", "20.49.0-dev", 3000); - load_config(boardConfig); TaskManager::instance().addTask(std::shared_ptr(new DisplayTask())); @@ -101,18 +99,23 @@ void setup() TaskManager::instance().addTask(std::shared_ptr(new WifiTask())); TaskManager::instance().addTask(std::shared_ptr(new OTATask())); TaskManager::instance().addTask(std::shared_ptr(new NTPTask())); - TaskManager::instance().addTask(std::shared_ptr(new FTPTask())); + if(userConfig->ftp.active) + { + TaskManager::instance().addTask(std::shared_ptr(new FTPTask())); + } TaskManager::instance().addTask(std::shared_ptr(new AprsIsTask())); TaskManager::instance().setup(userConfig, boardConfig); + Display::instance().showSpashScreen("LoRa APRS iGate", VERSION); + if(userConfig->display.overwritePin != 0) { pinMode(userConfig->display.overwritePin, INPUT); pinMode(userConfig->display.overwritePin, INPUT_PULLUP); } - delay(500); + delay(5000); logPrintlnI("setup done..."); } diff --git a/src/Task.h b/src/Task.h index 149ee27..eae32f8 100644 --- a/src/Task.h +++ b/src/Task.h @@ -3,8 +3,7 @@ enum TaskNames { - TaskDisplay, - TaskAprsIs, + TaskAprsIs = 1, TaskEth, TaskFtp, TaskLora, @@ -16,7 +15,6 @@ enum TaskNames //char const * const getTaskName(TaskNames task); -#define TASK_DISPLAY "DisplayTask" #define TASK_APRS_IS "AprsIsTask" #define TASK_ETH "EthTask" #define TASK_FTP "FTPTask" diff --git a/src/TaskAprsIs.cpp b/src/TaskAprsIs.cpp index 39c1302..c575828 100644 --- a/src/TaskAprsIs.cpp +++ b/src/TaskAprsIs.cpp @@ -34,7 +34,15 @@ bool AprsIsTask::loop(std::shared_ptr config) { if(!_aprs_is->connected()) { - return connect(config); + if(!connect(config)) + { + _stateInfo = "not connected"; + _state = Error; + return false; + } + _stateInfo = "connected"; + _state = Okay; + return false; } _aprs_is->getAPRSMessage(); @@ -50,8 +58,12 @@ bool AprsIsTask::loop(std::shared_ptr config) logPrintD("[" + timeString() + "] "); logPrintlnD(_beaconMsg->encode()); _aprs_is->sendMessage(_beaconMsg); + Display::instance().addFrame(std::shared_ptr(new TextFrame("BEACON", _beaconMsg->toString()))); _beacon_next_time = now() + config->beacon.timeout * 60UL; } + time_t diff = _beacon_next_time - now(); + _stateInfo = "beacon " + String(minute(diff)) + ":" + String(second(diff)); + _state = Okay; return true; } diff --git a/src/TaskFTP.cpp b/src/TaskFTP.cpp index 4a6eea6..a29fa32 100644 --- a/src/TaskFTP.cpp +++ b/src/TaskFTP.cpp @@ -17,40 +17,36 @@ FTPTask::~FTPTask() bool FTPTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { _ftpServer = std::shared_ptr(new FTPServer()); - if(config->ftp.active) + for(Configuration::Ftp::User user : config->ftp.users) { - for(Configuration::Ftp::User user : config->ftp.users) - { - logPrintD("Adding user to FTP Server: "); - logPrintlnD(user.name); - _ftpServer->addUser(user.name, user.password); - } - _ftpServer->addFilesystem("SPIFFS", &SPIFFS); + logPrintD("Adding user to FTP Server: "); + logPrintlnD(user.name); + _ftpServer->addUser(user.name, user.password); } + _ftpServer->addFilesystem("SPIFFS", &SPIFFS); + _stateInfo = "waiting"; return true; } bool FTPTask::loop(std::shared_ptr config) { - if(config->ftp.active) + if(!_beginCalled) { - if(!_beginCalled) - { - _ftpServer->begin(); - _beginCalled = true; - } - _ftpServer->handle(); - static bool configWasOpen = false; - if(configWasOpen && _ftpServer->countConnections() == 0) - { - logPrintlnW("Maybe the config has been changed via FTP, lets restart now to get the new config..."); - logPrintlnW(""); - ESP.restart(); - } - if(_ftpServer->countConnections() > 0) - { - configWasOpen = true; - } + _ftpServer->begin(); + _beginCalled = true; + } + _ftpServer->handle(); + static bool configWasOpen = false; + if(configWasOpen && _ftpServer->countConnections() == 0) + { + logPrintlnW("Maybe the config has been changed via FTP, lets restart now to get the new config..."); + logPrintlnW(""); + ESP.restart(); + } + if(_ftpServer->countConnections() > 0) + { + configWasOpen = true; + _stateInfo = "has connection"; } return true; } diff --git a/src/TaskLora.cpp b/src/TaskLora.cpp index cdac7ef..4a9dc61 100644 --- a/src/TaskLora.cpp +++ b/src/TaskLora.cpp @@ -20,6 +20,8 @@ bool LoraTask::setup(std::shared_ptr config, std::shared_ptrbegin(_lora_aprs->getRxFrequency())) { logPrintlnE("Starting LoRa failed!"); + _stateInfo = "LoRa-Modem failed"; + _state = Error; while(true); } _lora_aprs->setRxFrequency(config->lora.frequencyRx); @@ -30,6 +32,7 @@ bool LoraTask::setup(std::shared_ptr config, std::shared_ptrsetCodingRate4(config->lora.codingRate4); _lora_aprs->enableCrc(); + _stateInfo = ""; return true; } @@ -48,6 +51,7 @@ bool LoraTask::loop(std::shared_ptr config) logPrintlnD(String(_lora_aprs->packetSnr())); std::shared_ptr is_thread = std::static_pointer_cast(TaskManager::instance().getTask(TASK_APRS_IS)); is_thread->inputQueue.addElement(msg); + Display::instance().addFrame(std::shared_ptr(new TextFrame("LoRa", msg->toString()))); } if(!inputQueue.empty()) diff --git a/src/TaskNTP.cpp b/src/TaskNTP.cpp index a4993ac..56247e3 100644 --- a/src/TaskNTP.cpp +++ b/src/TaskNTP.cpp @@ -32,5 +32,7 @@ bool NTPTask::loop(std::shared_ptr config) logPrintI("Current time: "); logPrintlnI(_ntpClient->getFormattedTime()); } + _stateInfo = _ntpClient->getFormattedTime(); + _state = Okay; return true; } diff --git a/src/TaskOTA.cpp b/src/TaskOTA.cpp index d569011..bd8c453 100644 --- a/src/TaskOTA.cpp +++ b/src/TaskOTA.cpp @@ -47,6 +47,7 @@ bool OTATask::setup(std::shared_ptr config, std::shared_ptrsetHostname(config->callsign.c_str()); + _stateInfo = ""; return true; } diff --git a/src/TaskWifi.cpp b/src/TaskWifi.cpp index 7927526..8253272 100644 --- a/src/TaskWifi.cpp +++ b/src/TaskWifi.cpp @@ -34,6 +34,8 @@ bool WifiTask::loop(std::shared_ptr config) { logPrintlnE("WiFi not connected!"); _oldWifiStatus = wifi_status; + _stateInfo = "WiFi not connected"; + _state = Error; return false; } else if(wifi_status != _oldWifiStatus) @@ -41,6 +43,9 @@ bool WifiTask::loop(std::shared_ptr config) logPrintD("IP address: "); logPrintlnD(WiFi.localIP().toString()); _oldWifiStatus = wifi_status; + return false; } + _stateInfo = WiFi.localIP().toString(); + _state = Okay; return true; } From b5acc477281293b1fc883ae985d3c5c1be9f3652 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sat, 30 Jan 2021 22:53:06 +0100 Subject: [PATCH 35/60] fixing some cppchecks --- lib/Display/Bitmap.h | 4 ++-- lib/TaskManager/TaskManager.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Display/Bitmap.h b/lib/Display/Bitmap.h index 962aa05..fe9f0d5 100644 --- a/lib/Display/Bitmap.h +++ b/lib/Display/Bitmap.h @@ -9,8 +9,8 @@ class OLEDDisplay; class Bitmap { public: - Bitmap(uint width, uint height); - Bitmap(OLEDDisplay * display); + explicit Bitmap(uint width, uint height); + explicit Bitmap(OLEDDisplay * display); virtual ~Bitmap(); uint getWidth() const; diff --git a/lib/TaskManager/TaskManager.h b/lib/TaskManager/TaskManager.h index 65befbf..aa5ccd4 100644 --- a/lib/TaskManager/TaskManager.h +++ b/lib/TaskManager/TaskManager.h @@ -71,7 +71,7 @@ private: class StatusFrame : public DisplayFrame { public: - StatusFrame(std::list> tasks) : _tasks(tasks) {} + explicit StatusFrame(const std::list> & tasks) : _tasks(tasks) {} virtual ~StatusFrame() {} void drawStatusPage(Bitmap & bitmap) override; From 2cea42bad188e931d0fe2d7ee1d23aaefbed2e54 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sat, 30 Jan 2021 23:09:38 +0100 Subject: [PATCH 36/60] more cppcheck fixes --- lib/Display/Bitmap.cpp | 27 +++++++++++++++++++++++++-- lib/Display/OLEDDisplay.cpp | 19 ++++++++++++++----- lib/Display/SSD1306.h | 1 - platformio.ini | 2 +- 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/lib/Display/Bitmap.cpp b/lib/Display/Bitmap.cpp index b8374b5..b8518b8 100644 --- a/lib/Display/Bitmap.cpp +++ b/lib/Display/Bitmap.cpp @@ -3,18 +3,21 @@ #include "FontConfig.h" //#include "OLEDDisplayFonts.h" +// cppcheck-suppress unusedFunction Bitmap::Bitmap(uint width, uint height) : _width(width), _height(height), _buffer(0) { allocateBuffer(); } +// cppcheck-suppress unusedFunction Bitmap::Bitmap(OLEDDisplay * display) : _width(display->getWidth()), _height(display->getHeight()), _buffer(0) { allocateBuffer(); } +// cppcheck-suppress unusedFunction Bitmap::~Bitmap() { if(_buffer != 0) @@ -23,16 +26,19 @@ Bitmap::~Bitmap() } } +// cppcheck-suppress unusedFunction uint Bitmap::getWidth() const { return _width; } +// cppcheck-suppress unusedFunction uint Bitmap::getHeight() const { return _height; } +// cppcheck-suppress unusedFunction void Bitmap::setPixel(int x, int y) { if(x >= 0 && x < _width && y >= 0 && y < _height) @@ -41,6 +47,7 @@ void Bitmap::setPixel(int x, int y) } } +// cppcheck-suppress unusedFunction void Bitmap::clearPixel(int x, int y) { if(x >= 0 && x < _width && y >= 0 && y < _height) @@ -49,6 +56,7 @@ void Bitmap::clearPixel(int x, int y) } } +// cppcheck-suppress unusedFunction bool Bitmap::getPixel(int x, int y) const { if(x >= 0 && x < _width && y >= 0 && y < _height) @@ -58,11 +66,13 @@ bool Bitmap::getPixel(int x, int y) const return false; } +// cppcheck-suppress unusedFunction void Bitmap::clear() { memset(_buffer, 0, _width * _height / 8); } +// cppcheck-suppress unusedFunction void Bitmap::drawLine(int x0, int y0, int x1, int y1) { int dx = abs(x1 - x0); @@ -70,7 +80,6 @@ void Bitmap::drawLine(int x0, int y0, int x1, int y1) int sx = x0 < x1 ? 1 : -1; int sy = y0 < y1 ? 1 : -1; int err = (dx > dy ? dx : -dy) / 2; - int e2; while(true) { @@ -78,7 +87,7 @@ void Bitmap::drawLine(int x0, int y0, int x1, int y1) if(x0 == x1 && y0 == y1) break; - e2 = err; + int e2 = err; if(e2 > -dx) { err -= dy; @@ -92,6 +101,7 @@ void Bitmap::drawLine(int x0, int y0, int x1, int y1) } } +// cppcheck-suppress unusedFunction void Bitmap::drawHorizontalLine(int x, int y, int length) { if(y < 0 || y >= _height) @@ -105,6 +115,7 @@ void Bitmap::drawHorizontalLine(int x, int y, int length) } } +// cppcheck-suppress unusedFunction void Bitmap::drawVerticalLine(int x, int y, int length) { if (x < 0 || x >= _width) @@ -118,6 +129,7 @@ void Bitmap::drawVerticalLine(int x, int y, int length) } } +// cppcheck-suppress unusedFunction void Bitmap::drawRect(int x, int y, int width, int height) { drawHorizontalLine(x, y, width); @@ -126,6 +138,7 @@ void Bitmap::drawRect(int x, int y, int width, int height) drawHorizontalLine(x, y + height - 1, width); } +// cppcheck-suppress unusedFunction void Bitmap::fillRect(int x, int y, int width, int height) { for (int i = 0; i < width; i++) @@ -134,6 +147,7 @@ void Bitmap::fillRect(int x, int y, int width, int height) } } +// cppcheck-suppress unusedFunction void Bitmap::drawCircle(int x0, int y0, int radius) { int x = 0; @@ -168,6 +182,7 @@ void Bitmap::drawCircle(int x0, int y0, int radius) setPixel(x0, y0 - radius); } +// cppcheck-suppress unusedFunction void Bitmap::fillCircle(int x0, int y0, int radius) { int x = 0; @@ -195,6 +210,7 @@ void Bitmap::fillCircle(int x0, int y0, int radius) drawHorizontalLine(x0 - radius, y0, 2 * radius); } +// cppcheck-suppress unusedFunction void Bitmap::drawCircleQuads(int x0, int y0, int radius, int quads) { int x = 0; @@ -251,6 +267,7 @@ void Bitmap::drawCircleQuads(int x0, int y0, int radius, int quads) } } +// cppcheck-suppress unusedFunction void Bitmap::drawProgressBar(int x, int y, int width, int height, int progress) { int radius = height / 2; @@ -271,6 +288,7 @@ void Bitmap::drawProgressBar(int x, int y, int width, int height, int progress) fillCircle(xRadius + maxProgressWidth, yRadius, innerRadius); } +// cppcheck-suppress unusedFunction int Bitmap::drawChar(int x, int y, char c) { fontDesc_t const * font = getSystemFont(); @@ -322,6 +340,7 @@ int Bitmap::drawChar(int x, int y, char c) return x + FONT_CHAR_SPACING; } +// cppcheck-suppress unusedFunction int Bitmap::drawString(int x, int y, String text) { int next_x = x; @@ -332,6 +351,7 @@ int Bitmap::drawString(int x, int y, String text) return next_x; } +// cppcheck-suppress unusedFunction void Bitmap::drawStringf(int x, int y, char * buffer, String format, ... ) { va_list myargs; @@ -341,6 +361,7 @@ void Bitmap::drawStringf(int x, int y, char * buffer, String format, ... ) drawString(x, y, buffer); } +// cppcheck-suppress unusedFunction int Bitmap::drawStringLF(int x, int y, String text) { fontDesc_t const * font = getSystemFont(); @@ -357,6 +378,7 @@ int Bitmap::drawStringLF(int x, int y, String text) return next_x; } +// cppcheck-suppress unusedFunction void Bitmap::drawStringLFf(int x, int y, char * buffer, String format, ... ) { va_list myargs; @@ -394,6 +416,7 @@ void Bitmap::drawStringLFf(int x, int y, char * buffer, String format, ... ) } }*/ +// cppcheck-suppress unusedFunction void Bitmap::allocateBuffer() { _buffer = new uint8_t[_width * _height / 8]; diff --git a/lib/Display/OLEDDisplay.cpp b/lib/Display/OLEDDisplay.cpp index c5d0869..2bc7db8 100644 --- a/lib/Display/OLEDDisplay.cpp +++ b/lib/Display/OLEDDisplay.cpp @@ -40,26 +40,31 @@ OLEDDisplay::~OLEDDisplay() { } +// cppcheck-suppress unusedFunction void OLEDDisplay::displayOn() { sendCommand(DISPLAYON); } +// cppcheck-suppress unusedFunction void OLEDDisplay::displayOff() { sendCommand(DISPLAYOFF); } +// cppcheck-suppress unusedFunction void OLEDDisplay::invertDisplay() { sendCommand(INVERTDISPLAY); } +// cppcheck-suppress unusedFunction void OLEDDisplay::normalDisplay() { sendCommand(NORMALDISPLAY); } +// cppcheck-suppress unusedFunction void OLEDDisplay::setContrast(uint8_t contrast, uint8_t precharge, uint8_t comdetect) { sendCommand(SETPRECHARGE); //0xD9 @@ -73,18 +78,15 @@ void OLEDDisplay::setContrast(uint8_t contrast, uint8_t precharge, uint8_t comde sendCommand(DISPLAYON); } +// cppcheck-suppress unusedFunction void OLEDDisplay::setBrightness(uint8_t brightness) { - uint8_t contrast = brightness; + uint8_t contrast = brightness * 1.171 - 43; if (brightness < 128) { // Magic values to get a smooth/ step-free transition contrast = brightness * 1.171; } - else - { - contrast = brightness * 1.171 - 43; - } uint8_t precharge = 241; if (brightness == 0) @@ -95,28 +97,33 @@ void OLEDDisplay::setBrightness(uint8_t brightness) setContrast(contrast, precharge, comdetect); } +// cppcheck-suppress unusedFunction void OLEDDisplay::resetOrientation() { sendCommand(SEGREMAP); sendCommand(COMSCANINC); } +// cppcheck-suppress unusedFunction void OLEDDisplay::flipScreenVertically() { sendCommand(SEGREMAP | 0x01); sendCommand(COMSCANDEC); } +// cppcheck-suppress unusedFunction void OLEDDisplay::mirrorScreen() { sendCommand(SEGREMAP); sendCommand(COMSCANDEC); } +// cppcheck-suppress unusedFunction void OLEDDisplay::clear() { } +// cppcheck-suppress unusedFunction uint OLEDDisplay::getWidth() { switch(_geometry) @@ -131,6 +138,7 @@ uint OLEDDisplay::getWidth() return 0; } +// cppcheck-suppress unusedFunction uint OLEDDisplay::getHeight() { switch(_geometry) @@ -146,6 +154,7 @@ uint OLEDDisplay::getHeight() return 0; } +// cppcheck-suppress unusedFunction void OLEDDisplay::sendInitCommands() { sendCommand(DISPLAYOFF); diff --git a/lib/Display/SSD1306.h b/lib/Display/SSD1306.h index fe4b1d5..01d2032 100644 --- a/lib/Display/SSD1306.h +++ b/lib/Display/SSD1306.h @@ -46,7 +46,6 @@ private: TwoWire * _wire = NULL; uint8_t _address; bool _doI2cAutoInit = false; - int _frequency; virtual void sendCommand(uint8_t command) override; }; diff --git a/platformio.ini b/platformio.ini index f53dc1f..c150286 100644 --- a/platformio.ini +++ b/platformio.ini @@ -12,7 +12,7 @@ lib_deps = peterus/ESP-FTP-Server-Lib @ 0.9.5 check_tool = cppcheck check_flags = - cppcheck: --suppress=*:*.pio\* --inline-suppr -DCPPCHECK --force lib -ilib/TimeLib -ilib/LoRa -ilib/NTPClient -ilib/Display + cppcheck: --suppress=*:*.pio\* --inline-suppr -DCPPCHECK --force lib -ilib/TimeLib -ilib/LoRa -ilib/NTPClient check_skip_packages = yes #monitor_flags = --raw # activate for OTA Update, use the CALLSIGN from is-cfg.json as upload_port: From b7b88845949da7424a495adcbe8a4519c1909077 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sat, 30 Jan 2021 23:11:56 +0100 Subject: [PATCH 37/60] version bump! --- src/LoRa_APRS_iGate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index 56069b2..3888317 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -20,7 +20,7 @@ #include "TaskOTA.h" #include "TaskWifi.h" -#define VERSION "20.49.0-dev" +#define VERSION "21.04.0-dev" String create_lat_aprs(double lat); String create_long_aprs(double lng); From 8cf0c6768321ace66bc7a35b79b60c4397b10ef9 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Wed, 10 Feb 2021 22:37:18 +0100 Subject: [PATCH 38/60] add display turning close #61 --- data/is-cfg.json | 3 ++- lib/Display/Display.cpp | 5 +++++ lib/Display/Display.h | 1 + {lib/TaskManager => src}/TaskDisplay.cpp | 5 +++++ {lib/TaskManager => src}/TaskDisplay.h | 0 src/project_configuration.cpp | 2 ++ src/project_configuration.h | 3 ++- 7 files changed, 17 insertions(+), 2 deletions(-) rename {lib/TaskManager => src}/TaskDisplay.cpp (85%) rename {lib/TaskManager => src}/TaskDisplay.h (100%) diff --git a/data/is-cfg.json b/data/is-cfg.json index 5a2ee13..e7674fc 100644 --- a/data/is-cfg.json +++ b/data/is-cfg.json @@ -35,7 +35,8 @@ { "always_on": true, "timeout":10, - "overwrite_pin":0 + "overwrite_pin":0, + "turn180": true }, "ftp": { diff --git a/lib/Display/Display.cpp b/lib/Display/Display.cpp index 65ad3dd..1556487 100644 --- a/lib/Display/Display.cpp +++ b/lib/Display/Display.cpp @@ -25,6 +25,11 @@ void Display::setup(std::shared_ptr boardConfig) _disp->display(&bitmap); } +void Display::turn180() +{ + _disp->flipScreenVertically(); +} + void Display::update() { if(_statusFrame->isPrio()) diff --git a/lib/Display/Display.h b/lib/Display/Display.h index a86fc8e..86ddcb4 100644 --- a/lib/Display/Display.h +++ b/lib/Display/Display.h @@ -32,6 +32,7 @@ public: ~Display() {} void setup(std::shared_ptr boardConfig); + void turn180(); void update(); void addFrame(std::shared_ptr frame); diff --git a/lib/TaskManager/TaskDisplay.cpp b/src/TaskDisplay.cpp similarity index 85% rename from lib/TaskManager/TaskDisplay.cpp rename to src/TaskDisplay.cpp index af99345..bc2c703 100644 --- a/lib/TaskManager/TaskDisplay.cpp +++ b/src/TaskDisplay.cpp @@ -1,5 +1,6 @@ #include #include +#include "project_configuration.h" #include "TaskDisplay.h" DisplayTask::DisplayTask() @@ -14,6 +15,10 @@ DisplayTask::~DisplayTask() bool DisplayTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { Display::instance().setup(boardConfig); + if(config->display.turn180) + { + Display::instance().turn180(); + } std::shared_ptr statusFrame = std::shared_ptr(new StatusFrame(TaskManager::instance().getTasks())); Display::instance().setStatusFrame(statusFrame); _stateInfo = ""; diff --git a/lib/TaskManager/TaskDisplay.h b/src/TaskDisplay.h similarity index 100% rename from lib/TaskManager/TaskDisplay.h rename to src/TaskDisplay.h diff --git a/src/project_configuration.cpp b/src/project_configuration.cpp index ffb98d8..4d4f7b0 100644 --- a/src/project_configuration.cpp +++ b/src/project_configuration.cpp @@ -37,6 +37,7 @@ std::shared_ptr ProjectConfigurationManagement::readProjectConfig conf->display.alwaysOn = data["display"]["always_on"] | true; conf->display.timeout = data["display"]["timeout"] | 10; conf->display.overwritePin = data["display"]["overwrite_pin"] | 0; + conf->display.turn180 = data["display"]["turn180"] | true; conf->ftp.active = data["ftp"]["active"] | false; JsonArray users = data["ftp"]["user"].as(); @@ -89,6 +90,7 @@ void ProjectConfigurationManagement::writeProjectConfiguration(std::shared_ptrdisplay.alwaysOn; data["display"]["timeout"] = conf->display.timeout; data["display"]["overwrite_pin"] = conf->display.overwritePin; + data["display"]["turn180"] = conf->display.turn180; data["ftp"]["active"] = conf->ftp.active; JsonArray users = data["ftp"].createNestedArray("user"); for(Configuration::Ftp::User u : conf->ftp.users) diff --git a/src/project_configuration.h b/src/project_configuration.h index adb47d7..44da8e5 100644 --- a/src/project_configuration.h +++ b/src/project_configuration.h @@ -59,11 +59,12 @@ public: class Display { public: - Display() : alwaysOn(true), timeout(10), overwritePin(0) {} + Display() : alwaysOn(true), timeout(10), overwritePin(0), turn180(true) {} bool alwaysOn; int timeout; int overwritePin; + bool turn180; }; class Ftp From 54a1e5bac721a10c62c6887e790ff8e11227cde9 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Wed, 10 Feb 2021 23:35:17 +0100 Subject: [PATCH 39/60] fixing cppcheck --- lib/TaskManager/TaskManager.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/TaskManager/TaskManager.cpp b/lib/TaskManager/TaskManager.cpp index 1bf6d07..d660403 100644 --- a/lib/TaskManager/TaskManager.cpp +++ b/lib/TaskManager/TaskManager.cpp @@ -90,12 +90,8 @@ void StatusFrame::drawStatusPage(Bitmap & bitmap) bool StatusFrame::isPrio() const { - for(std::shared_ptr task : _tasks) + return std::any_of(_tasks.begin(), _tasks.end(), [](std::shared_ptr task) { - if(task->getState() != Okay) - { - return true; - } - } - return false; + return task->getState() != Okay; + }); } From 38d50cb8012898d90b29590e2375abce7bef3531 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Thu, 11 Feb 2021 22:07:17 +0100 Subject: [PATCH 40/60] add callsign on display close #64 --- src/TaskDisplay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TaskDisplay.cpp b/src/TaskDisplay.cpp index bc2c703..35f3e38 100644 --- a/src/TaskDisplay.cpp +++ b/src/TaskDisplay.cpp @@ -21,7 +21,7 @@ bool DisplayTask::setup(std::shared_ptr config, std::shared_ptr statusFrame = std::shared_ptr(new StatusFrame(TaskManager::instance().getTasks())); Display::instance().setStatusFrame(statusFrame); - _stateInfo = ""; + _stateInfo = config->callsign; return true; } From 7326a60ee2ce55d33cb3d56320a02c6fb804e965 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Thu, 11 Feb 2021 23:03:59 +0100 Subject: [PATCH 41/60] version push --- src/LoRa_APRS_iGate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index 3888317..faf1db5 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -20,7 +20,7 @@ #include "TaskOTA.h" #include "TaskWifi.h" -#define VERSION "21.04.0-dev" +#define VERSION "21.06.0-dev" String create_lat_aprs(double lat); String create_long_aprs(double lng); From bacecf62578e3cc90b9de2d9cc65d74a373e221a Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Fri, 12 Feb 2021 23:42:58 +0100 Subject: [PATCH 42/60] remove aprs-is files and add as library again --- lib/APRS-IS/APRS-IS.cpp | 107 ---------------------------------------- lib/APRS-IS/APRS-IS.h | 35 ------------- platformio.ini | 1 + 3 files changed, 1 insertion(+), 142 deletions(-) delete mode 100644 lib/APRS-IS/APRS-IS.cpp delete mode 100644 lib/APRS-IS/APRS-IS.h diff --git a/lib/APRS-IS/APRS-IS.cpp b/lib/APRS-IS/APRS-IS.cpp deleted file mode 100644 index af34a7c..0000000 --- a/lib/APRS-IS/APRS-IS.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include -#include "APRS-IS.h" - -APRS_IS::APRS_IS(const String & user, const String & passcode, const String & tool_name, const String & version) - : _user(user), _passcode(passcode), _tool_name(tool_name), _version(version) -{ -} - -bool APRS_IS::connect(const String & server, const int port) -{ - const String login = "user " + _user + " pass " + _passcode + " vers " + _tool_name + " " + _version + "\n\r"; - return connect_(server, port, login); -} - -bool APRS_IS::connect(const String & server, const int port, const String & filter) -{ - const String login = "user " + _user + " pass " + _passcode + " vers " + _tool_name + " " + _version + " filter " + filter + "\n\r"; - return connect_(server, port, login); -} - -bool APRS_IS::connect_(const String & server, const int port, const String & login_line) -{ - if(!_client.connect(server.c_str(), port)) - { - logPrintlnE("Something went wrong on connecting! Is the server reachable?"); - return false; - } - sendMessage(login_line); - while(true) - { - String line = _client.readStringUntil('\n'); - if(line.indexOf("logresp") != -1) - { - if(line.indexOf("unverified") == -1) - { - return true; - } - else - { - logPrintlnE("User can not be verified with passcode!"); - return false; - } - } - } - return true; -} - -bool APRS_IS::connected() -{ - return _client.connected(); -} - -bool APRS_IS::sendMessage(const String & message) -{ - if(!connected()) - { - return false; - } - _client.println(message); - return true; -} - -bool APRS_IS::sendMessage(const std::shared_ptr message) -{ - if(!connected()) - { - return false; - } - _client.println(message->encode() + "\n"); - return true; -} - -int APRS_IS::available() -{ - return _client.available(); -} - -String APRS_IS::getMessage() -{ - String line; - if (_client.available() > 0) - { - line = _client.readStringUntil('\n'); - } - return line; -} - -std::shared_ptr APRS_IS::getAPRSMessage() -{ - String line; - if (_client.available() > 0) - { - line = _client.readStringUntil('\n'); - } - if(line.startsWith("#")) - { - //logPrintlnD(line); - return 0; - } - if(line.length() == 0) - { - return 0; - } - std::shared_ptr msg = std::shared_ptr(new APRSMessage()); - msg->decode(line); - return msg; -} diff --git a/lib/APRS-IS/APRS-IS.h b/lib/APRS-IS/APRS-IS.h deleted file mode 100644 index 256df1e..0000000 --- a/lib/APRS-IS/APRS-IS.h +++ /dev/null @@ -1,35 +0,0 @@ - -#ifndef APRS_IS_Lib_h_ -#define APRS_IS_Lib_h_ - -#include -#include - -class APRS_IS -{ -public: - APRS_IS(const String & user, const String & passcode, const String & tool_name, const String & version); - - bool connect(const String & server, const int port); - bool connect(const String & server, const int port, const String & filter); - bool connect_(const String & server, const int port, const String & login_line); - bool connected(); - - bool sendMessage(const String & message); - bool sendMessage(const std::shared_ptr message); - - int available(); - - String getMessage(); - std::shared_ptr getAPRSMessage(); - -private: - const String _user; - const String _passcode; - const String _tool_name; - const String _version; - WiFiClient _client; -}; - -#endif - diff --git a/platformio.ini b/platformio.ini index c150286..5a17682 100644 --- a/platformio.ini +++ b/platformio.ini @@ -8,6 +8,7 @@ lib_deps = bblanchon/ArduinoJson @ 6.17.0 lewisxhe/AXP202X_Library @ 1.1.2 peterus/APRS-Decoder-Lib @ 0.0.6 + peterus/APRS-IS-Lib @ 0.0.8 peterus/esp-logger @ 0.0.1 peterus/ESP-FTP-Server-Lib @ 0.9.5 check_tool = cppcheck From 680be7887dd5cf78ec98730e09c4d51d6c2eb7ec Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Fri, 12 Feb 2021 23:45:51 +0100 Subject: [PATCH 43/60] change github actions --- .github/workflows/build_check.yml | 54 +++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build_check.yml b/.github/workflows/build_check.yml index 3fb5e36..a731bc7 100644 --- a/.github/workflows/build_check.yml +++ b/.github/workflows/build_check.yml @@ -1,35 +1,55 @@ name: Build check and build -on: - push: - paths-ignore: - - '*.md' - pull_request: - paths-ignore: - - '*.md' +on: [push, pull_request] jobs: PlatformIO-Check: runs-on: ubuntu-latest steps: - - run: sudo apt-get install python3-setuptools python3-wheel - - run: pip3 install platformio - - run: echo "$HOME/.local/bin" >> $GITHUB_PATH - uses: actions/checkout@v2 + - name: Cache pip + uses: actions/cache@v2 with: - submodules: 'recursive' - - run: platformio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: ${{ runner.os }}-pip- + - name: Cache PlatformIO + uses: actions/cache@v2 + with: + path: ~/.platformio + key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} + - name: Set up Python + uses: actions/setup-python@v2 + - name: Install PlatformIO + run: | + python -m pip install --upgrade pip + pip install --upgrade platformio + - name: Run PlatformIO Check + run: platformio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high PlatformIO-Build: runs-on: ubuntu-latest steps: - - run: sudo apt-get install python3-setuptools python3-wheel - - run: pip3 install platformio - - run: echo "$HOME/.local/bin" >> $GITHUB_PATH - uses: actions/checkout@v2 + - name: Cache pip + uses: actions/cache@v2 with: - submodules: 'recursive' - - run: platformio run + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: ${{ runner.os }}-pip- + - name: Cache PlatformIO + uses: actions/cache@v2 + with: + path: ~/.platformio + key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} + - name: Set up Python + uses: actions/setup-python@v2 + - name: Install PlatformIO + run: | + python -m pip install --upgrade pip + pip install --upgrade platformio + - name: Run PlatformIO CI + run: platformio run - uses: actions/upload-artifact@v2 with: name: firmware From 545d1e32b143ad0d2c6a602caff7e33161064868 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Fri, 12 Feb 2021 23:49:40 +0100 Subject: [PATCH 44/60] remove space --- platformio.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 5a17682..dfdaf06 100644 --- a/platformio.ini +++ b/platformio.ini @@ -20,7 +20,6 @@ check_skip_packages = yes #upload_protocol = espota #upload_port = .local - [env:lora_board] board = esp32doit-devkit-v1 build_flags = -Werror -Wall -DNO_GLOBAL_INSTANCES From 3bec532b1828d3aa67826710df74c826dde83c95 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sun, 7 Mar 2021 21:42:48 +0100 Subject: [PATCH 45/60] change aprs overlay to a L in a red box --- src/TaskAprsIs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TaskAprsIs.cpp b/src/TaskAprsIs.cpp index c575828..130ee7a 100644 --- a/src/TaskAprsIs.cpp +++ b/src/TaskAprsIs.cpp @@ -25,7 +25,7 @@ bool AprsIsTask::setup(std::shared_ptr config, std::shared_ptrsetDestination("APLG0"); String lat = create_lat_aprs(config->beacon.positionLatitude); String lng = create_long_aprs(config->beacon.positionLongitude); - _beaconMsg->getBody()->setData(String("=") + lat + "I" + lng + "&" + config->beacon.message); + _beaconMsg->getBody()->setData(String("=") + lat + "L" + lng + "a" + config->beacon.message); return true; } From 0b01014e50bf7d69036aa5db2e0721997b87a248 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sun, 7 Mar 2021 21:45:38 +0100 Subject: [PATCH 46/60] change internal version --- src/TaskAprsIs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TaskAprsIs.cpp b/src/TaskAprsIs.cpp index 130ee7a..7d05e54 100644 --- a/src/TaskAprsIs.cpp +++ b/src/TaskAprsIs.cpp @@ -18,11 +18,11 @@ AprsIsTask::~AprsIsTask() bool AprsIsTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { - _aprs_is = std::shared_ptr(new APRS_IS(config->callsign, config->aprs_is.passcode , "ESP32-APRS-IS", "0.1")); + _aprs_is = std::shared_ptr(new APRS_IS(config->callsign, config->aprs_is.passcode , "ESP32-APRS-IS", "0.2")); _beaconMsg = std::shared_ptr(new APRSMessage()); _beaconMsg->setSource(config->callsign); - _beaconMsg->setDestination("APLG0"); + _beaconMsg->setDestination("APLG1"); String lat = create_lat_aprs(config->beacon.positionLatitude); String lng = create_long_aprs(config->beacon.positionLongitude); _beaconMsg->getBody()->setData(String("=") + lat + "L" + lng + "a" + config->beacon.message); From d411376f8efb34405e9f928e99fe996e2d11c390 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Fri, 12 Mar 2021 20:01:47 +0100 Subject: [PATCH 47/60] add timer --- lib/TaskManager/Timer.cpp | 36 ++++++++++++++++++++++++++++++++++++ lib/TaskManager/Timer.h | 26 ++++++++++++++++++++++++++ lib/TimeLib/TimeLib.h | 9 +++++---- src/TaskAprsIs.cpp | 9 +++++---- src/TaskAprsIs.h | 3 ++- 5 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 lib/TaskManager/Timer.cpp create mode 100644 lib/TaskManager/Timer.h diff --git a/lib/TaskManager/Timer.cpp b/lib/TaskManager/Timer.cpp new file mode 100644 index 0000000..c89a105 --- /dev/null +++ b/lib/TaskManager/Timer.cpp @@ -0,0 +1,36 @@ +#include "Timer.h" + +Timer::Timer() + : _timeout_sec(0), _timeout(0) +{ +} + +void Timer::setTimeout(const time_t timeout_sec) +{ + _timeout_sec = timeout_sec; +} + +time_t Timer::getTriggerTime() const +{ + return _timeout; +} + +bool Timer::isActive() const +{ + return _timeout != 0; +} + +void Timer::reset() +{ + _timeout = 0; +} + +bool Timer::check() +{ + return now() > _timeout; +} + +void Timer::start() +{ + _timeout = now() + _timeout_sec; +} diff --git a/lib/TaskManager/Timer.h b/lib/TaskManager/Timer.h new file mode 100644 index 0000000..60f78e7 --- /dev/null +++ b/lib/TaskManager/Timer.h @@ -0,0 +1,26 @@ +#ifndef TIMER_H_ +#define TIMER_H_ + +#include + +class Timer +{ +public: + Timer(); + + void setTimeout(const time_t timeout_sec); + time_t getTriggerTime() const; + + bool isActive() const; + + void reset(); + + bool check(); + void start(); + +private: + time_t _timeout_sec; + time_t _timeout; +}; + +#endif diff --git a/lib/TimeLib/TimeLib.h b/lib/TimeLib/TimeLib.h index b624542..a5ffb24 100644 --- a/lib/TimeLib/TimeLib.h +++ b/lib/TimeLib/TimeLib.h @@ -11,6 +11,7 @@ #define _Time_h #include +#include typedef enum {timeNotSet, timeNeedsSync, timeSet } timeStatus_t ; @@ -70,10 +71,10 @@ typedef time_t(*getExternalTime)(); /* Useful Macros for converting elapsed time to a time_t */ -#define minutesToTime_t ((M)) ( (M) * SECS_PER_MIN) -#define hoursToTime_t ((H)) ( (H) * SECS_PER_HOUR) -#define daysToTime_t ((D)) ( (D) * SECS_PER_DAY) // fixed on Jul 22 2011 -#define weeksToTime_t ((W)) ( (W) * SECS_PER_WEEK) +#define minutesToTime_t(M) ((M) * SECS_PER_MIN) +#define hoursToTime_t(H) ((H) * SECS_PER_HOUR) +#define daysToTime_t(D) ((D) * SECS_PER_DAY) // fixed on Jul 22 2011 +#define weeksToTime_t(W) ((W) * SECS_PER_WEEK) /*============================================================================*/ /* time and date functions */ diff --git a/src/TaskAprsIs.cpp b/src/TaskAprsIs.cpp index 7d05e54..83be5ad 100644 --- a/src/TaskAprsIs.cpp +++ b/src/TaskAprsIs.cpp @@ -8,7 +8,7 @@ String create_lat_aprs(double lat); String create_long_aprs(double lng); AprsIsTask::AprsIsTask() - : Task(TASK_APRS_IS, TaskAprsIs), _beacon_next_time(0) + : Task(TASK_APRS_IS, TaskAprsIs) { } @@ -18,6 +18,7 @@ AprsIsTask::~AprsIsTask() bool AprsIsTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { + _beacon_timer.setTimeout(minutesToTime_t(config->beacon.timeout)); _aprs_is = std::shared_ptr(new APRS_IS(config->callsign, config->aprs_is.passcode , "ESP32-APRS-IS", "0.2")); _beaconMsg = std::shared_ptr(new APRSMessage()); @@ -53,15 +54,15 @@ bool AprsIsTask::loop(std::shared_ptr config) _aprs_is->sendMessage(msg); } - if(_beacon_next_time < now()) + if(_beacon_timer.check()) { logPrintD("[" + timeString() + "] "); logPrintlnD(_beaconMsg->encode()); _aprs_is->sendMessage(_beaconMsg); Display::instance().addFrame(std::shared_ptr(new TextFrame("BEACON", _beaconMsg->toString()))); - _beacon_next_time = now() + config->beacon.timeout * 60UL; + _beacon_timer.start(); } - time_t diff = _beacon_next_time - now(); + time_t diff = _beacon_timer.getTriggerTime() - now(); _stateInfo = "beacon " + String(minute(diff)) + ":" + String(second(diff)); _state = Okay; return true; diff --git a/src/TaskAprsIs.h b/src/TaskAprsIs.h index 4c99e0c..f26041f 100644 --- a/src/TaskAprsIs.h +++ b/src/TaskAprsIs.h @@ -4,6 +4,7 @@ #include #include #include +#include class AprsIsTask : public Task { @@ -19,7 +20,7 @@ public: private: std::shared_ptr _aprs_is; std::shared_ptr _beaconMsg; - time_t _beacon_next_time; + Timer _beacon_timer; bool connect(std::shared_ptr config); }; From 269c9c1aedd108fd4e2f6f6d15d7e96f1616825a Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Fri, 12 Mar 2021 20:04:51 +0100 Subject: [PATCH 48/60] add display timeout fixing #63 --- lib/Display/Display.cpp | 76 +++++++++++++++++++++++++++-------------- lib/Display/Display.h | 9 ++++- 2 files changed, 59 insertions(+), 26 deletions(-) diff --git a/lib/Display/Display.cpp b/lib/Display/Display.cpp index 1556487..b39e285 100644 --- a/lib/Display/Display.cpp +++ b/lib/Display/Display.cpp @@ -3,7 +3,7 @@ #include Display::Display() - : _disp(0), _statusFrame(0), _nextFrameTime(0) + : _disp(0), _statusFrame(0), _displayOff(false) { } @@ -23,6 +23,8 @@ void Display::setup(std::shared_ptr boardConfig) Bitmap bitmap(_disp->getWidth(), _disp->getHeight()); _disp->display(&bitmap); + _displayTimeout.setTimeout(10); + _frameTimeout.setTimeout(15); } void Display::turn180() @@ -32,33 +34,42 @@ void Display::turn180() void Display::update() { - if(_statusFrame->isPrio()) + if(_frameTimeout.check()) { - Bitmap bitmap(_disp.get()); - _statusFrame->drawStatusPage(bitmap); - _disp->display(&bitmap); - return; - } + if(_statusFrame->isPrio()) + { + Bitmap bitmap(_disp.get()); + _statusFrame->drawStatusPage(bitmap); + activateDisplay(); + _disp->display(&bitmap); + return; + } - if(_nextFrameTime > now()) - { - return; - } + if(_frames.size() > 0) + { + std::shared_ptr frame = *_frames.begin(); + Bitmap bitmap(_disp.get()); + frame->drawStatusPage(bitmap); + activateDisplay(); + _disp->display(&bitmap); + _frames.pop_front(); + _frameTimeout.start(); + return; + } - if(_frames.size() > 0) - { - std::shared_ptr frame = *_frames.begin(); - Bitmap bitmap(_disp.get()); - frame->drawStatusPage(bitmap); - _disp->display(&bitmap); - _frames.pop_front(); - _nextFrameTime = now() + 15; - } - else - { - Bitmap bitmap(_disp.get()); - _statusFrame->drawStatusPage(bitmap); - _disp->display(&bitmap); + if(!_displayOff && !_displayTimeout.isActive()) + { + Bitmap bitmap(_disp.get()); + _statusFrame->drawStatusPage(bitmap); + activateDisplay(); + _disp->display(&bitmap); + _displayTimeout.start(); + } + if(_displayTimeout.check()) + { + deactivateDisplay(); + _displayTimeout.reset(); + } } } @@ -82,6 +93,21 @@ void Display::showSpashScreen(String firmwareTitle, String version) _disp->display(&bitmap); } +void Display::activateDisplay() +{ + if(_displayOff) + { + _disp->displayOn(); + _displayOff = false; + } +} + +void Display::deactivateDisplay() +{ + _disp->displayOff(); + _displayOff = true; +} + void TextFrame::drawStatusPage(Bitmap & bitmap) { diff --git a/lib/Display/Display.h b/lib/Display/Display.h index 86ddcb4..438c221 100644 --- a/lib/Display/Display.h +++ b/lib/Display/Display.h @@ -9,7 +9,9 @@ #include #include #include +#include +class Timer; class StatusFrame; class DisplayFrame @@ -46,12 +48,17 @@ private: std::list> _frames; std::shared_ptr _statusFrame; + Timer _frameTimeout; - time_t _nextFrameTime; + Timer _displayTimeout; + bool _displayOff; Display(); Display(const Display &); Display & operator = (const Display &); + + void activateDisplay(); + void deactivateDisplay(); }; class TextFrame : public DisplayFrame From fd4e34bb6c65acc137ea89752f61d85b596c8df2 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Fri, 12 Mar 2021 21:43:22 +0100 Subject: [PATCH 49/60] upgrade platformio espressif32 package --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index dfdaf06..59ff75f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1,5 +1,5 @@ [env] -platform = espressif32 @ 2.1.0 +platform = espressif32 @ 3.0.0 framework = arduino lib_ldf_mode = deep+ monitor_speed = 115200 From ff25ad46962524cfccb74604f8ab852bb0567fa8 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Fri, 12 Mar 2021 23:21:45 +0100 Subject: [PATCH 50/60] add clang-format and format all source files --- .clang-format | 149 +++++ .vscode/extensions.json | 3 +- .vscode/settings.json | 4 + lib/BoardFinder/BoardFinder.cpp | 246 ++++---- lib/BoardFinder/BoardFinder.h | 72 +-- lib/ConfigurationManagement/configuration.cpp | 90 ++- lib/ConfigurationManagement/configuration.h | 17 +- lib/Display/Bitmap.cpp | 575 ++++++++---------- lib/Display/Bitmap.h | 61 +- lib/Display/Display.cpp | 165 +++-- lib/Display/Display.h | 87 +-- lib/LoRa_APRS/LoRa_APRS.cpp | 110 ++-- lib/LoRa_APRS/LoRa_APRS.h | 41 +- lib/PowerManagement/power_management.cpp | 48 +- lib/PowerManagement/power_management.h | 21 +- lib/TaskManager/TaskManager.cpp | 138 ++--- lib/TaskManager/TaskManager.h | 100 +-- lib/TaskManager/TaskQueue.h | 34 +- lib/TaskManager/Timer.cpp | 34 +- lib/TaskManager/Timer.h | 21 +- src/LoRa_APRS_iGate.cpp | 212 +++---- src/Task.cpp | 26 - src/Task.h | 32 +- src/TaskAprsIs.cpp | 120 ++-- src/TaskAprsIs.h | 23 +- src/TaskDisplay.cpp | 39 +- src/TaskDisplay.h | 11 +- src/TaskEth.cpp | 132 ++-- src/TaskEth.h | 11 +- src/TaskFTP.cpp | 74 +-- src/TaskFTP.h | 17 +- src/TaskLora.cpp | 96 ++- src/TaskLora.h | 17 +- src/TaskNTP.cpp | 50 +- src/TaskNTP.h | 17 +- src/TaskOTA.cpp | 102 ++-- src/TaskOTA.h | 17 +- src/TaskWifi.cpp | 73 +-- src/TaskWifi.h | 15 +- src/project_configuration.cpp | 210 +++---- src/project_configuration.h | 162 +++-- 41 files changed, 1664 insertions(+), 1808 deletions(-) create mode 100644 .clang-format create mode 100644 .vscode/settings.json delete mode 100644 src/Task.cpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..06c7984 --- /dev/null +++ b/.clang-format @@ -0,0 +1,149 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: true +AlignConsecutiveAssignments: true +AlignConsecutiveBitFields: true +AlignConsecutiveDeclarations: true +AlignEscapedNewlines: Left +AlignOperands: Align +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: false +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortLambdasOnASingleLine: None +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 500 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + - Regex: '.*' + Priority: 1 + SortPriority: 0 +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentCaseLabels: false +IndentCaseBlocks: false +IndentGotoLabels: true +IndentPPDirectives: None +IndentExternBlock: AfterExternBlock +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +Standard: Latest +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE +... + diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 0f0d740..27bdd05 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -2,6 +2,7 @@ // See http://go.microsoft.com/fwlink/?LinkId=827846 // for the documentation about the extensions.json format "recommendations": [ - "platformio.platformio-ide" + "platformio.platformio-ide", + "xaver.clang-format" ] } diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..38d51f2 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "files.insertFinalNewline": true, + "editor.formatOnSave": true +} \ No newline at end of file diff --git a/lib/BoardFinder/BoardFinder.cpp b/lib/BoardFinder/BoardFinder.cpp index 8b91cb5..57d3d28 100644 --- a/lib/BoardFinder/BoardFinder.cpp +++ b/lib/BoardFinder/BoardFinder.cpp @@ -1,167 +1,135 @@ +#include "BoardFinder.h" #include #include -#include "BoardFinder.h" -BoardConfig::BoardConfig( - String name, BoardType type, - uint8_t oledsda, uint8_t oledscl, uint8_t oledaddr, uint8_t oledreset, - uint8_t lorasck, uint8_t loramiso, uint8_t loramosi, uint8_t loracs, uint8_t lorareset, uint8_t lorairq, - bool needcheckpowerchip, bool powercheckstatus) - : - Name(name), Type(type), - OledSda(oledsda), OledScl(oledscl), OledAddr(oledaddr), OledReset(oledreset), - LoraSck(lorasck), LoraMiso(loramiso), LoraMosi(loramosi), LoraCS(loracs), LoraReset(lorareset), LoraIRQ(lorairq), - needCheckPowerChip(needcheckpowerchip), powerCheckStatus(powercheckstatus) -{ +BoardConfig::BoardConfig(String name, BoardType type, uint8_t oledsda, uint8_t oledscl, uint8_t oledaddr, uint8_t oledreset, uint8_t lorasck, uint8_t loramiso, uint8_t loramosi, uint8_t loracs, uint8_t lorareset, uint8_t lorairq, bool needcheckpowerchip, bool powercheckstatus) + : Name(name), Type(type), OledSda(oledsda), OledScl(oledscl), OledAddr(oledaddr), OledReset(oledreset), LoraSck(lorasck), LoraMiso(loramiso), LoraMosi(loramosi), LoraCS(loracs), LoraReset(lorareset), LoraIRQ(lorairq), needCheckPowerChip(needcheckpowerchip), powerCheckStatus(powercheckstatus) { } -BoardFinder::BoardFinder(std::list> & boardConfigs) - : _boardConfigs(boardConfigs) -{ +BoardFinder::BoardFinder(std::list> &boardConfigs) : _boardConfigs(boardConfigs) { } -std::shared_ptr BoardFinder::searchBoardConfig() -{ - logPrintlnI("looking for a board config."); - logPrintlnI("searching for OLED..."); +std::shared_ptr BoardFinder::searchBoardConfig() { + logPrintlnI("looking for a board config."); + logPrintlnI("searching for OLED..."); - for(std::shared_ptr boardconf : _boardConfigs) - { - if(boardconf->needCheckPowerChip && checkPowerConfig(boardconf) == boardconf->powerCheckStatus) - { - PowerManagement powerManagement; - TwoWire wire(0); - wire.begin(boardconf->OledSda, boardconf->OledScl); - powerManagement.begin(wire); - powerManagement.activateOLED(); - } - else if(boardconf->needCheckPowerChip) - { - continue; - } - if(checkOledConfig(boardconf)) - { - logPrintI("found a board config: "); - logPrintlnI(boardconf->Name); - return boardconf; - } - } + for (std::shared_ptr boardconf : _boardConfigs) { + if (boardconf->needCheckPowerChip && checkPowerConfig(boardconf) == boardconf->powerCheckStatus) { + PowerManagement powerManagement; + TwoWire wire(0); + wire.begin(boardconf->OledSda, boardconf->OledScl); + powerManagement.begin(wire); + powerManagement.activateOLED(); + } else if (boardconf->needCheckPowerChip) { + continue; + } + if (checkOledConfig(boardconf)) { + logPrintI("found a board config: "); + logPrintlnI(boardconf->Name); + return boardconf; + } + } - logPrintlnW("could not find OLED, will search for the modem now..."); + logPrintlnW("could not find OLED, will search for the modem now..."); - for(std::shared_ptr boardconf : _boardConfigs) - { - if(boardconf->needCheckPowerChip && checkPowerConfig(boardconf) == boardconf->powerCheckStatus) - { - PowerManagement powerManagement; - TwoWire wire(0); - wire.begin(boardconf->OledSda, boardconf->OledScl); - powerManagement.begin(wire); - powerManagement.activateLoRa(); - } - if(checkModemConfig(boardconf)) - { - logPrintI("found a board config: "); - logPrintlnI(boardconf->Name); - return boardconf; - } - } + for (std::shared_ptr boardconf : _boardConfigs) { + if (boardconf->needCheckPowerChip && checkPowerConfig(boardconf) == boardconf->powerCheckStatus) { + PowerManagement powerManagement; + TwoWire wire(0); + wire.begin(boardconf->OledSda, boardconf->OledScl); + powerManagement.begin(wire); + powerManagement.activateLoRa(); + } + if (checkModemConfig(boardconf)) { + logPrintI("found a board config: "); + logPrintlnI(boardconf->Name); + return boardconf; + } + } - logPrintlnW("could not find a board config!"); + logPrintlnW("could not find a board config!"); - return 0; + return 0; } -std::shared_ptr BoardFinder::getBoardConfig(String name) -{ - std::_List_iterator> elem = std::find_if(_boardConfigs.begin(), _boardConfigs.end(), [&](std::shared_ptr conf) - { - return conf->Name == name; - }); - if(elem == _boardConfigs.end()) - { - return 0; - } - return *elem; +std::shared_ptr BoardFinder::getBoardConfig(String name) { + std::_List_iterator> elem = std::find_if(_boardConfigs.begin(), _boardConfigs.end(), [&](std::shared_ptr conf) { + return conf->Name == name; + }); + if (elem == _boardConfigs.end()) { + return 0; + } + return *elem; } -bool BoardFinder::checkOledConfig(std::shared_ptr boardConfig) -{ - if(boardConfig->OledReset > 0) - { - pinMode(boardConfig->OledReset, OUTPUT); - digitalWrite(boardConfig->OledReset, HIGH); - delay(1); - digitalWrite(boardConfig->OledReset, LOW); - delay(10); - digitalWrite(boardConfig->OledReset, HIGH); - } - TwoWire wire(0); - if(!wire.begin(boardConfig->OledSda, boardConfig->OledScl)) - { - logPrintlnW("issue with wire"); - return false; - } - wire.beginTransmission(boardConfig->OledAddr); - if(!wire.endTransmission()) - { - return true; - } - return false; +bool BoardFinder::checkOledConfig(std::shared_ptr boardConfig) { + if (boardConfig->OledReset > 0) { + pinMode(boardConfig->OledReset, OUTPUT); + digitalWrite(boardConfig->OledReset, HIGH); + delay(1); + digitalWrite(boardConfig->OledReset, LOW); + delay(10); + digitalWrite(boardConfig->OledReset, HIGH); + } + TwoWire wire(0); + if (!wire.begin(boardConfig->OledSda, boardConfig->OledScl)) { + logPrintlnW("issue with wire"); + return false; + } + wire.beginTransmission(boardConfig->OledAddr); + if (!wire.endTransmission()) { + return true; + } + return false; } -bool BoardFinder::checkModemConfig(std::shared_ptr boardConfig) -{ - pinMode(boardConfig->LoraReset, OUTPUT); - digitalWrite(boardConfig->LoraReset, LOW); - delay(10); - digitalWrite(boardConfig->LoraReset, HIGH); - delay(10); +bool BoardFinder::checkModemConfig(std::shared_ptr boardConfig) { + pinMode(boardConfig->LoraReset, OUTPUT); + digitalWrite(boardConfig->LoraReset, LOW); + delay(10); + digitalWrite(boardConfig->LoraReset, HIGH); + delay(10); - pinMode(boardConfig->LoraCS, OUTPUT); - digitalWrite(boardConfig->LoraCS, HIGH); + pinMode(boardConfig->LoraCS, OUTPUT); + digitalWrite(boardConfig->LoraCS, HIGH); - SPIClass spi; - spi.begin(boardConfig->LoraSck, boardConfig->LoraMiso, boardConfig->LoraMosi, boardConfig->LoraCS); + SPIClass spi; + spi.begin(boardConfig->LoraSck, boardConfig->LoraMiso, boardConfig->LoraMosi, boardConfig->LoraCS); - digitalWrite(boardConfig->LoraCS, LOW); + digitalWrite(boardConfig->LoraCS, LOW); - spi.beginTransaction(SPISettings(8E6, MSBFIRST, SPI_MODE0)); - spi.transfer(0x42); - uint8_t response = spi.transfer(0x00); - spi.endTransaction(); + spi.beginTransaction(SPISettings(8E6, MSBFIRST, SPI_MODE0)); + spi.transfer(0x42); + uint8_t response = spi.transfer(0x00); + spi.endTransaction(); - digitalWrite(boardConfig->LoraCS, HIGH); + digitalWrite(boardConfig->LoraCS, HIGH); - if(response == 0x12) - { - return true; - } - return false; + if (response == 0x12) { + return true; + } + return false; } -bool BoardFinder::checkPowerConfig(std::shared_ptr boardConfig) -{ - TwoWire wire(0); - if(!wire.begin(boardConfig->OledSda, boardConfig->OledScl)) - { - logPrintlnW("issue with wire"); - return false; - } - wire.beginTransmission(0x34); - wire.write(0x03); - wire.endTransmission(); - - wire.requestFrom(0x34, 1); - int response = wire.read(); - wire.endTransmission(); +bool BoardFinder::checkPowerConfig(std::shared_ptr boardConfig) { + TwoWire wire(0); + if (!wire.begin(boardConfig->OledSda, boardConfig->OledScl)) { + logPrintlnW("issue with wire"); + return false; + } + wire.beginTransmission(0x34); + wire.write(0x03); + wire.endTransmission(); - logPrintlnD(String(response)); - if(response == 0x03) - { - logPrintlnD("power chip found!"); - return true; - } - logPrintlnD("power chip NOT found"); - return false; + wire.requestFrom(0x34, 1); + int response = wire.read(); + wire.endTransmission(); + + logPrintlnD(String(response)); + if (response == 0x03) { + logPrintlnD("power chip found!"); + return true; + } + logPrintlnD("power chip NOT found"); + return false; } diff --git a/lib/BoardFinder/BoardFinder.h b/lib/BoardFinder/BoardFinder.h index 4dbe435..04dc8a4 100644 --- a/lib/BoardFinder/BoardFinder.h +++ b/lib/BoardFinder/BoardFinder.h @@ -5,64 +5,58 @@ #include #include -#include #include +#include enum BoardType { - eHELTEC_WIFI_LORA_32_V1, - eHELTEC_WIFI_LORA_32_V2, - eTTGO_LORA32_V1, - eTTGO_LORA32_V2, - eTTGO_T_Beam_V0_7, - eTTGO_T_Beam_V1_0, - eETH_BOARD, - eTRACKERD + eHELTEC_WIFI_LORA_32_V1, + eHELTEC_WIFI_LORA_32_V2, + eTTGO_LORA32_V1, + eTTGO_LORA32_V2, + eTTGO_T_Beam_V0_7, + eTTGO_T_Beam_V1_0, + eETH_BOARD, + eTRACKERD }; -class BoardConfig -{ +class BoardConfig { public: - explicit BoardConfig( - String name, BoardType type, - uint8_t oledsda, uint8_t oledscl, uint8_t oledaddr, uint8_t oledreset, - uint8_t lorasck, uint8_t loramiso, uint8_t loramosi, uint8_t loracs, uint8_t lorareset, uint8_t lorairq, - bool needcheckpowerchip = false, bool powercheckstatus = false); + explicit BoardConfig(String name, BoardType type, uint8_t oledsda, uint8_t oledscl, uint8_t oledaddr, uint8_t oledreset, uint8_t lorasck, uint8_t loramiso, uint8_t loramosi, uint8_t loracs, uint8_t lorareset, uint8_t lorairq, bool needcheckpowerchip = false, bool powercheckstatus = false); - String Name; - BoardType Type; + String Name; + BoardType Type; - uint8_t OledSda; - uint8_t OledScl; - uint8_t OledAddr; - uint8_t OledReset; + uint8_t OledSda; + uint8_t OledScl; + uint8_t OledAddr; + uint8_t OledReset; - uint8_t LoraSck; - uint8_t LoraMiso; - uint8_t LoraMosi; - uint8_t LoraCS; - uint8_t LoraReset; - uint8_t LoraIRQ; + uint8_t LoraSck; + uint8_t LoraMiso; + uint8_t LoraMosi; + uint8_t LoraCS; + uint8_t LoraReset; + uint8_t LoraIRQ; - bool needCheckPowerChip; - bool powerCheckStatus; + bool needCheckPowerChip; + bool powerCheckStatus; }; -class BoardFinder -{ +class BoardFinder { public: - explicit BoardFinder(std::list> & boardConfigs); + explicit BoardFinder(std::list> &boardConfigs); - std::shared_ptr searchBoardConfig(); + std::shared_ptr searchBoardConfig(); - std::shared_ptr getBoardConfig(String name); + std::shared_ptr getBoardConfig(String name); private: - std::list> _boardConfigs; + std::list> _boardConfigs; - bool checkOledConfig(std::shared_ptr boardConfig); - bool checkModemConfig(std::shared_ptr boardConfig); - bool checkPowerConfig(std::shared_ptr boardConfig); + bool checkOledConfig(std::shared_ptr boardConfig); + bool checkModemConfig(std::shared_ptr boardConfig); + bool checkPowerConfig(std::shared_ptr boardConfig); }; #endif diff --git a/lib/ConfigurationManagement/configuration.cpp b/lib/ConfigurationManagement/configuration.cpp index b713489..7a35fdc 100644 --- a/lib/ConfigurationManagement/configuration.cpp +++ b/lib/ConfigurationManagement/configuration.cpp @@ -1,65 +1,55 @@ +#include "configuration.h" #include #include -#include "configuration.h" -ConfigurationManagement::ConfigurationManagement(String FilePath) - : mFilePath(FilePath) -{ - if(!SPIFFS.begin(true)) - { - logPrintlnE("Mounting SPIFFS was not possible. Trying to format SPIFFS..."); - SPIFFS.format(); - if(!SPIFFS.begin()) - { - logPrintlnE("Formating SPIFFS was not okay!"); - } - } +ConfigurationManagement::ConfigurationManagement(String FilePath) : mFilePath(FilePath) { + if (!SPIFFS.begin(true)) { + logPrintlnE("Mounting SPIFFS was not possible. Trying to format SPIFFS..."); + SPIFFS.format(); + if (!SPIFFS.begin()) { + logPrintlnE("Formating SPIFFS was not okay!"); + } + } } -ConfigurationManagement::~ConfigurationManagement() -{ +ConfigurationManagement::~ConfigurationManagement() { } -std::shared_ptr ConfigurationManagement::readConfiguration() -{ - File file = SPIFFS.open(mFilePath); - if(!file) - { - logPrintlnE("Failed to open file for reading..."); - return 0; - } - DynamicJsonDocument data(2048); - DeserializationError error = deserializeJson(data, file); - if(error) - { - logPrintlnW("Failed to read file, using default configuration."); - } - //serializeJson(data, Serial); - //Serial.println(); - file.close(); +std::shared_ptr ConfigurationManagement::readConfiguration() { + File file = SPIFFS.open(mFilePath); + if (!file) { + logPrintlnE("Failed to open file for reading..."); + return 0; + } + DynamicJsonDocument data(2048); + DeserializationError error = deserializeJson(data, file); + if (error) { + logPrintlnW("Failed to read file, using default configuration."); + } + // serializeJson(data, Serial); + // Serial.println(); + file.close(); - std::shared_ptr conf = readProjectConfiguration(data); + std::shared_ptr conf = readProjectConfiguration(data); - // update config in memory to get the new fields: - writeConfiguration(conf); + // update config in memory to get the new fields: + writeConfiguration(conf); - return conf; + return conf; } -void ConfigurationManagement::writeConfiguration(std::shared_ptr conf) -{ - File file = SPIFFS.open(mFilePath, "w"); - if(!file) - { - logPrintlnE("Failed to open file for writing..."); - return; - } - DynamicJsonDocument data(2048); +void ConfigurationManagement::writeConfiguration(std::shared_ptr conf) { + File file = SPIFFS.open(mFilePath, "w"); + if (!file) { + logPrintlnE("Failed to open file for writing..."); + return; + } + DynamicJsonDocument data(2048); - writeProjectConfiguration(conf, data); + writeProjectConfiguration(conf, data); - serializeJson(data, file); - //serializeJson(data, Serial); - //Serial.println(); - file.close(); + serializeJson(data, file); + // serializeJson(data, Serial); + // Serial.println(); + file.close(); } diff --git a/lib/ConfigurationManagement/configuration.h b/lib/ConfigurationManagement/configuration.h index 5c66303..cb7b6d3 100644 --- a/lib/ConfigurationManagement/configuration.h +++ b/lib/ConfigurationManagement/configuration.h @@ -11,20 +11,19 @@ class Configuration; -class ConfigurationManagement -{ +class ConfigurationManagement { public: - explicit ConfigurationManagement(String FilePath); - virtual ~ConfigurationManagement(); + explicit ConfigurationManagement(String FilePath); + virtual ~ConfigurationManagement(); - std::shared_ptr readConfiguration(); - void writeConfiguration(std::shared_ptr conf); + std::shared_ptr readConfiguration(); + void writeConfiguration(std::shared_ptr conf); private: - virtual std::shared_ptr readProjectConfiguration(DynamicJsonDocument & data) = 0; - virtual void writeProjectConfiguration(std::shared_ptr conf, DynamicJsonDocument & data) = 0; + virtual std::shared_ptr readProjectConfiguration(DynamicJsonDocument &data) = 0; + virtual void writeProjectConfiguration(std::shared_ptr conf, DynamicJsonDocument &data) = 0; - const String mFilePath; + const String mFilePath; }; #endif diff --git a/lib/Display/Bitmap.cpp b/lib/Display/Bitmap.cpp index b8518b8..7321a45 100644 --- a/lib/Display/Bitmap.cpp +++ b/lib/Display/Bitmap.cpp @@ -1,424 +1,353 @@ #include "Bitmap.h" -#include "OLEDDisplay.h" #include "FontConfig.h" +#include "OLEDDisplay.h" //#include "OLEDDisplayFonts.h" // cppcheck-suppress unusedFunction -Bitmap::Bitmap(uint width, uint height) - : _width(width), _height(height), _buffer(0) -{ - allocateBuffer(); +Bitmap::Bitmap(uint width, uint height) : _width(width), _height(height), _buffer(0) { + allocateBuffer(); } // cppcheck-suppress unusedFunction -Bitmap::Bitmap(OLEDDisplay * display) - : _width(display->getWidth()), _height(display->getHeight()), _buffer(0) -{ - allocateBuffer(); +Bitmap::Bitmap(OLEDDisplay *display) : _width(display->getWidth()), _height(display->getHeight()), _buffer(0) { + allocateBuffer(); } // cppcheck-suppress unusedFunction -Bitmap::~Bitmap() -{ - if(_buffer != 0) - { - delete _buffer; - } +Bitmap::~Bitmap() { + if (_buffer != 0) { + delete _buffer; + } } // cppcheck-suppress unusedFunction -uint Bitmap::getWidth() const -{ - return _width; +uint Bitmap::getWidth() const { + return _width; } // cppcheck-suppress unusedFunction -uint Bitmap::getHeight() const -{ - return _height; +uint Bitmap::getHeight() const { + return _height; } // cppcheck-suppress unusedFunction -void Bitmap::setPixel(int x, int y) -{ - if(x >= 0 && x < _width && y >= 0 && y < _height) - { - _buffer[x + (y / 8) * _width] |= (1 << (y % 8)); - } +void Bitmap::setPixel(int x, int y) { + if (x >= 0 && x < _width && y >= 0 && y < _height) { + _buffer[x + (y / 8) * _width] |= (1 << (y % 8)); + } } // cppcheck-suppress unusedFunction -void Bitmap::clearPixel(int x, int y) -{ - if(x >= 0 && x < _width && y >= 0 && y < _height) - { - _buffer[x + (y / 8) * _width] &= ~(1 << (y % 8)); - } +void Bitmap::clearPixel(int x, int y) { + if (x >= 0 && x < _width && y >= 0 && y < _height) { + _buffer[x + (y / 8) * _width] &= ~(1 << (y % 8)); + } } // cppcheck-suppress unusedFunction -bool Bitmap::getPixel(int x, int y) const -{ - if(x >= 0 && x < _width && y >= 0 && y < _height) - { - return _buffer[x + (y / 8) * _width] & (1 << (y % 8)); - } - return false; +bool Bitmap::getPixel(int x, int y) const { + if (x >= 0 && x < _width && y >= 0 && y < _height) { + return _buffer[x + (y / 8) * _width] & (1 << (y % 8)); + } + return false; } // cppcheck-suppress unusedFunction -void Bitmap::clear() -{ - memset(_buffer, 0, _width * _height / 8); +void Bitmap::clear() { + memset(_buffer, 0, _width * _height / 8); } // cppcheck-suppress unusedFunction -void Bitmap::drawLine(int x0, int y0, int x1, int y1) -{ - int dx = abs(x1 - x0); - int dy = abs(y1 - y0); - int sx = x0 < x1 ? 1 : -1; - int sy = y0 < y1 ? 1 : -1; - int err = (dx > dy ? dx : -dy) / 2; +void Bitmap::drawLine(int x0, int y0, int x1, int y1) { + int dx = abs(x1 - x0); + int dy = abs(y1 - y0); + int sx = x0 < x1 ? 1 : -1; + int sy = y0 < y1 ? 1 : -1; + int err = (dx > dy ? dx : -dy) / 2; - while(true) - { - setPixel(x0, y0); - if(x0 == x1 && y0 == y1) - break; + while (true) { + setPixel(x0, y0); + if (x0 == x1 && y0 == y1) + break; - int e2 = err; - if(e2 > -dx) - { - err -= dy; - x0 += sx; - } - if(e2 < dy) - { - err += dx; - y0 += sy; - } - } + int e2 = err; + if (e2 > -dx) { + err -= dy; + x0 += sx; + } + if (e2 < dy) { + err += dx; + y0 += sy; + } + } } // cppcheck-suppress unusedFunction -void Bitmap::drawHorizontalLine(int x, int y, int length) -{ - if(y < 0 || y >= _height) - { - return; - } +void Bitmap::drawHorizontalLine(int x, int y, int length) { + if (y < 0 || y >= _height) { + return; + } - for(int i = 0; i < length; i++) - { - setPixel(x + i, y); - } + for (int i = 0; i < length; i++) { + setPixel(x + i, y); + } } // cppcheck-suppress unusedFunction -void Bitmap::drawVerticalLine(int x, int y, int length) -{ - if (x < 0 || x >= _width) - { - return; - } +void Bitmap::drawVerticalLine(int x, int y, int length) { + if (x < 0 || x >= _width) { + return; + } - for(int i = 0; i < length; i++) - { - setPixel(x, y + i); - } + for (int i = 0; i < length; i++) { + setPixel(x, y + i); + } } // cppcheck-suppress unusedFunction -void Bitmap::drawRect(int x, int y, int width, int height) -{ - drawHorizontalLine(x, y, width); - drawVerticalLine(x, y, height); - drawVerticalLine(x + width - 1, y, height); - drawHorizontalLine(x, y + height - 1, width); +void Bitmap::drawRect(int x, int y, int width, int height) { + drawHorizontalLine(x, y, width); + drawVerticalLine(x, y, height); + drawVerticalLine(x + width - 1, y, height); + drawHorizontalLine(x, y + height - 1, width); } // cppcheck-suppress unusedFunction -void Bitmap::fillRect(int x, int y, int width, int height) -{ - for (int i = 0; i < width; i++) - { - drawVerticalLine(x + i, y, height); - } +void Bitmap::fillRect(int x, int y, int width, int height) { + for (int i = 0; i < width; i++) { + drawVerticalLine(x + i, y, height); + } } // cppcheck-suppress unusedFunction -void Bitmap::drawCircle(int x0, int y0, int radius) -{ - int x = 0; - int y = radius; - int dp = 1 - radius; +void Bitmap::drawCircle(int x0, int y0, int radius) { + int x = 0; + int y = radius; + int dp = 1 - radius; - do - { - if (dp < 0) - { - dp = dp + (x++) * 2 + 3; - } - else - { - dp = dp + (x++) * 2 - (y--) * 2 + 5; - } + do { + if (dp < 0) { + dp = dp + (x++) * 2 + 3; + } else { + dp = dp + (x++) * 2 - (y--) * 2 + 5; + } - setPixel(x0 + x, y0 + y); //For the 8 octants - setPixel(x0 - x, y0 + y); - setPixel(x0 + x, y0 - y); - setPixel(x0 - x, y0 - y); - setPixel(x0 + y, y0 + x); - setPixel(x0 - y, y0 + x); - setPixel(x0 + y, y0 - x); - setPixel(x0 - y, y0 - x); - } - while (x < y); + setPixel(x0 + x, y0 + y); // For the 8 octants + setPixel(x0 - x, y0 + y); + setPixel(x0 + x, y0 - y); + setPixel(x0 - x, y0 - y); + setPixel(x0 + y, y0 + x); + setPixel(x0 - y, y0 + x); + setPixel(x0 + y, y0 - x); + setPixel(x0 - y, y0 - x); + } while (x < y); - setPixel(x0 + radius, y0); - setPixel(x0, y0 + radius); - setPixel(x0 - radius, y0); - setPixel(x0, y0 - radius); + setPixel(x0 + radius, y0); + setPixel(x0, y0 + radius); + setPixel(x0 - radius, y0); + setPixel(x0, y0 - radius); } // cppcheck-suppress unusedFunction -void Bitmap::fillCircle(int x0, int y0, int radius) -{ - int x = 0; - int y = radius; - int dp = 1 - radius; +void Bitmap::fillCircle(int x0, int y0, int radius) { + int x = 0; + int y = radius; + int dp = 1 - radius; - do - { - if (dp < 0) - { - dp = dp + (x++) * 2 + 3; - } - else - { - dp = dp + (x++) * 2 - (y--) * 2 + 5; - } + do { + if (dp < 0) { + dp = dp + (x++) * 2 + 3; + } else { + dp = dp + (x++) * 2 - (y--) * 2 + 5; + } - drawHorizontalLine(x0 - x, y0 - y, 2 * x); - drawHorizontalLine(x0 - x, y0 + y, 2 * x); - drawHorizontalLine(x0 - y, y0 - x, 2 * y); - drawHorizontalLine(x0 - y, y0 + x, 2 * y); - } - while (x < y); - - drawHorizontalLine(x0 - radius, y0, 2 * radius); + drawHorizontalLine(x0 - x, y0 - y, 2 * x); + drawHorizontalLine(x0 - x, y0 + y, 2 * x); + drawHorizontalLine(x0 - y, y0 - x, 2 * y); + drawHorizontalLine(x0 - y, y0 + x, 2 * y); + } while (x < y); + + drawHorizontalLine(x0 - radius, y0, 2 * radius); } // cppcheck-suppress unusedFunction -void Bitmap::drawCircleQuads(int x0, int y0, int radius, int quads) -{ - int x = 0; - int y = radius; - int dp = 1 - radius; +void Bitmap::drawCircleQuads(int x0, int y0, int radius, int quads) { + int x = 0; + int y = radius; + int dp = 1 - radius; - while (x < y) - { - if (dp < 0) - { - dp = dp + (x++) * 2 + 3; - } - else - { - dp = dp + (x++) * 2 - (y--) * 2 + 5; - } + while (x < y) { + if (dp < 0) { + dp = dp + (x++) * 2 + 3; + } else { + dp = dp + (x++) * 2 - (y--) * 2 + 5; + } - if (quads & 0x1) - { - setPixel(x0 + x, y0 - y); - setPixel(x0 + y, y0 - x); - } - if (quads & 0x2) - { - setPixel(x0 - y, y0 - x); - setPixel(x0 - x, y0 - y); - } - if (quads & 0x4) - { - setPixel(x0 - y, y0 + x); - setPixel(x0 - x, y0 + y); - } - if (quads & 0x8) - { - setPixel(x0 + x, y0 + y); - setPixel(x0 + y, y0 + x); - } - } - if (quads & 0x1 && quads & 0x8) - { - setPixel(x0 + radius, y0); - } - if (quads & 0x4 && quads & 0x8) - { - setPixel(x0, y0 + radius); - } - if (quads & 0x2 && quads & 0x4) - { - setPixel(x0 - radius, y0); - } - if (quads & 0x1 && quads & 0x2) - { - setPixel(x0, y0 - radius); - } + if (quads & 0x1) { + setPixel(x0 + x, y0 - y); + setPixel(x0 + y, y0 - x); + } + if (quads & 0x2) { + setPixel(x0 - y, y0 - x); + setPixel(x0 - x, y0 - y); + } + if (quads & 0x4) { + setPixel(x0 - y, y0 + x); + setPixel(x0 - x, y0 + y); + } + if (quads & 0x8) { + setPixel(x0 + x, y0 + y); + setPixel(x0 + y, y0 + x); + } + } + if (quads & 0x1 && quads & 0x8) { + setPixel(x0 + radius, y0); + } + if (quads & 0x4 && quads & 0x8) { + setPixel(x0, y0 + radius); + } + if (quads & 0x2 && quads & 0x4) { + setPixel(x0 - radius, y0); + } + if (quads & 0x1 && quads & 0x2) { + setPixel(x0, y0 - radius); + } } // cppcheck-suppress unusedFunction -void Bitmap::drawProgressBar(int x, int y, int width, int height, int progress) -{ - int radius = height / 2; - int xRadius = x + radius; - int yRadius = y + radius; - int doubleRadius = 2 * radius; - int innerRadius = radius - 2; +void Bitmap::drawProgressBar(int x, int y, int width, int height, int progress) { + int radius = height / 2; + int xRadius = x + radius; + int yRadius = y + radius; + int doubleRadius = 2 * radius; + int innerRadius = radius - 2; - drawCircleQuads(xRadius, yRadius, radius, 0b00000110); - drawHorizontalLine(xRadius, y, width - doubleRadius + 1); - drawHorizontalLine(xRadius, y + height, width - doubleRadius + 1); - drawCircleQuads(x + width - radius, yRadius, radius, 0b00001001); + drawCircleQuads(xRadius, yRadius, radius, 0b00000110); + drawHorizontalLine(xRadius, y, width - doubleRadius + 1); + drawHorizontalLine(xRadius, y + height, width - doubleRadius + 1); + drawCircleQuads(x + width - radius, yRadius, radius, 0b00001001); - uint16_t maxProgressWidth = (width - doubleRadius + 1) * progress / 100; + uint16_t maxProgressWidth = (width - doubleRadius + 1) * progress / 100; - fillCircle(xRadius, yRadius, innerRadius); - fillRect(xRadius + 1, y + 2, maxProgressWidth, height - 3); - fillCircle(xRadius + maxProgressWidth, yRadius, innerRadius); + fillCircle(xRadius, yRadius, innerRadius); + fillRect(xRadius + 1, y + 2, maxProgressWidth, height - 3); + fillCircle(xRadius + maxProgressWidth, yRadius, innerRadius); } // cppcheck-suppress unusedFunction -int Bitmap::drawChar(int x, int y, char c) -{ - fontDesc_t const * font = getSystemFont(); +int Bitmap::drawChar(int x, int y, char c) { + fontDesc_t const *font = getSystemFont(); - if(c == ' ') - { - return x + font->widthInPixel * 4 / 10; - } + if (c == ' ') { + return x + font->widthInPixel * 4 / 10; + } - unsigned char cu = (unsigned char)c; - if(cu < font->firstChar || cu > font->lastChar) - { - cu = '?'; - } + unsigned char cu = (unsigned char)c; + if (cu < font->firstChar || cu > font->lastChar) { + cu = '?'; + } - int firstPixelBitPos = 0; - for(int i = 0; i < (cu - font->firstChar); i++) - { - firstPixelBitPos = firstPixelBitPos + font->pData[i]; - } - firstPixelBitPos = firstPixelBitPos * font->heightInPixel; + int firstPixelBitPos = 0; + for (int i = 0; i < (cu - font->firstChar); i++) { + firstPixelBitPos = firstPixelBitPos + font->pData[i]; + } + firstPixelBitPos = firstPixelBitPos * font->heightInPixel; - unsigned char const * pDataStart = &(font->pData[font->lastChar - font->firstChar + 1]); - const int top = y; - const int widthInPixel = font->pData[cu - font->firstChar]; - for(int i = 0; i < widthInPixel * font->heightInPixel; i++ ) - { - int bytePos = firstPixelBitPos / 8; - int bitPos = firstPixelBitPos % 8; + unsigned char const *pDataStart = &(font->pData[font->lastChar - font->firstChar + 1]); + const int top = y; + const int widthInPixel = font->pData[cu - font->firstChar]; + for (int i = 0; i < widthInPixel * font->heightInPixel; i++) { + int bytePos = firstPixelBitPos / 8; + int bitPos = firstPixelBitPos % 8; - if(pDataStart[bytePos] & ( 1 << bitPos)) - { - setPixel(x, y); - } - else - { - clearPixel(x, y); - } + if (pDataStart[bytePos] & (1 << bitPos)) { + setPixel(x, y); + } else { + clearPixel(x, y); + } - firstPixelBitPos++; - y++; - if(y == top + font->heightInPixel) - { - y = top; - x++; - } - } + firstPixelBitPos++; + y++; + if (y == top + font->heightInPixel) { + y = top; + x++; + } + } - return x + FONT_CHAR_SPACING; + return x + FONT_CHAR_SPACING; } // cppcheck-suppress unusedFunction -int Bitmap::drawString(int x, int y, String text) -{ - int next_x = x; - for(int i = 0; i < text.length(); i++) - { - next_x = drawChar(next_x, y, text[i]); - } - return next_x; +int Bitmap::drawString(int x, int y, String text) { + int next_x = x; + for (int i = 0; i < text.length(); i++) { + next_x = drawChar(next_x, y, text[i]); + } + return next_x; } // cppcheck-suppress unusedFunction -void Bitmap::drawStringf(int x, int y, char * buffer, String format, ... ) -{ - va_list myargs; - va_start(myargs, format); - vsprintf(buffer, format.c_str(), myargs); - va_end(myargs); - drawString(x, y, buffer); +void Bitmap::drawStringf(int x, int y, char *buffer, String format, ...) { + va_list myargs; + va_start(myargs, format); + vsprintf(buffer, format.c_str(), myargs); + va_end(myargs); + drawString(x, y, buffer); } // cppcheck-suppress unusedFunction -int Bitmap::drawStringLF(int x, int y, String text) -{ - fontDesc_t const * font = getSystemFont(); - int next_x = x; - for(int i = 0; i < text.length(); i++) - { - if(next_x + font->widthInPixel > _width) - { - next_x = 0; - y += font->heightInPixel; - } - next_x = drawChar(next_x, y, text[i]); - } - return next_x; +int Bitmap::drawStringLF(int x, int y, String text) { + fontDesc_t const *font = getSystemFont(); + int next_x = x; + for (int i = 0; i < text.length(); i++) { + if (next_x + font->widthInPixel > _width) { + next_x = 0; + y += font->heightInPixel; + } + next_x = drawChar(next_x, y, text[i]); + } + return next_x; } // cppcheck-suppress unusedFunction -void Bitmap::drawStringLFf(int x, int y, char * buffer, String format, ... ) -{ - va_list myargs; - va_start(myargs, format); - vsprintf(buffer, format.c_str(), myargs); - va_end(myargs); - drawStringLF(x, y, buffer); +void Bitmap::drawStringLFf(int x, int y, char *buffer, String format, ...) { + va_list myargs; + va_start(myargs, format); + vsprintf(buffer, format.c_str(), myargs); + va_end(myargs); + drawStringLF(x, y, buffer); } /*void Bitmap::drawBitmap(int x, int y, const Bitmap & bitmap) { - if(_width < x + bitmap.getWidth() || _height < y + bitmap.getHeight()) - { - return; - } + if(_width < x + bitmap.getWidth() || _height < y + bitmap.getHeight()) + { + return; + } - for(int _x = 0; _x < bitmap.getWidth(); _x++) - { - for(int _y = 0; _y < bitmap.getHeight(); _y++) - { - if(bitmap.getPixel(_x, _y)) - { - // _buffer[x + (y / 8) * _width] |= (1 << (y % 8)); - // return _buffer[x + (y / 8) * _width] & (1 << (y % 8)); - Serial.print(_x); - Serial.print(" "); - Serial.println(_y); - setPixel(x + _x, y + _y); - } - else - { - clearPixel(x + _x, y + _y); - } - } - } + for(int _x = 0; _x < bitmap.getWidth(); _x++) + { + for(int _y = 0; _y < bitmap.getHeight(); _y++) + { + if(bitmap.getPixel(_x, _y)) + { + // _buffer[x + (y / 8) * _width] |= (1 << (y % 8)); + // return _buffer[x + (y / 8) * _width] & (1 << (y % 8)); + Serial.print(_x); + Serial.print(" "); + Serial.println(_y); + setPixel(x + _x, y + _y); + } + else + { + clearPixel(x + _x, y + _y); + } + } + } }*/ // cppcheck-suppress unusedFunction -void Bitmap::allocateBuffer() -{ - _buffer = new uint8_t[_width * _height / 8]; - clear(); +void Bitmap::allocateBuffer() { + _buffer = new uint8_t[_width * _height / 8]; + clear(); } diff --git a/lib/Display/Bitmap.h b/lib/Display/Bitmap.h index fe9f0d5..4feb053 100644 --- a/lib/Display/Bitmap.h +++ b/lib/Display/Bitmap.h @@ -6,51 +6,50 @@ class OLEDDisplay; -class Bitmap -{ +class Bitmap { public: - explicit Bitmap(uint width, uint height); - explicit Bitmap(OLEDDisplay * display); - virtual ~Bitmap(); + explicit Bitmap(uint width, uint height); + explicit Bitmap(OLEDDisplay *display); + virtual ~Bitmap(); - uint getWidth() const; - uint getHeight() const; + uint getWidth() const; + uint getHeight() const; - void setPixel(int x, int y); - void clearPixel(int x, int y); - bool getPixel(int x, int y) const; - void clear(); + void setPixel(int x, int y); + void clearPixel(int x, int y); + bool getPixel(int x, int y) const; + void clear(); - void drawLine(int x0, int y0, int x1, int y1); - void drawHorizontalLine(int x, int y, int length); - void drawVerticalLine(int x, int y, int length); + void drawLine(int x0, int y0, int x1, int y1); + void drawHorizontalLine(int x, int y, int length); + void drawVerticalLine(int x, int y, int length); - void drawRect(int x, int y, int width, int height); - void fillRect(int x, int y, int width, int height); + void drawRect(int x, int y, int width, int height); + void fillRect(int x, int y, int width, int height); - void drawCircle(int x0, int y0, int radius); - void fillCircle(int x0, int y0, int radius); - void drawCircleQuads(int x0, int y0, int radius, int quads); + void drawCircle(int x0, int y0, int radius); + void fillCircle(int x0, int y0, int radius); + void drawCircleQuads(int x0, int y0, int radius, int quads); - void drawProgressBar(int x, int y, int width, int height, int progress); + void drawProgressBar(int x, int y, int width, int height, int progress); - int drawChar(int x, int y, char c); - int drawString(int x, int y, String text); - void drawStringf(int x, int y, char * buffer, String format, ... ); - int drawStringLF(int x, int y, String text); - void drawStringLFf(int x, int y, char * buffer, String format, ... ); + int drawChar(int x, int y, char c); + int drawString(int x, int y, String text); + void drawStringf(int x, int y, char *buffer, String format, ...); + int drawStringLF(int x, int y, String text); + void drawStringLFf(int x, int y, char *buffer, String format, ...); - //void drawBitmap(int x, int y, const Bitmap & bitmap); + // void drawBitmap(int x, int y, const Bitmap & bitmap); private: - const uint _width; - const uint _height; + const uint _width; + const uint _height; - uint8_t * _buffer; + uint8_t *_buffer; - void allocateBuffer(); + void allocateBuffer(); - friend class SSD1306; + friend class SSD1306; }; #endif diff --git a/lib/Display/Display.cpp b/lib/Display/Display.cpp index b39e285..d4f1799 100644 --- a/lib/Display/Display.cpp +++ b/lib/Display/Display.cpp @@ -1,116 +1,97 @@ -#include #include "Display.h" #include +#include -Display::Display() - : _disp(0), _statusFrame(0), _displayOff(false) -{ +Display::Display() : _disp(0), _statusFrame(0), _displayOff(false) { } -void Display::setup(std::shared_ptr boardConfig) -{ - if(boardConfig->OledReset != 0) - { - pinMode(boardConfig->OledReset, OUTPUT); - digitalWrite(boardConfig->OledReset, HIGH); - delay(1); - digitalWrite(boardConfig->OledReset, LOW); - delay(10); - digitalWrite(boardConfig->OledReset, HIGH); - } - Wire.begin(boardConfig->OledSda, boardConfig->OledScl); - _disp = std::shared_ptr(new SSD1306(&Wire, boardConfig->OledAddr)); - - Bitmap bitmap(_disp->getWidth(), _disp->getHeight()); - _disp->display(&bitmap); - _displayTimeout.setTimeout(10); - _frameTimeout.setTimeout(15); +void Display::setup(std::shared_ptr boardConfig) { + if (boardConfig->OledReset != 0) { + pinMode(boardConfig->OledReset, OUTPUT); + digitalWrite(boardConfig->OledReset, HIGH); + delay(1); + digitalWrite(boardConfig->OledReset, LOW); + delay(10); + digitalWrite(boardConfig->OledReset, HIGH); + } + Wire.begin(boardConfig->OledSda, boardConfig->OledScl); + _disp = std::shared_ptr(new SSD1306(&Wire, boardConfig->OledAddr)); + + Bitmap bitmap(_disp->getWidth(), _disp->getHeight()); + _disp->display(&bitmap); + _displayTimeout.setTimeout(10); + _frameTimeout.setTimeout(15); } -void Display::turn180() -{ - _disp->flipScreenVertically(); +void Display::turn180() { + _disp->flipScreenVertically(); } -void Display::update() -{ - if(_frameTimeout.check()) - { - if(_statusFrame->isPrio()) - { - Bitmap bitmap(_disp.get()); - _statusFrame->drawStatusPage(bitmap); - activateDisplay(); - _disp->display(&bitmap); - return; - } +void Display::update() { + if (_frameTimeout.check()) { + if (_statusFrame->isPrio()) { + Bitmap bitmap(_disp.get()); + _statusFrame->drawStatusPage(bitmap); + activateDisplay(); + _disp->display(&bitmap); + return; + } - if(_frames.size() > 0) - { - std::shared_ptr frame = *_frames.begin(); - Bitmap bitmap(_disp.get()); - frame->drawStatusPage(bitmap); - activateDisplay(); - _disp->display(&bitmap); - _frames.pop_front(); - _frameTimeout.start(); - return; - } + if (_frames.size() > 0) { + std::shared_ptr frame = *_frames.begin(); + Bitmap bitmap(_disp.get()); + frame->drawStatusPage(bitmap); + activateDisplay(); + _disp->display(&bitmap); + _frames.pop_front(); + _frameTimeout.start(); + return; + } - if(!_displayOff && !_displayTimeout.isActive()) - { - Bitmap bitmap(_disp.get()); - _statusFrame->drawStatusPage(bitmap); - activateDisplay(); - _disp->display(&bitmap); - _displayTimeout.start(); - } - if(_displayTimeout.check()) - { - deactivateDisplay(); - _displayTimeout.reset(); - } - } + if (!_displayOff && !_displayTimeout.isActive()) { + Bitmap bitmap(_disp.get()); + _statusFrame->drawStatusPage(bitmap); + activateDisplay(); + _disp->display(&bitmap); + _displayTimeout.start(); + } + if (_displayTimeout.check()) { + deactivateDisplay(); + _displayTimeout.reset(); + } + } } -void Display::addFrame(std::shared_ptr frame) -{ - _frames.push_back(frame); +void Display::addFrame(std::shared_ptr frame) { + _frames.push_back(frame); } -void Display::setStatusFrame(std::shared_ptr frame) -{ - _statusFrame = frame; +void Display::setStatusFrame(std::shared_ptr frame) { + _statusFrame = frame; } -void Display::showSpashScreen(String firmwareTitle, String version) -{ - Bitmap bitmap(_disp.get()); - bitmap.drawString( 0, 10, firmwareTitle); - bitmap.drawString( 0, 20, version); - bitmap.drawString( 0, 35, "by Peter Buchegger"); - bitmap.drawString(30, 45, "OE5BPA"); - _disp->display(&bitmap); +void Display::showSpashScreen(String firmwareTitle, String version) { + Bitmap bitmap(_disp.get()); + bitmap.drawString(0, 10, firmwareTitle); + bitmap.drawString(0, 20, version); + bitmap.drawString(0, 35, "by Peter Buchegger"); + bitmap.drawString(30, 45, "OE5BPA"); + _disp->display(&bitmap); } -void Display::activateDisplay() -{ - if(_displayOff) - { - _disp->displayOn(); - _displayOff = false; - } +void Display::activateDisplay() { + if (_displayOff) { + _disp->displayOn(); + _displayOff = false; + } } -void Display::deactivateDisplay() -{ - _disp->displayOff(); - _displayOff = true; +void Display::deactivateDisplay() { + _disp->displayOff(); + _displayOff = true; } - -void TextFrame::drawStatusPage(Bitmap & bitmap) -{ - bitmap.drawString(0, 0, _header); - bitmap.drawStringLF(0, 10, _text); +void TextFrame::drawStatusPage(Bitmap &bitmap) { + bitmap.drawString(0, 0, _header); + bitmap.drawStringLF(0, 10, _text); } diff --git a/lib/Display/Display.h b/lib/Display/Display.h index 438c221..5fd57dd 100644 --- a/lib/Display/Display.h +++ b/lib/Display/Display.h @@ -1,76 +1,77 @@ #ifndef DISPLAY_H_ #define DISPLAY_H_ -#include -#include -#include #include -#include -#include -#include #include +#include +#include #include +#include +#include +#include +#include class Timer; class StatusFrame; -class DisplayFrame -{ +class DisplayFrame { public: - DisplayFrame() {} - virtual ~DisplayFrame() {} - virtual void drawStatusPage(Bitmap & bitmap) = 0; + DisplayFrame() { + } + virtual ~DisplayFrame() { + } + virtual void drawStatusPage(Bitmap &bitmap) = 0; }; -class Display -{ +class Display { public: - static Display & instance() - { - static Display _instance; - return _instance; - } + static Display &instance() { + static Display _instance; + return _instance; + } - ~Display() {} + ~Display() { + } - void setup(std::shared_ptr boardConfig); - void turn180(); - void update(); + void setup(std::shared_ptr boardConfig); + void turn180(); + void update(); - void addFrame(std::shared_ptr frame); + void addFrame(std::shared_ptr frame); - void setStatusFrame(std::shared_ptr frame); + void setStatusFrame(std::shared_ptr frame); - void showSpashScreen(String firmwareTitle, String version); + void showSpashScreen(String firmwareTitle, String version); private: - std::shared_ptr _disp; + std::shared_ptr _disp; - std::list> _frames; - std::shared_ptr _statusFrame; - Timer _frameTimeout; + std::list> _frames; + std::shared_ptr _statusFrame; + Timer _frameTimeout; - Timer _displayTimeout; - bool _displayOff; + Timer _displayTimeout; + bool _displayOff; - Display(); - Display(const Display &); - Display & operator = (const Display &); + Display(); + Display(const Display &); + Display &operator=(const Display &); - void activateDisplay(); - void deactivateDisplay(); + void activateDisplay(); + void deactivateDisplay(); }; -class TextFrame : public DisplayFrame -{ +class TextFrame : public DisplayFrame { public: - TextFrame(String header, String text) : _header(header), _text(text) {} - virtual ~TextFrame() {} - void drawStatusPage(Bitmap & bitmap) override; + TextFrame(String header, String text) : _header(header), _text(text) { + } + virtual ~TextFrame() { + } + void drawStatusPage(Bitmap &bitmap) override; private: - String _header; - String _text; + String _header; + String _text; }; #endif diff --git a/lib/LoRa_APRS/LoRa_APRS.cpp b/lib/LoRa_APRS/LoRa_APRS.cpp index 2deb45f..d3279b2 100644 --- a/lib/LoRa_APRS/LoRa_APRS.cpp +++ b/lib/LoRa_APRS/LoRa_APRS.cpp @@ -1,81 +1,67 @@ -#include #include "LoRa_APRS.h" -LoRa_APRS::LoRa_APRS(std::shared_ptr boardConfig) - : _LastReceivedMsg(0), _RxFrequency(LORA_RX_FREQUENCY), _TxFrequency(LORA_TX_FREQUENCY) -{ - SPI.begin(boardConfig->LoraSck, boardConfig->LoraMiso, boardConfig->LoraMosi, boardConfig->LoraCS); - setPins(boardConfig->LoraCS, boardConfig->LoraReset, boardConfig->LoraIRQ); +LoRa_APRS::LoRa_APRS(std::shared_ptr boardConfig) : _LastReceivedMsg(0), _RxFrequency(LORA_RX_FREQUENCY), _TxFrequency(LORA_TX_FREQUENCY) { + SPI.begin(boardConfig->LoraSck, boardConfig->LoraMiso, boardConfig->LoraMosi, boardConfig->LoraCS); + setPins(boardConfig->LoraCS, boardConfig->LoraReset, boardConfig->LoraIRQ); } -bool LoRa_APRS::checkMessage() -{ - if(!parsePacket()) - { - return false; - } - // read header: - char dummy[4]; - readBytes(dummy, 3); - if(dummy[0] != '<') - { - // is no APRS message, ignore message - while(available()) - { - read(); - } - return false; - } - // read APRS data: - String str; - while(available()) - { - str += (char)read(); - } - _LastReceivedMsg = std::shared_ptr(new APRSMessage()); - _LastReceivedMsg->decode(str); - return true; +bool LoRa_APRS::checkMessage() { + if (!parsePacket()) { + return false; + } + // read header: + char dummy[4]; + readBytes(dummy, 3); + if (dummy[0] != '<') { + // is no APRS message, ignore message + while (available()) { + read(); + } + return false; + } + // read APRS data: + String str; + while (available()) { + str += (char)read(); + } + _LastReceivedMsg = std::shared_ptr(new APRSMessage()); + _LastReceivedMsg->decode(str); + return true; } -std::shared_ptr LoRa_APRS::getMessage() -{ - return _LastReceivedMsg; +std::shared_ptr LoRa_APRS::getMessage() { + return _LastReceivedMsg; } // cppcheck-suppress unusedFunction -void LoRa_APRS::sendMessage(const std::shared_ptr msg) -{ - setFrequency(_TxFrequency); - String data = msg->encode(); - beginPacket(); - // Header: - write('<'); - write(0xFF); - write(0x01); - // APRS Data: - write((const uint8_t *)data.c_str(), data.length()); - endPacket(); - setFrequency(_RxFrequency); +void LoRa_APRS::sendMessage(const std::shared_ptr msg) { + setFrequency(_TxFrequency); + String data = msg->encode(); + beginPacket(); + // Header: + write('<'); + write(0xFF); + write(0x01); + // APRS Data: + write((const uint8_t *)data.c_str(), data.length()); + endPacket(); + setFrequency(_RxFrequency); } -void LoRa_APRS::setRxFrequency(long frequency) -{ - _RxFrequency = frequency; - setFrequency(_RxFrequency); +void LoRa_APRS::setRxFrequency(long frequency) { + _RxFrequency = frequency; + setFrequency(_RxFrequency); } -long LoRa_APRS::getRxFrequency() const -{ - return _RxFrequency; +long LoRa_APRS::getRxFrequency() const { + return _RxFrequency; } -void LoRa_APRS::setTxFrequency(long frequency) -{ - _TxFrequency = frequency; +void LoRa_APRS::setTxFrequency(long frequency) { + _TxFrequency = frequency; } // cppcheck-suppress unusedFunction -long LoRa_APRS::getTxFrequency() const -{ - return _TxFrequency; +long LoRa_APRS::getTxFrequency() const { + return _TxFrequency; } diff --git a/lib/LoRa_APRS/LoRa_APRS.h b/lib/LoRa_APRS/LoRa_APRS.h index 1991528..1c29b41 100644 --- a/lib/LoRa_APRS/LoRa_APRS.h +++ b/lib/LoRa_APRS/LoRa_APRS.h @@ -1,37 +1,38 @@ #ifndef LORA_H_ #define LORA_H_ -#include #include -#include -#include -#define LORA_RX_FREQUENCY (433775000) -#define LORA_TX_FREQUENCY (433900000) +#include +#include +#include +#include + +#define LORA_RX_FREQUENCY (433775000) +#define LORA_TX_FREQUENCY (433900000) #define LORA_SPREADING_FACTOR (12) #define LORA_SIGNAL_BANDWIDTH (125E3) -#define LORA_CODING_RATE4 (5) +#define LORA_CODING_RATE4 (5) -class LoRa_APRS : public LoRaClass -{ +class LoRa_APRS : public LoRaClass { public: - explicit LoRa_APRS(std::shared_ptr boardConfig); - - bool checkMessage(); - std::shared_ptr getMessage(); + explicit LoRa_APRS(std::shared_ptr boardConfig); - void sendMessage(const std::shared_ptr msg); + bool checkMessage(); + std::shared_ptr getMessage(); - void setRxFrequency(long frequency); - long getRxFrequency() const; + void sendMessage(const std::shared_ptr msg); - void setTxFrequency(long frequency); - long getTxFrequency() const; + void setRxFrequency(long frequency); + long getRxFrequency() const; + + void setTxFrequency(long frequency); + long getTxFrequency() const; private: - std::shared_ptr _LastReceivedMsg; - long _RxFrequency; - long _TxFrequency; + std::shared_ptr _LastReceivedMsg; + long _RxFrequency; + long _TxFrequency; }; #endif diff --git a/lib/PowerManagement/power_management.cpp b/lib/PowerManagement/power_management.cpp index 8f017b6..06771a3 100644 --- a/lib/PowerManagement/power_management.cpp +++ b/lib/PowerManagement/power_management.cpp @@ -2,54 +2,44 @@ #include "power_management.h" // cppcheck-suppress uninitMemberVar -PowerManagement::PowerManagement() -{ +PowerManagement::PowerManagement() { } // cppcheck-suppress unusedFunction -bool PowerManagement::begin(TwoWire & port) -{ - bool result = axp.begin(port, AXP192_SLAVE_ADDRESS); - if(!result) - { - axp.setDCDC1Voltage(3300); - } - return result; +bool PowerManagement::begin(TwoWire &port) { + bool result = axp.begin(port, AXP192_SLAVE_ADDRESS); + if (!result) { + axp.setDCDC1Voltage(3300); + } + return result; } // cppcheck-suppress unusedFunction -void PowerManagement::activateLoRa() -{ - axp.setPowerOutPut(AXP192_LDO2, AXP202_ON); +void PowerManagement::activateLoRa() { + axp.setPowerOutPut(AXP192_LDO2, AXP202_ON); } // cppcheck-suppress unusedFunction -void PowerManagement::deactivateLoRa() -{ - axp.setPowerOutPut(AXP192_LDO2, AXP202_OFF); +void PowerManagement::deactivateLoRa() { + axp.setPowerOutPut(AXP192_LDO2, AXP202_OFF); } // cppcheck-suppress unusedFunction -void PowerManagement::activateGPS() -{ - axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); +void PowerManagement::activateGPS() { + axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); } // cppcheck-suppress unusedFunction -void PowerManagement::deactivateGPS() -{ - axp.setPowerOutPut(AXP192_LDO3, AXP202_OFF); +void PowerManagement::deactivateGPS() { + axp.setPowerOutPut(AXP192_LDO3, AXP202_OFF); } // cppcheck-suppress unusedFunction -void PowerManagement::activateOLED() -{ - axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON); +void PowerManagement::activateOLED() { + axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON); } // cppcheck-suppress unusedFunction -void PowerManagement::decativateOLED() -{ - axp.setPowerOutPut(AXP192_DCDC1, AXP202_OFF); +void PowerManagement::decativateOLED() { + axp.setPowerOutPut(AXP192_DCDC1, AXP202_OFF); } - diff --git a/lib/PowerManagement/power_management.h b/lib/PowerManagement/power_management.h index ecd6cf6..4cc110b 100644 --- a/lib/PowerManagement/power_management.h +++ b/lib/PowerManagement/power_management.h @@ -4,23 +4,22 @@ #include #include -class PowerManagement -{ +class PowerManagement { public: - PowerManagement(); - bool begin(TwoWire & port); + PowerManagement(); + bool begin(TwoWire &port); - void activateLoRa(); - void deactivateLoRa(); + void activateLoRa(); + void deactivateLoRa(); - void activateGPS(); - void deactivateGPS(); + void activateGPS(); + void deactivateGPS(); - void activateOLED(); - void decativateOLED(); + void activateOLED(); + void decativateOLED(); private: - AXP20X_Class axp; + AXP20X_Class axp; }; #endif diff --git a/lib/TaskManager/TaskManager.cpp b/lib/TaskManager/TaskManager.cpp index d660403..5a338e8 100644 --- a/lib/TaskManager/TaskManager.cpp +++ b/lib/TaskManager/TaskManager.cpp @@ -1,97 +1,77 @@ -#include #include "TaskManager.h" #include +#include -TaskManager::TaskManager() -{ +TaskManager::TaskManager() { } -void TaskManager::addTask(std::shared_ptr task) -{ - _tasks.push_back(task); +void TaskManager::addTask(std::shared_ptr task) { + _tasks.push_back(task); } -std::shared_ptr TaskManager::getTask(const char * name) -{ - std::_List_iterator> elem = std::find_if(_tasks.begin(), _tasks.end(), [&](std::shared_ptr task) - { - return task->getName() == name; - }); - if(elem == _tasks.end()) - { - return 0; - } - return *elem; +std::shared_ptr TaskManager::getTask(const char *name) { + std::_List_iterator> elem = std::find_if(_tasks.begin(), _tasks.end(), [&](std::shared_ptr task) { + return task->getName() == name; + }); + if (elem == _tasks.end()) { + return 0; + } + return *elem; } -std::list> TaskManager::getTasks() -{ - return _tasks; +std::list> TaskManager::getTasks() { + return _tasks; } -bool TaskManager::setup(std::shared_ptr config, std::shared_ptr boardConfig) -{ - logPrintlnV("will setup all tasks..."); - for(std::shared_ptr & elem : _tasks) - { - logPrintW("call setup from "); - logPrintlnW(elem->getName()); - if(!elem->setup(config, boardConfig)) - { - return false; - } - } - return true; +bool TaskManager::setup(std::shared_ptr config, std::shared_ptr boardConfig) { + logPrintlnV("will setup all tasks..."); + for (std::shared_ptr &elem : _tasks) { + logPrintW("call setup from "); + logPrintlnW(elem->getName()); + if (!elem->setup(config, boardConfig)) { + return false; + } + } + return true; } -bool TaskManager::loop(std::shared_ptr config) -{ - //logPrintlnD("will loop all tasks..."); - for(std::shared_ptr & elem : _tasks) - { - //logPrintD("call loop from "); - //logPrintlnD(elem->getName()); - if(!elem->loop(config)) - { - return false; - } - } - return true; +bool TaskManager::loop(std::shared_ptr config) { + // logPrintlnD("will loop all tasks..."); + for (std::shared_ptr &elem : _tasks) { + // logPrintD("call loop from "); + // logPrintlnD(elem->getName()); + if (!elem->loop(config)) { + return false; + } + } + return true; } -void StatusFrame::drawStatusPage(Bitmap & bitmap) -{ - int y = 0; - for(std::shared_ptr task : _tasks) - { - int x = bitmap.drawString(0, y, (task->getName()).substring(0, task->getName().indexOf("Task"))); - x = bitmap.drawString(x, y, ": "); - if(task->getStateInfo() == "") - { - switch (task->getState()) - { - case Error: - bitmap.drawString(x, y, "Error"); - break; - case Warning: - bitmap.drawString(x, y, "Warning"); - default: - break; - } - bitmap.drawString(x, y, "Okay"); - } - else - { - bitmap.drawString(x, y, task->getStateInfo()); - } - y += getSystemFont()->heightInPixel; - } +void StatusFrame::drawStatusPage(Bitmap &bitmap) { + int y = 0; + for (std::shared_ptr task : _tasks) { + int x = bitmap.drawString(0, y, (task->getName()).substring(0, task->getName().indexOf("Task"))); + x = bitmap.drawString(x, y, ": "); + if (task->getStateInfo() == "") { + switch (task->getState()) { + case Error: + bitmap.drawString(x, y, "Error"); + break; + case Warning: + bitmap.drawString(x, y, "Warning"); + default: + break; + } + bitmap.drawString(x, y, "Okay"); + } else { + bitmap.drawString(x, y, task->getStateInfo()); + } + y += getSystemFont()->heightInPixel; + } } -bool StatusFrame::isPrio() const -{ - return std::any_of(_tasks.begin(), _tasks.end(), [](std::shared_ptr task) - { - return task->getState() != Okay; - }); +bool StatusFrame::isPrio() const { + return std::any_of(_tasks.begin(), _tasks.end(), [](std::shared_ptr task) { + return task->getState() != Okay; + }); } diff --git a/lib/TaskManager/TaskManager.h b/lib/TaskManager/TaskManager.h index aa5ccd4..0495b69 100644 --- a/lib/TaskManager/TaskManager.h +++ b/lib/TaskManager/TaskManager.h @@ -1,84 +1,94 @@ #ifndef TASK_MANAGER_H_ #define TASK_MANAGER_H_ -#include -#include #include -#include #include #include +#include +#include +#include #include "TaskQueue.h" enum TaskDisplayState { - Error, - Warning, - Okay, + Error, + Warning, + Okay, }; -class Task -{ +class Task { public: - Task(String & name, int taskId) : _state(Okay), _stateInfo("Booting"), _name(name), _taskId(taskId) {} - Task(const char * name, int taskId) : _state(Okay), _stateInfo("Booting"), _name(name), _taskId(taskId) {} - virtual ~Task() {} + Task(String &name, int taskId) : _state(Okay), _stateInfo("Booting"), _name(name), _taskId(taskId) { + } + Task(const char *name, int taskId) : _state(Okay), _stateInfo("Booting"), _name(name), _taskId(taskId) { + } + virtual ~Task() { + } - String getName() const { return _name; } - int getTaskId() const { return _taskId; } + String getName() const { + return _name; + } + int getTaskId() const { + return _taskId; + } - TaskDisplayState getState() const { return _state; } - String getStateInfo() const { return _stateInfo; } + TaskDisplayState getState() const { + return _state; + } + String getStateInfo() const { + return _stateInfo; + } - virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) = 0; - virtual bool loop(std::shared_ptr config) = 0; + virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) = 0; + virtual bool loop(std::shared_ptr config) = 0; protected: - TaskDisplayState _state; - String _stateInfo; + TaskDisplayState _state; + String _stateInfo; private: - String _name; - int _taskId; + String _name; + int _taskId; }; -class TaskManager -{ +class TaskManager { public: - static TaskManager & instance() - { - static TaskManager _instance; - return _instance; - } + static TaskManager &instance() { + static TaskManager _instance; + return _instance; + } - ~TaskManager() {} + ~TaskManager() { + } - void addTask(std::shared_ptr task); - std::shared_ptr getTask(const char * name); - std::list> getTasks(); + void addTask(std::shared_ptr task); + std::shared_ptr getTask(const char *name); + std::list> getTasks(); - bool setup(std::shared_ptr config, std::shared_ptr boardConfig); - bool loop(std::shared_ptr config); + bool setup(std::shared_ptr config, std::shared_ptr boardConfig); + bool loop(std::shared_ptr config); private: - std::list> _tasks; + std::list> _tasks; - TaskManager(); - TaskManager(const TaskManager &); - TaskManager & operator = (const TaskManager &); + TaskManager(); + TaskManager(const TaskManager &); + TaskManager &operator=(const TaskManager &); }; -class StatusFrame : public DisplayFrame -{ +class StatusFrame : public DisplayFrame { public: - explicit StatusFrame(const std::list> & tasks) : _tasks(tasks) {} - virtual ~StatusFrame() {} - void drawStatusPage(Bitmap & bitmap) override; + explicit StatusFrame(const std::list> &tasks) : _tasks(tasks) { + } + virtual ~StatusFrame() { + } + void drawStatusPage(Bitmap &bitmap) override; - bool isPrio() const; + bool isPrio() const; private: - std::list> _tasks; + std::list> _tasks; }; #endif diff --git a/lib/TaskManager/TaskQueue.h b/lib/TaskManager/TaskQueue.h index 258e0de..7553281 100644 --- a/lib/TaskManager/TaskQueue.h +++ b/lib/TaskManager/TaskQueue.h @@ -3,31 +3,27 @@ #include -template -class TaskQueue -{ +template class TaskQueue { public: - TaskQueue() {} + TaskQueue() { + } - void addElement(T elem) - { - _elements.push_back(elem); - } + void addElement(T elem) { + _elements.push_back(elem); + } - T getElement() - { - T elem = _elements.front(); - _elements.pop_front(); - return elem; - } + T getElement() { + T elem = _elements.front(); + _elements.pop_front(); + return elem; + } - bool empty() const - { - return _elements.empty(); - } + bool empty() const { + return _elements.empty(); + } private: - std::list _elements; + std::list _elements; }; #endif diff --git a/lib/TaskManager/Timer.cpp b/lib/TaskManager/Timer.cpp index c89a105..b57d673 100644 --- a/lib/TaskManager/Timer.cpp +++ b/lib/TaskManager/Timer.cpp @@ -1,36 +1,28 @@ #include "Timer.h" -Timer::Timer() - : _timeout_sec(0), _timeout(0) -{ +Timer::Timer() : _timeout_sec(0), _timeout(0) { } -void Timer::setTimeout(const time_t timeout_sec) -{ - _timeout_sec = timeout_sec; +void Timer::setTimeout(const time_t timeout_sec) { + _timeout_sec = timeout_sec; } -time_t Timer::getTriggerTime() const -{ - return _timeout; +time_t Timer::getTriggerTime() const { + return _timeout; } -bool Timer::isActive() const -{ - return _timeout != 0; +bool Timer::isActive() const { + return _timeout != 0; } -void Timer::reset() -{ - _timeout = 0; +void Timer::reset() { + _timeout = 0; } -bool Timer::check() -{ - return now() > _timeout; +bool Timer::check() { + return now() > _timeout; } -void Timer::start() -{ - _timeout = now() + _timeout_sec; +void Timer::start() { + _timeout = now() + _timeout_sec; } diff --git a/lib/TaskManager/Timer.h b/lib/TaskManager/Timer.h index 60f78e7..77fe158 100644 --- a/lib/TaskManager/Timer.h +++ b/lib/TaskManager/Timer.h @@ -3,24 +3,23 @@ #include -class Timer -{ +class Timer { public: - Timer(); + Timer(); - void setTimeout(const time_t timeout_sec); - time_t getTriggerTime() const; + void setTimeout(const time_t timeout_sec); + time_t getTriggerTime() const; - bool isActive() const; + bool isActive() const; - void reset(); + void reset(); - bool check(); - void start(); + bool check(); + void start(); private: - time_t _timeout_sec; - time_t _timeout; + time_t _timeout_sec; + time_t _timeout; }; #endif diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index faf1db5..e57691b 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -1,15 +1,11 @@ #include -#include #include -#include - +#include #include - -#include "BoardFinder.h" -//#include "display.h" -#include "power_management.h" -#include "project_configuration.h" +#include +#include +#include #include "TaskAprsIs.h" #include "TaskDisplay.h" @@ -19,6 +15,7 @@ #include "TaskNTP.h" #include "TaskOTA.h" #include "TaskWifi.h" +#include "project_configuration.h" #define VERSION "21.06.0-dev" @@ -26,129 +23,116 @@ String create_lat_aprs(double lat); String create_long_aprs(double lng); std::shared_ptr userConfig; -std::shared_ptr boardConfig; -HardwareSerial Serial(0); +std::shared_ptr boardConfig; +HardwareSerial Serial(0); // cppcheck-suppress unusedFunction -void setup() -{ - Serial.begin(115200); - Logger::instance().setSerial(&Serial); - delay(500); - logPrintlnW("LoRa APRS iGate by OE5BPA (Peter Buchegger)"); - logPrintlnW("Version: " VERSION); +void setup() { + Serial.begin(115200); + Logger::instance().setSerial(&Serial); + delay(500); + logPrintlnW("LoRa APRS iGate by OE5BPA (Peter Buchegger)"); + logPrintlnW("Version: " VERSION); - ProjectConfigurationManagement confmg; - userConfig = confmg.readConfiguration(); + ProjectConfigurationManagement confmg; + userConfig = confmg.readConfiguration(); - std::list> boardConfigs; - boardConfigs.push_back(std::shared_ptr(new BoardConfig("TTGO_LORA32_V1", eTTGO_LORA32_V1, 4, 15, 0x3C, 0, 5, 19, 27, 18, 14, 26))); - boardConfigs.push_back(std::shared_ptr(new BoardConfig("TTGO_LORA32_V2", eTTGO_LORA32_V2, 21, 22, 0x3C, 0, 5, 19, 27, 18, 14, 26, true))); - boardConfigs.push_back(std::shared_ptr(new BoardConfig("TTGO_T_Beam_V0_7", eTTGO_T_Beam_V0_7, 21, 22, 0x3C, 0, 5, 19, 27, 18, 14, 26, true))); - boardConfigs.push_back(std::shared_ptr(new BoardConfig("TTGO_T_Beam_V1_0", eTTGO_T_Beam_V1_0, 21, 22, 0x3C, 0, 5, 19, 27, 18, 14, 26, true, true))); - boardConfigs.push_back(std::shared_ptr(new BoardConfig("ETH_BOARD", eETH_BOARD, 33, 32, 0x3C, 0, 14, 2, 15, 12, 4, 36))); - boardConfigs.push_back(std::shared_ptr(new BoardConfig("TRACKERD", eTRACKERD, 5, 4, 0x3C, 0, 18, 19, 23, 16, 14, 26))); - boardConfigs.push_back(std::shared_ptr(new BoardConfig("HELTEC_WIFI_LORA_32_V1", eHELTEC_WIFI_LORA_32_V1, 4, 15, 0x3C, 16, 5, 19, 27, 18, 14, 26))); - boardConfigs.push_back(std::shared_ptr(new BoardConfig("HELTEC_WIFI_LORA_32_V2", eHELTEC_WIFI_LORA_32_V2, 4, 15, 0x3C, 16, 5, 19, 27, 18, 14, 26))); + std::list> boardConfigs; + // clang-format off + boardConfigs.push_back(std::shared_ptr(new BoardConfig("TTGO_LORA32_V1", eTTGO_LORA32_V1, 4, 15, 0x3C, 0, 5, 19, 27, 18, 14, 26))); + boardConfigs.push_back(std::shared_ptr(new BoardConfig("TTGO_LORA32_V2", eTTGO_LORA32_V2, 21, 22, 0x3C, 0, 5, 19, 27, 18, 14, 26, true))); + boardConfigs.push_back(std::shared_ptr(new BoardConfig("TTGO_T_Beam_V0_7", eTTGO_T_Beam_V0_7, 21, 22, 0x3C, 0, 5, 19, 27, 18, 14, 26, true))); + boardConfigs.push_back(std::shared_ptr(new BoardConfig("TTGO_T_Beam_V1_0", eTTGO_T_Beam_V1_0, 21, 22, 0x3C, 0, 5, 19, 27, 18, 14, 26, true, true))); + boardConfigs.push_back(std::shared_ptr(new BoardConfig("ETH_BOARD", eETH_BOARD, 33, 32, 0x3C, 0, 14, 2, 15, 12, 4, 36))); + boardConfigs.push_back(std::shared_ptr(new BoardConfig("TRACKERD", eTRACKERD, 5, 4, 0x3C, 0, 18, 19, 23, 16, 14, 26))); + boardConfigs.push_back(std::shared_ptr(new BoardConfig("HELTEC_WIFI_LORA_32_V1", eHELTEC_WIFI_LORA_32_V1, 4, 15, 0x3C, 16, 5, 19, 27, 18, 14, 26))); + boardConfigs.push_back(std::shared_ptr(new BoardConfig("HELTEC_WIFI_LORA_32_V2", eHELTEC_WIFI_LORA_32_V2, 4, 15, 0x3C, 16, 5, 19, 27, 18, 14, 26))); + // clang-format on - BoardFinder finder(boardConfigs); - boardConfig = finder.getBoardConfig(userConfig->board); - if(boardConfig == 0) - { - boardConfig = finder.searchBoardConfig(); - if(boardConfig == 0) - { - logPrintlnE("Board config not set and search failed!"); - while(true) - {} - } - userConfig->board = boardConfig->Name; - confmg.writeConfiguration(userConfig); - logPrintlnI("will restart board now!"); - ESP.restart(); - } - logPrintI("Board "); - logPrintI(boardConfig->Name); - logPrintlnI(" loaded."); + BoardFinder finder(boardConfigs); + boardConfig = finder.getBoardConfig(userConfig->board); + if (boardConfig == 0) { + boardConfig = finder.searchBoardConfig(); + if (boardConfig == 0) { + logPrintlnE("Board config not set and search failed!"); + while (true) { + } + } + userConfig->board = boardConfig->Name; + confmg.writeConfiguration(userConfig); + logPrintlnI("will restart board now!"); + ESP.restart(); + } + logPrintI("Board "); + logPrintI(boardConfig->Name); + logPrintlnI(" loaded."); - if(boardConfig->Type == eTTGO_T_Beam_V1_0) - { - Wire.begin(boardConfig->OledSda, boardConfig->OledScl); - std::shared_ptr powerManagement = std::shared_ptr(new PowerManagement); - if (!powerManagement->begin(Wire)) - { - logPrintlnI("AXP192 init done!"); - } - else - { - logPrintlnE("AXP192 init failed!"); - } - powerManagement->activateLoRa(); - powerManagement->activateOLED(); - powerManagement->deactivateGPS(); - } + if (boardConfig->Type == eTTGO_T_Beam_V1_0) { + Wire.begin(boardConfig->OledSda, boardConfig->OledScl); + std::shared_ptr powerManagement = std::shared_ptr(new PowerManagement); + if (!powerManagement->begin(Wire)) { + logPrintlnI("AXP192 init done!"); + } else { + logPrintlnE("AXP192 init failed!"); + } + powerManagement->activateLoRa(); + powerManagement->activateOLED(); + powerManagement->deactivateGPS(); + } - load_config(boardConfig); + load_config(boardConfig); - TaskManager::instance().addTask(std::shared_ptr(new DisplayTask())); - TaskManager::instance().addTask(std::shared_ptr(new LoraTask())); - if(boardConfig->Type == eETH_BOARD) - { - TaskManager::instance().addTask(std::shared_ptr(new EthTask())); - } - TaskManager::instance().addTask(std::shared_ptr(new WifiTask())); - TaskManager::instance().addTask(std::shared_ptr(new OTATask())); - TaskManager::instance().addTask(std::shared_ptr(new NTPTask())); - if(userConfig->ftp.active) - { - TaskManager::instance().addTask(std::shared_ptr(new FTPTask())); - } - TaskManager::instance().addTask(std::shared_ptr(new AprsIsTask())); + TaskManager::instance().addTask(std::shared_ptr(new DisplayTask())); + TaskManager::instance().addTask(std::shared_ptr(new LoraTask())); + if (boardConfig->Type == eETH_BOARD) { + TaskManager::instance().addTask(std::shared_ptr(new EthTask())); + } + TaskManager::instance().addTask(std::shared_ptr(new WifiTask())); + TaskManager::instance().addTask(std::shared_ptr(new OTATask())); + TaskManager::instance().addTask(std::shared_ptr(new NTPTask())); + if (userConfig->ftp.active) { + TaskManager::instance().addTask(std::shared_ptr(new FTPTask())); + } + TaskManager::instance().addTask(std::shared_ptr(new AprsIsTask())); - TaskManager::instance().setup(userConfig, boardConfig); + TaskManager::instance().setup(userConfig, boardConfig); - Display::instance().showSpashScreen("LoRa APRS iGate", VERSION); + Display::instance().showSpashScreen("LoRa APRS iGate", VERSION); - if(userConfig->display.overwritePin != 0) - { - pinMode(userConfig->display.overwritePin, INPUT); - pinMode(userConfig->display.overwritePin, INPUT_PULLUP); - } + if (userConfig->display.overwritePin != 0) { + pinMode(userConfig->display.overwritePin, INPUT); + pinMode(userConfig->display.overwritePin, INPUT_PULLUP); + } - delay(5000); - logPrintlnI("setup done..."); + delay(5000); + logPrintlnI("setup done..."); } // cppcheck-suppress unusedFunction -void loop() -{ - TaskManager::instance().loop(userConfig); +void loop() { + TaskManager::instance().loop(userConfig); } -String create_lat_aprs(double lat) -{ - char str[20]; - char n_s = 'N'; - if(lat < 0) - { - n_s = 'S'; - } - lat = std::abs(lat); - sprintf(str, "%02d%05.2f%c", (int)lat, (lat - (double)((int)lat)) * 60.0, n_s); - String lat_str(str); - return lat_str; +String create_lat_aprs(double lat) { + char str[20]; + char n_s = 'N'; + if (lat < 0) { + n_s = 'S'; + } + lat = std::abs(lat); + sprintf(str, "%02d%05.2f%c", (int)lat, (lat - (double)((int)lat)) * 60.0, n_s); + String lat_str(str); + return lat_str; } -String create_long_aprs(double lng) -{ - char str[20]; - char e_w = 'E'; - if(lng < 0) - { - e_w = 'W'; - } - lng = std::abs(lng); - sprintf(str, "%03d%05.2f%c", (int)lng, (lng - (double)((int)lng)) * 60.0, e_w); - String lng_str(str); - return lng_str; +String create_long_aprs(double lng) { + char str[20]; + char e_w = 'E'; + if (lng < 0) { + e_w = 'W'; + } + lng = std::abs(lng); + sprintf(str, "%03d%05.2f%c", (int)lng, (lng - (double)((int)lng)) * 60.0, e_w); + String lng_str(str); + return lng_str; } diff --git a/src/Task.cpp b/src/Task.cpp deleted file mode 100644 index 6acb4df..0000000 --- a/src/Task.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "Task.h" - -/*char const * const getTaskName(TaskNames task) -{ - switch (task) - { - case TaskDisplay: - return "Display"; - case TaskAprsIs: - return "APRS-IS"; - case TaskEth: - return "ETH"; - case TaskFtp: - return "FTP"; - case TaskLora: - return "LORA"; - case TaskNtp: - return "NTP"; - case TaskOta: - return "OTA"; - case TaskWifi: - return "WIFI"; - default: - return "error"; - } -}*/ diff --git a/src/Task.h b/src/Task.h index eae32f8..4c881a4 100644 --- a/src/Task.h +++ b/src/Task.h @@ -3,24 +3,24 @@ enum TaskNames { - TaskAprsIs = 1, - TaskEth, - TaskFtp, - TaskLora, - TaskNtp, - TaskOta, - TaskWifi, - TaskSize, + TaskAprsIs = 1, + TaskEth, + TaskFtp, + TaskLora, + TaskNtp, + TaskOta, + TaskWifi, + TaskSize, }; -//char const * const getTaskName(TaskNames task); +// char const * const getTaskName(TaskNames task); -#define TASK_APRS_IS "AprsIsTask" -#define TASK_ETH "EthTask" -#define TASK_FTP "FTPTask" -#define TASK_LORA "LoraTask" -#define TASK_NTP "NTPTask" -#define TASK_OTA "OTATask" -#define TASK_WIFI "WifiTask" +#define TASK_APRS_IS "AprsIsTask" +#define TASK_ETH "EthTask" +#define TASK_FTP "FTPTask" +#define TASK_LORA "LoraTask" +#define TASK_NTP "NTPTask" +#define TASK_OTA "OTATask" +#define TASK_WIFI "WifiTask" #endif diff --git a/src/TaskAprsIs.cpp b/src/TaskAprsIs.cpp index 83be5ad..b064e72 100644 --- a/src/TaskAprsIs.cpp +++ b/src/TaskAprsIs.cpp @@ -1,84 +1,74 @@ -#include #include -#include "project_configuration.h" -#include "TaskAprsIs.h" +#include + #include "Task.h" +#include "TaskAprsIs.h" +#include "project_configuration.h" String create_lat_aprs(double lat); String create_long_aprs(double lng); -AprsIsTask::AprsIsTask() - : Task(TASK_APRS_IS, TaskAprsIs) -{ +AprsIsTask::AprsIsTask() : Task(TASK_APRS_IS, TaskAprsIs) { } -AprsIsTask::~AprsIsTask() -{ +AprsIsTask::~AprsIsTask() { } -bool AprsIsTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) -{ - _beacon_timer.setTimeout(minutesToTime_t(config->beacon.timeout)); - _aprs_is = std::shared_ptr(new APRS_IS(config->callsign, config->aprs_is.passcode , "ESP32-APRS-IS", "0.2")); +bool AprsIsTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { + _beacon_timer.setTimeout(minutesToTime_t(config->beacon.timeout)); + _aprs_is = std::shared_ptr(new APRS_IS(config->callsign, config->aprs_is.passcode, "ESP32-APRS-IS", "0.2")); - _beaconMsg = std::shared_ptr(new APRSMessage()); - _beaconMsg->setSource(config->callsign); - _beaconMsg->setDestination("APLG1"); - String lat = create_lat_aprs(config->beacon.positionLatitude); - String lng = create_long_aprs(config->beacon.positionLongitude); - _beaconMsg->getBody()->setData(String("=") + lat + "L" + lng + "a" + config->beacon.message); + _beaconMsg = std::shared_ptr(new APRSMessage()); + _beaconMsg->setSource(config->callsign); + _beaconMsg->setDestination("APLG1"); + String lat = create_lat_aprs(config->beacon.positionLatitude); + String lng = create_long_aprs(config->beacon.positionLongitude); + _beaconMsg->getBody()->setData(String("=") + lat + "L" + lng + "a" + config->beacon.message); - return true; + return true; } -bool AprsIsTask::loop(std::shared_ptr config) -{ - if(!_aprs_is->connected()) - { - if(!connect(config)) - { - _stateInfo = "not connected"; - _state = Error; - return false; - } - _stateInfo = "connected"; - _state = Okay; - return false; - } - - _aprs_is->getAPRSMessage(); +bool AprsIsTask::loop(std::shared_ptr config) { + if (!_aprs_is->connected()) { + if (!connect(config)) { + _stateInfo = "not connected"; + _state = Error; + return false; + } + _stateInfo = "connected"; + _state = Okay; + return false; + } - if(!inputQueue.empty()) - { - std::shared_ptr msg = inputQueue.getElement(); - _aprs_is->sendMessage(msg); - } + _aprs_is->getAPRSMessage(); - if(_beacon_timer.check()) - { - logPrintD("[" + timeString() + "] "); - logPrintlnD(_beaconMsg->encode()); - _aprs_is->sendMessage(_beaconMsg); - Display::instance().addFrame(std::shared_ptr(new TextFrame("BEACON", _beaconMsg->toString()))); - _beacon_timer.start(); - } - time_t diff = _beacon_timer.getTriggerTime() - now(); - _stateInfo = "beacon " + String(minute(diff)) + ":" + String(second(diff)); - _state = Okay; - return true; + if (!inputQueue.empty()) { + std::shared_ptr msg = inputQueue.getElement(); + _aprs_is->sendMessage(msg); + } + + if (_beacon_timer.check()) { + logPrintD("[" + timeString() + "] "); + logPrintlnD(_beaconMsg->encode()); + _aprs_is->sendMessage(_beaconMsg); + Display::instance().addFrame(std::shared_ptr(new TextFrame("BEACON", _beaconMsg->toString()))); + _beacon_timer.start(); + } + time_t diff = _beacon_timer.getTriggerTime() - now(); + _stateInfo = "beacon " + String(minute(diff)) + ":" + String(second(diff)); + _state = Okay; + return true; } -bool AprsIsTask::connect(std::shared_ptr config) -{ - logPrintI("connecting to APRS-IS server: "); - logPrintI(config->aprs_is.server); - logPrintI(" on port: "); - logPrintlnI(String(config->aprs_is.port)); - if(!_aprs_is->connect(config->aprs_is.server, config->aprs_is.port)) - { - logPrintlnE("Connection failed."); - return false; - } - logPrintlnI("Connected to APRS-IS server!"); - return true; +bool AprsIsTask::connect(std::shared_ptr config) { + logPrintI("connecting to APRS-IS server: "); + logPrintI(config->aprs_is.server); + logPrintI(" on port: "); + logPrintlnI(String(config->aprs_is.port)); + if (!_aprs_is->connect(config->aprs_is.server, config->aprs_is.port)) { + logPrintlnE("Connection failed."); + return false; + } + logPrintlnI("Connected to APRS-IS server!"); + return true; } diff --git a/src/TaskAprsIs.h b/src/TaskAprsIs.h index f26041f..0d0757e 100644 --- a/src/TaskAprsIs.h +++ b/src/TaskAprsIs.h @@ -1,28 +1,27 @@ #ifndef TASK_APRS_IS_H_ #define TASK_APRS_IS_H_ -#include #include #include +#include #include -class AprsIsTask : public Task -{ +class AprsIsTask : public Task { public: - AprsIsTask(); - virtual ~AprsIsTask(); + AprsIsTask(); + virtual ~AprsIsTask(); - virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; - virtual bool loop(std::shared_ptr config) override; + virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; + virtual bool loop(std::shared_ptr config) override; - TaskQueue> inputQueue; + TaskQueue> inputQueue; private: - std::shared_ptr _aprs_is; - std::shared_ptr _beaconMsg; - Timer _beacon_timer; + std::shared_ptr _aprs_is; + std::shared_ptr _beaconMsg; + Timer _beacon_timer; - bool connect(std::shared_ptr config); + bool connect(std::shared_ptr config); }; #endif diff --git a/src/TaskDisplay.cpp b/src/TaskDisplay.cpp index 35f3e38..626b9fb 100644 --- a/src/TaskDisplay.cpp +++ b/src/TaskDisplay.cpp @@ -1,32 +1,27 @@ -#include #include -#include "project_configuration.h" +#include + #include "TaskDisplay.h" +#include "project_configuration.h" -DisplayTask::DisplayTask() - : Task("DisplayTask", 0) -{ +DisplayTask::DisplayTask() : Task("DisplayTask", 0) { } -DisplayTask::~DisplayTask() -{ +DisplayTask::~DisplayTask() { } -bool DisplayTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) -{ - Display::instance().setup(boardConfig); - if(config->display.turn180) - { - Display::instance().turn180(); - } - std::shared_ptr statusFrame = std::shared_ptr(new StatusFrame(TaskManager::instance().getTasks())); - Display::instance().setStatusFrame(statusFrame); - _stateInfo = config->callsign; - return true; +bool DisplayTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { + Display::instance().setup(boardConfig); + if (config->display.turn180) { + Display::instance().turn180(); + } + std::shared_ptr statusFrame = std::shared_ptr(new StatusFrame(TaskManager::instance().getTasks())); + Display::instance().setStatusFrame(statusFrame); + _stateInfo = config->callsign; + return true; } -bool DisplayTask::loop(std::shared_ptr config) -{ - Display::instance().update(); - return true; +bool DisplayTask::loop(std::shared_ptr config) { + Display::instance().update(); + return true; } diff --git a/src/TaskDisplay.h b/src/TaskDisplay.h index 0d1ce2b..4980dee 100644 --- a/src/TaskDisplay.h +++ b/src/TaskDisplay.h @@ -4,14 +4,13 @@ #include #include -class DisplayTask : public Task -{ +class DisplayTask : public Task { public: - DisplayTask(); - virtual ~DisplayTask(); + DisplayTask(); + virtual ~DisplayTask(); - virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; - virtual bool loop(std::shared_ptr config) override; + virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; + virtual bool loop(std::shared_ptr config) override; }; #endif diff --git a/src/TaskEth.cpp b/src/TaskEth.cpp index a112217..e61d736 100644 --- a/src/TaskEth.cpp +++ b/src/TaskEth.cpp @@ -1,87 +1,81 @@ -#include #include +#include #include -#include "TaskEth.h" + #include "Task.h" +#include "TaskEth.h" volatile bool eth_connected = false; -static void WiFiEvent(WiFiEvent_t event) -{ - switch (event) { - case SYSTEM_EVENT_ETH_START: - logPrintlnI("ETH Started"); - ETH.setHostname("esp32-ethernet"); - break; - case SYSTEM_EVENT_ETH_CONNECTED: - logPrintlnI("ETH Connected"); - break; - case SYSTEM_EVENT_ETH_GOT_IP: - logPrintI("ETH MAC: "); - logPrintI(ETH.macAddress()); - logPrintI(", IPv4: "); - logPrintI(ETH.localIP().toString()); - if (ETH.fullDuplex()) { - logPrintI(", FULL_DUPLEX"); - } - logPrintI(", "); - logPrintI(String(ETH.linkSpeed())); - logPrintlnI("Mbps"); - eth_connected = true; - break; - case SYSTEM_EVENT_ETH_DISCONNECTED: - logPrintlnW("ETH Disconnected"); - eth_connected = false; - break; - case SYSTEM_EVENT_ETH_STOP: - logPrintlnW("ETH Stopped"); - eth_connected = false; - break; - default: - break; - } +static void WiFiEvent(WiFiEvent_t event) { + switch (event) { + case SYSTEM_EVENT_ETH_START: + logPrintlnI("ETH Started"); + ETH.setHostname("esp32-ethernet"); + break; + case SYSTEM_EVENT_ETH_CONNECTED: + logPrintlnI("ETH Connected"); + break; + case SYSTEM_EVENT_ETH_GOT_IP: + logPrintI("ETH MAC: "); + logPrintI(ETH.macAddress()); + logPrintI(", IPv4: "); + logPrintI(ETH.localIP().toString()); + if (ETH.fullDuplex()) { + logPrintI(", FULL_DUPLEX"); + } + logPrintI(", "); + logPrintI(String(ETH.linkSpeed())); + logPrintlnI("Mbps"); + eth_connected = true; + break; + case SYSTEM_EVENT_ETH_DISCONNECTED: + logPrintlnW("ETH Disconnected"); + eth_connected = false; + break; + case SYSTEM_EVENT_ETH_STOP: + logPrintlnW("ETH Stopped"); + eth_connected = false; + break; + default: + break; + } } -EthTask::EthTask() - : Task(TASK_ETH, TaskEth) -{ +EthTask::EthTask() : Task(TASK_ETH, TaskEth) { } -EthTask::~EthTask() -{ +EthTask::~EthTask() { } -bool EthTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) -{ - WiFi.onEvent(WiFiEvent); +bool EthTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { + WiFi.onEvent(WiFiEvent); - #define ETH_POWER_PIN -1 - #define ETH_TYPE ETH_PHY_LAN8720 - #define ETH_ADDR 0 - #define ETH_MDC_PIN 23 - #define ETH_MDIO_PIN 18 - #define ETH_NRST 5 - #define ETH_CLK ETH_CLOCK_GPIO17_OUT // TTGO PoE V1.0 - //#define ETH_CLK ETH_CLOCK_GPIO0_OUT // TTGO PoE V1.2 +#define ETH_POWER_PIN -1 +#define ETH_TYPE ETH_PHY_LAN8720 +#define ETH_ADDR 0 +#define ETH_MDC_PIN 23 +#define ETH_MDIO_PIN 18 +#define ETH_NRST 5 +#define ETH_CLK ETH_CLOCK_GPIO17_OUT // TTGO PoE V1.0 + //#define ETH_CLK ETH_CLOCK_GPIO0_OUT // TTGO PoE V1.2 - pinMode(ETH_NRST, OUTPUT); - digitalWrite(ETH_NRST, 0); - delay(200); - digitalWrite(ETH_NRST, 1); - delay(200); - digitalWrite(ETH_NRST, 0); - delay(200); - digitalWrite(ETH_NRST, 1); + pinMode(ETH_NRST, OUTPUT); + digitalWrite(ETH_NRST, 0); + delay(200); + digitalWrite(ETH_NRST, 1); + delay(200); + digitalWrite(ETH_NRST, 0); + delay(200); + digitalWrite(ETH_NRST, 1); - ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK); - while(!eth_connected) - { - sleep(1); - } - return true; + ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK); + while (!eth_connected) { + sleep(1); + } + return true; } -bool EthTask::loop(std::shared_ptr config) -{ - return true; +bool EthTask::loop(std::shared_ptr config) { + return true; } diff --git a/src/TaskEth.h b/src/TaskEth.h index a814495..79d0a47 100644 --- a/src/TaskEth.h +++ b/src/TaskEth.h @@ -3,14 +3,13 @@ #include -class EthTask : public Task -{ +class EthTask : public Task { public: - EthTask(); - virtual ~EthTask(); + EthTask(); + virtual ~EthTask(); - virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; - virtual bool loop(std::shared_ptr config) override; + virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; + virtual bool loop(std::shared_ptr config) override; private: }; diff --git a/src/TaskFTP.cpp b/src/TaskFTP.cpp index a29fa32..a44189f 100644 --- a/src/TaskFTP.cpp +++ b/src/TaskFTP.cpp @@ -1,52 +1,44 @@ -#include #include +#include #include -#include "project_configuration.h" -#include "TaskFTP.h" + #include "Task.h" +#include "TaskFTP.h" +#include "project_configuration.h" -FTPTask::FTPTask() - : Task(TASK_FTP, TaskFtp), _beginCalled(false) -{ +FTPTask::FTPTask() : Task(TASK_FTP, TaskFtp), _beginCalled(false) { } -FTPTask::~FTPTask() -{ +FTPTask::~FTPTask() { } -bool FTPTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) -{ - _ftpServer = std::shared_ptr(new FTPServer()); - for(Configuration::Ftp::User user : config->ftp.users) - { - logPrintD("Adding user to FTP Server: "); - logPrintlnD(user.name); - _ftpServer->addUser(user.name, user.password); - } - _ftpServer->addFilesystem("SPIFFS", &SPIFFS); - _stateInfo = "waiting"; - return true; +bool FTPTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { + _ftpServer = std::shared_ptr(new FTPServer()); + for (Configuration::Ftp::User user : config->ftp.users) { + logPrintD("Adding user to FTP Server: "); + logPrintlnD(user.name); + _ftpServer->addUser(user.name, user.password); + } + _ftpServer->addFilesystem("SPIFFS", &SPIFFS); + _stateInfo = "waiting"; + return true; } -bool FTPTask::loop(std::shared_ptr config) -{ - if(!_beginCalled) - { - _ftpServer->begin(); - _beginCalled = true; - } - _ftpServer->handle(); - static bool configWasOpen = false; - if(configWasOpen && _ftpServer->countConnections() == 0) - { - logPrintlnW("Maybe the config has been changed via FTP, lets restart now to get the new config..."); - logPrintlnW(""); - ESP.restart(); - } - if(_ftpServer->countConnections() > 0) - { - configWasOpen = true; - _stateInfo = "has connection"; - } - return true; +bool FTPTask::loop(std::shared_ptr config) { + if (!_beginCalled) { + _ftpServer->begin(); + _beginCalled = true; + } + _ftpServer->handle(); + static bool configWasOpen = false; + if (configWasOpen && _ftpServer->countConnections() == 0) { + logPrintlnW("Maybe the config has been changed via FTP, lets restart now to get the new config..."); + logPrintlnW(""); + ESP.restart(); + } + if (_ftpServer->countConnections() > 0) { + configWasOpen = true; + _stateInfo = "has connection"; + } + return true; } diff --git a/src/TaskFTP.h b/src/TaskFTP.h index 716424c..85c7fd7 100644 --- a/src/TaskFTP.h +++ b/src/TaskFTP.h @@ -1,21 +1,20 @@ #ifndef TASK_FTP_H_ #define TASK_FTP_H_ -#include #include +#include -class FTPTask : public Task -{ +class FTPTask : public Task { public: - FTPTask(); - virtual ~FTPTask(); + FTPTask(); + virtual ~FTPTask(); - virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; - virtual bool loop(std::shared_ptr config) override; + virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; + virtual bool loop(std::shared_ptr config) override; private: - std::shared_ptr _ftpServer; - bool _beginCalled; + std::shared_ptr _ftpServer; + bool _beginCalled; }; #endif diff --git a/src/TaskLora.cpp b/src/TaskLora.cpp index 4a9dc61..9194fb7 100644 --- a/src/TaskLora.cpp +++ b/src/TaskLora.cpp @@ -1,64 +1,58 @@ -#include #include -#include "project_configuration.h" -#include "TaskLora.h" -#include "TaskAprsIs.h" +#include + #include "Task.h" +#include "TaskAprsIs.h" +#include "TaskLora.h" +#include "project_configuration.h" -LoraTask::LoraTask() - : Task(TASK_LORA, TaskLora) -{ +LoraTask::LoraTask() : Task(TASK_LORA, TaskLora) { } -LoraTask::~LoraTask() -{ +LoraTask::~LoraTask() { } -bool LoraTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) -{ - _lora_aprs = std::shared_ptr(new LoRa_APRS(boardConfig)); - if(!_lora_aprs->begin(_lora_aprs->getRxFrequency())) - { - logPrintlnE("Starting LoRa failed!"); - _stateInfo = "LoRa-Modem failed"; - _state = Error; - while(true); - } - _lora_aprs->setRxFrequency(config->lora.frequencyRx); - _lora_aprs->setTxFrequency(config->lora.frequencyTx); - _lora_aprs->setTxPower(config->lora.power); - _lora_aprs->setSpreadingFactor(config->lora.spreadingFactor); - _lora_aprs->setSignalBandwidth(config->lora.signalBandwidth); - _lora_aprs->setCodingRate4(config->lora.codingRate4); - _lora_aprs->enableCrc(); +bool LoraTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { + _lora_aprs = std::shared_ptr(new LoRa_APRS(boardConfig)); + if (!_lora_aprs->begin(_lora_aprs->getRxFrequency())) { + logPrintlnE("Starting LoRa failed!"); + _stateInfo = "LoRa-Modem failed"; + _state = Error; + while (true) + ; + } + _lora_aprs->setRxFrequency(config->lora.frequencyRx); + _lora_aprs->setTxFrequency(config->lora.frequencyTx); + _lora_aprs->setTxPower(config->lora.power); + _lora_aprs->setSpreadingFactor(config->lora.spreadingFactor); + _lora_aprs->setSignalBandwidth(config->lora.signalBandwidth); + _lora_aprs->setCodingRate4(config->lora.codingRate4); + _lora_aprs->enableCrc(); - _stateInfo = ""; - return true; + _stateInfo = ""; + return true; } -bool LoraTask::loop(std::shared_ptr config) -{ - if(_lora_aprs->checkMessage()) - { - std::shared_ptr msg = _lora_aprs->getMessage(); - //msg->getAPRSBody()->setData(msg->getAPRSBody()->getData() + " 123"); - logPrintD("[" + timeString() + "] "); - logPrintD("Received packet '"); - logPrintD(msg->toString()); - logPrintD("' with RSSI "); - logPrintD(String(_lora_aprs->packetRssi())); - logPrintD(" and SNR "); - logPrintlnD(String(_lora_aprs->packetSnr())); - std::shared_ptr is_thread = std::static_pointer_cast(TaskManager::instance().getTask(TASK_APRS_IS)); - is_thread->inputQueue.addElement(msg); - Display::instance().addFrame(std::shared_ptr(new TextFrame("LoRa", msg->toString()))); - } +bool LoraTask::loop(std::shared_ptr config) { + if (_lora_aprs->checkMessage()) { + std::shared_ptr msg = _lora_aprs->getMessage(); + // msg->getAPRSBody()->setData(msg->getAPRSBody()->getData() + " 123"); + logPrintD("[" + timeString() + "] "); + logPrintD("Received packet '"); + logPrintD(msg->toString()); + logPrintD("' with RSSI "); + logPrintD(String(_lora_aprs->packetRssi())); + logPrintD(" and SNR "); + logPrintlnD(String(_lora_aprs->packetSnr())); + std::shared_ptr is_thread = std::static_pointer_cast(TaskManager::instance().getTask(TASK_APRS_IS)); + is_thread->inputQueue.addElement(msg); + Display::instance().addFrame(std::shared_ptr(new TextFrame("LoRa", msg->toString()))); + } - if(!inputQueue.empty()) - { - std::shared_ptr msg = inputQueue.getElement(); - _lora_aprs->sendMessage(msg); - } + if (!inputQueue.empty()) { + std::shared_ptr msg = inputQueue.getElement(); + _lora_aprs->sendMessage(msg); + } - return true; + return true; } diff --git a/src/TaskLora.h b/src/TaskLora.h index db2201d..75aac8f 100644 --- a/src/TaskLora.h +++ b/src/TaskLora.h @@ -1,23 +1,22 @@ #ifndef TASK_LORA_H_ #define TASK_LORA_H_ -#include #include #include +#include -class LoraTask : public Task -{ +class LoraTask : public Task { public: - LoraTask(); - virtual ~LoraTask(); + LoraTask(); + virtual ~LoraTask(); - virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; - virtual bool loop(std::shared_ptr config) override; + virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; + virtual bool loop(std::shared_ptr config) override; - TaskQueue> inputQueue; + TaskQueue> inputQueue; private: - std::shared_ptr _lora_aprs; + std::shared_ptr _lora_aprs; }; #endif diff --git a/src/TaskNTP.cpp b/src/TaskNTP.cpp index 56247e3..5371981 100644 --- a/src/TaskNTP.cpp +++ b/src/TaskNTP.cpp @@ -1,38 +1,32 @@ -#include #include -#include "project_configuration.h" -#include "TaskNTP.h" +#include + #include "Task.h" +#include "TaskNTP.h" +#include "project_configuration.h" -NTPTask::NTPTask() - : Task(TASK_NTP, TaskNtp), _beginCalled(false) -{ +NTPTask::NTPTask() : Task(TASK_NTP, TaskNtp), _beginCalled(false) { } -NTPTask::~NTPTask() -{ +NTPTask::~NTPTask() { } -bool NTPTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) -{ - _ntpClient = std::shared_ptr(new NTPClient(config->ntpServer.c_str())); - return true; +bool NTPTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { + _ntpClient = std::shared_ptr(new NTPClient(config->ntpServer.c_str())); + return true; } -bool NTPTask::loop(std::shared_ptr config) -{ - if(!_beginCalled) - { - _ntpClient->begin(); - _beginCalled = true; - } - if(_ntpClient->update()) - { - setTime(_ntpClient->getEpochTime()); - logPrintI("Current time: "); - logPrintlnI(_ntpClient->getFormattedTime()); - } - _stateInfo = _ntpClient->getFormattedTime(); - _state = Okay; - return true; +bool NTPTask::loop(std::shared_ptr config) { + if (!_beginCalled) { + _ntpClient->begin(); + _beginCalled = true; + } + if (_ntpClient->update()) { + setTime(_ntpClient->getEpochTime()); + logPrintI("Current time: "); + logPrintlnI(_ntpClient->getFormattedTime()); + } + _stateInfo = _ntpClient->getFormattedTime(); + _state = Okay; + return true; } diff --git a/src/TaskNTP.h b/src/TaskNTP.h index ef5240b..88ae419 100644 --- a/src/TaskNTP.h +++ b/src/TaskNTP.h @@ -1,21 +1,20 @@ #ifndef TASK_NTP_H_ #define TASK_NTP_H_ -#include #include +#include -class NTPTask : public Task -{ +class NTPTask : public Task { public: - NTPTask(); - virtual ~NTPTask(); + NTPTask(); + virtual ~NTPTask(); - virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; - virtual bool loop(std::shared_ptr config) override; + virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; + virtual bool loop(std::shared_ptr config) override; private: - std::shared_ptr _ntpClient; - bool _beginCalled; + std::shared_ptr _ntpClient; + bool _beginCalled; }; #endif diff --git a/src/TaskOTA.cpp b/src/TaskOTA.cpp index bd8c453..5cd7a35 100644 --- a/src/TaskOTA.cpp +++ b/src/TaskOTA.cpp @@ -1,63 +1,59 @@ #include -#include "project_configuration.h" -#include "TaskOTA.h" + #include "Task.h" +#include "TaskOTA.h" +#include "project_configuration.h" -OTATask::OTATask() - : Task(TASK_OTA, TaskOta), _beginCalled(false) -{ +OTATask::OTATask() : Task(TASK_OTA, TaskOta), _beginCalled(false) { } -OTATask::~OTATask() -{ +OTATask::~OTATask() { } -bool OTATask::setup(std::shared_ptr config, std::shared_ptr boardConfig) -{ - _ota = std::shared_ptr(new ArduinoOTAClass()); - _ota->onStart([&]() - { - String type; - if (_ota->getCommand() == U_FLASH) - type = "sketch"; - else // U_SPIFFS - type = "filesystem"; - logPrintlnI("Start updating " + type); - }) - .onEnd([]() - { - logPrintlnI(""); - logPrintlnI("OTA End"); - }) - .onProgress([](unsigned int progress, unsigned int total) - { - logPrintI("Progress: "); - logPrintI(String(progress / (total / 100))); - logPrintlnI("%"); - }) - .onError([](ota_error_t error) - { - logPrintE("Error["); - logPrintE(String(error)); - logPrintE("]: "); - if (error == OTA_AUTH_ERROR) logPrintlnE("Auth Failed"); - else if (error == OTA_BEGIN_ERROR) logPrintlnE("Begin Failed"); - else if (error == OTA_CONNECT_ERROR) logPrintlnE("Connect Failed"); - else if (error == OTA_RECEIVE_ERROR) logPrintlnE("Receive Failed"); - else if (error == OTA_END_ERROR) logPrintlnE("End Failed"); - }); - _ota->setHostname(config->callsign.c_str()); - _stateInfo = ""; - return true; +bool OTATask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { + _ota = std::shared_ptr(new ArduinoOTAClass()); + _ota->onStart([&]() { + String type; + if (_ota->getCommand() == U_FLASH) + type = "sketch"; + else // U_SPIFFS + type = "filesystem"; + logPrintlnI("Start updating " + type); + }) + .onEnd([]() { + logPrintlnI(""); + logPrintlnI("OTA End"); + }) + .onProgress([](unsigned int progress, unsigned int total) { + logPrintI("Progress: "); + logPrintI(String(progress / (total / 100))); + logPrintlnI("%"); + }) + .onError([](ota_error_t error) { + logPrintE("Error["); + logPrintE(String(error)); + logPrintE("]: "); + if (error == OTA_AUTH_ERROR) + logPrintlnE("Auth Failed"); + else if (error == OTA_BEGIN_ERROR) + logPrintlnE("Begin Failed"); + else if (error == OTA_CONNECT_ERROR) + logPrintlnE("Connect Failed"); + else if (error == OTA_RECEIVE_ERROR) + logPrintlnE("Receive Failed"); + else if (error == OTA_END_ERROR) + logPrintlnE("End Failed"); + }); + _ota->setHostname(config->callsign.c_str()); + _stateInfo = ""; + return true; } -bool OTATask::loop(std::shared_ptr config) -{ - if(!_beginCalled) - { - _ota->begin(); - _beginCalled = true; - } - _ota->handle(); - return true; +bool OTATask::loop(std::shared_ptr config) { + if (!_beginCalled) { + _ota->begin(); + _beginCalled = true; + } + _ota->handle(); + return true; } diff --git a/src/TaskOTA.h b/src/TaskOTA.h index f9aa88f..8e3e372 100644 --- a/src/TaskOTA.h +++ b/src/TaskOTA.h @@ -1,21 +1,20 @@ #ifndef TASK_OTA_H_ #define TASK_OTA_H_ -#include #include +#include -class OTATask : public Task -{ +class OTATask : public Task { public: - OTATask(); - virtual ~OTATask(); + OTATask(); + virtual ~OTATask(); - virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; - virtual bool loop(std::shared_ptr config) override; + virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; + virtual bool loop(std::shared_ptr config) override; private: - std::shared_ptr _ota; - bool _beginCalled; + std::shared_ptr _ota; + bool _beginCalled; }; #endif diff --git a/src/TaskWifi.cpp b/src/TaskWifi.cpp index 8253272..fe37c5b 100644 --- a/src/TaskWifi.cpp +++ b/src/TaskWifi.cpp @@ -1,51 +1,44 @@ #include #include -#include "project_configuration.h" -#include "TaskWifi.h" + #include "Task.h" +#include "TaskWifi.h" +#include "project_configuration.h" -WifiTask::WifiTask() - : Task(TASK_WIFI, TaskWifi), _oldWifiStatus(WL_IDLE_STATUS) -{ +WifiTask::WifiTask() : Task(TASK_WIFI, TaskWifi), _oldWifiStatus(WL_IDLE_STATUS) { } -WifiTask::~WifiTask() -{ +WifiTask::~WifiTask() { } -bool WifiTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) -{ - //WiFi.onEvent(WiFiEvent); - WiFi.setHostname(config->callsign.c_str()); - _wiFiMulti = std::shared_ptr(new WiFiMulti());; - for(Configuration::Wifi::AP ap : config->wifi.APs) - { - logPrintD("Looking for AP: "); - logPrintlnD(ap.SSID); - _wiFiMulti->addAP(ap.SSID.c_str(), ap.password.c_str()); - } - return true; +bool WifiTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { + // WiFi.onEvent(WiFiEvent); + WiFi.setHostname(config->callsign.c_str()); + _wiFiMulti = std::shared_ptr(new WiFiMulti()); + ; + for (Configuration::Wifi::AP ap : config->wifi.APs) { + logPrintD("Looking for AP: "); + logPrintlnD(ap.SSID); + _wiFiMulti->addAP(ap.SSID.c_str(), ap.password.c_str()); + } + return true; } -bool WifiTask::loop(std::shared_ptr config) -{ - const uint8_t wifi_status = _wiFiMulti->run(); - if(wifi_status != WL_CONNECTED) - { - logPrintlnE("WiFi not connected!"); - _oldWifiStatus = wifi_status; - _stateInfo = "WiFi not connected"; - _state = Error; - return false; - } - else if(wifi_status != _oldWifiStatus) - { - logPrintD("IP address: "); - logPrintlnD(WiFi.localIP().toString()); - _oldWifiStatus = wifi_status; - return false; - } - _stateInfo = WiFi.localIP().toString(); - _state = Okay; - return true; +bool WifiTask::loop(std::shared_ptr config) { + const uint8_t wifi_status = _wiFiMulti->run(); + if (wifi_status != WL_CONNECTED) { + logPrintlnE("WiFi not connected!"); + _oldWifiStatus = wifi_status; + _stateInfo = "WiFi not connected"; + _state = Error; + return false; + } else if (wifi_status != _oldWifiStatus) { + logPrintD("IP address: "); + logPrintlnD(WiFi.localIP().toString()); + _oldWifiStatus = wifi_status; + return false; + } + _stateInfo = WiFi.localIP().toString(); + _state = Okay; + return true; } diff --git a/src/TaskWifi.h b/src/TaskWifi.h index 24b2a13..4e99f0b 100644 --- a/src/TaskWifi.h +++ b/src/TaskWifi.h @@ -4,18 +4,17 @@ #include #include -class WifiTask : public Task -{ +class WifiTask : public Task { public: - WifiTask(); - virtual ~WifiTask(); + WifiTask(); + virtual ~WifiTask(); - virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; - virtual bool loop(std::shared_ptr config) override; + virtual bool setup(std::shared_ptr config, std::shared_ptr boardConfig) override; + virtual bool loop(std::shared_ptr config) override; private: - std::shared_ptr _wiFiMulti; - uint8_t _oldWifiStatus; + std::shared_ptr _wiFiMulti; + uint8_t _oldWifiStatus; }; #endif diff --git a/src/project_configuration.cpp b/src/project_configuration.cpp index 4d4f7b0..f34410a 100644 --- a/src/project_configuration.cpp +++ b/src/project_configuration.cpp @@ -1,125 +1,117 @@ #include +#include + #include "project_configuration.h" -#include "logger.h" -std::shared_ptr ProjectConfigurationManagement::readProjectConfiguration(DynamicJsonDocument & data) -{ - std::shared_ptr conf = std::shared_ptr(new Configuration); - if(data.containsKey("callsign")) - conf->callsign = data["callsign"].as(); +std::shared_ptr ProjectConfigurationManagement::readProjectConfiguration(DynamicJsonDocument &data) { + std::shared_ptr conf = std::shared_ptr(new Configuration); + if (data.containsKey("callsign")) + conf->callsign = data["callsign"].as(); - JsonArray aps = data["wifi"]["AP"].as(); - for(JsonVariant v : aps) - { - Configuration::Wifi::AP ap; - ap.SSID = v["SSID"].as(); - ap.password = v["password"].as(); - conf->wifi.APs.push_back(ap); - } - if(data.containsKey("beacon") && data["beacon"].containsKey("message")) - conf->beacon.message = data["beacon"]["message"].as(); - conf->beacon.positionLatitude = data["beacon"]["position"]["latitude"] | 0.0; - conf->beacon.positionLongitude = data["beacon"]["position"]["longitude"] | 0.0; - conf->beacon.timeout = data["beacon"]["timeout"] | 15; - if(data.containsKey("aprs_is") && data["aprs_is"].containsKey("passcode")) - conf->aprs_is.passcode = data["aprs_is"]["passcode"].as(); - if(data.containsKey("aprs_is") && data["aprs_is"].containsKey("server")) - conf->aprs_is.server = data["aprs_is"]["server"].as(); - conf->aprs_is.port = data["aprs_is"]["port"] | 14580; + JsonArray aps = data["wifi"]["AP"].as(); + for (JsonVariant v : aps) { + Configuration::Wifi::AP ap; + ap.SSID = v["SSID"].as(); + ap.password = v["password"].as(); + conf->wifi.APs.push_back(ap); + } + if (data.containsKey("beacon") && data["beacon"].containsKey("message")) + conf->beacon.message = data["beacon"]["message"].as(); + conf->beacon.positionLatitude = data["beacon"]["position"]["latitude"] | 0.0; + conf->beacon.positionLongitude = data["beacon"]["position"]["longitude"] | 0.0; + conf->beacon.timeout = data["beacon"]["timeout"] | 15; + if (data.containsKey("aprs_is") && data["aprs_is"].containsKey("passcode")) + conf->aprs_is.passcode = data["aprs_is"]["passcode"].as(); + if (data.containsKey("aprs_is") && data["aprs_is"].containsKey("server")) + conf->aprs_is.server = data["aprs_is"]["server"].as(); + conf->aprs_is.port = data["aprs_is"]["port"] | 14580; - conf->lora.frequencyRx = data["lora"]["frequency_rx"] | 433775000; - conf->lora.frequencyTx = data["lora"]["frequency_tx"] | 433775000; - conf->lora.power = data["lora"]["power"] | 20; - conf->lora.spreadingFactor = data["lora"]["spreading_factor"] | 12; - conf->lora.signalBandwidth = data["lora"]["signal_bandwidth"] | 125000; - conf->lora.codingRate4 = data["lora"]["coding_rate4"] | 5; - conf->display.alwaysOn = data["display"]["always_on"] | true; - conf->display.timeout = data["display"]["timeout"] | 10; - conf->display.overwritePin = data["display"]["overwrite_pin"] | 0; - conf->display.turn180 = data["display"]["turn180"] | true; + conf->lora.frequencyRx = data["lora"]["frequency_rx"] | 433775000; + conf->lora.frequencyTx = data["lora"]["frequency_tx"] | 433775000; + conf->lora.power = data["lora"]["power"] | 20; + conf->lora.spreadingFactor = data["lora"]["spreading_factor"] | 12; + conf->lora.signalBandwidth = data["lora"]["signal_bandwidth"] | 125000; + conf->lora.codingRate4 = data["lora"]["coding_rate4"] | 5; + conf->display.alwaysOn = data["display"]["always_on"] | true; + conf->display.timeout = data["display"]["timeout"] | 10; + conf->display.overwritePin = data["display"]["overwrite_pin"] | 0; + conf->display.turn180 = data["display"]["turn180"] | true; - conf->ftp.active = data["ftp"]["active"] | false; - JsonArray users = data["ftp"]["user"].as(); - for(JsonVariant u : users) - { - Configuration::Ftp::User us; - us.name = u["name"].as(); - us.password = u["password"].as(); - conf->ftp.users.push_back(us); - } - if(conf->ftp.users.empty()) - { - Configuration::Ftp::User us; - us.name = "ftp"; - us.password = "ftp"; - conf->ftp.users.push_back(us); - } - if(data.containsKey("ntp_server")) - conf->ntpServer = data["ntp_server"].as(); + conf->ftp.active = data["ftp"]["active"] | false; + JsonArray users = data["ftp"]["user"].as(); + for (JsonVariant u : users) { + Configuration::Ftp::User us; + us.name = u["name"].as(); + us.password = u["password"].as(); + conf->ftp.users.push_back(us); + } + if (conf->ftp.users.empty()) { + Configuration::Ftp::User us; + us.name = "ftp"; + us.password = "ftp"; + conf->ftp.users.push_back(us); + } + if (data.containsKey("ntp_server")) + conf->ntpServer = data["ntp_server"].as(); - if(data.containsKey("board")) - conf->board = data["board"].as(); + if (data.containsKey("board")) + conf->board = data["board"].as(); - return conf; + return conf; } -void ProjectConfigurationManagement::writeProjectConfiguration(std::shared_ptr conf, DynamicJsonDocument & data) -{ - data["callsign"] = conf->callsign; - JsonArray aps = data["wifi"].createNestedArray("AP"); - for(Configuration::Wifi::AP ap : conf->wifi.APs) - { - JsonObject v = aps.createNestedObject(); - v["SSID"] = ap.SSID; - v["password"] = ap.password; - } - data["beacon"]["message"] = conf->beacon.message; - data["beacon"]["position"]["latitude"] = conf->beacon.positionLatitude; - data["beacon"]["position"]["longitude"] = conf->beacon.positionLongitude; - data["beacon"]["timeout"] = conf->beacon.timeout; - data["aprs_is"]["passcode"] = conf->aprs_is.passcode; - data["aprs_is"]["server"] = conf->aprs_is.server; - data["aprs_is"]["port"] = conf->aprs_is.port; - data["lora"]["frequency_rx"] = conf->lora.frequencyRx; - data["lora"]["frequency_tx"] = conf->lora.frequencyTx; - data["lora"]["power"] = conf->lora.power; - data["lora"]["spreading_factor"] = conf->lora.spreadingFactor; - data["lora"]["signal_bandwidth"] = conf->lora.signalBandwidth; - data["lora"]["coding_rate4"] = conf->lora.codingRate4; - data["display"]["always_on"] = conf->display.alwaysOn; - data["display"]["timeout"] = conf->display.timeout; - data["display"]["overwrite_pin"] = conf->display.overwritePin; - data["display"]["turn180"] = conf->display.turn180; - data["ftp"]["active"] = conf->ftp.active; - JsonArray users = data["ftp"].createNestedArray("user"); - for(Configuration::Ftp::User u : conf->ftp.users) - { - JsonObject v = users.createNestedObject(); - v["name"] = u.name; - v["password"] = u.password; - } - data["ntp_server"] = conf->ntpServer; +void ProjectConfigurationManagement::writeProjectConfiguration(std::shared_ptr conf, DynamicJsonDocument &data) { + data["callsign"] = conf->callsign; + JsonArray aps = data["wifi"].createNestedArray("AP"); + for (Configuration::Wifi::AP ap : conf->wifi.APs) { + JsonObject v = aps.createNestedObject(); + v["SSID"] = ap.SSID; + v["password"] = ap.password; + } + data["beacon"]["message"] = conf->beacon.message; + data["beacon"]["position"]["latitude"] = conf->beacon.positionLatitude; + data["beacon"]["position"]["longitude"] = conf->beacon.positionLongitude; + data["beacon"]["timeout"] = conf->beacon.timeout; + data["aprs_is"]["passcode"] = conf->aprs_is.passcode; + data["aprs_is"]["server"] = conf->aprs_is.server; + data["aprs_is"]["port"] = conf->aprs_is.port; + data["lora"]["frequency_rx"] = conf->lora.frequencyRx; + data["lora"]["frequency_tx"] = conf->lora.frequencyTx; + data["lora"]["power"] = conf->lora.power; + data["lora"]["spreading_factor"] = conf->lora.spreadingFactor; + data["lora"]["signal_bandwidth"] = conf->lora.signalBandwidth; + data["lora"]["coding_rate4"] = conf->lora.codingRate4; + data["display"]["always_on"] = conf->display.alwaysOn; + data["display"]["timeout"] = conf->display.timeout; + data["display"]["overwrite_pin"] = conf->display.overwritePin; + data["display"]["turn180"] = conf->display.turn180; + data["ftp"]["active"] = conf->ftp.active; + JsonArray users = data["ftp"].createNestedArray("user"); + for (Configuration::Ftp::User u : conf->ftp.users) { + JsonObject v = users.createNestedObject(); + v["name"] = u.name; + v["password"] = u.password; + } + data["ntp_server"] = conf->ntpServer; - data["board"] = conf->board; + data["board"] = conf->board; } -std::shared_ptr load_config(std::shared_ptr boardConfig) -{ - ProjectConfigurationManagement confmg; - std::shared_ptr config = confmg.readConfiguration(); - if(config->callsign == "NOCALL-10") - { - logPrintlnE("You have to change your settings in 'data/is-cfg.json' and upload it via \"Upload File System image\"!"); - //show_display("ERROR", "You have to change your settings in 'data/is-cfg.json' and upload it via \"Upload File System image\"!"); - while (true) - {} - } +std::shared_ptr load_config(std::shared_ptr boardConfig) { + ProjectConfigurationManagement confmg; + std::shared_ptr config = confmg.readConfiguration(); + if (config->callsign == "NOCALL-10") { + logPrintlnE("You have to change your settings in 'data/is-cfg.json' and upload it via \"Upload File System image\"!"); + // show_display("ERROR", "You have to change your settings in 'data/is-cfg.json' and upload it via \"Upload File System image\"!"); + while (true) { + } + } - /*if(KEY_BUILTIN != 0 && Config->display.overwritePin == 0) - { - Config->display.overwritePin = KEY_BUILTIN; - }*/ - logPrintlnI("Configuration loaded!"); - return config; + /*if(KEY_BUILTIN != 0 && Config->display.overwritePin == 0) + { + Config->display.overwritePin = KEY_BUILTIN; + }*/ + logPrintlnI("Configuration loaded!"); + return config; } diff --git a/src/project_configuration.h b/src/project_configuration.h index 44da8e5..00ebefa 100644 --- a/src/project_configuration.h +++ b/src/project_configuration.h @@ -1,110 +1,108 @@ #ifndef PROJECT_CONFIGURATION_H_ #define PROJECT_CONFIGURATION_H_ -#include "configuration.h" -#include "BoardFinder.h" +#include +#include -class Configuration -{ +class Configuration { public: - class Wifi - { - public: - class AP - { - public: - String SSID; - String password; - }; + class Wifi { + public: + class AP { + public: + String SSID; + String password; + }; - Wifi() {} + Wifi() { + } - std::list APs; - }; + std::list APs; + }; - class Beacon - { - public: - Beacon() : message("LoRa iGATE & Digi, Info: github.com/peterus/LoRa_APRS_iGate"), positionLatitude(0.0), positionLongitude(0.0), timeout(15) {} + class Beacon { + public: + Beacon() : message("LoRa iGATE & Digi, Info: github.com/peterus/LoRa_APRS_iGate"), positionLatitude(0.0), positionLongitude(0.0), timeout(15) { + } - String message; - double positionLatitude; - double positionLongitude; - int timeout; - }; + String message; + double positionLatitude; + double positionLongitude; + int timeout; + }; - class APRS_IS - { - public: - APRS_IS() : server("euro.aprs2.net"), port(14580) {} + class APRS_IS { + public: + APRS_IS() : server("euro.aprs2.net"), port(14580) { + } - String passcode; - String server; - int port; - }; + String passcode; + String server; + int port; + }; - class LoRa - { - public: - LoRa() : frequencyRx(433775000), frequencyTx(433775000), power(20), spreadingFactor(12), signalBandwidth(125000), codingRate4(5) {} + class LoRa { + public: + LoRa() : frequencyRx(433775000), frequencyTx(433775000), power(20), spreadingFactor(12), signalBandwidth(125000), codingRate4(5) { + } - long frequencyRx; - long frequencyTx; - int power; - int spreadingFactor; - long signalBandwidth; - int codingRate4; - }; + long frequencyRx; + long frequencyTx; + int power; + int spreadingFactor; + long signalBandwidth; + int codingRate4; + }; - class Display - { - public: - Display() : alwaysOn(true), timeout(10), overwritePin(0), turn180(true) {} + class Display { + public: + Display() : alwaysOn(true), timeout(10), overwritePin(0), turn180(true) { + } - bool alwaysOn; - int timeout; - int overwritePin; - bool turn180; - }; + bool alwaysOn; + int timeout; + int overwritePin; + bool turn180; + }; - class Ftp - { - public: - class User - { - public: - String name; - String password; - }; + class Ftp { + public: + class User { + public: + String name; + String password; + }; - Ftp() : active(false) {} + Ftp() : active(false) { + } - bool active; - std::list users; - }; + bool active; + std::list users; + }; - Configuration() : callsign("NOCALL-10"), board(""), ntpServer("pool.ntp.org") {}; + Configuration() : callsign("NOCALL-10"), board(""), ntpServer("pool.ntp.org"){}; - String callsign; - Wifi wifi; - Beacon beacon; - APRS_IS aprs_is; - LoRa lora; - Display display; - Ftp ftp; - String board; - String ntpServer; + String callsign; + Wifi wifi; + Beacon beacon; + APRS_IS aprs_is; + LoRa lora; + Display display; + Ftp ftp; + String board; + String ntpServer; }; -class ProjectConfigurationManagement : public ConfigurationManagement -{ +class ProjectConfigurationManagement : public ConfigurationManagement { public: - explicit ProjectConfigurationManagement() : ConfigurationManagement("/is-cfg.json") {} - virtual ~ProjectConfigurationManagement() {} + explicit ProjectConfigurationManagement() : ConfigurationManagement("/is-cfg.json") { + } + virtual ~ProjectConfigurationManagement() { + } private: - virtual std::shared_ptr readProjectConfiguration(DynamicJsonDocument & data) override; - virtual void writeProjectConfiguration(std::shared_ptr conf, DynamicJsonDocument & data) override; + virtual std::shared_ptr readProjectConfiguration(DynamicJsonDocument &data) override; + virtual void writeProjectConfiguration(std::shared_ptr conf, DynamicJsonDocument &data) override; }; std::shared_ptr load_config(std::shared_ptr boardConfig); From 79f71a422da0be9fb6d22254d7bf9df599708428 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sat, 13 Mar 2021 00:19:33 +0100 Subject: [PATCH 51/60] Update build_check.yml --- .github/workflows/build_check.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build_check.yml b/.github/workflows/build_check.yml index a731bc7..b537185 100644 --- a/.github/workflows/build_check.yml +++ b/.github/workflows/build_check.yml @@ -1,9 +1,9 @@ -name: Build check and build +name: push pull checks on: [push, pull_request] jobs: - PlatformIO-Check: + check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -27,7 +27,7 @@ jobs: - name: Run PlatformIO Check run: platformio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high - PlatformIO-Build: + build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 From 993b8b40037e19afe98bdaaed7406151c175e520 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sat, 13 Mar 2021 22:27:46 +0100 Subject: [PATCH 52/60] ethernet fix --- src/LoRa_APRS_iGate.cpp | 3 ++- src/TaskEth.cpp | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index e57691b..533360f 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -86,8 +86,9 @@ void setup() { TaskManager::instance().addTask(std::shared_ptr(new LoraTask())); if (boardConfig->Type == eETH_BOARD) { TaskManager::instance().addTask(std::shared_ptr(new EthTask())); + } else { + TaskManager::instance().addTask(std::shared_ptr(new WifiTask())); } - TaskManager::instance().addTask(std::shared_ptr(new WifiTask())); TaskManager::instance().addTask(std::shared_ptr(new OTATask())); TaskManager::instance().addTask(std::shared_ptr(new NTPTask())); if (userConfig->ftp.active) { diff --git a/src/TaskEth.cpp b/src/TaskEth.cpp index e61d736..9435a5f 100644 --- a/src/TaskEth.cpp +++ b/src/TaskEth.cpp @@ -51,14 +51,14 @@ EthTask::~EthTask() { bool EthTask::setup(std::shared_ptr config, std::shared_ptr boardConfig) { WiFi.onEvent(WiFiEvent); -#define ETH_POWER_PIN -1 -#define ETH_TYPE ETH_PHY_LAN8720 -#define ETH_ADDR 0 -#define ETH_MDC_PIN 23 -#define ETH_MDIO_PIN 18 -#define ETH_NRST 5 -#define ETH_CLK ETH_CLOCK_GPIO17_OUT // TTGO PoE V1.0 - //#define ETH_CLK ETH_CLOCK_GPIO0_OUT // TTGO PoE V1.2 + constexpr uint8_t ETH_NRST = 5; + constexpr uint8_t ETH_ADDR = 0; + constexpr int ETH_POWER_PIN = -1; + constexpr int ETH_MDC_PIN = 23; + constexpr int ETH_MDIO_PIN = 18; + constexpr eth_phy_type_t ETH_TYPE = ETH_PHY_LAN8720; + constexpr eth_clock_mode_t ETH_CLK = ETH_CLOCK_GPIO17_OUT; // TTGO PoE V1.0 + // constexpr eth_clock_mode_t ETH_CLK = ETH_CLOCK_GPIO0_OUT; // TTGO PoE V1.2 pinMode(ETH_NRST, OUTPUT); digitalWrite(ETH_NRST, 0); From cd76c61196d04f1459bdfedc246bd9485407a150 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sat, 13 Mar 2021 22:28:30 +0100 Subject: [PATCH 53/60] fixing aprs overlay --- src/TaskAprsIs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TaskAprsIs.cpp b/src/TaskAprsIs.cpp index b064e72..032bbcf 100644 --- a/src/TaskAprsIs.cpp +++ b/src/TaskAprsIs.cpp @@ -23,7 +23,7 @@ bool AprsIsTask::setup(std::shared_ptr config, std::shared_ptrsetDestination("APLG1"); String lat = create_lat_aprs(config->beacon.positionLatitude); String lng = create_long_aprs(config->beacon.positionLongitude); - _beaconMsg->getBody()->setData(String("=") + lat + "L" + lng + "a" + config->beacon.message); + _beaconMsg->getBody()->setData(String("=") + lat + "L" + lng + "&" + config->beacon.message); return true; } From d5561e8f103a54af3f4b2509375ead7b533d07f3 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sat, 13 Mar 2021 22:29:42 +0100 Subject: [PATCH 54/60] clang-format for is-cfg.json file --- data/is-cfg.json | 65 ++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/data/is-cfg.json b/data/is-cfg.json index e7674fc..c84a3f5 100644 --- a/data/is-cfg.json +++ b/data/is-cfg.json @@ -1,48 +1,47 @@ { - "callsign":"NOCALL-10", - "wifi": - { + "callsign": "NOCALL-10", + "wifi": { "AP": [ - { "SSID":"YOURSSID", "password":"YOURPASSWORD" } + { + "SSID": "YOURSSID", + "password": "YOURPASSWORD" + } ] }, - "beacon": - { - "message":"LoRa iGATE & Digi, Info: github.com/peterus/LoRa_APRS_iGate", - "position": - { - "latitude":0.000000, - "longitude":0.000000 + "beacon": { + "message": "LoRa iGATE & Digi, Info: github.com/lora-aprs/LoRa_APRS_iGate", + "position": { + "latitude": 0.000000, + "longitude": 0.000000 }, - "timeout":15 + "timeout": 15 }, - "aprs_is": - { - "passcode":"", - "server":"euro.aprs2.net", - "port":14580 + "aprs_is": { + "passcode": "", + "server": "euro.aprs2.net", + "port": 14580 }, - "lora": - { - "frequency_rx":433775000, - "frequency_tx":433775000, - "power":20, - "spreading_factor":12, - "signal_bandwidth":125000, - "coding_rate4":5 + "lora": { + "frequency_rx": 433775000, + "frequency_tx": 433775000, + "power": 20, + "spreading_factor": 12, + "signal_bandwidth": 125000, + "coding_rate4": 5 }, - "display": - { + "display": { "always_on": true, - "timeout":10, - "overwrite_pin":0, + "timeout": 10, + "overwrite_pin": 0, "turn180": true }, - "ftp": - { - "active":false, + "ftp": { + "active": false, "user": [ - { "name":"ftp", "password":"ftp" } + { + "name": "ftp", + "password": "ftp" + } ] }, "ntp_server": "pool.ntp.org" From c72668ecadd8b87a74c5230fae6605569458980e Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sat, 13 Mar 2021 22:45:43 +0100 Subject: [PATCH 55/60] fixing some display timeout issues --- lib/Display/Display.cpp | 14 ++++++++++++-- lib/Display/Display.h | 3 +++ src/TaskDisplay.cpp | 4 ++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/Display/Display.cpp b/lib/Display/Display.cpp index d4f1799..b2c911d 100644 --- a/lib/Display/Display.cpp +++ b/lib/Display/Display.cpp @@ -2,7 +2,7 @@ #include #include -Display::Display() : _disp(0), _statusFrame(0), _displayOff(false) { +Display::Display() : _disp(0), _statusFrame(0), _displayOff(false), _displaySaveMode(false) { } void Display::setup(std::shared_ptr boardConfig) { @@ -27,6 +27,14 @@ void Display::turn180() { _disp->flipScreenVertically(); } +void Display::activateDisplaySaveMode() { + _displaySaveMode = true; +} + +void Display::setDisplayTimeout(time_t timeout) { + _displayTimeout.setTimeout(timeout); +} + void Display::update() { if (_frameTimeout.check()) { if (_statusFrame->isPrio()) { @@ -53,7 +61,9 @@ void Display::update() { _statusFrame->drawStatusPage(bitmap); activateDisplay(); _disp->display(&bitmap); - _displayTimeout.start(); + if (_displaySaveMode) { + _displayTimeout.start(); + } } if (_displayTimeout.check()) { deactivateDisplay(); diff --git a/lib/Display/Display.h b/lib/Display/Display.h index 5fd57dd..fa0aa26 100644 --- a/lib/Display/Display.h +++ b/lib/Display/Display.h @@ -35,6 +35,8 @@ public: void setup(std::shared_ptr boardConfig); void turn180(); + void activateDisplaySaveMode(); + void setDisplayTimeout(time_t timeout); void update(); void addFrame(std::shared_ptr frame); @@ -52,6 +54,7 @@ private: Timer _displayTimeout; bool _displayOff; + bool _displaySaveMode; Display(); Display(const Display &); diff --git a/src/TaskDisplay.cpp b/src/TaskDisplay.cpp index 626b9fb..3a42829 100644 --- a/src/TaskDisplay.cpp +++ b/src/TaskDisplay.cpp @@ -17,6 +17,10 @@ bool DisplayTask::setup(std::shared_ptr config, std::shared_ptr statusFrame = std::shared_ptr(new StatusFrame(TaskManager::instance().getTasks())); Display::instance().setStatusFrame(statusFrame); + if (!config->display.alwaysOn) { + Display::instance().activateDisplaySaveMode(); + Display::instance().setDisplayTimeout(config->display.timeout); + } _stateInfo = config->callsign; return true; } From 92b283e32fe1ec327fb58e5a0f11e96b2e540777 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sat, 13 Mar 2021 23:22:43 +0100 Subject: [PATCH 56/60] display and ethernet fix --- lib/Display/Display.cpp | 1 + src/TaskEth.cpp | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/Display/Display.cpp b/lib/Display/Display.cpp index b2c911d..a34b226 100644 --- a/lib/Display/Display.cpp +++ b/lib/Display/Display.cpp @@ -64,6 +64,7 @@ void Display::update() { if (_displaySaveMode) { _displayTimeout.start(); } + return; } if (_displayTimeout.check()) { deactivateDisplay(); diff --git a/src/TaskEth.cpp b/src/TaskEth.cpp index 9435a5f..a9a5d29 100644 --- a/src/TaskEth.cpp +++ b/src/TaskEth.cpp @@ -70,12 +70,16 @@ bool EthTask::setup(std::shared_ptr config, std::shared_ptr config) { + if (!eth_connected) { + _stateInfo = "Ethernet not connected"; + _state = Error; + return false; + } + _stateInfo = ETH.localIP().toString(); + _state = Okay; return true; } From 948e832905f16e08ad430be409d98f35cfaf63f8 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sun, 14 Mar 2021 00:18:11 +0100 Subject: [PATCH 57/60] clang-check in ci --- .github/workflows/build_check.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/build_check.yml b/.github/workflows/build_check.yml index b537185..b40fa40 100644 --- a/.github/workflows/build_check.yml +++ b/.github/workflows/build_check.yml @@ -54,3 +54,15 @@ jobs: with: name: firmware path: .pio/build/lora_board/firmware.bin + + formatting-check: + name: Formatting Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Run clang-format style check for C/C++ programs. + uses: jidicula/clang-format-action@v3.2.0 + with: + clang-format-version: '11' + check-path: 'src' + From 89afb43ca6360efa63e0edc79d1fe2a6b3a5000f Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sun, 14 Mar 2021 00:51:32 +0100 Subject: [PATCH 58/60] more clang-format --- .github/workflows/build_check.yml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_check.yml b/.github/workflows/build_check.yml index b40fa40..001a24e 100644 --- a/.github/workflows/build_check.yml +++ b/.github/workflows/build_check.yml @@ -58,11 +58,24 @@ jobs: formatting-check: name: Formatting Check runs-on: ubuntu-latest + strategy: + matrix: + path: + - 'src' + - 'lib/BoardFinder' + - 'lib/ConfigurationManagement' + - 'lib/Display' + - 'lib/LoRa' + - 'lib/LoRa_APRS' + - 'lib/NTPClient' + - 'lib/PowerManagement' + - 'lib/TaskManager' + - 'lib/TimeLib' steps: - uses: actions/checkout@v2 - name: Run clang-format style check for C/C++ programs. uses: jidicula/clang-format-action@v3.2.0 with: clang-format-version: '11' - check-path: 'src' + check-path: ${{ matrix.path }} From 7c4265b826213b082bc501c327549621ecc16311 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sun, 14 Mar 2021 00:54:57 +0100 Subject: [PATCH 59/60] update --- .github/workflows/build_check.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_check.yml b/.github/workflows/build_check.yml index 001a24e..83f920a 100644 --- a/.github/workflows/build_check.yml +++ b/.github/workflows/build_check.yml @@ -64,13 +64,13 @@ jobs: - 'src' - 'lib/BoardFinder' - 'lib/ConfigurationManagement' - - 'lib/Display' - - 'lib/LoRa' + #- 'lib/Display' + #- 'lib/LoRa' - 'lib/LoRa_APRS' - - 'lib/NTPClient' + #- 'lib/NTPClient' - 'lib/PowerManagement' - 'lib/TaskManager' - - 'lib/TimeLib' + #- 'lib/TimeLib' steps: - uses: actions/checkout@v2 - name: Run clang-format style check for C/C++ programs. From 64bf24bdd46f1a3136c68e9dea8429b9ff178e38 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Sun, 14 Mar 2021 16:00:14 +0100 Subject: [PATCH 60/60] version bump --- src/LoRa_APRS_iGate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index 533360f..2417f76 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -17,7 +17,7 @@ #include "TaskWifi.h" #include "project_configuration.h" -#define VERSION "21.06.0-dev" +#define VERSION "21.10.0" String create_lat_aprs(double lat); String create_long_aprs(double lng);