diff --git a/lib/lib_display/LedControl/src/LedMatrix.cpp b/lib/lib_display/LedControl/src/LedMatrix.cpp index 80ded02e2..b4fb8c260 100644 --- a/lib/lib_display/LedControl/src/LedMatrix.cpp +++ b/lib/lib_display/LedControl/src/LedMatrix.cpp @@ -1,5 +1,5 @@ /* - * LedMatrix.h - Extends the Library LedControl for multiple LED dot matrix modules, based on MAX7219/MAX7221 + * LedMatrix.h - Extends the Library LedControl for multiple 8x8 LED dot matrix modules, based on MAX7219/MAX7221 * Copyright (c) 2021 Michael Beuss * * Permission is hereby granted, free of charge, to any person @@ -25,7 +25,9 @@ */ #include "LedMatrix.h" +//#include "font_5x8_horizontal_MSB.h" #include "font_6x8_horizontal_MSB.h" +//#include "font_8x8_horizontal_latin_MSB.h" // public LedMatrix::LedMatrix(int dataPin, int clkPin, int csPin, unsigned int colums, unsigned int rows) @@ -44,13 +46,15 @@ LedMatrix::LedMatrix(int dataPin, int clkPin, int csPin, unsigned int colums, un } } + charWidth = font_char_width; // defined in header file of font + charHeight = font_char_height; // defined in header file of font modulesPerRow = colums; modulesPerCol = rows; displayWidth = colums * 8; displayHeight = rows * 8; modules = colums * rows; - moduleOrientation = ORIENTATION_UPSIDE_DOWN; - ledControl = new LedControl(dataPin, clkPin, csPin, modules); + moduleOrientation = ORIENTATION_UPSIDE_DOWN; // use setOrientation() to turn it + ledControl = new LedControl(dataPin, clkPin, csPin, modules); // initializes all connected LED matrix modules textBuf[0] = 0; textWidth = 0; textPosX = 0; @@ -62,11 +66,6 @@ LedMatrix::LedMatrix(int dataPin, int clkPin, int csPin, unsigned int colums, un setIntensity(7); } -void LedMatrix::power(bool on) -{ - shutdown(!on); // shut down on power off -} - bool LedMatrix::drawText( const char *str) { strncpy(textBuf, str, TEXT_BUFFER_SIZE -1); @@ -75,6 +74,7 @@ bool LedMatrix::drawText( const char *str) textWidth = strlen(textBuf) * charWidth; if(textWidth < displayWidth) { + // text fits into the display, place it into the center clear(); textPosX = (displayWidth - textWidth) / 2; // center } @@ -85,7 +85,7 @@ bool LedMatrix::drawText( const char *str) appendSpace(); } drawTextAt(textBuf, textPosX, textPosY); - refresh(); // refresh display with new string content + refresh(); // refresh display with the new drawed string content return true; } @@ -116,36 +116,16 @@ bool LedMatrix::scrollText() int startOfRepeatingTextPos = textPosX + textWidth; if(startOfRepeatingTextPos < displayWidth) { - // Draw repeating text. + // draw repeating text drawTextAt(textBuf, startOfRepeatingTextPos, textPosY); } refresh(); return true; } -bool LedMatrix::drawCharAt( char c, const int x, const int y) +void LedMatrix::power(bool on) { - // ignore when the character position is not visible on the display - bool visible = ( - x > 0 - (int)charWidth && x < (int)displayWidth && - y > 0 - (int)charHeight && y < (int)displayHeight - ); - if (!visible) return false; - - // ignore the leading bits above charWidth of the font definition - static const byte charOffset = 8 - charWidth; - - for (byte charY = 0; charY < charHeight; charY++) - { - char pixelRow = (font[c][charY]) << charOffset; // skip the first bits when the character width is smaller than 8 pixel - for (byte charX = 0; charX < charWidth; charX++) - { - bool pixel = (pixelRow & 0x80); // pixel=true when upper bit is set - setPixel(x + charX, y + charY, pixel); - pixelRow = pixelRow << 1; // next pixel - } - } - return true; + shutdown(!on); // power(false) shuts down the display with shutdown(true) } bool LedMatrix::clearDisplay(void) @@ -157,17 +137,6 @@ bool LedMatrix::clearDisplay(void) return true; } - -bool LedMatrix::clear(void) -{ - memset(buffer, 0, MATRIX_BUFFER_SIZE); - for (int addr = 0; addr < modules; addr++) - { - ledControl->clearDisplay(addr); - } - return true; -} - bool LedMatrix::setIntensity(byte dim) { for (int addr = 0; addr < modules; addr++) @@ -208,38 +177,40 @@ bool LedMatrix::setPixel(const int x, const int y, bool on) return true; } -void LedMatrix::test() +void LedMatrix::refresh() { - /* - const static byte testMatrix[] PROGMEM = { - B00000010, B00111100, B00111100, B00001000, - B00000110, B01000010, B01000010, B00010000, - B00001010, B00000010, B00000010, B00100000, - B00000010, B00000100, B00001100, B01000100, - B00000010, B00011000, B00000010, B01111110, - B00000010, B00100000, B01000010, B00000100, - B00000000, B01111110, B00111100, B00000100, - B00000000, B00000000, B00000000, B00000000, - }; - for (int i = 0; i < 32; i++) + for (int i = 0; i < modulesPerRow * displayHeight; i++) { - buffer[i] = testMatrix[i]; + refreshByteOfBuffer(i); } - refresh(); - */ - drawText("1234567890"); - delay(1000); - for( int i=0; i<320; i++) - { - delay(50); - scrollText(); - } - //drawCharAt(0x31, 1, 0); - //setPixel(1,30); - //refresh(); } -// private +// private functions +bool LedMatrix::drawCharAt( char c, const int x, const int y) +{ + // ignore when the character position is not visible on the display + bool visible = ( + x > 0 - (int)charWidth && x < (int)displayWidth && + y > 0 - (int)charHeight && y < (int)displayHeight + ); + if (!visible) return false; + + // ignore the leading bits above charWidth of the font definition + static const byte charOffset = 8 - charWidth; + + for (byte charY = 0; charY < charHeight; charY++) + { + char pixelRow = (font[c][charY]) << charOffset; // skip the first bits when the character width is smaller than 8 pixel + for (byte charX = 0; charX < charWidth; charX++) + { + bool pixel = (pixelRow & 0x80); // pixel=true when upper bit is set + setPixel(x + charX, y + charY, pixel); + pixelRow = pixelRow << 1; // next pixel + } + } + return true; +} + bool LedMatrix::shutdown(bool b) { for (int addr = 0; addr < modules; addr++) @@ -249,12 +220,14 @@ bool LedMatrix::shutdown(bool b) return true; } -void LedMatrix::refresh() +bool LedMatrix::clear(void) { - for (int i = 0; i < modulesPerRow * displayHeight; i++) + memset(buffer, 0, MATRIX_BUFFER_SIZE); + for (int addr = 0; addr < modules; addr++) { - refreshByteOfBuffer(i); + ledControl->clearDisplay(addr); } + return true; } void LedMatrix::refreshByteOfBuffer(int i) diff --git a/lib/lib_display/LedControl/src/LedMatrix.h b/lib/lib_display/LedControl/src/LedMatrix.h index 1d251030b..efb50b8e3 100644 --- a/lib/lib_display/LedControl/src/LedMatrix.h +++ b/lib/lib_display/LedControl/src/LedMatrix.h @@ -1,5 +1,5 @@ /* - * LedMatrix.h - Extends the Library LedControl for multiple LED dot matrix modules, based on MAX7219/MAX7221 + * LedMatrix.h - Extends the Library LedControl for multiple 8x8 LED dot matrix modules, based on MAX7219/MAX7221 * Copyright (c) 2021 Michael Beuss * * Permission is hereby granted, free of charge, to any person @@ -29,21 +29,21 @@ #include -#define MATRIX_MAX_MODULES 32 +#define MATRIX_MAX_MODULES 32 // maximum number of modules that can be used #define MATRIX_BUFFER_SIZE MATRIX_MAX_MODULES * 8 // 8 bytes per modul. One byte represents 8 LEDs. -#define TEXT_BUFFER_SIZE 256 -#define TEXT_APPEND_BUFFER_SIZE 16 +#define TEXT_BUFFER_SIZE 256 // maximum text length that can be scrolled +#define TEXT_APPEND_BUFFER_SIZE 16 // used for characters that are appended to the scroll text, before it repeats /** * @brief LedMatric controls multiple 8x8 LED dot matrx modules. - * All modules in rows and clolums together build a common matrix. + * All modules in rows and clolums together build a common display pixel matrix. * */ class LedMatrix { public: - enum ModuleOrientation // orientation of 8x8 LED dot matrix mdules (first module is top left) + enum ModuleOrientation // orientation of 8x8 LED dot matrix mdules (first module starts at top left) { ORIENTATION_NORMAL, // first pixel is on top left, no turn is necessary ORIENTATION_TURN_RIGHT, // first pixel is on bottom left, for correction it has to turn 90° right @@ -51,6 +51,100 @@ class LedMatrix ORIENTATION_TURN_LEFT, // first pixel is on top right, for correction is has to turn 90° left. }; + public: + /** + * @brief Construct a new LED Matrix object + * + * @param colums of 8x8 LED dot matrix modules + * @param rows of 8x8 LED dot matrix modules + */ + LedMatrix(int dataPin, int clkPin, int csPin, unsigned int colums, unsigned int rows); + + /** + * @brief Draws a string to the display. + * When the text fits into the display, it will be shown in the center. + * When the text is longer than than the display width, it can be scrolled per pixel with function scrollText(). + * + * @param str string to display + */ + bool drawText( const char *str ); + + /** + * @brief Dwaws a character string to a defined display position. The position (x,y) is used for the upper left pixel of the text. + * Existing text before the x position will not be cleared. Use refresh() after all text parts are drawed. + * + * @param str string to display + * @param x horizantal pixel position to start with string (0 is most left) + * @param y vertical pixel position for the top position of the string (0 is top) + */ + bool drawTextAt( const char *str, const int x, const int y ); + + /** + * @brief Scroll the current text one pixel to the left. + * Repeat with from start when end of text reached. This function can be called every 50 ms to get a propper scroll speed. + * + */ + bool scrollText(); + + /** + * @brief switches the display on or off + * + * @param on true: on false: off + */ + + void power( bool on ); + + /** + * @brief cleares the display and text buffer + * + */ + bool clearDisplay(void); + + /** + * @brief Set the brightness of the display + * + * @param dim 0..15 (0: dark .. 15: light) + */ + bool setIntensity(byte dim); + + /** + * @brief Set the orientation of the 8x8 LED dot matrix module + * + * @param orientation + */ + bool setOrientation(ModuleOrientation orientation); + + /** + * @brief Set ap pixel at a defined position. + * After all Pixels are set, call refresh() to send it to the display. + * + * @param x horizontal position from left + * @param y vertical position from top + * @param on true: on, false: off + */ + + /** + * @brief Set the a pending string to the scrolling text to set a distance to the repeating text. Usually some spaces are used. + * + * @param append text to append to the scrolling text before repeating. + */ + bool setScrollAppendText(const char* append ); + + bool setPixel( const int x, const int y, bool on=true); + /** + * @brief sends the changed content of the buffer to the display + * + */ + void refresh(); + + private: + bool drawCharAt( char c, int x, int y ); // Draws a character to a defined position + bool shutdown(bool b); // shutdown(true) switches the display off. Text and pixels can be set while it is off. shutdown(false) switches the display on. + bool clear(void); // clears the display content + void refreshByteOfBuffer( int i); // sends one byte of the buffer to the display. This updates an 8 pixel row of one matrix module. + byte revereBitorder(byte b); // returnes the byte in the reverse bit order. + void appendSpace(); // appends characters to the end of the text to get a distance to the repeating scroll text + private: unsigned int modulesPerRow; unsigned int modulesPerCol; @@ -60,112 +154,14 @@ class LedMatrix ModuleOrientation moduleOrientation; byte buffer[MATRIX_BUFFER_SIZE]; LedControl* ledControl; - const int charWidth = 6; - const int charHeight = 8; + int charWidth; + int charHeight; char textBuf[TEXT_BUFFER_SIZE]; char appendTextBuf[TEXT_APPEND_BUFFER_SIZE]; int textWidth; // width of text [pixel] int textPosX; // horizontal pixel position of scrolling text int textPosY; // vertical pixelposition of scrolling text; - - public: - /** - * @brief Construct a new Led Matrix object - * - * @param colums of 8x8 LED dot matrix modules - * @param rows of 8x8 LED dot matrix modules - */ - LedMatrix(int dataPin, int clkPin, int csPin, unsigned int colums, unsigned int rows); - - /** - * @brief Set all LEDs off. - * - */ - bool clearDisplay(void); - - /** - * @brief Set the brightness of the display - * - * @param dim 0..15 - */ - bool setIntensity(byte dim); - - /** - * @brief Set the a pending string to the scrolling text to set a distance to te repeating text. Usually some spaces. - * - * @param append text to append to the scrolling text before repeating. - */ - bool setScrollAppendText(const char* append ); - - /** - * @brief Switches the display on or off - * - * @param on true: on false: off - */ - void power( bool on ); - - /** - * @brief Set the orientation of the 8x8 LED dot matrix module - * - * @param orientation - */ - bool setOrientation(ModuleOrientation orientation); - - /** - * @brief draw a string to the display. - * When the text fits into the size of the display, it will be shown in the center. - * When the text is longer than than the display width, it can be scrolled per pixel with function scrollText(). - * - * @param str string to display - */ - bool drawText( const char *str ); - - /** - * @brief dwaws a character string to the display. The position (x,y) is used for the upper left pixtel of the text. - * Existing text before the x position will not be cleared. - * - * @param str string to display - * @param x horizantal pixel position to start with string (default 0) - * @param y vertical pixel position for the top position of the string (default 0) - */ - bool drawTextAt( const char *str, const int x, const int y ); - - /** - * @brief Scroll the current teext one picel to the left. - * Repeat with from start when end of text reached. - * - */ - bool scrollText(); - - /** - * @brief Set the Pixel object - * - * @param x horizontal position from left - * @param y vertical position from top - * @param on true: on, false: off - */ - bool setPixel( const int x, const int y, bool on=true); - void test(); - - private: - bool drawCharAt( char c, int x, int y ); - - bool shutdown(bool b); - bool clear(void); - - /** - * @brief sends the changed content of the buffer to the display - * - */ - void refresh(); - - void refreshByteOfBuffer( int i); - - byte revereBitorder (byte b); - - void appendSpace(); - }; #endif //LedMatrix_h \ No newline at end of file diff --git a/lib/lib_display/LedControl/src/font_5x8_horizontal_MSB.h b/lib/lib_display/LedControl/src/font_5x8_horizontal_MSB.h index 56df774a4..da3becc4e 100644 --- a/lib/lib_display/LedControl/src/font_5x8_horizontal_MSB.h +++ b/lib/lib_display/LedControl/src/font_5x8_horizontal_MSB.h @@ -2,6 +2,9 @@ #ifndef font_5x8_horizontal_MSB_h #define font_5x8_horizontal_MSB_h +const unsigned int font_char_width = 5; +const unsigned int font_char_height = 8; + const char font[256][8]={ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x00 {0x0E,0x11,0x1B,0x11,0x1F,0x0E,0x00,0x00}, // 0x01 diff --git a/lib/lib_display/LedControl/src/font_6x8_horizontal_MSB.h b/lib/lib_display/LedControl/src/font_6x8_horizontal_MSB.h index cc3a323cc..e5c522cd4 100644 --- a/lib/lib_display/LedControl/src/font_6x8_horizontal_MSB.h +++ b/lib/lib_display/LedControl/src/font_6x8_horizontal_MSB.h @@ -2,6 +2,9 @@ #ifndef font_6x8_horizontal_MSB_h #define font_6x8_horizontal_MSB_h +const unsigned int font_char_width = 6; +const unsigned int font_char_height = 8; + const char font[256][8]={ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x00 {0x0E,0x11,0x1B,0x11,0x15,0x11,0x0E,0x00}, // 0x01 diff --git a/lib/lib_display/LedControl/src/font_8x8_horizontal_latin_MSB.h b/lib/lib_display/LedControl/src/font_8x8_horizontal_latin_MSB.h new file mode 100644 index 000000000..e1a8af7ae --- /dev/null +++ b/lib/lib_display/LedControl/src/font_8x8_horizontal_latin_MSB.h @@ -0,0 +1,265 @@ +#ifndef font_8x8_horizontal_latin_MSB_h +#define font_8x8_horizontal_latin_MSB_h + +const unsigned int font_char_width = 8; +const unsigned int font_char_height = 8; + +const char font[256][8]={ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x00 +{0x0E,0x11,0x1B,0x11,0x15,0x11,0x0E,0x00}, // 0x01 +{0x0E,0x1F,0x15,0x1F,0x11,0x1F,0x0E,0x00}, // 0x02 +{0x00,0x0A,0x1F,0x1F,0x1F,0x0E,0x04,0x00}, // 0x03 +{0x00,0x04,0x0E,0x1F,0x1F,0x0E,0x04,0x00}, // 0x04 +{0x04,0x0E,0x0E,0x04,0x1F,0x1F,0x04,0x00}, // 0x05 +{0x00,0x04,0x0E,0x1F,0x1F,0x04,0x0E,0x00}, // 0x06 +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x07 +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x08 +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x09 +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x0A +{0x00,0x07,0x03,0x0D,0x12,0x12,0x0C,0x00}, // 0x0B +{0x0E,0x11,0x11,0x0E,0x04,0x0E,0x04,0x00}, // 0x0C +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x0D +{0x03,0x0D,0x0B,0x0D,0x0B,0x1B,0x18,0x00}, // 0x0E +{0x00,0x15,0x0E,0x1B,0x0E,0x15,0x00,0x00}, // 0x0F +{0x08,0x0C,0x0E,0x0F,0x0E,0x0C,0x08,0x00}, // 0x10 +{0x02,0x06,0x0E,0x1E,0x0E,0x06,0x02,0x00}, // 0x11 +{0x04,0x0E,0x1F,0x04,0x1F,0x0E,0x04,0x00}, // 0x12 +{0x0A,0x0A,0x0A,0x0A,0x0A,0x00,0x0A,0x00}, // 0x13 +{0x0F,0x15,0x15,0x0D,0x05,0x05,0x05,0x00}, // 0x14 +{0x0E,0x11,0x0C,0x0A,0x06,0x11,0x0E,0x00}, // 0x15 +{0x00,0x00,0x00,0x00,0x00,0x1E,0x1E,0x00}, // 0x16 +{0x04,0x0E,0x1F,0x04,0x1F,0x0E,0x04,0x0E}, // 0x17 +{0x04,0x0E,0x1F,0x04,0x04,0x04,0x04,0x00}, // 0x18 +{0x04,0x04,0x04,0x04,0x1F,0x0E,0x04,0x00}, // 0x19 +{0x00,0x04,0x06,0x1F,0x06,0x04,0x00,0x00}, // 0x1A +{0x00,0x04,0x0C,0x1F,0x0C,0x04,0x00,0x00}, // 0x1B +{0x00,0x00,0x00,0x10,0x10,0x10,0x1F,0x00}, // 0x1C +{0x00,0x0A,0x0A,0x1F,0x0A,0x0A,0x00,0x00}, // 0x1D +{0x04,0x04,0x0E,0x0E,0x1F,0x1F,0x00,0x00}, // 0x1E +{0x1F,0x1F,0x0E,0x0E,0x04,0x04,0x00,0x00}, // 0x1F + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 (space) + { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!) + { 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0022 (") + { 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // U+0023 (#) + { 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // U+0024 ($) + { 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // U+0025 (%) + { 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // U+0026 (&) + { 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0027 (') + { 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // U+0028 (() + { 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // U+0029 ()) + { 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // U+002A (*) + { 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // U+002B (+) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+002C (,) + { 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // U+002D (-) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+002E (.) + { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // U+002F (/) + { 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // U+0030 (0) + { 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // U+0031 (1) + { 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // U+0032 (2) + { 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // U+0033 (3) + { 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // U+0034 (4) + { 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // U+0035 (5) + { 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // U+0036 (6) + { 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // U+0037 (7) + { 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+0038 (8) + { 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // U+0039 (9) + { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+003A (:) + { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+003B (;) + { 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // U+003C (<) + { 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // U+003D (=) + { 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // U+003E (>) + { 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // U+003F (?) + { 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // U+0040 (@) + { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A) + { 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // U+0042 (B) + { 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // U+0043 (C) + { 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // U+0044 (D) + { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // U+0045 (E) + { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // U+0046 (F) + { 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // U+0047 (G) + { 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // U+0048 (H) + { 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0049 (I) + { 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // U+004A (J) + { 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // U+004B (K) + { 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // U+004C (L) + { 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // U+004D (M) + { 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // U+004E (N) + { 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // U+004F (O) + { 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // U+0050 (P) + { 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // U+0051 (Q) + { 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // U+0052 (R) + { 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // U+0053 (S) + { 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0054 (T) + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U+0055 (U) + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0056 (V) + { 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // U+0057 (W) + { 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // U+0058 (X) + { 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+0059 (Y) + { 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // U+005A (Z) + { 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // U+005B ([) + { 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // U+005C (\) + { 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // U+005D (]) + { 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // U+005E (^) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // U+005F (_) + { 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0060 (`) + { 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // U+0061 (a) + { 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // U+0062 (b) + { 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // U+0063 (c) + { 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // U+0064 (d) + { 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // U+0065 (e) + { 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // U+0066 (f) + { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0067 (g) + { 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // U+0068 (h) + { 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0069 (i) + { 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // U+006A (j) + { 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // U+006B (k) + { 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+006C (l) + { 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // U+006D (m) + { 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // U+006E (n) + { 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+006F (o) + { 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+0070 (p) + { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // U+0071 (q) + { 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // U+0072 (r) + { 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // U+0073 (s) + { 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // U+0074 (t) + { 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // U+0075 (u) + { 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0076 (v) + { 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // U+0077 (w) + { 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // U+0078 (x) + { 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0079 (y) + { 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // U+007A (z) + { 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // U+007B ({) + { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+007C (|) + { 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // U+007D (}) + { 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007E (~) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007F{0x0E,0x11,0x10,0x10,0x11,0x0E,0x04,0x0C}, // 0x80 +{0x12,0x00,0x12,0x12,0x12,0x16,0x0A,0x00}, // 0x81 +{0x03,0x00,0x0E,0x11,0x1E,0x10,0x0E,0x00}, // 0x82 +{0x0E,0x00,0x0E,0x01,0x0F,0x11,0x0F,0x00}, // 0x83 +{0x0A,0x00,0x0E,0x01,0x0F,0x11,0x0F,0x00}, // 0x84 +{0x0C,0x00,0x0E,0x01,0x0F,0x11,0x0F,0x00}, // 0x85 +{0x0E,0x0A,0x0E,0x01,0x0F,0x11,0x0F,0x00}, // 0x86 +{0x00,0x0E,0x11,0x10,0x11,0x0E,0x04,0x0C}, // 0x87 +{0x0E,0x00,0x0E,0x11,0x1E,0x10,0x0E,0x00}, // 0x88 +{0x0A,0x00,0x0E,0x11,0x1E,0x10,0x0E,0x00}, // 0x89 +{0x0C,0x00,0x0E,0x11,0x1E,0x10,0x0E,0x00}, // 0x8A +{0x0A,0x00,0x04,0x04,0x04,0x04,0x06,0x00}, // 0x8B +{0x0E,0x00,0x04,0x04,0x04,0x04,0x06,0x00}, // 0x8C +{0x08,0x00,0x04,0x04,0x04,0x04,0x06,0x00}, // 0x8D +{0x0A,0x00,0x04,0x0A,0x11,0x1F,0x11,0x00}, // 0x8E +{0x0E,0x0A,0x0E,0x1B,0x11,0x1F,0x11,0x00}, // 0x8F +{0x03,0x00,0x1F,0x10,0x1E,0x10,0x1F,0x00}, // 0x90 +{0x00,0x00,0x1E,0x05,0x1F,0x14,0x0F,0x00}, // 0x91 +{0x0F,0x14,0x14,0x1F,0x14,0x14,0x17,0x00}, // 0x92 +{0x0E,0x00,0x0C,0x12,0x12,0x12,0x0C,0x00}, // 0x93 +{0x0A,0x00,0x0C,0x12,0x12,0x12,0x0C,0x00}, // 0x94 +{0x18,0x00,0x0C,0x12,0x12,0x12,0x0C,0x00}, // 0x95 +{0x0E,0x00,0x12,0x12,0x12,0x16,0x0A,0x00}, // 0x96 +{0x18,0x00,0x12,0x12,0x12,0x16,0x0A,0x00}, // 0x97 +{0x0A,0x00,0x12,0x12,0x12,0x0E,0x04,0x18}, // 0x98 +{0x12,0x0C,0x12,0x12,0x12,0x12,0x0C,0x00}, // 0x99 +{0x0A,0x00,0x12,0x12,0x12,0x12,0x0C,0x00}, // 0x9A +{0x00,0x00,0x01,0x0E,0x16,0x1A,0x1C,0x20}, // 0x9B +{0x06,0x09,0x08,0x1E,0x08,0x09,0x17,0x00}, // 0x9C +{0x0F,0x13,0x15,0x15,0x15,0x19,0x1E,0x00}, // 0x9D +{0x00,0x11,0x0A,0x04,0x0A,0x11,0x00,0x00}, // 0x9E +{0x02,0x05,0x04,0x0E,0x04,0x04,0x14,0x08}, // 0x9F + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+00A0 (no break space) + { 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00}, // U+00A1 (inverted !) + { 0x18, 0x18, 0x7E, 0x03, 0x03, 0x7E, 0x18, 0x18}, // U+00A2 (dollarcents) + { 0x1C, 0x36, 0x26, 0x0F, 0x06, 0x67, 0x3F, 0x00}, // U+00A3 (pound sterling) + { 0x00, 0x00, 0x63, 0x3E, 0x36, 0x3E, 0x63, 0x00}, // U+00A4 (currency mark) + { 0x33, 0x33, 0x1E, 0x3F, 0x0C, 0x3F, 0x0C, 0x0C}, // U+00A5 (yen) + { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+00A6 (broken pipe) + { 0x7C, 0xC6, 0x1C, 0x36, 0x36, 0x1C, 0x33, 0x1E}, // U+00A7 (paragraph) + { 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+00A8 (diaeresis) + { 0x3C, 0x42, 0x99, 0x85, 0x85, 0x99, 0x42, 0x3C}, // U+00A9 (copyright symbol) + { 0x3C, 0x36, 0x36, 0x7C, 0x00, 0x00, 0x00, 0x00}, // U+00AA (superscript a) + { 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00}, // U+00AB (<<) + { 0x00, 0x00, 0x00, 0x3F, 0x30, 0x30, 0x00, 0x00}, // U+00AC (gun pointing left) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+00AD (soft hyphen) + { 0x3C, 0x42, 0x9D, 0xA5, 0x9D, 0xA5, 0x42, 0x3C}, // U+00AE (registered symbol) + { 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+00AF (macron) + { 0x1C, 0x36, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00}, // U+00B0 (degree) + { 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x7E, 0x00}, // U+00B1 (plusminus) + { 0x1C, 0x30, 0x18, 0x0C, 0x3C, 0x00, 0x00, 0x00}, // U+00B2 (superscript 2) + { 0x1C, 0x30, 0x18, 0x30, 0x1C, 0x00, 0x00, 0x00}, // U+00B2 (superscript 3) + { 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+00B2 (aigu) + { 0x00, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x03}, // U+00B5 (mu) + { 0xFE, 0xDB, 0xDB, 0xDE, 0xD8, 0xD8, 0xD8, 0x00}, // U+00B6 (pilcrow) + { 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00}, // U+00B7 (central dot) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x1E}, // U+00B8 (cedille) + { 0x08, 0x0C, 0x08, 0x1C, 0x00, 0x00, 0x00, 0x00}, // U+00B9 (superscript 1) + { 0x1C, 0x36, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00}, // U+00BA (superscript 0) + { 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00}, // U+00BB (>>) + { 0xC3, 0x63, 0x33, 0xBD, 0xEC, 0xF6, 0xF3, 0x03}, // U+00BC (1/4) + { 0xC3, 0x63, 0x33, 0x7B, 0xCC, 0x66, 0x33, 0xF0}, // U+00BD (1/2) + { 0x03, 0xC4, 0x63, 0xB4, 0xDB, 0xAC, 0xE6, 0x80}, // U+00BE (3/4) + { 0x0C, 0x00, 0x0C, 0x06, 0x03, 0x33, 0x1E, 0x00}, // U+00BF (inverted ?) + { 0x07, 0x00, 0x1C, 0x36, 0x63, 0x7F, 0x63, 0x00}, // U+00C0 (A grave) + { 0x70, 0x00, 0x1C, 0x36, 0x63, 0x7F, 0x63, 0x00}, // U+00C1 (A aigu) + { 0x1C, 0x36, 0x00, 0x3E, 0x63, 0x7F, 0x63, 0x00}, // U+00C2 (A circumflex) + { 0x6E, 0x3B, 0x00, 0x3E, 0x63, 0x7F, 0x63, 0x00}, // U+00C3 (A ~) + { 0x63, 0x1C, 0x36, 0x63, 0x7F, 0x63, 0x63, 0x00}, // U+00C4 (A umlaut) + { 0x0C, 0x0C, 0x00, 0x1E, 0x33, 0x3F, 0x33, 0x00}, // U+00C5 (A ring) + { 0x7C, 0x36, 0x33, 0x7F, 0x33, 0x33, 0x73, 0x00}, // U+00C6 (AE) + { 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x18, 0x30, 0x1E}, // U+00C7 (C cedille) + { 0x07, 0x00, 0x3F, 0x06, 0x1E, 0x06, 0x3F, 0x00}, // U+00C8 (E grave) + { 0x38, 0x00, 0x3F, 0x06, 0x1E, 0x06, 0x3F, 0x00}, // U+00C9 (E aigu) + { 0x0C, 0x12, 0x3F, 0x06, 0x1E, 0x06, 0x3F, 0x00}, // U+00CA (E circumflex) + { 0x36, 0x00, 0x3F, 0x06, 0x1E, 0x06, 0x3F, 0x00}, // U+00CB (E umlaut) + { 0x07, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+00CC (I grave) + { 0x38, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+00CD (I aigu) + { 0x0C, 0x12, 0x00, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+00CE (I circumflex) + { 0x33, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+00CF (I umlaut) + { 0x3F, 0x66, 0x6F, 0x6F, 0x66, 0x66, 0x3F, 0x00}, // U+00D0 (Eth) + { 0x3F, 0x00, 0x33, 0x37, 0x3F, 0x3B, 0x33, 0x00}, // U+00D1 (N ~) + { 0x0E, 0x00, 0x18, 0x3C, 0x66, 0x3C, 0x18, 0x00}, // U+00D2 (O grave) + { 0x70, 0x00, 0x18, 0x3C, 0x66, 0x3C, 0x18, 0x00}, // U+00D3 (O aigu) + { 0x3C, 0x66, 0x18, 0x3C, 0x66, 0x3C, 0x18, 0x00}, // U+00D4 (O circumflex) + { 0x6E, 0x3B, 0x00, 0x3E, 0x63, 0x63, 0x3E, 0x00}, // U+00D5 (O ~) + { 0xC3, 0x18, 0x3C, 0x66, 0x66, 0x3C, 0x18, 0x00}, // U+00D6 (O umlaut) + { 0x00, 0x36, 0x1C, 0x08, 0x1C, 0x36, 0x00, 0x00}, // U+00D7 (multiplicative x) + { 0x5C, 0x36, 0x73, 0x7B, 0x6F, 0x36, 0x1D, 0x00}, // U+00D8 (O stroke) + { 0x0E, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00}, // U+00D9 (U grave) + { 0x70, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00}, // U+00DA (U aigu) + { 0x3C, 0x66, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x00}, // U+00DB (U circumflex) + { 0x33, 0x00, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+00DC (U umlaut) + { 0x70, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x00}, // U+00DD (Y aigu) + { 0x0F, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+00DE (Thorn) + { 0x00, 0x1E, 0x33, 0x1F, 0x33, 0x1F, 0x03, 0x03}, // U+00DF (beta) + { 0x07, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E0 (a grave) + { 0x38, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E1 (a aigu) + { 0x7E, 0xC3, 0x3C, 0x60, 0x7C, 0x66, 0xFC, 0x00}, // U+00E2 (a circumflex) + { 0x6E, 0x3B, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E3 (a ~) + { 0x33, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E4 (a umlaut) + { 0x0C, 0x0C, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E5 (a ring) + { 0x00, 0x00, 0xFE, 0x30, 0xFE, 0x33, 0xFE, 0x00}, // U+00E6 (ae) + { 0x00, 0x00, 0x1E, 0x03, 0x03, 0x1E, 0x30, 0x1C}, // U+00E7 (c cedille) + { 0x07, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00}, // U+00E8 (e grave) + { 0x38, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00}, // U+00E9 (e aigu) + { 0x7E, 0xC3, 0x3C, 0x66, 0x7E, 0x06, 0x3C, 0x00}, // U+00EA (e circumflex) + { 0x33, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00}, // U+00EB (e umlaut) + { 0x07, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+00EC (i grave) + { 0x1C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+00ED (i augu) + { 0x3E, 0x63, 0x1C, 0x18, 0x18, 0x18, 0x3C, 0x00}, // U+00EE (i circumflex) + { 0x33, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+00EF (i umlaut) + { 0x1B, 0x0E, 0x1B, 0x30, 0x3E, 0x33, 0x1E, 0x00}, // U+00F0 (eth) + { 0x00, 0x1F, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x00}, // U+00F1 (n ~) + { 0x00, 0x07, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F2 (o grave) + { 0x00, 0x38, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F3 (o aigu) + { 0x1E, 0x33, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F4 (o circumflex) + { 0x6E, 0x3B, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F5 (o ~) + { 0x00, 0x33, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F6 (o umlaut) + { 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00}, // U+00F7 (division) + { 0x00, 0x60, 0x3C, 0x76, 0x7E, 0x6E, 0x3C, 0x06}, // U+00F8 (o stroke) + { 0x00, 0x07, 0x00, 0x33, 0x33, 0x33, 0x7E, 0x00}, // U+00F9 (u grave) + { 0x00, 0x38, 0x00, 0x33, 0x33, 0x33, 0x7E, 0x00}, // U+00FA (u aigu) + { 0x1E, 0x33, 0x00, 0x33, 0x33, 0x33, 0x7E, 0x00}, // U+00FB (u circumflex) + { 0x00, 0x33, 0x00, 0x33, 0x33, 0x33, 0x7E, 0x00}, // U+00FC (u umlaut) + { 0x00, 0x38, 0x00, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+00FD (y aigu) + { 0x00, 0x00, 0x06, 0x3E, 0x66, 0x3E, 0x06, 0x00}, // U+00FE (thorn) + { 0x00, 0x33, 0x00, 0x33, 0x33, 0x3E, 0x30, 0x1F} // U+00FF (y umlaut) +}; + +#endif \ No newline at end of file diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index 13fdf23e4..e3f3256fc 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -524,7 +524,6 @@ const uint16_t kGpioNiceList[] PROGMEM = { #ifdef USE_DISPLAY_MAX7219_MATRIX #undef USE_DISPLAY_MAX7219 #undef USE_DISPLAY_TM1637 - #define USE_DISPLAY_MODES1TO5 AGPIO(GPIO_MAX7219CLK), AGPIO(GPIO_MAX7219DIN), AGPIO(GPIO_MAX7219CS), diff --git a/tasmota/xdsp_19_max7219_matrix.ino b/tasmota/xdsp_19_max7219_matrix.ino index ec82420e2..3ec3ac332 100644 --- a/tasmota/xdsp_19_max7219_matrix.ino +++ b/tasmota/xdsp_19_max7219_matrix.ino @@ -1,5 +1,5 @@ /* - xdsp_19_max7219_matrix.ino.ino - Support for MAX7219 based dot matrix displays for Tasmota + xdsp_19_max7219_matrix.ino.ino - Support for MAX7219 based 8x8 dot matrix displays for Tasmota Copyright (C) 2021 Michael Beuss @@ -20,111 +20,63 @@ #ifdef USE_DISPLAY #ifdef USE_DISPLAY_MAX7219_MATRIX /*********************************************************************************************\ - This driver enables the display of ascii text on MAX7219 based LED dot matrix modules. + This driver enables the display of ascii text on MAX7219 based 8x8 LED dot matrix modules (1088AS). - Connect the MAX7219 display module's pins to any free GPIOs of the ESP8266 or ESP32 module - and assign the pins as follows from Tasmota's GUI: + Connect the MAX7219 display module's pins to any free GPIOs of the ESP8266 or ESP32 module. + VCC should be 5V. Depending on the number of used modules and the brightness, the used current can be more than 500 mA. + + Connect the 5 outgoing pins (VCC, GND, DI, CS, CLK) of the first module to the next one. + With this you can connect up to 32 modules. + To extend the display hieght, multiple rows are supported. Each module row starts from left to right. + + Assign the pins as follows from Tasmota's GUI: DIN hardware pin --> "MAX7219 DIN" CS hardware pin --> "MAX7219 CS" CLK hardware pin --> "MAX7219 CLK" + Once the GPIO configuration is saved and the ESP8266/ESP32 module restarts, set the Display Model to 19 and Display Mode to 0 - using the command "Backlog DisplayModel 15 ; DisplayMode 0" - If your display is a TM1637 with 6 digits, set Display Width to the number of digits your - display has, using the command "DisplayWidth 6". + Depending on order oth the wired 8x8 matrix modules you have got a display of size pixel_width x pixel_height. + The size has to be set with the commands "DisplayWidth " and "DisplayHeight " After the ESP8266/ESP32 module restarts again, turn ON the display with the command "Power 1" + Now, the following "Display" commands can be used: + DisplayText text + Sends the text to the display. + If the text fits into the display, it is shown in the center. + Otherwise it scrolls to the left and repeats as long it is cleared or new "DisplayText" overwrites it. + + DisplayDimmer [0..100] + Sets the intensity of the display. + + Power [ON|OFF] + Sitches the display on or off. When "off", the display buffer is not cleared and will be shown again when after "Power ON". + Other display commands are still active when off. DisplayClear + Clears the display - Clears the display, command: "DisplayClear" + DisplayScrollDelay [0..15] // default = 0 + Sets the speed of text scroll. Smaller delay = faster scrolling. + The maximum scroll speed is 50ms per pixel on DisplayScrollDelay 0. + DisplayWidth [8..256] + Sets the pixel width of the display (8x number of modules in a row) - DisplayNumber num [,position {0-(Settings->display_width-1))} [,leading_zeros {0|1} [,length {1 to Settings->display_width}]]] + DisplayHeight [8..256] + Sets the pixel height of the display (8x number of module rows) - Clears and then displays number without decimal. command e.g., "DisplayNumber 1234" - Control 'leading zeros', 'length' and 'position' with "DisplayNumber 1234, , , " - 'leading zeros' can be 1 or 0 (default), 'length' can be 1 to Settings->display_width, 'position' can be 0 (left-most) to Settings->display_width (right-most). - See function description below for more details. - - DisplayNumberNC num [,position {0-(Settings->display_width-1))} [,leading_zeros {0|1} [,length {1 to Settings->display_width}]]] - - Display integer number as above, but without clearing first. e.g., "DisplayNumberNC 1234". Usage is same as above. - - - - DisplayFloat num [,position {0-(Settings->display_width-1)} [,precision {0-Settings->display_width} [,length {1 to Settings->display_width}]]] - - Clears and then displays float (with decimal point) command e.g., "DisplayFloat 12.34" - See function description below for more details. - - - - DisplayFloatNC num [,position {0-(Settings->display_width-1)} [,precision {0-Settings->display_width} [,length {1 to Settings->display_width}]]] - - Displays float (with decimal point) as above, but without clearing first. command e.g., "DisplayFloatNC 12.34" - See function description below for more details. - - - - DisplayRaw position {0-(Settings->display_width-1)},length {1 to Settings->display_width}, num1 [, num2[, num3[, num4[, ...upto Settings->display_width numbers]]]]] - - Takes upto Settings->display_width comma-separated integers (0-255) and displays raw segments. Each number represents a - 7-segment digit. Each 8-bit number represents individual segments of a digit. - For example, the command "DisplayRaw 0, 4, 255, 255, 255, 255" would display "[8.8.8.8.]" - - - - DisplayText text [, position {0-(Settings->display_width-1)} [,length {1 to Settings->display_width}]] - - Clears and then displays basic text. command e.g., "DisplayText ajith vasudevan" - Control 'length' and 'position' with "DisplayText , , " - 'length' can be 1 to Settings->display_width, 'position' can be 0 (left-most) to Settings->display_width-1 (right-most) - A caret(^) symbol in the text input is dispayed as the degrees(°) symbol. This is useful for displaying Temperature! - For example, the command "DisplayText 22.5^" will display "22.5°". - - - DisplayTextNC text [, position {0-Settings->display_width-1} [,length {1 to Settings->display_width}]] - - Clears first, then displays text. Usage is same as above. - - - - DisplayScrollText text [, num_loops] - - Displays scrolling text indefinitely, until another Display- command (other than DisplayScrollText - or DisplayScrollDelay is issued). Optionally, stop scrolling after num_loops iterations. - - - - DisplayScrollDelay delay {0-15} // default = 4 - - Sets the speed of text scroll. Smaller delay = faster scrolling. - - - - DisplayLevel num {0-100} - - Display a horizontal bar graph (0-100) command e.g., "DisplayLevel 50" will display [|||| ] - - - - DisplayClock 1|2|0 - - Displays a clock. - Commands "DisplayClock 1" // 12 hr format - "DisplayClock 2" // 24 hr format - "DisplayClock 0" // turn off clock - - -In addition, setting DisplayMode to 1 shows the time, setting it to 2 shows the date -and setting it to 3 alternates between time and date. + DisplayClock [0|1|2] + Displays a clock. + Commands "DisplayClock 1" // 12 hr format + "DisplayClock 2" // 24 hr format + "DisplayClock 0" // turn off clock @@ -132,20 +84,26 @@ and setting it to 3 alternates between time and date. #define XDSP_19 19 -#include #include +#ifdef USE_DISPLAY_MODES1TO5 +#include +#endif + LedMatrix *max7219_Matrix = nullptr; bool max2791Matrix_initDriver_done = false; struct { byte modulesPerRow = 4; byte modulesPerCol = 1; + byte scroll_delay = 0; + byte scroll_iteration = 0; bool show_clock = false; - const char* timeFormat; + const char *timeFormat; } LedMatrix_settings; +// FUNC_DISPLAY_INIT_DRIVER bool MAX7291Matrix_initDriver(void) { if (!PinUsed(GPIO_MAX7219DIN) || !PinUsed(GPIO_MAX7219CLK) || !PinUsed(GPIO_MAX7219CS)) @@ -174,6 +132,7 @@ bool MAX7291Matrix_initDriver(void) return MAX7291Matrix_init(); } +// FUNC_DISPLAY_INIT bool MAX7291Matrix_init(void) { int intensity = GetDisplayDimmer16(); // 0..15 @@ -187,6 +146,39 @@ bool MAX7291Matrix_init(void) return true; } +// FUNC_DISPLAY_SCROLLDELAY +bool MAX7291Matrix_scrollDelay(void) +{ + if (ArgC() == 0) + { + XdrvMailbox.payload = LedMatrix_settings.scroll_delay; + return true; + } + if (LedMatrix_settings.scroll_delay < 0) + LedMatrix_settings.scroll_delay = 0; + LedMatrix_settings.scroll_delay = XdrvMailbox.payload; + return true; +} + +// FUNC_DISPLAY_EVERY_50_MSECOND +bool MAX7291Matrix_scrollText(void) +{ + // This function is called every 50 ms. + // scroll_delay defines the number of cycles to be ignored until the display scrolls by one pixel to the left. + // e.g. scrall_delay = 4 causes a scroll each 200 ms. + LedMatrix_settings.scroll_iteration++; + if (LedMatrix_settings.scroll_delay) + LedMatrix_settings.scroll_iteration = LedMatrix_settings.scroll_iteration % LedMatrix_settings.scroll_delay; + else + LedMatrix_settings.scroll_iteration = 0; + if (LedMatrix_settings.scroll_iteration) + return false; + + return max7219_Matrix->scrollText(); +} + +#ifdef USE_DISPLAY_MODES1TO5 +// FUNC_DISPLAY_CLOCK bool MAX7291Matrix_clock(void) { LedMatrix_settings.show_clock = XdrvMailbox.payload; @@ -213,11 +205,11 @@ bool MAX7291Matrix_clock(void) AddLog(LOG_LEVEL_DEBUG, PSTR("MTX: LedMatrix_settings.show_clock %d, timeFormat %s"), LedMatrix_settings.show_clock, LedMatrix_settings.timeFormat); - //max7219_Matrix->clearDisplay(); MAX7291Matrix_showTime(); return true; } +// FUNC_DISPLAY_EVERY_SECOND bool MAX7291Matrix_showTime() { time_t rawtime; @@ -227,11 +219,12 @@ bool MAX7291Matrix_showTime() time(&rawtime); timeinfo = localtime(&rawtime); strftime(timeStr, 10, LedMatrix_settings.timeFormat, timeinfo); - //AddLog(LOG_LEVEL_DEBUG, PSTR("MTX: showTime:%s"), timeStr); max7219_Matrix->drawText(timeStr); return true; } +#endif // USE_DISPLAY_MODES1TO5 + bool Xdsp19(uint8_t function) { @@ -260,30 +253,28 @@ bool Xdsp19(uint8_t function) case FUNC_DISPLAY_DIM: result = max7219_Matrix->setIntensity(GetDisplayDimmer16()); break; - case FUNC_DISPLAY_CLOCK: - result = MAX7291Matrix_clock(); - break; - case FUNC_DISPLAY_SEVENSEG_TEXT: - case FUNC_DISPLAY_SEVENSEG_TEXTNC: - case FUNC_DISPLAY_NUMBER: - case FUNC_DISPLAY_NUMBERNC: - case FUNC_DISPLAY_FLOAT: - case FUNC_DISPLAY_FLOATNC: - case FUNC_DISPLAY_RAW: - case FUNC_DISPLAY_LEVEL: - case FUNC_DISPLAY_SCROLLTEXT: case FUNC_DISPLAY_DRAW_STRING: result = max7219_Matrix->drawText(dsp_str); break; + case FUNC_DISPLAY_SCROLLDELAY: + result = MAX7291Matrix_scrollDelay(); + break; + case FUNC_DISPLAY_EVERY_50_MSECOND: + result = MAX7291Matrix_scrollText(); + break; + +#ifdef USE_DISPLAY_MODES1TO5 + case FUNC_DISPLAY_CLOCK: + result = MAX7291Matrix_clock(); + break; case FUNC_DISPLAY_EVERY_SECOND: if (LedMatrix_settings.show_clock) { result = MAX7291Matrix_showTime(); } - break; - case FUNC_DISPLAY_EVERY_50_MSECOND: - result = max7219_Matrix->scrollText(); +#endif // USE_DISPLAY_MODES1TO5 + default: result = false; }