From dea80e6a1743a02e119fe0a9bb4a00c3e6301d1e Mon Sep 17 00:00:00 2001 From: nickshl Date: Thu, 4 Oct 2018 20:23:23 -0500 Subject: DevCore - initial version --- Display/DisplayDrv.cpp | 573 +++++++++++++++++++++ Display/DisplayDrv.h | 202 ++++++++ Display/Fonts.c | 1312 ++++++++++++++++++++++++++++++++++++++++++++++++ Display/Fonts.h | 47 ++ Display/ILI9341.cpp | 566 +++++++++++++++++++++ Display/ILI9341.h | 258 ++++++++++ Display/Image.cpp | 366 ++++++++++++++ Display/Image.h | 178 +++++++ Display/Primitives.cpp | 326 ++++++++++++ Display/Primitives.h | 161 ++++++ Display/Strings.cpp | 242 +++++++++ Display/Strings.h | 146 ++++++ Display/TiledMap.cpp | 179 +++++++ Display/TiledMap.h | 131 +++++ Display/VisObject.cpp | 125 +++++ Display/VisObject.h | 199 ++++++++ Display/XPT2046.cpp | 145 ++++++ Display/XPT2046.h | 129 +++++ 18 files changed, 5285 insertions(+) create mode 100644 Display/DisplayDrv.cpp create mode 100644 Display/DisplayDrv.h create mode 100644 Display/Fonts.c create mode 100644 Display/Fonts.h create mode 100644 Display/ILI9341.cpp create mode 100644 Display/ILI9341.h create mode 100644 Display/Image.cpp create mode 100644 Display/Image.h create mode 100644 Display/Primitives.cpp create mode 100644 Display/Primitives.h create mode 100644 Display/Strings.cpp create mode 100644 Display/Strings.h create mode 100644 Display/TiledMap.cpp create mode 100644 Display/TiledMap.h create mode 100644 Display/VisObject.cpp create mode 100644 Display/VisObject.h create mode 100644 Display/XPT2046.cpp create mode 100644 Display/XPT2046.h (limited to 'Display') diff --git a/Display/DisplayDrv.cpp b/Display/DisplayDrv.cpp new file mode 100644 index 0000000..16c1eac --- /dev/null +++ b/Display/DisplayDrv.cpp @@ -0,0 +1,573 @@ +//****************************************************************************** +// @file DisplayDrv.cpp +// @author Nicolai Shlapunov +// +// @details DevCore: Display Driver Class, implementation +// +// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov +// All rights reserved. +// +// @section SUPPORT +// +// Devtronic invests time and resources providing this open source code, +// please support Devtronic and open-source hardware/software by +// donations and/or purchasing products from Devtronic. +// +//****************************************************************************** + +// ***************************************************************************** +// *** Includes ************************************************************ +// ***************************************************************************** +#include "DisplayDrv.h" + +// ***************************************************************************** +// *** Get Instance ******************************************************** +// ***************************************************************************** +DisplayDrv& DisplayDrv::GetInstance(void) +{ + static DisplayDrv display_drv; + return display_drv; +} + +// ***************************************************************************** +// *** Display Driver Setup ************************************************ +// ***************************************************************************** +Result DisplayDrv::Setup() +{ + // Init display driver + tft.Init(); + // Set mode - mode can be set earlier than Display initialization + SetUpdateMode(update_mode); + + // If deisplay and touchscreen share same SPI + if(tft_hspi == touch_hspi) + { + // Set prescaler for SPI + MODIFY_REG(tft_hspi->Instance->CR1, (uint32_t)SPI_CR1_BR_Msk, SPI_BAUDRATEPRESCALER_64); + // Init touchscreen driver + touch.Init(); + // Restore prescaler for SPI + MODIFY_REG(tft_hspi->Instance->CR1, (uint32_t)SPI_CR1_BR_Msk, SPI_BAUDRATEPRESCALER_2); + } + else + { + // Init touchscreen driver + touch.Init(); + } + + // Set string parameters + fps_str.SetParams(str, width/3, height - 6, COLOR_MAGENTA, String::FONT_4x6); + // Show string if flag is set + if(DISPLAY_DEBUG_INFO) + { + // Max Z + fps_str.Show(0xFFFFFFFFU); + } + + // Always ok + return Result::RESULT_OK; +} + +// ***************************************************************************** +// *** Display Driver Loop ************************************************* +// ***************************************************************************** +Result DisplayDrv::Loop() +{ + // Variable for find FPS + uint32_t time_ms = HAL_GetTick(); + + // If semaphore doesn't exist or taken within 100 ms - draw screen + // Time need for update touchscreen state every 100 ms even display not + // updated + if(screen_update.Take(100U) == Result::RESULT_OK) + { + // Set window for all screen and pointer to first pixel + LockDisplay(); + // Set address window for all screen + tft.SetAddrWindow(0, 0, width-1, height-1); + // For each line/row + for(int32_t i=0; i < height; i++) + { + // Clear half of buffer + memset(scr_buf[i%2], 0x00, sizeof(scr_buf[0])); + // Take semaphore before draw line + line_mutex.Lock(); + // Set pointer to first element + VisObject* p_obj = object_list; + // Do for all objects + while(p_obj != nullptr) + { + // Draw object to buf + if(update_mode) p_obj->DrawInBufH(scr_buf[i%2], width, i); + else p_obj->DrawInBufW(scr_buf[i%2], width, i); + // Set pointer to next object in list + p_obj = p_obj->p_next; + } + // Give semaphore after changes + line_mutex.Release(); + // Wait until previous transfer complete + while(tft.IsTransferComplete() == false) taskYIELD(); + // Write stream to LCD + tft.SpiWriteStream((uint8_t*)scr_buf[i%2], width*tft.GetBytesPerPixel()); + // DO NOT TRY "OPTIMIZE" CODE !!! + // Two "while" cycles used for generate next line when previous line + // transfer via SPI to display. + } + // Wait until last transfer complete + while(tft.IsTransferComplete() == false) taskYIELD(); + // Pull up CS + tft.StopTransfer(); + // Give semaphore after draw frame + UnlockDisplay(); + // Calculate FPS if debug info is ON + if(DISPLAY_DEBUG_INFO) + { + // FPS in format XX.X + fps_x10 = (1000 * 10) / (HAL_GetTick() - time_ms); + } + } + + bool tmp_is_touch = false; + int32_t tmp_tx = tx; + int32_t tmp_ty = ty; + // Try to take mutex. 1 ms should be enough. + if(touchscreen_mutex.Lock(1U) == Result::RESULT_OK) + { + // Set prescaler for SPI it display share save SPI with touchscreen + if(tft_hspi == touch_hspi) + { + MODIFY_REG(tft_hspi->Instance->CR1, (uint32_t)SPI_CR1_BR_Msk, SPI_BAUDRATEPRESCALER_64); + } + // Get touch coordinates + tmp_is_touch = touch.GetXY(tmp_tx, tmp_ty); + // Reset prescaler for SPI it display share save SPI with touchscreen + if(tft_hspi == touch_hspi) + { + // Restore prescaler for SPI + MODIFY_REG(tft_hspi->Instance->CR1, (uint32_t)SPI_CR1_BR_Msk, SPI_BAUDRATEPRESCALER_2); + } + // Give semaphore for drawing frame - we can enter in this "if" statement + // only if mutex taken + touchscreen_mutex.Release(); + } + // If touch state changed (move) + if(is_touch && tmp_is_touch && ((tx != tmp_tx) || (ty != tmp_ty)) ) + { + // Go thru VisObject list and call Active() function for active object + // Take semaphore before draw line + line_mutex.Lock(); + // Set pointer to first element + VisObject* p_obj = object_list_last; + // If list not empty + if(p_obj != nullptr) + { + // Do for all objects + while(p_obj != nullptr) + { + // If we found active object + if(p_obj->active) + { + // And touch in this object area + if( (tx >= p_obj->GetStartX()) && (tx <= p_obj->GetEndX()) + && (ty >= p_obj->GetStartY()) && (ty <= p_obj->GetEndY()) + && (tmp_tx >= p_obj->GetStartX()) && (tmp_tx <= p_obj->GetEndX()) + && (tmp_ty >= p_obj->GetStartY()) && (tmp_ty <= p_obj->GetEndY()) ) + { + // Call Action() function for Move + p_obj->Action(VisObject::ACT_MOVE, tmp_tx, tmp_ty); + // No need check all other objects - only one object can be touched + break; + } + if( (tx >= p_obj->GetStartX()) && (tx <= p_obj->GetEndX()) + && (ty >= p_obj->GetStartY()) && (ty <= p_obj->GetEndY()) + && ( ((tmp_tx < p_obj->GetStartX()) || (tmp_tx > p_obj->GetEndX())) + || ((tmp_ty < p_obj->GetStartY()) || (tmp_ty > p_obj->GetEndY())) ) ) + { + // Call Action() function for Move Out + p_obj->Action(VisObject::ACT_MOVEOUT, tmp_tx, tmp_ty); + } + if( (tmp_tx >= p_obj->GetStartX()) && (tmp_tx <= p_obj->GetEndX()) + && (tmp_ty >= p_obj->GetStartY()) && (tmp_ty <= p_obj->GetEndY()) + && ( ((tx < p_obj->GetStartX()) || (tx > p_obj->GetEndX())) + || ((ty < p_obj->GetStartY()) || (ty > p_obj->GetEndY())) ) ) + { + // Call Action() function for Move In + p_obj->Action(VisObject::ACT_MOVEIN, tmp_tx, tmp_ty); + } + } + // Get previous object + p_obj = p_obj->p_prev; + } + } + // Give semaphore after changes + line_mutex.Release(); + } + // If touch state changed (touch & release) + if(is_touch != tmp_is_touch) + { + // Go thru VisObject list and call Active() function for active object + // Take semaphore before draw line + line_mutex.Lock(); + // Set pointer to first element + VisObject* p_obj = object_list_last; + // If list not empty + if(p_obj != nullptr) + { + // Do for all objects + while(p_obj != nullptr) + { + // If we found active object + if(p_obj->active) + { + // And touch in this object area + if( (tmp_tx >= p_obj->GetStartX()) && (tmp_tx <= p_obj->GetEndX()) + && (tmp_ty >= p_obj->GetStartY()) && (tmp_ty <= p_obj->GetEndY()) ) + { + // Call Action() function + p_obj->Action(tmp_is_touch ? VisObject::ACT_TOUCH : VisObject::ACT_UNTOUCH, + tmp_tx, tmp_ty); + // No need check all other objects - only one object can be touched + break; + } + } + // Get previous object + p_obj = p_obj->p_prev; + } + } + // Give semaphore after changes + line_mutex.Release(); + } + // Save new touch state + is_touch = tmp_is_touch; + tx = tmp_tx; + ty = tmp_ty; + + // FIX ME: debug code. Should be removed. + if(DISPLAY_DEBUG_INFO) + { + if(is_touch) sprintf(str, "X: %4ld, Y: %4ld", tx, ty); + else sprintf(str, "FPS: %2lu.%1lu, time: %lu", fps_x10/10, fps_x10%10, RtosTick::GetTimeMs()/1000UL); + fps_str.SetString(str); + } + + // Always run + return Result::RESULT_OK; +} + +// ***************************************************************************** +// *** Add Visual Object to object list ************************************ +// ***************************************************************************** +Result DisplayDrv::AddVisObjectToList(VisObject* obj, uint32_t z) +{ + Result result = Result::ERR_NULL_PTR; + + if((obj != nullptr) && (obj->p_prev == nullptr) && (obj->p_next == nullptr) && (obj != object_list)) + { + // Take semaphore before add to list + line_mutex.Lock(); + // Set object Z + obj->z = z; + // Set prev pointer to nullptr + obj->p_prev = nullptr; + // Set next pointer to nullptr + obj->p_next = nullptr; + // If object list empty + if(object_list == nullptr) + { + // Add object to list + object_list = obj; + // Set pointer to last object in the list + object_list_last = obj; + } + else if(object_list->z > z) + { + // Set next element to current head element + obj->p_next = object_list; + // Set prev element to next after head element + object_list->p_prev = obj; + // Set new head for list + object_list = obj; + } + else + { + // Set temporary pointer + VisObject* p_last = object_list; + // Find last element + while((p_last->p_next != nullptr) && (p_last->p_next->z < z)) p_last = p_last->p_next; + // If it not last element + if(p_last->p_next != nullptr) + { + // Set next pointer in object + obj->p_next = p_last->p_next; + // Set prev pointer in object + obj->p_next->p_prev = obj; + } + else + { + // Set pointer to last object in the list + object_list_last = obj; + } + // Set next pointer in prev element + p_last->p_next = obj; + // Set prev pointer to new object in list + obj->p_prev = p_last; + } + // Give semaphore after changes + line_mutex.Release(); + // Set return status + result = Result::RESULT_OK; + } + + return result; +} + +// ***************************************************************************** +// *** Delete Visual Object from object list ******************************* +// ***************************************************************************** +Result DisplayDrv::DelVisObjectFromList(VisObject* obj) +{ + Result result = Result::ERR_NULL_PTR; + + if((obj != nullptr) && ((obj->p_prev != nullptr) || (obj->p_next != nullptr) || (obj == object_list)) ) + { + // Take semaphore before delete from list + line_mutex.Lock(); + // Remove element from head + if(obj == object_list) + { + // Set pointer to next object or clear pointer if no more elements + object_list = obj->p_next; + // Clear previous element in first object + object_list->p_prev = nullptr; + } + else if(obj == object_list_last) + { + // Set next pointer in previous object to nullptr + obj->p_prev->p_next = nullptr; + // Set pointer to previous object + object_list_last = obj->p_prev; + } + else + { + // Remove element from head + if(obj->p_prev == nullptr) object_list = obj->p_next; + // Remove element from middle + else if(obj->p_next != nullptr) + { + obj->p_prev->p_next = obj->p_next; + obj->p_next->p_prev = obj->p_prev; + } + // remove element from tail + else obj->p_prev->p_next = nullptr; + } + // Clear pointers in object + obj->p_prev = nullptr; + obj->p_next = nullptr; + // Give semaphore after changes + line_mutex.Release(); + // Set return status + result = Result::RESULT_OK; + } + + return result; +} + +// ***************************************************************************** +// *** Lock display ******************************************************** +// ***************************************************************************** +Result DisplayDrv::LockDisplay(uint32_t wait_ms) +{ + // Take semaphore for protect draw frame + Result result = frame_mutex.Lock(wait_ms); + // Return result + return result; +} + +// ***************************************************************************** +// *** Unlock display ****************************************************** +// ***************************************************************************** +Result DisplayDrv::UnlockDisplay(void) +{ + // Give semaphore for drawing frame + Result result = frame_mutex.Release(); + // Return result + return result; +} + +// ***************************************************************************** +// *** Lock display line *************************************************** +// ***************************************************************************** +Result DisplayDrv::LockDisplayLine(uint32_t wait_ms) +{ + // Take semaphore for protect draw line + Result result = line_mutex.Lock(wait_ms); + // Return result + return result; +} + +// ***************************************************************************** +// *** Unlock display line ************************************************* +// ***************************************************************************** +Result DisplayDrv::UnlockDisplayLine(void) +{ + // Give semaphore for drawing frame + Result result = line_mutex.Release(); + // Return result + return result; +} + +// ***************************************************************************** +// *** Update display ****************************************************** +// ***************************************************************************** +Result DisplayDrv::UpdateDisplay(void) +{ + // Give semaphore for update screen + Result result = screen_update.Give(); + // Return result + return result; +} + +// ***************************************************************************** +// *** Set Update Mode ***************************************************** +// ***************************************************************************** +void DisplayDrv::SetUpdateMode(bool is_vertical) +{ + // Lock display + LockDisplay(); + // Wait while transfer complete before change settings + while(tft.IsTransferComplete() == false); + // Change Update mode + if(is_vertical) + { + tft.SetRotation(2U); + } + else + { + tft.SetRotation(3U); + } + // Set width and height variables for selected screen update mode + width = tft.GetWidth(); + height = tft.GetHeight(); + // Save Update mode + update_mode = is_vertical; + // Unlock display + UnlockDisplay(); +} + +// ***************************************************************************** +// *** Get Touch X and Y coordinate **************************************** +// ***************************************************************************** +bool DisplayDrv::GetTouchXY(int32_t& x, int32_t& y) +{ + // Result variable + bool result = false; + + // Try to take mutex. 1 ms should be enough. + if(touchscreen_mutex.Lock(1U) == Result::RESULT_OK) + { + // If display driver gets touch coordinates and touch still present + if(is_touch && touch.IsTouch()) + { + // Return last values + x = tx; + y = ty; + // Set result + result = true; + } + else + { + // If no touch - clear flag for prevent return wrong coordinates if + // display will touched without reads new coordinates + is_touch = false; + } + // Give semaphore for drawing frame - we can enter in this "if" statement + // only if mutex taken + touchscreen_mutex.Release(); + } + // Return result + return result; +} + +// ************************************************************************* +// *** Check touch ***************************************************** +// ************************************************************************* +bool DisplayDrv::IsTouch() +{ + return touch.IsTouch(); +} + +// ***************************************************************************** +// *** Calibrate Touchscreen *********************************************** +// ***************************************************************************** +void DisplayDrv::TouchCalibrate() +{ + // Box for calibration + Box background(0, 0, width, height, COLOR_BLACK, true); + Box box(0, 0, 2, 2, COLOR_WHITE, true); + int32_t tx; + int32_t ty; + int32_t x1, x2; + int32_t y1, y2; + + // Reset calibration + touch.SetCalibrationConsts(XPT2046::COEF, XPT2046::COEF, 0, 0); + + // Show background box + background.Show(0xFFFFFFFFU-1U); + // Show box + box.Show(0xFFFFFFFFU); + + // Move box to position + box.Move(10-1, 10-1); + // Wait press for get initial coordinates + while(!GetTouchXY(x1, y1)) + { + // Update Display + UpdateDisplay(); + // Delay + RtosTick::DelayMs(100U); + } + // Wait unpress and measure coordinates continuously for averaging + while(GetTouchXY(tx, ty)) + { + x1 = (x1 + tx) / 2; + y1 = (y1 + ty) / 2; + // Update Display - for update touch coordinates + UpdateDisplay(); + // Delay + RtosTick::DelayMs(100U); + } + + // Move box to position + box.Move(width - 10 - 1, height - 10 - 1); + // Wait press for get initial coordinates + while(!GetTouchXY(x2, y2)) + { + // Update Display + UpdateDisplay(); + // Delay + RtosTick::DelayMs(100U); + } + // Wait unpress and measure coordinates continuously for averaging + while(GetTouchXY(tx, ty)) + { + x2 = (x2 + tx) / 2; + y2 = (y2 + ty) / 2; + // Update Display + UpdateDisplay(); + // Delay + RtosTick::DelayMs(100U); + } + + // Calc coefs + int32_t kx = ((x2 - x1) * XPT2046::COEF) / (width - 2*10); + int32_t ky = ((y2 - y1) * XPT2046::COEF) / (height - 2*10); + int32_t bx = 10 - (x1 * XPT2046::COEF) / kx; + int32_t by = 10 - (y1 * XPT2046::COEF) / ky; + + // Save calibration + touch.SetCalibrationConsts(kx, ky, bx, by); + + // Hide box + box.Hide(); +} diff --git a/Display/DisplayDrv.h b/Display/DisplayDrv.h new file mode 100644 index 0000000..aafa814 --- /dev/null +++ b/Display/DisplayDrv.h @@ -0,0 +1,202 @@ +//****************************************************************************** +// @file DisplayDrv.h +// @author Nicolai Shlapunov +// +// @details DevCore: Display Driver Class, header +// +// @section LICENSE +// +// Software License Agreement (BSD License) +// +// Copyright (c) 2016, Devtronic & Nicolai Shlapunov +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// 3. Neither the name of the Devtronic nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL DEVTRONIC BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//****************************************************************************** + +#ifndef DisplayDrv_h +#define DisplayDrv_h + +// ***************************************************************************** +// *** Includes ************************************************************ +// ***************************************************************************** +#include +#include +#include + +#include "DevCfg.h" +#include "AppTask.h" +#include "RtosMutex.h" +#include "RtosSemaphore.h" + +#include "ILI9341.h" +#include "XPT2046.h" +#include "VisObject.h" +#include "Primitives.h" +#include "Strings.h" +#include "Image.h" +#include "TiledMap.h" + +// ***************************************************************************** +// *** Display Driver Class ************************************************ +// ***************************************************************************** +class DisplayDrv : public AppTask +{ + public: + // ************************************************************************* + // *** Get Instance **************************************************** + // ************************************************************************* + static DisplayDrv& GetInstance(void); + + // ************************************************************************* + // *** Display Driver Setup ******************************************** + // ************************************************************************* + virtual Result Setup(); + + // ************************************************************************* + // *** Display Driver Loop ********************************************* + // ************************************************************************* + virtual Result Loop(); + + // ************************************************************************* + // *** Add Visual Object to object list ******************************** + // ************************************************************************* + Result AddVisObjectToList(VisObject* obj, uint32_t z); + + // ************************************************************************* + // *** Delete Visual Object from object list *************************** + // ************************************************************************* + Result DelVisObjectFromList(VisObject* obj); + + // ************************************************************************* + // *** Lock display **************************************************** + // ************************************************************************* + Result LockDisplay(uint32_t wait_ms = portMAX_DELAY); + + // ************************************************************************* + // *** Unlock display ************************************************** + // ************************************************************************* + Result UnlockDisplay(void); + + // ************************************************************************* + // *** Lock display line *********************************************** + // ************************************************************************* + Result LockDisplayLine(uint32_t wait_ms = portMAX_DELAY); + + // ************************************************************************* + // *** Unlock display line ********************************************* + // ************************************************************************* + Result UnlockDisplayLine(void); + + // ************************************************************************* + // *** Update display ************************************************** + // ************************************************************************* + Result UpdateDisplay(void); + + // ************************************************************************* + // *** Set Update Mode ************************************************* + // ************************************************************************* + void SetUpdateMode(bool is_vertical = false); + + // ************************************************************************* + // *** GetScreenW ****************************************************** + // ************************************************************************* + inline int32_t GetScreenW(void) {return width;} + + // ************************************************************************* + // *** GetScreenH ****************************************************** + // ************************************************************************* + inline int32_t GetScreenH(void) {return height;} + + // ************************************************************************* + // *** Get Touch X and Y coordinate ************************************ + // ************************************************************************* + bool GetTouchXY(int32_t& x, int32_t& y); + + // ************************************************************************* + // *** Check touch ***************************************************** + // ************************************************************************* + bool IsTouch(); + + // ************************************************************************* + // *** Calibrate Touchscreen ******************************************* + // ************************************************************************* + void TouchCalibrate(); + + private: + // Display FPS/touch coordinates + static const bool DISPLAY_DEBUG_INFO = true; + + // Display driver object + ILI9341 tft = TFT_HSPI; + // Display SPI handle + SPI_HandleTypeDef* tft_hspi = TFT_HSPI; + + // Touchscreen driver object + XPT2046 touch = TOUCH_HSPI; + // Touchscreen SPI handle + SPI_HandleTypeDef* touch_hspi = TOUCH_HSPI; + + // Pointer to first object in list + VisObject* object_list = nullptr; + // Pointer to last object in list + VisObject* object_list_last = nullptr; + + // Update mode: true - vertical, false = horizontal + bool update_mode = false; + // Variables for update screen mode + int32_t width = 0; + int32_t height = 0; + // Double Screen Line buffer + uint16_t scr_buf[2][ILI9341::GetMaxLine()]; + + // Touch coordinates and state + bool is_touch = false; + int32_t tx = 0; + int32_t ty = 0; + + // FPS multiplied to 10 + volatile uint32_t fps_x10 = 0U; + // Buffer for print FPS string + char str[32] = {" "}; + // FPS string + String fps_str; + + // Semaphore for update screen + RtosSemaphore screen_update; + // Mutex to synchronize when drawing lines + RtosMutex line_mutex; + // Mutex to synchronize when drawing frames + RtosMutex frame_mutex; + // Mutex for synchronize when reads touch coordinates + RtosMutex touchscreen_mutex; + + // ************************************************************************* + // ** Private constructor. Only GetInstance() allow to access this class. ** + // ************************************************************************* + DisplayDrv() : AppTask(DISPLAY_DRV_TASK_STACK_SIZE, DISPLAY_DRV_TASK_PRIORITY, + "DisplayDrv") {}; +}; + +#endif diff --git a/Display/Fonts.c b/Display/Fonts.c new file mode 100644 index 0000000..06bf86b --- /dev/null +++ b/Display/Fonts.c @@ -0,0 +1,1312 @@ +//****************************************************************************** +// @file Fonts.c +// @author Nicolai Shlapunov +// +// @details DevCore: Fonts data +// +// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov +// All rights reserved. +// +// @section SUPPORT +// +// Devtronic invests time and resources providing this open source code, +// please support Devtronic and open-source hardware/software by +// donations and/or purchasing products from Devtronic. +// +//****************************************************************************** + +const unsigned char font4x6[256][6] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x00 - ' ' + {0x04, 0x0A, 0x0E, 0x0A, 0x04, 0x00}, // 0x01 - '' + {0x04, 0x0E, 0x0A, 0x0E, 0x04, 0x00}, // 0x02 - '' + {0x00, 0x0A, 0x0E, 0x0E, 0x04, 0x00}, // 0x03 - '' + {0x00, 0x04, 0x0E, 0x0E, 0x04, 0x00}, // 0x04 - '' + {0x04, 0x0E, 0x0E, 0x04, 0x0E, 0x00}, // 0x05 - '' + {0x04, 0x04, 0x0E, 0x04, 0x0E, 0x00}, // 0x06 - '' + {0x00, 0x00, 0x04, 0x00, 0x00, 0x00}, // 0x07 - '' + {0x0F, 0x0F, 0x0B, 0x0F, 0x0F, 0x0F}, // 0x08 - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x09 - ' ' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0A - ' ' + {0x00, 0x0C, 0x08, 0x06, 0x06, 0x00}, // 0x0B - ' ' + {0x04, 0x0A, 0x04, 0x0E, 0x04, 0x00}, // 0x0C - ' ' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0D - ' ' + {0x04, 0x0C, 0x0A, 0x08, 0x04, 0x00}, // 0x0E - '' + {0x04, 0x0E, 0x0A, 0x0E, 0x04, 0x00}, // 0x0F - '' + {0x02, 0x06, 0x0E, 0x06, 0x02, 0x00}, // 0x10 - '' + {0x08, 0x0C, 0x0E, 0x0C, 0x08, 0x00}, // 0x11 - '' + {0x04, 0x0E, 0x04, 0x0E, 0x04, 0x00}, // 0x12 - '' + {0x0A, 0x0A, 0x0A, 0x00, 0x0A, 0x00}, // 0x13 - '' + {0x0E, 0x0B, 0x0B, 0x0A, 0x0A, 0x00}, // 0x14 - '' + {0x0C, 0x06, 0x0A, 0x0C, 0x06, 0x00}, // 0x15 - '' + {0x00, 0x00, 0x06, 0x06, 0x00, 0x00}, // 0x16 - '' + {0x04, 0x0E, 0x04, 0x0E, 0x04, 0x0E}, // 0x17 - '' + {0x04, 0x0E, 0x04, 0x04, 0x04, 0x00}, // 0x18 - '' + {0x04, 0x04, 0x04, 0x0E, 0x04, 0x00}, // 0x19 - '' + {0x00, 0x04, 0x0F, 0x04, 0x00, 0x00}, // 0x1A - ' ' + {0x00, 0x02, 0x0F, 0x02, 0x00, 0x00}, // 0x1B - '' + {0x00, 0x00, 0x02, 0x0E, 0x00, 0x00}, // 0x1C - '' + {0x00, 0x0A, 0x0E, 0x0A, 0x00, 0x00}, // 0x1D - '' + {0x00, 0x04, 0x0E, 0x0E, 0x00, 0x00}, // 0x1E - '' + {0x00, 0x0E, 0x0E, 0x04, 0x00, 0x00}, // 0x1F - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x20 - ' ' + {0x04, 0x04, 0x04, 0x00, 0x04, 0x00}, // 0x21 - '!' + {0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00}, // 0x22 - '"' + {0x0A, 0x0E, 0x0A, 0x0E, 0x0A, 0x00}, // 0x23 - '#' + {0x04, 0x0C, 0x06, 0x0C, 0x06, 0x04}, // 0x24 - '$' + {0x02, 0x08, 0x04, 0x02, 0x08, 0x00}, // 0x25 - '%' + {0x04, 0x0A, 0x0C, 0x0A, 0x0E, 0x00}, // 0x26 - '&' + {0x06, 0x02, 0x00, 0x00, 0x00, 0x00}, // 0x27 - ''' + {0x04, 0x02, 0x02, 0x02, 0x04, 0x00}, // 0x28 - '(' + {0x02, 0x04, 0x04, 0x04, 0x02, 0x00}, // 0x29 - ')' + {0x0A, 0x04, 0x0E, 0x04, 0x0A, 0x00}, // 0x2A - '*' + {0x00, 0x04, 0x0E, 0x04, 0x00, 0x00}, // 0x2B - '+' + {0x00, 0x00, 0x00, 0x00, 0x06, 0x02}, // 0x2C - ',' + {0x00, 0x00, 0x0E, 0x00, 0x00, 0x00}, // 0x2D - '-' + {0x00, 0x00, 0x00, 0x00, 0x04, 0x00}, // 0x2E - '.' + {0x08, 0x08, 0x04, 0x02, 0x02, 0x00}, // 0x2F - '/' + {0x0C, 0x0A, 0x0A, 0x0A, 0x06, 0x00}, // 0x30 - '0' + {0x04, 0x06, 0x04, 0x04, 0x0E, 0x00}, // 0x31 - '1' + {0x06, 0x08, 0x04, 0x02, 0x0E, 0x00}, // 0x32 - '2' + {0x06, 0x08, 0x04, 0x08, 0x06, 0x00}, // 0x33 - '3' + {0x08, 0x0A, 0x0E, 0x08, 0x08, 0x00}, // 0x34 - '4' + {0x0E, 0x02, 0x06, 0x08, 0x06, 0x00}, // 0x35 - '5' + {0x04, 0x02, 0x06, 0x0A, 0x04, 0x00}, // 0x36 - '6' + {0x0E, 0x08, 0x0C, 0x04, 0x04, 0x00}, // 0x37 - '7' + {0x04, 0x0A, 0x04, 0x0A, 0x04, 0x00}, // 0x38 - '8' + {0x04, 0x0A, 0x0C, 0x08, 0x04, 0x00}, // 0x39 - '9' + {0x00, 0x00, 0x04, 0x00, 0x04, 0x00}, // 0x3A - ':' + {0x00, 0x00, 0x04, 0x00, 0x06, 0x02}, // 0x3B - ';' + {0x08, 0x04, 0x02, 0x04, 0x08, 0x00}, // 0x3C - '<' + {0x00, 0x00, 0x0E, 0x00, 0x0E, 0x00}, // 0x3D - '=' + {0x02, 0x04, 0x08, 0x04, 0x02, 0x00}, // 0x3E - '>' + {0x06, 0x08, 0x04, 0x00, 0x04, 0x00}, // 0x3F - '?' + {0x0E, 0x0A, 0x0A, 0x02, 0x0E, 0x00}, // 0x40 - '@' + {0x04, 0x0A, 0x0E, 0x0A, 0x0A, 0x00}, // 0x41 - 'A' + {0x06, 0x0A, 0x06, 0x0A, 0x06, 0x00}, // 0x42 - 'B' + {0x0C, 0x02, 0x02, 0x02, 0x0C, 0x00}, // 0x43 - 'C' + {0x06, 0x0A, 0x0A, 0x0A, 0x06, 0x00}, // 0x44 - 'D' + {0x0E, 0x02, 0x06, 0x02, 0x0E, 0x00}, // 0x45 - 'E' + {0x0E, 0x02, 0x06, 0x02, 0x02, 0x00}, // 0x46 - 'F' + {0x0C, 0x02, 0x0A, 0x0A, 0x0C, 0x00}, // 0x47 - 'G' + {0x0A, 0x0A, 0x0E, 0x0A, 0x0A, 0x00}, // 0x48 - 'H' + {0x0E, 0x04, 0x04, 0x04, 0x0E, 0x00}, // 0x49 - 'I' + {0x08, 0x08, 0x08, 0x0A, 0x04, 0x00}, // 0x4A - 'J' + {0x0A, 0x0A, 0x06, 0x0A, 0x0A, 0x00}, // 0x4B - 'K' + {0x02, 0x02, 0x02, 0x02, 0x0E, 0x00}, // 0x4C - 'L' + {0x0A, 0x0E, 0x0E, 0x0A, 0x0A, 0x00}, // 0x4D - 'M' + {0x0A, 0x0E, 0x0A, 0x0A, 0x0A, 0x00}, // 0x4E - 'N' + {0x04, 0x0A, 0x0A, 0x0A, 0x04, 0x00}, // 0x4F - 'O' + {0x06, 0x0A, 0x06, 0x02, 0x02, 0x00}, // 0x50 - 'P' + {0x04, 0x0A, 0x0A, 0x0E, 0x0C, 0x00}, // 0x51 - 'Q' + {0x06, 0x0A, 0x06, 0x0A, 0x0A, 0x00}, // 0x52 - 'R' + {0x0C, 0x02, 0x0E, 0x08, 0x06, 0x00}, // 0x53 - 'S' + {0x0E, 0x04, 0x04, 0x04, 0x04, 0x00}, // 0x54 - 'T' + {0x0A, 0x0A, 0x0A, 0x0A, 0x0E, 0x00}, // 0x55 - 'U' + {0x0A, 0x0A, 0x0A, 0x0A, 0x04, 0x00}, // 0x56 - 'V' + {0x0A, 0x0A, 0x0E, 0x0E, 0x0A, 0x00}, // 0x57 - 'W' + {0x0A, 0x0A, 0x04, 0x0A, 0x0A, 0x00}, // 0x58 - 'X' + {0x0A, 0x0A, 0x04, 0x04, 0x04, 0x00}, // 0x59 - 'Y' + {0x0E, 0x08, 0x04, 0x02, 0x0E, 0x00}, // 0x5A - 'Z' + {0x06, 0x02, 0x02, 0x02, 0x06, 0x00}, // 0x5B - '[' + {0x02, 0x02, 0x04, 0x08, 0x08, 0x00}, // 0x5C - '\' + {0x06, 0x04, 0x04, 0x04, 0x06, 0x00}, // 0x5D - ']' + {0x04, 0x0A, 0x00, 0x00, 0x00, 0x00}, // 0x5E - '^' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x0F}, // 0x5F - '_' + {0x06, 0x04, 0x00, 0x00, 0x00, 0x00}, // 0x60 - '`' + {0x00, 0x00, 0x0C, 0x0A, 0x0E, 0x00}, // 0x61 - 'a' + {0x02, 0x02, 0x06, 0x0A, 0x06, 0x00}, // 0x62 - 'b' + {0x00, 0x00, 0x0C, 0x02, 0x0C, 0x00}, // 0x63 - 'c' + {0x08, 0x08, 0x0C, 0x0A, 0x0C, 0x00}, // 0x64 - 'd' + {0x00, 0x00, 0x0E, 0x06, 0x0C, 0x00}, // 0x65 - 'e' + {0x08, 0x04, 0x0E, 0x04, 0x04, 0x00}, // 0x66 - 'f' + {0x00, 0x00, 0x0E, 0x0A, 0x08, 0x0E}, // 0x67 - 'g' + {0x02, 0x02, 0x06, 0x0A, 0x0A, 0x00}, // 0x68 - 'h' + {0x04, 0x00, 0x04, 0x04, 0x04, 0x00}, // 0x69 - 'i' + {0x04, 0x00, 0x04, 0x04, 0x04, 0x06}, // 0x6A - 'j' + {0x02, 0x02, 0x0A, 0x06, 0x0A, 0x00}, // 0x6B - 'k' + {0x04, 0x04, 0x04, 0x04, 0x04, 0x00}, // 0x6C - 'l' + {0x00, 0x00, 0x0E, 0x0E, 0x0A, 0x00}, // 0x6D - 'm' + {0x00, 0x00, 0x06, 0x0A, 0x0A, 0x00}, // 0x6E - 'n' + {0x00, 0x00, 0x04, 0x0A, 0x04, 0x00}, // 0x6F - 'o' + {0x00, 0x00, 0x06, 0x0A, 0x06, 0x02}, // 0x70 - 'p' + {0x00, 0x00, 0x0C, 0x0A, 0x0C, 0x08}, // 0x71 - 'q' + {0x00, 0x00, 0x06, 0x02, 0x02, 0x00}, // 0x72 - 'r' + {0x00, 0x00, 0x0C, 0x04, 0x06, 0x00}, // 0x73 - 's' + {0x00, 0x04, 0x0E, 0x04, 0x0C, 0x00}, // 0x74 - 't' + {0x00, 0x00, 0x0A, 0x0A, 0x0E, 0x00}, // 0x75 - 'u' + {0x00, 0x00, 0x0A, 0x0A, 0x04, 0x00}, // 0x76 - 'v' + {0x00, 0x00, 0x0A, 0x0E, 0x0E, 0x00}, // 0x77 - 'w' + {0x00, 0x00, 0x0A, 0x04, 0x0A, 0x00}, // 0x78 - 'x' + {0x00, 0x00, 0x0A, 0x0A, 0x04, 0x02}, // 0x79 - 'y' + {0x00, 0x00, 0x06, 0x04, 0x0C, 0x00}, // 0x7A - 'z' + {0x0C, 0x04, 0x06, 0x04, 0x0C, 0x00}, // 0x7B - '{' + {0x04, 0x04, 0x04, 0x04, 0x04, 0x00}, // 0x7C - '|' + {0x06, 0x04, 0x0C, 0x04, 0x06, 0x00}, // 0x7D - '}' + {0x0A, 0x05, 0x00, 0x00, 0x00, 0x00}, // 0x7E - '~' + {0x00, 0x04, 0x0A, 0x0E, 0x00, 0x00}, // 0x7F - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x80 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x81 - '�' + {0x06, 0x02, 0x00, 0x00, 0x00, 0x00}, // 0x82 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x83 - '�' + {0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00}, // 0x84 - '�' + {0x00, 0x00, 0x04, 0x00, 0x04, 0x00}, // 0x85 - '�' + {0x04, 0x04, 0x0F, 0x04, 0x04, 0x04}, // 0x86 - '�' + {0x04, 0x0F, 0x00, 0x0F, 0x04, 0x04}, // 0x87 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x88 - '�' + {0x02, 0x08, 0x04, 0x02, 0x08, 0x00}, // 0x89 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8A - '�' + {0x08, 0x04, 0x02, 0x04, 0x08, 0x00}, // 0x8B - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8C - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8D - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8E - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8F - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x90 - '�' + {0x06, 0x02, 0x00, 0x00, 0x00, 0x00}, // 0x91 - '�' + {0x06, 0x02, 0x00, 0x00, 0x00, 0x00}, // 0x92 - '�' + {0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00}, // 0x93 - '�' + {0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00}, // 0x94 - '�' + {0x00, 0x00, 0x04, 0x00, 0x00, 0x00}, // 0x95 - '�' + {0x00, 0x00, 0x0E, 0x00, 0x00, 0x00}, // 0x96 - '�' + {0x00, 0x00, 0x0E, 0x00, 0x00, 0x00}, // 0x97 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x98 - '�' + {0x0E, 0x04, 0x04, 0x04, 0x04, 0x00}, // 0x99 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9A - '�' + {0x02, 0x04, 0x08, 0x04, 0x02, 0x00}, // 0x9B - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9C - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9D - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9E - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9F - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA0 - '�' + {0x07, 0x05, 0x07, 0x04, 0x03, 0x00}, // 0xA1 - '�' + {0x00, 0x02, 0x05, 0x05, 0x02, 0x01}, // 0xA2 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA3 - '�' + {0x00, 0x07, 0x05, 0x05, 0x07, 0x00}, // 0xA4 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA5 - '�' + {0x04, 0x04, 0x04, 0x04, 0x04, 0x04}, // 0xA6 - '�' + {0x0C, 0x06, 0x0A, 0x0C, 0x06, 0x00}, // 0xA7 - '�' + {0x07, 0x01, 0x03, 0x01, 0x07, 0x00}, // 0xA8 - '�' + {0x00, 0x00, 0x0C, 0x02, 0x0C, 0x00}, // 0xA9 - '�' + {0x06, 0x01, 0x07, 0x01, 0x06, 0x00}, // 0xAA - '�' + {0x08, 0x04, 0x02, 0x04, 0x08, 0x00}, // 0xAB - '�' + {0x00, 0x00, 0x07, 0x04, 0x04, 0x04}, // 0xAC - '�' + {0x00, 0x00, 0x0E, 0x00, 0x00, 0x00}, // 0xAD - '�' + {0x06, 0x0A, 0x06, 0x0A, 0x0A, 0x00}, // 0xAE - '�' + {0x05, 0x02, 0x02, 0x02, 0x02, 0x00}, // 0xAF - '�' + {0x04, 0x0A, 0x04, 0x00, 0x00, 0x00}, // 0xB0 - '�' + {0x00, 0x04, 0x0E, 0x04, 0x00, 0x00}, // 0xB1 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB2 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB3 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB4 - '�' + {0x00, 0x00, 0x05, 0x07, 0x04, 0x00}, // 0xB5 - '�' + {0x0E, 0x0B, 0x0B, 0x0A, 0x0A, 0x00}, // 0xB6 - '�' + {0x00, 0x00, 0x04, 0x00, 0x00, 0x00}, // 0xB7 - '�' + {0x05, 0x00, 0x07, 0x03, 0x06, 0x00}, // 0xB8 - '�' + {0x05, 0x07, 0x07, 0x07, 0x05, 0x00}, // 0xB9 - '�' + {0x00, 0x00, 0x06, 0x03, 0x06, 0x00}, // 0xBA - '�' + {0x02, 0x04, 0x08, 0x04, 0x02, 0x00}, // 0xBB - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBC - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBD - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBE - '�' + {0x00, 0x00, 0x05, 0x02, 0x02, 0x00}, // 0xBF - '�' + {0x02, 0x05, 0x07, 0x05, 0x05, 0x00}, // 0xC0 - '�' + {0x07, 0x01, 0x03, 0x05, 0x03, 0x00}, // 0xC1 - '�' + {0x03, 0x05, 0x03, 0x05, 0x03, 0x00}, // 0xC2 - '�' + {0x07, 0x01, 0x01, 0x01, 0x01, 0x00}, // 0xC3 - '�' + {0x02, 0x02, 0x02, 0x07, 0x05, 0x00}, // 0xC4 - '�' + {0x07, 0x01, 0x03, 0x01, 0x07, 0x00}, // 0xC5 - '�' + {0x05, 0x07, 0x02, 0x07, 0x05, 0x00}, // 0xC6 - '�' + {0x07, 0x04, 0x06, 0x04, 0x07, 0x00}, // 0xC7 - '�' + {0x05, 0x05, 0x07, 0x07, 0x05, 0x00}, // 0xC8 - '�' + {0x07, 0x05, 0x07, 0x07, 0x05, 0x00}, // 0xC9 - '�' + {0x05, 0x03, 0x03, 0x05, 0x05, 0x00}, // 0xCA - '�' + {0x06, 0x05, 0x05, 0x05, 0x05, 0x00}, // 0xCB - '�' + {0x05, 0x07, 0x05, 0x05, 0x05, 0x00}, // 0xCC - '�' + {0x05, 0x05, 0x07, 0x05, 0x05, 0x00}, // 0xCD - '�' + {0x02, 0x05, 0x05, 0x05, 0x02, 0x00}, // 0xCE - '�' + {0x07, 0x05, 0x05, 0x05, 0x05, 0x00}, // 0xCF - '�' + {0x03, 0x05, 0x03, 0x01, 0x01, 0x00}, // 0xD0 - '�' + {0x06, 0x01, 0x01, 0x01, 0x06, 0x00}, // 0xD1 - '�' + {0x07, 0x02, 0x02, 0x02, 0x02, 0x00}, // 0xD2 - '�' + {0x05, 0x05, 0x07, 0x04, 0x03, 0x00}, // 0xD3 - '�' + {0x02, 0x07, 0x05, 0x07, 0x02, 0x00}, // 0xD4 - '�' + {0x05, 0x05, 0x02, 0x05, 0x05, 0x00}, // 0xD5 - '�' + {0x05, 0x05, 0x05, 0x05, 0x0F, 0x08}, // 0xD6 - '�' + {0x05, 0x05, 0x07, 0x04, 0x04, 0x00}, // 0xD7 - '�' + {0x05, 0x05, 0x07, 0x07, 0x07, 0x00}, // 0xD8 - '�' + {0x05, 0x05, 0x07, 0x07, 0x0F, 0x08}, // 0xD9 - '�' + {0x03, 0x02, 0x06, 0x06, 0x06, 0x00}, // 0xDA - '�' + {0x05, 0x05, 0x07, 0x05, 0x07, 0x00}, // 0xDB - '�' + {0x01, 0x01, 0x03, 0x05, 0x03, 0x00}, // 0xDC - '�' + {0x03, 0x04, 0x06, 0x04, 0x03, 0x00}, // 0xDD - '�' + {0x05, 0x0F, 0x0B, 0x0F, 0x05, 0x00}, // 0xDE - '�' + {0x06, 0x05, 0x06, 0x05, 0x05, 0x00}, // 0xDF - '�' + {0x00, 0x00, 0x06, 0x05, 0x06, 0x00}, // 0xE0 - '�' + {0x00, 0x00, 0x07, 0x03, 0x07, 0x00}, // 0xE1 - '�' + {0x00, 0x00, 0x03, 0x07, 0x07, 0x00}, // 0xE2 - '�' + {0x00, 0x00, 0x07, 0x01, 0x01, 0x00}, // 0xE3 - '�' + {0x00, 0x00, 0x02, 0x07, 0x05, 0x00}, // 0xE4 - '�' + {0x00, 0x00, 0x07, 0x03, 0x06, 0x00}, // 0xE5 - '�' + {0x00, 0x00, 0x07, 0x02, 0x07, 0x00}, // 0xE6 - '�' + {0x00, 0x00, 0x07, 0x06, 0x07, 0x00}, // 0xE7 - '�' + {0x00, 0x00, 0x05, 0x07, 0x05, 0x00}, // 0xE8 - '�' + {0x02, 0x00, 0x05, 0x07, 0x05, 0x00}, // 0xE9 - '�' + {0x00, 0x00, 0x05, 0x03, 0x05, 0x00}, // 0xEA - '�' + {0x00, 0x00, 0x06, 0x05, 0x05, 0x00}, // 0xEB - '�' + {0x00, 0x00, 0x05, 0x07, 0x07, 0x00}, // 0xEC - '�' + {0x00, 0x00, 0x05, 0x07, 0x05, 0x00}, // 0xED - '�' + {0x00, 0x00, 0x02, 0x05, 0x02, 0x00}, // 0xEE - '�' + {0x00, 0x00, 0x07, 0x05, 0x05, 0x00}, // 0xEF - '�' + {0x00, 0x00, 0x03, 0x05, 0x03, 0x01}, // 0xF0 - '�' + {0x00, 0x00, 0x06, 0x01, 0x06, 0x00}, // 0xF1 - '�' + {0x00, 0x00, 0x07, 0x02, 0x02, 0x00}, // 0xF2 - '�' + {0x00, 0x00, 0x05, 0x05, 0x02, 0x01}, // 0xF3 - '�' + {0x00, 0x00, 0x07, 0x05, 0x07, 0x02}, // 0xF4 - '�' + {0x00, 0x00, 0x05, 0x02, 0x05, 0x00}, // 0xF5 - '�' + {0x00, 0x00, 0x05, 0x05, 0x0F, 0x08}, // 0xF6 - '�' + {0x00, 0x00, 0x05, 0x07, 0x04, 0x00}, // 0xF7 - '�' + {0x00, 0x00, 0x05, 0x07, 0x07, 0x00}, // 0xF8 - '�' + {0x00, 0x00, 0x05, 0x07, 0x0F, 0x08}, // 0xF9 - '�' + {0x00, 0x00, 0x03, 0x06, 0x06, 0x00}, // 0xFA - '�' + {0x00, 0x00, 0x05, 0x07, 0x07, 0x00}, // 0xFB - '�' + {0x00, 0x00, 0x01, 0x07, 0x07, 0x00}, // 0xFC - '�' + {0x00, 0x00, 0x03, 0x06, 0x03, 0x00}, // 0xFD - '�' + {0x00, 0x00, 0x05, 0x0F, 0x05, 0x00}, // 0xFE - '�' + {0x00, 0x00, 0x07, 0x06, 0x05, 0x00} // 0xFF - '�' +}; + +const unsigned char font6x8[256][8] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x00 - ' ' + {0x1C, 0x22, 0x36, 0x22, 0x2A, 0x22, 0x1C, 0x00}, // 0x01 - '' + {0x1C, 0x3E, 0x2A, 0x3E, 0x22, 0x3E, 0x1C, 0x00}, // 0x02 - '' + {0x00, 0x14, 0x3E, 0x3E, 0x3E, 0x1C, 0x08, 0x00}, // 0x03 - '' + {0x00, 0x08, 0x1C, 0x3E, 0x3E, 0x1C, 0x08, 0x00}, // 0x04 - '' + {0x08, 0x1C, 0x1C, 0x08, 0x3E, 0x3E, 0x08, 0x00}, // 0x05 - '' + {0x00, 0x08, 0x1C, 0x3E, 0x3E, 0x08, 0x1C, 0x00}, // 0x06 - '' + {0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x00}, // 0x07 - '' + {0x3F, 0x3F, 0x3F, 0x33, 0x33, 0x3F, 0x3F, 0x3F}, // 0x08 - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x09 - ' ' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0A - ' ' + {0x00, 0x38, 0x30, 0x2C, 0x12, 0x12, 0x0C, 0x00}, // 0x0B - ' ' + {0x1C, 0x22, 0x22, 0x1C, 0x08, 0x1C, 0x08, 0x00}, // 0x0C - ' ' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0D - ' ' + {0x30, 0x2C, 0x34, 0x2C, 0x34, 0x36, 0x06, 0x00}, // 0x0E - '' + {0x00, 0x2A, 0x1C, 0x36, 0x1C, 0x2A, 0x00, 0x00}, // 0x0F - '' + {0x04, 0x0C, 0x1C, 0x3C, 0x1C, 0x0C, 0x04, 0x00}, // 0x10 - '' + {0x10, 0x18, 0x1C, 0x1E, 0x1C, 0x18, 0x10, 0x00}, // 0x11 - '' + {0x08, 0x1C, 0x3E, 0x08, 0x3E, 0x1C, 0x08, 0x00}, // 0x12 - '' + {0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x14, 0x00}, // 0x13 - '' + {0x3C, 0x2A, 0x2A, 0x2C, 0x28, 0x28, 0x28, 0x00}, // 0x14 - '' + {0x1C, 0x22, 0x0C, 0x14, 0x18, 0x22, 0x1C, 0x00}, // 0x15 - '' + {0x00, 0x00, 0x1E, 0x1E, 0x1E, 0x1E, 0x00, 0x00}, // 0x16 - '' + {0x08, 0x1C, 0x3E, 0x08, 0x3E, 0x1C, 0x08, 0x1C}, // 0x17 - '' + {0x08, 0x1C, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x00}, // 0x18 - '' + {0x08, 0x08, 0x08, 0x08, 0x3E, 0x1C, 0x08, 0x00}, // 0x19 - '' + {0x00, 0x08, 0x18, 0x3E, 0x18, 0x08, 0x00, 0x00}, // 0x1A - ' ' + {0x00, 0x08, 0x0C, 0x3E, 0x0C, 0x08, 0x00, 0x00}, // 0x1B - '' + {0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x3E, 0x00}, // 0x1C - '' + {0x00, 0x14, 0x14, 0x3E, 0x14, 0x14, 0x00, 0x00}, // 0x1D - '' + {0x08, 0x08, 0x1C, 0x1C, 0x3E, 0x3E, 0x00, 0x00}, // 0x1E - '' + {0x3E, 0x3E, 0x1C, 0x1C, 0x08, 0x08, 0x00, 0x00}, // 0x1F - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x20 - ' ' + {0x08, 0x1C, 0x1C, 0x08, 0x08, 0x00, 0x08, 0x00}, // 0x21 - '!' + {0x36, 0x36, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x22 - '"' + {0x00, 0x14, 0x3E, 0x14, 0x14, 0x3E, 0x14, 0x00}, // 0x23 - '#' + {0x04, 0x1C, 0x02, 0x0C, 0x10, 0x0E, 0x08, 0x00}, // 0x24 - '$' + {0x26, 0x26, 0x10, 0x08, 0x04, 0x32, 0x32, 0x00}, // 0x25 - '%' + {0x04, 0x0A, 0x0A, 0x04, 0x2A, 0x12, 0x2C, 0x00}, // 0x26 - '&' + {0x0C, 0x0C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x27 - ''' + {0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x00}, // 0x28 - '(' + {0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x00}, // 0x29 - ')' + {0x00, 0x14, 0x1C, 0x3E, 0x1C, 0x14, 0x00, 0x00}, // 0x2A - '*' + {0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00}, // 0x2B - '+' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x04}, // 0x2C - ',' + {0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00}, // 0x2D - '-' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // 0x2E - '.' + {0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00}, // 0x2F - '/' + {0x1C, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x1C, 0x00}, // 0x30 - '0' + {0x08, 0x0C, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00}, // 0x31 - '1' + {0x1C, 0x22, 0x20, 0x18, 0x04, 0x02, 0x3E, 0x00}, // 0x32 - '2' + {0x1C, 0x22, 0x20, 0x1C, 0x20, 0x22, 0x1C, 0x00}, // 0x33 - '3' + {0x10, 0x18, 0x14, 0x12, 0x3E, 0x10, 0x10, 0x00}, // 0x34 - '4' + {0x3E, 0x02, 0x02, 0x1E, 0x20, 0x22, 0x1C, 0x00}, // 0x35 - '5' + {0x18, 0x04, 0x02, 0x1E, 0x22, 0x22, 0x1C, 0x00}, // 0x36 - '6' + {0x3E, 0x20, 0x10, 0x08, 0x04, 0x04, 0x04, 0x00}, // 0x37 - '7' + {0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00}, // 0x38 - '8' + {0x1C, 0x22, 0x22, 0x3C, 0x20, 0x10, 0x0C, 0x00}, // 0x39 - '9' + {0x00, 0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00}, // 0x3A - ':' + {0x00, 0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x04}, // 0x3B - ';' + {0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00}, // 0x3C - '<' + {0x00, 0x00, 0x3E, 0x00, 0x00, 0x3E, 0x00, 0x00}, // 0x3D - '=' + {0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00}, // 0x3E - '>' + {0x1C, 0x22, 0x20, 0x18, 0x08, 0x00, 0x08, 0x00}, // 0x3F - '?' + {0x1C, 0x22, 0x3A, 0x2A, 0x3A, 0x02, 0x1C, 0x00}, // 0x40 - '@' + {0x1C, 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00}, // 0x41 - 'A' + {0x1E, 0x22, 0x22, 0x1E, 0x22, 0x22, 0x1E, 0x00}, // 0x42 - 'B' + {0x1C, 0x22, 0x02, 0x02, 0x02, 0x22, 0x1C, 0x00}, // 0x43 - 'C' + {0x1E, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1E, 0x00}, // 0x44 - 'D' + {0x3E, 0x02, 0x02, 0x1E, 0x02, 0x02, 0x3E, 0x00}, // 0x45 - 'E' + {0x3E, 0x02, 0x02, 0x1E, 0x02, 0x02, 0x02, 0x00}, // 0x46 - 'F' + {0x1C, 0x22, 0x02, 0x3A, 0x22, 0x22, 0x3C, 0x00}, // 0x47 - 'G' + {0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00}, // 0x48 - 'H' + {0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00}, // 0x49 - 'I' + {0x20, 0x20, 0x20, 0x20, 0x22, 0x22, 0x1C, 0x00}, // 0x4A - 'J' + {0x22, 0x12, 0x0A, 0x06, 0x0A, 0x12, 0x22, 0x00}, // 0x4B - 'K' + {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x3E, 0x00}, // 0x4C - 'L' + {0x22, 0x36, 0x2A, 0x22, 0x22, 0x22, 0x22, 0x00}, // 0x4D - 'M' + {0x22, 0x26, 0x2A, 0x32, 0x22, 0x22, 0x22, 0x00}, // 0x4E - 'N' + {0x1C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00}, // 0x4F - 'O' + {0x1E, 0x22, 0x22, 0x1E, 0x02, 0x02, 0x02, 0x00}, // 0x50 - 'P' + {0x1C, 0x22, 0x22, 0x22, 0x2A, 0x12, 0x2C, 0x00}, // 0x51 - 'Q' + {0x1E, 0x22, 0x22, 0x1E, 0x12, 0x22, 0x22, 0x00}, // 0x52 - 'R' + {0x1C, 0x22, 0x02, 0x1C, 0x20, 0x22, 0x1C, 0x00}, // 0x53 - 'S' + {0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00}, // 0x54 - 'T' + {0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00}, // 0x55 - 'U' + {0x22, 0x22, 0x22, 0x22, 0x22, 0x14, 0x08, 0x00}, // 0x56 - 'V' + {0x22, 0x22, 0x2A, 0x2A, 0x2A, 0x2A, 0x14, 0x00}, // 0x57 - 'W' + {0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00}, // 0x58 - 'X' + {0x22, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x00}, // 0x59 - 'Y' + {0x1E, 0x10, 0x08, 0x04, 0x02, 0x02, 0x1E, 0x00}, // 0x5A - 'Z' + {0x1C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x1C, 0x00}, // 0x5B - '[' + {0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00}, // 0x5C - '\' + {0x1C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1C, 0x00}, // 0x5D - ']' + {0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x5E - '^' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00}, // 0x5F - '_' + {0x0C, 0x0C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x60 - '`' + {0x00, 0x00, 0x1C, 0x20, 0x3C, 0x22, 0x3C, 0x00}, // 0x61 - 'a' + {0x02, 0x02, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x00}, // 0x62 - 'b' + {0x00, 0x00, 0x1C, 0x22, 0x02, 0x22, 0x1C, 0x00}, // 0x63 - 'c' + {0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x00}, // 0x64 - 'd' + {0x00, 0x00, 0x1C, 0x22, 0x1E, 0x02, 0x1C, 0x00}, // 0x65 - 'e' + {0x18, 0x04, 0x04, 0x1E, 0x04, 0x04, 0x04, 0x00}, // 0x66 - 'f' + {0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x1C}, // 0x67 - 'g' + {0x02, 0x02, 0x0E, 0x12, 0x12, 0x12, 0x12, 0x00}, // 0x68 - 'h' + {0x08, 0x00, 0x08, 0x08, 0x08, 0x08, 0x18, 0x00}, // 0x69 - 'i' + {0x10, 0x00, 0x18, 0x10, 0x10, 0x10, 0x12, 0x0C}, // 0x6A - 'j' + {0x02, 0x02, 0x12, 0x0A, 0x06, 0x0A, 0x12, 0x00}, // 0x6B - 'k' + {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x18, 0x00}, // 0x6C - 'l' + {0x00, 0x00, 0x16, 0x2A, 0x2A, 0x22, 0x22, 0x00}, // 0x6D - 'm' + {0x00, 0x00, 0x0E, 0x12, 0x12, 0x12, 0x12, 0x00}, // 0x6E - 'n' + {0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00}, // 0x6F - 'o' + {0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02}, // 0x70 - 'p' + {0x00, 0x00, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x20}, // 0x71 - 'q' + {0x00, 0x00, 0x1A, 0x24, 0x04, 0x04, 0x0E, 0x00}, // 0x72 - 'r' + {0x00, 0x00, 0x1C, 0x02, 0x1C, 0x20, 0x1C, 0x00}, // 0x73 - 's' + {0x00, 0x04, 0x1E, 0x04, 0x04, 0x14, 0x08, 0x00}, // 0x74 - 't' + {0x00, 0x00, 0x12, 0x12, 0x12, 0x1A, 0x14, 0x00}, // 0x75 - 'u' + {0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x08, 0x00}, // 0x76 - 'v' + {0x00, 0x00, 0x22, 0x22, 0x2A, 0x3E, 0x14, 0x00}, // 0x77 - 'w' + {0x00, 0x00, 0x12, 0x12, 0x0C, 0x12, 0x12, 0x00}, // 0x78 - 'x' + {0x00, 0x00, 0x12, 0x12, 0x12, 0x1C, 0x08, 0x06}, // 0x79 - 'y' + {0x00, 0x00, 0x1E, 0x10, 0x0C, 0x02, 0x1E, 0x00}, // 0x7A - 'z' + {0x18, 0x04, 0x04, 0x06, 0x04, 0x04, 0x18, 0x00}, // 0x7B - '{' + {0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00}, // 0x7C - '|' + {0x0C, 0x10, 0x10, 0x30, 0x10, 0x10, 0x0C, 0x00}, // 0x7D - '}' + {0x14, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x7E - '~' + {0x08, 0x1C, 0x36, 0x22, 0x22, 0x3E, 0x00, 0x00}, // 0x7F - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x80 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x81 - '�' + {0x0C, 0x0C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x82 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x83 - '�' + {0x36, 0x36, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x84 - '�' + {0x00, 0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00}, // 0x85 - '�' + {0x08, 0x08, 0x08, 0x3F, 0x08, 0x08, 0x08, 0x08}, // 0x86 - '�' + {0x08, 0x3F, 0x08, 0x3F, 0x08, 0x08, 0x08, 0x08}, // 0x87 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x88 - '�' + {0x26, 0x26, 0x10, 0x08, 0x04, 0x32, 0x32, 0x00}, // 0x89 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8A - '�' + {0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00}, // 0x8B - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8C - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8D - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8E - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8F - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x90 - '�' + {0x0C, 0x0C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x91 - '�' + {0x0C, 0x0C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x92 - '�' + {0x36, 0x36, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x93 - '�' + {0x36, 0x36, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x94 - '�' + {0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x00}, // 0x95 - '�' + {0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00}, // 0x96 - '�' + {0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00}, // 0x97 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x98 - '�' + {0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00}, // 0x99 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9A - '�' + {0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00}, // 0x9B - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9C - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9D - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9E - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9F - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA0 - '�' + {0x2A, 0x2A, 0x22, 0x3C, 0x20, 0x22, 0x1C, 0x00}, // 0xA1 - '�' + {0x0C, 0x00, 0x12, 0x12, 0x12, 0x1C, 0x08, 0x06}, // 0xA2 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA3 - '�' + {0x00, 0x33, 0x1E, 0x33, 0x1E, 0x33, 0x00, 0x00}, // 0xA4 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA5 - '�' + {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}, // 0xA6 - '�' + {0x1C, 0x22, 0x0C, 0x14, 0x18, 0x22, 0x1C, 0x00}, // 0xA7 - '�' + {0x14, 0x3E, 0x02, 0x1E, 0x02, 0x02, 0x3E, 0x00}, // 0xA8 - '�' + {0x00, 0x00, 0x1C, 0x22, 0x02, 0x22, 0x1C, 0x00}, // 0xA9 - '�' + {0x1C, 0x22, 0x02, 0x0E, 0x02, 0x22, 0x1C, 0x00}, // 0xAA - '�' + {0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00}, // 0xAB - '�' + {0x00, 0x00, 0x00, 0x0F, 0x08, 0x08, 0x08, 0x08}, // 0xAC - '�' + {0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00}, // 0xAD - '�' + {0x1E, 0x22, 0x22, 0x1E, 0x12, 0x22, 0x22, 0x00}, // 0xAE - '�' + {0x22, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00}, // 0xAF - '�' + {0x0C, 0x12, 0x12, 0x0C, 0x00, 0x00, 0x00, 0x00}, // 0xB0 - '�' + {0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00}, // 0xB1 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB2 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB3 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB4 - '�' + {0x00, 0x00, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x00}, // 0xB5 - '�' + {0x3C, 0x2A, 0x2A, 0x2C, 0x28, 0x28, 0x28, 0x00}, // 0xB6 - '�' + {0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, // 0xB7 - '�' + {0x14, 0x00, 0x1C, 0x22, 0x1E, 0x02, 0x1C, 0x00}, // 0xB8 - '�' + {0x39, 0x3B, 0x0B, 0x0D, 0x3D, 0x09, 0x09, 0x00}, // 0xB9 - '�' + {0x00, 0x00, 0x1C, 0x22, 0x0E, 0x22, 0x1C, 0x00}, // 0xBA - '�' + {0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00}, // 0xBB - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBC - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBD - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBE - '�' + {0x14, 0x00, 0x08, 0x08, 0x08, 0x08, 0x18, 0x00}, // 0xBF - '�' + {0x1C, 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00}, // 0xC0 - '�' + {0x3E, 0x02, 0x02, 0x1E, 0x22, 0x22, 0x1E, 0x00}, // 0xC1 - '�' + {0x1E, 0x22, 0x22, 0x1E, 0x22, 0x22, 0x1E, 0x00}, // 0xC2 - '�' + {0x3E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00}, // 0xC3 - '�' + {0x1C, 0x12, 0x12, 0x12, 0x12, 0x3F, 0x21, 0x00}, // 0xC4 - '�' + {0x3E, 0x02, 0x02, 0x1E, 0x02, 0x02, 0x3E, 0x00}, // 0xC5 - '�' + {0x2A, 0x2A, 0x2A, 0x1C, 0x2A, 0x2A, 0x2A, 0x00}, // 0xC6 - '�' + {0x0E, 0x11, 0x10, 0x0E, 0x10, 0x11, 0x0E, 0x00}, // 0xC7 - '�' + {0x22, 0x22, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x00}, // 0xC8 - '�' + {0x2A, 0x2A, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x00}, // 0xC9 - '�' + {0x22, 0x12, 0x0A, 0x06, 0x0A, 0x12, 0x22, 0x00}, // 0xCA - '�' + {0x38, 0x24, 0x24, 0x24, 0x24, 0x24, 0x26, 0x00}, // 0xCB - '�' + {0x22, 0x36, 0x2A, 0x22, 0x22, 0x22, 0x22, 0x00}, // 0xCC - '�' + {0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00}, // 0xCD - '�' + {0x1C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00}, // 0xCE - '�' + {0x3E, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00}, // 0xCF - '�' + {0x1E, 0x22, 0x22, 0x1E, 0x02, 0x02, 0x02, 0x00}, // 0xD0 - '�' + {0x1C, 0x22, 0x02, 0x02, 0x02, 0x22, 0x1C, 0x00}, // 0xD1 - '�' + {0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00}, // 0xD2 - '�' + {0x22, 0x22, 0x22, 0x3C, 0x20, 0x22, 0x1C, 0x00}, // 0xD3 - '�' + {0x1C, 0x2A, 0x2A, 0x2A, 0x1C, 0x08, 0x08, 0x00}, // 0xD4 - '�' + {0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00}, // 0xD5 - '�' + {0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3E, 0x20}, // 0xD6 - '�' + {0x22, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x20, 0x00}, // 0xD7 - '�' + {0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x3E, 0x00}, // 0xD8 - '�' + {0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x3E, 0x20}, // 0xD9 - '�' + {0x07, 0x05, 0x04, 0x1C, 0x24, 0x24, 0x1C, 0x00}, // 0xDA - '�' + {0x22, 0x22, 0x22, 0x2E, 0x32, 0x32, 0x2E, 0x00}, // 0xDB - '�' + {0x02, 0x02, 0x02, 0x1E, 0x22, 0x22, 0x1E, 0x00}, // 0xDC - '�' + {0x1C, 0x22, 0x20, 0x38, 0x20, 0x22, 0x1C, 0x00}, // 0xDD - '�' + {0x12, 0x2A, 0x2A, 0x2E, 0x2A, 0x2A, 0x12, 0x00}, // 0xDE - '�' + {0x3C, 0x22, 0x22, 0x3C, 0x24, 0x22, 0x22, 0x00}, // 0xDF - '�' + {0x00, 0x00, 0x1C, 0x20, 0x3C, 0x22, 0x3C, 0x00}, // 0xE0 - '�' + {0x20, 0x1C, 0x02, 0x1E, 0x22, 0x22, 0x1C, 0x00}, // 0xE1 - '�' + {0x00, 0x00, 0x1E, 0x22, 0x1E, 0x22, 0x1E, 0x00}, // 0xE2 - '�' + {0x00, 0x00, 0x1E, 0x12, 0x02, 0x02, 0x02, 0x00}, // 0xE3 - '�' + {0x00, 0x00, 0x1C, 0x12, 0x12, 0x3F, 0x21, 0x00}, // 0xE4 - '�' + {0x00, 0x00, 0x1C, 0x22, 0x1E, 0x02, 0x1C, 0x00}, // 0xE5 - '�' + {0x00, 0x00, 0x2A, 0x2A, 0x1C, 0x2A, 0x2A, 0x00}, // 0xE6 - '�' + {0x00, 0x00, 0x1C, 0x22, 0x18, 0x22, 0x1C, 0x00}, // 0xE7 - '�' + {0x00, 0x00, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x00}, // 0xE8 - '�' + {0x00, 0x18, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x00}, // 0xE9 - '�' + {0x00, 0x00, 0x12, 0x0A, 0x06, 0x0A, 0x12, 0x00}, // 0xEA - '�' + {0x00, 0x00, 0x1C, 0x12, 0x12, 0x12, 0x11, 0x00}, // 0xEB - '�' + {0x00, 0x00, 0x22, 0x36, 0x2A, 0x22, 0x22, 0x00}, // 0xEC - '�' + {0x00, 0x00, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00}, // 0xED - '�' + {0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00}, // 0xEE - '�' + {0x00, 0x00, 0x3E, 0x22, 0x22, 0x22, 0x22, 0x00}, // 0xEF - '�' + {0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02}, // 0xF0 - '�' + {0x00, 0x00, 0x1C, 0x22, 0x02, 0x22, 0x1C, 0x00}, // 0xF1 - '�' + {0x00, 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x00}, // 0xF2 - '�' + {0x00, 0x00, 0x12, 0x12, 0x12, 0x1C, 0x08, 0x06}, // 0xF3 - '�' + {0x00, 0x00, 0x1C, 0x2A, 0x2A, 0x1C, 0x08, 0x00}, // 0xF4 - '�' + {0x00, 0x00, 0x12, 0x12, 0x0C, 0x12, 0x12, 0x00}, // 0xF5 - '�' + {0x00, 0x00, 0x12, 0x12, 0x12, 0x12, 0x3E, 0x20}, // 0xF6 - '�' + {0x00, 0x00, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x00}, // 0xF7 - '�' + {0x00, 0x00, 0x2A, 0x2A, 0x2A, 0x2A, 0x3E, 0x00}, // 0xF8 - '�' + {0x00, 0x00, 0x2A, 0x2A, 0x2A, 0x2A, 0x3E, 0x20}, // 0xF9 - '�' + {0x00, 0x00, 0x07, 0x05, 0x1C, 0x24, 0x1C, 0x00}, // 0xFA - '�' + {0x00, 0x00, 0x22, 0x22, 0x2E, 0x32, 0x2E, 0x00}, // 0xFB - '�' + {0x00, 0x00, 0x02, 0x02, 0x1E, 0x22, 0x1E, 0x00}, // 0xFC - '�' + {0x00, 0x00, 0x1C, 0x22, 0x38, 0x22, 0x1C, 0x00}, // 0xFD - '�' + {0x00, 0x00, 0x12, 0x2A, 0x2E, 0x2A, 0x12, 0x00}, // 0xFE - '�' + {0x00, 0x00, 0x3C, 0x22, 0x3C, 0x24, 0x22, 0x00} // 0xFF - '�' +}; + +const unsigned char font8x8[256][8] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x00 - ' ' + {0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E}, // 0x01 - '' + {0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E}, // 0x02 - '' + {0x36, 0x7F, 0x7F, 0x7F, 0x3E, 0x1C, 0x08, 0x00}, // 0x03 - '' + {0x08, 0x1C, 0x3E, 0x7F, 0x3E, 0x1C, 0x08, 0x00}, // 0x04 - '' + {0x1C, 0x3E, 0x1C, 0x7F, 0x7F, 0x6B, 0x08, 0x1C}, // 0x05 - '' + {0x08, 0x08, 0x1C, 0x3E, 0x7F, 0x3E, 0x08, 0x1C}, // 0x06 - '' + {0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00}, // 0x07 - '' + {0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF}, // 0x08 - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x09 - ' ' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0A - ' ' + {0xF0, 0xE0, 0xF0, 0xBE, 0x33, 0x33, 0x33, 0x1E}, // 0x0B - ' ' + {0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18}, // 0x0C - ' ' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0D - ' ' + {0xFE, 0xC6, 0xFE, 0xC6, 0xC6, 0xE6, 0x67, 0x03}, // 0x0E - '' + {0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99}, // 0x0F - '' + {0x01, 0x07, 0x1F, 0x7F, 0x1F, 0x07, 0x01, 0x00}, // 0x10 - '' + {0x40, 0x70, 0x7C, 0x7F, 0x7C, 0x70, 0x40, 0x00}, // 0x11 - '' + {0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18}, // 0x12 - '' + {0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00}, // 0x13 - '' + {0xFE, 0xDB, 0xDB, 0xDE, 0xD8, 0xD8, 0xD8, 0x00}, // 0x14 - '' + {0x7E, 0xC3, 0x1E, 0x33, 0x33, 0x1E, 0x31, 0x1F}, // 0x15 - '' + {0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00}, // 0x16 - '' + {0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF}, // 0x17 - '' + {0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00}, // 0x18 - '' + {0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00}, // 0x19 - '' + {0x00, 0x18, 0x30, 0x7F, 0x30, 0x18, 0x00, 0x00}, // 0x1A - ' ' + {0x00, 0x0C, 0x06, 0x7F, 0x06, 0x0C, 0x00, 0x00}, // 0x1B - '' + {0x00, 0x00, 0x03, 0x03, 0x03, 0x7F, 0x00, 0x00}, // 0x1C - '' + {0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00}, // 0x1D - '' + {0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00}, // 0x1E - '' + {0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00}, // 0x1F - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x20 - ' ' + {0x0C, 0x1E, 0x1E, 0x0C, 0x0C, 0x00, 0x0C, 0x00}, // 0x21 - '!' + {0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x22 - '"' + {0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // 0x23 - '#' + {0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // 0x24 - '$' + {0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // 0x25 - '%' + {0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // 0x26 - '&' + {0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x27 - ''' + {0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // 0x28 - '(' + {0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // 0x29 - ')' + {0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // 0x2A - '*' + {0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // 0x2B - '+' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x0C, 0x06}, // 0x2C - ',' + {0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // 0x2D - '-' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // 0x2E - '.' + {0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // 0x2F - '/' + {0x1E, 0x33, 0x3B, 0x3F, 0x37, 0x33, 0x1E, 0x00}, // 0x30 - '0' + {0x0C, 0x0F, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // 0x31 - '1' + {0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // 0x32 - '2' + {0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // 0x33 - '3' + {0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x30, 0x00}, // 0x34 - '4' + {0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // 0x35 - '5' + {0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // 0x36 - '6' + {0x3F, 0x33, 0x30, 0x18, 0x0C, 0x06, 0x06, 0x00}, // 0x37 - '7' + {0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // 0x38 - '8' + {0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // 0x39 - '9' + {0x00, 0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00}, // 0x3A - ':' + {0x00, 0x00, 0x0C, 0x0C, 0x00, 0x0E, 0x0C, 0x06}, // 0x3B - ';' + {0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // 0x3C - '<' + {0x00, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x00, 0x00}, // 0x3D - '=' + {0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // 0x3E - '>' + {0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // 0x3F - '?' + {0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // 0x40 - '@' + {0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // 0x41 - 'A' + {0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // 0x42 - 'B' + {0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // 0x43 - 'C' + {0x3F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x3F, 0x00}, // 0x44 - 'D' + {0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // 0x45 - 'E' + {0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // 0x46 - 'F' + {0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // 0x47 - 'G' + {0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // 0x48 - 'H' + {0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // 0x49 - 'I' + {0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // 0x4A - 'J' + {0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // 0x4B - 'K' + {0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // 0x4C - 'L' + {0x63, 0x77, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x00}, // 0x4D - 'M' + {0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // 0x4E - 'N' + {0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // 0x4F - 'O' + {0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // 0x50 - 'P' + {0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // 0x51 - 'Q' + {0x3F, 0x66, 0x66, 0x3E, 0x1E, 0x36, 0x67, 0x00}, // 0x52 - 'R' + {0x1E, 0x33, 0x07, 0x1C, 0x38, 0x33, 0x1E, 0x00}, // 0x53 - 'S' + {0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // 0x54 - 'T' + {0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // 0x55 - 'U' + {0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // 0x56 - 'V' + {0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // 0x57 - 'W' + {0x63, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x63, 0x00}, // 0x58 - 'X' + {0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // 0x59 - 'Y' + {0x7F, 0x33, 0x19, 0x0C, 0x46, 0x63, 0x7F, 0x00}, // 0x5A - 'Z' + {0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // 0x5B - '[' + {0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // 0x5C - '\' + {0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // 0x5D - ']' + {0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // 0x5E - '^' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00}, // 0x5F - '_' + {0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x60 - '`' + {0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // 0x61 - 'a' + {0x07, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3D, 0x00}, // 0x62 - 'b' + {0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // 0x63 - 'c' + {0x38, 0x30, 0x30, 0x3E, 0x33, 0x33, 0x6E, 0x00}, // 0x64 - 'd' + {0x00, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00}, // 0x65 - 'e' + {0x1C, 0x36, 0x06, 0x0F, 0x06, 0x06, 0x0F, 0x00}, // 0x66 - 'f' + {0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // 0x67 - 'g' + {0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // 0x68 - 'h' + {0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // 0x69 - 'i' + {0x18, 0x00, 0x1E, 0x18, 0x18, 0x18, 0x1B, 0x0E}, // 0x6A - 'j' + {0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // 0x6B - 'k' + {0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // 0x6C - 'l' + {0x00, 0x00, 0x37, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // 0x6D - 'm' + {0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // 0x6E - 'n' + {0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // 0x6F - 'o' + {0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // 0x70 - 'p' + {0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // 0x71 - 'q' + {0x00, 0x00, 0x1B, 0x36, 0x36, 0x06, 0x0F, 0x00}, // 0x72 - 'r' + {0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // 0x73 - 's' + {0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // 0x74 - 't' + {0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // 0x75 - 'u' + {0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // 0x76 - 'v' + {0x00, 0x00, 0x63, 0x63, 0x6B, 0x7F, 0x36, 0x00}, // 0x77 - 'w' + {0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // 0x78 - 'x' + {0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // 0x79 - 'y' + {0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // 0x7A - 'z' + {0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF}, // 0x7B - '{' + {0xFF, 0x81, 0xBD, 0xBD, 0xBD, 0xBD, 0x81, 0xFF}, // 0x7C - '|' + {0xFF, 0x20, 0x70, 0x7C, 0xFE, 0xFE, 0x7C, 0x00}, // 0x7D - '}' + {0x07, 0x00, 0x00, 0x40, 0xFF, 0x40, 0x00, 0x00}, // 0x7E - '~' + {0x00, 0xE1, 0xFD, 0xFF, 0xFD, 0x31, 0x10, 0x00}, // 0x7F - '' + {0x00, 0xC1, 0xE3, 0xFF, 0x3F, 0x00, 0x00, 0x00}, // 0x80 - '�' + {0xF0, 0x08, 0x04, 0x02, 0xE1, 0xC1, 0xE1, 0xC1}, // 0x81 - '�' + {0x0F, 0x10, 0x21, 0x71, 0x9F, 0x8F, 0x8F, 0x87}, // 0x82 - '�' + {0xC1, 0xE1, 0xFD, 0xF1, 0xDA, 0x0C, 0x08, 0xF0}, // 0x83 - '�' + {0x87, 0x8F, 0x8F, 0x8F, 0x4F, 0x20, 0x10, 0x0F}, // 0x84 - '�' + {0x00, 0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00}, // 0x85 - '�' + {0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18}, // 0x86 - '�' + {0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18}, // 0x87 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x88 - '�' + {0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // 0x89 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8A - '�' + {0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // 0x8B - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8C - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8D - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8E - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8F - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x90 - '�' + {0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x91 - '�' + {0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x92 - '�' + {0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x93 - '�' + {0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x94 - '�' + {0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00}, // 0x95 - '�' + {0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // 0x96 - '�' + {0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // 0x97 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x98 - '�' + {0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // 0x99 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9A - '�' + {0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // 0x9B - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9C - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9D - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9E - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9F - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA0 - '�' + {0x08, 0x63, 0x63, 0x7E, 0x60, 0x63, 0x3E, 0x00}, // 0xA1 - '�' + {0x6B, 0x6B, 0x63, 0x63, 0x63, 0x7E, 0x60, 0x3E}, // 0xA2 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA3 - '�' + {0x00, 0x63, 0x3E, 0x63, 0x63, 0x3E, 0x63, 0x00}, // 0xA4 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA5 - '�' + {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, // 0xA6 - '�' + {0x7E, 0xC3, 0x1E, 0x33, 0x33, 0x1E, 0x31, 0x1F}, // 0xA7 - '�' + {0x36, 0x7F, 0x46, 0x1E, 0x06, 0x46, 0x7F, 0x00}, // 0xA8 - '�' + {0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // 0xA9 - '�' + {0x3C, 0x66, 0x03, 0x1F, 0x03, 0x66, 0x3C, 0x00}, // 0xAA - '�' + {0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // 0xAB - '�' + {0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18}, // 0xAC - '�' + {0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // 0xAD - '�' + {0x3F, 0x66, 0x66, 0x3E, 0x1E, 0x36, 0x67, 0x00}, // 0xAE - '�' + {0x33, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // 0xAF - '�' + {0x1C, 0x36, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00}, // 0xB0 - '�' + {0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // 0xB1 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB2 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB3 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB4 - '�' + {0x00, 0x00, 0x63, 0x63, 0x7E, 0x60, 0x60, 0x00}, // 0xB5 - '�' + {0xFE, 0xDB, 0xDB, 0xDE, 0xD8, 0xD8, 0xD8, 0x00}, // 0xB6 - '�' + {0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00}, // 0xB7 - '�' + {0x33, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00}, // 0xB8 - '�' + {0x71, 0x33, 0x37, 0x7F, 0x3B, 0x33, 0x33, 0x00}, // 0xB9 - '�' + {0x00, 0x00, 0x3E, 0x63, 0x0F, 0x63, 0x3E, 0x00}, // 0xBA - '�' + {0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // 0xBB - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBC - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBD - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBE - '�' + {0x33, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // 0xBF - '�' + {0x7C, 0x66, 0x63, 0x63, 0x7F, 0x63, 0x63, 0x00}, // 0xC0 - '�' + {0x7F, 0x66, 0x06, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // 0xC1 - '�' + {0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // 0xC2 - '�' + {0x7F, 0x66, 0x06, 0x06, 0x06, 0x06, 0x0F, 0x00}, // 0xC3 - '�' + {0x78, 0x6C, 0x66, 0x66, 0x66, 0x66, 0xFF, 0xC3}, // 0xC4 - '�' + {0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // 0xC5 - '�' + {0x6B, 0x6B, 0x3E, 0x1C, 0x3E, 0x6B, 0x6B, 0x00}, // 0xC6 - '�' + {0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // 0xC7 - '�' + {0x63, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x63, 0x00}, // 0xC8 - '�' + {0x6B, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x63, 0x00}, // 0xC9 - '�' + {0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // 0xCA - '�' + {0x78, 0x6E, 0x66, 0x66, 0x66, 0x66, 0x63, 0x00}, // 0xCB - '�' + {0x63, 0x77, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x00}, // 0xCC - '�' + {0x63, 0x63, 0x63, 0x7F, 0x63, 0x63, 0x63, 0x00}, // 0xCD - '�' + {0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // 0xCE - '�' + {0x7F, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00}, // 0xCF - '�' + {0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // 0xD0 - '�' + {0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // 0xD1 - '�' + {0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // 0xD2 - '�' + {0x63, 0x63, 0x63, 0x7E, 0x60, 0x63, 0x3E, 0x00}, // 0xD3 - '�' + {0x3E, 0x6B, 0x6B, 0x6B, 0x3E, 0x08, 0x1C, 0x00}, // 0xD4 - '�' + {0x63, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x63, 0x00}, // 0xD5 - '�' + {0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x7F, 0x60}, // 0xD6 - '�' + {0x63, 0x63, 0x63, 0x7E, 0x60, 0x60, 0x60, 0x00}, // 0xD7 - '�' + {0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x7F, 0x00}, // 0xD8 - '�' + {0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0xFF, 0xC0}, // 0xD9 - '�' + {0x0F, 0x0F, 0x0D, 0x3C, 0x6C, 0x6C, 0x3C, 0x00}, // 0xDA - '�' + {0x63, 0x63, 0x63, 0x6F, 0x7B, 0x7B, 0x6F, 0x00}, // 0xDB - '�' + {0x0F, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x00}, // 0xDC - '�' + {0x1E, 0x33, 0x60, 0x7C, 0x60, 0x33, 0x1E, 0x00}, // 0xDD - '�' + {0x3B, 0x6B, 0x6B, 0x6F, 0x6B, 0x6B, 0x3B, 0x00}, // 0xDE - '�' + {0x7E, 0x63, 0x63, 0x7E, 0x7C, 0x66, 0x63, 0x00}, // 0xDF - '�' + {0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // 0xE0 - '�' + {0x60, 0x3E, 0x03, 0x3E, 0x63, 0x63, 0x3E, 0x00}, // 0xE1 - '�' + {0x00, 0x00, 0x3F, 0x66, 0x3E, 0x66, 0x3F, 0x00}, // 0xE2 - '�' + {0x00, 0x00, 0x7F, 0x66, 0x06, 0x06, 0x0F, 0x00}, // 0xE3 - '�' + {0x00, 0x00, 0x3C, 0x36, 0x36, 0x36, 0x7F, 0x63}, // 0xE4 - '�' + {0x00, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00}, // 0xE5 - '�' + {0x00, 0x00, 0x6B, 0x3E, 0x1C, 0x3E, 0x6B, 0x00}, // 0xE6 - '�' + {0x00, 0x00, 0x3E, 0x63, 0x38, 0x63, 0x3E, 0x00}, // 0xE7 - '�' + {0x00, 0x00, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x00}, // 0xE8 - '�' + {0x08, 0x63, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x00}, // 0xE9 - '�' + {0x00, 0x00, 0x67, 0x36, 0x1E, 0x36, 0x67, 0x00}, // 0xEA - '�' + {0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x67, 0x00}, // 0xEB - '�' + {0x00, 0x00, 0x63, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // 0xEC - '�' + {0x00, 0x00, 0x63, 0x63, 0x7F, 0x63, 0x63, 0x00}, // 0xED - '�' + {0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // 0xEE - '�' + {0x00, 0x00, 0x7F, 0x63, 0x63, 0x63, 0x63, 0x00}, // 0xEF - '�' + {0x00, 0x00, 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // 0xF0 - '�' + {0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // 0xF1 - '�' + {0x00, 0x00, 0x7E, 0x5A, 0x18, 0x18, 0x3C, 0x00}, // 0xF2 - '�' + {0x00, 0x00, 0x63, 0x63, 0x63, 0x7E, 0x60, 0x3E}, // 0xF3 - '�' + {0x00, 0x00, 0x3E, 0x6B, 0x6B, 0x3E, 0x08, 0x1C}, // 0xF4 - '�' + {0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // 0xF5 - '�' + {0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x7F, 0x60}, // 0xF6 - '�' + {0x00, 0x00, 0x63, 0x63, 0x7E, 0x60, 0x60, 0x00}, // 0xF7 - '�' + {0x00, 0x00, 0x6B, 0x6B, 0x6B, 0x6B, 0x7F, 0x00}, // 0xF8 - '�' + {0x00, 0x00, 0x6B, 0x6B, 0x6B, 0x6B, 0xFF, 0xC0}, // 0xF9 - '�' + {0x00, 0x00, 0x0F, 0x0D, 0x3C, 0x6C, 0x3C, 0x00}, // 0xFA - '�' + {0x00, 0x00, 0x63, 0x63, 0x6F, 0x7B, 0x6F, 0x00}, // 0xFB - '�' + {0x00, 0x00, 0x0F, 0x06, 0x3E, 0x66, 0x3E, 0x00}, // 0xFC - '�' + {0x00, 0x00, 0x3E, 0x63, 0x78, 0x63, 0x3E, 0x00}, // 0xFD - '�' + {0x00, 0x00, 0x3B, 0x6B, 0x6F, 0x6B, 0x3B, 0x00}, // 0xFE - '�' + {0x00, 0x00, 0x7E, 0x63, 0x7E, 0x66, 0x63, 0x00} // 0xFF - '�' +}; + +const unsigned char font8x12[256][12] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x00 - ' ' + {0x00, 0x7E, 0xC3, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0xC3, 0x7E, 0x00, 0x00}, // 0x01 - '' + {0x00, 0x7E, 0xFF, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E, 0x00, 0x00}, // 0x02 - '' + {0x00, 0x00, 0x22, 0x77, 0x7F, 0x7F, 0x7F, 0x3E, 0x1C, 0x08, 0x00, 0x00}, // 0x03 - '' + {0x00, 0x08, 0x1C, 0x3E, 0x7F, 0x7F, 0x3E, 0x1C, 0x08, 0x00, 0x00, 0x00}, // 0x04 - '' + {0x00, 0x18, 0x3C, 0x3C, 0xFF, 0xE7, 0xE7, 0x18, 0x18, 0x7E, 0x00, 0x00}, // 0x05 - '' + {0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x7E, 0x00, 0x00}, // 0x06 - '' + {0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x7E, 0x3C, 0x00, 0x00, 0x00, 0x00}, // 0x07 - '' + {0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x81, 0x81, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF}, // 0x08 - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x09 - ' ' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0A - ' ' + {0x00, 0x7C, 0x70, 0x5C, 0x4E, 0x1F, 0x33, 0x33, 0x33, 0x1E, 0x00, 0x00}, // 0x0B - ' ' + {0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00}, // 0x0C - ' ' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0D - ' ' + {0x00, 0xFE, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xE6, 0xE7, 0x67, 0x03, 0x00}, // 0x0E - '' + {0x00, 0x00, 0x18, 0xDB, 0x7E, 0xE7, 0xE7, 0x7E, 0xDB, 0x18, 0x00, 0x00}, // 0x0F - '' + {0x00, 0x01, 0x03, 0x07, 0x1F, 0x7F, 0x1F, 0x07, 0x03, 0x01, 0x00, 0x00}, // 0x10 - '' + {0x00, 0x40, 0x60, 0x70, 0x7C, 0x7F, 0x7C, 0x70, 0x60, 0x40, 0x00, 0x00}, // 0x11 - '' + {0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00}, // 0x12 - '' + {0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00}, // 0x13 - '' + {0x00, 0xFE, 0xDB, 0xDB, 0xDB, 0xDE, 0xD8, 0xD8, 0xD8, 0xD8, 0x00, 0x00}, // 0x14 - '' + {0x00, 0x7E, 0xC6, 0x0C, 0x3C, 0x66, 0x66, 0x3C, 0x30, 0x63, 0x7E, 0x00}, // 0x15 - '' + {0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00}, // 0x16 - '' + {0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00}, // 0x17 - '' + {0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00}, // 0x18 - '' + {0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00}, // 0x19 - '' + {0x00, 0x00, 0x00, 0x18, 0x30, 0x7F, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00}, // 0x1A - ' ' + {0x00, 0x00, 0x00, 0x0C, 0x06, 0x7F, 0x06, 0x0C, 0x00, 0x00, 0x00, 0x00}, // 0x1B - '' + {0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x7F, 0x00, 0x00, 0x00, 0x00}, // 0x1C - '' + {0x00, 0x00, 0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00}, // 0x1D - '' + {0x00, 0x00, 0x08, 0x08, 0x1C, 0x1C, 0x3E, 0x3E, 0x7F, 0x7F, 0x00, 0x00}, // 0x1E - '' + {0x00, 0x00, 0x7F, 0x7F, 0x3E, 0x3E, 0x1C, 0x1C, 0x08, 0x08, 0x00, 0x00}, // 0x1F - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x20 - ' ' + {0x00, 0x0C, 0x1E, 0x1E, 0x1E, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00, 0x00}, // 0x21 - '!' + {0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x22 - '"' + {0x00, 0x36, 0x36, 0x7F, 0x36, 0x36, 0x36, 0x7F, 0x36, 0x36, 0x00, 0x00}, // 0x23 - '#' + {0x0C, 0x0C, 0x3E, 0x03, 0x03, 0x1E, 0x30, 0x30, 0x1F, 0x0C, 0x0C, 0x00}, // 0x24 - '$' + {0x00, 0x00, 0x00, 0x23, 0x33, 0x18, 0x0C, 0x06, 0x33, 0x31, 0x00, 0x00}, // 0x25 - '%' + {0x00, 0x0E, 0x1B, 0x1B, 0x0E, 0x5F, 0x7B, 0x33, 0x3B, 0x6E, 0x00, 0x00}, // 0x26 - '&' + {0x00, 0x0C, 0x0C, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x27 - ''' + {0x00, 0x30, 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x00}, // 0x28 - '(' + {0x00, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00}, // 0x29 - ')' + {0x00, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00}, // 0x2A - '*' + {0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, // 0x2B - '+' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x1C, 0x06, 0x00}, // 0x2C - ',' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x2D - '-' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00}, // 0x2E - '.' + {0x00, 0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00, 0x00}, // 0x2F - '/' + {0x00, 0x3E, 0x63, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x63, 0x3E, 0x00, 0x00}, // 0x30 - '0' + {0x00, 0x08, 0x0C, 0x0F, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00, 0x00}, // 0x31 - '1' + {0x00, 0x1E, 0x33, 0x33, 0x30, 0x18, 0x0C, 0x06, 0x33, 0x3F, 0x00, 0x00}, // 0x32 - '2' + {0x00, 0x1E, 0x33, 0x30, 0x30, 0x1C, 0x30, 0x30, 0x33, 0x1E, 0x00, 0x00}, // 0x33 - '3' + {0x00, 0x30, 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x30, 0x78, 0x00, 0x00}, // 0x34 - '4' + {0x00, 0x3F, 0x03, 0x03, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00, 0x00}, // 0x35 - '5' + {0x00, 0x1C, 0x06, 0x03, 0x03, 0x1F, 0x33, 0x33, 0x33, 0x1E, 0x00, 0x00}, // 0x36 - '6' + {0x00, 0x7F, 0x63, 0x63, 0x60, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00, 0x00}, // 0x37 - '7' + {0x00, 0x1E, 0x33, 0x33, 0x37, 0x1E, 0x3B, 0x33, 0x33, 0x1E, 0x00, 0x00}, // 0x38 - '8' + {0x00, 0x1E, 0x33, 0x33, 0x33, 0x3E, 0x18, 0x18, 0x0C, 0x0E, 0x00, 0x00}, // 0x39 - '9' + {0x00, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x00}, // 0x3A - ':' + {0x00, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x1C, 0x1C, 0x18, 0x0C, 0x00}, // 0x3B - ';' + {0x00, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x00}, // 0x3C - '<' + {0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x3D - '=' + {0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00}, // 0x3E - '>' + {0x00, 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00, 0x00}, // 0x3F - '?' + {0x00, 0x3E, 0x63, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x03, 0x3E, 0x00, 0x00}, // 0x40 - '@' + {0x00, 0x0C, 0x1E, 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00, 0x00}, // 0x41 - 'A' + {0x00, 0x3F, 0x66, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x66, 0x3F, 0x00, 0x00}, // 0x42 - 'B' + {0x00, 0x3C, 0x66, 0x63, 0x03, 0x03, 0x03, 0x63, 0x66, 0x3C, 0x00, 0x00}, // 0x43 - 'C' + {0x00, 0x1F, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00, 0x00}, // 0x44 - 'D' + {0x00, 0x7F, 0x46, 0x06, 0x26, 0x3E, 0x26, 0x06, 0x46, 0x7F, 0x00, 0x00}, // 0x45 - 'E' + {0x00, 0x7F, 0x66, 0x46, 0x26, 0x3E, 0x26, 0x06, 0x06, 0x0F, 0x00, 0x00}, // 0x46 - 'F' + {0x00, 0x3C, 0x66, 0x63, 0x03, 0x03, 0x73, 0x63, 0x66, 0x7C, 0x00, 0x00}, // 0x47 - 'G' + {0x00, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00}, // 0x48 - 'H' + {0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00}, // 0x49 - 'I' + {0x00, 0x78, 0x30, 0x30, 0x30, 0x30, 0x33, 0x33, 0x33, 0x1E, 0x00, 0x00}, // 0x4A - 'J' + {0x00, 0x67, 0x66, 0x36, 0x36, 0x1E, 0x36, 0x36, 0x66, 0x67, 0x00, 0x00}, // 0x4B - 'K' + {0x00, 0x0F, 0x06, 0x06, 0x06, 0x06, 0x46, 0x66, 0x66, 0x7F, 0x00, 0x00}, // 0x4C - 'L' + {0x00, 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00}, // 0x4D - 'M' + {0x00, 0x63, 0x63, 0x67, 0x6F, 0x7F, 0x7B, 0x73, 0x63, 0x63, 0x00, 0x00}, // 0x4E - 'N' + {0x00, 0x1C, 0x36, 0x63, 0x63, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00, 0x00}, // 0x4F - 'O' + {0x00, 0x3F, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x0F, 0x00, 0x00}, // 0x50 - 'P' + {0x00, 0x1C, 0x36, 0x63, 0x63, 0x63, 0x73, 0x7B, 0x3E, 0x30, 0x78, 0x00}, // 0x51 - 'Q' + {0x00, 0x3F, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x66, 0x67, 0x00, 0x00}, // 0x52 - 'R' + {0x00, 0x1E, 0x33, 0x33, 0x03, 0x0E, 0x18, 0x33, 0x33, 0x1E, 0x00, 0x00}, // 0x53 - 'S' + {0x00, 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00}, // 0x54 - 'T' + {0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x00, 0x00}, // 0x55 - 'U' + {0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00, 0x00}, // 0x56 - 'V' + {0x00, 0x63, 0x63, 0x63, 0x63, 0x6B, 0x6B, 0x36, 0x36, 0x36, 0x00, 0x00}, // 0x57 - 'W' + {0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x1E, 0x33, 0x33, 0x33, 0x00, 0x00}, // 0x58 - 'X' + {0x00, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00}, // 0x59 - 'Y' + {0x00, 0x7F, 0x73, 0x19, 0x18, 0x0C, 0x06, 0x46, 0x63, 0x7F, 0x00, 0x00}, // 0x5A - 'Z' + {0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, 0x00}, // 0x5B - '[' + {0x00, 0x00, 0x01, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00, 0x00}, // 0x5C - '\' + {0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00}, // 0x5D - ']' + {0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x5E - '^' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00}, // 0x5F - '_' + {0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x60 - '`' + {0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x33, 0x6E, 0x00, 0x00}, // 0x61 - 'a' + {0x00, 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x3B, 0x00, 0x00}, // 0x62 - 'b' + {0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x03, 0x03, 0x33, 0x1E, 0x00, 0x00}, // 0x63 - 'c' + {0x00, 0x38, 0x30, 0x30, 0x3E, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00, 0x00}, // 0x64 - 'd' + {0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x33, 0x1E, 0x00, 0x00}, // 0x65 - 'e' + {0x00, 0x1C, 0x36, 0x06, 0x06, 0x1F, 0x06, 0x06, 0x06, 0x0F, 0x00, 0x00}, // 0x66 - 'f' + {0x00, 0x00, 0x00, 0x00, 0x6E, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x33, 0x1E}, // 0x67 - 'g' + {0x00, 0x07, 0x06, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x66, 0x67, 0x00, 0x00}, // 0x68 - 'h' + {0x00, 0x18, 0x18, 0x00, 0x1E, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, 0x00}, // 0x69 - 'i' + {0x00, 0x30, 0x30, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // 0x6A - 'j' + {0x00, 0x07, 0x06, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00, 0x00}, // 0x6B - 'k' + {0x00, 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, 0x00}, // 0x6C - 'l' + {0x00, 0x00, 0x00, 0x00, 0x3F, 0x6B, 0x6B, 0x6B, 0x6B, 0x63, 0x00, 0x00}, // 0x6D - 'm' + {0x00, 0x00, 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00}, // 0x6E - 'n' + {0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x00, 0x00}, // 0x6F - 'o' + {0x00, 0x00, 0x00, 0x00, 0x3B, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // 0x70 - 'p' + {0x00, 0x00, 0x00, 0x00, 0x6E, 0x33, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x78}, // 0x71 - 'q' + {0x00, 0x00, 0x00, 0x00, 0x37, 0x76, 0x6E, 0x06, 0x06, 0x0F, 0x00, 0x00}, // 0x72 - 'r' + {0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x06, 0x18, 0x33, 0x1E, 0x00, 0x00}, // 0x73 - 's' + {0x00, 0x00, 0x04, 0x06, 0x3F, 0x06, 0x06, 0x06, 0x36, 0x1C, 0x00, 0x00}, // 0x74 - 't' + {0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00, 0x00}, // 0x75 - 'u' + {0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00, 0x00}, // 0x76 - 'v' + {0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x6B, 0x6B, 0x36, 0x36, 0x00, 0x00}, // 0x77 - 'w' + {0x00, 0x00, 0x00, 0x00, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00, 0x00}, // 0x78 - 'x' + {0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x30, 0x18, 0x0F}, // 0x79 - 'y' + {0x00, 0x00, 0x00, 0x00, 0x3F, 0x31, 0x18, 0x06, 0x23, 0x3F, 0x00, 0x00}, // 0x7A - 'z' + {0x00, 0x38, 0x0C, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x0C, 0x38, 0x00, 0x00}, // 0x7B - '{' + {0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00}, // 0x7C - '|' + {0x00, 0x07, 0x0C, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x0C, 0x07, 0x00, 0x00}, // 0x7D - '}' + {0x00, 0xCE, 0x5B, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x7E - '~' + {0x00, 0x00, 0x00, 0x08, 0x1C, 0x36, 0x63, 0x63, 0x7F, 0x00, 0x00, 0x00}, // 0x7F - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x80 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x81 - '�' + {0x00, 0x0C, 0x0C, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x82 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x83 - '�' + {0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x84 - '�' + {0x00, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x00}, // 0x85 - '�' + {0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, // 0x86 - '�' + {0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18}, // 0x87 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x88 - '�' + {0x00, 0x00, 0x00, 0x23, 0x33, 0x18, 0x0C, 0x06, 0x33, 0x31, 0x00, 0x00}, // 0x89 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8A - '�' + {0x00, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x00}, // 0x8B - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8C - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8D - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8E - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8F - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x90 - '�' + {0x00, 0x0C, 0x0C, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x91 - '�' + {0x00, 0x0C, 0x0C, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x92 - '�' + {0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x93 - '�' + {0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x94 - '�' + {0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x7E, 0x3C, 0x00, 0x00, 0x00, 0x00}, // 0x95 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x96 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x97 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x98 - '�' + {0x00, 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00}, // 0x99 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9A - '�' + {0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00}, // 0x9B - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9C - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9D - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9E - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9F - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA0 - '�' + {0x18, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x66, 0x3C, 0x00, 0x00}, // 0xA1 - '�' + {0x00, 0x00, 0x18, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x30, 0x18, 0x0F}, // 0xA2 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA3 - '�' + {0x00, 0x00, 0x66, 0x3C, 0x24, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA4 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA5 - '�' + {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, // 0xA6 - '�' + {0x00, 0x7E, 0xC6, 0x0C, 0x3C, 0x66, 0x66, 0x3C, 0x30, 0x63, 0x7E, 0x00}, // 0xA7 - '�' + {0x36, 0x7F, 0x46, 0x06, 0x26, 0x3E, 0x26, 0x06, 0x46, 0x7F, 0x00, 0x00}, // 0xA8 - '�' + {0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x03, 0x03, 0x33, 0x1E, 0x00, 0x00}, // 0xA9 - '�' + {0x00, 0x3C, 0x66, 0x63, 0x03, 0x0F, 0x03, 0x63, 0x66, 0x3C, 0x00, 0x00}, // 0xAA - '�' + {0x00, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x00}, // 0xAB - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, // 0xAC - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xAD - '�' + {0x00, 0x3F, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x66, 0x67, 0x00, 0x00}, // 0xAE - '�' + {0x33, 0x33, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00}, // 0xAF - '�' + {0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB0 - '�' + {0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, // 0xB1 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB2 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB3 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB4 - '�' + {0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x30, 0x00, 0x00}, // 0xB5 - '�' + {0x00, 0xFE, 0xDB, 0xDB, 0xDB, 0xDE, 0xD8, 0xD8, 0xD8, 0xD8, 0x00, 0x00}, // 0xB6 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB7 - '�' + {0x00, 0x12, 0x12, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x33, 0x1E, 0x00, 0x00}, // 0xB8 - '�' + {0x00, 0x73, 0x73, 0x33, 0x37, 0x7F, 0x7B, 0x33, 0x33, 0x33, 0x00, 0x00}, // 0xB9 - '�' + {0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x0F, 0x03, 0x33, 0x1E, 0x00, 0x00}, // 0xBA - '�' + {0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00}, // 0xBB - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBC - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBD - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBE - '�' + {0x00, 0x66, 0x66, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00}, // 0xBF - '�' + {0x00, 0x0C, 0x1E, 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00, 0x00}, // 0xC0 - '�' + {0x00, 0x7F, 0x46, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x3F, 0x00, 0x00}, // 0xC1 - '�' + {0x00, 0x3F, 0x66, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x66, 0x3F, 0x00, 0x00}, // 0xC2 - '�' + {0x00, 0x7F, 0x46, 0x46, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0F, 0x00, 0x00}, // 0xC3 - '�' + {0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xFF, 0xC3, 0x00}, // 0xC4 - '�' + {0x00, 0x7F, 0x46, 0x06, 0x26, 0x3E, 0x26, 0x06, 0x46, 0x7F, 0x00, 0x00}, // 0xC5 - '�' + {0x00, 0x99, 0xDB, 0x5A, 0x7E, 0x3C, 0x7E, 0x5A, 0xDB, 0x99, 0x00, 0x00}, // 0xC6 - '�' + {0x00, 0x3C, 0x66, 0x62, 0x60, 0x38, 0x60, 0x62, 0x66, 0x3C, 0x00, 0x00}, // 0xC7 - '�' + {0x00, 0x63, 0x63, 0x73, 0x7B, 0x7F, 0x6F, 0x67, 0x63, 0x63, 0x00, 0x00}, // 0xC8 - '�' + {0x18, 0x6B, 0x6F, 0x73, 0x7B, 0x7F, 0x6F, 0x67, 0x63, 0x63, 0x00, 0x00}, // 0xC9 - '�' + {0x00, 0x67, 0x66, 0x36, 0x36, 0x1E, 0x36, 0x36, 0x66, 0x67, 0x00, 0x00}, // 0xCA - '�' + {0x00, 0x78, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x63, 0x00, 0x00}, // 0xCB - '�' + {0x00, 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00}, // 0xCC - '�' + {0x00, 0x63, 0x63, 0x63, 0x63, 0x7F, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00}, // 0xCD - '�' + {0x00, 0x1C, 0x36, 0x63, 0x63, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00, 0x00}, // 0xCE - '�' + {0x00, 0x7F, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00}, // 0xCF - '�' + {0x00, 0x3F, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x0F, 0x00, 0x00}, // 0xD0 - '�' + {0x00, 0x3C, 0x66, 0x63, 0x03, 0x03, 0x03, 0x63, 0x66, 0x3C, 0x00, 0x00}, // 0xD1 - '�' + {0x00, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00}, // 0xD2 - '�' + {0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x66, 0x3C, 0x00, 0x00}, // 0xD3 - '�' + {0x00, 0x18, 0x7E, 0xDB, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x00, 0x00}, // 0xD4 - '�' + {0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x1E, 0x33, 0x33, 0x33, 0x00, 0x00}, // 0xD5 - '�' + {0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x7F, 0x60, 0x00}, // 0xD6 - '�' + {0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7E, 0x60, 0x60, 0x60, 0x00, 0x00}, // 0xD7 - '�' + {0x00, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x7F, 0x00, 0x00}, // 0xD8 - '�' + {0x00, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0xFF, 0xC0, 0x00}, // 0xD9 - '�' + {0x00, 0x07, 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00, 0x00}, // 0xDA - '�' + {0x00, 0x63, 0x63, 0x63, 0x63, 0x6F, 0x7B, 0x7B, 0x7B, 0x6F, 0x00, 0x00}, // 0xDB - '�' + {0x00, 0x00, 0x03, 0x03, 0x03, 0x3F, 0x63, 0x63, 0x63, 0x3F, 0x00, 0x00}, // 0xDC - '�' + {0x00, 0x1E, 0x33, 0x63, 0x60, 0x78, 0x60, 0x63, 0x33, 0x1E, 0x00, 0x00}, // 0xDD - '�' + {0x00, 0x73, 0xDB, 0xDB, 0xDF, 0xDF, 0xDB, 0xDB, 0xDB, 0x73, 0x00, 0x00}, // 0xDE - '�' + {0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0xE7, 0x00, 0x00}, // 0xDF - '�' + {0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x33, 0x6E, 0x00, 0x00}, // 0xE0 - '�' + {0x00, 0x00, 0x00, 0x20, 0x3E, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00, 0x00}, // 0xE1 - '�' + {0x00, 0x00, 0x00, 0x00, 0x1F, 0x33, 0x1F, 0x33, 0x33, 0x1F, 0x00, 0x00}, // 0xE2 - '�' + {0x00, 0x00, 0x00, 0x00, 0x3F, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00}, // 0xE3 - '�' + {0x00, 0x00, 0x00, 0x00, 0x3E, 0x36, 0x36, 0x36, 0x36, 0x7F, 0x63, 0x00}, // 0xE4 - '�' + {0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x33, 0x1E, 0x00, 0x00}, // 0xE5 - '�' + {0x00, 0x00, 0x00, 0x00, 0x49, 0x6B, 0x3E, 0x3E, 0x6B, 0x49, 0x00, 0x00}, // 0xE6 - '�' + {0x00, 0x00, 0x00, 0x00, 0x1E, 0x31, 0x1C, 0x30, 0x31, 0x1E, 0x00, 0x00}, // 0xE7 - '�' + {0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x3B, 0x3F, 0x37, 0x33, 0x00, 0x00}, // 0xE8 - '�' + {0x00, 0x10, 0x18, 0x08, 0x33, 0x33, 0x3B, 0x3F, 0x37, 0x33, 0x00, 0x00}, // 0xE9 - '�' + {0x00, 0x00, 0x00, 0x00, 0x33, 0x1B, 0x0F, 0x1B, 0x13, 0x33, 0x00, 0x00}, // 0xEA - '�' + {0x00, 0x00, 0x00, 0x00, 0x38, 0x3C, 0x34, 0x36, 0x32, 0x33, 0x00, 0x00}, // 0xEB - '�' + {0x00, 0x00, 0x00, 0x00, 0x63, 0x77, 0x6B, 0x6B, 0x63, 0x63, 0x00, 0x00}, // 0xEC - '�' + {0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00, 0x00}, // 0xED - '�' + {0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x00, 0x00}, // 0xEE - '�' + {0x00, 0x00, 0x00, 0x00, 0x3F, 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00}, // 0xEF - '�' + {0x00, 0x00, 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x1F, 0x03, 0x03}, // 0xF0 - '�' + {0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x03, 0x03, 0x33, 0x1E, 0x00, 0x00}, // 0xF1 - '�' + {0x00, 0x00, 0x00, 0x00, 0x3F, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x00, 0x00}, // 0xF2 - '�' + {0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x66, 0x3C}, // 0xF3 - '�' + {0x00, 0x00, 0x00, 0x08, 0x3E, 0x6B, 0x6B, 0x6B, 0x3E, 0x08, 0x08, 0x00}, // 0xF4 - '�' + {0x00, 0x00, 0x00, 0x00, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00, 0x00}, // 0xF5 - '�' + {0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x7F, 0x60, 0x00}, // 0xF6 - '�' + {0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x30, 0x00, 0x00}, // 0xF7 - '�' + {0x00, 0x00, 0x00, 0x00, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x7F, 0x00, 0x00}, // 0xF8 - '�' + {0x00, 0x00, 0x00, 0x00, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0xFF, 0xC0, 0x00}, // 0xF9 - '�' + {0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x3E, 0x66, 0x66, 0x3E, 0x00, 0x00}, // 0xFA - '�' + {0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x6F, 0x7B, 0x7B, 0x6F, 0x00, 0x00}, // 0xFB - '�' + {0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x1F, 0x33, 0x33, 0x1F, 0x00, 0x00}, // 0xFC - '�' + {0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x3C, 0x30, 0x33, 0x1E, 0x00, 0x00}, // 0xFD - '�' + {0x00, 0x00, 0x00, 0x00, 0x3B, 0x6F, 0x6F, 0x6F, 0x6F, 0x3B, 0x00, 0x00}, // 0xFE - '�' + {0x00, 0x00, 0x00, 0x00, 0x3E, 0x33, 0x33, 0x3E, 0x36, 0x33, 0x00, 0x00} // 0xFF - '�' +}; + +const unsigned char font12x16[256][32] = +{ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x00 - ' ' + {0xE0, 0x00, 0x18, 0x03, 0x04, 0x04, 0x04, 0x04, 0xB2, 0x09, 0xB2, 0x09, 0x02, 0x08, 0x02, 0x08, 0x12, 0x09, 0xE2, 0x08, 0x04, 0x04, 0x04, 0x04, 0x18, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x01 - '' + {0xE0, 0x00, 0xF8, 0x03, 0xFC, 0x07, 0xFC, 0x07, 0x4E, 0x0E, 0x4E, 0x0E, 0xFE, 0x0F, 0xFE, 0x0F, 0xEE, 0x0E, 0x1E, 0x0F, 0xFC, 0x07, 0xFC, 0x07, 0xF8, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x02 - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0xBC, 0x07, 0xFC, 0x07, 0xFC, 0x07, 0xFC, 0x07, 0xF8, 0x03, 0xF0, 0x01, 0xE0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x03 - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0xE0, 0x00, 0xF0, 0x01, 0xF8, 0x03, 0xFC, 0x07, 0xF8, 0x03, 0xF0, 0x01, 0xE0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x04 - '' + {0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0xF0, 0x01, 0xF0, 0x01, 0xF0, 0x01, 0xEC, 0x06, 0xFE, 0x0F, 0xFE, 0x0F, 0xFE, 0x0F, 0x4C, 0x06, 0xE0, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x05 - '' + {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0xE0, 0x00, 0xF0, 0x01, 0xF8, 0x03, 0xFC, 0x07, 0xFC, 0x07, 0xFC, 0x07, 0x58, 0x03, 0xE0, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x06 - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x07 - '' + {0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0x9F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x9F, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F}, // 0x08 - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x90, 0x00, 0x08, 0x01, 0x08, 0x01, 0x08, 0x01, 0x08, 0x01, 0x90, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x09 - ' ' + {0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0x9F, 0x0F, 0x6F, 0x0F, 0xF7, 0x0E, 0xF7, 0x0E, 0xF7, 0x0E, 0xF7, 0x0E, 0x6F, 0x0F, 0x9F, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F}, // 0x0A - ' ' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x06, 0x78, 0x05, 0xCC, 0x04, 0x86, 0x01, 0x86, 0x01, 0x86, 0x01, 0xCC, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0B - ' ' + {0x00, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x30, 0x03, 0x18, 0x06, 0x18, 0x06, 0x18, 0x06, 0x30, 0x03, 0xE0, 0x01, 0xC0, 0x00, 0xC0, 0x00, 0xF0, 0x03, 0xC0, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0C - ' ' + {0x40, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x01, 0x40, 0x00, 0x40, 0x00, 0x70, 0x00, 0x78, 0x00, 0x78, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0D - ' ' + {0x30, 0x00, 0x70, 0x00, 0xD0, 0x00, 0x90, 0x01, 0x30, 0x03, 0x70, 0x02, 0xD0, 0x02, 0x90, 0x03, 0x1C, 0x03, 0x1E, 0x02, 0x1E, 0x02, 0x8C, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0x80, 0x01, 0x00, 0x00}, // 0x0E - '' + {0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0xE4, 0x04, 0xF8, 0x03, 0x18, 0x03, 0x0C, 0x06, 0x0E, 0x0E, 0x0C, 0x06, 0x18, 0x03, 0xF8, 0x03, 0xE4, 0x04, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0F - '' + {0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x00, 0x38, 0x00, 0x78, 0x00, 0xF8, 0x00, 0xF8, 0x01, 0xF8, 0x00, 0x78, 0x00, 0x38, 0x00, 0x18, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x10 - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x01, 0xC0, 0x01, 0xE0, 0x01, 0xF0, 0x01, 0xF8, 0x01, 0xF0, 0x01, 0xE0, 0x01, 0xC0, 0x01, 0x80, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x11 - '' + {0x00, 0x00, 0x40, 0x00, 0xE0, 0x00, 0xF0, 0x01, 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, 0xF0, 0x01, 0xE0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x12 - '' + {0x00, 0x00, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x00, 0x00, 0x98, 0x01, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x13 - '' + {0x00, 0x00, 0xF8, 0x07, 0x6C, 0x03, 0x66, 0x03, 0x66, 0x03, 0x66, 0x03, 0x6C, 0x03, 0x78, 0x03, 0x60, 0x03, 0x60, 0x03, 0x60, 0x03, 0x60, 0x03, 0x60, 0x03, 0x60, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x14 - '' + {0x00, 0x00, 0xF8, 0x01, 0x0C, 0x03, 0x0C, 0x00, 0x0C, 0x00, 0xF8, 0x01, 0x0C, 0x03, 0x0C, 0x03, 0xF8, 0x01, 0x00, 0x03, 0x00, 0x03, 0x0C, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x15 - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x07, 0xF8, 0x07, 0xF8, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0x16 - '' + {0x40, 0x00, 0xE0, 0x00, 0xF0, 0x01, 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, 0xF0, 0x01, 0xE0, 0x00, 0x40, 0x00, 0xF8, 0x03, 0x00, 0x00}, // 0x17 - '' + {0x00, 0x00, 0x40, 0x00, 0xE0, 0x00, 0xF0, 0x01, 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x18 - '' + {0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, 0xF0, 0x01, 0xE0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x19 - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x01, 0x80, 0x03, 0xFC, 0x07, 0x80, 0x03, 0x80, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1A - ' ' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x30, 0x00, 0x38, 0x00, 0xFC, 0x07, 0x38, 0x00, 0x30, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1B - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xFE, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0x1C - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x18, 0x03, 0x1C, 0x07, 0xFE, 0x0F, 0x1C, 0x07, 0x18, 0x03, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1D - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0xE0, 0x00, 0xF0, 0x01, 0xF8, 0x03, 0xFC, 0x07, 0xFE, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1E - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x0F, 0xFC, 0x07, 0xF8, 0x03, 0xF0, 0x01, 0xE0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1F - '' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x20 - ' ' + {0x60, 0x00, 0x60, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x21 - '!' + {0x00, 0x00, 0x00, 0x00, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x22 - '"' + {0x00, 0x00, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0xFC, 0x0F, 0x30, 0x03, 0x30, 0x03, 0x98, 0x01, 0x98, 0x01, 0xFE, 0x03, 0xCC, 0x00, 0xCC, 0x00, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x23 - '#' + {0x60, 0x00, 0x60, 0x00, 0xF8, 0x01, 0xFC, 0x03, 0x6C, 0x00, 0x6C, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0x60, 0x03, 0x60, 0x03, 0xFC, 0x03, 0xF8, 0x01, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x24 - '$' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x0C, 0x1C, 0x0E, 0x1C, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x07, 0x0E, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0x25 - '%' + {0x00, 0x00, 0xE0, 0x00, 0xB0, 0x01, 0x98, 0x01, 0x98, 0x01, 0xD8, 0x00, 0x70, 0x00, 0x78, 0x00, 0x7C, 0x00, 0xCC, 0x06, 0xCC, 0x03, 0x8C, 0x01, 0xDC, 0x03, 0x78, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x26 - '&' + {0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x60, 0x00, 0x60, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x27 - ''' + {0xC0, 0x01, 0x60, 0x00, 0x70, 0x00, 0x30, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x30, 0x00, 0x70, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x28 - '(' + {0x38, 0x00, 0x60, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0x60, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x29 - ')' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x03, 0x6C, 0x03, 0xF8, 0x01, 0xF0, 0x00, 0xFC, 0x03, 0xF0, 0x00, 0xF8, 0x01, 0x6C, 0x03, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x2A - '*' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xFC, 0x03, 0xFC, 0x03, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x2B - '+' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x60, 0x00, 0x30, 0x00}, // 0x2C - ',' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x03, 0xFC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x2D - '-' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x2E - '.' + {0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0E, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x2F - '/' + {0xF0, 0x01, 0xFC, 0x07, 0x0C, 0x06, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x0C, 0x06, 0xFC, 0x07, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x30 - '0' + {0xC0, 0x00, 0xE0, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xF8, 0x07, 0xF8, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0x31 - '1' + {0xF8, 0x03, 0xFC, 0x07, 0x0E, 0x0E, 0x06, 0x0C, 0x06, 0x0E, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0xFE, 0x0F, 0xFE, 0x0F, 0x00, 0x00, 0x00, 0x00}, // 0x32 - '2' + {0xF8, 0x03, 0xFC, 0x07, 0x0E, 0x0E, 0x06, 0x0C, 0x00, 0x0C, 0x00, 0x0E, 0xF0, 0x07, 0xF0, 0x03, 0x00, 0x06, 0x00, 0x0C, 0x06, 0x0C, 0x0E, 0x0E, 0xFC, 0x07, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x33 - '3' + {0x80, 0x03, 0xC0, 0x03, 0xE0, 0x03, 0x70, 0x03, 0x38, 0x03, 0x1C, 0x03, 0x0E, 0x03, 0x06, 0x03, 0xFE, 0x0F, 0xFE, 0x0F, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x34 - '4' + {0xFE, 0x0F, 0xFE, 0x0F, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x03, 0xFC, 0x07, 0x00, 0x0E, 0x00, 0x0C, 0x00, 0x0C, 0x06, 0x0C, 0x0E, 0x0E, 0xFC, 0x07, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x35 - '5' + {0xC0, 0x03, 0xE0, 0x03, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0C, 0x00, 0xFE, 0x03, 0xFE, 0x07, 0x0E, 0x0E, 0x06, 0x0C, 0x06, 0x0C, 0x0E, 0x0E, 0xFC, 0x07, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x36 - '6' + {0xFE, 0x0F, 0xFE, 0x0F, 0x00, 0x06, 0x00, 0x06, 0x00, 0x03, 0x00, 0x03, 0x80, 0x01, 0x80, 0x01, 0xC0, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x37 - '7' + {0xF0, 0x01, 0xF8, 0x03, 0x1C, 0x07, 0x0C, 0x06, 0x0C, 0x06, 0x1C, 0x07, 0xF8, 0x03, 0xFC, 0x07, 0x0E, 0x0E, 0x06, 0x0C, 0x06, 0x0C, 0x0E, 0x0E, 0xFC, 0x07, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x38 - '8' + {0xF8, 0x03, 0xFC, 0x07, 0x0E, 0x0E, 0x06, 0x0C, 0x06, 0x0C, 0x0E, 0x0E, 0xFC, 0x0F, 0xF8, 0x0F, 0x00, 0x06, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xF8, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x39 - '9' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x3A - ':' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x60, 0x00, 0x60, 0x00, 0x30, 0x00}, // 0x3B - ';' + {0x00, 0x03, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x3C - '<' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x07, 0xFC, 0x07, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x07, 0xFC, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x3D - '=' + {0x0C, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x3E - '>' + {0xF8, 0x01, 0xFC, 0x03, 0x0E, 0x07, 0x06, 0x06, 0x06, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x3F - '?' + {0xF8, 0x03, 0xFC, 0x07, 0x0C, 0x06, 0xE6, 0x0D, 0xF6, 0x0D, 0xB6, 0x0D, 0xB6, 0x0D, 0xB6, 0x0D, 0xB6, 0x0D, 0xF6, 0x07, 0xE6, 0x03, 0x0E, 0x00, 0xFC, 0x03, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x40 - '@' + {0x60, 0x00, 0x60, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x0C, 0x03, 0xFC, 0x03, 0xFC, 0x03, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x41 - 'A' + {0xFE, 0x00, 0xFE, 0x01, 0x86, 0x03, 0x06, 0x03, 0x06, 0x03, 0x86, 0x03, 0xFE, 0x01, 0xFE, 0x03, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0xFE, 0x03, 0xFE, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x42 - 'B' + {0xF0, 0x01, 0xF8, 0x03, 0x1C, 0x07, 0x0C, 0x06, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x0C, 0x06, 0x1C, 0x07, 0xF8, 0x03, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x43 - 'C' + {0xFE, 0x00, 0xFE, 0x01, 0x86, 0x03, 0x06, 0x03, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x03, 0x86, 0x03, 0xFE, 0x01, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x44 - 'D' + {0xFE, 0x07, 0xFE, 0x07, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x01, 0xFE, 0x01, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x07, 0xFE, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0x45 - 'E' + {0xFE, 0x07, 0xFE, 0x07, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x01, 0xFE, 0x01, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x46 - 'F' + {0xF0, 0x03, 0xF8, 0x07, 0x1C, 0x06, 0x0C, 0x00, 0x06, 0x00, 0x06, 0x00, 0xC6, 0x07, 0xC6, 0x07, 0x06, 0x06, 0x06, 0x06, 0x0C, 0x06, 0x1C, 0x06, 0xF8, 0x07, 0xF0, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0x47 - 'G' + {0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xFE, 0x07, 0xFE, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x48 - 'H' + {0xF8, 0x01, 0xF8, 0x01, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xF8, 0x01, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x49 - 'I' + {0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0E, 0x03, 0xFC, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x4A - 'J' + {0x06, 0x06, 0x06, 0x07, 0x86, 0x03, 0xC6, 0x01, 0xE6, 0x00, 0x76, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x76, 0x00, 0xE6, 0x00, 0xC6, 0x01, 0x86, 0x03, 0x06, 0x07, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x4B - 'K' + {0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x07, 0xFE, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0x4C - 'L' + {0x06, 0x06, 0x0E, 0x07, 0x0E, 0x07, 0x9E, 0x07, 0x9E, 0x07, 0xF6, 0x06, 0xF6, 0x06, 0x66, 0x06, 0x66, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x4D - 'M' + {0x06, 0x06, 0x0E, 0x06, 0x0E, 0x06, 0x1E, 0x06, 0x36, 0x06, 0x36, 0x06, 0x66, 0x06, 0x66, 0x06, 0xC6, 0x06, 0xC6, 0x06, 0x86, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x4E - 'N' + {0xF0, 0x00, 0xF8, 0x01, 0x9C, 0x03, 0x0C, 0x03, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0C, 0x03, 0x9C, 0x03, 0xF8, 0x01, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x4F - 'O' + {0xFE, 0x01, 0xFE, 0x03, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0xFE, 0x03, 0xFE, 0x01, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x50 - 'P' + {0xF0, 0x00, 0xF8, 0x01, 0x9C, 0x03, 0x0C, 0x03, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xC6, 0x06, 0xCC, 0x03, 0x9C, 0x03, 0xF8, 0x07, 0xF0, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x51 - 'Q' + {0xFE, 0x01, 0xFE, 0x03, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0xFE, 0x03, 0xFE, 0x01, 0xE6, 0x00, 0xC6, 0x01, 0x86, 0x03, 0x06, 0x07, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x52 - 'R' + {0xF8, 0x01, 0xFC, 0x03, 0x0E, 0x07, 0x06, 0x06, 0x06, 0x00, 0x0E, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0x00, 0x07, 0x00, 0x06, 0x06, 0x06, 0x0E, 0x07, 0xFC, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x53 - 'S' + {0xFC, 0x03, 0xFC, 0x03, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x54 - 'T' + {0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0C, 0x03, 0xFC, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x55 - 'U' + {0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x56 - 'V' + {0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x06, 0x66, 0x06, 0xF6, 0x06, 0x9E, 0x07, 0x0E, 0x07, 0x0E, 0x07, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x57 - 'W' + {0x06, 0x06, 0x06, 0x06, 0x0C, 0x03, 0x0C, 0x03, 0x98, 0x01, 0xF0, 0x00, 0x60, 0x00, 0x60, 0x00, 0xF0, 0x00, 0x98, 0x01, 0x0C, 0x03, 0x0C, 0x03, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x58 - 'X' + {0x06, 0x06, 0x06, 0x06, 0x0C, 0x03, 0x0C, 0x03, 0x98, 0x01, 0x98, 0x01, 0xF0, 0x00, 0xF0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x59 - 'Y' + {0xFE, 0x07, 0xFE, 0x07, 0x00, 0x03, 0x00, 0x03, 0x80, 0x01, 0xC0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0xFE, 0x07, 0xFE, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0x5A - 'Z' + {0xF8, 0x01, 0xF8, 0x01, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0xF8, 0x01, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x5B - '[' + {0x00, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x0E, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x5C - '\' + {0xF8, 0x01, 0xF8, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xF8, 0x01, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x5D - ']' + {0x40, 0x00, 0xE0, 0x00, 0xF0, 0x01, 0xB8, 0x03, 0x1C, 0x07, 0x0E, 0x0E, 0x06, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x5E - '^' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x0F, 0xFE, 0x0F}, // 0x5F - '_' + {0x00, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0x60, 0x00, 0x60, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x60 - '`' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x03, 0xFC, 0x07, 0x00, 0x06, 0xF8, 0x07, 0xFC, 0x07, 0x06, 0x06, 0x06, 0x06, 0xFE, 0x07, 0xFC, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0x61 - 'a' + {0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xF6, 0x01, 0xFE, 0x03, 0x0E, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0xFE, 0x03, 0xFE, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x62 - 'b' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x01, 0xFC, 0x03, 0x0E, 0x06, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x0E, 0x06, 0xFC, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x63 - 'c' + {0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0xF8, 0x06, 0xFC, 0x07, 0x8E, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0E, 0x06, 0xFC, 0x07, 0xF8, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0x64 - 'd' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x01, 0xFC, 0x03, 0x0E, 0x06, 0xFE, 0x07, 0xFE, 0x03, 0x06, 0x00, 0x0E, 0x00, 0xFC, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x65 - 'e' + {0xE0, 0x01, 0xF0, 0x01, 0x38, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x66 - 'f' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x07, 0xFC, 0x07, 0x0E, 0x06, 0x06, 0x06, 0x0E, 0x07, 0xFC, 0x07, 0xF8, 0x06, 0x00, 0x06, 0x00, 0x07, 0xFC, 0x03, 0xFC, 0x01}, // 0x67 - 'g' + {0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xF6, 0x00, 0xFE, 0x01, 0x8E, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x68 - 'h' + {0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xF8, 0x01, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x69 - 'i' + {0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x00, 0x00, 0xC0, 0x01, 0xC0, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x98, 0x01, 0xF8, 0x01, 0xF0, 0x00}, // 0x6A - 'j' + {0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x8C, 0x01, 0xCC, 0x01, 0xEC, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0xEC, 0x00, 0xCC, 0x01, 0x8C, 0x03, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x6B - 'k' + {0x70, 0x00, 0x70, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xF8, 0x01, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x6C - 'l' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A, 0x01, 0xFE, 0x03, 0xFE, 0x07, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x6D - 'm' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x01, 0xFC, 0x03, 0x0C, 0x07, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x6E - 'n' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x01, 0xFC, 0x03, 0x0E, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0E, 0x07, 0xFC, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x6F - 'o' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0xFE, 0x03, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x0E, 0x07, 0xFE, 0x03, 0xF6, 0x01, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00}, // 0x70 - 'p' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x07, 0xFC, 0x07, 0x0E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0E, 0x07, 0xFC, 0x07, 0xF8, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06}, // 0x71 - 'q' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x03, 0xFC, 0x07, 0x1C, 0x06, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x72 - 'r' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0xFE, 0x01, 0x06, 0x00, 0xFE, 0x00, 0xFC, 0x01, 0x80, 0x01, 0x80, 0x01, 0xFE, 0x01, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x73 - 's' + {0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0xF8, 0x01, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x74 - 't' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0E, 0x07, 0xFC, 0x07, 0xF8, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x75 - 'u' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x0C, 0x03, 0x0C, 0x03, 0x98, 0x01, 0x98, 0x01, 0xF0, 0x00, 0xF0, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x76 - 'v' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0xF6, 0x06, 0xFC, 0x03, 0x9C, 0x03, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x77 - 'w' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x03, 0x8E, 0x03, 0xDC, 0x01, 0xF8, 0x00, 0x70, 0x00, 0xF8, 0x00, 0xDC, 0x01, 0x8E, 0x03, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x78 - 'x' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x0C, 0x03, 0x98, 0x01, 0x98, 0x01, 0xF0, 0x00, 0xF0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x30, 0x00, 0x30, 0x00, 0x18, 0x00}, // 0x79 - 'y' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x03, 0xFE, 0x01, 0xC0, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00, 0x0C, 0x00, 0xFE, 0x03, 0xFE, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x7A - 'z' + {0xC0, 0x03, 0xE0, 0x03, 0x70, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x70, 0x00, 0xE0, 0x03, 0xC0, 0x03, 0x00, 0x00}, // 0x7B - '{' + {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x7C - '|' + {0x3C, 0x00, 0x7C, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0x80, 0x03, 0xC0, 0x01, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xE0, 0x00, 0x7C, 0x00, 0x3C, 0x00, 0x00, 0x00}, // 0x7D - '}' + {0x00, 0x00, 0x00, 0x00, 0x38, 0x06, 0x6C, 0x03, 0xC6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x7E - '~' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0xF0, 0x00, 0x98, 0x01, 0x0C, 0x03, 0x06, 0x06, 0x06, 0x06, 0xFE, 0x07, 0xFE, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x7F - '' + {0x11, 0x01, 0x44, 0x04, 0x11, 0x01, 0x44, 0x04, 0x11, 0x01, 0x44, 0x04, 0x11, 0x01, 0x44, 0x04, 0x11, 0x01, 0x44, 0x04, 0x11, 0x01, 0x44, 0x04, 0x11, 0x01, 0x44, 0x04, 0x11, 0x01, 0x44, 0x04}, // 0x80 - '�' + {0xAA, 0x0A, 0x55, 0x05, 0xAA, 0x0A, 0x55, 0x05, 0xAA, 0x0A, 0x55, 0x05, 0xAA, 0x0A, 0x55, 0x05, 0xAA, 0x0A, 0x55, 0x05, 0xAA, 0x0A, 0x55, 0x05, 0xAA, 0x0A, 0x55, 0x05, 0xAA, 0x0A, 0x55, 0x05}, // 0x81 - '�' + {0xEE, 0x0E, 0xBB, 0x0B, 0xEE, 0x0E, 0xBB, 0x0B, 0xEE, 0x0E, 0xBB, 0x0B, 0xEE, 0x0E, 0xBB, 0x0B, 0xEE, 0x0E, 0xBB, 0x0B, 0xEE, 0x0E, 0xBB, 0x0B, 0xEE, 0x0E, 0xBB, 0x0B, 0xEE, 0x0E, 0xBB, 0x0B}, // 0x82 - '�' + {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0x83 - '�' + {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0x84 - '�' + {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x60, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0x85 - '�' + {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0x86 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0x87 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x60, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0x88 - '�' + {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x60, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0x89 - '�' + {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0x8A - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x60, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0x8B - '�' + {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x60, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8C - '�' + {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8D - '�' + {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x60, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8E - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0x8F - '�' + {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x90 - '�' + {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x91 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0x92 - '�' + {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0x93 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x94 - '�' + {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0x95 - '�' + {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0x60, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0x96 - '�' + {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0xEC, 0x0F, 0xEC, 0x0F, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0x97 - '�' + {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0xEC, 0x0F, 0xEC, 0x0F, 0x0C, 0x00, 0xFC, 0x0F, 0xFC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x98 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0xFC, 0x0F, 0x0C, 0x00, 0xEC, 0x0F, 0xEC, 0x0F, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0x99 - '�' + {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0xEF, 0x0F, 0xEF, 0x0F, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9A - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0xEF, 0x0F, 0xEF, 0x0F, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0x9B - '�' + {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0xEC, 0x0F, 0xEC, 0x0F, 0x0C, 0x00, 0xEC, 0x0F, 0xEC, 0x0F, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0x9C - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9D - '�' + {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0xEF, 0x0F, 0xEF, 0x0F, 0x00, 0x00, 0xEF, 0x0F, 0xEF, 0x0F, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0x9E - '�' + {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9F - '�' + {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA0 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0xA1 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0xA2 - '�' + {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0xFC, 0x0F, 0xFC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA3 - '�' + {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0x60, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA4 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0x60, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0xA5 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0xFC, 0x0F, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0xA6 - '�' + {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0xEF, 0x0F, 0xEF, 0x0F, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0xA7 - '�' + {0x98, 0x01, 0x98, 0x01, 0x00, 0x00, 0xFE, 0x07, 0xFE, 0x07, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x01, 0xFE, 0x01, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x07, 0xFE, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0xA8 - '�' + {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0xA9 - '�' + {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xAA - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0xAB - '�' + {0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F}, // 0xAC - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F}, // 0xAD - '�' + {0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00}, // 0xAE - '�' + {0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F}, // 0xAF - '�' + {0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB0 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0xA4, 0x04, 0x44, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x02, 0x10, 0x01, 0xA0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB1 - '�' + {0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x20, 0x04, 0x1C, 0x08, 0xFE, 0x0F, 0xFE, 0x0F, 0xFE, 0x0F, 0xFE, 0x0F, 0xFC, 0x07, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB2 - '�' + {0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x20, 0x04, 0x1C, 0x08, 0xFE, 0x0F, 0x02, 0x08, 0x02, 0x08, 0x02, 0x08, 0x04, 0x04, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB3 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB4 - '�' + {0x00, 0x00, 0xC0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0x90, 0x00, 0x00, 0x00, 0xFE, 0x07, 0x00, 0x00, 0x90, 0x00, 0x90, 0x00, 0xE0, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB5 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x01, 0x60, 0x00, 0x0C, 0x03, 0x0C, 0x03, 0x98, 0x01, 0x98, 0x01, 0xF0, 0x00, 0xF0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x30, 0x00, 0x30, 0x00, 0x18, 0x00}, // 0xB6 - '�' + {0xF0, 0x00, 0xF8, 0x01, 0x98, 0x01, 0x98, 0x01, 0xF8, 0x01, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB7 - '�' + {0x00, 0x00, 0x00, 0x00, 0x98, 0x01, 0x98, 0x01, 0x00, 0x00, 0xF8, 0x01, 0xFC, 0x03, 0x0E, 0x06, 0xFE, 0x07, 0xFE, 0x07, 0x06, 0x00, 0x06, 0x00, 0xFC, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xB8 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xF8, 0x01, 0xF8, 0x01, 0xF8, 0x01, 0xF8, 0x01, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB9 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBA - '�' + {0x00, 0x00, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC4, 0x00, 0xCC, 0x00, 0xD8, 0x00, 0xF0, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBB - '�' + {0xC3, 0x00, 0xC7, 0x06, 0xC7, 0x0F, 0xC7, 0x09, 0xCF, 0x0F, 0xCB, 0x06, 0xCB, 0x00, 0xDB, 0x00, 0xD3, 0x0F, 0xF3, 0x0F, 0xE3, 0x00, 0xE3, 0x00, 0xE3, 0x00, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBC - '�' + {0x00, 0x00, 0x06, 0x06, 0xF6, 0x06, 0xFC, 0x03, 0x0E, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0E, 0x07, 0xFC, 0x03, 0xF6, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBD - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBE - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBF - '�' + {0xF0, 0x07, 0xF8, 0x07, 0x1C, 0x06, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xFE, 0x07, 0xFE, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xC0 - '�' + {0xFE, 0x07, 0xFE, 0x07, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x01, 0xFE, 0x03, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0xFE, 0x03, 0xFE, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xC1 - '�' + {0xFE, 0x00, 0xFE, 0x01, 0x86, 0x03, 0x06, 0x03, 0x06, 0x03, 0x86, 0x03, 0xFE, 0x01, 0xFE, 0x03, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0xFE, 0x03, 0xFE, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xC2 - '�' + {0xFE, 0x07, 0xFE, 0x07, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xC3 - '�' + {0xF0, 0x07, 0xF8, 0x07, 0x1C, 0x06, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xFF, 0x0F, 0xFF, 0x0F, 0x03, 0x0C, 0x03, 0x0C}, // 0xC4 - '�' + {0xFE, 0x07, 0xFE, 0x07, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x01, 0xFE, 0x01, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x07, 0xFE, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0xC5 - '�' + {0x61, 0x08, 0x63, 0x0C, 0x63, 0x0C, 0x67, 0x06, 0x66, 0x06, 0x6E, 0x03, 0xFC, 0x03, 0xFC, 0x03, 0x6E, 0x07, 0x66, 0x06, 0x67, 0x0E, 0x63, 0x0C, 0x63, 0x0C, 0x61, 0x08, 0x00, 0x00, 0x00, 0x00}, // 0xC6 - '�' + {0xF8, 0x03, 0xFC, 0x07, 0x0E, 0x0E, 0x06, 0x0C, 0x00, 0x0C, 0x00, 0x0E, 0xF0, 0x07, 0xF0, 0x03, 0x00, 0x06, 0x00, 0x0C, 0x06, 0x0C, 0x0E, 0x0E, 0xFC, 0x07, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0xC7 - '�' + {0x06, 0x06, 0x06, 0x07, 0x06, 0x07, 0x86, 0x07, 0xC6, 0x06, 0xC6, 0x06, 0x66, 0x06, 0x66, 0x06, 0x36, 0x06, 0x36, 0x06, 0x1E, 0x06, 0x0E, 0x06, 0x0E, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xC8 - '�' + {0x46, 0x06, 0x66, 0x07, 0x26, 0x07, 0x86, 0x07, 0xC6, 0x06, 0xC6, 0x06, 0x66, 0x06, 0x66, 0x06, 0x36, 0x06, 0x36, 0x06, 0x1E, 0x06, 0x0E, 0x06, 0x0E, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xC9 - '�' + {0x06, 0x06, 0x06, 0x07, 0x86, 0x03, 0xC6, 0x01, 0xE6, 0x00, 0x76, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x76, 0x00, 0xE6, 0x00, 0xC6, 0x01, 0x86, 0x03, 0x06, 0x07, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xCA - '�' + {0xF0, 0x07, 0xF8, 0x07, 0x1C, 0x06, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xCB - '�' + {0x06, 0x06, 0x0E, 0x07, 0x0E, 0x07, 0x9E, 0x07, 0x9E, 0x07, 0xF6, 0x06, 0xF6, 0x06, 0x66, 0x06, 0x66, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xCC - '�' + {0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xFE, 0x07, 0xFE, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xCD - '�' + {0xF0, 0x00, 0xF8, 0x01, 0x9C, 0x03, 0x0C, 0x03, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0C, 0x03, 0x9C, 0x03, 0xF8, 0x01, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xCE - '�' + {0xFE, 0x07, 0xFE, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xCF - '�' + {0xFE, 0x01, 0xFE, 0x03, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0xFE, 0x03, 0xFE, 0x01, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xD0 - '�' + {0xF0, 0x01, 0xF8, 0x03, 0x1C, 0x07, 0x0C, 0x06, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x0C, 0x06, 0x1C, 0x07, 0xF8, 0x03, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xD1 - '�' + {0xFC, 0x03, 0xFC, 0x03, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xD2 - '�' + {0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xFE, 0x07, 0xFC, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x06, 0x03, 0xFE, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xD3 - '�' + {0x60, 0x00, 0x60, 0x00, 0xFC, 0x03, 0xFE, 0x07, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0xFE, 0x07, 0xFC, 0x03, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xD4 - '�' + {0x06, 0x06, 0x06, 0x06, 0x0C, 0x03, 0x0C, 0x03, 0x98, 0x01, 0xF0, 0x00, 0x60, 0x00, 0x60, 0x00, 0xF0, 0x00, 0x98, 0x01, 0x0C, 0x03, 0x0C, 0x03, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xD5 - '�' + {0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0xFE, 0x07, 0xFE, 0x07, 0x00, 0x06, 0x00, 0x06}, // 0xD6 - '�' + {0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xFE, 0x07, 0xFC, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xD7 - '�' + {0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0xFE, 0x07, 0xFE, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0xD8 - '�' + {0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0xFE, 0x0F, 0xFE, 0x0F, 0x00, 0x0C, 0x00, 0x0C}, // 0xD9 - '�' + {0x1F, 0x00, 0x1F, 0x00, 0x1B, 0x00, 0x1B, 0x00, 0x18, 0x00, 0xF8, 0x01, 0xF8, 0x03, 0x18, 0x07, 0x18, 0x06, 0x18, 0x06, 0x18, 0x06, 0x18, 0x07, 0xF8, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xDA - '�' + {0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x3E, 0x06, 0x7E, 0x06, 0xE6, 0x06, 0xC6, 0x06, 0xC6, 0x06, 0xC6, 0x06, 0xE6, 0x06, 0x7E, 0x06, 0x3E, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xDB - '�' + {0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x01, 0xFE, 0x03, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0xFE, 0x03, 0xFE, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xDC - '�' + {0xF8, 0x00, 0xFC, 0x01, 0x8E, 0x03, 0x06, 0x03, 0x00, 0x06, 0x00, 0x06, 0xF0, 0x07, 0xF0, 0x07, 0x00, 0x06, 0x00, 0x06, 0x06, 0x03, 0x8E, 0x03, 0xFC, 0x01, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xDD - '�' + {0xC3, 0x01, 0xE3, 0x03, 0x73, 0x07, 0x33, 0x06, 0x1B, 0x0C, 0x1B, 0x0C, 0x1F, 0x0C, 0x1F, 0x0C, 0x1B, 0x0C, 0x1B, 0x0C, 0x33, 0x06, 0x73, 0x07, 0xE3, 0x03, 0xC3, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xDE - '�' + {0xF8, 0x07, 0xFC, 0x07, 0x0E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0E, 0x06, 0xFC, 0x07, 0xF8, 0x07, 0x70, 0x06, 0x38, 0x06, 0x1C, 0x06, 0x0E, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xDF - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x03, 0xFC, 0x07, 0x00, 0x06, 0xF8, 0x07, 0xFC, 0x07, 0x06, 0x06, 0x06, 0x06, 0xFE, 0x07, 0xFC, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0xE0 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFC, 0x03, 0xFE, 0x01, 0x06, 0x00, 0xF6, 0x01, 0xFE, 0x03, 0x0E, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0xFE, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xE1 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x01, 0xFC, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0xFC, 0x01, 0x0C, 0x03, 0x0C, 0x03, 0xFC, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xE2 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x03, 0xFC, 0x03, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xE3 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x03, 0xF8, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0xFE, 0x07, 0xFE, 0x07, 0x06, 0x06, 0x06, 0x06}, // 0xE4 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x01, 0xFC, 0x03, 0x0E, 0x06, 0xFE, 0x07, 0xFE, 0x03, 0x06, 0x00, 0x0E, 0x00, 0xFC, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xE5 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x0C, 0x67, 0x0E, 0x6E, 0x07, 0xFC, 0x03, 0xFC, 0x03, 0x6C, 0x03, 0x66, 0x06, 0x67, 0x0E, 0x63, 0x0C, 0x00, 0x00, 0x00, 0x00}, // 0xE6 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xF8, 0x01, 0x0C, 0x03, 0x00, 0x03, 0xE0, 0x01, 0x00, 0x03, 0x0C, 0x03, 0xF8, 0x01, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xE7 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x07, 0x8C, 0x07, 0xCC, 0x06, 0x6C, 0x06, 0x3C, 0x06, 0x1C, 0x06, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xE8 - '�' + {0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xC0, 0x00, 0x40, 0x00, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x07, 0x8C, 0x07, 0xCC, 0x06, 0x6C, 0x06, 0x3C, 0x06, 0x1C, 0x06, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xE9 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x01, 0xCC, 0x01, 0xEC, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0xEC, 0x00, 0xCC, 0x01, 0x8C, 0x03, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0xEA - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x03, 0xF8, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0xEB - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x07, 0x9E, 0x07, 0x9E, 0x07, 0xF6, 0x06, 0x66, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xEC - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0xFC, 0x07, 0xFC, 0x07, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xED - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x01, 0xFC, 0x03, 0x0E, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0E, 0x07, 0xFC, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xEE - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x07, 0xFC, 0x07, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xEF - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0xFE, 0x03, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x0E, 0x07, 0xFE, 0x03, 0xF6, 0x01, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00}, // 0xF0 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x01, 0xFC, 0x03, 0x0E, 0x06, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x0E, 0x06, 0xFC, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xF1 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x03, 0xFC, 0x03, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xF2 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x0C, 0x03, 0x98, 0x01, 0x98, 0x01, 0xF0, 0x00, 0xF0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x30, 0x00, 0x30, 0x00, 0x18, 0x00}, // 0xF3 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0xFC, 0x03, 0xFE, 0x07, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0xFE, 0x07, 0xFC, 0x03, 0x60, 0x00, 0x60, 0x00}, // 0xF4 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x03, 0x8E, 0x03, 0xDC, 0x01, 0xF8, 0x00, 0x70, 0x00, 0xF8, 0x00, 0xDC, 0x01, 0x8E, 0x03, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0xF5 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0xFC, 0x07, 0xFC, 0x07, 0x00, 0x06, 0x00, 0x06}, // 0xF6 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0xFC, 0x03, 0xF8, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0xF7 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0xFE, 0x07, 0xFE, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0xF8 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0xFE, 0x0F, 0xFE, 0x0F, 0x00, 0x0C, 0x00, 0x0C}, // 0xF9 - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x36, 0x00, 0xF0, 0x03, 0xF0, 0x07, 0x30, 0x06, 0x30, 0x06, 0xF0, 0x07, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0xFA - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7E, 0x06, 0xFE, 0x06, 0xC6, 0x06, 0xC6, 0x06, 0xFE, 0x06, 0x7E, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xFB - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0xFC, 0x01, 0xFC, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0xFC, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xFC - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0xFC, 0x01, 0x06, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0x00, 0x03, 0x86, 0x03, 0xFC, 0x01, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xFD - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x01, 0xE6, 0x03, 0x76, 0x07, 0x3E, 0x06, 0x3E, 0x06, 0x36, 0x06, 0x76, 0x07, 0xE6, 0x03, 0xC6, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xFE - '�' + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x03, 0xFC, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0xF8, 0x03, 0x70, 0x03, 0x38, 0x03, 0x1C, 0x03, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x00} // 0xFF - '�' +}; diff --git a/Display/Fonts.h b/Display/Fonts.h new file mode 100644 index 0000000..5dc96ca --- /dev/null +++ b/Display/Fonts.h @@ -0,0 +1,47 @@ +//****************************************************************************** +// @file Fonts.h +// @author Nicolai Shlapunov +// +// @details DevCore: Fonts data, header +// +// @section LICENSE +// +// Software License Agreement (BSD License) +// +// Copyright (c) 2016, Devtronic & Nicolai Shlapunov +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// 3. Neither the name of the Devtronic nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL DEVTRONIC BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//****************************************************************************** + +#ifndef Fonts_h +#define Fonts_h + +extern const unsigned char font4x6[256][6]; +extern const unsigned char font6x8[256][8]; +extern const unsigned char font8x8[256][8]; +extern const unsigned char font8x12[256][16]; +extern const unsigned char font12x16[256][24]; + +#endif diff --git a/Display/ILI9341.cpp b/Display/ILI9341.cpp new file mode 100644 index 0000000..f680a33 --- /dev/null +++ b/Display/ILI9341.cpp @@ -0,0 +1,566 @@ +//****************************************************************************** +// @file ILI9341.cpp +// @author Nicolai Shlapunov +// +// @details DevCore: ILI9341 Low Level Driver Class, implementation +// +// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov +// All rights reserved. +// +// @section SUPPORT +// +// Devtronic invests time and resources providing this open source code, +// please support Devtronic and open-source hardware/software by +// donations and/or purchasing products from Devtronic. +// +//****************************************************************************** + +// ***************************************************************************** +// *** Includes ************************************************************ +// ***************************************************************************** +#include "ILI9341.h" + +// ***************************************************************************** +// *** Defines ************************************************************* +// ***************************************************************************** + +// Commands definitions + +#define CMD_NOP 0x00 // No Operation +#define CMD_SWRESET 0x01 // Software Reset +#define CMD_RDDID 0x04 // Read Display Identification Information +#define CMD_RDDST 0x09 // Read Display Status + +#define CMD_RDMODE 0x0A // Read Display Power Mode +#define CMD_RDMADCTL 0x0B // Read Display MADCTL +#define CMD_RDPIXFMT 0x0C // Read Display Pixel Format +#define CMD_RDIMGFMT 0x0D // Read Display Image Format +#define CMD_RDSIGMOD 0x0E // Read Display Signal Mode +#define CMD_RDSELFDIAG 0x0F // Read Display Self-Diagnostic Result + +#define CMD_SLPIN 0x10 // Enter Sleep Mode +#define CMD_SLPOUT 0x11 // Sleep OUT +#define CMD_PTLON 0x12 // Partial Mode ON +#define CMD_NORON 0x13 // Normal Display Mode ON + +#define CMD_INVOFF 0x20 // Display Inversion OFF +#define CMD_INVON 0x21 // Display Inversion ON +#define CMD_GAMMASET 0x26 // Gamma Set +#define CMD_DISPOFF 0x28 // Display OFF +#define CMD_DISPON 0x29 // Display ON + +#define CMD_CASET 0x2A // Column Address Set +#define CMD_PASET 0x2B // Page Address Set +#define CMD_RAMWR 0x2C // Memory Write +#define CMD_GSET 0x2D // Color SET +#define CMD_RAMRD 0x2E // Memory Read + +#define CMD_PTLAR 0x30 // Partial Area +#define CMD_VSCRDEF 0x33 // Vertical Scrolling Definition +#define CMD_TELOFF 0x34 // Tearing Effect Line OFF +#define CMD_TELON 0x35 // Tearing Effect Line ON +#define CMD_MADCTL 0x36 // Memory Access Control +#define CMD_VSAADDR 0x37 // Vertical Scrolling Start Address +#define CMD_IDLMOFF 0x38 // Idle Mode OFF +#define CMD_IDLMON 0x39 // Idle Mode ON +#define CMD_PIXFMT 0x3A // Pixel Format Set + +#define CMD_RGBISC 0xB0 // RGB Interface Signal Control +#define CMD_FRMCTR1 0xB1 // Frame Control (In Normal Mode) +#define CMD_FRMCTR2 0xB2 // Frame Control (In Idle Mode) +#define CMD_FRMCTR3 0xB3 // Frame Control (In Partial Mode) +#define CMD_INVCTR 0xB4 // Display Inversion Control +#define CMD_BLKPC 0xB5 // Blanking Porch Control +#define CMD_DFUNCTR 0xB6 // Display Function Control + +#define CMD_PWCTR1 0xC0 // Power Control 1 +#define CMD_PWCTR2 0xC1 // Power Control 2 +#define CMD_VMCTR1 0xC5 // VCOM Control 1 +#define CMD_VMCTR2 0xC7 // VCOM Control 2 +#define CMD_PWCTRA 0xCB // Power control A +#define CMD_PWCTRB 0xCF // Power control B + +#define CMD_NVMEMWR 0xD0 // NV Memory Write +#define CMD_NVMEMPK 0xD1 // NV Memory Protection Key +#define CMD_NVMEMSR 0xD2 // NV Memory Status Read +#define CMD_READID4 0xD3 // Read ID4 + +#define CMD_RDID1 0xDA // Read ID1 +#define CMD_RDID2 0xDB // Read ID2 +#define CMD_RDID3 0xDC // Read ID3 + +#define CMD_GMCTRP1 0xE0 // Positive Gamma Correction +#define CMD_GMCTRN1 0xE1 // Negative Gamma Correction +#define CMD_DGCTRL1 0xE2 // Digital Gamma Control 1 +#define CMD_DGCTRL2 0xE3 // Digital Gamma Control 2 +#define CMD_DRVTMCA 0xE8 // Driver timing control A +#define CMD_DRVTMCB 0xEA // Driver timing control B +#define CMD_PWONSC 0xED // Power on sequence control + +#define CMD_EN3G 0xF2 // Enable 3 gamma control +#define CMD_INTCTRL 0xF6 // Interface Control +#define CMD_PUMPRC 0xF7 // Pump ratio control + +// Memory Access Control register bits definitions + +#define MADCTL_MY 0x80 // Row Address Order +#define MADCTL_MX 0x40 // Column Address Order +#define MADCTL_MV 0x20 // Row / Column Exchange +#define MADCTL_ML 0x10 // Vertical Refresh Order +#define MADCTL_BGR 0x08 // BGR Order +#define MADCTL_RGB 0x00 // RGB Order (No BGR bit) +#define MADCTL_MH 0x04 // Horizontal Refresh ORDER + +// ***************************************************************************** +// *** Constructor ********************************************************* +// ***************************************************************************** +ILI9341::ILI9341(SPI_HandleTypeDef* in_hspi) : hspi(in_hspi) {}; + +// ***************************************************************************** +// *** Write byte to SPI *************************************************** +// ***************************************************************************** +inline void ILI9341::SpiWrite(uint8_t c) +{ + HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET); // Pull down CS + HAL_SPI_Transmit(hspi, &c, sizeof(c), 1U); + HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET); // Pull up CS +} + +// ***************************************************************************** +// *** Write byte stream to SPI ******************************************** +// ***************************************************************************** +void ILI9341::SpiWriteStream(uint8_t* data, uint32_t n) +{ + HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET); // Pull down CS + HAL_SPI_Transmit_DMA(hspi, data, n); +} + +// ***************************************************************************** +// *** Write command to SPI ************************************************ +// ***************************************************************************** +inline void ILI9341::WriteCommand(uint8_t c) +{ + HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_RESET); // Command + SpiWrite(c); +} + +// ***************************************************************************** +// *** Write data to SPI *************************************************** +// ***************************************************************************** +inline void ILI9341::WriteData(uint8_t c) +{ + HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET); // Data + SpiWrite(c); +} + +// ***************************************************************************** +// *** Write data steram to SPI ******************************************** +// ***************************************************************************** +void ILI9341::WriteDataStream(uint8_t* data, uint32_t n) +{ + // Data + HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET); + // Pull down CS + HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET); + // Send data to screen + HAL_SPI_Transmit_DMA(hspi, data, n); +} + +// ***************************************************************************** +// *** Check SPI transfer status ******************************************* +// ***************************************************************************** +bool ILI9341::IsTransferComplete(void) +{ + return (hspi->State != HAL_SPI_STATE_BUSY_TX); +// return (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == SET); +} + +// ***************************************************************************** +// *** Pull up CS line for LCD ********************************************** +// ***************************************************************************** +void ILI9341::StopTransfer(void) +{ + // Pull up CS + HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET); +} + +// ***************************************************************************** +// *** Init screen ********************************************************* +// ***************************************************************************** +void ILI9341::Init(void) +{ +// // Reset sequence. Used only if GPIO pin used as LCD reset. +// HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_SET); +// HAL_Delay(5); +// HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_RESET); +// HAL_Delay(20); +// HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_SET); +// HAL_Delay(150); + + // Exit Sleep + WriteCommand(CMD_SWRESET); + // Delay for execute previous command + HAL_Delay(100U); + + // Power control + WriteCommand(CMD_PWCTR1); + WriteData(0x23); // VRH[5:0] // 25 + + // Power control + WriteCommand(CMD_PWCTR2); + WriteData(0x10); // SAP[2:0]; BT[3:0] // 11 + + // VCM control 1 + WriteCommand(CMD_VMCTR1); + WriteData(0x2B); + WriteData(0x2B); + + // VCM control 2 + WriteCommand(CMD_VMCTR2); + WriteData(0xC0); + + // Pixel Format Set + WriteCommand(CMD_PIXFMT); + WriteData(0x55); + + // Frame Control (In Normal Mode) + WriteCommand(CMD_FRMCTR1); + WriteData(0x00); + WriteData(0x18); + + // Power control A + WriteCommand(CMD_PWCTRA); + WriteData(0x39); + WriteData(0x2C); + WriteData(0x00); + WriteData(0x34); + WriteData(0x02); + + // Power control B + WriteCommand(CMD_PWCTRB); + WriteData(0x00); + WriteData(0XC1); + WriteData(0X30); + + // Power on sequence control + WriteCommand(CMD_PWONSC); + WriteData(0x64); + WriteData(0x03); + WriteData(0X12); + WriteData(0X81); + + // Driver timing control A + WriteCommand(CMD_DRVTMCA); + WriteData(0x85); + WriteData(0x00); + WriteData(0x78); + + // Driver timing control B + WriteCommand(CMD_DRVTMCB); + WriteData(0x00); + WriteData(0x00); + + // Pump ratio control + WriteCommand(CMD_PUMPRC); + WriteData(0x20); + + // Memory Access Control + WriteCommand(CMD_MADCTL); + WriteData(0x48); + + // Display Function Control + WriteCommand(CMD_DFUNCTR); + WriteData(0x08); + WriteData(0x82); + WriteData(0x27); + + // Enable 3 gamma control - Disable 3 Gamma Function + WriteCommand(CMD_EN3G); + WriteData(0x00); + + // Gamma Set - Gamma curve selected + WriteCommand(CMD_GAMMASET); + WriteData(0x01); + + // Positive Gamma Correction + WriteCommand(CMD_GMCTRP1); + WriteData(0x0F); + WriteData(0x31); + WriteData(0x2B); + WriteData(0x0C); + WriteData(0x0E); + WriteData(0x08); + WriteData(0x4E); + WriteData(0xF1); + WriteData(0x37); + WriteData(0x07); + WriteData(0x10); + WriteData(0x03); + WriteData(0x0E); + WriteData(0x09); + WriteData(0x00); + + // Negative Gamma Correction + WriteCommand(CMD_GMCTRN1); + WriteData(0x00); + WriteData(0x0E); + WriteData(0x14); + WriteData(0x03); + WriteData(0x11); + WriteData(0x07); + WriteData(0x31); + WriteData(0xC1); + WriteData(0x48); + WriteData(0x08); + WriteData(0x0F); + WriteData(0x0C); + WriteData(0x31); + WriteData(0x36); + WriteData(0x0F); + + // Interface Control + WriteCommand(CMD_INTCTRL); + WriteData(0x01); + WriteData(0x00); + WriteData(0x01 << 5); + + // Exit Sleep + WriteCommand(CMD_SLPOUT); + // Delay for execute previous command + HAL_Delay(120U); + // Display on + WriteCommand(CMD_DISPON); +} + +// ***************************************************************************** +// *** Set output window *************************************************** +// ***************************************************************************** +void ILI9341::SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) +{ + WriteCommand(CMD_CASET); // Column address set + WriteData(x0 >> 8); + WriteData(x0 & 0xFF); // XSTART + WriteData(x1 >> 8); + WriteData(x1 & 0xFF); // XEND + + WriteCommand(CMD_PASET); // Row address set + WriteData(y0 >> 8); + WriteData(y0); // YSTART + WriteData(y1 >> 8); + WriteData(y1); // YEND + + WriteCommand(CMD_RAMWR); // write to RAM + + // Prepare for write data + HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET); // Data +} + +// ***************************************************************************** +// *** Pass 8-bit (each) R,G,B, get back 16-bit packed color *************** +// ***************************************************************************** +uint16_t ILI9341::GetColor565(uint8_t r, uint8_t g, uint8_t b) +{ + return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); +} + +// ***************************************************************************** +// *** Set screen orientation ********************************************** +// ***************************************************************************** +void ILI9341::SetRotation(uint8_t m) +{ + WriteCommand(CMD_MADCTL); + rotation = m % 4; // can't be higher than 3 + switch (rotation) + { + case 0: + WriteData(MADCTL_BGR); + width = TFT_HEIGHT; + height = TFT_WIDTH; + break; + + case 1: + WriteData(MADCTL_MV | MADCTL_BGR); + width = TFT_WIDTH; + height = TFT_HEIGHT; + break; + + case 2: // Y: up -> down + WriteData(MADCTL_MX | MADCTL_MY | MADCTL_BGR); + width = TFT_HEIGHT; + height = TFT_WIDTH; + break; + + case 3: // X: left -> right + WriteData(MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR); + width = TFT_WIDTH; + height = TFT_HEIGHT; + break; + + default: + break; + } +} + +// ***************************************************************************** +// *** Write color to screen *********************************************** +// ***************************************************************************** +void ILI9341::PushColor(uint16_t color) +{ + HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET); // Data + + SpiWrite(color >> 8); + SpiWrite(color); +} + +// ***************************************************************************** +// *** Draw one pixel on screen ******************************************* +// ***************************************************************************** +void ILI9341::DrawPixel(int16_t x, int16_t y, uint16_t color) +{ + if((x < 0) ||(x >= width) || (y < 0) || (y >= height)) return; + + SetAddrWindow(x,y,x+1,y+1); + + HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET); // Data + + SpiWrite(color >> 8); + SpiWrite(color); +} + +// ***************************************************************************** +// *** Draw vertical line ************************************************** +// ***************************************************************************** +void ILI9341::DrawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) +{ + // Rudimentary clipping + if((x >= width) || (y >= height)) return; + + if((y+h-1) >= height) h = height-y; + + SetAddrWindow(x, y, x, y+h-1); + + uint8_t hi = color >> 8, lo = color; + + HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET); // Data + + while (h--) + { + SpiWrite(hi); + SpiWrite(lo); + } +} + +// ***************************************************************************** +// *** Draw horizontal line ************************************************ +// ***************************************************************************** +void ILI9341::DrawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) +{ + if((x >= width) || (y >= height)) return; + if((x+w-1) >= width) w = width-x; + + SetAddrWindow(x, y, x+w-1, y); + + uint8_t hi = color >> 8, lo = color; + + HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET); // Data + + while (w--) + { + SpiWrite(hi); + SpiWrite(lo); + } +} + +// ***************************************************************************** +// *** Fill full screen **************************************************** +// ***************************************************************************** +void ILI9341::FillScreen(uint16_t color) +{ + FillRect(0, 0, width, height, color); +} + +// ***************************************************************************** +// *** Fill rectangle on screen ******************************************** +// ***************************************************************************** +void ILI9341::FillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) +{ + if((x >= width) || (y >= height)) return; + if((x + w - 1) >= width) w = width - x; + if((y + h - 1) >= height) h = height - y; + + SetAddrWindow(x, y, x+w-1, y+h-1); + + uint8_t hi = color >> 8, lo = color; + + HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET); // Data + + HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET); // Pull down CS + for(y=h; y>0; y--) + { + for(x=w; x>0; x--) + { + // Wait until TXE flag is set to send data + while(__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == RESET); + hspi->Instance->DR = hi; + while(__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == RESET); + hspi->Instance->DR = lo; + } + } + HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET); // Pull up CS +} + +// ***************************************************************************** +// *** Invert display ****************************************************** +// ***************************************************************************** +void ILI9341::InvertDisplay(bool invert) +{ + WriteCommand(invert ? CMD_INVON : CMD_INVOFF); +} + +// ***************************************************************************** +// *** Read data from SPI ************************************************** +// ***************************************************************************** +inline uint8_t ILI9341::SpiRead(void) +{ + // Result variable + uint8_t r = 0; + // Pull down CS + HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET); + // Receive data + HAL_SPI_Receive(hspi, &r, sizeof(r), 100U); + // Pull up CS + HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET); + // Return result + return r; +} + +// ***************************************************************************** +// *** Read data from display ********************************************** +// ***************************************************************************** +inline uint8_t ILI9341::ReadData(void) +{ + // Data + HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET); // Data + // Receive data + uint8_t r = SpiRead(); + // Return result + return r; +} + +// ***************************************************************************** +// *** Send read command ad read result ************************************ +// ***************************************************************************** +uint8_t ILI9341::ReadCommand(uint8_t c) +{ + // Set command mode + HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_RESET); // Command + SpiWrite(c); + + // Set data mode + HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET); // Data + // Receive data + uint8_t r = SpiRead(); + + // Return result + return r; +} diff --git a/Display/ILI9341.h b/Display/ILI9341.h new file mode 100644 index 0000000..15712c1 --- /dev/null +++ b/Display/ILI9341.h @@ -0,0 +1,258 @@ +//****************************************************************************** +// @file ILI9341.h +// @author Nicolai Shlapunov +// +// @details DevCore: ILI9341 Low Level Driver Class, header +// +// @section LICENSE +// +// Software License Agreement (BSD License) +// +// Copyright (c) 2016, Devtronic & Nicolai Shlapunov +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// 3. Neither the name of the Devtronic nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL DEVTRONIC BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//****************************************************************************** + +#ifndef ILI9341_h +#define ILI9341_h + +// ***************************************************************************** +// *** Includes ************************************************************ +// ***************************************************************************** +#include + +// ***************************************************************************** +// *** Enums *************************************************************** +// ***************************************************************************** + +// Color definitions +enum Color +{ + COLOR_BLACK = 0x0000, // 0, 0, 0 + COLOR_VERYDARKGREY = 0xEF7B, // 32, 32, 32 + COLOR_DARKGREY = 0xEF7B, // 64, 64, 64 + COLOR_GREY = 0xEF7B, // 128, 128, 128 + COLOR_LIGHTGREY = 0x18C6, // 192, 192, 192 + COLOR_WHITE = 0xFFFF, // 255, 255, 255 + + COLOR_VERYDARKRED = 0x0018, // 32, 0, 0 + COLOR_DARKRED = 0x0038, // 64, 0, 0 + COLOR_MEDIUMRED = 0x0078, // 128, 0, 0 + COLOR_LIGHTRED = 0x00B8, // 192, 0, 0 + COLOR_RED = 0x00F8, // 255, 0, 0 + + COLOR_VERYDARKGREEN = 0xE000, // 0, 32, 0 + COLOR_DARKGREEN = 0xE001, // 0, 64, 0 + COLOR_MEDIUMGREEN = 0xE003, // 0, 128, 0 + COLOR_LIGHTGREEN = 0xE005, // 0, 192, 0 + COLOR_GREEN = 0xE007, // 0, 255, 0 + + COLOR_VERYDARKBLUE = 0x0300, // 0, 0, 32 + COLOR_DARKBLUE = 0x0700, // 0, 0, 64 + COLOR_MEDIUMBLUE = 0x0F00, // 0, 0, 128 + COLOR_LIGHTBLUE = 0x1700, // 0, 0, 192 + COLOR_BLUE = 0x1F00, // 0, 0, 255 + + COLOR_VERYDARKYELLOW = 0xE018, // 32, 32, 0 + COLOR_DARKYELLOW = 0xE039, // 64, 64, 0 + COLOR_MEDIUMYELLOW = 0xE07B, // 128, 128, 0 + COLOR_LIGHTYELLOW = 0xE0BD, // 192, 192, 0 + COLOR_YELLOW = 0xE0FF, // 255, 255, 0 + + COLOR_VERYDARKCYAN = 0xE300, // 0, 32, 32 + COLOR_DARKCYAN = 0xE701, // 0, 64, 64 + COLOR_MEDIUMCYAN = 0xEF03, // 0, 128, 128 + COLOR_LIGHTCYAN = 0xF705, // 0, 192, 192 + COLOR_CYAN = 0xFF07, // 0, 255, 255 + + COLOR_VERYDARKMAGENTA = 0x0318, // 32, 0, 32 + COLOR_DARKMAGENTA = 0x0738, // 64, 0, 64 + COLOR_MEDIUMMAGENTA = 0x0F78, // 128, 0, 128 + COLOR_LIGHTMAGENTA = 0x17B8, // 192, 0, 192 + COLOR_MAGENTA = 0x1FF8, // 255, 0, 255 +}; + +class ILI9341 +{ + public: + // ************************************************************************* + // *** Constructor ***************************************************** + // ************************************************************************* + ILI9341(SPI_HandleTypeDef* in_hspi); + + // ************************************************************************* + // *** Write byte to SPI *********************************************** + // ************************************************************************* + inline void SpiWrite(uint8_t c); + + // ************************************************************************* + // *** Write byte stream to SPI **************************************** + // ************************************************************************* + void SpiWriteStream(uint8_t* data, uint32_t n); + + // ************************************************************************* + // *** Write command to SPI ******************************************** + // ************************************************************************* + inline void WriteCommand(uint8_t c); + + // ************************************************************************* + // *** Write data to SPI *********************************************** + // ************************************************************************* + inline void WriteData(uint8_t c); + + // ************************************************************************* + // *** Write data steram to SPI **************************************** + // ************************************************************************* + void WriteDataStream(uint8_t* data, uint32_t n); + + // ************************************************************************* + // *** Check SPI transfer status **************************************** + // ************************************************************************* + bool IsTransferComplete(void); + + // ************************************************************************* + // *** Pull up CS line for LCD ****************************************** + // ************************************************************************* + void StopTransfer(void); + + // ************************************************************************* + // *** Init screen ***************************************************** + // ************************************************************************* + void Init(void); + + // ************************************************************************* + // *** Set output window *********************************************** + // ************************************************************************* + void SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); + + // ************************************************************************* + // *** Pass 8-bit (each) R,G,B, get back 16-bit packed color *********** + // ************************************************************************* + uint16_t GetColor565(uint8_t r, uint8_t g, uint8_t b); + + // ************************************************************************* + // *** Set screen orientation ****************************************** + // ************************************************************************* + void SetRotation(uint8_t r); + + // ************************************************************************* + // *** Write color to screen ******************************************* + // ************************************************************************* + void PushColor(uint16_t color); + + // ************************************************************************* + // *** Draw one pixel on screen *************************************** + // ************************************************************************* + void DrawPixel(int16_t x, int16_t y, uint16_t color); + + // ************************************************************************* + // *** Draw vertical line ********************************************** + // ************************************************************************* + void DrawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + + // ************************************************************************* + // *** Draw horizontal line ******************************************** + // ************************************************************************* + void DrawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + + // ************************************************************************* + // *** Fill full screen ************************************************ + // ************************************************************************* + void FillScreen(uint16_t color); + + // ************************************************************************* + // *** Fill rectangle on screen **************************************** + // ************************************************************************* + void FillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + + // ************************************************************************* + // *** Invert display ************************************************** + // ************************************************************************* + void InvertDisplay(bool invert); + + // ************************************************************************* + // *** Read data from SPI ********************************************** + // ************************************************************************* + inline uint8_t SpiRead(void); + + // ************************************************************************* + // *** Read data from display ****************************************** + // ************************************************************************* + inline uint8_t ReadData(void); + + // ************************************************************************* + // *** Send read command ad read result ******************************** + // ************************************************************************* + uint8_t ReadCommand(uint8_t c); + + // ************************************************************************* + // *** Return screen width ********************************************* + // ************************************************************************* + inline int32_t GetWidth(void) {return width;} + + // ************************************************************************* + // *** Return screen height ******************************************** + // ************************************************************************* + inline int32_t GetHeight(void) {return height;} + + // ************************************************************************* + // *** Return byte(s) per pixel **************************************** + // ************************************************************************* + inline int32_t GetBytesPerPixel(void) {return byte_per_pixel;} + + // ************************************************************************* + // *** Return max line ************************************************* + // ************************************************************************* + static constexpr int32_t GetMaxLine(void) {return TFT_WIDTH > TFT_HEIGHT ? TFT_WIDTH : TFT_HEIGHT;} + + // ************************************************************************* + // *** Return max line ************************************************* + // ************************************************************************* + static constexpr int32_t GetMaxBpp(void) {return TFT_BPP;} + + private: + + // Display width + static const int32_t TFT_WIDTH = 320; + // Display height + static const int32_t TFT_HEIGHT = 240; + // Display byte per pixel + static const int32_t TFT_BPP = 2; + + // Handle to screen SPI + SPI_HandleTypeDef* hspi = nullptr; + + // Width + int32_t width = TFT_WIDTH; + // Height + int32_t height = TFT_HEIGHT; + // Byte(s) per pixel + int32_t byte_per_pixel = TFT_BPP; + + // Rotation + uint32_t rotation = 0U; +}; + +#endif diff --git a/Display/Image.cpp b/Display/Image.cpp new file mode 100644 index 0000000..cc17e54 --- /dev/null +++ b/Display/Image.cpp @@ -0,0 +1,366 @@ +//****************************************************************************** +// @file Image.cpp +// @author Nicolai Shlapunov +// +// @details DevCore: Image Visual Object Class, implementation +// +// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov +// All rights reserved. +// +// @section SUPPORT +// +// Devtronic invests time and resources providing this open source code, +// please support Devtronic and open-source hardware/software by +// donations and/or purchasing products from Devtronic. +// +//****************************************************************************** + +// ***************************************************************************** +// *** Includes ************************************************************ +// ***************************************************************************** +#include "Image.h" + +// ***************************************************************************** +// ***************************************************************************** +// *** Image *************************************************************** +// ***************************************************************************** +// ***************************************************************************** + +// ***************************************************************************** +// *** Constructor ********************************************************* +// ***************************************************************************** +Image::Image(int32_t x, int32_t y, const ImageDesc& img_dsc) : img_description(img_dsc) +{ + x_start = x; + y_start = y; + width = img_dsc.width; + height = img_dsc.height; + x_end = x + width - 1; + y_end = y + height - 1; + bits_per_pixel = img_dsc.bits_per_pixel; + img = img_dsc.img; + palette = img_dsc.palette; + transparent_color = img_dsc.transparent_color; + hor_mirror = false; +} + +// ***************************************************************************** +// *** Put line in buffer ************************************************** +// ***************************************************************************** +void Image::DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t start_x) +{ + // Draw only if needed + if((line >= y_start) && (line <= y_end)) + { + // Find idx in the image buffer + uint32_t idx = (line - y_start) * width; + // Find start x position + int32_t start = x_start - start_x; + // Prevent write in memory before buffer + if(start < 0) + { + // Minus minus - plus + idx -= start; + start = 0; + } + // Find start x position + int32_t end = x_end - start_x; + // Prevent buffer overflow + if(end >= n) end = n - 1; + // Delta for cycle increment/decrement + int32_t delta = 1; + // Flip horizontally if needed + if(hor_mirror) + { + idx += end - start; + // Set delta to minus one for decrement cycle + delta = -1; + } + // Draw image + if(bits_per_pixel == 16) + { + // Get pointer to 16-bit image data + uint16_t* p_img = (uint16_t*)img; + // Pixels data copy cycle + for(int32_t i = start; i <= end; i++) + { + // Get pixel data + uint16_t data = p_img[idx]; + // Change index + idx += delta; + // If not transparent - output to buffer + if(data != transparent_color) buf[i] = data; + } + } + else + { + // Get pointer to 8-bit image data + uint8_t* p_img = (uint8_t*)img; + // Pixels data copy cycle + for(int32_t i = start; i <= end; i++) + { + // Get pixel data + uint16_t data = palette[p_img[idx]]; + // Change index + idx += delta; + // If not transparent - output to buffer + if(data != transparent_color) buf[i] = data; + } + } + } +} + +// ***************************************************************************** +// *** Put line in buffer ************************************************** +// ***************************************************************************** +void Image::DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t start_y) +{ + // Draw only if needed + if((row >= x_start) && (row <= x_end)) + { + // Find start x position + int32_t start = y_start - start_y; + // Prevent write in memory before buffer + if(start < 0) start = 0; + // Find start x position + int32_t end = y_end - start_y; + // Prevent buffer overflow + if(end >= n) end = n - 1; + // Have sense draw only if end pointer in buffer + if(end > 0) + { + // Not implemented yet + } + } +} + +// ***************************************************************************** +// *** Set Image function ************************************************** +// ***************************************************************************** +void Image::SetImage(const ImageDesc& img_dsc, bool semaphore_taken) +{ + if(semaphore_taken == false) LockVisObject(); + width = img_dsc.width; + height = img_dsc.height; + x_end = x_start + width - 1; + y_end = y_start + height - 1; + bits_per_pixel = img_dsc.bits_per_pixel; + img = img_dsc.img; + palette = img_dsc.palette; + transparent_color = img_dsc.transparent_color; + if(semaphore_taken == false) UnlockVisObject(); +} + +// ***************************************************************************** +// ***************************************************************************** +// *** Image8 ************************************************************** +// ***************************************************************************** +// ***************************************************************************** + +// ***************************************************************************** +// *** Constructor ********************************************************* +// ***************************************************************************** +Image8::Image8(int32_t x, int32_t y, int32_t w, int32_t h, const uint8_t* p_img, const uint16_t* p_palette) +{ + x_start = x; + y_start = y; + x_end = x + w - 1; + y_end = y + h - 1; + width = w; + height = h; + img = p_img; + palette = p_palette; +} + +// ***************************************************************************** +// *** Put line in buffer ************************************************** +// ***************************************************************************** +void Image8::DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t start_x) +{ + // Draw only if needed + if((line >= y_start) && (line <= y_end)) + { + // Find start x position + int32_t start = x_start - start_x; + // Prevent write in memory before buffer + if(start < 0) start = 0; + // Find start x position + int32_t end = x_end - start_x; + // Prevent buffer overflow + if(end >= n) end = n - 1; + // Have sense draw only if end pointer in buffer + if(x_end > 0) + { + int idx = (line - y_start) * width; + for(int32_t i = start; i <= end; i++) + { + buf[i] = palette[img[idx++]]; + } + } + } +} + +// ***************************************************************************** +// *** Put line in buffer ************************************************** +// ***************************************************************************** +void Image8::DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t start_y) +{ + // Draw only if needed + if((row >= x_start) && (row <= x_end)) + { + // Find start x position + int32_t start = y_start - start_y; + // Prevent write in memory before buffer + if(start < 0) start = 0; + // Find start x position + int32_t end = y_end - start_y; + // Prevent buffer overflow + if(end >= n) end = n - 1; + // Have sense draw only if end pointer in buffer + if(end > 0) + { + // Not implemented yet + } + } +} + +// ***************************************************************************** +// ***************************************************************************** +// *** Image16 ************************************************************* +// ***************************************************************************** +// ***************************************************************************** + +// ***************************************************************************** +// *** Constructor ********************************************************* +// ***************************************************************************** +Image16::Image16(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t* p_img) +{ + x_start = x; + y_start = y; + x_end = x + w - 1; + y_end = y + h - 1; + width = w; + height = h; + img = p_img; +} + +// ***************************************************************************** +// *** Put line in buffer ************************************************** +// ***************************************************************************** +void Image16::DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t start_x) +{ + // Draw only if needed + if((line >= y_start) && (line <= y_end)) + { + // Find start x position + int32_t start = x_start - start_x; + // Prevent write in memory before buffer + if(start < 0) start = 0; + // Find start x position + int32_t end = x_end - start_x; + // Prevent buffer overflow + if(end >= n) end = n - 1; + // Have sense draw only if end pointer in buffer + if(x_end > 0) + { + int idx = (line - y_start) * width; + for(int32_t i = start; i <= end; i++) + { + buf[i] = img[idx++]; + } + } + } +} + +// ***************************************************************************** +// *** Put line in buffer ************************************************** +// ***************************************************************************** +void Image16::DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t start_y) +{ + // Draw only if needed + if((row >= x_start) && (row <= x_end)) + { + // Find start x position + int32_t start = y_start - start_y; + // Prevent write in memory before buffer + if(start < 0) start = 0; + // Find start x position + int32_t end = y_end - start_y; + // Prevent buffer overflow + if(end >= n) end = n - 1; + // Have sense draw only if end pointer in buffer + if(end > 0) + { + // Not implemented yet + } + } +} + +// ***************************************************************************** +// ***************************************************************************** +// *** Palettes ************************************************************ +// ***************************************************************************** +// ***************************************************************************** + +// ***************************************************************************** +// *** Palette with 8R-8G-4B levels (bits 3-3-2) *************************** +// ***************************************************************************** +const uint16_t PALETTE_884[256] = { +0x0000, 0x0020, 0x0040, 0x0068, 0x0088, 0x00B0, 0x00D0, 0x00F8, 0x0001, 0x0021, 0x0041, 0x0069, 0x0089, 0x00B1, 0x00D1, 0x00F9, +0x2002, 0x2022, 0x2042, 0x206A, 0x208A, 0x20B2, 0x20D2, 0x20FA, 0x4003, 0x4023, 0x4043, 0x406B, 0x408B, 0x40B3, 0x40D3, 0x40FB, +0x6004, 0x6024, 0x6044, 0x606C, 0x608C, 0x60B4, 0x60D4, 0x60FC, 0x8005, 0x8025, 0x8045, 0x806D, 0x808D, 0x80B5, 0x80D5, 0x80FD, +0xA006, 0xA026, 0xA046, 0xA06E, 0xA08E, 0xA0B6, 0xA0D6, 0xA0FE, 0xE007, 0xE027, 0xE047, 0xE06F, 0xE08F, 0xE0B7, 0xE0D7, 0xE0FF, +0x0A00, 0x0A20, 0x0A40, 0x0A68, 0x0A88, 0x0AB0, 0x0AD0, 0x0AF8, 0x0A01, 0x0A21, 0x0A41, 0x0A69, 0x0A89, 0x0AB1, 0x0AD1, 0x0AF9, +0x2A02, 0x2A22, 0x2A42, 0x2A6A, 0x2A8A, 0x2AB2, 0x2AD2, 0x2AFA, 0x4A03, 0x4A23, 0x4A43, 0x4A6B, 0x4A8B, 0x4AB3, 0x4AD3, 0x4AFB, +0x6A04, 0x6A24, 0x6A44, 0x6A6C, 0x6A8C, 0x6AB4, 0x6AD4, 0x6AFC, 0x8A05, 0x8A25, 0x8A45, 0x8A6D, 0x8A8D, 0x8AB5, 0x8AD5, 0x8AFD, +0xAA06, 0xAA26, 0xAA46, 0xAA6E, 0xAA8E, 0xAAB6, 0xAAD6, 0xAAFE, 0xEA07, 0xEA27, 0xEA47, 0xEA6F, 0xEA8F, 0xEAB7, 0xEAD7, 0xEAFF, +0x1400, 0x1420, 0x1440, 0x1468, 0x1488, 0x14B0, 0x14D0, 0x14F8, 0x1401, 0x1421, 0x1441, 0x1469, 0x1489, 0x14B1, 0x14D1, 0x14F9, +0x3402, 0x3422, 0x3442, 0x346A, 0x348A, 0x34B2, 0x34D2, 0x34FA, 0x5403, 0x5423, 0x5443, 0x546B, 0x548B, 0x54B3, 0x54D3, 0x54FB, +0x7404, 0x7424, 0x7444, 0x746C, 0x748C, 0x74B4, 0x74D4, 0x74FC, 0x9405, 0x9425, 0x9445, 0x946D, 0x948D, 0x94B5, 0x94D5, 0x94FD, +0xB406, 0xB426, 0xB446, 0xB46E, 0xB48E, 0xB4B6, 0xB4D6, 0xB4FE, 0xF407, 0xF427, 0xF447, 0xF46F, 0xF48F, 0xF4B7, 0xF4D7, 0xF4FF, +0x1F00, 0x1F20, 0x1F40, 0x1F68, 0x1F88, 0x1FB0, 0x1FD0, 0x1FF8, 0x1F01, 0x1F21, 0x1F41, 0x1F69, 0x1F89, 0x1FB1, 0x1FD1, 0x1FF9, +0x3F02, 0x3F22, 0x3F42, 0x3F6A, 0x3F8A, 0x3FB2, 0x3FD2, 0x3FFA, 0x5F03, 0x5F23, 0x5F43, 0x5F6B, 0x5F8B, 0x5FB3, 0x5FD3, 0x5FFB, +0x7F04, 0x7F24, 0x7F44, 0x7F6C, 0x7F8C, 0x7FB4, 0x7FD4, 0x7FFC, 0x9F05, 0x9F25, 0x9F45, 0x9F6D, 0x9F8D, 0x9FB5, 0x9FD5, 0x9FFD, +0xBF06, 0xBF26, 0xBF46, 0xBF6E, 0xBF8E, 0xBFB6, 0xBFD6, 0xBFFE, 0xFF07, 0xFF27, 0xFF47, 0xFF6F, 0xFF8F, 0xFFB7, 0xFFD7, 0xFFFF}; + +// ***************************************************************************** +// *** Palette with 7R-7G-5B levels (245 colors) *************************** +// ***************************************************************************** +const uint16_t PALETTE_775[256] = { +0x0000, 0x0028, 0x0050, 0x0078, 0x00A0, 0x00C8, 0x00F8, 0x4001, 0x4029, 0x4051, 0x4079, 0x40A1, 0x40C9, 0x40F9, 0xA002, 0xA02A, +0xA052, 0xA07A, 0xA0A2, 0xA0CA, 0xA0FA, 0xE003, 0xE02B, 0xE053, 0xE07B, 0xE0A3, 0xE0CB, 0xE0FB, 0x4005, 0x402D, 0x4055, 0x407D, +0x40A5, 0x40CD, 0x40FD, 0x8006, 0x802E, 0x8056, 0x807E, 0x80A6, 0x80CE, 0x80FE, 0xE007, 0xE02F, 0xE057, 0xE07F, 0xE0A7, 0xE0CF, +0xE0FF, 0x0700, 0x0728, 0x0750, 0x0778, 0x07A0, 0x07C8, 0x07F8, 0x4701, 0x4729, 0x4751, 0x4779, 0x47A1, 0x47C9, 0x47F9, 0xA702, +0xA72A, 0xA752, 0xA77A, 0xA7A2, 0xA7CA, 0xA7FA, 0xE703, 0xE72B, 0xE753, 0xE77B, 0xE7A3, 0xE7CB, 0xE7FB, 0x4705, 0x472D, 0x4755, +0x477D, 0x47A5, 0x47CD, 0x47FD, 0x8706, 0x872E, 0x8756, 0x877E, 0x87A6, 0x87CE, 0x87FE, 0xE707, 0xE72F, 0xE757, 0xE77F, 0xE7A7, +0xE7CF, 0xE7FF, 0x0F00, 0x0F28, 0x0F50, 0x0F78, 0x0FA0, 0x0FC8, 0x0FF8, 0x4F01, 0x4F29, 0x4F51, 0x4F79, 0x4FA1, 0x4FC9, 0x4FF9, +0xAF02, 0xAF2A, 0xAF52, 0xAF7A, 0xAFA2, 0xAFCA, 0xAFFA, 0xEF03, 0xEF2B, 0xEF53, 0xEF7B, 0xEFA3, 0xEFCB, 0xEFFB, 0x4F05, 0x4F2D, +0x4F55, 0x4F7D, 0x4FA5, 0x4FCD, 0x4FFD, 0x8F06, 0x8F2E, 0x8F56, 0x8F7E, 0x8FA6, 0x8FCE, 0x8FFE, 0xEF07, 0xEF2F, 0xEF57, 0xEF7F, +0xEFA7, 0xEFCF, 0xEFFF, 0x1700, 0x1728, 0x1750, 0x1778, 0x17A0, 0x17C8, 0x17F8, 0x5701, 0x5729, 0x5751, 0x5779, 0x57A1, 0x57C9, +0x57F9, 0xB702, 0xB72A, 0xB752, 0xB77A, 0xB7A2, 0xB7CA, 0xB7FA, 0xF703, 0xF72B, 0xF753, 0xF77B, 0xF7A3, 0xF7CB, 0xF7FB, 0x5705, +0x572D, 0x5755, 0x577D, 0x57A5, 0x57CD, 0x57FD, 0x9706, 0x972E, 0x9756, 0x977E, 0x97A6, 0x97CE, 0x97FE, 0xF707, 0xF72F, 0xF757, +0xF77F, 0xF7A7, 0xF7CF, 0xF7FF, 0x1F00, 0x1F28, 0x1F50, 0x1F78, 0x1FA0, 0x1FC8, 0x1FF8, 0x5F01, 0x5F29, 0x5F51, 0x5F79, 0x5FA1, +0x5FC9, 0x5FF9, 0xBF02, 0xBF2A, 0xBF52, 0xBF7A, 0xBFA2, 0xBFCA, 0xBFFA, 0xFF03, 0xFF2B, 0xFF53, 0xFF7B, 0xFFA3, 0xFFCB, 0xFFFB, +0x5F05, 0x5F2D, 0x5F55, 0x5F7D, 0x5FA5, 0x5FCD, 0x5FFD, 0x9F06, 0x9F2E, 0x9F56, 0x9F7E, 0x9FA6, 0x9FCE, 0x9FFE, 0xFF07, 0xFF2F, +0xFF57, 0xFF7F, 0xFFA7, 0xFFCF, 0xFFFF, 0x0000, 0x0028, 0x0050, 0x0078, 0x00A0, 0x00C8, 0x00F8, 0x4001, 0x4029, 0x4051, 0x4079}; + +// ***************************************************************************** +// *** Palette with 6R-7G-6B levels (252 colors) *************************** +// ***************************************************************************** +const uint16_t PALETTE_676[256] = { +0x0000, 0x0030, 0x0060, 0x0090, 0x00C0, 0x00F8, 0x4001, 0x4031, 0x4061, 0x4091, 0x40C1, 0x40F9, 0xA002, 0xA032, 0xA062, 0xA092, +0xA0C2, 0xA0FA, 0xE003, 0xE033, 0xE063, 0xE093, 0xE0C3, 0xE0FB, 0x4005, 0x4035, 0x4065, 0x4095, 0x40C5, 0x40FD, 0x8006, 0x8036, +0x8066, 0x8096, 0x80C6, 0x80FE, 0xE007, 0xE037, 0xE067, 0xE097, 0xE0C7, 0xE0FF, 0x0600, 0x0630, 0x0660, 0x0690, 0x06C0, 0x06F8, +0x4601, 0x4631, 0x4661, 0x4691, 0x46C1, 0x46F9, 0xA602, 0xA632, 0xA662, 0xA692, 0xA6C2, 0xA6FA, 0xE603, 0xE633, 0xE663, 0xE693, +0xE6C3, 0xE6FB, 0x4605, 0x4635, 0x4665, 0x4695, 0x46C5, 0x46FD, 0x8606, 0x8636, 0x8666, 0x8696, 0x86C6, 0x86FE, 0xE607, 0xE637, +0xE667, 0xE697, 0xE6C7, 0xE6FF, 0x0C00, 0x0C30, 0x0C60, 0x0C90, 0x0CC0, 0x0CF8, 0x4C01, 0x4C31, 0x4C61, 0x4C91, 0x4CC1, 0x4CF9, +0xAC02, 0xAC32, 0xAC62, 0xAC92, 0xACC2, 0xACFA, 0xEC03, 0xEC33, 0xEC63, 0xEC93, 0xECC3, 0xECFB, 0x4C05, 0x4C35, 0x4C65, 0x4C95, +0x4CC5, 0x4CFD, 0x8C06, 0x8C36, 0x8C66, 0x8C96, 0x8CC6, 0x8CFE, 0xEC07, 0xEC37, 0xEC67, 0xEC97, 0xECC7, 0xECFF, 0x1200, 0x1230, +0x1260, 0x1290, 0x12C0, 0x12F8, 0x5201, 0x5231, 0x5261, 0x5291, 0x52C1, 0x52F9, 0xB202, 0xB232, 0xB262, 0xB292, 0xB2C2, 0xB2FA, +0xF203, 0xF233, 0xF263, 0xF293, 0xF2C3, 0xF2FB, 0x5205, 0x5235, 0x5265, 0x5295, 0x52C5, 0x52FD, 0x9206, 0x9236, 0x9266, 0x9296, +0x92C6, 0x92FE, 0xF207, 0xF237, 0xF267, 0xF297, 0xF2C7, 0xF2FF, 0x1800, 0x1830, 0x1860, 0x1890, 0x18C0, 0x18F8, 0x5801, 0x5831, +0x5861, 0x5891, 0x58C1, 0x58F9, 0xB802, 0xB832, 0xB862, 0xB892, 0xB8C2, 0xB8FA, 0xF803, 0xF833, 0xF863, 0xF893, 0xF8C3, 0xF8FB, +0x5805, 0x5835, 0x5865, 0x5895, 0x58C5, 0x58FD, 0x9806, 0x9836, 0x9866, 0x9896, 0x98C6, 0x98FE, 0xF807, 0xF837, 0xF867, 0xF897, +0xF8C7, 0xF8FF, 0x1F00, 0x1F30, 0x1F60, 0x1F90, 0x1FC0, 0x1FF8, 0x5F01, 0x5F31, 0x5F61, 0x5F91, 0x5FC1, 0x5FF9, 0xBF02, 0xBF32, +0xBF62, 0xBF92, 0xBFC2, 0xBFFA, 0xFF03, 0xFF33, 0xFF63, 0xFF93, 0xFFC3, 0xFFFB, 0x5F05, 0x5F35, 0x5F65, 0x5F95, 0x5FC5, 0x5FFD, +0x9F06, 0x9F36, 0x9F66, 0x9F96, 0x9FC6, 0x9FFE, 0xFF07, 0xFF37, 0xFF67, 0xFF97, 0xFFC7, 0xFFFF, 0x0000, 0x0030, 0x0060, 0x0090}; diff --git a/Display/Image.h b/Display/Image.h new file mode 100644 index 0000000..57061bd --- /dev/null +++ b/Display/Image.h @@ -0,0 +1,178 @@ +//****************************************************************************** +// @file Image.h +// @author Nicolai Shlapunov +// +// @details DevCore: Image Visual Object Class, header +// +// @section LICENSE +// +// Software License Agreement (BSD License) +// +// Copyright (c) 2016, Devtronic & Nicolai Shlapunov +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// 3. Neither the name of the Devtronic nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL DEVTRONIC BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//****************************************************************************** + +#ifndef Images_h +#define Images_h + +// ***************************************************************************** +// *** Includes ************************************************************ +// ***************************************************************************** +#include "DevCfg.h" +#include "VisObject.h" + +// ***************************************************************************** +// *** Palettes external *************************************************** +// ***************************************************************************** +extern const uint16_t PALETTE_884[256]; +extern const uint16_t PALETTE_775[256]; +extern const uint16_t PALETTE_676[256]; + +// ***************************************************************************** +// *** Image description structure ***************************************** +// ***************************************************************************** +typedef struct typeImageDesc +{ + // Image width + uint16_t width; + // Image height + uint16_t height; + // Bits per pixel + uint8_t bits_per_pixel; + // Pointer to image data + union + { + const uint8_t* img8; + const uint16_t* img16; + const void* img; + }; + // Pointer to palette + const uint16_t* palette; + // Transparent color (-1 no transparent colors) + int32_t transparent_color; +} ImageDesc; + +// ***************************************************************************** +// *** Universal Image Class *********************************************** +// ***************************************************************************** +class Image : public VisObject +{ + public: + // ************************************************************************* + // *** Constructor ***************************************************** + // ************************************************************************* + Image(int32_t x, int32_t y, const ImageDesc& img_dsc); + + // ************************************************************************* + // *** Put line in buffer ********************************************** + // ************************************************************************* + virtual void DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t y = 0); + + // ************************************************************************* + // *** Put line in buffer ********************************************** + // ************************************************************************* + virtual void DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t x = 0); + + // ************************************************************************* + // *** Set Horizontal Flip function ************************************ + // ************************************************************************* + void SetHorizontalFlip(bool flip) {hor_mirror = flip;} + + // ************************************************************************* + // *** Set Image function ********************************************** + // ************************************************************************* + void SetImage(const ImageDesc& img_dsc, bool semaphore_taken = false); + + protected: + // Reference to image description structure + const ImageDesc& img_description; + // Bits per pixel + uint8_t bits_per_pixel; + // Pointer to the image + const void* img; + // Pointer to the palette + const uint16_t* palette; + // Transparent color (-1 no transparent colors) + int32_t transparent_color; + // Horizontal mirror + bool hor_mirror; +}; + +// ***************************************************************************** +// *** Image 8-bit Class *************************************************** +// ***************************************************************************** +class Image8 : public VisObject +{ + public: + // ************************************************************************* + // *** Constructor ***************************************************** + // ************************************************************************* + Image8(int32_t x, int32_t y, int32_t w, int32_t h, const uint8_t* p_img, const uint16_t* p_palette); + + // ************************************************************************* + // *** Put line in buffer ********************************************** + // ************************************************************************* + virtual void DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t y = 0); + + // ************************************************************************* + // *** Put line in buffer ********************************************** + // ************************************************************************* + virtual void DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t x = 0); + + private: + // Pointer to the image + const uint8_t* img; + // Pointer to the palette + const uint16_t* palette; +}; + +// ***************************************************************************** +// *** Image 16-bit Class *************************************************** +// ***************************************************************************** +class Image16 : public VisObject +{ + public: + // ************************************************************************* + // *** Constructor ***************************************************** + // ************************************************************************* + Image16(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t* p_img); + + // ************************************************************************* + // *** Put line in buffer ********************************************** + // ************************************************************************* + virtual void DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t y = 0); + + // ************************************************************************* + // *** Put line in buffer ********************************************** + // ************************************************************************* + virtual void DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t x = 0); + + private: + // Pointer to the image + const uint16_t* img; +}; + +#endif diff --git a/Display/Primitives.cpp b/Display/Primitives.cpp new file mode 100644 index 0000000..2b7ad57 --- /dev/null +++ b/Display/Primitives.cpp @@ -0,0 +1,326 @@ +//****************************************************************************** +// @file Primitives.cpp +// @author Nicolai Shlapunov +// +// @details DevCore: Primitives Visual Object Classes(Box, Line, Circle), implementation +// +// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov +// All rights reserved. +// +// @section SUPPORT +// +// Devtronic invests time and resources providing this open source code, +// please support Devtronic and open-source hardware/software by +// donations and/or purchasing products from Devtronic. +// +//****************************************************************************** + +// ***************************************************************************** +// *** Includes ************************************************************ +// ***************************************************************************** +#include "Primitives.h" + +#include // for abs() + +// ***************************************************************************** +// ***************************************************************************** +// *** Box ***************************************************************** +// ***************************************************************************** +// ***************************************************************************** + +// ***************************************************************************** +// *** Constructor ********************************************************* +// ***************************************************************************** +Box::Box(int32_t x, int32_t y, int32_t w, int32_t h, int32_t c, bool is_fill) +{ + SetParams(x, y, w, h, c, is_fill); +} + +// ***************************************************************************** +// *** SetParams *********************************************************** +// ***************************************************************************** +void Box::SetParams(int32_t x, int32_t y, int32_t w, int32_t h, int32_t c, bool is_fill) +{ + color = c; + x_start = x; + y_start = y; + x_end = x + w - 1; + y_end = y + h - 1; + width = w; + height = h; + rotation = 0; + fill = is_fill; +} + +// ***************************************************************************** +// *** Put line in buffer ************************************************** +// ***************************************************************************** +void Box::DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t start_x) +{ + // Draw only if needed + if((line >= y_start) && (line <= y_end)) + { + // Find start x position + int32_t start = x_start - start_x; + // Prevent write in memory before buffer + if(start < 0) start = 0; + // Find start x position + int32_t end = x_end - start_x; + // Prevent buffer overflow + if(end >= n) end = n - 1; + // Have sense draw only if end pointer in buffer + if(end > 0) + { + // If fill or first/last line - must be solid + if(fill || line == y_start || line == y_end) + { + for(int32_t i = start; i <= end; i++) buf[i] = color; + } + else + { + if(x_start - start_x >= 0) buf[start] = color; + if(x_end - start_x < n) buf[end] = color; + } + } + } +} + +// ***************************************************************************** +// *** Put line in buffer ************************************************** +// ***************************************************************************** +void Box::DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t start_y) +{ + // Draw only if needed + if((row >= x_start) && (row <= x_end)) + { + // Find start x position + int32_t start = y_start - start_y; + // Prevent write in memory before buffer + if(start < 0) start = 0; + // Find start x position + int32_t end = y_end - start_y; + // Prevent buffer overflow + if(end >= n) end = n - 1; + // Have sense draw only if end pointer in buffer + if(end > 0) + { + // If fill or first/last row - must be solid + if(fill || row == x_start || row == x_end) + { + for(int32_t i = start; i <= end; i++) buf[i] = color; + } + else + { + if(y_start - start_y >= 0) buf[start] = color; + if(y_end - start_y < n) buf[end] = color; + } + } + } +} + +// ***************************************************************************** +// ***************************************************************************** +// *** Line **************************************************************** +// ***************************************************************************** +// ***************************************************************************** + +// ***************************************************************************** +// *** Constructor ********************************************************* +// ***************************************************************************** +Line::Line(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t c) +{ + SetParams(x1, y1, x2, y2, c); +} + +// ***************************************************************************** +// *** SetParams *********************************************************** +// ***************************************************************************** +void Line::SetParams(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t c) +{ + color = c; + x_start = x1; + y_start = y1; + x_end = x2; + y_end = y2; + width = (x1 < x2) ? (x2 - x1) : (x1 - x2); + height = (y1 < y2) ? (y2 - y1) : (y1 - y2); + rotation = 0; +} + +// ***************************************************************************** +// *** Put line in buffer ************************************************** +// ***************************************************************************** +void Line::DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t start_x) +{ + // Draw only if needed + if((line >= y_start) && (line <= y_end)) + { + const int32_t deltaX = abs(x_end - x_start); + const int32_t deltaY = abs(y_end - y_start); + const int32_t signX = x_start < x_end ? 1 : -1; + const int32_t signY = y_start < y_end ? 1 : -1; + + int32_t error = deltaX - deltaY; + + int32_t x = x_start - start_x; + int32_t y = y_start; + + int32_t end_x = x_end - start_x; + while((x != end_x || y != y_end) && (y != line)) + { + const int32_t error2 = error * 2; + if(error2 > -deltaY) + { + error -= deltaY; + x += signX; + } + if(error2 < deltaX) + { + error += deltaX; + y += signY; + } + } + + while((x != end_x || y != y_end) && (y == line)) + { + if((x >= 0) && (x < n)) buf[x] = color; + const int32_t error2 = error * 2; + if(error2 > -deltaY) + { + error -= deltaY; + x += signX; + } + if(error2 < deltaX) + { + break; + } + } + } +} + +// ***************************************************************************** +// *** Put line in buffer ************************************************** +// ***************************************************************************** +void Line::DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t start_y) +{ + // FIX ME: implement for Vertical Update Mode too +} + +// ***************************************************************************** +// ***************************************************************************** +// *** Circle ************************************************************** +// ***************************************************************************** +// ***************************************************************************** + +// ***************************************************************************** +// *** Constructor ********************************************************* +// ***************************************************************************** +Circle::Circle(int32_t x, int32_t y, int32_t r, int32_t c, bool is_fill) +{ + SetParams(x, y, r, c, is_fill); +} + +// ***************************************************************************** +// *** SetParams *********************************************************** +// ***************************************************************************** +void Circle::SetParams(int32_t x, int32_t y, int32_t r, int32_t c, bool is_fill) +{ + color = c; + radius = r; + x_start = x - r; + y_start = y - r; + x_end = x + r; + y_end = y + r; + width = r*2; + height = r*2; + rotation = 0; + fill = is_fill; +} + +// ***************************************************************************** +// *** Put line in buffer ************************************************** +// ***************************************************************************** +void Circle::DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t start_x) +{ + // Draw only if needed + if((line >= y_start) && (line <= y_end)) + { + int32_t x = 0; + int32_t y = radius; + int32_t x0 = x_start + radius - start_x; + int32_t y0 = y_start + radius; + int32_t delta = 1 - 2 * radius; + int32_t error = 0; + bool line_drawed = false; + + while(y >= 0) + { + if( (y0 + y == line) || (y0 - y == line) ) + { + if(fill) + { + int32_t i = x0 - x; + if(i < 0) i = 0; + if(x0 + x < n) n = x0 + x; + for(;i < n; i++) + { + buf[i] = color; + } + break; + } + else + { + int32_t xl = x0 - x; + int32_t xr = x0 + x; + if((xl > 0) && (xl < n)) buf[xl] = color; + if((xr > 0) && (xr < n)) buf[xr] = color; + } + line_drawed = true; + } + else + { + if(line_drawed == true) break; + } + error = 2 * (delta + y) - 1; + if(delta < 0 && error <= 0) + { + ++x; + delta += 2 * x + 1; + continue; + } + error = 2 * (delta - x) - 1; + if(delta > 0 && error > 0) + { + --y; + delta += 1 - 2 * y; + continue; + } + ++x; + delta += 2 * (x - y); + --y; + } + } +} + +// ***************************************************************************** +// *** Put line in buffer ************************************************** +// ***************************************************************************** +void Circle::DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t start_y) +{ + if((row >= x_start) && (row <= x_end)) + { + // Find start x position + int32_t start = y_start - start_y; + // Prevent write in memory before buffer + if(start < 0) start = 0; + // Find start x position + int32_t end = y_end - start_y; + // Prevent buffer overflow + if(end > n) end = n; + // Have sense draw only if end pointer in buffer + if(end > 0) + { + for(int32_t i = start; i < end; i++) buf[i] = color; + } + } +} diff --git a/Display/Primitives.h b/Display/Primitives.h new file mode 100644 index 0000000..2a4e0ee --- /dev/null +++ b/Display/Primitives.h @@ -0,0 +1,161 @@ +//****************************************************************************** +// @file Primitives.h +// @author Nicolai Shlapunov +// +// @details DevCore: Primitives Visual Object Classes(Box, Line, Circle), header +// +// @section LICENSE +// +// Software License Agreement (BSD License) +// +// Copyright (c) 2016, Devtronic & Nicolai Shlapunov +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// 3. Neither the name of the Devtronic nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL DEVTRONIC BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//****************************************************************************** + +#ifndef Primitives_h +#define Primitives_h + +// ***************************************************************************** +// *** Includes ************************************************************ +// ***************************************************************************** +#include "DevCfg.h" +#include "VisObject.h" + +// ***************************************************************************** +// *** Box Class *********************************************************** +// ***************************************************************************** +class Box : public VisObject +{ + public: + // ************************************************************************* + // *** Constructor ***************************************************** + // ************************************************************************* + Box() {}; + + // ************************************************************************* + // *** Constructor ***************************************************** + // ************************************************************************* + Box(int32_t x, int32_t y, int32_t w, int32_t h, int32_t c, bool is_fill = false); + + // ************************************************************************* + // *** SetParams ******************************************************* + // ************************************************************************* + void SetParams(int32_t x, int32_t y, int32_t w, int32_t h, int32_t c, bool is_fill = false); + + // ************************************************************************* + // *** Put line in buffer ********************************************** + // ************************************************************************* + virtual void DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t y = 0); + + // ************************************************************************* + // *** Put line in buffer ********************************************** + // ************************************************************************* + virtual void DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t x = 0); + + private: + // Box color + uint16_t color = 0U; + // Is box fill ? + bool fill = false; +}; + +// ***************************************************************************** +// *** Line Class ********************************************************** +// ***************************************************************************** +class Line : public VisObject +{ + public: + // ************************************************************************* + // *** Constructor ***************************************************** + // ************************************************************************* + Line() {}; + + // ************************************************************************* + // *** Constructor ***************************************************** + // ************************************************************************* + Line(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t c); + + // ************************************************************************* + // *** SetParams ******************************************************* + // ************************************************************************* + void SetParams(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t c); + + // ************************************************************************* + // *** Put line in buffer ********************************************** + // ************************************************************************* + virtual void DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t y = 0); + + // ************************************************************************* + // *** Put line in buffer ********************************************** + // ************************************************************************* + virtual void DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t x = 0); + + private: + // Line color + uint16_t color = 0U; +}; + +// ***************************************************************************** +// *** Circle Class ******************************************************** +// ***************************************************************************** +class Circle : public VisObject +{ + public: + // ************************************************************************* + // *** Constructor ***************************************************** + // ************************************************************************* + Circle() {}; + + // ************************************************************************* + // *** Constructor ***************************************************** + // ************************************************************************* + Circle(int32_t x, int32_t y, int32_t r, int32_t c, bool is_fill = false); + + // ************************************************************************* + // *** SetParams **************************************II*************** + // ************************************************************************* + void SetParams(int32_t x, int32_t y, int32_t r, int32_t c, bool is_fill = false); + + // ************************************************************************* + // *** Put line in buffer ********************************************** + // ************************************************************************* + virtual void DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t y = 0); + + // ************************************************************************* + // *** Put line in buffer ********************************************** + // ************************************************************************* + virtual void DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t x = 0); + + private: + // Circle color + uint16_t color = 0U; + // Circle radius + int16_t radius = 0; + // Is box fill ? + bool fill = false; +}; + +#endif diff --git a/Display/Strings.cpp b/Display/Strings.cpp new file mode 100644 index 0000000..e600867 --- /dev/null +++ b/Display/Strings.cpp @@ -0,0 +1,242 @@ +//****************************************************************************** +// @file String.cpp +// @author Nicolai Shlapunov +// +// @details DevCore: String Visual Object Class, implementation +// +// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov +// All rights reserved. +// +// @section SUPPORT +// +// Devtronic invests time and resources providing this open source code, +// please support Devtronic and open-source hardware/software by +// donations and/or purchasing products from Devtronic. +// +//****************************************************************************** + +// ***************************************************************************** +// *** Includes ************************************************************ +// ***************************************************************************** +#include "Strings.h" +#include "Fonts.h" + +#include // for strlen() + +// ***************************************************************************** +// ***************************************************************************** +// *** Strings ************************************************************* +// ***************************************************************************** +// ***************************************************************************** +const String::FontProfile String::fonts[FONTS_MAX] = +// W H BPP Pointer to data +{ { 4, 6, 6, (const uint8_t*)font4x6}, + { 6, 8, 8, (const uint8_t*)font6x8}, + { 8, 8, 8, (const uint8_t*)font8x8}, + { 8, 12, 12, (const uint8_t*)font8x12}, + {12, 16, 32, (const uint8_t*)font12x16} }; + +// ***************************************************************************** +// *** Constructor ********************************************************* +// ***************************************************************************** +String::String(const char* str, int32_t x, int32_t y, uint32_t tc, FontType ft) +{ + SetParams(str, x, y, tc, ft); +} + +// ***************************************************************************** +// *** Constructor ********************************************************* +// ***************************************************************************** +String::String(const char* str, int32_t x, int32_t y, uint32_t tc, uint32_t bgc, FontType ft) +{ + SetParams(str, x, y, tc, bgc, ft); +} + +// ***************************************************************************** +// *** SetParams *********************************************************** +// ***************************************************************************** +void String::SetParams(const char* str, int32_t x, int32_t y, uint32_t tc, FontType ft) +{ + string = (const uint8_t*)str; + x_start = x; + y_start = y; + txt_color = tc; + bg_color = 0; + font_type = ft; + transpatent_bg = true; + width = fonts[ft].w * strlen(str); + height = fonts[ft].h; + x_end = x + width - 1; + y_end = y + height - 1; + rotation = 0; +} + +// ***************************************************************************** +// *** SetParams *********************************************************** +// ***************************************************************************** +void String::SetParams(const char* str, int32_t x, int32_t y, uint32_t tc, uint32_t bgc, FontType ft) +{ + string = (const uint8_t*)str; + x_start = x; + y_start = y; + txt_color = tc; + bg_color = bgc; + font_type = ft; + transpatent_bg = false; + width = fonts[ft].w * strlen(str); + height = fonts[ft].h; + x_end = x + width - 1; + y_end = y + height - 1; + rotation = 0; +} + +// ***************************************************************************** +// *** SetColor ************************************************************ +// ***************************************************************************** +void String::SetColor(uint32_t tc, uint32_t bgc, bool is_trnsp) +{ + txt_color = tc; + bg_color = bgc; + transpatent_bg = is_trnsp; +} + +// ***************************************************************************** +// *** SetString *********************************************************** +// ***************************************************************************** +void String::SetString(const char* str) +{ + // Lock object for changes + LockVisObject(); + //Set new pointer to string + string = (const uint8_t*)str; + width = fonts[font_type].w * strlen(str); + x_end = x_start + width - 1; + // Unlock object after changes + UnlockVisObject(); +} + +// ***************************************************************************** +// *** Put line in buffer ************************************************** +// ***************************************************************************** +void String::DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t start_x) +{ + // Draw only if needed + if((line >= y_start) && (line <= y_end) && (string != nullptr)) + { + // Current symbol X position + int32_t x = x_start; + // Number of bytes need skipped for draw line + uint32_t skip_bytes = (line - y_start) * fonts[font_type].bytes_per_char / fonts[font_type].h; + // Pointer to string. Will increment for get characters. + const uint8_t* str = string; + + // While we have symbols + while(*str != '\0') + { + uint32_t b = 0; + uint32_t w = 0; + // Get all symbol line + for(uint32_t i = 0; i < fonts[font_type].bytes_per_char; i++) + { + b |= fonts[font_type].font_data[((uint32_t)(*str)) * fonts[font_type].bytes_per_char + skip_bytes + i] << (i*8); + } + // Output symbol line + while(w < fonts[font_type].w) + { + // Put color in buffer only if visible + if((x >= start_x) && (x < start_x+n)) + { + if((b&1) == 1) + { + buf[x] = txt_color; + } + else if(transpatent_bg == false) + { + buf[x] = bg_color; + } + else + { + // Empty statement + } + } + b >>= 1; + w++; + x++; + } + str++; + } + } +} + +// ***************************************************************************** +// *** Put line in buffer ************************************************** +// ***************************************************************************** +void String::DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t start_y) +{ + // Draw only if needed + if((row >= x_start) && (row <= x_end) && (string != nullptr)) + { + // Find line in symbol + int16_t start = y_start - start_y; + // Find line in symbol + int16_t line = (row - x_start); + + if(line >= 0) + { + // Get symbol + uint8_t c = string[line / fonts[font_type].w]; + // Find line in symbol + line %= fonts[font_type].w; + // Index to symbol in data array + uint16_t s_idx = c * fonts[font_type].bytes_per_char; + // Index to symbol in data array + uint16_t bytes_per_line = fonts[font_type].bytes_per_char / fonts[font_type].h; + // Get symbols lines + for(int32_t i = 0; i < fonts[font_type].h; i++) + { + uint32_t b = *(uint32_t *)(&fonts[font_type].font_data[s_idx + i*bytes_per_line]); + if(b & (1U< 0) && (start+i < n)) + { + buf[start+i] = txt_color; + } + } + } + } + } +} + +// ***************************************************************************** +// *** GetFontW ************************************************************ +// ***************************************************************************** +uint32_t String::GetFontW(FontType ft) +{ + // Zero my default + uint32_t font_w = 0U; + // If provided valid font number + if(ft < FONTS_MAX) + { + // Get font width + font_w = fonts[ft].w; + } + // Return result + return font_w; +}; + +// ***************************************************************************** +// *** GetFontH ************************************************************ +// ***************************************************************************** +uint32_t String::GetFontH(FontType ft) +{ + // Zero my default + uint32_t font_h = 0U; + // If provided valid font number + if(ft < FONTS_MAX) + { + // Get font height + font_h = fonts[ft].h; + } + // Return result + return font_h; +}; diff --git a/Display/Strings.h b/Display/Strings.h new file mode 100644 index 0000000..4dd5633 --- /dev/null +++ b/Display/Strings.h @@ -0,0 +1,146 @@ +//****************************************************************************** +// @file String.h +// @author Nicolai Shlapunov +// +// @details DevCore: String Visual Object Class, header +// +// @section LICENSE +// +// Software License Agreement (BSD License) +// +// Copyright (c) 2016, Devtronic & Nicolai Shlapunov +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// 3. Neither the name of the Devtronic nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL DEVTRONIC BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//****************************************************************************** + +#ifndef Strings_h +#define Strings_h + +// ***************************************************************************** +// *** Includes ************************************************************ +// ***************************************************************************** +#include "DevCfg.h" +#include "VisObject.h" + +// ***************************************************************************** +// *** String Class ******************************************************** +// ***************************************************************************** +class String : public VisObject +{ + public: + // ************************************************************************* + // *** Enum with all fonts types *************************************** + // ************************************************************************* + typedef enum + { + FONT_4x6, + FONT_6x8, + FONT_8x8, + FONT_8x12, + FONT_12x16, + FONTS_MAX + } FontType; + + // ************************************************************************* + // *** Constructor ***************************************************** + // ************************************************************************* + String() {}; + + // ************************************************************************* + // *** Constructor ***************************************************** + // ************************************************************************* + String(const char* str, int32_t x, int32_t y, uint32_t tc, FontType ft = FONT_8x8); + + // ************************************************************************* + // *** Constructor ***************************************************** + // ************************************************************************* + String(const char* str, int32_t x, int32_t y, uint32_t tc, uint32_t bgc, FontType ft = FONT_8x8); + + // ************************************************************************* + // *** SetParams ******************************************************* + // ************************************************************************* + void SetParams(const char* str, int32_t x, int32_t y, uint32_t tc, FontType ft); + + // ************************************************************************* + // *** SetParams ******************************************************* + // ************************************************************************* + void SetParams(const char* str, int32_t x, int32_t y, uint32_t tc, uint32_t bgc, FontType ft); + + // ************************************************************************* + // *** SetString ******************************************************* + // ************************************************************************* + void SetString(const char* str); + + // ************************************************************************* + // *** SetColor ******************************************************** + // ************************************************************************* + void SetColor(uint32_t tc, uint32_t bgc = 0U, bool is_trnsp = true); + + // ************************************************************************* + // *** Put line in buffer ********************************************** + // ************************************************************************* + virtual void DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t y = 0); + + // ************************************************************************* + // *** Put line in buffer ********************************************** + // ************************************************************************* + virtual void DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t x = 0); + + // ************************************************************************* + // *** GetFontW ******************************************************** + // ************************************************************************* + static uint32_t GetFontW(FontType ft); + + // ************************************************************************* + // *** GetFontH ******************************************************** + // ************************************************************************* + static uint32_t GetFontH(FontType ft); + + private: + // Pointer to string + // FIX ME: must be changed for prevent changing string during drawing + const uint8_t* string = nullptr; + // Text color + uint16_t txt_color = 0; + // Background color + uint16_t bg_color = 0; + // Font type + FontType font_type = FONT_8x8; + // Is background transparent ? + bool transpatent_bg = false; + + typedef struct + { + uint8_t w; // Width of character + uint8_t h; // Height of character + uint8_t bytes_per_char; // Bytes Per Char + const uint8_t* font_data; // Pointer to font data + } FontProfile; + + // Fonts structures. One for all String classes. + static const FontProfile fonts[FONTS_MAX]; +}; + +#endif diff --git a/Display/TiledMap.cpp b/Display/TiledMap.cpp new file mode 100644 index 0000000..8b59e42 --- /dev/null +++ b/Display/TiledMap.cpp @@ -0,0 +1,179 @@ +//****************************************************************************** +// @file TiledMap.cpp +// @author Nicolai Shlapunov +// +// @details DevCore: Tiled Map Class, implementation +// +// @copyright Copyright (c) 2017, Devtronic & Nicolai Shlapunov +// All rights reserved. +// +// @section SUPPORT +// +// Devtronic invests time and resources providing this open source code, +// please support Devtronic and open-source hardware/software by +// donations and/or purchasing products from Devtronic. +// +//****************************************************************************** + +// ***************************************************************************** +// *** Includes ************************************************************ +// ***************************************************************************** +#include "TiledMap.h" + +// ***************************************************************************** +// *** Constructor ********************************************************* +// ***************************************************************************** +TiledMap::TiledMap(int32_t x, int32_t y, int32_t w, int32_t h, + uint8_t* map, uint32_t map_w, uint32_t map_h, uint8_t bitmask, + const ImageDesc* tiles, uint32_t n, int32_t def_color) +{ + x_start = x; + y_start = y; + width = w; + height = h; + x_end = x_start + width - 1; + y_end = y_start + height - 1; + tiles_map = map; + map_width = map_w; + map_height = map_h; + tile_bitmask = bitmask; + tiles_img = tiles; + tiles_cnt = n; + tile_width = tiles->width; + tile_height = tiles->height; + bg_color = def_color; +} + +// ***************************************************************************** +// *** Put line in buffer ************************************************** +// ***************************************************************************** +void TiledMap::DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t start_x) +{ + // Draw only if needed + if((line >= y_start) && (line <= y_end)) + { + int32_t start_offset = 0; + // Find start x position + int32_t start = x_start - start_x; + // Prevent write in memory before buffer + if(start < 0) + { + start_offset = -start; + start = 0; + } + // Find end x position + int32_t end = x_end - start_x; + // Prevent buffer overflow + if(end >= n) end = n - 1; + + // Find start tile index and offsets + int32_t x_tile_idx = (x_pos + start_x + start_offset) / tile_width; + int32_t y_tile_idx = (y_pos + line - y_start) / tile_height; + int32_t tile_idx = y_tile_idx * map_width + x_tile_idx; + int32_t x_tile_offset = (x_pos + start_x + start_offset) % tile_width; + int32_t y_tile_offset = ((y_pos + line - y_start) % tile_height) * tile_width; + + // If default color is 0 or greater + if(bg_color >= 0) + { + // Fill buffer by default color + for(int32_t i = start; i < end; i++) + { + buf[i] = bg_color; + } + } + // Prepare variables for first cycle + int32_t pix_idx = start; + int32_t tile_pix_idx = x_tile_offset; + // Draw line with tiles + while(pix_idx < n) + { + // Get tile value + uint8_t tile_val = tiles_map[tile_idx] & tile_bitmask; + // Skip empty tiles + if(tile_val >= tiles_cnt) + { + pix_idx += tile_width - tile_pix_idx; + tile_idx++; + tile_pix_idx = 0; + continue; + } + // Get pointer to the current tile image + const uint8_t* tile_ptr = &tiles_img[tile_val].img8[y_tile_offset]; + // Get pointer to the current tile palette + const uint16_t* palette_ptr = tiles_img[tile_val].palette; + // Get transparent color + const int32_t transparent_color = tiles_img[tile_val].transparent_color; + // Draw tile + for(;(tile_pix_idx < (int32_t)tile_width) && (pix_idx <= end); tile_pix_idx++) + { + // Get pixel data + uint16_t data = palette_ptr[tile_ptr[tile_pix_idx]]; + // If not transparent - output to buffer + if(data != transparent_color) buf[pix_idx] = data; + pix_idx++; + } + // Increase tile index + tile_idx++; + // Clear tile pixel counter + tile_pix_idx = 0; + } + } +} + +// ***************************************************************************** +// *** Put line in buffer ************************************************** +// ***************************************************************************** +void TiledMap::DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t start_y) +{ + // Not implemented yet +} + +// ***************************************************************************** +// *** Scroll tiled map **************************************************** +// ***************************************************************************** +void TiledMap::ScrollView(int32_t dx, int32_t dy) +{ + LockVisObject(); + x_pos += dx; + if(x_pos < 0) x_pos = 0; + y_pos += dy; + if(y_pos < 0) y_pos = 0; + UnlockVisObject(); +} + +// ***************************************************************************** +// *** GetLvlIdxByXY ******************************************************* +// ***************************************************************************** +int32_t TiledMap::GetLvlIdxByXY(uint32_t x, uint32_t y) +{ + uint32_t result = -1; + // Calculate tiles indexes + uint32_t x_tile = x/tile_width; + uint32_t y_tile = y/tile_height; + // Set result only if x & y valid values + if(x_tile < map_width && y_tile < map_height) + { + result = y_tile*map_width + x_tile; + } + // Return result + return result; +} + +// ***************************************************************************** +// *** GetLvlDataByXY ****************************************************** +// ***************************************************************************** +int8_t TiledMap::GetLvlDataByXY(uint32_t x, uint32_t y) +{ + uint32_t result = 0U; + // Calculate tiles indexes + uint32_t x_tile = x/tile_width; + uint32_t y_tile = y/tile_height; + // Set result only if x & y valid values + if(x_tile < map_width && y_tile < map_height) + { + result = tiles_map[y_tile*map_width + x_tile]; + } + // Return result + return result; +} diff --git a/Display/TiledMap.h b/Display/TiledMap.h new file mode 100644 index 0000000..fc4bb74 --- /dev/null +++ b/Display/TiledMap.h @@ -0,0 +1,131 @@ +//****************************************************************************** +// @file TiledMap.h +// @author Nicolai Shlapunov +// +// @details DevCore: Tiled Map Class, header +// +// @section LICENSE +// +// Software License Agreement (BSD License) +// +// Copyright (c) 2017, Devtronic & Nicolai Shlapunov +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// 3. Neither the name of the Devtronic nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL DEVTRONIC BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//****************************************************************************** + +#ifndef TilesMap_h +#define TilesMap_h + +// ***************************************************************************** +// *** Includes ************************************************************ +// ***************************************************************************** +#include "DevCfg.h" +#include "VisObject.h" +#include "Image.h" + +// ***************************************************************************** +// *** Tile Map Class ****************************************************** +// ***************************************************************************** +class TiledMap : public VisObject +{ + public: + // ************************************************************************* + // *** Constructor ***************************************************** + // ************************************************************************* + TiledMap(int32_t x, int32_t y, int32_t w, int32_t h, + uint8_t* map, uint32_t map_w, uint32_t map_h, uint8_t bitmask, + const ImageDesc* tiles, uint32_t n, int32_t def_color); + + // ************************************************************************* + // *** Put line in buffer ********************************************** + // ************************************************************************* + virtual void DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t y = 0); + + // ************************************************************************* + // *** Put line in buffer ********************************************** + // ************************************************************************* + virtual void DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t x = 0); + + // ************************************************************************* + // *** Scroll tiled map ************************************************ + // ************************************************************************* + void ScrollView(int32_t dx, int32_t dy = 0); + + // ************************************************************************* + // *** GetMapPosX ****************************************************** + // ************************************************************************* + int32_t GetLvlIdxByXY(uint32_t x, uint32_t y); + + // ************************************************************************* + // *** GetMapPosX ****************************************************** + // ************************************************************************* + int8_t GetLvlDataByXY(uint32_t x, uint32_t y); + + // ************************************************************************* + // *** GetMapPosX ****************************************************** + // ************************************************************************* + int32_t GetMapPosX(void) {return x_pos;} + + // ************************************************************************* + // *** GetMapPosY ****************************************************** + // ************************************************************************* + int32_t GetMapPosY(void) {return y_pos;} + + // ************************************************************************* + // *** GetPixWidth ***************************************************** + // ************************************************************************* + int32_t GetPixWidth() {return (tile_width * map_width);} + + // ************************************************************************* + // *** GetPixHeight **************************************************** + // ************************************************************************* + int32_t GetPixHeight() {return (tile_height * map_height);} + + private: + // Pointer to the tiles map + uint8_t* tiles_map; + // Map width in tiles + uint32_t map_width; + // Map height in tiles + uint32_t map_height; + // Bitmask for tiles + uint8_t tile_bitmask; + // Image descriptions of tiles picture + const ImageDesc* tiles_img; + // Image descriptions of tiles picture + uint32_t tiles_cnt; + // Tiles width in pixels + uint32_t tile_width; + // Tiles height in pixels + uint32_t tile_height; + // Background color (-1 - transparent) + int32_t bg_color; + // X position of tiled map in the viewport + int32_t x_pos = 0; + // Y position of tiled map in the viewport + int32_t y_pos = 0; +}; + +#endif diff --git a/Display/VisObject.cpp b/Display/VisObject.cpp new file mode 100644 index 0000000..3b206ea --- /dev/null +++ b/Display/VisObject.cpp @@ -0,0 +1,125 @@ +//****************************************************************************** +// @file VisObject.cpp +// @author Nicolai Shlapunov +// +// @details DevCore: Visual Object Base Class, implementation +// +// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov +// All rights reserved. +// +// @section SUPPORT +// +// Devtronic invests time and resources providing this open source code, +// please support Devtronic and open-source hardware/software by +// donations and/or purchasing products from Devtronic. +// +//****************************************************************************** + +// ***************************************************************************** +// *** Includes ************************************************************ +// ***************************************************************************** +#include "VisObject.h" +#include "DisplayDrv.h" // for DelVisObjectFromList() + +// ***************************************************************************** +// *** Destructor ********************************************************** +// ***************************************************************************** +VisObject::~VisObject() +{ + // Remove object from object list before delete + DisplayDrv::GetInstance().DelVisObjectFromList(this); +} + +// ***************************************************************************** +// *** Lock Visual Object *************************************************** +// ***************************************************************************** +void VisObject::LockVisObject() +{ + // Lock line + DisplayDrv::GetInstance().LockDisplayLine(); +}; + +// ***************************************************************************** +// *** Unlock Visual Object ************************************************ +// ***************************************************************************** +void VisObject::UnlockVisObject() +{ + // Unlock line + DisplayDrv::GetInstance().UnlockDisplayLine(); +}; + +// ***************************************************************************** +// *** Show Visual Object ************************************************** +// ***************************************************************************** +void VisObject::Show(uint32_t z_pos) +{ + // Z position is 0 by default. In this case we can use 0 here as "no pos" flag + if(z_pos != 0) + { + z = z_pos; + } + // Add to VisObject List + DisplayDrv::GetInstance().AddVisObjectToList(this, z); +} + +// ***************************************************************************** +// *** Hide Visual Object ************************************************** +// ***************************************************************************** +void VisObject::Hide(void) +{ + // Delete from VisObject List + DisplayDrv::GetInstance().DelVisObjectFromList(this); +} + +// ***************************************************************************** +// *** Check status of Show Visual Object ********************************** +// ***************************************************************************** +bool VisObject::IsShow(void) +{ + // Return false by default + bool ret = false; + // If any pointer is not null - object in list + if( (p_next != nullptr) || (p_prev != nullptr) ) + { + ret = true; + } + // Return result + return ret; +} + +// ***************************************************************************** +// *** Move Visual Object ************************************************** +// ***************************************************************************** +void VisObject::Move(int32_t x, int32_t y, bool is_delta) +{ + // Lock object for changes + LockVisObject(); + // Make changes + if(is_delta == true) + { + // Move object in delta coordinates + x_start += x; + y_start += y; + x_end += x; + y_end += y; + } + else + { + // Move object in absolute coordinates + x_start = x; + y_start = y; + x_end = x + width - 1; + y_end = y + height - 1; + } + // Unlock object after changes + UnlockVisObject(); +} + +// ***************************************************************************** +// *** Action ************************************************************** +// ***************************************************************************** +void VisObject::Action(ActionType action, int32_t tx, int32_t ty) +{ + // Empty function. We can do active object without custom Action function + // for cover active object with lower Z. +} diff --git a/Display/VisObject.h b/Display/VisObject.h new file mode 100644 index 0000000..a8b5439 --- /dev/null +++ b/Display/VisObject.h @@ -0,0 +1,199 @@ +//****************************************************************************** +// @file VisObject.h +// @author Nicolai Shlapunov +// +// @details DevCore: Visual Object Base Class, header +// +// @section LICENSE +// +// Software License Agreement (BSD License) +// +// Copyright (c) 2016, Devtronic & Nicolai Shlapunov +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// 3. Neither the name of the Devtronic nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL DEVTRONIC BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//****************************************************************************** + +#ifndef VisObject_h +#define VisObject_h + +// ***************************************************************************** +// *** Includes ************************************************************ +// ***************************************************************************** +#include "DevCfg.h" + +// ***************************************************************************** +// * VisObject class. This class implements base Visual Objects properties. +class VisObject +{ + public: + // ************************************************************************* + // *** Action ********************************************************** + // ************************************************************************* + typedef enum + { + ACT_TOUCH, // When object touched + ACT_UNTOUCH, // When object detouched + ACT_MOVE, // When object moved on object + ACT_MOVEIN, // When object moved in to object + ACT_MOVEOUT, // When object moved out of object + ACT_MAX // Total possible actions + } ActionType; + + // ************************************************************************* + // *** VisObject ******************************************************* + // ************************************************************************* + VisObject() {}; + + // ************************************************************************* + // *** ~VisObject ****************************************************** + // ************************************************************************* + // * Destructor. Call DelVisObjectFromList() from DisplayDrv class for + // * remove from list before delete and delete semaphore. + virtual ~VisObject(); + + // ************************************************************************* + // *** LockVisObject *************************************************** + // ************************************************************************* + void LockVisObject(); + + // ************************************************************************* + // *** UnlockVisObject ************************************************* + // ************************************************************************* + void UnlockVisObject(); + + // ************************************************************************* + // *** Show ************************************************************ + // ************************************************************************* + // * Show VisObject on screen. This function call AddVisObjectToList() from + // * DisplayDrv class. When this function calls first time, user must + // * provide Z level. In future user can call this function without + // * parameters - previously set Z will be used. + virtual void Show(uint32_t z_pos = 0); + + // ************************************************************************* + // *** Hide ************************************************************ + // ************************************************************************* + // * Hide VisObject from screen. This function call DelVisObjectFromList() + // * from DisplayDrv class. + virtual void Hide(void); + + // ************************************************************************* + // *** IsShow ********************************************************** + // ************************************************************************* + // * Check status of Show Visual Object. Return true if object in DisplayDrv list. + virtual bool IsShow(void); + + // ************************************************************************* + // *** Move ************************************************************ + // ************************************************************************* + // * Move object on screen. Set new x and y coordinates. If flag is set - + // * move is relative, not absolute. + virtual void Move(int32_t x, int32_t y, bool is_delta = false); + + // ************************************************************************* + // *** DrawInBufH ****************************************************** + // ************************************************************************* + // * Draw one horizontal line of object in specified buffer. + // * Each derived class must implement this function. + virtual void DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t start_y = 0) = 0; + + // ************************************************************************* + // *** DrawInBufW ****************************************************** + // ************************************************************************* + // * Draw one vertical line of object in specified buffer. + // * Each derived class must implement this function. + virtual void DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t start_x = 0) = 0; + + // ************************************************************************* + // *** Action ********************************************************** + // ************************************************************************* + virtual void Action(ActionType action, int32_t tx, int32_t ty); + + // ************************************************************************* + // *** Return Start X coordinate *************************************** + // ************************************************************************* + virtual int32_t GetStartX(void) {return x_start;}; + + // ************************************************************************* + // *** Return Start Y coordinate *************************************** + // ************************************************************************* + virtual int32_t GetStartY(void) {return y_start;}; + + // ************************************************************************* + // *** Return End X coordinate ***************************************** + // ************************************************************************* + virtual int32_t GetEndX(void) {return x_end;}; + + // ************************************************************************* + // *** Return End Y coordinate ***************************************** + // ************************************************************************* + virtual int32_t GetEndY(void) {return y_end;}; + + // ************************************************************************* + // *** Return Width of object ****************************************** + // ************************************************************************* + virtual int32_t GetWidth(void) {return width;}; + + // ************************************************************************* + // *** Return Height of object ***************************************** + // ************************************************************************* + virtual int32_t GetHeight(void) {return height;}; + + protected: + // ************************************************************************* + // *** Object parameters *********************************************** + // ************************************************************************* + + // X and Y start coordinates of object + int16_t x_start = 0, y_start = 0; + // X and Y end coordinates of object + int16_t x_end = 0, y_end = 0; + // Width and Height of object + int16_t width = 0, height = 0; + // Rotation of object + int8_t rotation = 0; + // Object active + bool active = false; + + private: + // ************************************************************************* + // *** Object parameters *********************************************** + // ************************************************************************* + // * Only base class and DisplayDrv have access to this parameters + + // Z position of object + uint16_t z = 0; + // Pointer to next object. This pointer need to maker object list. Object + // can be added only to one list. + VisObject* p_next = nullptr; + // Pointer to next object. This pointer need to maker object list. Object + // can be added only to one list. + VisObject* p_prev = nullptr; + + // DisplayDrv is friend for access to pointers and Z + friend class DisplayDrv; +}; + +#endif diff --git a/Display/XPT2046.cpp b/Display/XPT2046.cpp new file mode 100644 index 0000000..0e7f396 --- /dev/null +++ b/Display/XPT2046.cpp @@ -0,0 +1,145 @@ +//****************************************************************************** +// @file XPT2046.cpp +// @author Nicolai Shlapunov +// +// @details DevCore: XPT2046 Low Level Driver Class, implementation +// +// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov +// All rights reserved. +// +// @section SUPPORT +// +// Devtronic invests time and resources providing this open source code, +// please support Devtronic and open-source hardware/software by +// donations and/or purchasing products from Devtronic. +// +//****************************************************************************** + +// ***************************************************************************** +// *** Includes ************************************************************ +// ***************************************************************************** +#include + +// ***************************************************************************** +// *** Init touchscreen **************************************************** +// ***************************************************************************** +void XPT2046::Init(void) +{ + // Pull down CS + HAL_GPIO_WritePin(TOUCH_CS_GPIO_Port, TOUCH_CS_Pin, GPIO_PIN_RESET); + // Send ON command + SpiWrite(TON); + // Send empty byte for skip answer + SpiWrite(EMP); + // Send empty byte for skip answer + SpiWrite(EMP); + // Pull up CS + HAL_GPIO_WritePin(TOUCH_CS_GPIO_Port, TOUCH_CS_Pin, GPIO_PIN_SET); +} + +// ***************************************************************************** +// *** If touched - return true. ******************************************* +// ***************************************************************************** +bool XPT2046::IsTouch(void) +{ + // Check T_IRQ input and return state + return(HAL_GPIO_ReadPin(T_IRQ_GPIO_Port, T_IRQ_Pin) == GPIO_PIN_RESET); +} + +// ***************************************************************************** +// *** Get X and Y coordinates. If touched - return true. ****************** +// ***************************************************************************** +bool XPT2046::GetRawXY(int32_t& x, int32_t& y) +{ + // Return value + bool ret = false; + // If touch present + if(HAL_GPIO_ReadPin(T_IRQ_GPIO_Port, T_IRQ_Pin) == GPIO_PIN_RESET) + { + // Pull down CS + HAL_GPIO_WritePin(TOUCH_CS_GPIO_Port, TOUCH_CS_Pin, GPIO_PIN_RESET); + // Request X coordinate + SpiWrite(CHX); + // Receive High byte for X + x = SpiWriteRead(EMP) << 8; + // Receive Low byte for X + x |= SpiWriteRead(EMP); + // Shift, because result have only 12 bits, 3 because answer started from + // second rise edge + x >>= 3; + // Pull up CS + HAL_GPIO_WritePin(TOUCH_CS_GPIO_Port, TOUCH_CS_Pin, GPIO_PIN_SET); + + // Pull down CS + HAL_GPIO_WritePin(TOUCH_CS_GPIO_Port, TOUCH_CS_Pin, GPIO_PIN_RESET); + // Request Y coordinate + SpiWrite(CHY); + // Receive High byte for Y + y = SpiWriteRead(EMP) << 8; + // Receive Low byte for Y + y |= SpiWriteRead(EMP); + // Shift, because result have only 12 bits, 3 because answer started from + // second rise edge + y >>= 3; + // Pull up CS + HAL_GPIO_WritePin(TOUCH_CS_GPIO_Port, TOUCH_CS_Pin, GPIO_PIN_SET); + + // Touch present + ret = true; + } + // Return result + return ret; +} + +// ***************************************************************************** +// *** Get X and Y coordinates. If touched - return true. ****************** +// ***************************************************************************** +bool XPT2046::GetXY(int32_t& x, int32_t& y) +{ + // Return value + bool ret = GetRawXY(x, y); + // If touch present + if(ret) + { + // Calculate X + x = ((x * COEF) / kx) + bx; + // Calculate Y + y = ((y * COEF) / ky) + by; + } + // Return touch state + return ret; +} + +// ***************************************************************************** +// *** SetCalibrationConsts ************************************************ +// ***************************************************************************** +void XPT2046::SetCalibrationConsts(int32_t nkx, int32_t nky, int32_t nbx, int32_t nby) +{ + // Save calibration constants + kx = nkx; + ky = nky; + bx = nbx; + by = nby; +} + +// ***************************************************************************** +// *** Write byte to SPI *************************************************** +// ***************************************************************************** +inline void XPT2046::SpiWrite(uint8_t c) +{ + // Call HAL function for send byte by SPI + (void) HAL_SPI_Transmit(hspi, &c, sizeof(c), 1U); +} + +// ***************************************************************************** +// *** Write and read byte to/from SPI ************************************* +// ***************************************************************************** +inline uint8_t XPT2046::SpiWriteRead(uint8_t c) +{ + // Temporary variable for receive byte + uint8_t rcv; + // Call HAL function for send/receive byte by SPI + (void) HAL_SPI_TransmitReceive(hspi, &c, &rcv, sizeof(uint8_t), 1U); + // Return received byte + return rcv; +} diff --git a/Display/XPT2046.h b/Display/XPT2046.h new file mode 100644 index 0000000..51b35a5 --- /dev/null +++ b/Display/XPT2046.h @@ -0,0 +1,129 @@ +//****************************************************************************** +// @file XPT2046.h +// @author Nicolai Shlapunov +// +// @details DevCore: XPT2046 Low Level Driver Class, header +// +// @section LICENSE +// +// Software License Agreement (BSD License) +// +// Copyright (c) 2016, Devtronic & Nicolai Shlapunov +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// 3. Neither the name of the Devtronic nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL DEVTRONIC BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//****************************************************************************** + +#ifndef XPT2046_h +#define XPT2046_h + +// ***************************************************************************** +// *** Includes ************************************************************ +// ***************************************************************************** +#include "DevCfg.h" + +// ***************************************************************************** +// *** Defines ************************************************************* +// ***************************************************************************** + +// ***************************************************************************** +// * XPT2046 class. Implements work with XPT2046 resistive touchscreen. +class XPT2046 +{ + public: + // Coefficient for calibration + const static int32_t COEF = 100; + + // ************************************************************************* + // *** Constructor ***************************************************** + // ************************************************************************* + // * This class hasn't task inside. For use this class user must provide + // * handle to SPI. Previously I think shape SPI between TFT and Touch. + // * But now it is two different SPI. Anyway main idea it is use this class + // * in DisplayDrv class for find pressed VisObjects. + XPT2046(SPI_HandleTypeDef* in_hspi) : hspi(in_hspi) {}; + + // ************************************************************************* + // *** Init ************************************************************ + // ************************************************************************* + // * Init function. Send init sequence to touchscreen controller. + void Init(void); + + // ************************************************************************* + // *** IsTouch ********************************************************* + // ************************************************************************* + // * Check touched or not by T_IRQ pin. Return true if touched. + bool IsTouch(void); + + // ************************************************************************* + // *** GetRawXY ******************************************************** + // ************************************************************************* + // * Return raw X and Y coordinates. If touched - return true. + bool GetRawXY(int32_t& x, int32_t& y); + + // ************************************************************************* + // *** GetXY *********************************************************** + // ************************************************************************* + // * Return recalculated using calibration constants X and Y coordinates. + // * If touched - return true. Can be used for second calibration. + bool GetXY(int32_t& x, int32_t& y); + + // ************************************************************************* + // *** SetCalibrationConsts ******************************************** + // ************************************************************************* + // * Set calibration constants. Must be call for calibration touchscreen. + void SetCalibrationConsts(int32_t nkx, int32_t nky, int32_t nbx, int32_t nby); + + private: + // Turn touchscreen ON + const static uint8_t TON = 0x80; + // Empty byte + const static uint8_t EMP = 0x00; + // Request X coordinate + const static uint8_t CHX = 0x90; + // Request Y coordinate + const static uint8_t CHY = 0xD0; + + // Handle to SPI used for touchscreen + SPI_HandleTypeDef* hspi = nullptr; + + // Display width and height offset + int32_t kx = -1097, ky = -1499; + // Display width and height coefficient + int32_t bx = 334, by = 259; + + // ************************************************************************* + // *** SpiWrite ******************************************************** + // ************************************************************************* + // * Write byte to SPI + inline void SpiWrite(uint8_t c); + + // ************************************************************************* + // *** SpiWriteRead **************************************************** + // ************************************************************************* + // * Write/read byte from/to SPI + inline uint8_t SpiWriteRead(uint8_t c); +}; + +#endif -- cgit v1.2.3