diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index ef9b6bfca4..734c79e6fc 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -32,8 +32,50 @@ static uint32_t _atoi(const char* sp) { #elif defined(ESP32) #include DataStore store(SPIFFS, rtc_clock); -#endif +#if defined(ARDUINO_M5STACK_CORE2) + #include + #include + + constexpr uint8_t kCore2HeartbeatPin = 14; + constexpr unsigned long kCore2HeartbeatPeriodMs = 30000UL; + constexpr unsigned long kCore2HeartbeatHighMs = 5000UL; + + static void initCore2SdCard() { + uint8_t card_type = SD.cardType(); + if (card_type == CARD_NONE) { + Serial.println("SD: mount failed, retrying at lower SPI speed"); + if (!SD.begin(TFCARD_CS_PIN, SPI, 10000000)) { + Serial.println("SD: retry failed"); + return; + } + card_type = SD.cardType(); + } + + if (!SD.exists("/meshcore")) { + SD.mkdir("/meshcore"); + } + + uint64_t total_bytes = SD.totalBytes(); + uint64_t used_bytes = SD.usedBytes(); + Serial.printf("SD: mounted type=%u total=%lluKB used=%lluKB\n", + static_cast(card_type), + static_cast(total_bytes / 1024ULL), + static_cast(used_bytes / 1024ULL)); + } + static void updateCore2HeartbeatPulse() { + static bool initialized = false; + if (!initialized) { + pinMode(kCore2HeartbeatPin, OUTPUT); + digitalWrite(kCore2HeartbeatPin, LOW); + initialized = true; + } + + const bool pulse_high = (millis() % kCore2HeartbeatPeriodMs) < kCore2HeartbeatHighMs; + digitalWrite(kCore2HeartbeatPin, pulse_high ? HIGH : LOW); + } +#endif +#endif #ifdef ESP32 #ifdef WIFI_SSID #include @@ -113,23 +155,52 @@ void halt() { void setup() { Serial.begin(115200); - - board.begin(); + delay(50); #ifdef DISPLAY_CLASS DisplayDriver* disp = NULL; - if (display.begin()) { - disp = &display; + bool display_ready = false; + auto showBootStatus = [&](const char* msg) { + if (!display_ready || disp == NULL) { + return; + } disp->startFrame(); - #ifdef ST7789 - disp->setTextSize(2); - #endif - disp->drawTextCentered(disp->width() / 2, 28, "Loading..."); + disp->setColor(DisplayDriver::LIGHT); + disp->setCursor(0, 0); + disp->print(msg); disp->endFrame(); + }; + + display_ready = display.begin(); + if (display_ready) { + disp = &display; + showBootStatus("Please wait...\nInit radio..."); } +#else + auto showBootStatus = [&](const char*) {}; #endif - if (!radio_init()) { halt(); } + board.begin(); + +#if defined(CORE2_ALWAYS_POWERED) && CORE2_ALWAYS_POWERED + board.setInhibitSleep(true); + Serial.println("PWR: sleep inhibited (always powered build)"); +#endif + + if (!radio_init()) { +#ifdef DISPLAY_CLASS + if (display_ready && disp != NULL) { + disp->startFrame(); + disp->setColor(DisplayDriver::LIGHT); + disp->setCursor(0, 0); + disp->print("Radio init failed"); + disp->endFrame(); + } +#endif + halt(); + } + + showBootStatus("Radio OK"); fast_rng.begin(radio_driver.getRngSeed()); @@ -190,6 +261,9 @@ void setup() { the_mesh.startInterface(serial_interface); #elif defined(ESP32) SPIFFS.begin(true); +#if defined(ARDUINO_M5STACK_CORE2) + initCore2SdCard(); +#endif store.begin(); the_mesh.begin( #ifdef DISPLAY_CLASS @@ -240,9 +314,15 @@ void setup() { #endif board.onBootComplete(); +#if defined(ARDUINO_M5STACK_CORE2) + updateCore2HeartbeatPulse(); +#endif } void loop() { +#if defined(ARDUINO_M5STACK_CORE2) + updateCore2HeartbeatPulse(); +#endif the_mesh.loop(); sensors.loop(); #ifdef DISPLAY_CLASS diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index 7c84201941..7842af6620 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -2,6 +2,38 @@ #include #include "../MyMesh.h" #include "target.h" +#if defined(ARDUINO_M5STACK_CORE2) +#include +#include +#include "ProtoNerdFont.h" +#include "ProtoNerdValueFont.h" +#ifndef CORE2_TOUCH_DEBUG_LOGGING + #define CORE2_TOUCH_DEBUG_LOGGING 1 +#endif +#if CORE2_TOUCH_DEBUG_LOGGING + #define CORE2_TOUCH_TRACE(fmt, ...) MESH_DEBUG_PRINTLN("core2-touch: " fmt, ##__VA_ARGS__) +#else + #define CORE2_TOUCH_TRACE(...) do {} while (0) +#endif +#ifdef RED +#undef RED +#endif +#ifdef GREEN +#undef GREEN +#endif +#ifdef BLUE +#undef BLUE +#endif +#ifdef YELLOW +#undef YELLOW +#endif +#ifdef ORANGE +#undef ORANGE +#endif +#endif +#ifndef CORE2_TOUCH_TRACE + #define CORE2_TOUCH_TRACE(...) do {} while (0) +#endif #ifdef WIFI_SSID #include #endif @@ -18,6 +50,9 @@ #endif #define LONG_PRESS_MILLIS 1200 +#define CORE2_MODE_SWITCH_LONG_PRESS_MILLIS 1000 +#define CORE2_SWIPE_MIN_DX 50 +#define CORE2_SWIPE_MAX_DY 80 #ifndef UI_RECENT_LIST_SIZE #define UI_RECENT_LIST_SIZE 4 @@ -31,6 +66,121 @@ #include "icons.h" +#if defined(ARDUINO_M5STACK_CORE2) +static void formatStorageBytes(char* out, size_t out_len, uint64_t bytes) { + if (bytes >= (1024ULL * 1024ULL * 1024ULL)) { + snprintf(out, out_len, "%.2f GB", bytes / 1073741824.0); + } else { + snprintf(out, out_len, "%.0f MB", bytes / 1048576.0); + } +} + +static void drawCore2NerdText(int x, int y, const char* text, uint16_t color) { + proto_nerd_font::drawTextTransparent(M5.Lcd, x, y, text, color, 1); +} + +static void drawCore2NerdCentered(int mid_x, int y, const char* text, uint16_t color) { + const int width = proto_nerd_font::textWidth(text, 1); + drawCore2NerdText(mid_x - (width / 2), y, text, color); +} + +static void drawCore2NerdRight(int right_x, int y, const char* text, uint16_t color) { + const int width = proto_nerd_font::textWidth(text, 1); + drawCore2NerdText(right_x - width, y, text, color); +} + +static void drawCore2ValueCentered(int mid_x, int y, const char* text, uint16_t color) { + const int width = proto_nerd_value_font::textWidth(text, 1); + proto_nerd_value_font::drawTextTransparent(M5.Lcd, mid_x - (width / 2), y, text, color, 1); +} + +static void drawCore2NerdEllipsized(int x, int y, int max_width, const char* text, uint16_t color) { + char temp[128]; + StrHelper::strncpy(temp, text, sizeof(temp)); + if (proto_nerd_font::textWidth(temp, 1) <= max_width) { + drawCore2NerdText(x, y, temp, color); + return; + } + + while (temp[0] != 0) { + const size_t len = strlen(temp); + temp[len - 1] = 0; + char candidate[128]; + snprintf(candidate, sizeof(candidate), "%s...", temp); + if (proto_nerd_font::textWidth(candidate, 1) <= max_width) { + drawCore2NerdText(x, y, candidate, color); + return; + } + } + + drawCore2NerdText(x, y, "...", color); +} + +static int drawCore2NerdWrapped(int x, int y, int max_width, const char* text, uint16_t color, int line_height) { + char remaining[192]; + StrHelper::strncpy(remaining, text, sizeof(remaining)); + int line_y = y; + + while (remaining[0] != 0) { + char line[96] = ""; + char* cursor = remaining; + char* last_space = nullptr; + + while (*cursor != 0) { + const size_t candidate_len = static_cast(cursor - remaining + 1); + char candidate[96]; + if (candidate_len >= sizeof(candidate)) { + break; + } + memcpy(candidate, remaining, candidate_len); + candidate[candidate_len] = 0; + if (proto_nerd_font::textWidth(candidate, 1) > max_width) { + break; + } + if (*cursor == ' ') { + last_space = cursor; + } + ++cursor; + } + + if (*cursor == 0 && proto_nerd_font::textWidth(remaining, 1) <= max_width) { + drawCore2NerdText(x, line_y, remaining, color); + line_y += line_height; + break; + } + + if (last_space != nullptr) { + const size_t line_len = static_cast(last_space - remaining); + memcpy(line, remaining, line_len); + line[line_len] = 0; + while (*last_space == ' ') { + ++last_space; + } + memmove(remaining, last_space, strlen(last_space) + 1); + } else { + size_t take = 1; + while (remaining[take] != 0) { + char probe[96]; + memcpy(probe, remaining, take + 1); + probe[take + 1] = 0; + if (proto_nerd_font::textWidth(probe, 1) > max_width) { + break; + } + ++take; + } + memcpy(line, remaining, take); + line[take] = 0; + memmove(remaining, remaining + take, strlen(remaining + take) + 1); + } + + drawCore2NerdText(x, line_y, line, color); + line_y += line_height; + } + + return line_y; +} +#endif + class SplashScreen : public UIScreen { UITask* _task; unsigned long dismiss_after; @@ -95,6 +245,9 @@ class HomeScreen : public UIScreen { #endif #if UI_SENSORS_PAGE == 1 SENSORS, +#endif +#if defined(ARDUINO_M5STACK_CORE2) + STORAGE, #endif SHUTDOWN, Count // keep as last @@ -181,6 +334,8 @@ class HomeScreen : public UIScreen { : _task(task), _rtc(rtc), _sensors(sensors), _node_prefs(node_prefs), _page(0), _shutdown_init(false), sensors_lpp(200) { } + bool isFirstPanel() const { return _page == HomePage::FIRST; } + void poll() override { if (_shutdown_init && !_task->isButtonPressed()) { // must wait for USR button to be released _task->shutdown(); @@ -188,6 +343,204 @@ class HomeScreen : public UIScreen { } int render(DisplayDriver& display) override { +#if defined(ARDUINO_M5STACK_CORE2) + M5.Lcd.fillScreen(TFT_BLACK); + + char tmp_core[80]; + char filtered_name_core[sizeof(_node_prefs->node_name)]; + display.translateUTF8ToBlocks(filtered_name_core, _node_prefs->node_name, sizeof(filtered_name_core)); + drawCore2NerdText(10, 8, filtered_name_core, TFT_GREEN); + renderBatteryIndicator(display, _task->getBattMilliVolts()); + + int indicator_x = (display.width() / 2) - (9 * (HomePage::Count - 1)); + for (uint8_t i = 0; i < HomePage::Count; i++, indicator_x += 18) { + M5.Lcd.fillRoundRect(indicator_x, 30, (i == _page) ? 12 : 6, 6, 3, (i == _page) ? TFT_CYAN : TFT_DARKGREY); + } + + if (_page == HomePage::FIRST) { + drawCore2NerdCentered(display.width() / 2, 56, "MESSAGES", TFT_YELLOW); + snprintf(tmp_core, sizeof(tmp_core), "%d", _task->getMsgCount()); + drawCore2ValueCentered(display.width() / 2, 84, tmp_core, TFT_WHITE); + + if (_task->hasConnection()) { + drawCore2NerdCentered(display.width() / 2, 142, "CONNECTED", TFT_GREEN); + } else if (the_mesh.getBLEPin() != 0) { + snprintf(tmp_core, sizeof(tmp_core), "PIN %d", the_mesh.getBLEPin()); + drawCore2NerdCentered(display.width() / 2, 142, tmp_core, TFT_RED); + } + +#ifdef WIFI_SSID + IPAddress ip = WiFi.localIP(); + snprintf(tmp_core, sizeof(tmp_core), "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + drawCore2NerdCentered(display.width() / 2, 172, tmp_core, TFT_WHITE); +#endif + drawCore2NerdCentered(display.width() / 2, 202, "SWIPE FOR PANELS", TFT_DARKGREY); + return 5000; + } + + if (_page == HomePage::RECENT) { + the_mesh.getRecentlyHeard(recent, UI_RECENT_LIST_SIZE); + drawCore2NerdCentered(display.width() / 2, 48, "RECENT NODES", TFT_YELLOW); + int row_y = 78; + for (int i = 0; i < UI_RECENT_LIST_SIZE; i++, row_y += 34) { + auto a = &recent[i]; + if (a->name[0] == 0) continue; + int secs = _rtc->getCurrentTime() - a->recv_timestamp; + if (secs < 60) snprintf(tmp_core, sizeof(tmp_core), "%ds", secs); + else if (secs < 3600) snprintf(tmp_core, sizeof(tmp_core), "%dm", secs / 60); + else snprintf(tmp_core, sizeof(tmp_core), "%dh", secs / 3600); + + char filtered_recent_name[sizeof(a->name)]; + display.translateUTF8ToBlocks(filtered_recent_name, a->name, sizeof(filtered_recent_name)); + drawCore2NerdEllipsized(12, row_y, display.width() - proto_nerd_font::textWidth(tmp_core, 1) - 28, filtered_recent_name, TFT_GREEN); + drawCore2NerdRight(display.width() - 12, row_y, tmp_core, TFT_WHITE); + } + return 5000; + } + + if (_page == HomePage::RADIO) { + drawCore2NerdCentered(display.width() / 2, 48, "RADIO", TFT_YELLOW); + snprintf(tmp_core, sizeof(tmp_core), "FREQ %.3f", _node_prefs->freq); + drawCore2NerdText(16, 82, tmp_core, TFT_WHITE); + snprintf(tmp_core, sizeof(tmp_core), "SF %d BW %.2f", _node_prefs->sf, _node_prefs->bw); + drawCore2NerdText(16, 114, tmp_core, TFT_WHITE); + snprintf(tmp_core, sizeof(tmp_core), "CR %d TX %ddBm", _node_prefs->cr, _node_prefs->tx_power_dbm); + drawCore2NerdText(16, 146, tmp_core, TFT_WHITE); + snprintf(tmp_core, sizeof(tmp_core), "NOISE FLOOR %d", radio_driver.getNoiseFloor()); + drawCore2NerdText(16, 178, tmp_core, TFT_WHITE); + return 5000; + } + + if (_page == HomePage::BLUETOOTH) { + M5.Lcd.drawXBitmap((display.width() - 32) / 2, 70, + _task->isSerialEnabled() ? bluetooth_on : bluetooth_off, + 32, 32, TFT_GREEN); + drawCore2NerdCentered(display.width() / 2, 48, "BLUETOOTH", TFT_YELLOW); + drawCore2NerdCentered(display.width() / 2, 148, _task->isSerialEnabled() ? "ENABLED" : "DISABLED", TFT_WHITE); + drawCore2NerdCentered(display.width() / 2, 198, "LONG PRESS TO TOGGLE", TFT_DARKGREY); + return 5000; + } + + if (_page == HomePage::ADVERT) { + M5.Lcd.drawXBitmap((display.width() - 32) / 2, 70, advert_icon, 32, 32, TFT_GREEN); + drawCore2NerdCentered(display.width() / 2, 48, "ADVERT", TFT_YELLOW); + drawCore2NerdCentered(display.width() / 2, 148, "SEND NODE ADVERT", TFT_WHITE); + drawCore2NerdCentered(display.width() / 2, 198, "LONG PRESS TO SEND", TFT_DARKGREY); + return 5000; + } +#if defined(ARDUINO_M5STACK_CORE2) + if (_page == HomePage::STORAGE) { + const bool mounted = (SD.cardType() != CARD_NONE) && (SD.totalBytes() > 0); + const uint64_t total_bytes = mounted ? SD.totalBytes() : 0; + const uint64_t used_bytes = mounted ? SD.usedBytes() : 0; + char total_buf[24]; + char used_buf[24]; + formatStorageBytes(total_buf, sizeof(total_buf), total_bytes); + formatStorageBytes(used_buf, sizeof(used_buf), used_bytes); + + M5.Lcd.drawXBitmap((display.width() - 32) / 2, 62, sdcard_icon, 32, 32, TFT_GREEN); + drawCore2NerdCentered(display.width() / 2, 48, "STORAGE", TFT_YELLOW); + drawCore2NerdText(16, 118, "STATE", TFT_GREEN); + drawCore2NerdRight(display.width() - 16, 118, mounted ? "MOUNTED" : "NOT MOUNTED", mounted ? TFT_WHITE : TFT_RED); + drawCore2NerdText(16, 150, "USED", TFT_GREEN); + drawCore2NerdRight(display.width() - 16, 150, used_buf, TFT_WHITE); + drawCore2NerdText(16, 182, "TOTAL", TFT_GREEN); + drawCore2NerdRight(display.width() - 16, 182, total_buf, TFT_WHITE); + return 5000; + } +#endif +#if ENV_INCLUDE_GPS == 1 + if (_page == HomePage::GPS) { + LocationProvider* nmea = sensors.getLocationProvider(); + char buf[50]; + int row_y = 50; + bool gps_state = _task->getGPSState(); + drawCore2NerdCentered(display.width() / 2, 20, "GPS", TFT_YELLOW); +#ifdef PIN_GPS_SWITCH + bool hw_gps_state = digitalRead(PIN_GPS_SWITCH); + if (gps_state != hw_gps_state) strcpy(buf, gps_state ? "OFF (HW)" : "OFF (SW)"); + else strcpy(buf, gps_state ? "ON" : "OFF"); +#else + strcpy(buf, gps_state ? "ON" : "OFF"); +#endif + drawCore2NerdText(16, row_y, "STATE", TFT_GREEN); + drawCore2NerdRight(display.width() - 16, row_y, buf, TFT_WHITE); + row_y += 32; + if (nmea == NULL) { + drawCore2NerdCentered(display.width() / 2, row_y, "CAN'T ACCESS GPS", TFT_RED); + } else { + drawCore2NerdText(16, row_y, "FIX", TFT_GREEN); + drawCore2NerdRight(display.width() - 16, row_y, nmea->isValid() ? "YES" : "NO", TFT_WHITE); + row_y += 32; + drawCore2NerdText(16, row_y, "SAT", TFT_GREEN); + snprintf(buf, sizeof(buf), "%d", nmea->satellitesCount()); + drawCore2NerdRight(display.width() - 16, row_y, buf, TFT_WHITE); + row_y += 32; + drawCore2NerdText(16, row_y, "POS", TFT_GREEN); + snprintf(buf, sizeof(buf), "%.4f %.4f", nmea->getLatitude()/1000000., nmea->getLongitude()/1000000.); + drawCore2NerdRight(display.width() - 16, row_y, buf, TFT_WHITE); + row_y += 32; + drawCore2NerdText(16, row_y, "ALT", TFT_GREEN); + snprintf(buf, sizeof(buf), "%.2f", nmea->getAltitude()/1000.); + drawCore2NerdRight(display.width() - 16, row_y, buf, TFT_WHITE); + } + return 5000; + } +#endif +#if UI_SENSORS_PAGE == 1 + if (_page == HomePage::SENSORS) { + int y = 50; + refresh_sensors(); + char buf[30]; + char name[30]; + LPPReader r(sensors_lpp.getBuffer(), sensors_lpp.getSize()); + drawCore2NerdCentered(display.width() / 2, 20, "SENSORS", TFT_YELLOW); + + for (int i = 0; i < sensors_scroll_offset; i++) { + uint8_t channel, type; + r.readHeader(channel, type); + r.skipData(type); + } + + for (int i = 0; i < (sensors_scroll ? UI_RECENT_LIST_SIZE : sensors_nb); i++) { + uint8_t channel, type; + if (!r.readHeader(channel, type)) { + r.reset(); + r.readHeader(channel, type); + } + + float v; + switch (type) { + case LPP_GPS: { float lat, lon, alt; r.readGPS(lat, lon, alt); strcpy(name, "gps"); sprintf(buf, "%.4f %.4f", lat, lon); break; } + case LPP_VOLTAGE: r.readVoltage(v); strcpy(name, "voltage"); sprintf(buf, "%6.2f", v); break; + case LPP_CURRENT: r.readCurrent(v); strcpy(name, "current"); sprintf(buf, "%.3f", v); break; + case LPP_TEMPERATURE: r.readTemperature(v); strcpy(name, "temperature"); sprintf(buf, "%.2f", v); break; + case LPP_RELATIVE_HUMIDITY: r.readRelativeHumidity(v); strcpy(name, "humidity"); sprintf(buf, "%.2f", v); break; + case LPP_BAROMETRIC_PRESSURE: r.readPressure(v); strcpy(name, "pressure"); sprintf(buf, "%.2f", v); break; + case LPP_ALTITUDE: r.readAltitude(v); strcpy(name, "altitude"); sprintf(buf, "%.0f", v); break; + case LPP_POWER: r.readPower(v); strcpy(name, "power"); sprintf(buf, "%6.2f", v); break; + default: r.skipData(type); strcpy(name, "unk"); sprintf(buf, ""); + } + drawCore2NerdText(12, y, name, TFT_GREEN); + drawCore2NerdRight(display.width() - 12, y, buf, TFT_WHITE); + y += 28; + } + if (sensors_scroll) sensors_scroll_offset = (sensors_scroll_offset + 1) % sensors_nb; + else sensors_scroll_offset = 0; + return 5000; + } +#endif + drawCore2NerdCentered(display.width() / 2, 48, "POWER", TFT_YELLOW); + if (_shutdown_init) { + drawCore2NerdCentered(display.width() / 2, 148, "HIBERNATING...", TFT_WHITE); + } else { + M5.Lcd.drawXBitmap((display.width() - 32) / 2, 70, power_icon, 32, 32, TFT_GREEN); + drawCore2NerdCentered(display.width() / 2, 148, "ENTER HIBERNATE", TFT_WHITE); + drawCore2NerdCentered(display.width() / 2, 198, "LONG PRESS TO CONFIRM", TFT_DARKGREY); + } + return 5000; +#endif + char tmp[80]; // node name display.setTextSize(1); @@ -289,6 +642,25 @@ class HomeScreen : public UIScreen { display.setColor(DisplayDriver::GREEN); display.drawXbm((display.width() - 32) / 2, 18, advert_icon, 32, 32); display.drawTextCentered(display.width() / 2, 64 - 11, "advert: " PRESS_LABEL); +#if defined(ARDUINO_M5STACK_CORE2) + } else if (_page == HomePage::STORAGE) { + const bool mounted = (SD.cardType() != CARD_NONE) && (SD.totalBytes() > 0); + const uint64_t total_bytes = mounted ? SD.totalBytes() : 0; + const uint64_t used_bytes = mounted ? SD.usedBytes() : 0; + char total_buf[24]; + char used_buf[24]; + formatStorageBytes(total_buf, sizeof(total_buf), total_bytes); + formatStorageBytes(used_buf, sizeof(used_buf), used_bytes); + + display.setColor(DisplayDriver::GREEN); + display.drawXbm((display.width() - 32) / 2, 18, sdcard_icon, 32, 32); + display.setTextSize(1); + display.drawTextCentered(display.width() / 2, 64 - 11, mounted ? "mounted" : "not mounted"); + display.drawTextLeftAlign(0, 92, "used"); + display.drawTextRightAlign(display.width() - 1, 92, used_buf); + display.drawTextLeftAlign(0, 104, "total"); + display.drawTextRightAlign(display.width() - 1, 104, total_buf); +#endif #if ENV_INCLUDE_GPS == 1 } else if (_page == HomePage::GPS) { LocationProvider* nmea = sensors.getLocationProvider(); @@ -472,7 +844,9 @@ class MsgPreviewScreen : public UIScreen { char origin[62]; char msg[78]; }; - #define MAX_UNREAD_MSGS 32 + #ifndef MAX_UNREAD_MSGS + #define MAX_UNREAD_MSGS 32 + #endif int num_unread; int head = MAX_UNREAD_MSGS - 1; // index of latest unread message MsgEntry unread[MAX_UNREAD_MSGS]; @@ -495,6 +869,40 @@ class MsgPreviewScreen : public UIScreen { } int render(DisplayDriver& display) override { +#if defined(ARDUINO_M5STACK_CORE2) + M5.Lcd.fillScreen(TFT_BLACK); + char tmp_core[16]; + drawCore2NerdText(10, 8, "UNREAD", TFT_GREEN); + snprintf(tmp_core, sizeof(tmp_core), "%d", num_unread); + drawCore2NerdRight(display.width() - 10, 8, tmp_core, TFT_GREEN); + + auto preview = &unread[head]; + int preview_secs = _rtc->getCurrentTime() - preview->timestamp; + if (preview_secs < 60) { + snprintf(tmp_core, sizeof(tmp_core), "%ds", preview_secs); + } else if (preview_secs < 60*60) { + snprintf(tmp_core, sizeof(tmp_core), "%dm", preview_secs / 60); + } else { + snprintf(tmp_core, sizeof(tmp_core), "%dh", preview_secs / (60*60)); + } + drawCore2NerdRight(display.width() - 10, 30, tmp_core, TFT_DARKGREY); + M5.Lcd.drawFastHLine(10, 54, display.width() - 20, TFT_DARKGREY); + + char filtered_origin_core[sizeof(preview->origin)]; + display.translateUTF8ToBlocks(filtered_origin_core, preview->origin, sizeof(filtered_origin_core)); + drawCore2NerdEllipsized(10, 70, display.width() - 20, filtered_origin_core, TFT_YELLOW); + + char filtered_msg_core[sizeof(preview->msg)]; + display.translateUTF8ToBlocks(filtered_msg_core, preview->msg, sizeof(filtered_msg_core)); + drawCore2NerdWrapped(10, 102, display.width() - 20, filtered_msg_core, TFT_WHITE, 22); + +#if AUTO_OFF_MILLIS==0 + return 10000; +#else + return 1000; +#endif +#endif + char tmp[16]; display.setCursor(0, 0); display.setTextSize(1); @@ -591,6 +999,65 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no setCurrScreen(splash); } +#if defined(ARDUINO_M5STACK_CORE2) +char UITask::handleCore2TouchToggle() { + M5.update(); + char action = 0; + const bool pressed = (M5.Touch.points > 0); + const unsigned long now = millis(); + + if (pressed) { + _core2_touch_last_x = M5.Touch.point[0].x; + _core2_touch_last_y = M5.Touch.point[0].y; + } + + if (pressed && !_core2_touch_was_pressed) { + if (_display != NULL && !_display->isOn()) { + _display->turnOn(); + _auto_off = now + AUTO_OFF_MILLIS; + _next_refresh = 0; + CORE2_TOUCH_TRACE("wake-on-touch"); + } + _core2_touch_press_started_at = now; + _core2_touch_longpress_fired = false; + _core2_touch_start_x = _core2_touch_last_x; + _core2_touch_start_y = _core2_touch_last_y; + CORE2_TOUCH_TRACE("down x=%d y=%d points=%d display_on=%d", _core2_touch_start_x, _core2_touch_start_y, M5.Touch.points, (_display != NULL && _display->isOn()) ? 1 : 0); + } + + if (pressed && !_core2_touch_longpress_fired && now >= _core2_touch_debounce_until) { + if ((uint32_t)(now - _core2_touch_press_started_at) >= CORE2_MODE_SWITCH_LONG_PRESS_MILLIS) { + _core2_touch_longpress_fired = true; + _core2_touch_debounce_until = now + 250; + action = KEY_ENTER; + CORE2_TOUCH_TRACE("long-press panel-action"); + + _next_refresh = 0; + _auto_off = millis() + AUTO_OFF_MILLIS; + } + } + + if (!pressed && _core2_touch_was_pressed) { + if (!_core2_touch_longpress_fired && curr == home) { + const int dx = _core2_touch_last_x - _core2_touch_start_x; + const int dy = _core2_touch_last_y - _core2_touch_start_y; + if (abs(dx) >= CORE2_SWIPE_MIN_DX && abs(dy) <= CORE2_SWIPE_MAX_DY) { + action = (dx < 0) ? KEY_RIGHT : KEY_LEFT; + CORE2_TOUCH_TRACE("swipe dx=%d dy=%d action=%s", dx, dy, dx < 0 ? "right" : "left"); + } + else { + CORE2_TOUCH_TRACE("release dx=%d dy=%d no-swipe", dx, dy); + } + } else { + CORE2_TOUCH_TRACE("release longpress=%d", _core2_touch_longpress_fired ? 1 : 0); + } + } + + _core2_touch_was_pressed = pressed; + return action; +} +#endif + void UITask::showAlert(const char* text, int duration_millis) { strcpy(_alert, text); _alert_expiry = millis() + duration_millis; @@ -713,6 +1180,9 @@ bool UITask::isButtonPressed() const { void UITask::loop() { char c = 0; +#if defined(ARDUINO_M5STACK_CORE2) + c = handleCore2TouchToggle(); +#endif #if UI_HAS_JOYSTICK int ev = user_btn.check(); if (ev == BUTTON_EVENT_CLICK) { @@ -790,23 +1260,25 @@ void UITask::loop() { if (curr) curr->poll(); if (_display != NULL && _display->isOn()) { - if (millis() >= _next_refresh && curr) { - _display->startFrame(); - int delay_millis = curr->render(*_display); - if (millis() < _alert_expiry) { // render alert popup - _display->setTextSize(1); - int y = _display->height() / 3; - int p = _display->height() / 32; - _display->setColor(DisplayDriver::DARK); - _display->fillRect(p, y, _display->width() - p*2, y); - _display->setColor(DisplayDriver::LIGHT); // draw box border - _display->drawRect(p, y, _display->width() - p*2, y); - _display->drawTextCentered(_display->width() / 2, y + p*3, _alert); - _next_refresh = _alert_expiry; // will need refresh when alert is dismissed - } else { - _next_refresh = millis() + delay_millis; + if (millis() >= _next_refresh) { + if (curr) { + _display->startFrame(); + int delay_millis = curr->render(*_display); + if (millis() < _alert_expiry) { // render alert popup + _display->setTextSize(1); + int y = _display->height() / 3; + int p = _display->height() / 32; + _display->setColor(DisplayDriver::DARK); + _display->fillRect(p, y, _display->width() - p*2, y); + _display->setColor(DisplayDriver::LIGHT); // draw box border + _display->drawRect(p, y, _display->width() - p*2, y); + _display->drawTextCentered(_display->width() / 2, y + p*3, _alert); + _next_refresh = _alert_expiry; // will need refresh when alert is dismissed + } else { + _next_refresh = millis() + delay_millis; + } + _display->endFrame(); } - _display->endFrame(); } #if AUTO_OFF_MILLIS > 0 #ifdef KEEP_DISPLAY_ON_USB @@ -819,6 +1291,7 @@ void UITask::loop() { } #endif if (millis() > _auto_off) { + CORE2_TOUCH_TRACE("display auto-off"); _display->turnOff(); } #endif diff --git a/examples/companion_radio/ui-new/UITask.h b/examples/companion_radio/ui-new/UITask.h index a77ad6e7ec..7d1b46ba98 100644 --- a/examples/companion_radio/ui-new/UITask.h +++ b/examples/companion_radio/ui-new/UITask.h @@ -38,6 +38,16 @@ class UITask : public AbstractUITask { int _msgcount; unsigned long ui_started_at, next_batt_chck; int next_backlight_btn_check = 0; +#if defined(ARDUINO_M5STACK_CORE2) + bool _core2_touch_was_pressed = false; + bool _core2_touch_longpress_fired = false; + unsigned long _core2_touch_press_started_at = 0; + unsigned long _core2_touch_debounce_until = 0; + int16_t _core2_touch_start_x = 0; + int16_t _core2_touch_start_y = 0; + int16_t _core2_touch_last_x = 0; + int16_t _core2_touch_last_y = 0; +#endif #ifdef PIN_STATUS_LED int led_state = 0; int next_led_change = 0; @@ -63,6 +73,10 @@ class UITask : public AbstractUITask { void setCurrScreen(UIScreen* c); +#if defined(ARDUINO_M5STACK_CORE2) + char handleCore2TouchToggle(); +#endif + public: UITask(mesh::MainBoard* board, BaseSerialInterface* serial) : AbstractUITask(board, serial), _display(NULL), _sensors(NULL) { diff --git a/examples/companion_radio/ui-new/icons.h b/examples/companion_radio/ui-new/icons.h index cbe237902d..7a327ef079 100644 --- a/examples/companion_radio/ui-new/icons.h +++ b/examples/companion_radio/ui-new/icons.h @@ -119,4 +119,36 @@ static const uint8_t advert_icon[] = { static const uint8_t muted_icon[] = { 0x20, 0x6a, 0xea, 0xe4, 0xe4, 0xea, 0x6a, 0x20 +}; + +static const uint8_t sdcard_icon[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0x80, 0x00, 0x00, 0xff, 0xc0, + 0x00, 0x01, 0x80, 0x60, 0x00, 0x03, 0x00, 0x30, + 0x00, 0x06, 0x7e, 0x38, 0x00, 0x0c, 0xff, 0x98, + 0x00, 0x19, 0x81, 0xcc, 0x00, 0x33, 0x00, 0xcc, + 0x00, 0x66, 0x00, 0x66, 0x00, 0xcc, 0x00, 0x66, + 0x00, 0xcc, 0x00, 0x66, 0x00, 0xcc, 0x00, 0x66, + 0x00, 0xcc, 0x00, 0x66, 0x00, 0xcc, 0x00, 0x66, + 0x00, 0xcc, 0x00, 0x66, 0x00, 0xcc, 0x00, 0x66, + 0x00, 0xcc, 0x00, 0x66, 0x00, 0xcc, 0x00, 0x66, + 0x00, 0xcc, 0x00, 0x66, 0x00, 0xcc, 0x00, 0x66, + 0x00, 0xcc, 0x00, 0x66, 0x00, 0xcc, 0x00, 0x66, + 0x00, 0xcc, 0x00, 0x66, 0x00, 0xcc, 0x00, 0x66, + 0x00, 0xcc, 0x00, 0x66, 0x00, 0xcc, 0x00, 0x66, + 0x00, 0xcc, 0x00, 0x66, 0x00, 0xcc, 0x00, 0x66, + 0x00, 0x66, 0x00, 0xcc, 0x00, 0x33, 0x00, 0xcc, + 0x00, 0x19, 0x81, 0x98, 0x00, 0x0c, 0xff, 0x30, + 0x00, 0x06, 0x7e, 0x60, 0x00, 0x03, 0x00, 0xc0, + 0x00, 0x01, 0x80, 0x80, 0x00, 0x00, 0xff, 0x00, + 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, }; \ No newline at end of file diff --git a/variants/m5stack_core2_lora868_v11_lan_poe_env4/Core2M5Display.cpp b/variants/m5stack_core2_lora868_v11_lan_poe_env4/Core2M5Display.cpp new file mode 100644 index 0000000000..5cc49a3721 --- /dev/null +++ b/variants/m5stack_core2_lora868_v11_lan_poe_env4/Core2M5Display.cpp @@ -0,0 +1,135 @@ +#include "Core2M5Display.h" +#include + +#ifdef RED +#undef RED +#endif +#ifdef GREEN +#undef GREEN +#endif +#ifdef BLUE +#undef BLUE +#endif +#ifdef YELLOW +#undef YELLOW +#endif +#ifdef ORANGE +#undef ORANGE +#endif + +namespace { +bool s_core2_initialized = false; +constexpr uint8_t kCore2BrightnessMax = 255; + +void enforceCore2DisplayPower() { + M5.Axp.SetLcdVoltage(2800); + M5.Axp.SetVibration(false); + M5.Axp.SetLed(0); + M5.Axp.SetSpkEnable(false); +} +} + +uint16_t Core2M5Display::toColor(Color c) const { + switch (c) { + case DARK: + return TFT_BLACK; + case LIGHT: + return TFT_WHITE; + case RED: + return TFT_RED; + case GREEN: + return TFT_GREEN; + case BLUE: + return TFT_BLUE; + case YELLOW: + return TFT_YELLOW; + case ORANGE: + return TFT_ORANGE; + default: + return TFT_WHITE; + } +} + +bool Core2M5Display::begin() { + if (!s_core2_initialized) { + M5.begin(true, true, true, false, kMBusModeOutput, false); + M5.Axp.SetCHGCurrent(AXP192::kCHG_190mA); + M5.Axp.SetVibration(false); + M5.Axp.SetLed(0); + M5.Axp.SetSpkEnable(false); + s_core2_initialized = true; + } + M5.update(); + enforceCore2DisplayPower(); + M5.Axp.ScreenBreath(kCore2BrightnessMax); + M5.Lcd.setRotation(1); + M5.Lcd.fillScreen(TFT_BLACK); + M5.Lcd.setTextSize(1); + Serial.printf("LCD: M5Core2 init bl=%u\n", static_cast(kCore2BrightnessMax)); + setColor(LIGHT); + turnOn(); + return true; +} + +void Core2M5Display::turnOn() { + enforceCore2DisplayPower(); + M5.Axp.ScreenBreath(kCore2BrightnessMax); + _isOn = true; +} + +void Core2M5Display::turnOff() { + M5.Axp.SetVibration(false); + _isOn = false; +} + +void Core2M5Display::clear() { + M5.Lcd.fillScreen(TFT_BLACK); +} + +void Core2M5Display::startFrame(Color bkg) { + M5.Lcd.startWrite(); + M5.Lcd.fillScreen(toColor(bkg)); + setColor(LIGHT); +} + +void Core2M5Display::setTextSize(int sz) { + M5.Lcd.setTextSize(sz); +} + +void Core2M5Display::setColor(Color c) { + _color = toColor(c); + M5.Lcd.setTextColor(_color); +} + +void Core2M5Display::setCursor(int x, int y) { + _cursor_x = x; + _cursor_y = y; + M5.Lcd.setCursor(x, y); +} + +void Core2M5Display::print(const char* str) { + M5.Lcd.setCursor(_cursor_x, _cursor_y); + M5.Lcd.print(str); + _cursor_x = M5.Lcd.getCursorX(); + _cursor_y = M5.Lcd.getCursorY(); +} + +void Core2M5Display::fillRect(int x, int y, int w, int h) { + M5.Lcd.fillRect(x, y, w, h, _color); +} + +void Core2M5Display::drawRect(int x, int y, int w, int h) { + M5.Lcd.drawRect(x, y, w, h, _color); +} + +void Core2M5Display::drawXbm(int x, int y, const uint8_t* bits, int w, int h) { + M5.Lcd.drawXBitmap(x, y, bits, w, h, _color); +} + +uint16_t Core2M5Display::getTextWidth(const char* str) { + return M5.Lcd.textWidth(str); +} + +void Core2M5Display::endFrame() { + M5.Lcd.endWrite(); +} diff --git a/variants/m5stack_core2_lora868_v11_lan_poe_env4/Core2M5Display.h b/variants/m5stack_core2_lora868_v11_lan_poe_env4/Core2M5Display.h new file mode 100644 index 0000000000..7b2a0c6794 --- /dev/null +++ b/variants/m5stack_core2_lora868_v11_lan_poe_env4/Core2M5Display.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +class Core2M5Display : public DisplayDriver { + bool _isOn = false; + uint16_t _color = TFT_WHITE; + int _cursor_x = 0; + int _cursor_y = 0; + + uint16_t toColor(Color c) const; + +public: + Core2M5Display() : DisplayDriver(320, 240) {} + + bool isOn() override { return _isOn; } + void turnOn() override; + void turnOff() override; + void clear() override; + bool begin(); + void startFrame(Color bkg = DARK) override; + void setTextSize(int sz) override; + void setColor(Color c) override; + void setCursor(int x, int y) override; + void print(const char* str) override; + void fillRect(int x, int y, int w, int h) override; + void drawRect(int x, int y, int w, int h) override; + void drawXbm(int x, int y, const uint8_t* bits, int w, int h) override; + uint16_t getTextWidth(const char* str) override; + void endFrame() override; +}; diff --git a/variants/m5stack_core2_lora868_v11_lan_poe_env4/ProtoNerdFont.cpp b/variants/m5stack_core2_lora868_v11_lan_poe_env4/ProtoNerdFont.cpp new file mode 100644 index 0000000000..ac747b6ad3 --- /dev/null +++ b/variants/m5stack_core2_lora868_v11_lan_poe_env4/ProtoNerdFont.cpp @@ -0,0 +1,92 @@ +#include "ProtoNerdFont.h" + +#include "ProtoNerdFontData.h" + +namespace proto_nerd_font { + +static uint8_t normalizeChar(char c) { + uint8_t uc = static_cast(c); + if (uc < kFirst || uc > kLast) { + return static_cast('?'); + } + return uc; +} + +int textWidth(const char* text, uint8_t scale) { + if (!text || !*text) { + return 0; + } + int count = 0; + for (const char* p = text; *p; ++p) { + ++count; + } + return count * static_cast(kCellWidth) * static_cast(scale); +} + +void drawText(M5Display& lcd, int x, int y, const char* text, uint16_t fg, uint16_t bg, uint8_t scale) { + if (!text || !*text) { + return; + } + + const int cell_w = static_cast(kCellWidth) * static_cast(scale); + const int cell_h = static_cast(kCellHeight) * static_cast(scale); + + int cx = x; + for (const char* p = text; *p; ++p) { + uint8_t ch = normalizeChar(*p); + uint16_t glyph_index = static_cast(ch - kFirst); + uint32_t off = static_cast(glyph_index) * static_cast(kBytesPerGlyph); + + // Erase glyph cell first to provide deterministic redraw and prevent ghosting. + lcd.fillRect(cx, y, cell_w, cell_h, bg); + + for (uint8_t row = 0; row < kCellHeight; ++row) { + for (uint8_t col = 0; col < kCellWidth; ++col) { + uint32_t byte_idx = off + static_cast(row) * static_cast(kBytesPerRow) + (col >> 3); + uint8_t bit = static_cast(0x80 >> (col & 7)); + if (kBitmap[byte_idx] & bit) { + if (scale == 1) { + lcd.drawPixel(cx + col, y + row, fg); + } else { + lcd.fillRect(cx + static_cast(col) * scale, y + static_cast(row) * scale, scale, scale, fg); + } + } + } + } + + cx += cell_w; + } +} + +void drawTextTransparent(M5Display& lcd, int x, int y, const char* text, uint16_t fg, uint8_t scale) { + if (!text || !*text) { + return; + } + + const int cell_w = static_cast(kCellWidth) * static_cast(scale); + + int cx = x; + for (const char* p = text; *p; ++p) { + uint8_t ch = normalizeChar(*p); + uint16_t glyph_index = static_cast(ch - kFirst); + uint32_t off = static_cast(glyph_index) * static_cast(kBytesPerGlyph); + + for (uint8_t row = 0; row < kCellHeight; ++row) { + for (uint8_t col = 0; col < kCellWidth; ++col) { + uint32_t byte_idx = off + static_cast(row) * static_cast(kBytesPerRow) + (col >> 3); + uint8_t bit = static_cast(0x80 >> (col & 7)); + if (kBitmap[byte_idx] & bit) { + if (scale == 1) { + lcd.drawPixel(cx + col, y + row, fg); + } else { + lcd.fillRect(cx + static_cast(col) * scale, y + static_cast(row) * scale, scale, scale, fg); + } + } + } + } + + cx += cell_w; + } +} + +} // namespace proto_nerd_font diff --git a/variants/m5stack_core2_lora868_v11_lan_poe_env4/ProtoNerdFont.h b/variants/m5stack_core2_lora868_v11_lan_poe_env4/ProtoNerdFont.h new file mode 100644 index 0000000000..c29da3b7ec --- /dev/null +++ b/variants/m5stack_core2_lora868_v11_lan_poe_env4/ProtoNerdFont.h @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +namespace proto_nerd_font { + +int textWidth(const char* text, uint8_t scale = 1); +void drawText(M5Display& lcd, int x, int y, const char* text, uint16_t fg, uint16_t bg, uint8_t scale = 1); +void drawTextTransparent(M5Display& lcd, int x, int y, const char* text, uint16_t fg, uint8_t scale = 1); + +} // namespace proto_nerd_font diff --git a/variants/m5stack_core2_lora868_v11_lan_poe_env4/ProtoNerdFontData.h b/variants/m5stack_core2_lora868_v11_lan_poe_env4/ProtoNerdFontData.h new file mode 100644 index 0000000000..b73fedcfdf --- /dev/null +++ b/variants/m5stack_core2_lora868_v11_lan_poe_env4/ProtoNerdFontData.h @@ -0,0 +1,2013 @@ +#pragma once +#include + +namespace proto_nerd_font { +static constexpr uint8_t kFirst = 32; +static constexpr uint8_t kLast = 126; +static constexpr uint8_t kCellWidth = 11; +static constexpr uint8_t kCellHeight = 20; +static constexpr uint8_t kBytesPerRow = 2; +static constexpr uint16_t kBytesPerGlyph= 40; +static constexpr uint8_t kAscent = 16; +static constexpr uint8_t kDescent = 4; +static constexpr uint8_t kLineHeight = 20; + +static const uint8_t kBitmap[] = { + // 'U+0020' + 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, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '!' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x00, 0x00, + 0x06, 0x00, + 0x0E, 0x00, + 0x0E, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '"' + 0x00, 0x00, + 0x00, 0x00, + 0x1B, 0x00, + 0x19, 0x00, + 0x19, 0x00, + 0x19, 0x00, + 0x19, 0x00, + 0x11, 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, + 0x0C, 0x80, + 0x0C, 0x80, + 0x09, 0x80, + 0x3F, 0xC0, + 0x3F, 0xC0, + 0x19, 0x00, + 0x19, 0x00, + 0x13, 0x00, + 0x7F, 0xC0, + 0x7F, 0xC0, + 0x32, 0x00, + 0x32, 0x00, + 0x26, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '$' + 0x00, 0x00, + 0x00, 0x00, + 0x04, 0x00, + 0x0E, 0x00, + 0x1F, 0x80, + 0x35, 0xC0, + 0x24, 0xC0, + 0x24, 0x00, + 0x34, 0x00, + 0x3F, 0x00, + 0x0F, 0x80, + 0x05, 0xC0, + 0x04, 0xC0, + 0x64, 0xC0, + 0x35, 0xC0, + 0x3F, 0x80, + 0x0E, 0x00, + 0x04, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '%' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x38, 0x00, + 0x7C, 0x00, + 0x6C, 0x00, + 0x6C, 0x40, + 0x78, 0xC0, + 0x33, 0x00, + 0x06, 0x00, + 0x19, 0x80, + 0x33, 0xC0, + 0x46, 0x40, + 0x46, 0x40, + 0x03, 0xC0, + 0x03, 0x80, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '&' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x0E, 0x00, + 0x1F, 0x00, + 0x19, 0x00, + 0x19, 0x00, + 0x1B, 0x00, + 0x0E, 0x00, + 0x0C, 0x00, + 0x3E, 0xC0, + 0x33, 0x80, + 0x63, 0x80, + 0x63, 0x80, + 0x3E, 0xC0, + 0x1C, 0xE0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // ''' + 0x00, 0x00, + 0x00, 0x00, + 0x06, 0x00, + 0x04, 0x00, + 0x04, 0x00, + 0x04, 0x00, + 0x04, 0x00, + 0x04, 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, 0x80, + 0x03, 0x80, + 0x06, 0x00, + 0x0C, 0x00, + 0x0C, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x0C, 0x00, + 0x0C, 0x00, + 0x07, 0x00, + 0x03, 0x80, + 0x00, 0x80, + 0x00, 0x00, + // ')' + 0x00, 0x00, + 0x20, 0x00, + 0x38, 0x00, + 0x0E, 0x00, + 0x06, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x06, 0x00, + 0x0C, 0x00, + 0x38, 0x00, + 0x20, 0x00, + 0x00, 0x00, + // '*' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x06, 0x00, + 0x04, 0x00, + 0x44, 0x40, + 0x7D, 0xC0, + 0x1F, 0x00, + 0x0E, 0x00, + 0x1B, 0x00, + 0x39, 0x80, + 0x11, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '+' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x04, 0x00, + 0x04, 0x00, + 0x04, 0x00, + 0x7F, 0xC0, + 0x7F, 0xC0, + 0x04, 0x00, + 0x04, 0x00, + 0x04, 0x00, + 0x04, 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, + 0x00, 0x00, + 0x00, 0x00, + 0x0E, 0x00, + 0x0E, 0x00, + 0x0E, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x0C, 0x00, + 0x00, 0x00, + // '-' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x7F, 0xC0, + 0x7F, 0xC0, + 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, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x0E, 0x00, + 0x0E, 0x00, + 0x0E, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '/' + 0x00, 0x00, + 0x00, 0x00, + 0x01, 0x80, + 0x01, 0x80, + 0x01, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x02, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x04, 0x00, + 0x0C, 0x00, + 0x0C, 0x00, + 0x08, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x30, 0x00, + 0x30, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '0' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x1F, 0x00, + 0x3F, 0x80, + 0x30, 0xC0, + 0x60, 0xC0, + 0x61, 0xC0, + 0x63, 0xC0, + 0x6E, 0xC0, + 0x7C, 0xC0, + 0x70, 0xC0, + 0x60, 0xC0, + 0x30, 0xC0, + 0x3F, 0x80, + 0x1F, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '1' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x0E, 0x00, + 0x3E, 0x00, + 0x36, 0x00, + 0x26, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x3F, 0xC0, + 0x3F, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '2' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x0F, 0x00, + 0x3F, 0x80, + 0x30, 0xC0, + 0x60, 0xC0, + 0x00, 0xC0, + 0x00, 0xC0, + 0x01, 0x80, + 0x03, 0x00, + 0x0E, 0x00, + 0x1C, 0x00, + 0x30, 0x00, + 0x3F, 0xC0, + 0x3F, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '3' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x1F, 0x00, + 0x3F, 0x80, + 0x30, 0xC0, + 0x60, 0xC0, + 0x00, 0xC0, + 0x0F, 0x80, + 0x0F, 0x00, + 0x01, 0x80, + 0x00, 0xC0, + 0x60, 0xC0, + 0x30, 0xC0, + 0x3F, 0x80, + 0x1F, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '4' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x07, 0x00, + 0x0D, 0x00, + 0x0D, 0x00, + 0x19, 0x00, + 0x31, 0x00, + 0x31, 0x00, + 0x61, 0x00, + 0x7F, 0xC0, + 0x7F, 0xC0, + 0x01, 0x00, + 0x01, 0x00, + 0x01, 0x00, + 0x01, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '5' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x3F, 0xC0, + 0x3F, 0xC0, + 0x30, 0x00, + 0x30, 0x00, + 0x3F, 0x00, + 0x3F, 0x80, + 0x30, 0xC0, + 0x00, 0xC0, + 0x00, 0xC0, + 0x60, 0xC0, + 0x31, 0xC0, + 0x3F, 0x80, + 0x1F, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '6' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x03, 0x00, + 0x06, 0x00, + 0x0C, 0x00, + 0x18, 0x00, + 0x1E, 0x00, + 0x3F, 0x80, + 0x31, 0x80, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x30, 0xC0, + 0x3F, 0x80, + 0x1F, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '7' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x3F, 0x80, + 0x3F, 0x80, + 0x00, 0x80, + 0x01, 0x80, + 0x01, 0x80, + 0x03, 0x00, + 0x03, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x0C, 0x00, + 0x0C, 0x00, + 0x08, 0x00, + 0x18, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '8' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x1F, 0x00, + 0x3F, 0x80, + 0x60, 0xC0, + 0x60, 0xC0, + 0x20, 0xC0, + 0x3F, 0x80, + 0x1F, 0x80, + 0x31, 0x80, + 0x60, 0xC0, + 0x60, 0xC0, + 0x70, 0xC0, + 0x3F, 0x80, + 0x1F, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '9' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x1F, 0x00, + 0x3F, 0x80, + 0x30, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x31, 0xC0, + 0x3F, 0x80, + 0x0F, 0x00, + 0x03, 0x00, + 0x06, 0x00, + 0x0C, 0x00, + 0x1C, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // ':' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x0E, 0x00, + 0x0E, 0x00, + 0x0E, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x0E, 0x00, + 0x0E, 0x00, + 0x0E, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // ';' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x0E, 0x00, + 0x0E, 0x00, + 0x0E, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x0E, 0x00, + 0x0E, 0x00, + 0x0E, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x0C, 0x00, + 0x00, 0x00, + // '<' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x80, + 0x01, 0x80, + 0x07, 0x80, + 0x1E, 0x00, + 0x38, 0x00, + 0x20, 0x00, + 0x38, 0x00, + 0x0E, 0x00, + 0x03, 0x80, + 0x00, 0x80, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '=' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x7F, 0xC0, + 0x7F, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x7F, 0xC0, + 0x7F, 0xC0, + 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, 0x00, + 0x30, 0x00, + 0x3C, 0x00, + 0x0F, 0x00, + 0x01, 0x80, + 0x00, 0x80, + 0x03, 0x80, + 0x0F, 0x00, + 0x3C, 0x00, + 0x30, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '?' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x0F, 0x00, + 0x3F, 0x80, + 0x31, 0x80, + 0x20, 0x80, + 0x01, 0x80, + 0x03, 0x80, + 0x07, 0x00, + 0x06, 0x00, + 0x0C, 0x00, + 0x00, 0x00, + 0x0C, 0x00, + 0x0E, 0x00, + 0x0C, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '@' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x0F, 0x00, + 0x1F, 0x80, + 0x30, 0xC0, + 0x22, 0xC0, + 0x67, 0xC0, + 0x6C, 0xC0, + 0x6C, 0xC0, + 0x4C, 0xC0, + 0x4C, 0xC0, + 0x6C, 0xC0, + 0x67, 0xC0, + 0x67, 0xC0, + 0x20, 0x00, + 0x30, 0x00, + 0x1F, 0x00, + 0x0F, 0x00, + 0x00, 0x00, + // 'A' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x0E, 0x00, + 0x0E, 0x00, + 0x1B, 0x00, + 0x1B, 0x00, + 0x1B, 0x00, + 0x19, 0x00, + 0x31, 0x80, + 0x3F, 0x80, + 0x3F, 0x80, + 0x20, 0x80, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'B' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x3F, 0x00, + 0x3F, 0x80, + 0x30, 0xC0, + 0x30, 0xC0, + 0x30, 0xC0, + 0x3F, 0x80, + 0x3F, 0x80, + 0x30, 0xC0, + 0x30, 0xC0, + 0x30, 0xC0, + 0x30, 0xC0, + 0x3F, 0x80, + 0x3F, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'C' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x0F, 0x00, + 0x1F, 0x80, + 0x30, 0xC0, + 0x30, 0xC0, + 0x60, 0x40, + 0x60, 0x00, + 0x60, 0x00, + 0x60, 0x00, + 0x60, 0x00, + 0x20, 0xC0, + 0x30, 0xC0, + 0x1F, 0x80, + 0x0F, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'D' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x7F, 0x00, + 0x7F, 0x80, + 0x61, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x61, 0xC0, + 0x7F, 0x80, + 0x7F, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'E' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x3F, 0xC0, + 0x3F, 0xC0, + 0x30, 0x00, + 0x30, 0x00, + 0x30, 0x00, + 0x3F, 0x80, + 0x3F, 0x80, + 0x30, 0x00, + 0x30, 0x00, + 0x30, 0x00, + 0x30, 0x00, + 0x3F, 0xC0, + 0x3F, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'F' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x1F, 0xC0, + 0x1F, 0xC0, + 0x10, 0x00, + 0x10, 0x00, + 0x10, 0x00, + 0x10, 0x00, + 0x1F, 0x80, + 0x1F, 0x80, + 0x10, 0x00, + 0x10, 0x00, + 0x10, 0x00, + 0x10, 0x00, + 0x10, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'G' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x0F, 0x00, + 0x3F, 0x80, + 0x30, 0xC0, + 0x60, 0xC0, + 0x60, 0x00, + 0x60, 0x00, + 0x63, 0xC0, + 0x63, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x31, 0xC0, + 0x3F, 0xC0, + 0x1E, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'H' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x7F, 0xC0, + 0x7F, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'I' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x7F, 0xC0, + 0x7F, 0xC0, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x7F, 0xC0, + 0x7F, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'J' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x3F, 0x80, + 0x3F, 0x80, + 0x00, 0x80, + 0x00, 0x80, + 0x00, 0x80, + 0x00, 0x80, + 0x00, 0x80, + 0x60, 0x80, + 0x60, 0x80, + 0x60, 0x80, + 0x61, 0x80, + 0x3F, 0x80, + 0x1F, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'K' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x30, 0xC0, + 0x31, 0x80, + 0x33, 0x80, + 0x33, 0x00, + 0x36, 0x00, + 0x3C, 0x00, + 0x3C, 0x00, + 0x3C, 0x00, + 0x36, 0x00, + 0x37, 0x00, + 0x33, 0x00, + 0x31, 0x80, + 0x30, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'L' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x1F, 0xC0, + 0x1F, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'M' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x71, 0xC0, + 0x71, 0xC0, + 0x79, 0xC0, + 0x79, 0xC0, + 0x6B, 0xC0, + 0x6A, 0xC0, + 0x6A, 0xC0, + 0x6E, 0xC0, + 0x6E, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'N' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x78, 0xC0, + 0x78, 0xC0, + 0x68, 0xC0, + 0x6C, 0xC0, + 0x6C, 0xC0, + 0x6C, 0xC0, + 0x64, 0xC0, + 0x66, 0xC0, + 0x66, 0xC0, + 0x62, 0xC0, + 0x63, 0xC0, + 0x63, 0xC0, + 0x61, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'O' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x1F, 0x00, + 0x3F, 0x80, + 0x30, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x30, 0xC0, + 0x3F, 0x80, + 0x1F, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'P' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x3F, 0x80, + 0x3F, 0xC0, + 0x30, 0xC0, + 0x30, 0x40, + 0x30, 0x40, + 0x30, 0xC0, + 0x3F, 0x80, + 0x3F, 0x00, + 0x30, 0x00, + 0x30, 0x00, + 0x30, 0x00, + 0x30, 0x00, + 0x30, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'Q' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x1F, 0x00, + 0x3F, 0x80, + 0x30, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x39, 0x80, + 0x1F, 0x00, + 0x04, 0x00, + 0x07, 0x80, + 0x03, 0xC0, + 0x00, 0x40, + // 'R' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x3F, 0x00, + 0x3F, 0xC0, + 0x30, 0xC0, + 0x30, 0xC0, + 0x30, 0xC0, + 0x30, 0xC0, + 0x3F, 0x80, + 0x3E, 0x00, + 0x33, 0x00, + 0x33, 0x00, + 0x31, 0x80, + 0x30, 0xC0, + 0x30, 0xE0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'S' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x1F, 0x00, + 0x3F, 0x80, + 0x30, 0xC0, + 0x20, 0xC0, + 0x20, 0x00, + 0x38, 0x00, + 0x1F, 0x80, + 0x03, 0xC0, + 0x00, 0xC0, + 0x40, 0xC0, + 0x30, 0xC0, + 0x3F, 0x80, + 0x1F, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'T' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x7F, 0xC0, + 0x7F, 0xC0, + 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, + 0x00, 0x00, + 0x00, 0x00, + // 'U' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x31, 0xC0, + 0x3F, 0x80, + 0x1F, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'V' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x30, 0x80, + 0x31, 0x80, + 0x31, 0x80, + 0x31, 0x80, + 0x19, 0x00, + 0x1B, 0x00, + 0x1B, 0x00, + 0x1B, 0x00, + 0x0E, 0x00, + 0x0E, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'W' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0xC0, 0x60, + 0x40, 0x60, + 0x40, 0x60, + 0x4E, 0x40, + 0x6E, 0x40, + 0x6A, 0x40, + 0x6A, 0xC0, + 0x6A, 0xC0, + 0x6A, 0xC0, + 0x2B, 0xC0, + 0x2B, 0xC0, + 0x3B, 0x80, + 0x39, 0x80, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'X' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x60, 0xC0, + 0x30, 0xC0, + 0x31, 0x80, + 0x19, 0x80, + 0x1B, 0x00, + 0x0B, 0x00, + 0x0E, 0x00, + 0x0E, 0x00, + 0x1B, 0x00, + 0x1B, 0x00, + 0x31, 0x80, + 0x31, 0x80, + 0x60, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'Y' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x60, 0xE0, + 0x60, 0xC0, + 0x31, 0x80, + 0x11, 0x80, + 0x1B, 0x00, + 0x0B, 0x00, + 0x0E, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'Z' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x3F, 0xC0, + 0x3F, 0xC0, + 0x00, 0xC0, + 0x01, 0x80, + 0x03, 0x00, + 0x07, 0x00, + 0x0E, 0x00, + 0x0C, 0x00, + 0x18, 0x00, + 0x30, 0x00, + 0x20, 0x00, + 0x3F, 0xC0, + 0x3F, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '[' + 0x00, 0x00, + 0x0F, 0x80, + 0x0F, 0x80, + 0x08, 0x00, + 0x08, 0x00, + 0x08, 0x00, + 0x08, 0x00, + 0x08, 0x00, + 0x08, 0x00, + 0x08, 0x00, + 0x08, 0x00, + 0x08, 0x00, + 0x08, 0x00, + 0x08, 0x00, + 0x08, 0x00, + 0x08, 0x00, + 0x0F, 0x80, + 0x0F, 0x80, + 0x00, 0x00, + 0x00, 0x00, + // '\' + 0x00, 0x00, + 0x00, 0x00, + 0x30, 0x00, + 0x30, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x08, 0x00, + 0x0C, 0x00, + 0x0C, 0x00, + 0x04, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x02, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x01, 0x00, + 0x01, 0x80, + 0x01, 0x80, + 0x00, 0x00, + 0x00, 0x00, + // ']' + 0x00, 0x00, + 0x3F, 0x00, + 0x3F, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x3F, 0x00, + 0x3F, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '^' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x0E, 0x00, + 0x0F, 0x00, + 0x1B, 0x00, + 0x11, 0x80, + 0x31, 0x80, + 0x60, 0xC0, + 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, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x7F, 0xC0, + 0x7F, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + // '`' + 0x00, 0x00, + 0x00, 0x00, + 0x18, 0x00, + 0x0C, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x03, 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, + // 'a' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x1F, 0x00, + 0x3F, 0x80, + 0x61, 0x80, + 0x60, 0x80, + 0x0F, 0x80, + 0x3E, 0x80, + 0x30, 0x80, + 0x31, 0x80, + 0x3F, 0x80, + 0x1E, 0x80, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'b' + 0x00, 0x00, + 0x00, 0x00, + 0x20, 0x00, + 0x20, 0x00, + 0x20, 0x00, + 0x20, 0x00, + 0x2F, 0x00, + 0x3F, 0x80, + 0x30, 0xC0, + 0x30, 0xC0, + 0x20, 0xC0, + 0x20, 0xC0, + 0x30, 0xC0, + 0x30, 0xC0, + 0x3F, 0x80, + 0x2F, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'c' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x0F, 0x00, + 0x1F, 0x80, + 0x30, 0xC0, + 0x20, 0xC0, + 0x20, 0x00, + 0x20, 0x00, + 0x20, 0xC0, + 0x30, 0xC0, + 0x1F, 0x80, + 0x0F, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'd' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0xC0, + 0x00, 0xC0, + 0x00, 0xC0, + 0x00, 0xC0, + 0x1E, 0xC0, + 0x3F, 0xC0, + 0x61, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x61, 0xC0, + 0x3F, 0xC0, + 0x1E, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'e' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x0F, 0x00, + 0x1F, 0x80, + 0x31, 0x80, + 0x20, 0xC0, + 0x3F, 0xC0, + 0x3F, 0xC0, + 0x20, 0x00, + 0x30, 0xC0, + 0x1F, 0x80, + 0x0F, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'f' + 0x00, 0x00, + 0x00, 0x00, + 0x07, 0x80, + 0x07, 0xC0, + 0x0C, 0x60, + 0x0C, 0x00, + 0x3F, 0xC0, + 0x3F, 0xC0, + 0x0C, 0x00, + 0x0C, 0x00, + 0x0C, 0x00, + 0x0C, 0x00, + 0x0C, 0x00, + 0x0C, 0x00, + 0x0C, 0x00, + 0x0C, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'g' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x1E, 0xC0, + 0x3F, 0xC0, + 0x31, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x31, 0xC0, + 0x3F, 0xC0, + 0x1E, 0xC0, + 0x00, 0xC0, + 0x61, 0x80, + 0x3F, 0x80, + 0x1F, 0x00, + 0x00, 0x00, + // 'h' + 0x00, 0x00, + 0x00, 0x00, + 0x30, 0x00, + 0x30, 0x00, + 0x30, 0x00, + 0x30, 0x00, + 0x37, 0x00, + 0x3F, 0x80, + 0x31, 0x80, + 0x30, 0xC0, + 0x30, 0xC0, + 0x30, 0xC0, + 0x30, 0xC0, + 0x30, 0xC0, + 0x30, 0xC0, + 0x30, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'i' + 0x00, 0x00, + 0x00, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x00, 0x00, + 0x3E, 0x00, + 0x3E, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x3F, 0xC0, + 0x3F, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'j' + 0x00, 0x00, + 0x00, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x00, 0x00, + 0x3F, 0x00, + 0x3F, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x03, 0x00, + 0x23, 0x00, + 0x3F, 0x00, + 0x1E, 0x00, + 0x00, 0x00, + // 'k' + 0x00, 0x00, + 0x00, 0x00, + 0x10, 0x00, + 0x10, 0x00, + 0x10, 0x00, + 0x10, 0x00, + 0x10, 0xC0, + 0x11, 0x80, + 0x13, 0x00, + 0x16, 0x00, + 0x1E, 0x00, + 0x1C, 0x00, + 0x16, 0x00, + 0x13, 0x00, + 0x11, 0x80, + 0x11, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'l' + 0x00, 0x00, + 0x00, 0x00, + 0x3E, 0x00, + 0x3E, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x3F, 0xC0, + 0x3F, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'm' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x6D, 0x80, + 0x7F, 0xC0, + 0x66, 0xC0, + 0x64, 0xC0, + 0x64, 0xC0, + 0x64, 0xC0, + 0x64, 0xC0, + 0x64, 0xC0, + 0x64, 0xC0, + 0x64, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'n' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x3F, 0x00, + 0x3F, 0x80, + 0x31, 0x80, + 0x30, 0xC0, + 0x30, 0xC0, + 0x30, 0xC0, + 0x30, 0xC0, + 0x30, 0xC0, + 0x30, 0xC0, + 0x30, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'o' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x1F, 0x00, + 0x3F, 0x80, + 0x31, 0x80, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x31, 0x80, + 0x3F, 0x80, + 0x1F, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'p' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x2F, 0x00, + 0x3F, 0x80, + 0x30, 0xC0, + 0x30, 0xC0, + 0x20, 0xC0, + 0x20, 0xC0, + 0x30, 0xC0, + 0x30, 0xC0, + 0x3F, 0x80, + 0x2F, 0x00, + 0x20, 0x00, + 0x20, 0x00, + 0x20, 0x00, + 0x00, 0x00, + // 'q' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x1E, 0xC0, + 0x3F, 0xC0, + 0x61, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x60, 0xC0, + 0x61, 0xC0, + 0x3F, 0xC0, + 0x1E, 0xC0, + 0x00, 0xC0, + 0x00, 0xC0, + 0x00, 0xC0, + 0x00, 0x00, + // 'r' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x3B, 0x80, + 0x3F, 0xC0, + 0x0C, 0xC0, + 0x08, 0xC0, + 0x08, 0x00, + 0x08, 0x00, + 0x08, 0x00, + 0x08, 0x00, + 0x3F, 0x00, + 0x3F, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 's' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x1F, 0x00, + 0x3F, 0x80, + 0x30, 0xC0, + 0x30, 0x00, + 0x3E, 0x00, + 0x0F, 0x80, + 0x01, 0x80, + 0x30, 0x80, + 0x3F, 0x80, + 0x1F, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 't' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x7F, 0x80, + 0x7F, 0x80, + 0x18, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x18, 0x00, + 0x18, 0xC0, + 0x18, 0xC0, + 0x0F, 0x80, + 0x07, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'u' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x20, 0x80, + 0x20, 0x80, + 0x20, 0x80, + 0x20, 0x80, + 0x20, 0x80, + 0x20, 0x80, + 0x20, 0x80, + 0x31, 0x80, + 0x3F, 0x80, + 0x1E, 0x80, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'v' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x60, 0xC0, + 0x20, 0xC0, + 0x30, 0x80, + 0x31, 0x80, + 0x11, 0x80, + 0x19, 0x00, + 0x1B, 0x00, + 0x1B, 0x00, + 0x0E, 0x00, + 0x0E, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'w' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0xCE, 0x60, + 0x4E, 0x40, + 0x6A, 0x40, + 0x6A, 0x40, + 0x6A, 0xC0, + 0x6A, 0xC0, + 0x2B, 0xC0, + 0x2B, 0x80, + 0x2B, 0x80, + 0x39, 0x80, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'x' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x60, 0xC0, + 0x31, 0x80, + 0x19, 0x80, + 0x1B, 0x00, + 0x0E, 0x00, + 0x0E, 0x00, + 0x1B, 0x00, + 0x1B, 0x00, + 0x31, 0x80, + 0x71, 0xC0, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // 'y' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x60, 0xC0, + 0x20, 0xC0, + 0x30, 0x80, + 0x31, 0x80, + 0x19, 0x80, + 0x19, 0x00, + 0x1B, 0x00, + 0x0F, 0x00, + 0x0E, 0x00, + 0x06, 0x00, + 0x66, 0x00, + 0x3C, 0x00, + 0x3C, 0x00, + 0x00, 0x00, + // 'z' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x3F, 0x80, + 0x3F, 0x80, + 0x01, 0x80, + 0x03, 0x80, + 0x07, 0x00, + 0x0C, 0x00, + 0x38, 0x00, + 0x30, 0x00, + 0x3F, 0x80, + 0x3F, 0x80, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '{' + 0x01, 0x80, + 0x0F, 0x80, + 0x0C, 0x00, + 0x0C, 0x00, + 0x0C, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x3C, 0x00, + 0x3C, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x0C, 0x00, + 0x0C, 0x00, + 0x0C, 0x00, + 0x0F, 0x80, + 0x07, 0x80, + 0x00, 0x00, + 0x00, 0x00, + // '|' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x04, 0x00, + 0x04, 0x00, + 0x04, 0x00, + 0x04, 0x00, + 0x04, 0x00, + 0x04, 0x00, + 0x04, 0x00, + 0x04, 0x00, + 0x04, 0x00, + 0x04, 0x00, + 0x04, 0x00, + 0x04, 0x00, + 0x04, 0x00, + 0x04, 0x00, + 0x04, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '}' + 0x38, 0x00, + 0x3E, 0x00, + 0x06, 0x00, + 0x02, 0x00, + 0x06, 0x00, + 0x04, 0x00, + 0x0C, 0x00, + 0x0C, 0x00, + 0x07, 0x80, + 0x03, 0x80, + 0x0C, 0x00, + 0x0C, 0x00, + 0x0C, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x06, 0x00, + 0x3E, 0x00, + 0x3C, 0x00, + 0x00, 0x00, + 0x00, 0x00, + // '~' + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x38, 0x00, + 0x7C, 0xC0, + 0x67, 0xC0, + 0x03, 0x80, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, +}; + +} // namespace proto_nerd_font diff --git a/variants/m5stack_core2_lora868_v11_lan_poe_env4/ProtoNerdValueFont.cpp b/variants/m5stack_core2_lora868_v11_lan_poe_env4/ProtoNerdValueFont.cpp new file mode 100644 index 0000000000..e07bc62dc3 --- /dev/null +++ b/variants/m5stack_core2_lora868_v11_lan_poe_env4/ProtoNerdValueFont.cpp @@ -0,0 +1,99 @@ +#include "ProtoNerdValueFont.h" + +#include "ProtoNerdValueFontData.h" + +namespace proto_nerd_value_font { + +using proto_nerd_font::kBitmap; +using proto_nerd_font::kBytesPerGlyph; +using proto_nerd_font::kBytesPerRow; +using proto_nerd_font::kCellHeight; +using proto_nerd_font::kCellWidth; +using proto_nerd_font::kFirst; +using proto_nerd_font::kLast; + +static uint8_t normalizeChar(char c) { + uint8_t uc = static_cast(c); + if (uc < kFirst || uc > kLast) { + return static_cast('?'); + } + return uc; +} + +int textWidth(const char* text, uint8_t scale) { + if (!text || !*text) { + return 0; + } + int count = 0; + for (const char* p = text; *p; ++p) { + ++count; + } + return count * static_cast(kCellWidth) * static_cast(scale); +} + +void drawText(M5Display& lcd, int x, int y, const char* text, uint16_t fg, uint16_t bg, uint8_t scale) { + if (!text || !*text) { + return; + } + + const int cell_w = static_cast(kCellWidth) * static_cast(scale); + const int cell_h = static_cast(kCellHeight) * static_cast(scale); + + int cx = x; + for (const char* p = text; *p; ++p) { + uint8_t ch = normalizeChar(*p); + uint16_t glyph_index = static_cast(ch - kFirst); + uint32_t off = static_cast(glyph_index) * static_cast(kBytesPerGlyph); + + lcd.fillRect(cx, y, cell_w, cell_h, bg); + + for (uint8_t row = 0; row < kCellHeight; ++row) { + for (uint8_t col = 0; col < kCellWidth; ++col) { + uint32_t byte_idx = off + static_cast(row) * static_cast(kBytesPerRow) + (col >> 3); + uint8_t bit = static_cast(0x80 >> (col & 7)); + if (kBitmap[byte_idx] & bit) { + if (scale == 1) { + lcd.drawPixel(cx + col, y + row, fg); + } else { + lcd.fillRect(cx + static_cast(col) * scale, y + static_cast(row) * scale, scale, scale, fg); + } + } + } + } + + cx += cell_w; + } +} + +void drawTextTransparent(M5Display& lcd, int x, int y, const char* text, uint16_t fg, uint8_t scale) { + if (!text || !*text) { + return; + } + + const int cell_w = static_cast(kCellWidth) * static_cast(scale); + + int cx = x; + for (const char* p = text; *p; ++p) { + uint8_t ch = normalizeChar(*p); + uint16_t glyph_index = static_cast(ch - kFirst); + uint32_t off = static_cast(glyph_index) * static_cast(kBytesPerGlyph); + + for (uint8_t row = 0; row < kCellHeight; ++row) { + for (uint8_t col = 0; col < kCellWidth; ++col) { + uint32_t byte_idx = off + static_cast(row) * static_cast(kBytesPerRow) + (col >> 3); + uint8_t bit = static_cast(0x80 >> (col & 7)); + if (kBitmap[byte_idx] & bit) { + if (scale == 1) { + lcd.drawPixel(cx + col, y + row, fg); + } else { + lcd.fillRect(cx + static_cast(col) * scale, y + static_cast(row) * scale, scale, scale, fg); + } + } + } + } + + cx += cell_w; + } +} + +} // namespace proto_nerd_value_font \ No newline at end of file diff --git a/variants/m5stack_core2_lora868_v11_lan_poe_env4/ProtoNerdValueFont.h b/variants/m5stack_core2_lora868_v11_lan_poe_env4/ProtoNerdValueFont.h new file mode 100644 index 0000000000..991b4de190 --- /dev/null +++ b/variants/m5stack_core2_lora868_v11_lan_poe_env4/ProtoNerdValueFont.h @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +namespace proto_nerd_value_font { + +int textWidth(const char* text, uint8_t scale = 1); +void drawText(M5Display& lcd, int x, int y, const char* text, uint16_t fg, uint16_t bg, uint8_t scale = 1); +void drawTextTransparent(M5Display& lcd, int x, int y, const char* text, uint16_t fg, uint8_t scale = 1); + +} // namespace proto_nerd_value_font \ No newline at end of file diff --git a/variants/m5stack_core2_lora868_v11_lan_poe_env4/ProtoNerdValueFontData.h b/variants/m5stack_core2_lora868_v11_lan_poe_env4/ProtoNerdValueFontData.h new file mode 100644 index 0000000000..0ef3619923 --- /dev/null +++ b/variants/m5stack_core2_lora868_v11_lan_poe_env4/ProtoNerdValueFontData.h @@ -0,0 +1,2868 @@ +#pragma once +#include + +namespace proto_nerd_font { +static constexpr uint8_t kFirst = 32; +static constexpr uint8_t kLast = 126; +static constexpr uint8_t kCellWidth = 17; +static constexpr uint8_t kCellHeight = 29; +static constexpr uint8_t kBytesPerRow = 3; +static constexpr uint16_t kBytesPerGlyph= 87; +static constexpr uint8_t kAscent = 24; +static constexpr uint8_t kDescent = 5; +static constexpr uint8_t kLineHeight = 29; + +static const uint8_t kBitmap[] = { + // 'U+0020' + 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, + 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, + 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, + 0x00, 0x00, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x00, 0x00, 0x00, + 0x01, 0xC0, 0x00, + 0x03, 0xC0, 0x00, + 0x03, 0xC0, 0x00, + 0x01, 0xC0, 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, + 0x0E, 0x38, 0x00, + 0x0E, 0x38, 0x00, + 0x0E, 0x30, 0x00, + 0x0E, 0x30, 0x00, + 0x0E, 0x30, 0x00, + 0x0E, 0x30, 0x00, + 0x06, 0x30, 0x00, + 0x06, 0x30, 0x00, + 0x06, 0x30, 0x00, + 0x06, 0x30, 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, 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, + 0x01, 0x8C, 0x00, + 0x03, 0x1C, 0x00, + 0x03, 0x18, 0x00, + 0x03, 0x18, 0x00, + 0x3F, 0xFF, 0x00, + 0x3F, 0xFF, 0x00, + 0x3F, 0xFF, 0x00, + 0x06, 0x30, 0x00, + 0x06, 0x30, 0x00, + 0x06, 0x30, 0x00, + 0x0E, 0x30, 0x00, + 0x7F, 0xFC, 0x00, + 0x7F, 0xFC, 0x00, + 0x7F, 0xFC, 0x00, + 0x0C, 0x60, 0x00, + 0x0C, 0x60, 0x00, + 0x1C, 0xE0, 0x00, + 0x18, 0xC0, 0x00, + 0x18, 0xC0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // '$' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x03, 0xF0, 0x00, + 0x0F, 0xF8, 0x00, + 0x1F, 0xFC, 0x00, + 0x1C, 0xDE, 0x00, + 0x38, 0xCE, 0x00, + 0x38, 0xC6, 0x00, + 0x38, 0xC0, 0x00, + 0x3C, 0xC0, 0x00, + 0x1F, 0xC0, 0x00, + 0x0F, 0xF0, 0x00, + 0x07, 0xF8, 0x00, + 0x00, 0xFC, 0x00, + 0x00, 0xDE, 0x00, + 0x00, 0xCE, 0x00, + 0x00, 0xCE, 0x00, + 0x38, 0xCE, 0x00, + 0x3C, 0xDC, 0x00, + 0x1F, 0xFC, 0x00, + 0x0F, 0xF8, 0x00, + 0x03, 0xF0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xC0, 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, + 0x1E, 0x00, 0x00, + 0x3F, 0x00, 0x00, + 0x3F, 0x80, 0x00, + 0x73, 0x81, 0x00, + 0x73, 0x83, 0x00, + 0x3F, 0x06, 0x00, + 0x3F, 0x18, 0x00, + 0x0C, 0x30, 0x00, + 0x00, 0xE0, 0x00, + 0x01, 0x80, 0x00, + 0x07, 0x10, 0x00, + 0x0C, 0x7C, 0x00, + 0x38, 0x7E, 0x00, + 0x70, 0xE6, 0x00, + 0x40, 0xE6, 0x00, + 0x00, 0xE6, 0x00, + 0x00, 0xFE, 0x00, + 0x00, 0x7E, 0x00, + 0x00, 0x3C, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // '&' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x03, 0xE0, 0x00, + 0x07, 0xF0, 0x00, + 0x0F, 0xF0, 0x00, + 0x0E, 0x38, 0x00, + 0x0E, 0x38, 0x00, + 0x0E, 0x70, 0x00, + 0x07, 0xE0, 0x00, + 0x03, 0xC0, 0x00, + 0x07, 0x80, 0x00, + 0x0F, 0xCF, 0x00, + 0x1E, 0xEE, 0x00, + 0x3C, 0xFC, 0x00, + 0x38, 0x7C, 0x00, + 0x38, 0x78, 0x00, + 0x38, 0x78, 0x00, + 0x38, 0x7C, 0x00, + 0x3F, 0xFC, 0x00, + 0x1F, 0xCE, 0x00, + 0x0F, 0x8F, 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, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0x80, 0x00, + 0x01, 0x80, 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, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // '(' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x1C, 0x00, + 0x00, 0x7C, 0x00, + 0x00, 0xF8, 0x00, + 0x01, 0xE0, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x06, 0x00, 0x00, + 0x06, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x06, 0x00, 0x00, + 0x06, 0x00, 0x00, + 0x06, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0xC0, 0x00, + 0x01, 0xE0, 0x00, + 0x00, 0xFC, 0x00, + 0x00, 0x7C, 0x00, + 0x00, 0x0C, 0x00, + 0x00, 0x00, 0x00, + // ')' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1F, 0x00, 0x00, + 0x1F, 0x80, 0x00, + 0x03, 0xC0, 0x00, + 0x01, 0xE0, 0x00, + 0x00, 0xE0, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x30, 0x00, + 0x00, 0x30, 0x00, + 0x00, 0x30, 0x00, + 0x00, 0x30, 0x00, + 0x00, 0x30, 0x00, + 0x00, 0x30, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0xE0, 0x00, + 0x01, 0xC0, 0x00, + 0x03, 0xC0, 0x00, + 0x1F, 0x80, 0x00, + 0x1E, 0x00, 0x00, + 0x18, 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, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x21, 0xC2, 0x00, + 0x39, 0x8E, 0x00, + 0x3F, 0xFE, 0x00, + 0x1F, 0xF8, 0x00, + 0x01, 0xC0, 0x00, + 0x03, 0xE0, 0x00, + 0x07, 0x70, 0x00, + 0x0E, 0x38, 0x00, + 0x1E, 0x38, 0x00, + 0x04, 0x10, 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, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x3F, 0xFE, 0x00, + 0x3F, 0xFE, 0x00, + 0x3F, 0xFE, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 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, 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, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x01, 0xC0, 0x00, + 0x03, 0xE0, 0x00, + 0x03, 0xE0, 0x00, + 0x03, 0xE0, 0x00, + 0x01, 0xE0, 0x00, + 0x00, 0xE0, 0x00, + 0x00, 0xE0, 0x00, + 0x00, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x03, 0xC0, 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, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x3F, 0xFE, 0x00, + 0x3F, 0xFE, 0x00, + 0x3F, 0xFE, 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, 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, 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, + 0x01, 0xC0, 0x00, + 0x03, 0xC0, 0x00, + 0x03, 0xE0, 0x00, + 0x03, 0xC0, 0x00, + 0x01, 0xC0, 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, 0x1C, 0x00, + 0x00, 0x18, 0x00, + 0x00, 0x38, 0x00, + 0x00, 0x38, 0x00, + 0x00, 0x30, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0xE0, 0x00, + 0x00, 0xE0, 0x00, + 0x00, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x00, 0x00, + 0x03, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x06, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0C, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // '0' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x03, 0xE0, 0x00, + 0x0F, 0xF8, 0x00, + 0x1F, 0xFC, 0x00, + 0x3C, 0x1C, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x30, 0x1E, 0x00, + 0x70, 0x7E, 0x00, + 0x70, 0xF6, 0x00, + 0x73, 0xE6, 0x00, + 0x77, 0x86, 0x00, + 0x7F, 0x06, 0x00, + 0x3C, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x3C, 0x1C, 0x00, + 0x1F, 0xFC, 0x00, + 0x0F, 0xF8, 0x00, + 0x03, 0xE0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // '1' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x03, 0xC0, 0x00, + 0x0F, 0xC0, 0x00, + 0x1E, 0xC0, 0x00, + 0x1C, 0xC0, 0x00, + 0x10, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x1F, 0xFE, 0x00, + 0x1F, 0xFE, 0x00, + 0x1F, 0xFE, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // '2' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x03, 0xE0, 0x00, + 0x0F, 0xF8, 0x00, + 0x1F, 0xFC, 0x00, + 0x1C, 0x1C, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x00, 0x0E, 0x00, + 0x00, 0x0E, 0x00, + 0x00, 0x1C, 0x00, + 0x00, 0x3C, 0x00, + 0x00, 0x78, 0x00, + 0x00, 0xF0, 0x00, + 0x03, 0xC0, 0x00, + 0x07, 0x80, 0x00, + 0x1F, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xFC, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // '3' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x03, 0xF0, 0x00, + 0x0F, 0xF8, 0x00, + 0x1F, 0xFC, 0x00, + 0x3C, 0x1E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x00, 0x0C, 0x00, + 0x03, 0xFC, 0x00, + 0x03, 0xF0, 0x00, + 0x03, 0xF8, 0x00, + 0x00, 0x1C, 0x00, + 0x00, 0x0C, 0x00, + 0x00, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x1C, 0x1C, 0x00, + 0x1F, 0xFC, 0x00, + 0x0F, 0xF8, 0x00, + 0x03, 0xE0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // '4' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0xF8, 0x00, + 0x01, 0xF8, 0x00, + 0x03, 0xB8, 0x00, + 0x03, 0xB8, 0x00, + 0x07, 0x38, 0x00, + 0x0E, 0x38, 0x00, + 0x0E, 0x38, 0x00, + 0x1C, 0x38, 0x00, + 0x38, 0x38, 0x00, + 0x38, 0x38, 0x00, + 0x70, 0x38, 0x00, + 0x7F, 0xFF, 0x00, + 0x7F, 0xFF, 0x00, + 0x7F, 0xFF, 0x00, + 0x00, 0x38, 0x00, + 0x00, 0x38, 0x00, + 0x00, 0x38, 0x00, + 0x00, 0x38, 0x00, + 0x00, 0x38, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // '5' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x1F, 0xFE, 0x00, + 0x1F, 0xFE, 0x00, + 0x1F, 0xFE, 0x00, + 0x1C, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1C, 0x40, 0x00, + 0x1F, 0xF0, 0x00, + 0x1F, 0xF8, 0x00, + 0x1E, 0x3C, 0x00, + 0x1C, 0x1E, 0x00, + 0x00, 0x0E, 0x00, + 0x00, 0x0E, 0x00, + 0x00, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x1C, 0x1C, 0x00, + 0x1F, 0xFC, 0x00, + 0x0F, 0xF8, 0x00, + 0x03, 0xE0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // '6' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0xF0, 0x00, + 0x00, 0xE0, 0x00, + 0x01, 0xC0, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x0F, 0xE0, 0x00, + 0x0F, 0xF8, 0x00, + 0x1F, 0x7C, 0x00, + 0x1C, 0x1C, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x3C, 0x1C, 0x00, + 0x1F, 0xFC, 0x00, + 0x0F, 0xF8, 0x00, + 0x03, 0xE0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // '7' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x3F, 0xFC, 0x00, + 0x3F, 0xFC, 0x00, + 0x3F, 0xFC, 0x00, + 0x00, 0x0C, 0x00, + 0x00, 0x1C, 0x00, + 0x00, 0x1C, 0x00, + 0x00, 0x38, 0x00, + 0x00, 0x38, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0xE0, 0x00, + 0x00, 0xE0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // '8' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x07, 0xE0, 0x00, + 0x1F, 0xF8, 0x00, + 0x1F, 0xFC, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0C, 0x00, + 0x1F, 0xFC, 0x00, + 0x07, 0xF0, 0x00, + 0x0F, 0xF8, 0x00, + 0x1C, 0x1C, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x3C, 0x1C, 0x00, + 0x1F, 0xFC, 0x00, + 0x0F, 0xF8, 0x00, + 0x07, 0xE0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // '9' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x03, 0xE0, 0x00, + 0x0F, 0xF8, 0x00, + 0x1F, 0xFC, 0x00, + 0x3C, 0x1C, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x3C, 0x1E, 0x00, + 0x1F, 0xFC, 0x00, + 0x0F, 0xFC, 0x00, + 0x07, 0xF8, 0x00, + 0x00, 0x78, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0xE0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x03, 0x80, 0x00, + 0x07, 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, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x01, 0xC0, 0x00, + 0x03, 0xC0, 0x00, + 0x03, 0xE0, 0x00, + 0x03, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x01, 0xC0, 0x00, + 0x03, 0xC0, 0x00, + 0x03, 0xE0, 0x00, + 0x03, 0xC0, 0x00, + 0x01, 0xC0, 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, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x01, 0xC0, 0x00, + 0x03, 0xC0, 0x00, + 0x03, 0xE0, 0x00, + 0x03, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x01, 0xC0, 0x00, + 0x03, 0xE0, 0x00, + 0x03, 0xE0, 0x00, + 0x03, 0xE0, 0x00, + 0x01, 0xE0, 0x00, + 0x00, 0xE0, 0x00, + 0x00, 0xE0, 0x00, + 0x00, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x03, 0xC0, 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, 0x04, 0x00, + 0x00, 0x1C, 0x00, + 0x00, 0x7C, 0x00, + 0x01, 0xF8, 0x00, + 0x07, 0xE0, 0x00, + 0x1F, 0x80, 0x00, + 0x1C, 0x00, 0x00, + 0x10, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1F, 0x00, 0x00, + 0x07, 0xC0, 0x00, + 0x01, 0xF0, 0x00, + 0x00, 0x7C, 0x00, + 0x00, 0x1C, 0x00, + 0x00, 0x04, 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, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x3F, 0xFE, 0x00, + 0x3F, 0xFE, 0x00, + 0x3F, 0xFE, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x3F, 0xFE, 0x00, + 0x3F, 0xFE, 0x00, + 0x3F, 0xFE, 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, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, + 0x18, 0x00, 0x00, + 0x1F, 0x00, 0x00, + 0x0F, 0xC0, 0x00, + 0x03, 0xF0, 0x00, + 0x00, 0xFC, 0x00, + 0x00, 0x3C, 0x00, + 0x00, 0x0C, 0x00, + 0x00, 0x1C, 0x00, + 0x00, 0x7C, 0x00, + 0x03, 0xF0, 0x00, + 0x0F, 0xC0, 0x00, + 0x1F, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x10, 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, 0x00, 0x00, + 0x03, 0xE0, 0x00, + 0x0F, 0xF8, 0x00, + 0x1F, 0xFC, 0x00, + 0x1C, 0x1C, 0x00, + 0x18, 0x1C, 0x00, + 0x20, 0x1C, 0x00, + 0x00, 0x1C, 0x00, + 0x00, 0x3C, 0x00, + 0x00, 0x78, 0x00, + 0x00, 0xF0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0x80, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0xC0, 0x00, + 0x03, 0xC0, 0x00, + 0x03, 0x80, 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, + 0x01, 0xF0, 0x00, + 0x07, 0xF8, 0x00, + 0x0F, 0xFC, 0x00, + 0x1C, 0x0E, 0x00, + 0x18, 0x0E, 0x00, + 0x38, 0xE6, 0x00, + 0x31, 0xFE, 0x00, + 0x31, 0xFE, 0x00, + 0x71, 0x8E, 0x00, + 0x73, 0x8E, 0x00, + 0x73, 0x86, 0x00, + 0x73, 0x86, 0x00, + 0x73, 0x86, 0x00, + 0x73, 0x8E, 0x00, + 0x71, 0x8E, 0x00, + 0x71, 0xFE, 0x00, + 0x31, 0xFE, 0x00, + 0x30, 0xE6, 0x00, + 0x38, 0x00, 0x00, + 0x18, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x0F, 0xF0, 0x00, + 0x07, 0xF0, 0x00, + 0x01, 0xF0, 0x00, + // 'A' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x03, 0xE0, 0x00, + 0x03, 0xE0, 0x00, + 0x03, 0xE0, 0x00, + 0x07, 0x70, 0x00, + 0x07, 0x70, 0x00, + 0x06, 0x70, 0x00, + 0x0E, 0x30, 0x00, + 0x0E, 0x38, 0x00, + 0x0E, 0x38, 0x00, + 0x0C, 0x38, 0x00, + 0x1F, 0xF8, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xFC, 0x00, + 0x18, 0x1C, 0x00, + 0x38, 0x0C, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x30, 0x0E, 0x00, + 0x70, 0x07, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'B' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x1F, 0xF0, 0x00, + 0x1F, 0xF8, 0x00, + 0x1F, 0xFC, 0x00, + 0x1C, 0x0E, 0x00, + 0x1C, 0x0E, 0x00, + 0x1C, 0x0E, 0x00, + 0x1C, 0x0E, 0x00, + 0x1C, 0x1C, 0x00, + 0x1F, 0xF8, 0x00, + 0x1F, 0xF8, 0x00, + 0x1F, 0xFC, 0x00, + 0x1C, 0x0E, 0x00, + 0x1C, 0x0E, 0x00, + 0x1C, 0x0E, 0x00, + 0x1C, 0x0E, 0x00, + 0x1C, 0x0E, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xF0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'C' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x03, 0xF0, 0x00, + 0x07, 0xF8, 0x00, + 0x0F, 0xFC, 0x00, + 0x1C, 0x0E, 0x00, + 0x1C, 0x0E, 0x00, + 0x38, 0x06, 0x00, + 0x38, 0x06, 0x00, + 0x38, 0x00, 0x00, + 0x38, 0x00, 0x00, + 0x38, 0x00, 0x00, + 0x38, 0x00, 0x00, + 0x38, 0x00, 0x00, + 0x38, 0x00, 0x00, + 0x38, 0x0E, 0x00, + 0x1C, 0x0E, 0x00, + 0x1C, 0x1C, 0x00, + 0x0F, 0xFC, 0x00, + 0x0F, 0xF8, 0x00, + 0x03, 0xE0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'D' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x3F, 0xE0, 0x00, + 0x3F, 0xF8, 0x00, + 0x3F, 0xFC, 0x00, + 0x38, 0x1C, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x06, 0x00, + 0x38, 0x06, 0x00, + 0x38, 0x06, 0x00, + 0x38, 0x06, 0x00, + 0x38, 0x06, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x1C, 0x00, + 0x3F, 0xFC, 0x00, + 0x3F, 0xF8, 0x00, + 0x3F, 0xE0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'E' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x1F, 0xFE, 0x00, + 0x1F, 0xFE, 0x00, + 0x1F, 0xFE, 0x00, + 0x1C, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xFC, 0x00, + 0x1C, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xFC, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'F' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x0F, 0xFE, 0x00, + 0x0F, 0xFE, 0x00, + 0x0F, 0xFE, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0F, 0xFC, 0x00, + 0x0F, 0xFC, 0x00, + 0x0F, 0xFC, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'G' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x03, 0xF0, 0x00, + 0x0F, 0xF8, 0x00, + 0x1F, 0xFC, 0x00, + 0x1C, 0x1E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x06, 0x00, + 0x38, 0x00, 0x00, + 0x38, 0x00, 0x00, + 0x30, 0x00, 0x00, + 0x30, 0xFE, 0x00, + 0x30, 0xFE, 0x00, + 0x38, 0xFE, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x1C, 0x1E, 0x00, + 0x1F, 0xFE, 0x00, + 0x0F, 0xFE, 0x00, + 0x03, 0xCE, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'H' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x3F, 0xFE, 0x00, + 0x3F, 0xFE, 0x00, + 0x3F, 0xFE, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'I' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x3F, 0xFE, 0x00, + 0x3F, 0xFE, 0x00, + 0x3F, 0xFE, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x3F, 0xFE, 0x00, + 0x3F, 0xFE, 0x00, + 0x3F, 0xFE, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'J' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xFC, 0x00, + 0x00, 0x1C, 0x00, + 0x00, 0x1C, 0x00, + 0x00, 0x1C, 0x00, + 0x00, 0x1C, 0x00, + 0x00, 0x1C, 0x00, + 0x00, 0x1C, 0x00, + 0x00, 0x1C, 0x00, + 0x38, 0x1C, 0x00, + 0x38, 0x1C, 0x00, + 0x38, 0x1C, 0x00, + 0x38, 0x1C, 0x00, + 0x38, 0x1C, 0x00, + 0x38, 0x1C, 0x00, + 0x1F, 0xF8, 0x00, + 0x0F, 0xF0, 0x00, + 0x07, 0xE0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'K' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x1C, 0x0F, 0x00, + 0x1C, 0x1E, 0x00, + 0x1C, 0x1C, 0x00, + 0x1C, 0x38, 0x00, + 0x1C, 0x70, 0x00, + 0x1C, 0xF0, 0x00, + 0x1C, 0xE0, 0x00, + 0x1D, 0xC0, 0x00, + 0x1F, 0x80, 0x00, + 0x1F, 0x80, 0x00, + 0x1F, 0x80, 0x00, + 0x1F, 0xC0, 0x00, + 0x1D, 0xE0, 0x00, + 0x1C, 0xE0, 0x00, + 0x1C, 0x70, 0x00, + 0x1C, 0x78, 0x00, + 0x1C, 0x38, 0x00, + 0x1C, 0x1C, 0x00, + 0x1C, 0x0E, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'L' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0F, 0xFE, 0x00, + 0x0F, 0xFE, 0x00, + 0x0F, 0xFE, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'M' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x3C, 0x1E, 0x00, + 0x3C, 0x1E, 0x00, + 0x3E, 0x3E, 0x00, + 0x36, 0x36, 0x00, + 0x36, 0x36, 0x00, + 0x36, 0x36, 0x00, + 0x36, 0x36, 0x00, + 0x37, 0x66, 0x00, + 0x33, 0x66, 0x00, + 0x33, 0x66, 0x00, + 0x33, 0x66, 0x00, + 0x33, 0xE6, 0x00, + 0x31, 0xC6, 0x00, + 0x30, 0x06, 0x00, + 0x30, 0x06, 0x00, + 0x30, 0x06, 0x00, + 0x30, 0x06, 0x00, + 0x30, 0x06, 0x00, + 0x30, 0x06, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'N' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x3E, 0x0E, 0x00, + 0x3E, 0x0E, 0x00, + 0x3E, 0x0E, 0x00, + 0x3F, 0x0E, 0x00, + 0x3B, 0x0E, 0x00, + 0x3B, 0x0E, 0x00, + 0x3B, 0x8E, 0x00, + 0x39, 0x8E, 0x00, + 0x39, 0x8E, 0x00, + 0x39, 0xCE, 0x00, + 0x39, 0xCE, 0x00, + 0x38, 0xCE, 0x00, + 0x38, 0xEE, 0x00, + 0x38, 0xEE, 0x00, + 0x38, 0x6E, 0x00, + 0x38, 0x7E, 0x00, + 0x38, 0x7E, 0x00, + 0x38, 0x3E, 0x00, + 0x38, 0x3E, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'O' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x03, 0xE0, 0x00, + 0x0F, 0xF8, 0x00, + 0x1F, 0xFC, 0x00, + 0x3C, 0x1C, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x30, 0x0E, 0x00, + 0x70, 0x06, 0x00, + 0x70, 0x06, 0x00, + 0x70, 0x06, 0x00, + 0x70, 0x06, 0x00, + 0x70, 0x06, 0x00, + 0x30, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x3C, 0x1C, 0x00, + 0x1F, 0xFC, 0x00, + 0x0F, 0xF8, 0x00, + 0x03, 0xE0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'P' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x1F, 0xF0, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xFE, 0x00, + 0x1C, 0x0E, 0x00, + 0x1C, 0x07, 0x00, + 0x1C, 0x07, 0x00, + 0x1C, 0x07, 0x00, + 0x1C, 0x0E, 0x00, + 0x1F, 0xFE, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xF8, 0x00, + 0x1C, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'Q' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x03, 0xE0, 0x00, + 0x0F, 0xF8, 0x00, + 0x1F, 0xFC, 0x00, + 0x1C, 0x1C, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x30, 0x0E, 0x00, + 0x70, 0x06, 0x00, + 0x70, 0x06, 0x00, + 0x70, 0x06, 0x00, + 0x70, 0x06, 0x00, + 0x70, 0x06, 0x00, + 0x70, 0x06, 0x00, + 0x30, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x3C, 0x1C, 0x00, + 0x1F, 0xFC, 0x00, + 0x0F, 0xF8, 0x00, + 0x07, 0xE0, 0x00, + 0x00, 0x80, 0x00, + 0x00, 0xF8, 0x00, + 0x00, 0xFE, 0x00, + 0x00, 0x3E, 0x00, + // 'R' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x1F, 0xF0, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xFE, 0x00, + 0x1C, 0x0E, 0x00, + 0x1C, 0x06, 0x00, + 0x1C, 0x06, 0x00, + 0x1C, 0x0E, 0x00, + 0x1C, 0x1E, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xF8, 0x00, + 0x1F, 0xE0, 0x00, + 0x1C, 0xE0, 0x00, + 0x1C, 0x70, 0x00, + 0x1C, 0x38, 0x00, + 0x1C, 0x38, 0x00, + 0x1C, 0x1C, 0x00, + 0x1C, 0x1C, 0x00, + 0x1C, 0x0E, 0x00, + 0x1C, 0x0F, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'S' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x03, 0xF0, 0x00, + 0x0F, 0xF8, 0x00, + 0x1F, 0xFC, 0x00, + 0x1C, 0x1E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x06, 0x00, + 0x38, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1F, 0xC0, 0x00, + 0x0F, 0xF8, 0x00, + 0x01, 0xFC, 0x00, + 0x00, 0x1C, 0x00, + 0x00, 0x0E, 0x00, + 0x00, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x3C, 0x1E, 0x00, + 0x1F, 0xFC, 0x00, + 0x0F, 0xF8, 0x00, + 0x03, 0xF0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'T' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x7F, 0xFE, 0x00, + 0x7F, 0xFE, 0x00, + 0x7F, 0xFE, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'U' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x1C, 0x1C, 0x00, + 0x1F, 0xFC, 0x00, + 0x0F, 0xF8, 0x00, + 0x07, 0xE0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'V' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x70, 0x07, 0x00, + 0x30, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0C, 0x00, + 0x1C, 0x1C, 0x00, + 0x1C, 0x1C, 0x00, + 0x1C, 0x1C, 0x00, + 0x1C, 0x18, 0x00, + 0x0E, 0x38, 0x00, + 0x0E, 0x38, 0x00, + 0x0E, 0x38, 0x00, + 0x0E, 0x30, 0x00, + 0x07, 0x70, 0x00, + 0x07, 0x70, 0x00, + 0x07, 0x70, 0x00, + 0x03, 0xE0, 0x00, + 0x03, 0xE0, 0x00, + 0x03, 0xE0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'W' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x60, 0x03, 0x00, + 0x60, 0x03, 0x00, + 0x60, 0x03, 0x00, + 0x70, 0x07, 0x00, + 0x71, 0xC7, 0x00, + 0x73, 0xE7, 0x00, + 0x73, 0x66, 0x00, + 0x73, 0x66, 0x00, + 0x33, 0x66, 0x00, + 0x33, 0x66, 0x00, + 0x33, 0x66, 0x00, + 0x33, 0x6E, 0x00, + 0x3B, 0x6E, 0x00, + 0x3A, 0x6E, 0x00, + 0x3E, 0x2C, 0x00, + 0x3E, 0x3C, 0x00, + 0x1E, 0x3C, 0x00, + 0x1E, 0x3C, 0x00, + 0x1E, 0x3C, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'X' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x78, 0x0F, 0x00, + 0x38, 0x0E, 0x00, + 0x3C, 0x1C, 0x00, + 0x1C, 0x1C, 0x00, + 0x0E, 0x38, 0x00, + 0x0E, 0x38, 0x00, + 0x07, 0x70, 0x00, + 0x07, 0x70, 0x00, + 0x03, 0xE0, 0x00, + 0x03, 0xE0, 0x00, + 0x03, 0xE0, 0x00, + 0x07, 0x60, 0x00, + 0x07, 0x70, 0x00, + 0x0E, 0x70, 0x00, + 0x0E, 0x38, 0x00, + 0x1C, 0x38, 0x00, + 0x1C, 0x1C, 0x00, + 0x38, 0x1C, 0x00, + 0x38, 0x0E, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'Y' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x70, 0x07, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0C, 0x00, + 0x1C, 0x1C, 0x00, + 0x0E, 0x38, 0x00, + 0x0E, 0x38, 0x00, + 0x07, 0x70, 0x00, + 0x07, 0x70, 0x00, + 0x03, 0xE0, 0x00, + 0x03, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'Z' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x3F, 0xFC, 0x00, + 0x3F, 0xFC, 0x00, + 0x3F, 0xFC, 0x00, + 0x00, 0x0C, 0x00, + 0x00, 0x1C, 0x00, + 0x00, 0x3C, 0x00, + 0x00, 0x78, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0xE0, 0x00, + 0x01, 0xC0, 0x00, + 0x03, 0x80, 0x00, + 0x07, 0x00, 0x00, + 0x0F, 0x00, 0x00, + 0x1E, 0x00, 0x00, + 0x3C, 0x00, 0x00, + 0x38, 0x00, 0x00, + 0x3F, 0xFC, 0x00, + 0x3F, 0xFC, 0x00, + 0x3F, 0xFC, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // '[' + 0x00, 0x00, 0x00, + 0x07, 0xFC, 0x00, + 0x07, 0xFC, 0x00, + 0x07, 0xFC, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0xFC, 0x00, + 0x07, 0xFC, 0x00, + 0x07, 0xFC, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // '\' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x0C, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x06, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x03, 0x00, 0x00, + 0x03, 0x00, 0x00, + 0x03, 0x80, 0x00, + 0x01, 0x80, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xE0, 0x00, + 0x00, 0xE0, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x30, 0x00, + 0x00, 0x38, 0x00, + 0x00, 0x38, 0x00, + 0x00, 0x18, 0x00, + 0x00, 0x1C, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // ']' + 0x00, 0x00, 0x00, + 0x1F, 0xE0, 0x00, + 0x1F, 0xE0, 0x00, + 0x1F, 0xE0, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x60, 0x00, + 0x1F, 0xE0, 0x00, + 0x1F, 0xE0, 0x00, + 0x1F, 0xE0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // '^' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x01, 0xC0, 0x00, + 0x03, 0xE0, 0x00, + 0x07, 0x60, 0x00, + 0x07, 0x70, 0x00, + 0x0E, 0x38, 0x00, + 0x0E, 0x38, 0x00, + 0x1C, 0x1C, 0x00, + 0x18, 0x1C, 0x00, + 0x38, 0x0E, 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, 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, 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, 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, + 0x3F, 0xFE, 0x00, + 0x3F, 0xFE, 0x00, + 0x3F, 0xFE, 0x00, + 0x00, 0x00, 0x00, + // '`' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x01, 0xC0, 0x00, + 0x00, 0xE0, 0x00, + 0x00, 0x60, 0x00, + 0x00, 0x70, 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, 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, + // 'a' + 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, + 0x07, 0xE0, 0x00, + 0x0F, 0xF8, 0x00, + 0x1F, 0xF8, 0x00, + 0x38, 0x1C, 0x00, + 0x38, 0x1C, 0x00, + 0x00, 0x1C, 0x00, + 0x01, 0xFC, 0x00, + 0x0F, 0xFC, 0x00, + 0x1F, 0x9C, 0x00, + 0x1C, 0x1C, 0x00, + 0x18, 0x1C, 0x00, + 0x1C, 0x3C, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xFC, 0x00, + 0x07, 0x9C, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'b' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, + 0x38, 0x00, 0x00, + 0x38, 0x00, 0x00, + 0x38, 0x00, 0x00, + 0x38, 0x00, 0x00, + 0x38, 0x00, 0x00, + 0x39, 0xF0, 0x00, + 0x3F, 0xF8, 0x00, + 0x3F, 0xFC, 0x00, + 0x3C, 0x1E, 0x00, + 0x3C, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x06, 0x00, + 0x38, 0x06, 0x00, + 0x38, 0x06, 0x00, + 0x38, 0x0E, 0x00, + 0x3C, 0x0E, 0x00, + 0x3C, 0x1E, 0x00, + 0x3F, 0xFC, 0x00, + 0x3B, 0xF8, 0x00, + 0x39, 0xF0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'c' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x03, 0xF0, 0x00, + 0x07, 0xF8, 0x00, + 0x0F, 0xFC, 0x00, + 0x1C, 0x1E, 0x00, + 0x1C, 0x0E, 0x00, + 0x38, 0x06, 0x00, + 0x38, 0x00, 0x00, + 0x38, 0x00, 0x00, + 0x38, 0x00, 0x00, + 0x38, 0x00, 0x00, + 0x18, 0x0E, 0x00, + 0x1C, 0x1C, 0x00, + 0x0F, 0xFC, 0x00, + 0x07, 0xF8, 0x00, + 0x03, 0xE0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'd' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x0C, 0x00, + 0x00, 0x0C, 0x00, + 0x00, 0x0C, 0x00, + 0x00, 0x0C, 0x00, + 0x00, 0x0C, 0x00, + 0x00, 0x0C, 0x00, + 0x07, 0xCC, 0x00, + 0x0F, 0xFC, 0x00, + 0x1F, 0xFC, 0x00, + 0x38, 0x3C, 0x00, + 0x38, 0x1C, 0x00, + 0x30, 0x0C, 0x00, + 0x30, 0x0C, 0x00, + 0x30, 0x0C, 0x00, + 0x30, 0x0C, 0x00, + 0x30, 0x0C, 0x00, + 0x38, 0x1C, 0x00, + 0x38, 0x3C, 0x00, + 0x1F, 0xFC, 0x00, + 0x0F, 0xEC, 0x00, + 0x07, 0x8C, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'e' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x03, 0xE0, 0x00, + 0x0F, 0xF8, 0x00, + 0x0F, 0xF8, 0x00, + 0x1C, 0x1C, 0x00, + 0x18, 0x0C, 0x00, + 0x38, 0x0C, 0x00, + 0x3F, 0xFC, 0x00, + 0x3F, 0xFE, 0x00, + 0x3F, 0xFC, 0x00, + 0x38, 0x00, 0x00, + 0x18, 0x0E, 0x00, + 0x1C, 0x1C, 0x00, + 0x0F, 0xFC, 0x00, + 0x0F, 0xF8, 0x00, + 0x03, 0xE0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'f' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x7C, 0x00, + 0x01, 0xFE, 0x00, + 0x01, 0xFF, 0x00, + 0x03, 0x87, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xFC, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'g' + 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, + 0x07, 0xCC, 0x00, + 0x0F, 0xFC, 0x00, + 0x1F, 0xFC, 0x00, + 0x1C, 0x1C, 0x00, + 0x38, 0x1C, 0x00, + 0x38, 0x0C, 0x00, + 0x38, 0x0C, 0x00, + 0x38, 0x0C, 0x00, + 0x38, 0x0C, 0x00, + 0x38, 0x1C, 0x00, + 0x3C, 0x1C, 0x00, + 0x1F, 0xFC, 0x00, + 0x0F, 0xEC, 0x00, + 0x07, 0xCC, 0x00, + 0x00, 0x0C, 0x00, + 0x30, 0x1C, 0x00, + 0x38, 0x1C, 0x00, + 0x3F, 0xF8, 0x00, + 0x1F, 0xF8, 0x00, + 0x07, 0xE0, 0x00, + // 'h' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, + 0x18, 0x00, 0x00, + 0x18, 0x00, 0x00, + 0x18, 0x00, 0x00, + 0x18, 0x00, 0x00, + 0x18, 0x00, 0x00, + 0x19, 0xF0, 0x00, + 0x1F, 0xF8, 0x00, + 0x1F, 0xFC, 0x00, + 0x1C, 0x1C, 0x00, + 0x1C, 0x1C, 0x00, + 0x18, 0x0C, 0x00, + 0x18, 0x0C, 0x00, + 0x18, 0x0C, 0x00, + 0x18, 0x0C, 0x00, + 0x18, 0x0C, 0x00, + 0x18, 0x0C, 0x00, + 0x18, 0x0C, 0x00, + 0x18, 0x0C, 0x00, + 0x18, 0x0C, 0x00, + 0x18, 0x0C, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'i' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0xC0, 0x00, + 0x01, 0xE0, 0x00, + 0x01, 0xE0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x1F, 0xC0, 0x00, + 0x1F, 0xC0, 0x00, + 0x1F, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x1F, 0xFE, 0x00, + 0x1F, 0xFE, 0x00, + 0x1F, 0xFE, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'j' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x78, 0x00, + 0x00, 0x78, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x1F, 0xF0, 0x00, + 0x1F, 0xF0, 0x00, + 0x1F, 0xF0, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x70, 0x00, + 0x00, 0x70, 0x00, + 0x38, 0x70, 0x00, + 0x1F, 0xF0, 0x00, + 0x1F, 0xE0, 0x00, + 0x07, 0xC0, 0x00, + // 'k' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, + 0x0C, 0x00, 0x00, + 0x0C, 0x00, 0x00, + 0x0C, 0x00, 0x00, + 0x0C, 0x00, 0x00, + 0x0C, 0x00, 0x00, + 0x0C, 0x0E, 0x00, + 0x0C, 0x1C, 0x00, + 0x0C, 0x38, 0x00, + 0x0C, 0x78, 0x00, + 0x0C, 0xF0, 0x00, + 0x0C, 0xE0, 0x00, + 0x0D, 0xC0, 0x00, + 0x0F, 0x80, 0x00, + 0x0F, 0xC0, 0x00, + 0x0D, 0xE0, 0x00, + 0x0C, 0xE0, 0x00, + 0x0C, 0x70, 0x00, + 0x0C, 0x38, 0x00, + 0x0C, 0x1C, 0x00, + 0x0C, 0x1E, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'l' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x1F, 0xC0, 0x00, + 0x1F, 0xC0, 0x00, + 0x1F, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xFC, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'm' + 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, + 0x33, 0x9C, 0x00, + 0x3F, 0xFE, 0x00, + 0x3F, 0xFE, 0x00, + 0x31, 0xCE, 0x00, + 0x31, 0xC6, 0x00, + 0x31, 0xC6, 0x00, + 0x31, 0xC6, 0x00, + 0x31, 0xC6, 0x00, + 0x31, 0xC6, 0x00, + 0x31, 0xC6, 0x00, + 0x31, 0xC6, 0x00, + 0x31, 0xC6, 0x00, + 0x31, 0xC6, 0x00, + 0x31, 0xC6, 0x00, + 0x31, 0xC6, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'n' + 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, + 0x19, 0xF0, 0x00, + 0x1F, 0xF8, 0x00, + 0x1F, 0xFC, 0x00, + 0x1C, 0x1C, 0x00, + 0x1C, 0x1C, 0x00, + 0x18, 0x0C, 0x00, + 0x18, 0x0C, 0x00, + 0x18, 0x0C, 0x00, + 0x18, 0x0C, 0x00, + 0x18, 0x0C, 0x00, + 0x18, 0x0C, 0x00, + 0x18, 0x0C, 0x00, + 0x18, 0x0C, 0x00, + 0x18, 0x0C, 0x00, + 0x18, 0x0C, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'o' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x03, 0xE0, 0x00, + 0x0F, 0xF8, 0x00, + 0x1F, 0xFC, 0x00, + 0x1C, 0x1C, 0x00, + 0x38, 0x0C, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x30, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0C, 0x00, + 0x1C, 0x1C, 0x00, + 0x1F, 0xFC, 0x00, + 0x0F, 0xF8, 0x00, + 0x03, 0xE0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'p' + 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, + 0x39, 0xF0, 0x00, + 0x3B, 0xF8, 0x00, + 0x3F, 0xFC, 0x00, + 0x3C, 0x1E, 0x00, + 0x3C, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x06, 0x00, + 0x38, 0x06, 0x00, + 0x38, 0x06, 0x00, + 0x38, 0x0E, 0x00, + 0x3C, 0x0E, 0x00, + 0x3C, 0x1E, 0x00, + 0x3F, 0xFC, 0x00, + 0x3F, 0xF8, 0x00, + 0x39, 0xF0, 0x00, + 0x38, 0x00, 0x00, + 0x38, 0x00, 0x00, + 0x38, 0x00, 0x00, + 0x38, 0x00, 0x00, + 0x38, 0x00, 0x00, + // 'q' + 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, + 0x07, 0x8C, 0x00, + 0x0F, 0xEC, 0x00, + 0x1F, 0xFC, 0x00, + 0x38, 0x3C, 0x00, + 0x38, 0x1C, 0x00, + 0x30, 0x0C, 0x00, + 0x30, 0x0C, 0x00, + 0x30, 0x0C, 0x00, + 0x30, 0x0C, 0x00, + 0x30, 0x0C, 0x00, + 0x38, 0x1C, 0x00, + 0x38, 0x3C, 0x00, + 0x1F, 0xFC, 0x00, + 0x0F, 0xFC, 0x00, + 0x07, 0xCC, 0x00, + 0x00, 0x0C, 0x00, + 0x00, 0x0C, 0x00, + 0x00, 0x0C, 0x00, + 0x00, 0x0C, 0x00, + 0x00, 0x0C, 0x00, + // 'r' + 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, + 0x3F, 0x78, 0x00, + 0x3F, 0xFC, 0x00, + 0x3F, 0xFE, 0x00, + 0x07, 0x8E, 0x00, + 0x07, 0x0E, 0x00, + 0x07, 0x0E, 0x00, + 0x07, 0x0E, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x1F, 0xF8, 0x00, + 0x1F, 0xF8, 0x00, + 0x1F, 0xF8, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 's' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x03, 0xE0, 0x00, + 0x0F, 0xF8, 0x00, + 0x1F, 0xFC, 0x00, + 0x1C, 0x1C, 0x00, + 0x18, 0x0E, 0x00, + 0x1C, 0x00, 0x00, + 0x1F, 0xC0, 0x00, + 0x0F, 0xF8, 0x00, + 0x03, 0xFC, 0x00, + 0x00, 0x1C, 0x00, + 0x18, 0x0C, 0x00, + 0x1C, 0x1C, 0x00, + 0x1F, 0xFC, 0x00, + 0x0F, 0xF8, 0x00, + 0x03, 0xF0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 't' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x3F, 0xFC, 0x00, + 0x3F, 0xFC, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x00, 0x00, + 0x07, 0x0E, 0x00, + 0x07, 0x0C, 0x00, + 0x03, 0xFC, 0x00, + 0x03, 0xF8, 0x00, + 0x01, 0xF0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'u' + 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, + 0x38, 0x1C, 0x00, + 0x38, 0x1C, 0x00, + 0x38, 0x1C, 0x00, + 0x38, 0x1C, 0x00, + 0x38, 0x1C, 0x00, + 0x38, 0x1C, 0x00, + 0x38, 0x1C, 0x00, + 0x38, 0x1C, 0x00, + 0x38, 0x1C, 0x00, + 0x38, 0x1C, 0x00, + 0x18, 0x1C, 0x00, + 0x1C, 0x1C, 0x00, + 0x1F, 0xFC, 0x00, + 0x0F, 0xFC, 0x00, + 0x07, 0xDC, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'v' + 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, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0C, 0x00, + 0x1C, 0x1C, 0x00, + 0x1C, 0x1C, 0x00, + 0x1C, 0x18, 0x00, + 0x0C, 0x38, 0x00, + 0x0E, 0x38, 0x00, + 0x0E, 0x38, 0x00, + 0x06, 0x30, 0x00, + 0x07, 0x70, 0x00, + 0x07, 0x70, 0x00, + 0x03, 0xE0, 0x00, + 0x03, 0xE0, 0x00, + 0x03, 0xE0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'w' + 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, + 0x61, 0xC3, 0x00, + 0x71, 0xC7, 0x00, + 0x73, 0x67, 0x00, + 0x73, 0x67, 0x00, + 0x73, 0x66, 0x00, + 0x33, 0x66, 0x00, + 0x33, 0x66, 0x00, + 0x33, 0x66, 0x00, + 0x3B, 0x6E, 0x00, + 0x3A, 0x6C, 0x00, + 0x1A, 0x6C, 0x00, + 0x1E, 0x3C, 0x00, + 0x1E, 0x3C, 0x00, + 0x1E, 0x3C, 0x00, + 0x1E, 0x3C, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'x' + 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, + 0x38, 0x0E, 0x00, + 0x1C, 0x1C, 0x00, + 0x1C, 0x1C, 0x00, + 0x0E, 0x38, 0x00, + 0x0E, 0x70, 0x00, + 0x07, 0x70, 0x00, + 0x07, 0xE0, 0x00, + 0x03, 0xE0, 0x00, + 0x03, 0xE0, 0x00, + 0x07, 0x70, 0x00, + 0x07, 0x70, 0x00, + 0x0E, 0x38, 0x00, + 0x1C, 0x38, 0x00, + 0x1C, 0x1C, 0x00, + 0x38, 0x1E, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // 'y' + 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, + 0x38, 0x0E, 0x00, + 0x38, 0x0E, 0x00, + 0x38, 0x0C, 0x00, + 0x1C, 0x1C, 0x00, + 0x1C, 0x1C, 0x00, + 0x1C, 0x18, 0x00, + 0x0E, 0x18, 0x00, + 0x0E, 0x38, 0x00, + 0x06, 0x38, 0x00, + 0x07, 0x30, 0x00, + 0x07, 0x70, 0x00, + 0x03, 0xF0, 0x00, + 0x03, 0xE0, 0x00, + 0x00, 0xE0, 0x00, + 0x00, 0xE0, 0x00, + 0x00, 0xC0, 0x00, + 0x39, 0xC0, 0x00, + 0x3F, 0xC0, 0x00, + 0x1F, 0x80, 0x00, + 0x0F, 0x00, 0x00, + // 'z' + 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, + 0x1F, 0xFC, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xFC, 0x00, + 0x00, 0x1C, 0x00, + 0x00, 0x3C, 0x00, + 0x00, 0x78, 0x00, + 0x00, 0xF0, 0x00, + 0x03, 0xE0, 0x00, + 0x07, 0x80, 0x00, + 0x0F, 0x00, 0x00, + 0x1E, 0x00, 0x00, + 0x1C, 0x00, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xFC, 0x00, + 0x1F, 0xFC, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // '{' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x7C, 0x00, + 0x01, 0xFC, 0x00, + 0x03, 0xFC, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x01, 0x80, 0x00, + 0x01, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xE0, 0x00, + 0x00, 0xE0, 0x00, + 0x01, 0xC0, 0x00, + 0x1F, 0x80, 0x00, + 0x1C, 0x00, 0x00, + 0x1F, 0xC0, 0x00, + 0x00, 0xC0, 0x00, + 0x00, 0xE0, 0x00, + 0x00, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0xFC, 0x00, + 0x01, 0xFC, 0x00, + 0x00, 0x7C, 0x00, + 0x00, 0x00, 0x00, + // '|' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + // '}' + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x1F, 0x00, 0x00, + 0x1F, 0xC0, 0x00, + 0x1F, 0xE0, 0x00, + 0x00, 0xE0, 0x00, + 0x00, 0xE0, 0x00, + 0x00, 0xE0, 0x00, + 0x01, 0xC0, 0x00, + 0x01, 0xC0, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x01, 0xC0, 0x00, + 0x00, 0xFC, 0x00, + 0x00, 0x3C, 0x00, + 0x01, 0xFC, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x03, 0x80, 0x00, + 0x01, 0x80, 0x00, + 0x01, 0xC0, 0x00, + 0x00, 0xE0, 0x00, + 0x00, 0xE0, 0x00, + 0x00, 0xE0, 0x00, + 0x1F, 0xE0, 0x00, + 0x1F, 0xC0, 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, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, + 0x1F, 0x86, 0x00, + 0x3F, 0xC6, 0x00, + 0x31, 0xFE, 0x00, + 0x30, 0xFC, 0x00, + 0x00, 0x78, 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, 0x00, +}; + +} // namespace proto_nerd_font diff --git a/variants/m5stack_core2_lora868_v11_lan_poe_env4/gen_martian_mono_fonts.py b/variants/m5stack_core2_lora868_v11_lan_poe_env4/gen_martian_mono_fonts.py new file mode 100644 index 0000000000..46d4aed91b --- /dev/null +++ b/variants/m5stack_core2_lora868_v11_lan_poe_env4/gen_martian_mono_fonts.py @@ -0,0 +1,267 @@ +#!/usr/bin/env python3 +""" +Generate ProtoNerdFontData.h (16px) and ProtoNerdValueFontData.h (24px) +from the Martian Mono Nerd Font. + +Both output files use the 'proto_nerd_font' namespace so zero C++ changes +are needed in the rendering code (ProtoNerdFont.cpp, ProtoNerdValueFont.cpp). + +Usage: + python gen_martian_mono_fonts.py +""" + +import io +import os +import sys +import zipfile +import urllib.request +import subprocess + +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) + +FONT_URL = ( + "https://github.com/ryanoasis/nerd-fonts/releases/latest/download/MartianMono.zip" +) +FONT_FILENAME_CANDIDATES = [ + "MartianMonoNerdFont-Regular.ttf", + "MartianMono-Regular.ttf", + "MartianMonoNFM-Regular.ttf", +] +FONT_LOCAL_PATH = os.path.join(SCRIPT_DIR, "MartianMonoNerdFont-Regular.ttf") + +FIRST_CHAR = 32 # space +LAST_CHAR = 126 # ~ + + +# --------------------------------------------------------------------------- +# Dependency bootstrap +# --------------------------------------------------------------------------- + +def _pip_install(*packages): + subprocess.check_call( + [sys.executable, "-m", "pip", "install", "--quiet"] + list(packages) + ) + + +def ensure_deps(): + missing = [] + try: + import freetype # noqa: F401 + except ImportError: + missing.append("freetype-py") + if missing: + print(f"Installing: {missing}") + _pip_install(*missing) + + +# --------------------------------------------------------------------------- +# Font download +# --------------------------------------------------------------------------- + +def download_font() -> str: + if os.path.exists(FONT_LOCAL_PATH): + print(f"Font cache: {FONT_LOCAL_PATH}") + return FONT_LOCAL_PATH + + print(f"Downloading MartianMono.zip from GitHub …") + with urllib.request.urlopen(FONT_URL) as resp: + data = resp.read() + + with zipfile.ZipFile(io.BytesIO(data)) as zf: + names = zf.namelist() + print(f" {len(names)} files in zip") + + target_member = None + for candidate in FONT_FILENAME_CANDIDATES: + for name in names: + if name.endswith(candidate) or os.path.basename(name) == candidate: + target_member = name + break + if target_member: + break + + if target_member is None: + # Fallback: pick any Regular TTF + for name in names: + bn = os.path.basename(name) + if bn.endswith(".ttf") and "Regular" in bn and "NFM" not in bn: + target_member = name + break + + if target_member is None: + raise RuntimeError( + "Could not find a Regular TTF in the zip.\n" + f"Available files:\n" + "\n".join(f" {n}" for n in names) + ) + + print(f" Extracting: {target_member}") + font_bytes = zf.read(target_member) + + with open(FONT_LOCAL_PATH, "wb") as f: + f.write(font_bytes) + + print(f" Saved to: {FONT_LOCAL_PATH} ({len(font_bytes):,} bytes)") + return FONT_LOCAL_PATH + + +# --------------------------------------------------------------------------- +# Bitmap rendering via FreeType +# --------------------------------------------------------------------------- + +def render_font(font_path: str, pixel_height: int): + """ + Render ASCII 32-126 from *font_path* at *pixel_height*. + + Returns: + cell_w – advance width in pixels (monospace) + cell_h – total cell height = ascent + descent + bytes_per_row – ceil(cell_w / 8) + glyph_bytes – packed 1-bit-per-pixel bitmap for all glyphs + ascent – pixels above baseline + descent – pixels below baseline (positive value) + """ + import freetype # type: ignore + + face = freetype.Face(font_path) + face.set_pixel_sizes(0, pixel_height) + + # Measure advance from a representative character ('0'). + face.load_char( + "0", + freetype.FT_LOAD_RENDER | freetype.FT_LOAD_TARGET_MONO, + ) + cell_w = face.glyph.advance.x >> 6 + ascent = face.size.ascender >> 6 + descent = -(face.size.descender >> 6) # descender is negative in FreeType + cell_h = ascent + descent + + bytes_per_row = (cell_w + 7) // 8 + bytes_per_glyph = bytes_per_row * cell_h + + glyph_bytes = bytearray() + + for code in range(FIRST_CHAR, LAST_CHAR + 1): + ch = chr(code) + face.load_char( + ch, + freetype.FT_LOAD_RENDER | freetype.FT_LOAD_TARGET_MONO, + ) + g = face.glyph + bm = g.bitmap + + cell = bytearray(bytes_per_glyph) + + for row in range(bm.rows): + y_in_cell = ascent - g.bitmap_top + row + if y_in_cell < 0 or y_in_cell >= cell_h: + continue + for col in range(bm.width): + x_in_cell = g.bitmap_left + col + if x_in_cell < 0 or x_in_cell >= cell_w: + continue + # FreeType MONO bitmap: MSB-first, 1-bit/pixel + src_byte_idx = row * bm.pitch + (col >> 3) + src_bit = 7 - (col & 7) + if ( + src_byte_idx < len(bm.buffer) + and (bm.buffer[src_byte_idx] >> src_bit) & 1 + ): + dst_byte_idx = y_in_cell * bytes_per_row + (x_in_cell >> 3) + dst_bit = 7 - (x_in_cell & 7) + cell[dst_byte_idx] |= 1 << dst_bit + + glyph_bytes.extend(cell) + + return cell_w, cell_h, bytes_per_row, bytes(glyph_bytes), ascent, descent + + +# --------------------------------------------------------------------------- +# Header file writer +# --------------------------------------------------------------------------- + +def write_header( + out_path: str, + namespace: str, + cell_w: int, + cell_h: int, + bytes_per_row: int, + ascent: int, + descent: int, + glyph_bytes: bytes, +): + bytes_per_glyph = bytes_per_row * cell_h + num_glyphs = LAST_CHAR - FIRST_CHAR + 1 + + lines = [ + "#pragma once", + "#include ", + "", + f"namespace {namespace} {{", + f"static constexpr uint8_t kFirst = {FIRST_CHAR};", + f"static constexpr uint8_t kLast = {LAST_CHAR};", + f"static constexpr uint8_t kCellWidth = {cell_w};", + f"static constexpr uint8_t kCellHeight = {cell_h};", + f"static constexpr uint8_t kBytesPerRow = {bytes_per_row};", + f"static constexpr uint16_t kBytesPerGlyph= {bytes_per_glyph};", + f"static constexpr uint8_t kAscent = {ascent};", + f"static constexpr uint8_t kDescent = {descent};", + f"static constexpr uint8_t kLineHeight = {cell_h};", + "", + "static const uint8_t kBitmap[] = {", + ] + + # Emit one row (bytes_per_row bytes) per source line for readability. + for glyph_idx in range(num_glyphs): + glyph_off = glyph_idx * bytes_per_glyph + # Comment showing which character this glyph is. + ch = chr(FIRST_CHAR + glyph_idx) + display_ch = ch if ch.isprintable() and ch != " " else f"U+{FIRST_CHAR + glyph_idx:04X}" + lines.append(f" // '{display_ch}'") + for row in range(cell_h): + row_off = glyph_off + row * bytes_per_row + row_bytes = glyph_bytes[row_off : row_off + bytes_per_row] + hex_str = ", ".join(f"0x{b:02X}" for b in row_bytes) + lines.append(f" {hex_str},") + + lines.append("};") + lines.append("") + lines.append(f"}} // namespace {namespace}") + lines.append("") + + with open(out_path, "w", newline="\n") as f: + f.write("\n".join(lines)) + + total_bytes = len(glyph_bytes) + print( + f" Written: {os.path.basename(out_path)} " + f"({num_glyphs} glyphs, {cell_w}x{cell_h}px, " + f"{bytes_per_glyph}B/glyph, {total_bytes}B total)" + ) + + +# --------------------------------------------------------------------------- +# Main +# --------------------------------------------------------------------------- + +def main(): + ensure_deps() + + font_path = download_font() + + # ---- 16px label/body font (ProtoNerdFontData.h) ---- + print("\nRendering body font at 16px …") + cw, ch, bpr, gdata, asc, dsc = render_font(font_path, 16) + out_body = os.path.join(SCRIPT_DIR, "ProtoNerdFontData.h") + write_header(out_body, "proto_nerd_font", cw, ch, bpr, asc, dsc, gdata) + + # ---- 24px value/tile font (ProtoNerdValueFontData.h) ---- + print("\nRendering value font at 24px …") + cw, ch, bpr, gdata, asc, dsc = render_font(font_path, 24) + out_value = os.path.join(SCRIPT_DIR, "ProtoNerdValueFontData.h") + write_header(out_value, "proto_nerd_font", cw, ch, bpr, asc, dsc, gdata) + + print("\nDone – rebuild the firmware to use the new Martian Mono fonts.") + + +if __name__ == "__main__": + main() diff --git a/variants/m5stack_core2_lora868_v11_lan_poe_env4/patch_m5core2_i2c.py b/variants/m5stack_core2_lora868_v11_lan_poe_env4/patch_m5core2_i2c.py new file mode 100644 index 0000000000..6c8167ecb3 --- /dev/null +++ b/variants/m5stack_core2_lora868_v11_lan_poe_env4/patch_m5core2_i2c.py @@ -0,0 +1,45 @@ +Import("env") + +from pathlib import Path + + +def patch_file(path: Path) -> bool: + if not path.exists(): + print(f"[m5core2-i2c] skip missing file: {path}") + return False + + original = path.read_text(encoding="utf-8") + patched = original.replace("Wire1", "Wire") + + if patched == original: + print(f"[m5core2-i2c] no changes needed: {path.name}") + return False + + path.write_text(patched, encoding="utf-8") + print(f"[m5core2-i2c] patched: {path.name}") + return True + + +def apply_patches(): + project_dir = Path(env["PROJECT_DIR"]) + libdeps_dir = Path(env["PROJECT_LIBDEPS_DIR"]) + pioenv = env["PIOENV"] + + m5_dir = libdeps_dir / pioenv / "M5Core2" / "src" + files = [ + m5_dir / "M5Touch.cpp", + m5_dir / "RTC.cpp", + m5_dir / "AXP.cpp", + m5_dir / "AXP192.cpp", + m5_dir / "utility" / "MPU6886.cpp", + ] + + patched_any = False + for file_path in files: + patched_any = patch_file(file_path) or patched_any + + if not patched_any: + print("[m5core2-i2c] no file updates were required") + + +apply_patches() diff --git a/variants/m5stack_core2_lora868_v11_lan_poe_env4/platformio.ini b/variants/m5stack_core2_lora868_v11_lan_poe_env4/platformio.ini new file mode 100644 index 0000000000..81354f8fad --- /dev/null +++ b/variants/m5stack_core2_lora868_v11_lan_poe_env4/platformio.ini @@ -0,0 +1,125 @@ +[M5Stack_Core2_LoRa868_v11_ENV4] +extends = esp32_base +board = m5stack-core2 +board_build.partitions = default_16MB.csv +extra_scripts = + ${esp32_base.extra_scripts} + post:variants/m5stack_core2_lora868_v11_lan_poe_env4/patch_m5core2_i2c.py +build_flags = + ${esp32_base.build_flags} + -I variants/m5stack_core2_lora868_v11_lan_poe_env4 + -D ARDUINO_M5STACK_CORE2 + -D USE_SX1276 + -D RADIO_CLASS=CustomSX1276 + -D WRAPPER_CLASS=CustomSX1276Wrapper + -D P_LORA_SCLK=18 + -D P_LORA_MISO=38 + -D P_LORA_MOSI=23 + -D P_LORA_NSS=27 + -D P_LORA_DIO_0=35 + -D P_LORA_DIO_1=-1 + -D P_LORA_RESET=25 + -D SX127X_CURRENT_LIMIT=120 + -D LORA_TX_POWER=20 + -D PIN_BOARD_SDA=21 + -D PIN_BOARD_SCL=22 + -D RTC_FIXED_PCF8563=1 + -D ENV_PIN_SDA=32 + -D ENV_PIN_SCL=33 + -D ENV_INCLUDE_BMP280=1 + -D ENV_INCLUDE_SHT4X=1 + -D ENV_INCLUDE_SGP30=1 +build_src_filter = ${esp32_base.build_src_filter} + +<../variants/m5stack_core2_lora868_v11_lan_poe_env4> + + +lib_deps = + ${esp32_base.lib_deps} + adafruit/Adafruit BMP280 Library @ ^3.0.0 + sensirion/Sensirion I2C SHT4x @ ^1.1.2 + adafruit/Adafruit SGP30 Sensor @ ^2.0.3 + m5stack/M5Core2 @ ^0.2.0 + +[env:M5Stack_Core2_LoRa868_v11_ENV4_repeater] +extends = M5Stack_Core2_LoRa868_v11_ENV4 +build_flags = + ${M5Stack_Core2_LoRa868_v11_ENV4.build_flags} + -D ADVERT_NAME='"M5Core2 LoRa868 Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=50 +build_src_filter = ${M5Stack_Core2_LoRa868_v11_ENV4.build_src_filter} + +<../examples/simple_repeater> +lib_deps = + ${M5Stack_Core2_LoRa868_v11_ENV4.lib_deps} + ${esp32_ota.lib_deps} + +[env:M5Stack_Core2_LoRa868_v11_ENV4_room_server] +extends = M5Stack_Core2_LoRa868_v11_ENV4 +build_src_filter = ${M5Stack_Core2_LoRa868_v11_ENV4.build_src_filter} + +<../examples/simple_room_server> +build_flags = + ${M5Stack_Core2_LoRa868_v11_ENV4.build_flags} + -D ADVERT_NAME='"M5Core2 LoRa868 Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +lib_deps = + ${M5Stack_Core2_LoRa868_v11_ENV4.lib_deps} + ${esp32_ota.lib_deps} + +[env:M5Stack_Core2_LoRa868_v11_ENV4_companion_radio_usb] +extends = M5Stack_Core2_LoRa868_v11_ENV4 +build_flags = + ${M5Stack_Core2_LoRa868_v11_ENV4.build_flags} + -D DISPLAY_CLASS=Core2M5Display + -D CORE2_ALWAYS_POWERED=1 + -I examples/companion_radio/ui-new + -D MAX_CONTACTS=175 + -D MAX_GROUP_CHANNELS=20 + -D OFFLINE_QUEUE_SIZE=32 + -D MAX_UNREAD_MSGS=8 +build_src_filter = ${M5Stack_Core2_LoRa868_v11_ENV4.build_src_filter} + + + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-new/*.cpp> +lib_deps = + ${M5Stack_Core2_LoRa868_v11_ENV4.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:M5Stack_Core2_LoRa868_v11_ENV4_companion_radio_ble] +extends = M5Stack_Core2_LoRa868_v11_ENV4 +build_flags = + ${M5Stack_Core2_LoRa868_v11_ENV4.build_flags} + -D DISPLAY_CLASS=Core2M5Display + -D CORE2_ALWAYS_POWERED=1 + -I examples/companion_radio/ui-new + -D MAX_CONTACTS=175 + -D MAX_GROUP_CHANNELS=20 + -D BLE_PIN_CODE=123456 + -D BLE_DEBUG_LOGGING=0 + -D OFFLINE_QUEUE_SIZE=32 + -D MAX_UNREAD_MSGS=8 +build_src_filter = ${M5Stack_Core2_LoRa868_v11_ENV4.build_src_filter} + + + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-new/*.cpp> +lib_deps = + ${M5Stack_Core2_LoRa868_v11_ENV4.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:M5Stack_Core2_LoRa868_v11_ENV4_kiss_modem] +extends = M5Stack_Core2_LoRa868_v11_ENV4 +build_src_filter = ${M5Stack_Core2_LoRa868_v11_ENV4.build_src_filter} + +<../examples/kiss_modem/> + +[env:M5Stack_Core2_LoRa868_v11_ENV4_simple_sensor] +extends = M5Stack_Core2_LoRa868_v11_ENV4 +build_flags = + ${M5Stack_Core2_LoRa868_v11_ENV4.build_flags} + -D DISPLAY_CLASS=Core2M5Display + -D CORE2_ALWAYS_POWERED=1 + -D SENSOR_READ_INTERVAL_SECS=60 +build_src_filter = ${M5Stack_Core2_LoRa868_v11_ENV4.build_src_filter} + +<../examples/simple_sensor> diff --git a/variants/m5stack_core2_lora868_v11_lan_poe_env4/target.cpp b/variants/m5stack_core2_lora868_v11_lan_poe_env4/target.cpp new file mode 100644 index 0000000000..94a7c2e77e --- /dev/null +++ b/variants/m5stack_core2_lora868_v11_lan_poe_env4/target.cpp @@ -0,0 +1,116 @@ +#include +#include "target.h" + +#ifdef DISPLAY_CLASS +static void showRadioInitStage(const char* msg) { +#if defined(SENSOR_TILE_DASHBOARD) && SENSOR_TILE_DASHBOARD + (void)msg; + return; +#else + display.startFrame(); + display.setCursor(0, 0); + display.print(msg); + display.endFrame(); +#endif +} +#endif + +Core2Board board; + +#if defined(P_LORA_SCLK) + // Core2 routes LCD on VSPI pins (SCK/MOSI). Keep LoRa on VSPI too when sharing these pins. + static SPIClass spi(VSPI); + RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi); +#else + RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1); +#endif + +WRAPPER_CLASS radio_driver(radio, board); + +ESP32RTCClock fallback_clock; +AutoDiscoverRTCClock rtc_clock(fallback_clock); +EnvironmentSensorManager sensors; +#ifdef DISPLAY_CLASS +DISPLAY_CLASS display; +#endif + +bool radio_init() { +#ifdef DISPLAY_CLASS + showRadioInitStage("Init radio...\nRTC fallback"); +#endif + Serial.println("radio_init: fallback_clock.begin"); + fallback_clock.begin(); + +#ifdef DISPLAY_CLASS + showRadioInitStage("Init radio...\nRTC core2"); +#endif + Serial.println("radio_init: rtc_clock.begin"); + rtc_clock.begin(Wire); + +#if defined(P_LORA_RESET) && (P_LORA_RESET >= 0) +#ifdef DISPLAY_CLASS + showRadioInitStage("Init radio...\nLoRa reset"); +#endif + Serial.println("radio_init: lora reset pulse"); + pinMode(P_LORA_RESET, OUTPUT); + digitalWrite(P_LORA_RESET, LOW); + delay(50); + digitalWrite(P_LORA_RESET, HIGH); + delay(250); +#endif + +#if defined(P_LORA_SCLK) +#ifdef DISPLAY_CLASS + showRadioInitStage("Init radio...\nLoRa SPI"); +#endif + Serial.println("radio_init: spi.begin"); + spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); +#endif + +#if defined(P_LORA_NSS) && (P_LORA_NSS >= 0) + Serial.println("radio_init: nss high"); + pinMode(P_LORA_NSS, OUTPUT); + digitalWrite(P_LORA_NSS, HIGH); + delay(10); +#endif + +#ifdef DISPLAY_CLASS + showRadioInitStage("Init radio...\nLoRa begin"); +#endif + +#ifdef LORA_CR + constexpr uint8_t coding_rate = LORA_CR; +#else + constexpr uint8_t coding_rate = 5; +#endif + + Serial.println("radio_init: radio.begin"); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, coding_rate, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16); + if (status != RADIOLIB_ERR_NONE) { + Serial.print("ERROR: radio init failed: "); + Serial.println(status); + return false; + } + +#ifdef SX127X_CURRENT_LIMIT + radio.setCurrentLimit(SX127X_CURRENT_LIMIT); +#endif + +#if defined(SX176X_RXEN) || defined(SX176X_TXEN) + #ifndef SX176X_RXEN + #define SX176X_RXEN RADIOLIB_NC + #endif + #ifndef SX176X_TXEN + #define SX176X_TXEN RADIOLIB_NC + #endif + radio.setRfSwitchPins(SX176X_RXEN, SX176X_TXEN); +#endif + + radio.setCRC(1); + return true; +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); +} diff --git a/variants/m5stack_core2_lora868_v11_lan_poe_env4/target.h b/variants/m5stack_core2_lora868_v11_lan_poe_env4/target.h new file mode 100644 index 0000000000..34f4a86fd1 --- /dev/null +++ b/variants/m5stack_core2_lora868_v11_lan_poe_env4/target.h @@ -0,0 +1,38 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include +#include +#include +#ifdef DISPLAY_CLASS +#include +#include "Core2M5Display.h" +#endif +#include + +class Core2Board : public ESP32Board { +public: + uint16_t getBattMilliVolts() override { + float v = M5.Axp.GetBatVoltage(); + if (v < 0.1f) return 0; + return (uint16_t)(v * 1000.0f); + } + + bool isExternalPowered() override { + return M5.Axp.isCharging() || M5.Axp.GetVBusVoltage() > 4.0f; + } +}; + +extern Core2Board board; +extern WRAPPER_CLASS radio_driver; +extern AutoDiscoverRTCClock rtc_clock; +extern EnvironmentSensorManager sensors; +#ifdef DISPLAY_CLASS +extern DISPLAY_CLASS display; +#endif + +bool radio_init(); +mesh::LocalIdentity radio_new_identity();