From b119b4756518fd81c867b76098611b258ebbbc9c Mon Sep 17 00:00:00 2001 From: Lutz Date: Sat, 11 May 2024 23:31:55 -0700 Subject: [PATCH] V1.13.3 Updates (#243) --- Changelog.md | 9 +- Configuration.hpp | 14 + ConfigurationValidation.hpp | 14 + Configuration_adv.hpp | 22 +- Constants.hpp | 13 +- Version.h | 2 +- platformio.ini | 2 +- src/InfoDisplayRender.hpp | 17 ++ src/MeadeCommandProcessor.cpp | 11 +- src/Mount.cpp | 134 ++++++++- src/Mount.hpp | 34 ++- src/SSD1306_128x64_Display.hpp | 484 +++++++++++++++++++++++++++++++++ src/b_setup.hpp | 44 ++- src/c76_menuCAL.hpp | 35 ++- src/fonts128x64.h | 442 ++++++++++++++++++++++++++++++ 15 files changed, 1239 insertions(+), 38 deletions(-) create mode 100644 src/InfoDisplayRender.hpp create mode 100644 src/SSD1306_128x64_Display.hpp create mode 100644 src/fonts128x64.h diff --git a/Changelog.md b/Changelog.md index 5289940f..ca97316c 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,12 @@ +**V1.13.3 - Updates** +- Allowed ALT steps per revolution to be set directly +- Removed drift alignment and added ability to add it back with define +- Optimized string memory a little +- Lowered ESP32 second core priority +- Added support for informational display + **V1.13.2 - Updates** -- Fix for RA steps being incrrectly set on every boot. +- Fix for RA steps being incorrectly set on every boot. **V1.13.1 - Updates** - Fix for uploading on AVR platform. Apparently atmelavr@5.0.0 (current stable) is broken and can't upload, so we peg it at atmelavr@4.2.0 for now. diff --git a/Configuration.hpp b/Configuration.hpp index 9f975d2a..95585a71 100644 --- a/Configuration.hpp +++ b/Configuration.hpp @@ -61,6 +61,20 @@ #define DISPLAY_TYPE DISPLAY_TYPE_NONE #endif +#ifndef INFO_DISPLAY_TYPE + #define INFO_DISPLAY_TYPE INFO_DISPLAY_TYPE_NONE +#elif (INFO_DISPLAY_TYPE == INFO_DISPLAY_TYPE_I2C_SSD1306_128x64) + #ifndef INFO_DISPLAY_I2C_ADDRESS + #define INFO_DISPLAY_I2C_ADDRESS 0x3C + #endif + #ifndef INFO_DISPLAY_I2C_SDA_PIN + #define INFO_DISPLAY_I2C_SDA_PIN 5 + #endif + #ifndef INFO_DISPLAY_I2C_SCL_PIN + #define INFO_DISPLAY_I2C_SCL_PIN 4 + #endif +#endif + // Used RA wheel version. Unless you printed your OAT before March 2020, you're using // a version 2 or higher (software only differentiates between 1 and more than 1) #ifndef RA_WHEEL_VERSION diff --git a/ConfigurationValidation.hpp b/ConfigurationValidation.hpp index 5441cea3..6660e854 100644 --- a/ConfigurationValidation.hpp +++ b/ConfigurationValidation.hpp @@ -34,6 +34,20 @@ #error Unsupported display configuration. Use at own risk. #endif +// Info Display validations +#if defined(__AVR_ATmega2560__) + #if (INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE) + #if (DISPLAY_TYPE != DISPLAY_TYPE_NONE) + #error Unsupported configuration. Not enough memory to use LCD and OLED at the same time. + #endif + #if (FOCUS_STEPPER_TYPE != STEPPER_TYPE_NONE) + #if (BOARD == BOARD_AVR_MKS_GEN_L_V1) || (BOARD == BOARD_AVR_MKS_GEN_L_V2) || (BOARD == BOARD_AVR_MKS_GEN_L_V21) + #warning OLED requires I2C, so E1 port on a MKS GenL is not available. Make sure you are not attempting to use it. + #endif + #endif + #endif +#endif + #if (RA_DRIVER_TYPE == DRIVER_TYPE_TMC2209_UART) #ifndef RA_DRIVER_ADDRESS // Serial bus address must be specified for TMC2209 in UART mode diff --git a/Configuration_adv.hpp b/Configuration_adv.hpp index e9b202ea..ec68b723 100644 --- a/Configuration_adv.hpp +++ b/Configuration_adv.hpp @@ -69,6 +69,9 @@ #ifndef RA_SLEW_MICROSTEPPING #define RA_SLEW_MICROSTEPPING 8 // Microstep mode set by MS pin strapping. Use the same microstep mode for both slewing & tracking #endif + #if defined(RA_TRACKING_MICROSTEPPING) && (RA_TRACKING_MICROSTEPPING != RA_SLEW_MICROSTEPPING) + #error With A4988 drivers or TMC2209 drivers in Standalone mode, RA microstepping must be the same for slewing and tracking. Delete RA_TRACKING_MICROSTEPPING from your config. + #endif #define RA_TRACKING_MICROSTEPPING RA_SLEW_MICROSTEPPING #else #error Unknown RA driver type @@ -89,6 +92,9 @@ #define DEC_SLEW_MICROSTEPPING \ 16 // Only UART drivers support dynamic switching. Use the same microstep mode for both slewing & guiding #endif + #if defined(DEC_GUIDE_MICROSTEPPING) && (DEC_GUIDE_MICROSTEPPING != DEC_SLEW_MICROSTEPPING) + #error With A4988 drivers or TMC2209 drivers in Standalone mode, DEC microstepping must be the same for slewing and guiding. Delete DEC_GUIDE_MICROSTEPPING from your config. + #endif #define DEC_GUIDE_MICROSTEPPING DEC_SLEW_MICROSTEPPING #else #error Unknown DEC driver type @@ -399,10 +405,11 @@ // the ratio of the ALT gearbox for AutoPA V2 (40:1) #define ALT_WORMGEAR_RATIO (40.0f) #endif - - #define ALTITUDE_STEPS_PER_REV \ - (ALT_CORRECTION_FACTOR * (ALT_CIRCUMFERENCE / (ALT_PULLEY_TEETH * GT2_BELT_PITCH)) * ALT_STEPPER_SPR * ALT_MICROSTEPPING \ - * ALT_WORMGEAR_RATIO) // Actually u-steps/rev + #ifndef ALTITUDE_STEPS_PER_REV + #define ALTITUDE_STEPS_PER_REV \ + (ALT_CORRECTION_FACTOR * (ALT_CIRCUMFERENCE / (ALT_PULLEY_TEETH * GT2_BELT_PITCH)) * ALT_STEPPER_SPR * ALT_MICROSTEPPING \ + * ALT_WORMGEAR_RATIO) // Actually u-steps/rev + #endif #endif #ifndef ALTITUDE_STEPS_PER_ARC_MINUTE @@ -549,6 +556,8 @@ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // /// // FEATURE SUPPORT SECTION /// +// FOR MOUNTS WITH /// +// LCD DISPLAY /// // /// ////////////////////////////// // @@ -589,7 +598,10 @@ #define SUPPORT_MANUAL_CONTROL 0 #define SUPPORT_CALIBRATION 0 #define SUPPORT_INFO_DISPLAY 0 - + #if SUPPORT_DRIFT_ALIGNMENT == 1 + #error "Drift Alignment is only available with a display." + #endif + #define SUPPORT_DRIFT_ALIGNMENT 0 #endif // DISPLAY_TYPE // Enable Meade protocol communication over serial diff --git a/Constants.hpp b/Constants.hpp index 0bebe043..1a5387a3 100644 --- a/Constants.hpp +++ b/Constants.hpp @@ -20,7 +20,7 @@ #define BOARD_ESP32_ESP32DEV 1001 /** - * Supported display types. Use one of these values for DISPLAY_TYPE configuration matching your used display. + * Supported keypad/display types. Use one of these values for DISPLAY_TYPE configuration matching your used display and keypad. * * DISPLAY_TYPE_NONE: No display. Use this if you don't use any display. * DISPLAY_TYPE_LCD_KEYPAD: 1602 LCD Keypad shield which can be mounted directly to an Arduino UNO / Mega boards. @@ -39,6 +39,16 @@ #define DISPLAY_TYPE_LCD_KEYPAD_I2C_MCP23017 3 #define DISPLAY_TYPE_LCD_JOY_I2C_SSD1306 4 +/** + * Supported info display types. Use one of these values for INF_DISPLAY_TYPE configuration matching your used display. + * + * INFO_DISPLAY_TYPE_NONE: No display. Use this if you don't use any display. + * INFO_DISPLAY_TYPE_SSD1306_I2C_128x64: I2C 128x64 OLED display module with SSD1306 controller, attached via I2C + * Amazon: https://www.amazon.com/dp/B06XRBTBTB?_encoding=UTF8&psc=1&ref_=cm_sw_r_cp_ud_dp_DQCWKZ7YB40X84RZSHJ0 + **/ +#define INFO_DISPLAY_TYPE_NONE 0 +#define INFO_DISPLAY_TYPE_I2C_SSD1306_128x64 1 + // Supported stepper models #define STEPPER_TYPE_NONE -1 #define STEPPER_TYPE_ENABLED 1 @@ -81,4 +91,5 @@ #define DEBUG_GPS 0x0800 // GPS activity #define DEBUG_FOCUS 0x1000 // Focuser activity #define DEBUG_COORD_CALC 0x2000 // Calculations of coordinates +#define DEBUG_DISPLAY 0x4000 // Info display #define DEBUG_ANY 0xFFFF // All debug output diff --git a/Version.h b/Version.h index e411922b..28e05907 100644 --- a/Version.h +++ b/Version.h @@ -3,4 +3,4 @@ // Also, numbers are interpreted as simple numbers. _ __ _ // So 1.8 is actually 1.08, meaning that 1.12 is a later version than 1.8. \_(..)_/ -#define VERSION "V1.13.2" +#define VERSION "V1.13.3" diff --git a/platformio.ini b/platformio.ini index b25ac4a7..fec30a35 100644 --- a/platformio.ini +++ b/platformio.ini @@ -13,6 +13,7 @@ lib_deps = arduino-libraries/LiquidCrystal @ ^1.0.7 lincomatic/LiquidTWI2@^1.2.7 olikraus/U8g2@^2.28.8 + https://github.com/ClutchplateDude/esp8266-oled-ssd1306@4.5.1 [env] extra_scripts = @@ -71,7 +72,6 @@ debug_init_break = ; Always upload firmware when initializing a debug session debug_load_mode = always - [env:ramps] extends = common_embedded ; atmelavr@5.0.0 is currently broken (can't upload, gets stk500v2_recv errors) diff --git a/src/InfoDisplayRender.hpp b/src/InfoDisplayRender.hpp new file mode 100644 index 00000000..ed8cf2a5 --- /dev/null +++ b/src/InfoDisplayRender.hpp @@ -0,0 +1,17 @@ +#pragma once +#include + +class Mount; + +// Base class to implement a +class InfoDisplayRender +{ + public: + InfoDisplayRender() {}; + + virtual void init() {}; + virtual void render(Mount *mount) {}; + virtual void setConsoleMode(bool active) {}; + virtual int addConsoleText(String text, bool tinyFont = true); + virtual void updateConsoleText(int line, String newText); +}; diff --git a/src/MeadeCommandProcessor.cpp b/src/MeadeCommandProcessor.cpp index e5eabd97..3eff94f4 100644 --- a/src/MeadeCommandProcessor.cpp +++ b/src/MeadeCommandProcessor.cpp @@ -640,7 +640,7 @@ bool gpsAqcuisitionComplete(int &indicator); // defined in c72_menuHA_GPS.hpp // // :XDnnn# // Description: -// Run drift alignment +// Run drift alignment (only supported if SUPPORT_DRIFT_ALIGNMENT is enabled) // Information: // This runs a drift alignment procedure where the mounts slews east, pauses, slews west and pauses. // Where nnn is the number of seconds the entire alignment should take. The call is blocking and will @@ -1450,7 +1450,7 @@ String MeadeCommandProcessor::handleMeadeSetInfo(String inCmd) SC: Calendar: If the date is valid 2 s are returned, each string is 31 bytes long. The first is: "Updating planetary data#" followed by a second string of 30 spaces terminated by '#' */ - return "1Updating Planetary Data# #"; // + return F("1Updating Planetary Data# #"); // } else { @@ -1654,7 +1654,7 @@ String MeadeCommandProcessor::handleMeadeDistance(String inCmd) ///////////////////////////// String MeadeCommandProcessor::handleMeadeExtraCommands(String inCmd) { - // 0123 +#if SUPPORT_DRIFT_ALIGNMENT == 1 // :XDmmm if (inCmd[0] == 'D') // :XD { // Drift Alignemnt @@ -1682,7 +1682,9 @@ String MeadeCommandProcessor::handleMeadeExtraCommands(String inCmd) _lcdMenu->setCursor(0, 1); _mount->startSlewing(TRACKING); } - else if (inCmd[0] == 'G') + else +#endif + if (inCmd[0] == 'G') { // Get RA/DEC steps/deg, speedfactor if (inCmd[1] == 'R') // :XGR# { @@ -2131,6 +2133,7 @@ String MeadeCommandProcessor::processCommand(String inCmd) LOG(DEBUG_MEADE, "[MEADE]: Processing command '%s'", inCmd.c_str()); char command = inCmd[1]; inCmd = inCmd.substring(2); + _mount->commandReceived(); switch (command) { case 'S': diff --git a/src/Mount.cpp b/src/Mount.cpp index 5ca1ceae..233ed1ec 100644 --- a/src/Mount.cpp +++ b/src/Mount.cpp @@ -16,6 +16,9 @@ PUSH_NO_WARNINGS #endif #endif +#if (INFO_DISPLAY_TYPE == INFO_DISPLAY_TYPE_I2C_SSD1306_128x64) + #include "SSD1306_128x64_Display.hpp" +#endif #include #if (RA_DRIVER_TYPE == DRIVER_TYPE_TMC2209_UART) || (DEC_DRIVER_TYPE == DRIVER_TYPE_TMC2209_UART) \ @@ -82,6 +85,10 @@ Mount::Mount(LcdMenu *lcdMenu) #endif { + _commandReceived = 0; +#if (INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE) + _loops = 0; +#endif _lcdMenu = lcdMenu; initializeVariables(); } @@ -1078,6 +1085,15 @@ String Mount::getMountHardwareInfo() ret += F("LCD_JOY_I2C_SSD1306,"); #endif +#if INFO_DISPLAY_TYPE == DISPLAY_TYPE_NONE + ret += F("NO_INFO_DISP,"); +#elif INFO_DISPLAY_TYPE == INFO_DISPLAY_TYPE_I2C_SSD1306_128x64 + ret += F("INFO_I2C_SSD1306_128x64,"); + // To add new display types, format this string in the same way: INFO___ +#else + ret += F("INFO_UNKNOWN,"); +#endif + #if FOCUS_STEPPER_TYPE == STEPPER_TYPE_NONE ret += F("NO_FOC,"); #else @@ -1592,10 +1608,26 @@ void Mount::guidePulse(byte direction, int duration) _guideRaEndTime = millis() + duration; break; } +// Since we will not be updating the display during a guide pulse, update the display here. +#if INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE + updateInfoDisplay(); +#endif LOG(DEBUG_STEPPERS, "[STEPPERS]: guidePulse: < Guide Pulse"); } +///////////////////////////////// +// +// commandReceived() +// +// Keeps track of how many Meade commands have been processed. +///////////////////////////////// +void Mount::commandReceived() +{ + _commandReceived++; +} + +#if SUPPORT_DRIFT_ALIGNMENT == 1 ///////////////////////////////// // // runDriftAlignmentPhase @@ -1644,6 +1676,7 @@ void Mount::runDriftAlignmentPhase(int direction, int durationSecs) break; } } +#endif ///////////////////////////////// // @@ -2057,48 +2090,58 @@ void Mount::clearStatusFlag(int flag) // getStatusString // ///////////////////////////////// -String Mount::getStatusString() +String Mount::getStatusStateString() { String status; if (_mountStatus == STATUS_PARKED) { - status = F("Parked,"); + status = F("Parked"); } else if ((_mountStatus & STATUS_PARKING) || (_mountStatus & STATUS_PARKING_POS)) { - status = F("Parking,"); + status = F("Parking"); } else if (isFindingHome()) { - status = F("Homing,"); + status = F("Homing"); } else if (isGuiding()) { - status = F("Guiding,"); + status = F("Guiding"); } else if (slewStatus() & SLEW_MASK_ANY) { if (_mountStatus & STATUS_SLEWING_TO_TARGET) { - status = F("SlewToTarget,"); + status = F("SlewToTarget"); } else if (_mountStatus & STATUS_SLEWING_FREE) { - status = F("FreeSlew,"); + status = F("FreeSlew"); } else if (_mountStatus & STATUS_SLEWING_MANUAL) { - status = F("ManualSlew,"); + status = F("ManualSlew"); } else if (slewStatus() & SLEWING_TRACKING) { - status = F("Tracking,"); + status = F("Tracking"); } } else { - status = "Idle,"; + status = "Idle"; } + return status; +} +///////////////////////////////// +// +// getStatusString +// +///////////////////////////////// +String Mount::getStatusString() +{ + String status = getStatusStateString() + ","; String disp = "------,"; if (_mountStatus & STATUS_SLEWING) @@ -2181,7 +2224,7 @@ byte Mount::mountStatus() const ///////////////////////////////// bool Mount::isGuiding() const { - return (_mountStatus & STATUS_GUIDE_PULSE); + return (_mountStatus & STATUS_GUIDE_PULSE) != 0; } ///////////////////////////////// @@ -2987,8 +3030,44 @@ void Mount::loop() #endif _stepperWasRunning = raStillRunning || decStillRunning; +#if INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE + updateInfoDisplay(); +#endif } +#if (INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE) +void Mount::setupInfoDisplay() +{ + #if (INFO_DISPLAY_TYPE == INFO_DISPLAY_TYPE_I2C_SSD1306_128x64) + LOG(DEBUG_DISPLAY, "[DISPLAY]: Create SSD1306 OLED class..."); + infoDisplay = new SDD1306OLED128x64(INFO_DISPLAY_I2C_ADDRESS, INFO_DISPLAY_I2C_SDA_PIN, INFO_DISPLAY_I2C_SCL_PIN); + LOG(DEBUG_ANY, "[SYSTEM]: SSD1306 OLED created... initializing"); + infoDisplay->init(); + LOG(DEBUG_DISPLAY, "[DISPLAY]: Created and initialized SSD1306 OLED class..."); + #endif +} + +void Mount::updateInfoDisplay() +{ + #if (INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE) + _loops++; + // Update display every 8 cycles + if (_loops % 8 == 0) + { + LOG(DEBUG_DISPLAY, "[DISPLAY]: Render state to OLED ..."); + infoDisplay->render(this); + LOG(DEBUG_DISPLAY, "[DISPLAY]: Rendered state to OLED ..."); + } + #endif +} + +InfoDisplayRender *Mount::getInfoDisplay() +{ + return infoDisplay; +} + +#endif + ///////////////////////////////// // // bootComplete @@ -3471,6 +3550,39 @@ void Mount::moveStepperTo(StepperAxis axis, long position) moveStepperBy(axis, delta); } +///////////////////////////////// +// +// getStepperProgress +// +///////////////////////////////// +bool Mount::getStepperProgress(int &raPercentage, int &decPercentage) +{ + bool slewInProgress = true; + decPercentage = 100; + raPercentage = 100; + if ((fabsf(_totalDECMove) > 0.001f) && (fabsf(_totalRAMove) > 0.001f)) + { + // Both axes moving to target + decPercentage = (int) round(100.0f - 100.0f * _stepperDEC->distanceToGo() / _totalDECMove); + raPercentage = (int) round(100.0f - 100.0f * _stepperRA->distanceToGo() / _totalRAMove); + } + else if (fabsf(_totalDECMove) > 0.001f) + { + // Only DEC moving to target + decPercentage = (int) round(100.0f - 100.0f * _stepperDEC->distanceToGo() / _totalDECMove); + } + else if (fabsf(_totalRAMove) > 0.001f) + { + // Only RA is moving to target + raPercentage = (int) round(100.0f - 100.0f * _stepperRA->distanceToGo() / _totalRAMove); + } + else + { + // Nothing is slewing + slewInProgress = false; + } + return slewInProgress; +} ///////////////////////////////// // // displayStepperPosition diff --git a/src/Mount.hpp b/src/Mount.hpp index 5cf4c31d..aa0f7d6e 100644 --- a/src/Mount.hpp +++ b/src/Mount.hpp @@ -6,6 +6,10 @@ #include "Longitude.hpp" #include "Types.hpp" +#if (INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE) +class InfoDisplayRender; +#endif + #ifdef NEW_STEPPER_LIB #include "StepperConfiguration.hpp" @@ -374,19 +378,41 @@ class Mount // Return a string of DEC in the given format. For LCDSTRING, active determines where the cursor is String RAString(byte type, byte active = 0); + // Returns string (singfle word) representing the mounts status. + String getStatusStateString(); + // Returns a comma-delimited string with all the mounts' information String getStatusString(); + void setStatusFlag(int flag); void clearStatusFlag(int flag); // Get the current speed of the stepper. NORTH, WEST, TRACKING float getSpeed(int direction); + // See if a slew to target is in progress and return the percentage along the path + bool getStepperProgress(int &raPercentage, int &decPercentage); + // Displays the current location of the mount every n ms, where n is defined in Globals.h as DISPLAY_UPDATE_TIME void displayStepperPositionThrottled(); +#if (INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE) + void setupInfoDisplay(); + void updateInfoDisplay(); + InfoDisplayRender *getInfoDisplay(); + long _loops; +#endif + // Called by Meade processor every time a command is received. + void commandReceived(); + long getNumCommandsReceived() + { + return _commandReceived; + } + +#if SUPPORT_DRIFT_ALIGNMENT == 1 // Runs a phase of the drift alignment procedure void runDriftAlignmentPhase(int direction, int durationSecs); +#endif // Toggle the state where we run the motors at a constant speed void setManualSlewMode(bool state); @@ -475,6 +501,9 @@ class Mount // Returns the remaining tracking time available and stops tracking if it reaches zero. float checkRALimit(); + // Calculate the stepper positions for the current target coordinates + void calculateRAandDECSteppers(long &targetRASteps, long &targetDECSteps, long pSolutions[6] = nullptr) const; + #if UART_CONNECTION_TEST_TX == 1 #if RA_DRIVER_TYPE == DRIVER_TYPE_TMC2209_UART void testRA_UART_TX(); @@ -493,7 +522,6 @@ class Mount // Reads values from EEPROM that configure the mount (if previously stored) void readPersistentData(); - void calculateRAandDECSteppers(long &targetRASteps, long &targetDECSteps, long pSolutions[6] = nullptr) const; void displayStepperPosition(); void moveSteppersTo(float targetRA, float targetDEC, StepperAxis direction); @@ -501,6 +529,9 @@ class Mount private: LcdMenu *_lcdMenu; +#if (INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE) + InfoDisplayRender *infoDisplay; +#endif float _stepsPerRADegree; // u-steps/degree when slewing (see RA_STEPS_PER_DEGREE) float _stepsPerDECDegree; // u-steps/degree when slewing (see DEC_STEPS_PER_DEGREE) uint32_t _maxRASpeed; @@ -538,6 +569,7 @@ class Mount float _totalRAMove; Latitude _latitude; Longitude _longitude; + long _commandReceived; // Stepper control for RA, DEC and TRK. #ifdef NEW_STEPPER_LIB diff --git a/src/SSD1306_128x64_Display.hpp b/src/SSD1306_128x64_Display.hpp new file mode 100644 index 00000000..f3e04ed4 --- /dev/null +++ b/src/SSD1306_128x64_Display.hpp @@ -0,0 +1,484 @@ +#pragma once +#include "SSD1306Wire.h" +#include "Utility.hpp" +#include "Version.h" +#include "fonts128x64.h" +#include "Mount.hpp" +#include "InfoDisplayRender.hpp" + +const float sineSize = 18.0; +const uint8_t sineTable[] PROGMEM = {0, 22, 44, 66, 87, 108, 128, 146, 164, 180, 195, 209, 221, 231, 240, 246, 251, 254, 255, 255}; + +// This class renders the mount status to a 128x64 pixel display controlled by a SSD1306 chip. +class SDD1306OLED128x64 : public InfoDisplayRender +{ +#ifdef OAM + const float bottomDEC = -180.0f; + const float rangeDEC = 360.0; +#else + const float bottomDEC = -90.0f; + const float rangeDEC = 270.0; +#endif + const float leftRA = -6.0f; + const float rightRA = 6.0f; + + const int _leftEdgeMount = 69; // x pos of start of scale + const int _raSize = 41; // width of ra scale + const int _raScalePos = 51; // Y pos of ra scale dotted line + + const int _topEdgeMount = 14; + const int _decSize = 43; + const int _decScalePos = 115; + + const int yMaxStatus = 63 - 11; + + SSD1306Wire *display; + int _sizeMount; + int _yStatus; + int _dirStatus; + char _commLetter; + long _lastNumCmds; + long _lastUpdate; + bool _consoleMode; + String _textList[6]; // At most 6 lines of text in console mode + int _curLine; + + public: + SDD1306OLED128x64(byte addr, int sda, int scl) : InfoDisplayRender() + { + display = new SSD1306Wire(addr, sda, scl, GEOMETRY_128_64); + _sizeMount = 128 - _leftEdgeMount; + _consoleMode = true; + _curLine = 0; + _yStatus = 0; + _dirStatus = 1; + _commLetter = ' '; + for (int i = 0; i < 6; i++) + { + _textList[i] = ""; + } + } + + // Initialize the display + virtual void init() + { + display->init(); + display->clear(); + display->displayOn(); + }; + + // Build the display from the mount + virtual void render(Mount *mount) + { + display->clear(); + if (_consoleMode) + { + display->setColor(WHITE); + + // Logo on the left + display->setFont(OATLogo); + display->drawString(0, 0, "!"); + + // Name on the right + display->setFont(Bitmap5x7); +#ifdef OAM + display->drawString(32, 6, F("OpenAstroMount")); +#else + display->drawString(32, 6, F("OpenAstroTracker")); +#endif + + // Other lines + int y = 21; + display->setFont(Bitmap3x5); + for (int i = 0; i < 6; i++) + { + if (_textList[i].length() != 0) + { + display->drawString(0, y, _textList[i]); + } + y += 7; + } + } + else + { + drawIndicators(mount); + } + display->display(); + }; + + virtual void setConsoleMode(bool active) + { + _consoleMode = active; + }; + + virtual int addConsoleText(String text, bool tinyFont) + { + _textList[_curLine++] = text; + render(NULL); + return _curLine - 1; + }; + + virtual void updateConsoleText(int line, String text) + { + _textList[line] = text; + render(NULL); + }; + + // Display the tiem left before tracking hits the limit + void drawTime(Mount *mount, String label, const DayTime &time) + { + char achTemp[24]; + display->setColor(WHITE); + display->setFont(Bitmap3x5); + sprintf(achTemp, "%s%02d:%02d", label.c_str(), time.getHours(), time.getMinutes()); + display->drawString(55, 59, achTemp); + } + + // Draw all the indicators on screen + void drawIndicators(Mount *mount) + { + char scratchBuffer[24]; + display->setFont(Bitmap5x7); + display->setColor(WHITE); + + drawStepperStates(mount); + int ra, dec; + // If a slew is in progress, we don't display the safe time, version, and + // comms indicator, since the progress bar takes up the same space + if (mount->getStepperProgress(ra, dec)) + { + drawProgressBar(ra, dec); + } + else + { + long timeSecs = millis() / 2000; // Change every 2 secs + int index = timeSecs % 5; // Cycle through multiple data displays + + display->setFont(CommSymbols); + display->drawString(11, 59, F("L")); // Memory chip icon + display->setFont(Bitmap3x5); + long availMem = freeMemory(); + if (availMem > 9999) + { + display->drawString(20, 59, String(availMem / 1024) + "K"); + } + else + { + display->drawString(20, 59, String(availMem)); + } + + switch (index) + { + case 0: + { + float hoursLeft = mount->checkRALimit(); + DayTime dt(hoursLeft); + drawTime(mount, F("REM "), dt); + } + break; + case 1: + { + drawTime(mount, F("LST "), mount->calculateLst()); + } + break; + case 2: + { + long now = millis(); + long msPerDay = 60L * 60 * 24 * 1000; + int days = (int) (now / msPerDay); + now -= days * msPerDay; + DayTime elapsed(1.0 * now / (1000.0 * 3600.0)); + drawTime(mount, F("UPT "), elapsed); + } + break; + case 3: + { + display->drawString(55, 59, (String(F(" FW ")) + String(VERSION)).c_str()); + } + break; + case 4: + { + float lat = fabsf(mount->latitude().getTotalHours()); + float lng = fabsf(mount->longitude().getTotalHours()); + const char dirLat = (mount->latitude().getTotalHours() < 0) ? 'S' : 'N'; + const char dirLong = (mount->longitude().getTotalHours() < 0) ? 'W' : 'E'; + sprintf(scratchBuffer, "LOC %s%c %s%c", String(lat, 0).c_str(), dirLat, String(lng, 0).c_str(), dirLong); + display->drawString(55, 59, scratchBuffer); + } + break; + } + drawCommunicationStatus(mount); + } + drawCoordinates(mount); + drawMountPosition(mount); + drawStatus(mount); + } + + // Display two 2-pixel high progress bar in the last 4 lines of the display + void drawProgressBar(int percRA, int percDEC) + { + display->setColor(WHITE); + display->drawVerticalLine(127, 60, 4); + int raWidth = round(1.28f * percRA); + display->fillRect(0, 60, raWidth, 2); + int decWidth = round(1.28f * percDEC); + display->fillRect(0, 62, decWidth, 2); + } + + // Display a rectangle with the stepper label in it + void drawStepperState(String name, bool active, int xoff, int width, int textOffX = 0) + { + display->setColor(WHITE); + if (active) + { + display->fillRect(xoff, 0, width, 11); + } + else + { + display->drawRect(xoff, 0, width, 11); + } + display->setColor(INVERSE); + display->drawString(xoff + 2 + textOffX, 2, name); + } + + // Display all the configured stepper status rectangles + // Focuser is currently not supported, but could be added here, if possible. + void drawStepperStates(Mount *mount) + { + display->setFont(Bitmap5x7); + drawStepperState(F("RA"), mount->isAxisRunning(RA_STEPS), 0, 15); + drawStepperState(F("DEC"), mount->isAxisRunning(DEC_STEPS), 16, 21); +#if (ALT_STEPPER_TYPE != STEPPER_TYPE_NONE) + drawStepperState(F("ALT"), mount->isRunningALT(), 38, 21); +#endif +#if (AZ_STEPPER_TYPE != STEPPER_TYPE_NONE) + drawStepperState(F("AZ"), mount->isRunningAZ(), 60, 16); +#endif + drawStepperState(F("GDE"), mount->isGuiding(), 83, 21); + drawStepperState(F("TRK"), mount->isSlewingTRK(), 105, 23, 1); + } + + void drawCommunicationStatus(Mount *mount) + { + long recvdCmds = mount->getNumCommandsReceived(); + // If we have received any commands since the last display, draw the marker. + + if (_commLetter != ' ') + { + display->setFont(CommSymbols); + display->drawString(1, 59, String(_commLetter)); + _commLetter++; + if (_commLetter == 'G') // Past last communication animation frame (F) + { + _commLetter = ' '; + } + } + else if (recvdCmds != _lastNumCmds) + { + _commLetter = 'C'; // First communication animation frame + _lastNumCmds = recvdCmds; + } + } + + // Draw the given coordinate string at the given point + void drawCoordinate(int x, int y, const char *coord) + { + char achCoord[30]; + char *n = achCoord; + // Since this is not a full font, remap the supported letters to the right character + for (const char *p = coord; *p != 0; p++) + { + switch (*p) + { + case 'R': + *n = '!'; + break; + case 'A': + *n = '&'; + break; + case 'D': + *n = '#'; + break; + case 'E': + *n = '$'; + break; + case 'C': + *n = '%'; + break; + case 'h': + *n = '<'; + break; + case 'm': + *n = ';'; + break; + case 's': + *n = '='; + break; + case '@': + *n = '('; + break; + default: + *n = *p; + break; + } + n++; + } + *n = 0; + display->setFont(Bitmap7x15); + display->setColor(WHITE); + display->drawString(x, y, achCoord); + } + + // Draw the mounts celestial RA and DEC coordinates + void drawCoordinates(Mount *mount) + { + String rc = mount->RAString(LCD_STRING | CURRENT_STRING); + String dc = mount->DECString(LCD_STRING | CURRENT_STRING); + drawCoordinate(8, 24, rc.c_str()); + drawCoordinate(0, 42, dc.c_str()); + } + + // Map the given RA coordinate to the pixel position on the display + int xRAPixel(float ra) + { + float rangeRA = rightRA - leftRA; + int x = 4 + (int) round(1.0f * (_raSize - 9) * ((ra - leftRA) / rangeRA)); + return (_leftEdgeMount + x); + } + + // Map the given DEC coordinate to the pixel position on the display + int yDECPixel(float dec) + { + int y = (int) round(1.0f * (_decSize) * ((dec - bottomDEC) / rangeDEC)); + return (_topEdgeMount + _decSize - y); + } + + // Draw the rectangle with the current and target positions + void drawMountPosition(Mount *mount) + { + display->setColor(WHITE); + display->setFont(Bitmap3x5); + + // DEC tickmarks + for (int p = _topEdgeMount; p <= _topEdgeMount + _decSize; p += 2) + { + display->setPixel(_decScalePos, p); + } +#ifdef OAM + display->drawHorizontalLine(_decScalePos - 1, yDECPixel(-180.0), 2); +#endif + display->drawHorizontalLine(_decScalePos - 1, yDECPixel(-90.0), 2); + display->drawHorizontalLine(_decScalePos - 1, yDECPixel(0.0), 2); + display->drawHorizontalLine(_decScalePos - 1, yDECPixel(90.0), 2); + display->drawHorizontalLine(_decScalePos - 1, yDECPixel(180.0), 2); +// DEC tickmark labels +#ifdef OAM + display->drawString(_decScalePos + 6, yDECPixel(-180.0f) - 2, F("180")); + display->drawHorizontalLine(_decScalePos + 3, yDECPixel(-180.0), 2); // Smaller minus sign +#endif + display->drawString(_decScalePos + 6, yDECPixel(-90.0f) - 2, F("90")); + display->drawHorizontalLine(_decScalePos + 3, yDECPixel(-90.0), 2); // Smaller minus sign + display->drawString(_decScalePos + 3, yDECPixel(0.0f) - 2, "0"); + display->drawString(_decScalePos + 3, yDECPixel(90.0f) - 2, F("90")); + display->drawString(_decScalePos + 3, yDECPixel(180.0f) - 2, F("180")); + + // DEC Pos Marker + float decStepsPerDeg = mount->getStepsPerDegree(StepperAxis::DEC_STEPS); + long decSteps = mount->getCurrentStepperPosition(StepperAxis::DEC_STEPS); + float decDegrees = decSteps / decStepsPerDeg; + int yMark = yDECPixel(decDegrees); + display->setPixel(_decScalePos - 2, yMark); + display->drawVerticalLine(_decScalePos - 3, yMark - 1, 3); + display->drawVerticalLine(_decScalePos - 4, yMark - 2, 5); + + // RA tickmarks + for (int p = _leftEdgeMount; p <= _leftEdgeMount + _raSize; p += 2) + { + display->setPixel(p, _raScalePos); + } + display->drawVerticalLine(xRAPixel(-6.0f), _raScalePos - 1, 2); + display->drawVerticalLine(xRAPixel(-3.0f), _raScalePos - 1, 2); + display->drawVerticalLine(xRAPixel(0.0f), _raScalePos - 1, 2); + display->drawVerticalLine(xRAPixel(3.0f), _raScalePos - 1, 2); + display->drawVerticalLine(xRAPixel(6.0f), _raScalePos - 1, 2); + + // RA tickmark labels + display->drawString(xRAPixel(-6.0f) - 1, _raScalePos + 2, "6"); + display->drawHorizontalLine(xRAPixel(-6.0f) - 4, _raScalePos + 2 + 2, 2); // Smaller minus sign + display->drawString(xRAPixel(-3.0f) - 1, _raScalePos + 2, "3"); + display->drawHorizontalLine(xRAPixel(-3.0f) - 4, _raScalePos + 2 + 2, 2); // Smaller minus sign + display->drawString(xRAPixel(0.0f) - 1, _raScalePos + 2, "0"); + display->drawString(xRAPixel(3.0f) - 1, _raScalePos + 2, "3"); + display->drawString(xRAPixel(6.0f) - 1, _raScalePos + 2, "6"); + + float raStepsPerDeg = mount->getStepsPerDegree(StepperAxis::RA_STEPS); + float trkSteps = 1.0f * mount->getCurrentStepperPosition(TRACKING) / (1.0f * RA_TRACKING_MICROSTEPPING / RA_SLEW_MICROSTEPPING); + long raSteps = mount->getCurrentStepperPosition(StepperAxis::RA_STEPS); + float raHours = (trkSteps + raSteps) / raStepsPerDeg / 15.0f; + + // RA Position Marker + int xMark = xRAPixel(raHours); + display->setPixel(xMark, _raScalePos - 2); + display->drawHorizontalLine(xMark - 1, _raScalePos - 3, 3); + display->drawHorizontalLine(xMark - 2, _raScalePos - 4, 5); + } + + // Display the tiem left before tracking hits the limit + void drawSafeTime(Mount *mount) + { + char achTemp[10]; + float hoursLeft = mount->checkRALimit(); + DayTime dt(hoursLeft); + display->setColor(WHITE); + display->setFont(CommSymbols); + display->drawString(48, 59, "M"); // Clock sign + display->setFont(Bitmap3x5); + sprintf(achTemp, "%02d:%02d", dt.getHours(), dt.getMinutes()); + display->drawString(55, 59, achTemp); + } + + float sinLookup(float deg) + { + while (deg < 0.0f) + deg += 360.0f; + while (deg > 360.0f) + deg -= 360.0f; + + if (deg <= 90) + { + int index = (int) roundf(sineSize * deg / 90.0f); + return 1.0f * pgm_read_byte(sineTable + index) / 255.0; + } + else if (deg <= 180) + { + int index = (int) roundf(sineSize * (180.0f - deg) / 90.0f); + return 1.0f * pgm_read_byte(sineTable + index) / 255.0; + } + else if (deg <= 270) + { + int index = (int) roundf(sineSize * (deg - 180.0f) / 90.0f); + return -1.0f * pgm_read_byte(sineTable + index) / 255.0; + } + else if (deg <= 360) + { + int index = (int) roundf(sineSize * (360.0f - deg) / 90.0f); + return -1.0f * pgm_read_byte(sineTable + index) / 255.0; + } + return 0.0f; + } + + // Display the mount status string + void drawStatus(Mount *mount) + { + display->setColor(WHITE); + display->setFont(Bitmap5x7); + String state = mount->getStatusStateString(); + state.toUpperCase(); + display->drawString(4, 14, state.c_str()); + + // Bouncing pixel (bounce frequency every 1.5s). 180 degrees is one cap. + float deg = 180.0f * (millis() % 1500) / 1500.0f; + int pixPos = (int) round(1.0f * yMaxStatus * sinLookup(deg)); + display->setPixel(0, 11 + yMaxStatus - pixPos); + } +}; diff --git a/src/b_setup.hpp b/src/b_setup.hpp index 59012877..310716d2 100644 --- a/src/b_setup.hpp +++ b/src/b_setup.hpp @@ -21,6 +21,9 @@ POP_NO_WARNINGS #include "a_inits.hpp" #include "LcdMenu.hpp" #include "LcdButtons.hpp" +#if (INFO_DISPLAY_TYPE == INFO_DISPLAY_TYPE_I2C_SSD1306_128x64) + #include "SSD1306_128x64_Display.hpp" +#endif LcdMenu lcdMenu(16, 2, MAXMENUITEMS); #if DISPLAY_TYPE == DISPLAY_TYPE_LCD_KEYPAD @@ -110,6 +113,13 @@ void setup() LOG(DEBUG_ANY, "[SYSTEM]: Hello, universe, this is OAT %s!", VERSION); +#if (INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE) + LOG(DEBUG_ANY, "[SYSTEM]: Get OLED info screen ready..."); + mount.setupInfoDisplay(); + LOG(DEBUG_ANY, "[SYSTEM]: OLED info screen ready!"); + mount.getInfoDisplay()->addConsoleText(F("BOOTING " VERSION), false); +#endif + #if USE_GPS == 1 GPS_SERIAL_PORT.begin(GPS_BAUD_RATE); #endif @@ -219,8 +229,17 @@ void setup() pinMode(DEC_HOMING_SENSOR_PIN, INPUT); #endif +#if (INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE) + int eepromLine = mount.getInfoDisplay()->addConsoleText(F("INIT EEPROM...")); +#endif + LOG(DEBUG_ANY, "[SYSTEM]: Get EEPROM store ready..."); EEPROMStore::initialize(); + LOG(DEBUG_ANY, "[SYSTEM]: EEPROM store ready!"); + +#if (INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE) + mount.getInfoDisplay()->updateConsoleText(eepromLine, F("INIT EEPROM... OK")); +#endif // Calling the LCD startup here, I2C can't be found if called earlier #if DISPLAY_TYPE != DISPLAY_TYPE_NONE @@ -307,6 +326,10 @@ void setup() wifiControl.setup(); #endif +#if (INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE) + int stepperLine = mount.getInfoDisplay()->addConsoleText(F("INIT STEPPERS...")); +#endif + // Configure the mount // Delay for a while to get UARTs booted... delay(1000); @@ -416,6 +439,14 @@ void setup() #endif #endif +#if (INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE) + mount.getInfoDisplay()->updateConsoleText(stepperLine, F("INIT STEPPERS... OK")); +#endif + +#if (INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE) + mount.getInfoDisplay()->addConsoleText(F("CONFIGURING...")); +#endif + LOG(DEBUG_ANY, "[SYSTEM]: Read Configuration..."); // The mount uses EEPROM storage locations 0-10 that it reads during construction @@ -441,7 +472,7 @@ void setup() "StepperControl", // Name of this task 32767, // Stack space in bytes &mount, // payload - 2, // Priority (2 is higher than 1) + 1, // Priority (2 is higher than 1) &StepperTask, // The location that receives the thread id 0); // The core to run this on @@ -456,6 +487,9 @@ void setup() #endif #if UART_CONNECTION_TEST_TX == 1 + #if (INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE) + int testLine = mount.getInfoDisplay()->addConsoleText(F("TEST STEPPERS...")); + #endif #if RA_DRIVER_TYPE == DRIVER_TYPE_TMC2209_UART LOG(DEBUG_STEPPERS, "[STEPPERS]: Moving RA axis using UART commands..."); mount.testRA_UART_TX(); @@ -467,6 +501,9 @@ void setup() mount.testDEC_UART_TX(); LOG(DEBUG_STEPPERS, "[STEPPERS]: Finished moving DEC axis using UART commands."); #endif + #if (INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE) + mount.getInfoDisplay()->updateConsoleText(testLine, F("TEST STEPPERS... OK")); + #endif #endif LOG(DEBUG_ANY, "[SYSTEM]: Setting %s hemisphere...", inNorthernHemisphere ? "northern" : "southern"); @@ -480,4 +517,9 @@ void setup() mount.bootComplete(); LOG(DEBUG_ANY, "[SYSTEM]: Boot complete!"); +#if (INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE) + mount.getInfoDisplay()->addConsoleText(F("BOOT COMPLETE!")); + delay(250); + mount.getInfoDisplay()->setConsoleMode(false); +#endif } diff --git a/src/c76_menuCAL.hpp b/src/c76_menuCAL.hpp index ff5df4d7..6b3b715e 100644 --- a/src/c76_menuCAL.hpp +++ b/src/c76_menuCAL.hpp @@ -12,7 +12,9 @@ enum { HIGHLIGHT_POLAR = 1, + #ifdef SUPPORT_DRIFT_ALIGNMENT HIGHLIGHT_DRIFT, + #endif HIGHLIGHT_SPEED, HIGHLIGHT_RA_STEPS, HIGHLIGHT_DEC_STEPS, @@ -42,12 +44,14 @@ enum #define POLAR_CALIBRATION_WAIT_CENTER_POLARIS 20 #define POLAR_CALIBRATION_WAIT_HOME 21 - // Drift calibration goes through 2 states - // 15- Display four durations and wait for the user to select one - // 16- Start the calibration run after user presses SELECT. This state waits 1.5s, takes duration time - // to slew east in half the time selected, then waits 1.5s and slews west in the same duration, and waits 1.5s. - #define DRIFT_CALIBRATION_WAIT 30 - #define DRIFT_CALIBRATION_RUNNING 31 + #if SUPPORT_DRIFT_ALIGNMENT == 1 + // Drift calibration goes through 2 states + // 15- Display four durations and wait for the user to select one + // 16- Start the calibration run after user presses SELECT. This state waits 1.5s, takes duration time + // to slew east in half the time selected, then waits 1.5s and slews west in the same duration, and waits 1.5s. + #define DRIFT_CALIBRATION_WAIT 30 + #define DRIFT_CALIBRATION_RUNNING 31 + #endif // Speed calibration only has one state, allowing you to adjust the speed with UP and DOWN #define SPEED_CALIBRATION 40 @@ -96,18 +100,20 @@ float SpeedCalibration; // The current delay in ms when changing calibration value. The longer a button is depressed, the smaller this gets. int calDelay = 150; + #if SUPPORT_DRIFT_ALIGNMENT == 1 // The index of durations that the user has selected. byte driftSubIndex = 1; +// The requested total duration of the drift alignment run. +byte driftDuration = 0; + #endif + // The index of Yes or No to confirm parking pos byte parkYesNoIndex = 0; // The index of Y or N to confirm DEC limits (used for hi and lo). byte limitSetClearCancelIndex = 0; -// The requested total duration of the drift alignment run. -byte driftDuration = 0; - // The number of steps to use for backlash compensation (read from the mount). int BacklashSteps = 0; @@ -369,6 +375,7 @@ bool processCalibrationKeys() } #endif } + #if SUPPORT_DRIFT_ALIGNMENT == 1 else if (calState == DRIFT_CALIBRATION_RUNNING) { lcdMenu.setCursor(0, 1); @@ -396,7 +403,7 @@ bool processCalibrationKeys() mount.startSlewing(TRACKING); calState = HIGHLIGHT_DRIFT; } - + #endif if (checkForKeyChange && lcdButtons.keyChanged(&key)) { waitForRelease = true; @@ -736,7 +743,7 @@ bool processCalibrationKeys() } } break; - + #if SUPPORT_DRIFT_ALIGNMENT == 1 case HIGHLIGHT_DRIFT: { if (key == btnDOWN) @@ -779,7 +786,7 @@ bool processCalibrationKeys() } } break; - + #endif case DEC_LOWER_LIMIT_CONFIRM: case DEC_UPPER_LIMIT_CONFIRM: { @@ -1030,10 +1037,12 @@ void printCalibrationSubmenu() { lcdMenu.printMenu(">Speed calibratn"); } + #if SUPPORT_DRIFT_ALIGNMENT == 1 else if (calState == HIGHLIGHT_DRIFT) { lcdMenu.printMenu(">Drift alignment"); } + #endif else if (calState == HIGHLIGHT_RA_STEPS) { lcdMenu.printMenu(">RA Step Adjust"); @@ -1101,12 +1110,14 @@ void printCalibrationSubmenu() dtostrf(mount.getSpeedCalibration(), 6, 4, &scratchBuffer[9]); lcdMenu.printMenu(scratchBuffer); } + #if SUPPORT_DRIFT_ALIGNMENT == 1 else if (calState == DRIFT_CALIBRATION_WAIT) { sprintf(scratchBuffer, " 1m 2m 3m 5m"); scratchBuffer[driftSubIndex * 4] = '>'; lcdMenu.printMenu(scratchBuffer); } + #endif else if (calState == RA_STEP_CALIBRATION) { sprintf(scratchBuffer, "RA Steps: %s", String(0.1 * RAStepsPerDegree, 1).c_str()); diff --git a/src/fonts128x64.h b/src/fonts128x64.h new file mode 100644 index 00000000..be6c8bcb --- /dev/null +++ b/src/fonts128x64.h @@ -0,0 +1,442 @@ +#include + +// Font generated or edited with the glyphEditor +const uint8_t Bitmap3x5[] PROGMEM = { +0x03, // Width: 3 +0x05, // Height: 5 +0x20, // First char: 32 +0x3B, // Number of chars: 59 +// Jump Table: +0xFF, 0xFF, 0x00, 0x03, // 32 +0x00, 0x00, 0x02, 0x03, // 33 +0x00, 0x02, 0x03, 0x04, // 34 +0x00, 0x05, 0x03, 0x04, // 35 +0x00, 0x08, 0x03, 0x04, // 36 +0x00, 0x0B, 0x03, 0x04, // 37 +0x00, 0x0E, 0x03, 0x04, // 38 +0x00, 0x11, 0x02, 0x03, // 39 +0x00, 0x13, 0x03, 0x04, // 40 +0x00, 0x16, 0x02, 0x03, // 41 +0x00, 0x18, 0x03, 0x04, // 42 +0x00, 0x1B, 0x03, 0x04, // 43 +0x00, 0x1E, 0x02, 0x03, // 44 +0x00, 0x20, 0x03, 0x04, // 45 +0x00, 0x23, 0x02, 0x03, // 46 +0x00, 0x25, 0x03, 0x04, // 47 +0x00, 0x28, 0x03, 0x04, // 48 +0x00, 0x2B, 0x02, 0x03, // 49 +0x00, 0x2D, 0x03, 0x04, // 50 +0x00, 0x30, 0x03, 0x04, // 51 +0x00, 0x33, 0x03, 0x04, // 52 +0x00, 0x36, 0x03, 0x04, // 53 +0x00, 0x39, 0x03, 0x04, // 54 +0x00, 0x3C, 0x03, 0x04, // 55 +0x00, 0x3F, 0x03, 0x04, // 56 +0x00, 0x42, 0x03, 0x04, // 57 +0x00, 0x45, 0x02, 0x03, // 58 +0x00, 0x47, 0x02, 0x03, // 59 +0x00, 0x49, 0x03, 0x04, // 60 +0x00, 0x4C, 0x03, 0x04, // 61 +0x00, 0x4F, 0x03, 0x04, // 62 +0x00, 0x52, 0x03, 0x04, // 63 +0x00, 0x55, 0x03, 0x04, // 64 +0x00, 0x58, 0x03, 0x04, // 65 +0x00, 0x5B, 0x03, 0x04, // 66 +0x00, 0x5E, 0x03, 0x04, // 67 +0x00, 0x61, 0x03, 0x04, // 68 +0x00, 0x64, 0x03, 0x04, // 69 +0x00, 0x67, 0x03, 0x04, // 70 +0x00, 0x6A, 0x03, 0x04, // 71 +0x00, 0x6D, 0x03, 0x04, // 72 +0x00, 0x70, 0x02, 0x03, // 73 +0x00, 0x72, 0x03, 0x04, // 74 +0x00, 0x75, 0x03, 0x04, // 75 +0x00, 0x78, 0x03, 0x04, // 76 +0x00, 0x7B, 0x03, 0x04, // 77 +0x00, 0x7E, 0x03, 0x04, // 78 +0x00, 0x81, 0x03, 0x04, // 79 +0x00, 0x84, 0x03, 0x04, // 80 +0x00, 0x87, 0x03, 0x04, // 81 +0x00, 0x8A, 0x03, 0x04, // 82 +0x00, 0x8D, 0x03, 0x04, // 83 +0x00, 0x90, 0x03, 0x04, // 84 +0x00, 0x93, 0x03, 0x04, // 85 +0x00, 0x96, 0x03, 0x04, // 86 +0x00, 0x99, 0x03, 0x04, // 87 +0x00, 0x9C, 0x03, 0x04, // 88 +0x00, 0x9F, 0x03, 0x04, // 89 +0x00, 0xA2, 0x03, 0x04, // 90 +// Font Data: +0x00, 0x17, // 33 +0x03, 0x00, 0x03, // 34 +0x0E, 0x0A, 0x0E, // 35 +0x12, 0x1F, 0x09, // 36 +0x19, 0x04, 0x13, // 37 +0x1A, 0x15, 0x0E, // 38 +0x00, 0x03, // 39 +0x00, 0x0E, 0x11, // 40 +0x11, 0x0E, // 41 +0x0A, 0x04, 0x0A, // 42 +0x04, 0x0E, 0x04, // 43 +0x10, 0x08, // 44 +0x04, 0x04, 0x04, // 45 +0x00, 0x10, // 46 +0x18, 0x04, 0x03, // 47 +0x1F, 0x11, 0x1F, // 48 +0x02, 0x1F, // 49 +0x19, 0x15, 0x13, // 50 +0x11, 0x15, 0x1F, // 51 +0x07, 0x04, 0x1F, // 52 +0x17, 0x15, 0x1D, // 53 +0x1F, 0x15, 0x1D, // 54 +0x01, 0x1D, 0x03, // 55 +0x1F, 0x15, 0x1F, // 56 +0x17, 0x15, 0x1F, // 57 +0x00, 0x0A, // 58 +0x10, 0x0A, // 59 +0x04, 0x0A, 0x11, // 60 +0x0A, 0x0A, 0x0A, // 61 +0x11, 0x0A, 0x04, // 62 +0x01, 0x15, 0x02, // 63 +0x0E, 0x1F, 0x0E, // 64 +0x1E, 0x09, 0x1E, // 65 +0x1F, 0x15, 0x0A, // 66 +0x0E, 0x11, 0x11, // 67 +0x1F, 0x11, 0x0E, // 68 +0x1F, 0x15, 0x11, // 69 +0x1F, 0x05, 0x01, // 70 +0x0E, 0x11, 0x1D, // 71 +0x1F, 0x04, 0x1F, // 72 +0x00, 0x1F, // 73 +0x08, 0x10, 0x0F, // 74 +0x1F, 0x04, 0x1B, // 75 +0x1F, 0x10, 0x10, // 76 +0x1F, 0x02, 0x1F, // 77 +0x1F, 0x0E, 0x1F, // 78 +0x0E, 0x11, 0x0E, // 79 +0x1F, 0x05, 0x02, // 80 +0x0E, 0x19, 0x1E, // 81 +0x1F, 0x05, 0x1A, // 82 +0x12, 0x15, 0x09, // 83 +0x01, 0x1F, 0x01, // 84 +0x0F, 0x10, 0x0F, // 85 +0x07, 0x18, 0x07, // 86 +0x1F, 0x0C, 0x1F, // 87 +0x1B, 0x04, 0x1B, // 88 +0x03, 0x1C, 0x03, // 89 +0x19, 0x15, 0x13, // 90 +}; + +// Font generated or edited with the glyphEditor +const uint8_t Bitmap5x7[] PROGMEM = { +0x05, // Width: 5 +0x07, // Height: 7 +0x20, // First char: 32 +0x60, // Number of chars: 96 +// Jump Table: +0xFF, 0xFF, 0x00, 0x05, // 32 +0x00, 0x00, 0x03, 0x04, // 33 +0x00, 0x03, 0x04, 0x05, // 34 +0x00, 0x07, 0x05, 0x06, // 35 +0x00, 0x0C, 0x05, 0x06, // 36 +0x00, 0x11, 0x05, 0x06, // 37 +0x00, 0x16, 0x05, 0x06, // 38 +0x00, 0x1B, 0x03, 0x04, // 39 +0x00, 0x1E, 0x04, 0x05, // 40 +0x00, 0x22, 0x04, 0x05, // 41 +0x00, 0x26, 0x05, 0x06, // 42 +0x00, 0x2B, 0x05, 0x06, // 43 +0x00, 0x30, 0x03, 0x04, // 44 +0x00, 0x33, 0x05, 0x06, // 45 +0x00, 0x38, 0x03, 0x04, // 46 +0x00, 0x3B, 0x05, 0x06, // 47 +0x00, 0x40, 0x05, 0x06, // 48 +0x00, 0x45, 0x04, 0x05, // 49 +0x00, 0x49, 0x05, 0x06, // 50 +0x00, 0x4E, 0x05, 0x06, // 51 +0x00, 0x53, 0x05, 0x06, // 52 +0x00, 0x58, 0x05, 0x06, // 53 +0x00, 0x5D, 0x05, 0x06, // 54 +0x00, 0x62, 0x05, 0x06, // 55 +0x00, 0x67, 0x05, 0x06, // 56 +0x00, 0x6C, 0x05, 0x06, // 57 +0x00, 0x71, 0x03, 0x04, // 58 +0x00, 0x74, 0x03, 0x04, // 59 +0x00, 0x77, 0x05, 0x06, // 60 +0x00, 0x7C, 0x05, 0x06, // 61 +0x00, 0x81, 0x05, 0x06, // 62 +0x00, 0x86, 0x05, 0x06, // 63 +0x00, 0x8B, 0x05, 0x06, // 64 +0x00, 0x90, 0x05, 0x06, // 65 +0x00, 0x95, 0x05, 0x06, // 66 +0x00, 0x9A, 0x05, 0x06, // 67 +0x00, 0x9F, 0x05, 0x06, // 68 +0x00, 0xA4, 0x05, 0x06, // 69 +0x00, 0xA9, 0x05, 0x06, // 70 +0x00, 0xAE, 0x05, 0x06, // 71 +0x00, 0xB3, 0x05, 0x06, // 72 +0x00, 0xB8, 0x04, 0x05, // 73 +0x00, 0xBC, 0x05, 0x06, // 74 +0x00, 0xC1, 0x05, 0x06, // 75 +0x00, 0xC6, 0x05, 0x06, // 76 +0x00, 0xCB, 0x05, 0x06, // 77 +0x00, 0xD0, 0x05, 0x06, // 78 +0x00, 0xD5, 0x05, 0x06, // 79 +0x00, 0xDA, 0x05, 0x06, // 80 +0x00, 0xDF, 0x05, 0x06, // 81 +0x00, 0xE4, 0x05, 0x06, // 82 +0x00, 0xE9, 0x05, 0x06, // 83 +0x00, 0xEE, 0x05, 0x06, // 84 +0x00, 0xF3, 0x05, 0x06, // 85 +0x00, 0xF8, 0x05, 0x06, // 86 +0x00, 0xFD, 0x05, 0x06, // 87 +0x01, 0x02, 0x05, 0x06, // 88 +0x01, 0x07, 0x05, 0x06, // 89 +0x01, 0x0C, 0x05, 0x06, // 90 +0x01, 0x11, 0x04, 0x05, // 91 +0x01, 0x15, 0x05, 0x06, // 92 +0x01, 0x1A, 0x04, 0x05, // 93 +0x01, 0x1E, 0x05, 0x06, // 94 +0x01, 0x23, 0x05, 0x06, // 95 +0x01, 0x28, 0x03, 0x04, // 96 +0x01, 0x2B, 0x05, 0x06, // 97 +0x01, 0x30, 0x05, 0x06, // 98 +0x01, 0x35, 0x05, 0x06, // 99 +0x01, 0x3A, 0x05, 0x06, // 100 +0x01, 0x3F, 0x05, 0x06, // 101 +0x01, 0x44, 0x04, 0x05, // 102 +0x01, 0x48, 0x05, 0x06, // 103 +0x01, 0x4D, 0x04, 0x05, // 104 +0x01, 0x51, 0x03, 0x04, // 105 +0x01, 0x54, 0x03, 0x04, // 106 +0x01, 0x57, 0x04, 0x05, // 107 +0x01, 0x5B, 0x03, 0x04, // 108 +0x01, 0x5E, 0x05, 0x06, // 109 +0x01, 0x63, 0x04, 0x05, // 110 +0x01, 0x67, 0x05, 0x06, // 111 +0x01, 0x6C, 0x05, 0x06, // 112 +0x01, 0x71, 0x05, 0x06, // 113 +0x01, 0x76, 0x04, 0x05, // 114 +0x01, 0x7A, 0x05, 0x06, // 115 +0x01, 0x7F, 0x03, 0x04, // 116 +0x01, 0x82, 0x04, 0x05, // 117 +0x01, 0x86, 0x04, 0x05, // 118 +0x01, 0x8A, 0x05, 0x06, // 119 +0x01, 0x8F, 0x05, 0x06, // 120 +0x01, 0x94, 0x05, 0x06, // 121 +0x01, 0x99, 0x04, 0x05, // 122 +0x01, 0x9D, 0x04, 0x05, // 123 +0x01, 0xA1, 0x03, 0x04, // 124 +0x01, 0xA4, 0x05, 0x06, // 125 +0x01, 0xA9, 0x04, 0x05, // 126 +0x01, 0xAD, 0x05, 0x06, // 127 +// Font Data: +0x00, 0x00, 0x5F, // 33 +0x00, 0x03, 0x00, 0x03, // 34 +0x0A, 0x1F, 0x0A, 0x1F, 0x0A, // 35 +0x26, 0x49, 0x77, 0x49, 0x32, // 36 +0x43, 0x33, 0x08, 0x66, 0x61, // 37 +0x36, 0x49, 0x55, 0x22, 0x50, // 38 +0x00, 0x00, 0x03, // 39 +0x00, 0x1C, 0x22, 0x41, // 40 +0x00, 0x41, 0x22, 0x1C, // 41 +0x2A, 0x1C, 0x3E, 0x1C, 0x2A, // 42 +0x08, 0x08, 0x3E, 0x08, 0x08, // 43 +0x00, 0x00, 0x60, // 44 +0x08, 0x08, 0x08, 0x08, 0x08, // 45 +0x00, 0x00, 0x40, // 46 +0x40, 0x30, 0x08, 0x06, 0x01, // 47 +0x3E, 0x51, 0x49, 0x45, 0x3E, // 48 +0x00, 0x42, 0x7F, 0x40, // 49 +0x42, 0x61, 0x51, 0x49, 0x46, // 50 +0x22, 0x49, 0x49, 0x49, 0x36, // 51 +0x0F, 0x08, 0x08, 0x7F, 0x08, // 52 +0x2F, 0x49, 0x49, 0x49, 0x31, // 53 +0x3E, 0x49, 0x49, 0x49, 0x32, // 54 +0x61, 0x11, 0x09, 0x05, 0x03, // 55 +0x36, 0x49, 0x49, 0x49, 0x36, // 56 +0x26, 0x49, 0x49, 0x49, 0x3E, // 57 +0x00, 0x00, 0x14, // 58 +0x00, 0x40, 0x34, // 59 +0x08, 0x14, 0x14, 0x22, 0x22, // 60 +0x14, 0x14, 0x14, 0x14, 0x14, // 61 +0x22, 0x22, 0x14, 0x14, 0x08, // 62 +0x02, 0x01, 0x51, 0x09, 0x06, // 63 +0x3E, 0x49, 0x5D, 0x59, 0x5E, // 64 +0x7C, 0x0A, 0x09, 0x0A, 0x7C, // 65 +0x7F, 0x49, 0x49, 0x49, 0x36, // 66 +0x3E, 0x41, 0x41, 0x41, 0x22, // 67 +0x7F, 0x41, 0x41, 0x41, 0x3E, // 68 +0x7F, 0x49, 0x49, 0x49, 0x41, // 69 +0x7F, 0x09, 0x09, 0x09, 0x01, // 70 +0x3E, 0x41, 0x49, 0x49, 0x3A, // 71 +0x7F, 0x08, 0x08, 0x08, 0x7F, // 72 +0x00, 0x41, 0x7F, 0x41, // 73 +0x20, 0x40, 0x40, 0x40, 0x3F, // 74 +0x7F, 0x08, 0x14, 0x22, 0x41, // 75 +0x7F, 0x40, 0x40, 0x40, 0x40, // 76 +0x7F, 0x04, 0x08, 0x04, 0x7F, // 77 +0x7F, 0x04, 0x08, 0x10, 0x7F, // 78 +0x3E, 0x41, 0x41, 0x41, 0x3E, // 79 +0x7F, 0x09, 0x09, 0x09, 0x06, // 80 +0x3E, 0x41, 0x51, 0x61, 0x7E, // 81 +0x7F, 0x09, 0x09, 0x09, 0x76, // 82 +0x26, 0x49, 0x49, 0x49, 0x32, // 83 +0x01, 0x01, 0x7F, 0x01, 0x01, // 84 +0x3F, 0x40, 0x40, 0x40, 0x3F, // 85 +0x1F, 0x20, 0x40, 0x20, 0x1F, // 86 +0x3F, 0x40, 0x38, 0x40, 0x3F, // 87 +0x63, 0x14, 0x08, 0x14, 0x63, // 88 +0x03, 0x04, 0x78, 0x04, 0x03, // 89 +0x61, 0x51, 0x49, 0x45, 0x43, // 90 +0x00, 0x7F, 0x41, 0x41, // 91 +0x01, 0x06, 0x08, 0x30, 0x40, // 92 +0x00, 0x41, 0x41, 0x7F, // 93 +0x04, 0x02, 0x01, 0x02, 0x04, // 94 +0x40, 0x40, 0x40, 0x40, 0x40, // 95 +0x00, 0x03, 0x04, // 96 +0x30, 0x54, 0x54, 0x54, 0x78, // 97 +0x7E, 0x48, 0x48, 0x48, 0x30, // 98 +0x38, 0x44, 0x44, 0x44, 0x44, // 99 +0x30, 0x48, 0x48, 0x48, 0x7E, // 100 +0x38, 0x54, 0x54, 0x54, 0x18, // 101 +0x10, 0x7E, 0x11, 0x11, // 102 +0x08, 0x54, 0x54, 0x54, 0x38, // 103 +0x7E, 0x08, 0x08, 0x70, // 104 +0x00, 0x00, 0x7A, // 105 +0x00, 0x40, 0x7A, // 106 +0x7E, 0x10, 0x28, 0x40, // 107 +0x00, 0x7E, 0x40, // 108 +0x7C, 0x04, 0x7C, 0x04, 0x78, // 109 +0x7C, 0x04, 0x04, 0x78, // 110 +0x38, 0x44, 0x44, 0x44, 0x38, // 111 +0x7C, 0x24, 0x24, 0x24, 0x18, // 112 +0x18, 0x24, 0x24, 0x24, 0x7C, // 113 +0x78, 0x04, 0x04, 0x04, // 114 +0x48, 0x54, 0x54, 0x54, 0x24, // 115 +0x04, 0x7F, 0x44, // 116 +0x3C, 0x40, 0x40, 0x7C, // 117 +0x1C, 0x20, 0x40, 0x7C, // 118 +0x3C, 0x40, 0x70, 0x40, 0x7C, // 119 +0x44, 0x28, 0x10, 0x28, 0x44, // 120 +0x4C, 0x50, 0x20, 0x10, 0x0C, // 121 +0x64, 0x54, 0x54, 0x4C, // 122 +0x08, 0x36, 0x41, 0x41, // 123 +0x00, 0x00, 0x7F, // 124 +0x00, 0x41, 0x41, 0x36, 0x08, // 125 +0x02, 0x01, 0x02, 0x01, // 126 +0x7F, 0x7F, 0x7F, 0x7F, 0x7F, // 127 +}; + +// Font generated or edited with the glyphEditor +const uint8_t Bitmap7x15[] PROGMEM = { + 0x07, // Width: 7 + 0x0F, // Height: 15 + 0x20, // First char: 32 + 0x1E, // Number of chars: 30 + // Jump Table: + 0xFF, 0xFF, 0x00, 0x07, // 32 + 0x00, 0x00, 0x0E, 0x08, // 33 + 0x00, 0x0E, 0x0B, 0x07, // 34 + 0x00, 0x19, 0x0E, 0x08, // 35 + 0x00, 0x27, 0x0E, 0x08, // 36 + 0x00, 0x35, 0x0C, 0x07, // 37 + 0x00, 0x41, 0x0E, 0x08, // 38 + 0x00, 0x4F, 0x03, 0x03, // 39 + 0x00, 0x52, 0x09, 0x06, // 40 + 0xFF, 0xFF, 0x00, 0x07, // 41 + 0xFF, 0xFF, 0x00, 0x07, // 42 + 0x00, 0x5B, 0x0B, 0x07, // 43 + 0xFF, 0xFF, 0x00, 0x07, // 44 + 0x00, 0x66, 0x0B, 0x07, // 45 + 0x00, 0x71, 0x06, 0x04, // 46 + 0xFF, 0xFF, 0x00, 0x07, // 47 + 0x00, 0x77, 0x0C, 0x07, // 48 + 0x00, 0x83, 0x0C, 0x07, // 49 + 0x00, 0x8F, 0x0C, 0x07, // 50 + 0x00, 0x9B, 0x0C, 0x07, // 51 + 0x00, 0xA7, 0x0C, 0x07, // 52 + 0x00, 0xB3, 0x0C, 0x07, // 53 + 0x00, 0xBF, 0x0C, 0x07, // 54 + 0x00, 0xCB, 0x0B, 0x07, // 55 + 0x00, 0xD6, 0x0C, 0x07, // 56 + 0x00, 0xE2, 0x0C, 0x07, // 57 + 0x00, 0xEE, 0x06, 0x04, // 58 + 0x00, 0xF4, 0x0A, 0x06, // 59 + 0x00, 0xFE, 0x08, 0x05, // 60 + 0x01, 0x06, 0x08, 0x05, // 61 + // Font Data: + 0xFF, 0x7F, 0xFF, 0x7F, 0x83, 0x01, 0x83, 0x01, 0x83, 0x07, 0xFF, 0x7F, 0xFE, 0x7C, // 33 + 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0F, // 34 + 0xFF, 0x7F, 0xFF, 0x7F, 0x03, 0x60, 0x03, 0x60, 0x07, 0x70, 0xFE, 0x3F, 0xFC, 0x1F, // 35 + 0xFF, 0x7F, 0xFF, 0x7F, 0xC3, 0x60, 0xC3, 0x60, 0x03, 0x60, 0x03, 0x60, 0x03, 0x60, // 36 + 0xF8, 0x0F, 0xFE, 0x3F, 0x0F, 0x78, 0x03, 0x60, 0x03, 0x60, 0x03, 0x60, // 37 + 0xFE, 0x7F, 0xFF, 0x7F, 0x83, 0x01, 0x83, 0x01, 0x83, 0x01, 0xFF, 0x7F, 0xFE, 0x7F, // 38 + 0x0F, 0x00, 0x0F, // 39 + 0x1E, 0x00, 0x33, 0x00, 0x21, 0x00, 0x33, 0x00, 0x1E, // 40 + 0xC0, 0x00, 0xC0, 0x00, 0xF0, 0x03, 0xF0, 0x03, 0xC0, 0x00, 0xC0, // 43 + 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, // 45 + 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, // 46 + 0xFE, 0x3F, 0xFF, 0x7F, 0x03, 0x60, 0x03, 0x60, 0xFF, 0x7F, 0xFE, 0x3F, // 48 + 0x00, 0x60, 0x03, 0x60, 0xFF, 0x7F, 0xFF, 0x7F, 0x00, 0x60, 0x00, 0x60, // 49 + 0x03, 0x7E, 0x03, 0x7F, 0x83, 0x63, 0xE7, 0x61, 0xFE, 0x60, 0x3C, 0x60, // 50 + 0x03, 0x60, 0x03, 0x60, 0xC3, 0x60, 0xC7, 0x70, 0xFE, 0x3F, 0x3C, 0x1F, // 51 + 0xFF, 0x01, 0xFF, 0x01, 0x80, 0x01, 0x80, 0x01, 0xF8, 0x7F, 0xF8, 0x7F, // 52 + 0x7F, 0x60, 0x7F, 0x60, 0x63, 0x60, 0xE3, 0x70, 0xC3, 0x3F, 0x83, 0x1F, // 53 + 0xFE, 0x3F, 0xFF, 0x7F, 0x63, 0x60, 0x63, 0x60, 0xE3, 0x7F, 0xC0, 0x3F, // 54 + 0x03, 0x00, 0x03, 0x70, 0x03, 0x7F, 0xF3, 0x0F, 0xFF, 0x01, 0x1F, // 55 + 0x3E, 0x3F, 0xFF, 0x7F, 0xC3, 0x60, 0xC3, 0x60, 0xFF, 0x7F, 0x3E, 0x3F, // 56 + 0x7E, 0x00, 0xFF, 0x60, 0xC3, 0x60, 0xC3, 0x60, 0xFF, 0x7F, 0xFE, 0x3F, // 57 + 0x00, 0x00, 0x30, 0x03, 0x30, 0x03, // 58 + 0x00, 0x7F, 0x00, 0x01, 0x00, 0x7E, 0x00, 0x01, 0x00, 0x7E, // 59 + 0xF0, 0x7F, 0x00, 0x01, 0x00, 0x01, 0x00, 0x7E, // 60 + 0x00, 0x23, 0x80, 0x44, 0x80, 0x44, 0x00, 0x39, // 61 +}; + +// Font generated or edited with the glyphEditor +const uint8_t CommSymbols[] PROGMEM = { +0x0A, // Width: 10 +0x08, // Height: 8 +0x41, // First char: 65 +0x0D, // Number of chars: 13 +// Jump Table: +0x00, 0x00, 0x05, 0x06, // 65 +0x00, 0x05, 0x0A, 0x0B, // 66 +0x00, 0x0F, 0x05, 0x06, // 67 +0x00, 0x14, 0x05, 0x06, // 68 +0x00, 0x19, 0x06, 0x07, // 69 +0x00, 0x1F, 0x07, 0x08, // 70 +0x00, 0x26, 0x09, 0x0A, // 71 +0x00, 0x2F, 0x09, 0x0A, // 72 +0x00, 0x38, 0x09, 0x0A, // 73 +0x00, 0x41, 0x0A, 0x0B, // 74 +0x00, 0x4B, 0x07, 0x08, // 75 +0x00, 0x52, 0x07, 0x08, // 76 +0x00, 0x59, 0x05, 0x06, // 77 +// Font Data: +0x15, 0x05, 0x19, 0x02, 0x1C, // 65 +0x02, 0x07, 0x02, 0x0A, 0x0A, 0x0A, 0x0A, 0x08, 0x1C, 0x08, // 66 +0x00, 0x00, 0x08, 0x18, 0x08, // 67 +0x00, 0x00, 0x04, 0x14, 0x04, // 68 +0x00, 0x04, 0x02, 0x12, 0x02, 0x04, // 69 +0x02, 0x01, 0x01, 0x11, 0x01, 0x01, 0x02, // 70 +0x0E, 0x11, 0x15, 0x71, 0x45, 0x31, 0x15, 0x11, 0x0E, // 71 +0x10, 0x1F, 0x01, 0x1F, 0x10, 0x1F, 0x01, 0x1F, 0x10, // 72 +0x07, 0x03, 0x05, 0x08, 0x11, 0x02, 0x14, 0x18, 0x1C, // 73 +0x07, 0x03, 0x05, 0x08, 0x11, 0x22, 0x04, 0x28, 0x30, 0x38, // 74 +0x1C, 0x22, 0x41, 0x4F, 0x49, 0x2A, 0x1C, // 75 +0x0E, 0x1B, 0x0A, 0x1B, 0x0A, 0x1F, 0x0E, // 76 +0x0E, 0x11, 0x17, 0x15, 0x0E, // 77 +}; + +// Font generated or edited with the glyphEditor +const uint8_t OATLogo[] PROGMEM = { +0x1A, // Width: 26 +0x11, // Height: 17 +0x21, // First char: 33 +0x01, // Number of chars: 1 +// Jump Table: +0x00, 0x00, 0x4D, 0x1B, // 33 +// Font Data: +0x00, 0x0E, 0x00, 0x80, 0x31, 0x00, 0xC0, 0x40, 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x01, 0x00, 0x10, 0x00, 0x00, 0x08, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x20, 0x05, 0x00, 0x40, 0x03, 0x00, 0x80, 0x03, 0x00, 0xF5, 0x5F, 0x01, 0x80, 0x03, 0x00, 0x40, 0x05, 0x00, 0x40, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x20, 0x00, 0x00, 0x21, 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x00, 0x00, 0x08, 0x00, 0x08, 0x0C, 0x00, 0x30, 0x06, 0x00, 0xC0, 0x01, // 33 +};