diff --git a/ChangeLog b/ChangeLog index f6bc754..6250d27 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +R2306: +====== +- fix: enable/disable at-jobs not working as expected +- create static tasks with static memory +- removed obsolete socket-based inetd +- fix: default S2(uart)/S3(jtag) console config +- fix: S2/S3 GPIO ranges +- added ILI9341 driver +- added XPT2046 driver + R2305: ====== - support to list root directory diff --git a/README.md b/README.md index 3537082..e443277 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ About Atrium Firmware: ====================== Atrium Firmware is software stack for the ESP family of controllers from Espressif. It provides ready to build configuration (e.g. for S20 -socket) and supports ESP8285, ESP8266, ESP32, ESP32-C3, and ESP32-S3 in -one source code package, providing infrastructure to build, configure, -and use the devices in a consistent manner. +socket) and supports ESP8285, ESP8266, ESP32, ESP32-C3, ESP32-S2, and +ESP32-S3 in one source code package, providing infrastructure to build, +configure, and use the devices in a consistent manner. The intended audience of this distribution are enthusiasts and hobbyists that want a home-automation without cloud access. For remote operation diff --git a/components/cyclic/cyclic.cpp b/components/cyclic/cyclic.cpp index 18ee07b..3e47aaf 100644 --- a/components/cyclic/cyclic.cpp +++ b/components/cyclic/cyclic.cpp @@ -37,10 +37,20 @@ #include +#if!defined APP_CPU_NUM || defined CONFIG_FREERTOS_UNICORE +#define CYCLIC_CPU_NUM 0 +#else +#define CYCLIC_CPU_NUM APP_CPU_NUM +#endif + +#ifndef CONFIG_CYCLIC_STACK_SIZE +#define CONFIG_CYCLIC_STACK_SIZE 4096 +#endif using namespace std; #define TAG MODULE_CYCLIC +#define STATIC_TASK struct SubTask { @@ -71,6 +81,10 @@ struct SubTaskCmp { return l.nextrun < r.nextrun; } }; +#ifdef STATIC_TASK +static StackType_t CyclicStack[CONFIG_CYCLIC_STACK_SIZE]; +static StaticTask_t CyclicTask; +#endif static SubTask *SubTasks = 0; static SemaphoreHandle_t Mtx = 0; @@ -182,9 +196,13 @@ void cyclic_setup() { Mtx = xSemaphoreCreateMutex(); #ifdef ESP32 +#ifdef STATIC_TASK + xTaskCreateStaticPinnedToCore(cyclic_task, "cyclic", sizeof(CyclicStack), (void*)0, 20, CyclicStack, &CyclicTask, CYCLIC_CPU_NUM); +#else BaseType_t r = xTaskCreatePinnedToCore(cyclic_task, "cyclic", 8192, (void*)0, 20, NULL, 1); if (r != pdPASS) log_error(TAG,"create task: %d",r); +#endif // STATIC_TASK #else // cyclic_execute is called from the event task #endif diff --git a/components/event/event.cpp b/components/event/event.cpp index 1a621a8..6fde613 100644 --- a/components/event/event.cpp +++ b/components/event/event.cpp @@ -35,6 +35,15 @@ using namespace std; +#define TAG MODULE_EVENT +#define STATIC_TASK + +#if!defined APP_CPU_NUM || defined CONFIG_FREERTOS_UNICORE +#define EVENT_CPU_NUM 0 +#else +#define EVENT_CPU_NUM APP_CPU_NUM +#endif + #if 0 #define log_devel log_dbug #else @@ -51,6 +60,10 @@ extern "C" void busy_set(int on); #define busy_set(...) #endif +#ifndef CONFIG_EVENT_STACK_SIZE +#define CONFIG_EVENT_STACK_SIZE 8192 +#endif + struct Event { event_t id; @@ -61,11 +74,14 @@ struct Event { { } }; +#if defined STATIC_TASK && !defined CONFIG_IDF_TARGET_ESP8266 +static StackType_t EventStack[CONFIG_EVENT_STACK_SIZE]; +static StaticTask_t EventTask; +#endif static QueueHandle_t EventsQ = 0; static SemaphoreHandle_t EventMtx = 0; static vector EventHandlers; -#define TAG MODULE_EVENT #ifdef ESP32 static atomic Lost, Discarded, Invalid, Processed; #else @@ -500,10 +516,16 @@ void event_init(void) int event_start(void) { +#ifdef CONFIG_IDF_TARGET_ESP8266 + xTaskCreate(&event_task, "events", CONFIG_EVENT_STACK_SIZE, (void*)0, 9, 0); +#elif defined STATIC_TASK + xTaskCreateStaticPinnedToCore(&event_task, "events", sizeof(EventStack), (void*)0, 9, EventStack, &EventTask, EVENT_CPU_NUM); +#else BaseType_t r = xTaskCreatePinnedToCore(&event_task, "events", 8*1024, (void*)0, 9, NULL, 1); if (r != pdPASS) { log_error(TAG,"create task: %d",r); return 1; } +#endif return 0; } diff --git a/components/logging/logging.c b/components/logging/logging.c index eca6ae9..7a640ba 100644 --- a/components/logging/logging.c +++ b/components/logging/logging.c @@ -118,9 +118,11 @@ const char UartPrefix[][8] = { void con_print(const char *str) { + if (str == 0) + return; + size_t s = strlen(str); #if CONFIG_CONSOLE_UART_NONE != 1 - if ((LogUart != -1) && (str != 0)) { - size_t s = strlen(str); + if ((LogUart != -1) && (s != 0)) { if (pdFALSE == xSemaphoreTake(UartLock,MUTEX_ABORT_TIMEOUT)) abort_on_mutex(UartLock,__FUNCTION__); uart_write_bytes(LogUart,str,s); @@ -129,10 +131,10 @@ void con_print(const char *str) xSemaphoreGive(UartLock); } #endif -#ifdef CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG +#if defined CONFIG_USB_DIAGLOG && (defined CONFIG_IDF_TARGET_ESP32C3 || defined CONFIG_IDF_TARGET_ESP32S3) // will block until a jtag connection is present // therefore, max delay: 10ms - usb_serial_jtag_write_bytes(str,strlen(str),10); + usb_serial_jtag_write_bytes(str,s,10); usb_serial_jtag_write_bytes("\r\n",2,10); #endif } @@ -140,42 +142,34 @@ void con_print(const char *str) void con_printf(const char *f, ...) { -#if CONFIG_CONSOLE_UART_NONE != 1 - if (LogUart == -1) - return; - char buf[256]; va_list val; va_start(val,f); - int n = vsnprintf(buf,sizeof(buf),f,val); + con_printv(f,val); va_end(val); - if (n > 0) { - if (n > sizeof(buf)) - n = sizeof(buf); - con_write(buf,n); - //uart_wait_tx_done((uart_port_t)LogUart,portMAX_DELAY); - } -#endif } void con_printv(const char *f, va_list val) { -#if CONFIG_CONSOLE_UART_NONE != 1 - if (LogUart == -1) - return; char buf[256]; int n = vsnprintf(buf,sizeof(buf),f,val); if (n > 0) { if (n > sizeof(buf)) n = sizeof(buf); - if (pdFALSE == xSemaphoreTake(UartLock,MUTEX_ABORT_TIMEOUT)) - abort_on_mutex(UartLock,__FUNCTION__); - uart_write_bytes(LogUart,buf,n); - uart_write_bytes(LogUart,"\r\n",2); - uart_wait_tx_done((uart_port_t)LogUart,portMAX_DELAY); - xSemaphoreGive(UartLock); - } +#if CONFIG_CONSOLE_UART_NONE != 1 + if (LogUart != -1) { + if (pdFALSE == xSemaphoreTake(UartLock,MUTEX_ABORT_TIMEOUT)) + abort_on_mutex(UartLock,__FUNCTION__); + uart_write_bytes(LogUart,buf,n); + uart_write_bytes(LogUart,"\r\n",2); + uart_wait_tx_done((uart_port_t)LogUart,portMAX_DELAY); + xSemaphoreGive(UartLock); + } +#endif +#ifdef CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG + usb_serial_jtag_write_bytes(buf,n,portMAX_DELAY); #endif + } } @@ -188,6 +182,9 @@ void con_write(const char *str, ssize_t s) xSemaphoreGive(UartLock); } #endif +#ifdef CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG + usb_serial_jtag_write_bytes(str,s,portMAX_DELAY); +#endif } @@ -304,7 +301,7 @@ void log_common(log_level_t l, logmod_t m, const char *f, va_list val) if (pdTRUE != xSemaphoreTake(UartLock,MUTEX_ABORT_TIMEOUT)) abort_on_mutex(UartLock,__BASE_FILE__); uart_write_bytes((uart_port_t)LogUart,buf,s); - if (l <= ll_warn) +// if (l <= ll_warn) uart_wait_tx_done((uart_port_t)LogUart,portMAX_DELAY); xSemaphoreGive(UartLock); } diff --git a/components/logging/modules.c b/components/logging/modules.c index 763e4f6..0f90039 100644 --- a/components/logging/modules.c +++ b/components/logging/modules.c @@ -19,7 +19,7 @@ #include "modules.h" const char ModNames[] = - "\0action\0adc\0alarms\0apds\0bh1750\0bmx\0button\0cam\0ccs811b\0cfg\0con\0cyclic\0dht\0dim\0disp\0ds18b20\0event\0fs\0ftpd\0gpio\0hcsr04\0hd44780u\0hdc1000\0hlw8012\0ht16k33\0http\0i2c\0ina219\0inetd\0influx\0init\0led\0ledc\0log\0lua\0lwtcp\0max7219\0mcp230xx\0mqtt\0nightsky\0ns\0nvm\0ota\0owb\0pca9685\0pcf8574\0relay\0rgbleds\0romfs\0screen\0sgp30\0shell\0si7021\0sm\0sntp\0spi\0ssd130x\0sx1276\0tca9555\0telnet\0ti\0timefuse\0tlc5916\0tlc5947\0tp\0uart\0udns\0udpctrl\0usb\0wlan\0ws2812\0www\0xio\0"; + "\0action\0adc\0alarms\0apds\0bh1750\0bmx\0button\0cam\0ccs811b\0cfg\0con\0cyclic\0dht\0dim\0disp\0ds18b20\0event\0fs\0ftpd\0gpio\0hcsr04\0hd44780u\0hdc1000\0hlw8012\0ht16k33\0http\0i2c\0ili9341\0ina219\0influx\0init\0led\0ledc\0log\0lua\0lwtcp\0max7219\0mcp230xx\0mqtt\0nightsky\0ns\0nvm\0ota\0owb\0pca9685\0pcf8574\0relay\0rgbleds\0romfs\0screen\0sgp30\0shell\0si7021\0sm\0sntp\0spi\0ssd130x\0sx1276\0tca9555\0telnet\0ti\0timefuse\0tlc5916\0tlc5947\0tp\0uart\0udns\0udpctrl\0usb\0wlan\0ws2812\0www\0xio\0xpt2046\0"; const uint16_t ModNameOff[] = { 0, @@ -50,50 +50,51 @@ const uint16_t ModNameOff[] = { 148, // ht16k33 156, // http 161, // i2c - 165, // ina219 - 172, // inetd - 178, // influx - 185, // init - 190, // led - 194, // ledc - 199, // log - 203, // lua - 207, // lwtcp - 213, // max7219 - 221, // mcp230xx - 230, // mqtt - 235, // nightsky - 244, // ns - 247, // nvm - 251, // ota - 255, // owb - 259, // pca9685 - 267, // pcf8574 - 275, // relay - 281, // rgbleds - 289, // romfs - 295, // screen - 302, // sgp30 - 308, // shell - 314, // si7021 - 321, // sm - 324, // sntp - 329, // spi - 333, // ssd130x - 341, // sx1276 - 348, // tca9555 - 356, // telnet - 363, // ti - 366, // timefuse - 375, // tlc5916 - 383, // tlc5947 - 391, // tp - 394, // uart - 399, // udns - 404, // udpctrl - 412, // usb - 416, // wlan - 421, // ws2812 - 428, // www - 432, // xio + 165, // ili9341 + 173, // ina219 + 180, // influx + 187, // init + 192, // led + 196, // ledc + 201, // log + 205, // lua + 209, // lwtcp + 215, // max7219 + 223, // mcp230xx + 232, // mqtt + 237, // nightsky + 246, // ns + 249, // nvm + 253, // ota + 257, // owb + 261, // pca9685 + 269, // pcf8574 + 277, // relay + 283, // rgbleds + 291, // romfs + 297, // screen + 304, // sgp30 + 310, // shell + 316, // si7021 + 323, // sm + 326, // sntp + 331, // spi + 335, // ssd130x + 343, // sx1276 + 350, // tca9555 + 358, // telnet + 365, // ti + 368, // timefuse + 377, // tlc5916 + 385, // tlc5947 + 393, // tp + 396, // uart + 401, // udns + 406, // udpctrl + 414, // usb + 418, // wlan + 423, // ws2812 + 430, // www + 434, // xio + 438, // xpt2046 }; diff --git a/components/logging/modules.h b/components/logging/modules.h index 2e4b764..2537daa 100644 --- a/components/logging/modules.h +++ b/components/logging/modules.h @@ -56,8 +56,8 @@ typedef enum logmod_e { logmod_ht16k33, logmod_http, logmod_i2c, + logmod_ili9341, logmod_ina219, - logmod_inetd, logmod_influx, logmod_init, logmod_led, @@ -102,6 +102,7 @@ typedef enum logmod_e { logmod_ws2812, logmod_www, logmod_xio, + logmod_xpt2046, } logmod_t; // module defines @@ -132,8 +133,8 @@ typedef enum logmod_e { #define MODULE_HT16K33 logmod_ht16k33 #define MODULE_HTTP logmod_http #define MODULE_I2C logmod_i2c +#define MODULE_ILI9341 logmod_ili9341 #define MODULE_INA219 logmod_ina219 -#define MODULE_INETD logmod_inetd #define MODULE_INFLUX logmod_influx #define MODULE_INIT logmod_init #define MODULE_LED logmod_led @@ -178,8 +179,9 @@ typedef enum logmod_e { #define MODULE_WS2812 logmod_ws2812 #define MODULE_WWW logmod_www #define MODULE_XIO logmod_xio -#define MAX_MODULE_ID 73 -#define NUM_MODULES 74 +#define MODULE_XPT2046 logmod_xpt2046 +#define MAX_MODULE_ID 74 +#define NUM_MODULES 75 #ifdef USE_MODULE #define TAG USE_MODULE diff --git a/components/netsvc/lwtcp.cpp b/components/netsvc/lwtcp.cpp index acc6a7e..7168da5 100644 --- a/components/netsvc/lwtcp.cpp +++ b/components/netsvc/lwtcp.cpp @@ -20,153 +20,24 @@ #include "lwtcp.h" #include "netsvc.h" #include "profiling.h" - -#ifndef APP_CPU_NUM -#define APP_CPU_NUM 0 -#endif - -#define TAG MODULE_LWTCP - - -#ifdef CONFIG_SOCKET_API -#include - -LwTcp::LwTcp(int con) -: m_con(con) -{ - m_flags = lwip_fcntl(con,F_GETFL,0); -} - -int LwTcp::close() -{ - if (m_con == -1) - return -1; - int r = ::close(m_con); - m_con = -1; - return r; -} - - -int LwTcp::connect(const char *hn, uint16_t port, bool block) -{ - log_local(TAG,"connect %s:%d",hn,(int)port); - ip_addr_t ip; - if (err_t e = resolve_fqhn(hn,&ip)) { - m_err = e; - return e; - } - return connect(&ip,port,block); -} - - -int LwTcp::connect(ip_addr_t *ip, uint16_t port, bool block) -{ - if (m_con != -1) { - log_warn(TAG,"already connected"); - return ERR_USE; - } - int s = socket(AF_INET,SOCK_STREAM,0); - if (-1 == s) { - log_warn(TAG,"unable to create socket: %s",strerror(errno)); - return -1; - } - struct sockaddr_in in; - struct sockaddr_in6 in6; - struct sockaddr *a; - size_t as; - if (IP_IS_V6(ip)) { - in6.sin6_family = AF_INET6; - in6.sin6_port = htons(port); - a = (struct sockaddr *) &in6; - as = sizeof(struct sockaddr_in6); - memcpy(&in6.sin6_addr,ip_2_ip6(ip),sizeof(in6.sin6_addr)); - } else { - in.sin_family = AF_INET; - in.sin_port = htons(port); - a = (struct sockaddr *) ∈ - as = sizeof(struct sockaddr_in); - memcpy(&in.sin_addr,ip_2_ip4(ip),sizeof(in.sin_addr)); - } - if (-1 == lwip_connect(s,a,as)) { - log_warn(TAG,"connect to %s failed: %s\n",inet_ntoa(ip),strerror(errno)); - ::close(s); - return -1; - } - m_con = s; - log_dbugx(TAG,"connected to %s",inet_ntoa(ip)); - return 0; -} - - -const char *LwTcp::error() const -{ return strerror(errno); } - - -int LwTcp::read(char *data, size_t l, unsigned timeout) -{ - if (m_con == -1) - return -1; - log_dbug(TAG,"read(%d,%u)",l,timeout); - if (timeout) { - if ((m_flags & O_NONBLOCK) != 0) { - m_flags &= !O_NONBLOCK; - int r = lwip_fcntl(m_con,F_SETFL,m_flags); - log_dbug(TAG,"setfl block %d",r); - } - /* - if (timeout != portMAX_DELAY) { - int r; - struct timeval tv; - tv.tv_sec = timeout/1000; - tv.tv_usec = (timeout - tv.tv_sec*1000)*1000; - do { - fd_set s; - FD_SET(m_con,&s); - r = select(1,&s,0,0,&tv); - log_dbug(TAG,"select = %d",r); - } while ((r == -1) && (errno == EINTR)); - if (r <= 0) - return r; - } - */ - } else { - if ((m_flags & O_NONBLOCK) == 0) { - m_flags |= O_NONBLOCK; - int r = lwip_fcntl(m_con,F_SETFL,m_flags); - log_dbug(TAG,"setfl non-block %d",r); - } - } - int r = ::read(m_con,data,l); - log_dbug(TAG,"read(%d,%u)=%d %d",l,timeout,r,errno); - if ((r == -1) && (errno == EWOULDBLOCK)) - return 0; - return r; -} - -int LwTcp::write(const char *data, size_t l, bool copy_ignored) -{ - if (m_con == -1) - return -1; - return ::write(m_con,data,l); -} - - -/////////////////////////////////////////////////////////////////////////////// -#else // !CONFIG_SOCKET_API -/////////////////////////////////////////////////////////////////////////////// - -#include "lwip/inet.h" #include "udns.h" #include "tcpio.h" #include #include +#include #include #include #include +#define TAG MODULE_LWTCP + +#ifndef PRO_CPU_NUM +#define PRO_CPU_NUM 0 +#endif + #define TCP_BLOCK_SIZE 1460 #ifdef ESP32 #define MAX_BUF_SIZE (8*1024) @@ -191,7 +62,7 @@ LwTcp::LwTcp(struct tcp_pcb *pcb) m_mtx = xSemaphoreCreateRecursiveMutex(); m_sem = xSemaphoreCreateBinary(); m_send = xSemaphoreCreateBinary(); -#ifndef CONFIG_IDF_TARGET_ESP8266 +#if LWIP_TCPIP_CORE_LOCKING == 0 m_lwip = xSemaphoreCreateBinary(); #endif // no LWIP_LOCK(); -- called from lwip context @@ -209,7 +80,7 @@ LwTcp::LwTcp() m_mtx = xSemaphoreCreateRecursiveMutex(); m_sem = xSemaphoreCreateBinary(); m_send = xSemaphoreCreateBinary(); -#ifndef CONFIG_IDF_TARGET_ESP8266 +#if LWIP_TCPIP_CORE_LOCKING == 0 m_lwip = xSemaphoreCreateBinary(); #endif } @@ -221,7 +92,7 @@ LwTcp::~LwTcp() if (m_pcb) close(); if (m_pbuf) { -#ifdef CONFIG_IDF_TARGET_ESP8266 +#if LWIP_TCPIP_CORE_LOCKING == 1 LWIP_LOCK(); pbuf_free(m_pbuf); LWIP_UNLOCK(); @@ -235,14 +106,14 @@ LwTcp::~LwTcp() vSemaphoreDelete(m_mtx); vSemaphoreDelete(m_sem); vSemaphoreDelete(m_send); -#ifndef CONFIG_IDF_TARGET_ESP8266 +#if LWIP_TCPIP_CORE_LOCKING == 0 vSemaphoreDelete(m_lwip); #endif log_devel(TAG,"~%u: %u done",m_port,m_total); } -#ifndef CONFIG_IDF_TARGET_ESP8266 +#if LWIP_TCPIP_CORE_LOCKING == 0 void LwTcp::close_fn(void *arg) { LwTcp *a = (LwTcp *)arg; @@ -262,7 +133,7 @@ int LwTcp::close() { if (m_pcb == 0) return -1; -#ifdef CONFIG_IDF_TARGET_ESP8266 +#if LWIP_TCPIP_CORE_LOCKING == 1 LWIP_LOCK(); tcp_err(m_pcb,0); tcp_recv(m_pcb,0); @@ -296,7 +167,7 @@ int LwTcp::connect(const char *hn, uint16_t port, bool block) } -#ifndef CONFIG_IDF_TARGET_ESP8266 +#if LWIP_TCPIP_CORE_LOCKING == 0 void LwTcp::connect_fn(void *arg) { LwTcp *a = (LwTcp *)arg; @@ -320,7 +191,7 @@ int LwTcp::connect(ip_addr_t *a, uint16_t port, bool block) inet_ntoa_r(a,ipstr,sizeof(ipstr)); log_direct(ll_local,TAG,"connect ip %s:%d",ipstr,(int)port); } -#ifdef CONFIG_IDF_TARGET_ESP8266 +#if LWIP_TCPIP_CORE_LOCKING != 0 LWIP_LOCK(); m_pcb = tcp_new(); tcp_arg(m_pcb,this); @@ -550,7 +421,7 @@ int LwTcp::read(char *buf, size_t l, unsigned timeout) } xSemaphoreGiveRecursive(m_mtx); if (tofree) { -#if LWIP_TCPIP_CORE_LOCKING == 1 +#if LWIP_TCPIP_CORE_LOCKING != 0 LWIP_LOCK(); pbuf_free(tofree); LWIP_UNLOCK(); @@ -758,7 +629,7 @@ void LwTcpListener::abort_fn(void *arg) LwTcpListener::~LwTcpListener() { -#ifdef CONFIG_IDF_TARGET_ESP8266 +#if LWIP_TCPIP_CORE_LOCKING != 0 if (m_pcb) { LWIP_LOCK(); tcp_abort(m_pcb); @@ -784,7 +655,7 @@ err_t LwTcpListener::handle_accept(void *arg, struct tcp_pcb *pcb, err_t x) LwTcp *N = new LwTcp(pcb); char name[24]; sprintf(name,"%s%u",P->m_name,(unsigned)++P->m_id); - BaseType_t r = xTaskCreatePinnedToCore((void (*)(void*))P->m_session,name,P->m_stack,(void*) N,P->m_prio,NULL,APP_CPU_NUM); + BaseType_t r = xTaskCreatePinnedToCore((void (*)(void*))P->m_session,name,P->m_stack,(void*) N,P->m_prio,NULL,PRO_CPU_NUM); if (r != pdTRUE) { log_warn(TAG,"cannot create session %s",name); return 1; @@ -803,4 +674,3 @@ int listen_port(int port, int mode, void (*session)(LwTcp*), const char *basenam return (server == 0); } -#endif diff --git a/components/netsvc/lwtcp.h b/components/netsvc/lwtcp.h index 5160231..af97c12 100644 --- a/components/netsvc/lwtcp.h +++ b/components/netsvc/lwtcp.h @@ -21,50 +21,6 @@ #include -#ifdef CONFIG_SOCKET_API - -#include -#include - -class LwTcp -{ - public: - LwTcp() - { } - - ~LwTcp() - { close(); } - - explicit LwTcp(int con); - - int connect(const char *hn, uint16_t port, bool block = true); - int connect(ip_addr_t *a, uint16_t port, bool block = true); - bool isConnected() const - { return m_con != -1; } - int write(const char *data, size_t l, bool = true); - int read(char *data, size_t l, unsigned timeout = portMAX_DELAY); - void sync(bool = true) - { } - int close(); - - const char *error() const; - - void setSync(bool s) - { } - - private: - LwTcp(const LwTcp &); - LwTcp &operator = (const LwTcp &); - - int m_con = -1, m_flags = 0; - - friend class LwTcpListener; -}; - - -#else ////////////////////// ESP8266 - - #include #include #include @@ -172,5 +128,3 @@ class LwTcpListener }; #endif - -#endif diff --git a/components/nvm/nvm.cpp b/components/nvm/nvm.cpp index 01c0da1..d3cf99f 100644 --- a/components/nvm/nvm.cpp +++ b/components/nvm/nvm.cpp @@ -136,19 +136,26 @@ void nvm_store_float(const char *id, float v) int nvm_read_blob(const char *name, uint8_t **buf, size_t *len) { - size_t s = 0; - if (esp_err_t e = nvs_get_blob(NVS,name,0,&s)) { - return e; + bool m = false; + if (*buf == 0) { + size_t s = 0; + if (esp_err_t e = nvs_get_blob(NVS,name,0,&s)) { + return e; + } + uint8_t *b = (uint8_t*)malloc(s); + if (b == 0) + return ENOMEM; + m = true; + *buf = b; + *len = s; } - uint8_t *b = (uint8_t*)malloc(s); - if (b == 0) - return ENOMEM; - if (esp_err_t e = nvs_get_blob(NVS,name,b,&s)) { - free(buf); + if (esp_err_t e = nvs_get_blob(NVS,name,*buf,len)) { + if (m) { + free(*buf); + *buf = 0; + } return e; } - *buf = b; - *len = s; return 0; } diff --git a/components/term/jtag_terminal.cpp b/components/term/jtag_terminal.cpp index 38a0fb3..fc6462d 100644 --- a/components/term/jtag_terminal.cpp +++ b/components/term/jtag_terminal.cpp @@ -18,7 +18,7 @@ #include -#ifdef CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG +#if defined CONFIG_IDF_TARGET_ESP32C3 || defined CONFIG_IDF_TARGET_ESP32S3 #include "jtag_terminal.h" #include @@ -32,6 +32,7 @@ using namespace std; JtagTerminal::JtagTerminal(bool crnl) : Terminal(crnl) { +// usb_serial_jtag_driver_config_t cfg = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT(); usb_serial_jtag_driver_config_t cfg; bzero(&cfg,sizeof(cfg)); cfg.rx_buffer_size = 256; diff --git a/components/term/terminal.h b/components/term/terminal.h index 29e3df8..460b6bb 100644 --- a/components/term/terminal.h +++ b/components/term/terminal.h @@ -40,7 +40,7 @@ class Terminal : public stream ~Terminal() override; virtual const char *type() const - { return 0; } + { return "unnamed"; } // bare metal read minimum 1 character virtual int read(char *, size_t, bool block = true) diff --git a/components/term/uart_terminal.cpp b/components/term/uart_terminal.cpp index 7d4e4e8..3b4a670 100644 --- a/components/term/uart_terminal.cpp +++ b/components/term/uart_terminal.cpp @@ -74,6 +74,7 @@ UartTerminal::UartTerminal(bool crnl) , m_uart_rx(UART_NUM_MAX) , m_uart_tx(UART_NUM_MAX) { + memcpy(m_name,"uart",5); } @@ -81,8 +82,11 @@ void UartTerminal::init(uint8_t uart) { m_uart_rx = uart; m_uart_tx = uart; - uart_driver_install((uart_port_t)uart,UART_FIFO_LEN*2,UART_FIFO_LEN*2,0,DRIVER_ARG); -// uart_set_baudrate((uart_port_t)uart,115200); +#if CONFIG_UART_CONSOLE_NONE != 1 + if ((int)uart != CONFIG_CONSOLE_UART_NUM) +#endif + uart_driver_install((uart_port_t)uart,UART_FIFO_LEN*2,UART_FIFO_LEN*2,0,DRIVER_ARG); + sprintf(m_name,"uart@%d",uart); } @@ -90,11 +94,13 @@ void UartTerminal::init(uint8_t rx, uint8_t tx) { m_uart_rx = rx; m_uart_tx = tx; - uart_driver_install((uart_port_t)rx,UART_FIFO_LEN*2,UART_FIFO_LEN*2,0,DRIVER_ARG); -// uart_set_baudrate((uart_port_t)m_uart_rx,115200); + sprintf(m_name,"uart@%d,%d",rx,tx); +#if CONFIG_UART_CONSOLE_NONE != 1 + if ((int)rx != CONFIG_CONSOLE_UART_NUM) +#endif + uart_driver_install((uart_port_t)rx,UART_FIFO_LEN*2,UART_FIFO_LEN*2,0,DRIVER_ARG); if (rx != tx) uart_driver_install((uart_port_t)tx,UART_FIFO_LEN*2,UART_FIFO_LEN*2,0,DRIVER_ARG); -// uart_set_baudrate((uart_port_t)m_uart_tx,115200); } @@ -145,5 +151,5 @@ int UartTerminal::write(const char *str, size_t l) void UartTerminal::sync(bool block) { -// uart_wait_tx_done((uart_port_t)m_uart_tx,block ? portMAX_DELAY : 0); + uart_wait_tx_done((uart_port_t)m_uart_tx,block ? portMAX_DELAY : 0); } diff --git a/components/term/uart_terminal.h b/components/term/uart_terminal.h index 900e2ad..6a60ea2 100644 --- a/components/term/uart_terminal.h +++ b/components/term/uart_terminal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2022, Thomas Maier-Komor + * Copyright (C) 2018-2023, Thomas Maier-Komor * Atrium Firmware Package for ESP * * This program is free software: you can redistribute it and/or modify @@ -29,7 +29,7 @@ class UartTerminal : public Terminal explicit UartTerminal(bool = false); const char *type() const override - { return "uart"; } + { return m_name; } void init(uint8_t uart); void init(uint8_t rx, uint8_t tx); @@ -40,6 +40,7 @@ class UartTerminal : public Terminal private: int8_t m_uart_rx, m_uart_tx; + char m_name[10]; }; extern "C" diff --git a/components/wfc/hwcfg_esp32.cpp b/components/wfc/hwcfg_esp32.cpp index b69cd9d..9d4d3fc 100644 --- a/components/wfc/hwcfg_esp32.cpp +++ b/components/wfc/hwcfg_esp32.cpp @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -409,6 +409,7 @@ const char *i2cdrv_t_str(i2cdrv_t e) #ifdef CONFIG_ESPTOOLPY_FLASHSIZE_1MB static const char *disp_t_names[] = { + "dt_ili9341", "dt_none", "dt_pcf8574_hd44780u", "dt_sd_14seg", @@ -418,6 +419,7 @@ static const char *disp_t_names[] = { }; static disp_t disp_t_values[] = { + dt_ili9341, dt_none, dt_pcf8574_hd44780u, dt_sd_14seg, @@ -431,6 +433,7 @@ size_t parse_ascii_disp_t(disp_t *v, const char *s) { #ifndef CONFIG_ESPTOOLPY_FLASHSIZE_1MB static std::map namesmap = { + { "dt_ili9341", dt_ili9341}, { "dt_none", dt_none}, { "dt_pcf8574_hd44780u", dt_pcf8574_hd44780u}, { "dt_sd_14seg", dt_sd_14seg}, @@ -480,6 +483,8 @@ const char *disp_t_str(disp_t e) return "dt_ssd1306"; case dt_ssd1309: return "dt_ssd1309"; + case dt_ili9341: + return "dt_ili9341"; } #endif // !CONFIG_ESPTOOLPY_FLASHSIZE_1MB #ifdef CONFIG_ESPTOOLPY_FLASHSIZE_1MB @@ -493,15 +498,19 @@ const char *disp_t_str(disp_t e) #ifdef CONFIG_ESPTOOLPY_FLASHSIZE_1MB static const char *spidrv_t_names[] = { + "spidrv_ili9341", "spidrv_invalid", "spidrv_ssd1309", "spidrv_sx1276", + "spidrv_xpt2046", }; static spidrv_t spidrv_t_values[] = { + spidrv_ili9341, spidrv_invalid, spidrv_ssd1309, spidrv_sx1276, + spidrv_xpt2046, }; #endif // !CONFIG_ESPTOOLPY_FLASHSIZE_1MB @@ -509,9 +518,11 @@ size_t parse_ascii_spidrv_t(spidrv_t *v, const char *s) { #ifndef CONFIG_ESPTOOLPY_FLASHSIZE_1MB static std::map namesmap = { + { "spidrv_ili9341", spidrv_ili9341}, { "spidrv_invalid", spidrv_invalid}, { "spidrv_ssd1309", spidrv_ssd1309}, { "spidrv_sx1276", spidrv_sx1276}, + { "spidrv_xpt2046", spidrv_xpt2046}, }; #endif // !CONFIG_ESPTOOLPY_FLASHSIZE_1MB char *e; @@ -549,6 +560,10 @@ const char *spidrv_t_str(spidrv_t e) return "spidrv_sx1276"; case spidrv_ssd1309: return "spidrv_ssd1309"; + case spidrv_ili9341: + return "spidrv_ili9341"; + case spidrv_xpt2046: + return "spidrv_xpt2046"; } #endif // !CONFIG_ESPTOOLPY_FLASHSIZE_1MB #ifdef CONFIG_ESPTOOLPY_FLASHSIZE_1MB diff --git a/components/wfc/hwcfg_esp32.h b/components/wfc/hwcfg_esp32.h index 97dcc37..7c3f422 100644 --- a/components/wfc/hwcfg_esp32.h +++ b/components/wfc/hwcfg_esp32.h @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -188,6 +188,7 @@ typedef enum { dt_pcf8574_hd44780u = 16, dt_ssd1306 = 32, dt_ssd1309 = 33, + dt_ili9341 = 64, } disp_t; //! Function to get an ASCII string from a value of a disp_t. const char *disp_t_str(disp_t e); @@ -198,6 +199,8 @@ typedef enum { spidrv_invalid = 0, spidrv_sx1276 = 1, spidrv_ssd1309 = 2, + spidrv_ili9341 = 3, + spidrv_xpt2046 = 4, } spidrv_t; //! Function to get an ASCII string from a value of a spidrv_t. const char *spidrv_t_str(spidrv_t e); diff --git a/components/wfc/hwcfg_esp8266.cpp b/components/wfc/hwcfg_esp8266.cpp index 5909054..e1f950b 100644 --- a/components/wfc/hwcfg_esp8266.cpp +++ b/components/wfc/hwcfg_esp8266.cpp @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -409,6 +409,7 @@ const char *i2cdrv_t_str(i2cdrv_t e) #ifdef CONFIG_ESPTOOLPY_FLASHSIZE_1MB static const char *disp_t_names[] = { + "dt_ili9341", "dt_none", "dt_pcf8574_hd44780u", "dt_sd_14seg", @@ -418,6 +419,7 @@ static const char *disp_t_names[] = { }; static disp_t disp_t_values[] = { + dt_ili9341, dt_none, dt_pcf8574_hd44780u, dt_sd_14seg, @@ -431,6 +433,7 @@ size_t parse_ascii_disp_t(disp_t *v, const char *s) { #ifndef CONFIG_ESPTOOLPY_FLASHSIZE_1MB static std::map namesmap = { + { "dt_ili9341", dt_ili9341}, { "dt_none", dt_none}, { "dt_pcf8574_hd44780u", dt_pcf8574_hd44780u}, { "dt_sd_14seg", dt_sd_14seg}, @@ -480,6 +483,8 @@ const char *disp_t_str(disp_t e) return "dt_ssd1306"; case dt_ssd1309: return "dt_ssd1309"; + case dt_ili9341: + return "dt_ili9341"; } #endif // !CONFIG_ESPTOOLPY_FLASHSIZE_1MB #ifdef CONFIG_ESPTOOLPY_FLASHSIZE_1MB @@ -493,15 +498,19 @@ const char *disp_t_str(disp_t e) #ifdef CONFIG_ESPTOOLPY_FLASHSIZE_1MB static const char *spidrv_t_names[] = { + "spidrv_ili9341", "spidrv_invalid", "spidrv_ssd1309", "spidrv_sx1276", + "spidrv_xpt2046", }; static spidrv_t spidrv_t_values[] = { + spidrv_ili9341, spidrv_invalid, spidrv_ssd1309, spidrv_sx1276, + spidrv_xpt2046, }; #endif // !CONFIG_ESPTOOLPY_FLASHSIZE_1MB @@ -509,9 +518,11 @@ size_t parse_ascii_spidrv_t(spidrv_t *v, const char *s) { #ifndef CONFIG_ESPTOOLPY_FLASHSIZE_1MB static std::map namesmap = { + { "spidrv_ili9341", spidrv_ili9341}, { "spidrv_invalid", spidrv_invalid}, { "spidrv_ssd1309", spidrv_ssd1309}, { "spidrv_sx1276", spidrv_sx1276}, + { "spidrv_xpt2046", spidrv_xpt2046}, }; #endif // !CONFIG_ESPTOOLPY_FLASHSIZE_1MB char *e; @@ -549,6 +560,10 @@ const char *spidrv_t_str(spidrv_t e) return "spidrv_sx1276"; case spidrv_ssd1309: return "spidrv_ssd1309"; + case spidrv_ili9341: + return "spidrv_ili9341"; + case spidrv_xpt2046: + return "spidrv_xpt2046"; } #endif // !CONFIG_ESPTOOLPY_FLASHSIZE_1MB #ifdef CONFIG_ESPTOOLPY_FLASHSIZE_1MB diff --git a/components/wfc/hwcfg_esp8266.h b/components/wfc/hwcfg_esp8266.h index 6833351..dee79db 100644 --- a/components/wfc/hwcfg_esp8266.h +++ b/components/wfc/hwcfg_esp8266.h @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -189,6 +189,7 @@ typedef enum { dt_pcf8574_hd44780u = 16, dt_ssd1306 = 32, dt_ssd1309 = 33, + dt_ili9341 = 64, } disp_t; //! Function to get an ASCII string from a value of a disp_t. const char *disp_t_str(disp_t e); @@ -199,6 +200,8 @@ typedef enum { spidrv_invalid = 0, spidrv_sx1276 = 1, spidrv_ssd1309 = 2, + spidrv_ili9341 = 3, + spidrv_xpt2046 = 4, } spidrv_t; //! Function to get an ASCII string from a value of a spidrv_t. const char *spidrv_t_str(spidrv_t e); diff --git a/components/wfc/hwcfg_esp8285.cpp b/components/wfc/hwcfg_esp8285.cpp index d247609..9778ae3 100644 --- a/components/wfc/hwcfg_esp8285.cpp +++ b/components/wfc/hwcfg_esp8285.cpp @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -411,6 +411,7 @@ const char *i2cdrv_t_str(i2cdrv_t e) #ifdef CONFIG_ESPTOOLPY_FLASHSIZE_1MB static const char *disp_t_names[] = { + "dt_ili9341", "dt_none", "dt_pcf8574_hd44780u", "dt_sd_14seg", @@ -420,6 +421,7 @@ static const char *disp_t_names[] = { }; static disp_t disp_t_values[] = { + dt_ili9341, dt_none, dt_pcf8574_hd44780u, dt_sd_14seg, @@ -433,6 +435,7 @@ size_t parse_ascii_disp_t(disp_t *v, const char *s) { #ifndef CONFIG_ESPTOOLPY_FLASHSIZE_1MB static std::map namesmap = { + { "dt_ili9341", dt_ili9341}, { "dt_none", dt_none}, { "dt_pcf8574_hd44780u", dt_pcf8574_hd44780u}, { "dt_sd_14seg", dt_sd_14seg}, @@ -482,6 +485,8 @@ const char *disp_t_str(disp_t e) return "dt_ssd1306"; case dt_ssd1309: return "dt_ssd1309"; + case dt_ili9341: + return "dt_ili9341"; } #endif // !CONFIG_ESPTOOLPY_FLASHSIZE_1MB #ifdef CONFIG_ESPTOOLPY_FLASHSIZE_1MB @@ -495,15 +500,19 @@ const char *disp_t_str(disp_t e) #ifdef CONFIG_ESPTOOLPY_FLASHSIZE_1MB static const char *spidrv_t_names[] = { + "spidrv_ili9341", "spidrv_invalid", "spidrv_ssd1309", "spidrv_sx1276", + "spidrv_xpt2046", }; static spidrv_t spidrv_t_values[] = { + spidrv_ili9341, spidrv_invalid, spidrv_ssd1309, spidrv_sx1276, + spidrv_xpt2046, }; #endif // !CONFIG_ESPTOOLPY_FLASHSIZE_1MB @@ -511,9 +520,11 @@ size_t parse_ascii_spidrv_t(spidrv_t *v, const char *s) { #ifndef CONFIG_ESPTOOLPY_FLASHSIZE_1MB static std::map namesmap = { + { "spidrv_ili9341", spidrv_ili9341}, { "spidrv_invalid", spidrv_invalid}, { "spidrv_ssd1309", spidrv_ssd1309}, { "spidrv_sx1276", spidrv_sx1276}, + { "spidrv_xpt2046", spidrv_xpt2046}, }; #endif // !CONFIG_ESPTOOLPY_FLASHSIZE_1MB char *e; @@ -551,6 +562,10 @@ const char *spidrv_t_str(spidrv_t e) return "spidrv_sx1276"; case spidrv_ssd1309: return "spidrv_ssd1309"; + case spidrv_ili9341: + return "spidrv_ili9341"; + case spidrv_xpt2046: + return "spidrv_xpt2046"; } #endif // !CONFIG_ESPTOOLPY_FLASHSIZE_1MB #ifdef CONFIG_ESPTOOLPY_FLASHSIZE_1MB diff --git a/components/wfc/hwcfg_esp8285.h b/components/wfc/hwcfg_esp8285.h index e633373..405ba39 100644 --- a/components/wfc/hwcfg_esp8285.h +++ b/components/wfc/hwcfg_esp8285.h @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -190,6 +190,7 @@ typedef enum { dt_pcf8574_hd44780u = 16, dt_ssd1306 = 32, dt_ssd1309 = 33, + dt_ili9341 = 64, } disp_t; //! Function to get an ASCII string from a value of a disp_t. const char *disp_t_str(disp_t e); @@ -200,6 +201,8 @@ typedef enum { spidrv_invalid = 0, spidrv_sx1276 = 1, spidrv_ssd1309 = 2, + spidrv_ili9341 = 3, + spidrv_xpt2046 = 4, } spidrv_t; //! Function to get an ASCII string from a value of a spidrv_t. const char *spidrv_t_str(spidrv_t e); diff --git a/components/wfc/hwcfg_pc.cpp b/components/wfc/hwcfg_pc.cpp index a9cb5ad..32bcde1 100644 --- a/components/wfc/hwcfg_pc.cpp +++ b/components/wfc/hwcfg_pc.cpp @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -254,6 +254,7 @@ const char *i2cdrv_t_str(i2cdrv_t e) } static const char *disp_t_names[] = { + "dt_ili9341", "dt_none", "dt_pcf8574_hd44780u", "dt_sd_14seg", @@ -263,6 +264,7 @@ static const char *disp_t_names[] = { }; static disp_t disp_t_values[] = { + dt_ili9341, dt_none, dt_pcf8574_hd44780u, dt_sd_14seg, @@ -298,15 +300,19 @@ const char *disp_t_str(disp_t e) } static const char *spidrv_t_names[] = { + "spidrv_ili9341", "spidrv_invalid", "spidrv_ssd1309", "spidrv_sx1276", + "spidrv_xpt2046", }; static spidrv_t spidrv_t_values[] = { + spidrv_ili9341, spidrv_invalid, spidrv_ssd1309, spidrv_sx1276, + spidrv_xpt2046, }; size_t parse_ascii_spidrv_t(spidrv_t *v, const char *s) diff --git a/components/wfc/hwcfg_pc.h b/components/wfc/hwcfg_pc.h index 6665d6d..0675a54 100644 --- a/components/wfc/hwcfg_pc.h +++ b/components/wfc/hwcfg_pc.h @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -190,6 +190,7 @@ typedef enum { dt_pcf8574_hd44780u = 16, dt_ssd1306 = 32, dt_ssd1309 = 33, + dt_ili9341 = 64, } disp_t; //! Function to get an ASCII string from a value of a disp_t. const char *disp_t_str(disp_t e); @@ -200,6 +201,8 @@ typedef enum { spidrv_invalid = 0, spidrv_sx1276 = 1, spidrv_ssd1309 = 2, + spidrv_ili9341 = 3, + spidrv_xpt2046 = 4, } spidrv_t; //! Function to get an ASCII string from a value of a spidrv_t. const char *spidrv_t_str(spidrv_t e); diff --git a/components/wfc/swcfg_esp32.cpp b/components/wfc/swcfg_esp32.cpp index 003a5a0..4174a57 100644 --- a/components/wfc/swcfg_esp32.cpp +++ b/components/wfc/swcfg_esp32.cpp @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/components/wfc/swcfg_esp32.h b/components/wfc/swcfg_esp32.h index 1cf6c9d..0a12329 100644 --- a/components/wfc/swcfg_esp32.h +++ b/components/wfc/swcfg_esp32.h @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/components/wfc/swcfg_esp8266.cpp b/components/wfc/swcfg_esp8266.cpp index b5a06b4..c64c992 100644 --- a/components/wfc/swcfg_esp8266.cpp +++ b/components/wfc/swcfg_esp8266.cpp @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/components/wfc/swcfg_esp8266.h b/components/wfc/swcfg_esp8266.h index 97a642b..fb10026 100644 --- a/components/wfc/swcfg_esp8266.h +++ b/components/wfc/swcfg_esp8266.h @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/components/wfc/swcfg_esp8285.cpp b/components/wfc/swcfg_esp8285.cpp index 34ce608..7789a2a 100644 --- a/components/wfc/swcfg_esp8285.cpp +++ b/components/wfc/swcfg_esp8285.cpp @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/components/wfc/swcfg_esp8285.h b/components/wfc/swcfg_esp8285.h index fe9f2c0..7716e37 100644 --- a/components/wfc/swcfg_esp8285.h +++ b/components/wfc/swcfg_esp8285.h @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/components/wfc/swcfg_pc.cpp b/components/wfc/swcfg_pc.cpp index aba53f4..0780f88 100644 --- a/components/wfc/swcfg_pc.cpp +++ b/components/wfc/swcfg_pc.cpp @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/components/wfc/swcfg_pc.h b/components/wfc/swcfg_pc.h index 868054d..e42c465 100644 --- a/components/wfc/swcfg_pc.h +++ b/components/wfc/swcfg_pc.h @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/components/wfc/wfccore_esp32.cpp b/components/wfc/wfccore_esp32.cpp index c223046..4078ebb 100644 --- a/components/wfc/wfccore_esp32.cpp +++ b/components/wfc/wfccore_esp32.cpp @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/components/wfc/wfccore_esp32.h b/components/wfc/wfccore_esp32.h index f8c198d..a9e5ee4 100644 --- a/components/wfc/wfccore_esp32.h +++ b/components/wfc/wfccore_esp32.h @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/components/wfc/wfccore_esp8266.cpp b/components/wfc/wfccore_esp8266.cpp index abb327a..1102862 100644 --- a/components/wfc/wfccore_esp8266.cpp +++ b/components/wfc/wfccore_esp8266.cpp @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/components/wfc/wfccore_esp8266.h b/components/wfc/wfccore_esp8266.h index 0c898a5..302a51c 100644 --- a/components/wfc/wfccore_esp8266.h +++ b/components/wfc/wfccore_esp8266.h @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/components/wfc/wfccore_esp8285.cpp b/components/wfc/wfccore_esp8285.cpp index 68012f0..41188d3 100644 --- a/components/wfc/wfccore_esp8285.cpp +++ b/components/wfc/wfccore_esp8285.cpp @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/components/wfc/wfccore_esp8285.h b/components/wfc/wfccore_esp8285.h index ac41558..098791d 100644 --- a/components/wfc/wfccore_esp8285.h +++ b/components/wfc/wfccore_esp8285.h @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/components/wfc/wfccore_pc.cpp b/components/wfc/wfccore_pc.cpp index d73bf52..59ca23e 100644 --- a/components/wfc/wfccore_pc.cpp +++ b/components/wfc/wfccore_pc.cpp @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/components/wfc/wfccore_pc.h b/components/wfc/wfccore_pc.h index d52fcd8..57529f6 100644 --- a/components/wfc/wfccore_pc.h +++ b/components/wfc/wfccore_pc.h @@ -10,7 +10,7 @@ * Copyright: 2018-2023 * Author : Thomas Maier-Komor * - * Code generated on 2023-04-23, 11:07:00 (CET). + * Code generated on 2023-07-01, 22:37:39 (CET). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drv/display/CMakeLists.txt b/drv/display/CMakeLists.txt index f339174..625c77e 100644 --- a/drv/display/CMakeLists.txt +++ b/drv/display/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register( - SRCS display.cpp hd44780u.cpp ledcluster.cpp fonts_ssd1306.c font6x8_ssd130x.c + SRCS display.cpp hd44780u.cpp ledcluster.cpp ssd130x.cpp fonts_generic.c fonts_ssd1306.c font6x8_ssd130x.c INCLUDE_DIRS . REQUIRES i2c logging ) diff --git a/drv/display/display.cpp b/drv/display/display.cpp index 6bcce38..61f2cf7 100644 --- a/drv/display/display.cpp +++ b/drv/display/display.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021, Thomas Maier-Komor + * Copyright (C) 2021-2023, Thomas Maier-Komor * Atrium Firmware Package for ESP * * This program is free software: you can redistribute it and/or modify @@ -18,6 +18,9 @@ #include "display.h" #include "log.h" +#include "profiling.h" + +#include #define TAG MODULE_DISP @@ -128,27 +131,57 @@ static const uint8_t Circle14[] = { }; +static struct { const char *name; color_t color; } Colors[] = { + { "black", BLACK }, + { "white", WHITE }, + { "blue", BLUE }, + { "red", RED }, + { "green", GREEN }, + { "cyan", CYAN }, + { "magenta", MAGENTA }, + { "yellow", YELLOW }, +}; + + TextDisplay *TextDisplay::Instance = 0; +color_t color_get(const char *n) +{ + for (const auto &c : Colors) { + if (0 == strcasecmp(n,c.name)) + return c.color; + } + return BLACK; +} + + void TextDisplay::initOK() { if (Instance) { - TextDisplay *i = Instance; - while (i->m_next) - i = i->m_next; - i->m_next = this; + log_error(TAG,"only one display is supported"); } else { Instance = this; } } +int TextDisplay::setPos(uint16_t x, uint16_t y) +{ + log_dbug(TAG,"setPos(%u,%u)",x,y); + if ((x < m_width) && (y < m_height)) { + m_posx = x; + m_posy = y; + return 0; + } + return -1; +} + + SegmentDisplay::SegmentDisplay(LedCluster *l, addrmode_t m, uint8_t maxx, uint8_t maxy) -: m_drv(l) +: TextDisplay(maxx,maxy) +, m_drv(l) , m_addrmode(m) -, m_maxx(maxx) -, m_maxy(maxy) { l->setNumDigits((maxx+1)*(maxy+1)); initOK(); @@ -301,6 +334,7 @@ int SegmentDisplay::writeBin(uint8_t v) } +/* int SegmentDisplay::writeHex(uint8_t v, bool comma) { log_dbug(TAG,"writeHex(%x,%d)",v,comma); @@ -325,30 +359,32 @@ int SegmentDisplay::writeHex(uint8_t v, bool comma) } return -1; } +*/ int SegmentDisplay::writeChar(char c, bool comma) { - log_dbug(TAG,"writeChar(%c,%d)",c,comma); + log_dbug(TAG,"writeChar('%c',%d) at %d/%d",c,comma,m_posx,m_posy); if (m_addrmode == e_raw) return -1; if (c == '\n') { - uint16_t y = m_pos / m_maxy; - ++y; - if (y > m_maxy) - y = 0; - return setPos(0,y); + uint16_t y = m_posy + 1; + if (y >= m_height) + y = m_height - 1; + m_posy = y; + return 0; } if (c == '\r') { - uint16_t y = m_pos / m_maxy; - return setPos(0,y); + m_drv->write(c); + m_posx = 0; + return 0; } if (m_addrmode == e_seg14) { uint16_t d = char2seg14(c); if (d == 0) { if (c == ' ') { writeBin(0); - return writeBin(comma?0x80:0); + writeBin(comma?0x80:0); } return 0; // no error to print rest of string } @@ -381,17 +417,529 @@ int SegmentDisplay::writeChar(char c, bool comma) return 1; } -int SegmentDisplay::write(const char *s, int n) + +void SegmentDisplay::write(const char *s, int n) { - log_dbug(TAG,"write('%s')",s); + log_dbug(TAG,"write('%s',%d)",s,n); while (*s && (n != 0)) { - bool comma = s[1] == '.'; - if (writeChar(*s,comma)) - return 1; + log_dbug(TAG,"write('%s',%d) ::",s,n); + bool comma = (s[1] == '.') || ((s[1] == ':') && !hasChar(':')); + writeChar(*s,comma); if (comma) ++s; ++s; --n; } - return 0; } + + +uint16_t MatrixDisplay::fontHeight() const +{ + const Font *font = Fonts+(int)m_font; + return font->yAdvance; +} + + +void MatrixDisplay::clrEol() +{ + fillRect(m_posx,m_posy,m_width-m_posx,fontHeight(),m_colbg); +} + + +void MatrixDisplay::drawBitmap(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *data, int32_t fg, int32_t bg) +{ + log_dbug(TAG,"drawBitmap(%u,%u,%u,%u,%d,%d)",x,y,w,h,fg,bg); + if (fg == -1) + fg = m_colfg; + if (bg == -1) + bg = m_colbg; + const uint8_t *e = data + w*h; + if (fg != -2) { + unsigned idx = 0; + uint8_t b = 0; + const uint8_t *d = data; + while (d != e) { + if ((idx & 7) == 0) { + b = *d++; + if (b == 0) { + idx += 8; + continue; + } + } + if (b&0x80) + setPixel(x+idx%w,y+idx/w,fg); + b<<=1; + ++idx; + } + } + if (bg != -2) { + unsigned idx = 0; + uint8_t b = 0; + const uint8_t *d = data; + while (d != e) { + if ((idx & 7) == 0) { + b = *d++; + if (b == 0xff) { + idx += 8; + continue; + } + } + if ((b&0x80) == 0) + setPixel(x+idx%w,y+idx/w,bg); + b<<=1; + ++idx; + } + } +} + + +static uint8_t charToGlyph(char c) +{ + switch ((unsigned char) c) { + case '\r': + return 0; + case '\n': + return 0; + case 176: // '°' + return 133; + case 196: // 'Ä' + return 130; + case 220: // 'Ü' + return 128; + case 214: // 'Ö' + return 132; + case 223: // 'ß' + return 134; + case 228: // 'ä' + return 129; + case 246: // 'ö' + return 131; + case 252: // 'ü' + return 127; + default: + return c; + } +} + + +uint16_t MatrixDisplay::charWidth(char c) const +{ + c = charToGlyph(c); + if (c == 0) + return 0; + const Font *font = Fonts+(int)m_font; + if ((c < font->first) || (c > font->last)) + return 0; + uint8_t ch = c - font->first; + return font->glyph[ch].xAdvance; +} + + +void MatrixDisplay::clear() +{ + log_dbug(TAG,"clear"); + m_posx = 0; + m_posy = 0; + fillRect(0,0,m_width,m_height,m_colbg); +} + + +unsigned MatrixDisplay::drawChar(uint16_t x, uint16_t y, char c, int32_t fg, int32_t bg) +{ + PROFILE_FUNCTION(); + c = charToGlyph(c); + const Font *font = Fonts+(int)m_font; + if ((c < font->first) || (c > font->last)) + return 0; + if (fg == -1) + fg = m_colfg; + if (bg == -1) + bg = m_colbg; + uint8_t ch = c - font->first; + const uint8_t *data = font->bitmap + font->glyph[ch].bitmapOffset; + uint8_t w = font->glyph[ch].width; + uint8_t h = font->glyph[ch].height; + int8_t dx = font->glyph[ch].xOffset; + int8_t dy = font->glyph[ch].yOffset; + uint8_t a = font->glyph[ch].xAdvance; + log_dbug(TAG,"drawChar(%d,%d,'%c') = %u",x,y,c,a); +// log_info(TAG,"%d/%d %+d/%+d, adv %u len %u",(int)w,(int)h,(int)dx,(int)dy,a,l); + if (bg != -1) + fillRect(x,y,dx,a,bg); + drawBitmap(x+dx,y+dy+font->yAdvance-1,w,h,data,fg,bg); + return a; +} + + +unsigned MatrixDisplay::drawText(uint16_t x, uint16_t y, const char *txt, int n, int32_t fg, int32_t bg) +{ + log_dbug(TAG,"drawText(%d,%d,'%s')",x,y,txt); + if (n < 0) + n = strlen(txt); + const Font *font = Fonts+(int)m_font; + uint16_t a = 0, amax = 0; + const char *e = txt + n; + while (txt != e) { + char c = *txt++; + if (c == 0) + break; + if (c == '\n') { + x = 0; + y += font->yAdvance; + if (y+font->yAdvance > m_height) + break; + if (a > amax) + amax = a; + a = 0; + } else if (c == '\r') { + if (a > amax) + amax = a; + a = 0; + x = 0; + } else { + uint16_t cw = charWidth(c); + if (m_posx + cw > m_width) + break; + drawChar(x,y,c,fg,bg); + a += cw; + x += cw; + } + } + return a > amax ? a : amax; +} + + +void MatrixDisplay::drawPicture16(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint16_t *data) +{ + for (uint16_t i = x, xe = x+w; i < xe; ++i) { + for (uint16_t j = y, ye = x+w; j < ye; ++j) + setPixel(i,j,*data++); + } +} + + +void MatrixDisplay::drawPicture32(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const int32_t *data) +{ + for (uint16_t i = x, xe = x+w; i < xe; ++i) { + for (uint16_t j = y, ye = x+w; j < ye; ++j) { + if (*data != -1) + setPixel(i,j,*data); + ++data; + } + } +} + + +void MatrixDisplay::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, int32_t col) +{ + if (col == -1) + col = m_colfg; + uint16_t x = x0; + uint16_t y = y0; + uint16_t dx = x1 - x0; + uint16_t dy = y1 - y0; + float d = 2 * dy - dx; // discriminator + + // Euclidean distance of point (x,y) from line (signed) + float D = 0; + + // Euclidean distance between points (x1, y1) and (x2, y2) + float length = sqrtf((float)(dx * dx + dy * dy)); + + float sin = dx / length; + float cos = dy / length; + while (x <= x1) { +// IntensifyPixels(x, y - 1, D + cos); +// IntensifyPixels(x, y, D); +// IntensifyPixels(x, y + 1, D - cos); + setPixel(x,y,col); + ++x; + if (d <= 0) { + D = D + sin; + d = d + 2 * dy; + } else { + D = D + sin - cos; + d = d + 2 * (dy - dx); + ++y; + } + } +} + + +void MatrixDisplay::drawHLine(uint16_t x, uint16_t y, uint16_t len, int32_t col) +{ + if (col == -1) + col = m_colfg; + if ((x >= m_width) || (y >= m_height)) + return; + if ((x+len) > m_width) + len = m_width - x; + while (len) { + setPixel(x,y,col); + ++x; + --len; + } +} + + +void MatrixDisplay::drawVLine(uint16_t x, uint16_t y, uint16_t len, int32_t col) +{ + if (col == -1) + col = m_colfg; + if ((x >= m_width) || (y >= m_height)) + return; + if ((y+len) > m_height) + len = m_height - y; + while (len) { + setPixel(x,y,col); + ++y; + --len; + } +} + + +void MatrixDisplay::drawRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, int32_t col) +{ + log_dbug(TAG,"drawRect(%u,%u,%u,%u,%x)",x,y,w,h,col); + if (col == -1) + col = m_colfg; + drawHLine(x,y,w,col); + drawHLine(x,y+h-1,w,col); + drawVLine(x,y,h,col); + drawVLine(x+w-1,y,h,col); +// log_hex(TAG,m_disp,m_width*m_height/8,"frame"); +} + + +void MatrixDisplay::fillRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, int32_t col) +{ + if (col == -1) + col = m_colfg; + if ((x >= m_width) || (y >= m_height)) + return; + if ((x+w) > m_width) + w = m_width - x; + if ((y+h) > m_height) + h = m_height - y; + while (h) { + drawHLine(x,y,w,col); + ++y; + --h; + } +} + + +static int32_t getColor16BGR(color_t c) +{ + switch (c) { + case WHITE: return 0xffff; + case BLACK: return 0x0000; + case BLUE: return 0xf800; + case RED: return 0x001f; + case GREEN: return 0x07e0; + case YELLOW: return 0xffe0; + case CYAN: return 0x07ff; + case MAGENTA: return 0xf81f; + default: return -1; + } +} + + +static int32_t getColor18BGR(color_t c) +{ + switch (c) { + case WHITE: return 0xfcfcfc; + case BLACK: return 0x000000; + case BLUE: return 0xfc0000; + case RED: return 0x0000cf; + case GREEN: return 0x00fc00; + case YELLOW: return 0xfcfc00; + case CYAN: return 0x00fcfc; + case MAGENTA: return 0xfc00fc; + default: return -1; + } +} + + +static int32_t getColor16RGB(color_t c) +{ + switch (c) { + case WHITE: return 0xffff; + case BLACK: return 0x0000; + case BLUE: return 0x001f; + case RED: return 0xf800; + case GREEN: return 0x07e0; + case YELLOW: return 0xffe0; + case CYAN: return 0x07ff; + case MAGENTA: return 0xf81f; + default: return -1; + } +} + + +static int32_t getColor18RGB(color_t c) +{ + switch (c) { + case WHITE: return 0xfcfcfc; + case BLACK: return 0x000000; + case BLUE: return 0x0000fc; + case RED: return 0xfc0000; + case GREEN: return 0x00fc00; + case YELLOW: return 0xfcfc00; + case CYAN: return 0x00fcfc; + case MAGENTA: return 0xfc00fc; + default: return -1; + } +} + + +int32_t MatrixDisplay::getColor(color_t c) const +{ + switch (m_colorspace) { + case cs_mono: + switch (c) { + case WHITE: return 0x1; + case BLACK: return 0x0; + default: return -1; + } + case cs_rgb16: + return getColor16RGB(c); + case cs_rgb18: + return getColor18RGB(c); + case cs_bgr16: + return getColor16BGR(c); + case cs_bgr18: + return getColor18BGR(c); + default: + return -1; + } +} + + +int32_t MatrixDisplay::setFgColor(color_t c) +{ + int32_t col = getColor(c); + if (col != -1) + m_colfg = col; + return col; +} + + +int32_t MatrixDisplay::setBgColor(color_t c) +{ + int32_t col = getColor16RGB(c); + if (col != -1) + m_colfg = col; + return col; +} + + +int MatrixDisplay::setFont(unsigned f) +{ + if (f < font_numfonts) { + m_font = (fontid_t)f; + return 0; + } + return -1; +} + + +int MatrixDisplay::setFont(const char *fn) +{ + if (0 == strcasecmp(fn,"native")) { + m_font = (fontid_t)-1; + return 0; + } + if (0 == strcasecmp(fn,"nativedbl")) { + m_font = (fontid_t)-2; + return 0; + } + for (int i = 0; i < font_numfonts; ++i) { + if (0 == strcasecmp(Fonts[i].name,fn)) { + m_font = (fontid_t)i; + return 0; + } + } + return -1; +} + + +void MatrixDisplay::write(const char *txt, int n) +{ + log_dbug(TAG,"write '%s' at %u/%u",txt,m_posx,m_posy); + if (n < 0) + n = strlen(txt); + const char *e = txt + n; + while (txt != e) { + const char *at = txt; + char c = *at; + while (c && (c != '\n') && (c != '\r') && n) { + ++at; + c = *at; + --n; + } + if (at != txt) { + m_posx += drawText(m_posx,m_posy,txt,at-txt,-1,-1); + txt = at; + if (m_posx >= m_width) { + m_posx = m_width - 1; + return; + } + } + if (c == '\n') { + const Font *font = Fonts+(int)m_font; + uint16_t fh = font->yAdvance; + m_posx = 0; + if (m_posy + fh >= m_height) { + m_posy = m_height -1; + return; + } + m_posy += fh; + ++txt; + } else if (c == '\r') { + m_posx = 0; + ++txt; + /* + } else { + unsigned w = drawChar(m_posx,m_posy,c,m_colfg,m_colbg); + m_posx += w; + if (m_posx >= m_width) { + m_posx = m_width - 1; + return; + } + */ + } + } +#if 0 + if (n < 0) + n = strlen(txt); + unsigned width = 0; + for (unsigned x = 0; x < n; ++x) { + width += charWidth(txt[x]); + } + if (m_posx + width > m_width) + return -1; + const Font *font = Fonts+(int)m_font; + uint16_t height = font->yAdvance; + uint16_t widht = 0; + uint16_t x = m_posx; + const char *e = txt + n; + const char *at = txt; + while (at != e) { + char c = *at++; + if ((c < font->first) || (c > font->last)) + continue; + uint8_t ch = c - font->first; + if (x + font->glyph[ch].xAdvance > m_width) + break; + width += font->glyph[ch].xAdvance; + } + e = at; + at = txt; + while (at != e) { + // TODO + const uint8_t *data = font->bitmap + font->glyph[ch].bitmapOffset; + } +#endif +} + diff --git a/drv/display/display.h b/drv/display/display.h index 76f9c53..a0e1c0d 100644 --- a/drv/display/display.h +++ b/drv/display/display.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021, Thomas Maier-Komor + * Copyright (C) 2021-2023, Thomas Maier-Komor * Atrium Firmware Package for ESP * * This program is free software: you can redistribute it and/or modify @@ -20,21 +20,39 @@ #define DISPLAY_H #include "ledcluster.h" +#include "fonts_generic.h" -class DotMatrix; +class MatrixDisplay; class SegmentDisplay; +typedef enum color_e { + BLACK = 1, WHITE, BLUE, RED, GREEN, CYAN, YELLOW, MAGENTA //, PURPLE +} color_t; + +typedef enum colorspace_e + { cs_mono, cs_map8 + , cs_rgb15, cs_rgb16, cs_rgb18, cs_rgb24 + , cs_bgr15, cs_bgr16, cs_bgr18, cs_bgr24 +} colorspace_t; + +#define COLOR_DEFAULT -1 +#define COLOR_NONE -2 + + +color_t color_get(const char *); + struct TextDisplay { - virtual DotMatrix *toDotMatrix() + virtual MatrixDisplay *toMatrixDisplay() { return 0; } virtual SegmentDisplay *toSegmentDisplay() { return 0; } - virtual int clear() - { return -1; } + virtual void clear() + { } + // can display specific char? virtual bool hasChar(char c) const { return false; } @@ -44,13 +62,17 @@ struct TextDisplay virtual int setCursor(bool) { return -1; } - virtual int setPos(uint16_t x, uint16_t y = 0) - { return -1; } + virtual int setPos(uint16_t x, uint16_t y = 0); - virtual uint8_t charsPerLine() const + // may change after changing the font + virtual uint16_t charsPerLine() const { return 0; } - virtual uint8_t numLines() const + virtual uint16_t charWidth(char c) const + { return 1; } + + // may change after changing the font + virtual uint16_t numLines() const { return 0; } virtual int setOn(bool on) @@ -59,43 +81,41 @@ struct TextDisplay static TextDisplay *getFirst() { return Instance; } - TextDisplay *getNext() const - { return m_next; } + uint16_t maxX() const + { return m_width; } - virtual int writeBin(uint8_t) - { return -1; } + uint16_t maxY() const + { return m_height; } + +// virtual int writeBin(uint8_t) +// { return -1; } virtual int writeHex(uint8_t h, bool comma = false) { return -1; } - virtual int write(const char *txt, int n = -1) - { return -1; } + virtual void write(const char *txt, int n = -1) + { } + // support for displaying a-z, A-Z? virtual bool hasAlpha() const { return false; } - virtual uint8_t maxDim() const + virtual uint8_t maxBrightness() const { return 1; } - virtual int getDim() const - { return -1; } - - virtual int setDim(uint8_t) + virtual int getBrightness() const { return -1; } - virtual int sync() + virtual int setBrightness(uint8_t) { return -1; } - virtual int clrEol() - { return -1; } + virtual void flush() + { } - virtual int setPixel(uint16_t x, uint16_t y) - { return -1; } + virtual void clrEol() + { } - virtual int clrPixel(uint16_t x, uint16_t y) - { return -1; } - - virtual int setFont(int) + virtual int setFont(unsigned) { return -1; } virtual int setFont(const char *) @@ -103,54 +123,120 @@ struct TextDisplay void initOK(); + protected: + TextDisplay(uint16_t w, uint16_t h) + : m_width(w) + , m_height(h) + { } + + TextDisplay() + { } + + uint16_t m_width = 0, m_height = 0; + uint16_t m_posx = 0, m_posy = 0; // cursor position + private: static TextDisplay *Instance; - TextDisplay *m_next = 0; }; -struct DotMatrix : public TextDisplay +struct MatrixDisplay : public TextDisplay { - DotMatrix *toDotMatrix() override + explicit MatrixDisplay(colorspace_t cs) + : m_colorspace(cs) + , m_colfg(getColor(WHITE)) + , m_colbg(getColor(BLACK)) + { + } + + MatrixDisplay *toMatrixDisplay() override { return this; } - virtual uint16_t maxX() const - { return 0; } - - virtual uint16_t maxY() const - { return 0; } + /* + int setXY(uint16_t x, uint16_t y) + { + if (x >= m_width) + return -1; + if (y >= m_height) + return -1; + m_posx = x; + m_posy = y; + return 0; + } + */ + + virtual int setFont(unsigned); + virtual int setFont(const char *); + + uint16_t charWidth(char c) const override; + uint16_t fontHeight() const; + void clrEol() override; + uint16_t charsPerLine() const override + { return m_width/8; } + uint16_t numLines() const override + { return m_height/fontHeight(); } + + virtual void setPixel(uint16_t x, uint16_t y, int32_t color) + { } + + // col = -1: use default color (m_colfg/m_colbg) + // col = -2 for bg: do not fill + virtual void fillRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, int32_t col = -1); + virtual void drawRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, int32_t col = -1); + virtual void drawBitmap(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *data, int32_t fg = -1, int32_t bg = -1); + // without transparency + virtual void drawPicture16(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint16_t *data); + // with transparency (*data == -1) and 24bit color depth + virtual void drawPicture32(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const int32_t *data); + virtual void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, int32_t col = -1); + virtual void drawHLine(uint16_t x0, uint16_t y0, uint16_t len, int32_t col = -1); + virtual void drawVLine(uint16_t x0, uint16_t y0, uint16_t len, int32_t col = -1); + virtual unsigned drawText(uint16_t x, uint16_t y, const char *txt, int n = -1, int32_t fg = -1, int32_t bg = -1); + virtual unsigned drawChar(uint16_t x, uint16_t y, char c, int32_t fg, int32_t bg); - virtual int setXY(uint16_t x, uint16_t y) + virtual int setInvert(bool) { return -1; } - virtual int clearRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h) - { return -1; } + virtual int32_t getColor(color_t) const; + virtual int32_t setFgColor(color_t); + virtual int32_t setBgColor(color_t); - virtual int drawRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h) - { return -1; } + void setFgColorVal(int32_t v) + { + if ((v >= 0) && (v <= UINT16_MAX)) + m_colfg = v; + } - virtual int drawBitmap(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *data) - { return -1; } + void setBgColorVal(int32_t v) + { + if ((v >= 0) && (v <= UINT16_MAX)) + m_colbg = v; + } - virtual int drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) - { return -1; } +// virtual int setContrast(uint8_t contrast) +// { return -1; } - virtual int setInvert(bool) - { return -1; } + void flush() override + { } - virtual int setContrast(uint8_t contrast) - { return -1; } - - virtual int sync() - { return -1; } -}; + void clear() override; + void write(const char *txt, int n = -1) override; +#if 0 // TODO + void setClipping(uint16_t xl, uint16_t xh, uint16_t yl, uint16_t yh) + { m_clxl = xl; m_clxh = xh; m_clyl = yl; m_clyh = yh; } +#endif -struct TftDisplay : public DotMatrix -{ - virtual int setColor(uint32_t) - { return -1; } + protected: +// int writeChar(uint16_t x, uint16_t y, char c); +#if 0 // TODO + // clip x/y-low/high + uint16_t m_clxl = 0, m_clxh = 0xffff, m_clyl = 0, m_clyh = 0xffff; +#endif + fontid_t m_font = font_native; + colorspace_t m_colorspace; + int32_t m_colfg, m_colbg; }; @@ -163,35 +249,36 @@ struct SegmentDisplay : public TextDisplay SegmentDisplay *toSegmentDisplay() override { return this; } - int writeHex(uint8_t d, bool comma = false); + //int writeHex(uint8_t d, bool comma = false); int writeChar(char, bool = false); - int writeBin(uint8_t); - int write(const char *txt, int n = -1) override; - int clear() override - { return m_drv->clear(); } + void write(const char *txt, int n = -1) override; + void clear() override + { m_drv->clear(); } int setOn(bool on) override { return m_drv->setOn(on); } - int getDim() const override + int getBrightness() const override { return m_drv->getDim(); } - int setDim(uint8_t d) override + int setBrightness(uint8_t d) override { return m_drv->setDim(d); } // X=0,Y=0: upper left int setPos(uint16_t x, uint16_t y = 0) override; + /* // characters per line - uint8_t charsPerLine() const override - { return m_maxx; } + uint16_t charsPerLine() const override + { return m_width; } // number of lines - uint8_t numLines() const override - { return m_maxy; } + uint16_t numLines() const override + { return m_height; } + */ // maximum brightness - uint8_t maxDim() const override + uint8_t maxBrightness() const override { return m_drv->maxDim(); } bool hasAlpha() const override @@ -202,11 +289,10 @@ struct SegmentDisplay : public TextDisplay protected: static uint16_t char2seg7(char c); static uint16_t char2seg14(char c); + int writeBin(uint8_t); LedCluster *m_drv; addrmode_t m_addrmode; - uint8_t m_maxx, m_maxy; - uint16_t m_pos = 0; }; diff --git a/drv/display/fonts_generic.c b/drv/display/fonts_generic.c new file mode 100644 index 0000000..95b2b30 --- /dev/null +++ b/drv/display/fonts_generic.c @@ -0,0 +1,5113 @@ +#include +#include "font.h" +#include "FreeSans9pt7b.h" +#include "FreeSans12pt7b.h" +#include "FreeMono9pt7b.h" +#include "FreeMono12pt7b.h" +#include "FreeMono18pt7b.h" +#include "FreeMono24pt7b.h" +#include "TomThumb.h" +#include "Org_01.h" +#include "opensanslight-10.h" +#include "opensanslight-12.h" +#include "opensanslight-14.h" +#include "opensanslight-16.h" + + +static const uint8_t FreeSans9pt7b_generic[] = { + // ' ' (0x20) 0x0, offset 0-0, at +0/+1 + // in regular row-major format + // '!' (0x21) 2x13, offset 0-4, at +2/-12 + // in regular row-major format + 0xff, 0xff, 0xf8, 0xc0, + // '"' (0x22) 5x4, offset 4-7, at +1/-12 + // in regular row-major format + 0xde, 0xf7, 0x20, + // '#' (0x23) 10x12, offset 7-22, at +0/-11 + // in regular row-major format + 0x09, 0x86, 0x41, 0x91, 0xff, 0x13, 0x04, 0xc3, + 0x20, 0xc8, 0xff, 0x89, 0x82, 0x61, 0x90, + // '$' (0x24) 9x16, offset 22-40, at +1/-13 + // in regular row-major format + 0x10, 0x1f, 0x14, 0xda, 0x3d, 0x1e, 0x83, 0x40, + 0x78, 0x17, 0x08, 0xf4, 0x7a, 0x35, 0x33, 0xf0, + 0x40, 0x20, + // '%' (0x25) 16x13, offset 40-66, at +1/-12 + // in regular row-major format + 0x38, 0x10, 0xec, 0x20, 0xc6, 0x20, 0xc6, 0x40, + 0xc6, 0x40, 0x6c, 0x80, 0x39, 0x00, 0x01, 0x3c, + 0x02, 0x77, 0x02, 0x63, 0x04, 0x63, 0x04, 0x77, + 0x08, 0x3c, + // '&' (0x26) 11x13, offset 66-84, at +1/-12 + // in regular row-major format + 0x0e, 0x06, 0x60, 0xcc, 0x19, 0x81, 0xe0, 0x18, + 0x0f, 0x03, 0x36, 0xc2, 0xd8, 0x73, 0x06, 0x31, + 0xe3, 0xc4, + // ''' (0x27) 2x4, offset 84-85, at +1/-12 + // in regular row-major format + 0xfe, + // '(' (0x28) 4x17, offset 85-94, at +1/-12 + // in regular row-major format + 0x13, 0x26, 0x6c, 0xcc, 0xcc, 0xc4, 0x66, 0x23, + 0x10, + // ')' (0x29) 4x17, offset 94-103, at +1/-12 + // in regular row-major format + 0x8c, 0x46, 0x63, 0x33, 0x33, 0x32, 0x66, 0x4c, + 0x80, + // '*' (0x2a) 5x5, offset 103-107, at +1/-12 + // in regular row-major format + 0x25, 0x7e, 0xa5, 0x00, + // '+' (0x2b) 6x8, offset 107-113, at +3/-7 + // in regular row-major format + 0x30, 0xc3, 0x3f, 0x30, 0xc3, 0x0c, + // ',' (0x2c) 2x4, offset 113-114, at +2/+0 + // in regular row-major format + 0xd6, + // '-' (0x2d) 4x1, offset 114-115, at +1/-4 + // in regular row-major format + 0xf0, + // '.' (0x2e) 2x1, offset 115-116, at +1/+0 + // in regular row-major format + 0xc0, + // '/' (0x2f) 5x13, offset 116-125, at +0/-12 + // in regular row-major format + 0x08, 0x44, 0x21, 0x10, 0x84, 0x42, 0x11, 0x08, + 0x00, + // '0' (0x30) 8x13, offset 125-138, at +1/-12 + // in regular row-major format + 0x3c, 0x66, 0x42, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, + 0xc3, 0xc3, 0x42, 0x66, 0x3c, + // '1' (0x31) 4x13, offset 138-145, at +3/-12 + // in regular row-major format + 0x11, 0x3f, 0x33, 0x33, 0x33, 0x33, 0x30, + // '2' (0x32) 9x13, offset 145-160, at +1/-12 + // in regular row-major format + 0x3e, 0x31, 0xb0, 0x78, 0x30, 0x18, 0x1c, 0x1c, + 0x1c, 0x18, 0x18, 0x10, 0x08, 0x07, 0xf8, + // '3' (0x33) 8x13, offset 160-173, at +1/-12 + // in regular row-major format + 0x3c, 0x66, 0xc3, 0xc3, 0x03, 0x06, 0x1c, 0x07, + 0x03, 0xc3, 0xc3, 0x66, 0x3c, + // '4' (0x34) 7x13, offset 173-185, at +2/-12 + // in regular row-major format + 0x0c, 0x18, 0x71, 0x62, 0xc9, 0xa3, 0x46, 0xfe, + 0x18, 0x30, 0x60, 0xc0, + // '5' (0x35) 9x13, offset 185-200, at +1/-12 + // in regular row-major format + 0x7f, 0x20, 0x10, 0x08, 0x08, 0x07, 0xf3, 0x8c, + 0x03, 0x01, 0x80, 0xf0, 0x6c, 0x63, 0xe0, + // '6' (0x36) 9x13, offset 200-215, at +1/-12 + // in regular row-major format + 0x1e, 0x31, 0x98, 0x78, 0x0c, 0x06, 0xf3, 0x8d, + 0x83, 0xc1, 0xe0, 0xd0, 0x6c, 0x63, 0xe0, + // '7' (0x37) 8x13, offset 215-228, at +0/-12 + // in regular row-major format + 0xff, 0x03, 0x02, 0x06, 0x04, 0x0c, 0x08, 0x18, + 0x18, 0x18, 0x10, 0x30, 0x30, + // '8' (0x38) 9x13, offset 228-243, at +1/-12 + // in regular row-major format + 0x3e, 0x31, 0xb0, 0x78, 0x3c, 0x1b, 0x18, 0xf8, + 0xc6, 0xc1, 0xe0, 0xf0, 0x6c, 0x63, 0xe0, + // '9' (0x39) 8x13, offset 243-256, at +1/-12 + // in regular row-major format + 0x3c, 0x66, 0xc2, 0xc3, 0xc3, 0xc3, 0x67, 0x3b, + 0x03, 0x03, 0xc2, 0x66, 0x3c, + // ':' (0x3a) 2x10, offset 256-259, at +1/-9 + // in regular row-major format + 0xc0, 0x00, 0x30, + // ';' (0x3b) 3x12, offset 259-264, at +1/-8 + // in regular row-major format + 0xc0, 0x00, 0x00, 0x64, 0xa0, + // '<' (0x3c) 9x9, offset 264-275, at +1/-8 + // in regular row-major format + 0x00, 0x81, 0xc7, 0x8e, 0x0c, 0x07, 0x80, 0x70, + 0x0e, 0x01, 0x80, + // '=' (0x3d) 9x4, offset 275-280, at +1/-5 + // in regular row-major format + 0xff, 0x80, 0x00, 0x1f, 0xf0, + // '>' (0x3e) 9x9, offset 280-291, at +1/-8 + // in regular row-major format + 0x00, 0x70, 0x0e, 0x01, 0xc0, 0x18, 0x38, 0x71, + 0xc0, 0x80, 0x00, + // '?' (0x3f) 9x13, offset 291-306, at +1/-12 + // in regular row-major format + 0x3e, 0x31, 0xb0, 0x78, 0x30, 0x18, 0x18, 0x38, + 0x18, 0x18, 0x0c, 0x00, 0x00, 0x01, 0x80, + // '@' (0x40) 17x16, offset 306-340, at +1/-12 + // in regular row-major format + 0x03, 0xf0, 0x06, 0x0e, 0x06, 0x01, 0x86, 0x00, + 0x66, 0x1d, 0xbb, 0x31, 0xcf, 0x18, 0xc7, 0x98, + 0x63, 0xcc, 0x31, 0xe6, 0x11, 0xb3, 0x99, 0xcc, + 0xf7, 0x86, 0x00, 0x01, 0x80, 0x00, 0x70, 0x40, + 0x0f, 0xe0, + // 'A' (0x41) 12x13, offset 340-360, at +0/-12 + // in regular row-major format + 0x06, 0x00, 0xf0, 0x0f, 0x00, 0x90, 0x19, 0x81, + 0x98, 0x10, 0x83, 0x0c, 0x3f, 0xc2, 0x04, 0x60, + 0x66, 0x06, 0xc0, 0x30, + // 'B' (0x42) 11x13, offset 360-378, at +1/-12 + // in regular row-major format + 0xff, 0x18, 0x33, 0x03, 0x60, 0x6c, 0x0d, 0x83, + 0x3f, 0xc6, 0x06, 0xc0, 0x78, 0x0f, 0x01, 0xe0, + 0x6f, 0xf8, + // 'C' (0x43) 11x13, offset 378-396, at +1/-12 + // in regular row-major format + 0x1f, 0x86, 0x19, 0x81, 0xa0, 0x3c, 0x01, 0x80, + 0x30, 0x06, 0x00, 0xc0, 0x68, 0x0d, 0x83, 0x18, + 0x61, 0xf0, + // 'D' (0x44) 11x13, offset 396-414, at +1/-12 + // in regular row-major format + 0xff, 0x18, 0x33, 0x03, 0x60, 0x3c, 0x07, 0x80, + 0xf0, 0x1e, 0x03, 0xc0, 0x78, 0x0f, 0x03, 0x60, + 0xcf, 0xf0, + // 'E' (0x45) 9x13, offset 414-429, at +1/-12 + // in regular row-major format + 0xff, 0xe0, 0x30, 0x18, 0x0c, 0x06, 0x03, 0xfd, + 0x80, 0xc0, 0x60, 0x30, 0x18, 0x0f, 0xf8, + // 'F' (0x46) 8x13, offset 429-442, at +1/-12 + // in regular row-major format + 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc0, + 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, + // 'G' (0x47) 12x13, offset 442-462, at +1/-12 + // in regular row-major format + 0x0f, 0x83, 0x0e, 0x60, 0x66, 0x03, 0xc0, 0x0c, + 0x00, 0xc1, 0xfc, 0x03, 0xc0, 0x36, 0x03, 0x60, + 0x73, 0x0f, 0x0f, 0x10, + // 'H' (0x48) 11x13, offset 462-480, at +1/-12 + // in regular row-major format + 0xc0, 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x07, 0x80, + 0xff, 0xfe, 0x03, 0xc0, 0x78, 0x0f, 0x01, 0xe0, + 0x3c, 0x06, + // 'I' (0x49) 2x13, offset 480-484, at +2/-12 + // in regular row-major format + 0xff, 0xff, 0xff, 0xc0, + // 'J' (0x4a) 7x13, offset 484-496, at +1/-12 + // in regular row-major format + 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0x83, 0x07, + 0x8f, 0x1e, 0x27, 0x80, + // 'K' (0x4b) 11x13, offset 496-514, at +1/-12 + // in regular row-major format + 0xc0, 0xd8, 0x33, 0x0c, 0x63, 0x0c, 0xc1, 0xb8, + 0x3f, 0x07, 0x30, 0xc3, 0x18, 0x63, 0x06, 0x60, + 0x6c, 0x0c, + // 'L' (0x4c) 8x13, offset 514-527, at +1/-12 + // in regular row-major format + 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, + 0xc0, 0xc0, 0xc0, 0xc0, 0xff, + // 'M' (0x4d) 13x13, offset 527-549, at +1/-12 + // in regular row-major format + 0xe0, 0x3f, 0x01, 0xfc, 0x1f, 0xe0, 0xfd, 0x05, + 0xec, 0x6f, 0x63, 0x79, 0x13, 0xcd, 0x9e, 0x6c, + 0xf1, 0x47, 0x8e, 0x3c, 0x71, 0x80, + // 'N' (0x4e) 11x13, offset 549-567, at +1/-12 + // in regular row-major format + 0xe0, 0x7c, 0x0f, 0xc1, 0xe8, 0x3d, 0x87, 0x98, + 0xf1, 0x1e, 0x33, 0xc3, 0x78, 0x6f, 0x07, 0xe0, + 0x7c, 0x0e, + // 'O' (0x4f) 13x13, offset 567-589, at +1/-12 + // in regular row-major format + 0x0f, 0x81, 0x83, 0x18, 0x0c, 0xc0, 0x6c, 0x01, + 0xe0, 0x0f, 0x00, 0x78, 0x03, 0xc0, 0x1b, 0x01, + 0x98, 0x0c, 0x60, 0xc0, 0xf8, 0x00, + // 'P' (0x50) 10x13, offset 589-606, at +1/-12 + // in regular row-major format + 0xff, 0x30, 0x6c, 0x0f, 0x03, 0xc0, 0xf0, 0x6f, + 0xf3, 0x00, 0xc0, 0x30, 0x0c, 0x03, 0x00, 0xc0, + 0x00, + // 'Q' (0x51) 13x14, offset 606-629, at +1/-12 + // in regular row-major format + 0x0f, 0x81, 0x83, 0x18, 0x0c, 0xc0, 0x6c, 0x01, + 0xe0, 0x0f, 0x00, 0x78, 0x03, 0xc0, 0x1b, 0x01, + 0x98, 0x6c, 0x60, 0xc0, 0xfb, 0x00, 0x08, + // 'R' (0x52) 12x13, offset 629-649, at +1/-12 + // in regular row-major format + 0xff, 0x8c, 0x0e, 0xc0, 0x6c, 0x06, 0xc0, 0x6c, + 0x0c, 0xff, 0x8c, 0x0e, 0xc0, 0x6c, 0x06, 0xc0, + 0x6c, 0x06, 0xc0, 0x70, + // 'S' (0x53) 10x13, offset 649-666, at +1/-12 + // in regular row-major format + 0x3f, 0x18, 0x6c, 0x0f, 0x03, 0xc0, 0x1e, 0x01, + 0xf0, 0x0e, 0x00, 0xf0, 0x3c, 0x0d, 0x86, 0x3f, + 0x00, + // 'T' (0x54) 9x13, offset 666-681, at +1/-12 + // in regular row-major format + 0xff, 0x86, 0x03, 0x01, 0x80, 0xc0, 0x60, 0x30, + 0x18, 0x0c, 0x06, 0x03, 0x01, 0x80, 0xc0, + // 'U' (0x55) 11x13, offset 681-699, at +1/-12 + // in regular row-major format + 0xc0, 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x07, 0x80, + 0xf0, 0x1e, 0x03, 0xc0, 0x78, 0x0f, 0x01, 0xb0, + 0x61, 0xf0, + // 'V' (0x56) 11x13, offset 699-717, at +0/-12 + // in regular row-major format + 0xc0, 0x6c, 0x0d, 0x81, 0x10, 0x63, 0x0c, 0x61, + 0x04, 0x60, 0xcc, 0x19, 0x01, 0x60, 0x3c, 0x07, + 0x00, 0x60, + // 'W' (0x57) 17x13, offset 717-745, at +0/-12 + // in regular row-major format + 0xc1, 0x81, 0x30, 0xe1, 0x98, 0x70, 0xcc, 0x28, + 0x66, 0x26, 0x21, 0x13, 0x30, 0xc8, 0x98, 0x6c, + 0x4c, 0x14, 0x34, 0x0a, 0x1a, 0x07, 0x07, 0x03, + 0x03, 0x80, 0x81, 0x80, + // 'X' (0x58) 12x13, offset 745-765, at +0/-12 + // in regular row-major format + 0x60, 0x63, 0x0c, 0x30, 0xc1, 0x98, 0x0f, 0x00, + 0xe0, 0x06, 0x00, 0xf0, 0x19, 0x01, 0x98, 0x30, + 0xc6, 0x0e, 0x60, 0x60, + // 'Y' (0x59) 12x13, offset 765-785, at +0/-12 + // in regular row-major format + 0xc0, 0x36, 0x06, 0x30, 0xc3, 0x0c, 0x19, 0x81, + 0xd8, 0x0f, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, + 0x00, 0x60, 0x06, 0x00, + // 'Z' (0x5a) 10x13, offset 785-802, at +1/-12 + // in regular row-major format + 0xff, 0xc0, 0x60, 0x30, 0x0c, 0x06, 0x03, 0x01, + 0xc0, 0x60, 0x30, 0x18, 0x06, 0x03, 0x00, 0xff, + 0xc0, + // '[' (0x5b) 3x17, offset 802-809, at +1/-12 + // in regular row-major format + 0xfb, 0x6d, 0xb6, 0xdb, 0x6d, 0xb6, 0xe0, + // '\' (0x5c) 5x13, offset 809-818, at +0/-12 + // in regular row-major format + 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, + 0x80, + // ']' (0x5d) 3x17, offset 818-825, at +0/-12 + // in regular row-major format + 0xed, 0xb6, 0xdb, 0x6d, 0xb6, 0xdb, 0xe0, + // '^' (0x5e) 7x7, offset 825-832, at +1/-12 + // in regular row-major format + 0x30, 0x60, 0xa2, 0x44, 0xd8, 0xa1, 0x80, + // '_' (0x5f) 10x1, offset 832-834, at +0/+3 + // in regular row-major format + 0xff, 0xc0, + // '`' (0x60) 4x3, offset 834-836, at +0/-12 + // in regular row-major format + 0xc6, 0x30, + // 'a' (0x61) 9x10, offset 836-848, at +1/-9 + // in regular row-major format + 0x7e, 0x71, 0xb0, 0xc0, 0x60, 0xf3, 0xdb, 0x0d, + 0x86, 0xc7, 0x3d, 0xc0, + // 'b' (0x62) 9x13, offset 848-863, at +1/-12 + // in regular row-major format + 0xc0, 0x60, 0x30, 0x1b, 0xce, 0x36, 0x0f, 0x07, + 0x83, 0xc1, 0xe0, 0xf0, 0x7c, 0x6d, 0xe0, + // 'c' (0x63) 8x10, offset 863-873, at +1/-9 + // in regular row-major format + 0x3c, 0x66, 0xc3, 0xc0, 0xc0, 0xc0, 0xc0, 0xc3, + 0x66, 0x3c, + // 'd' (0x64) 8x13, offset 873-886, at +1/-12 + // in regular row-major format + 0x03, 0x03, 0x03, 0x3b, 0x67, 0xc3, 0xc3, 0xc3, + 0xc3, 0xc3, 0xc3, 0x67, 0x3b, + // 'e' (0x65) 8x10, offset 886-896, at +1/-9 + // in regular row-major format + 0x3c, 0x66, 0xc3, 0xc3, 0xff, 0xc0, 0xc0, 0xc3, + 0x66, 0x3c, + // 'f' (0x66) 4x13, offset 896-903, at +1/-12 + // in regular row-major format + 0x36, 0x6f, 0x66, 0x66, 0x66, 0x66, 0x60, + // 'g' (0x67) 8x14, offset 903-917, at +1/-9 + // in regular row-major format + 0x3b, 0x67, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, + 0x67, 0x3b, 0x03, 0x03, 0xc6, 0x7c, + // 'h' (0x68) 8x13, offset 917-930, at +1/-12 + // in regular row-major format + 0xc0, 0xc0, 0xc0, 0xde, 0xe3, 0xc3, 0xc3, 0xc3, + 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, + // 'i' (0x69) 2x13, offset 930-934, at +1/-12 + // in regular row-major format + 0xc3, 0xff, 0xff, 0xc0, + // 'j' (0x6a) 4x17, offset 934-943, at +0/-12 + // in regular row-major format + 0x30, 0x03, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0xe0, + // 'k' (0x6b) 9x13, offset 943-958, at +1/-12 + // in regular row-major format + 0xc0, 0x60, 0x30, 0x18, 0x4c, 0x46, 0x63, 0x61, + 0xf0, 0xec, 0x62, 0x31, 0x98, 0x6c, 0x30, + // 'l' (0x6c) 2x13, offset 958-962, at +1/-12 + // in regular row-major format + 0xff, 0xff, 0xff, 0xc0, + // 'm' (0x6d) 13x10, offset 962-979, at +1/-9 + // in regular row-major format + 0xde, 0xf7, 0x1c, 0xf0, 0xc7, 0x86, 0x3c, 0x31, + 0xe1, 0x8f, 0x0c, 0x78, 0x63, 0xc3, 0x1e, 0x18, + 0xc0, + // 'n' (0x6e) 8x10, offset 979-989, at +1/-9 + // in regular row-major format + 0xde, 0xe3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, + 0xc3, 0xc3, + // 'o' (0x6f) 8x10, offset 989-999, at +1/-9 + // in regular row-major format + 0x3c, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, + 0x66, 0x3c, + // 'p' (0x70) 9x13, offset 999-1014, at +1/-9 + // in regular row-major format + 0xde, 0x71, 0xb0, 0x78, 0x3c, 0x1e, 0x0f, 0x07, + 0x83, 0xe3, 0x6f, 0x30, 0x18, 0x0c, 0x00, + // 'q' (0x71) 8x13, offset 1014-1027, at +1/-9 + // in regular row-major format + 0x3b, 0x67, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, + 0x67, 0x3b, 0x03, 0x03, 0x03, + // 'r' (0x72) 5x10, offset 1027-1034, at +1/-9 + // in regular row-major format + 0xdf, 0x31, 0x8c, 0x63, 0x18, 0xc6, 0x00, + // 's' (0x73) 8x10, offset 1034-1044, at +1/-9 + // in regular row-major format + 0x3e, 0xe3, 0xc0, 0xc0, 0xe0, 0x3c, 0x07, 0xc3, + 0xe3, 0x7e, + // 't' (0x74) 4x12, offset 1044-1050, at +1/-11 + // in regular row-major format + 0x66, 0xf6, 0x66, 0x66, 0x66, 0x67, + // 'u' (0x75) 8x10, offset 1050-1060, at +1/-9 + // in regular row-major format + 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, + 0xc7, 0x7b, + // 'v' (0x76) 9x10, offset 1060-1072, at +0/-9 + // in regular row-major format + 0xc1, 0xa0, 0x98, 0xcc, 0x42, 0x21, 0xb0, 0xd0, + 0x28, 0x1c, 0x0c, 0x00, + // 'w' (0x77) 13x10, offset 1072-1089, at +0/-9 + // in regular row-major format + 0xc6, 0x1e, 0x38, 0x91, 0xc4, 0xca, 0x66, 0xd3, + 0x16, 0xd0, 0xa6, 0x87, 0x1c, 0x38, 0xc0, 0xc6, + 0x00, + // 'x' (0x78) 8x10, offset 1089-1099, at +0/-9 + // in regular row-major format + 0x43, 0x62, 0x36, 0x1c, 0x18, 0x1c, 0x3c, 0x26, + 0x62, 0x43, + // 'y' (0x79) 9x14, offset 1099-1115, at +0/-9 + // in regular row-major format + 0xc1, 0x21, 0x98, 0xcc, 0x42, 0x61, 0xb0, 0xd0, + 0x38, 0x1c, 0x0c, 0x06, 0x03, 0x01, 0x03, 0x00, + // 'z' (0x7a) 7x10, offset 1115-1124, at +1/-9 + // in regular row-major format + 0xfe, 0x0c, 0x30, 0xc1, 0x86, 0x18, 0x20, 0xc1, + 0xfc, + // '{' (0x7b) 4x17, offset 1124-1133, at +1/-12 + // in regular row-major format + 0x36, 0x66, 0x66, 0x6e, 0xce, 0x66, 0x66, 0x66, + 0x30, + // '|' (0x7c) 2x17, offset 1133-1138, at +2/-12 + // in regular row-major format + 0xff, 0xff, 0xff, 0xff, 0xc0, + // '}' (0x7d) 4x17, offset 1138-1147, at +1/-12 + // in regular row-major format + 0xc6, 0x66, 0x66, 0x67, 0x37, 0x66, 0x66, 0x66, + 0xc0, +}; + + +static const uint8_t FreeSans12pt7b_generic[] = { + // ' ' (0x20) 0x0, offset 0-0, at +0/+1 + // in regular row-major format + // '!' (0x21) 2x18, offset 0-5, at +3/-17 + // in regular row-major format + 0xff, 0xff, 0xff, 0xf0, 0xf0, + // '"' (0x22) 6x6, offset 5-10, at +1/-16 + // in regular row-major format + 0xcf, 0x3c, 0xf3, 0x8a, 0x20, + // '#' (0x23) 13x16, offset 10-36, at +0/-15 + // in regular row-major format + 0x06, 0x30, 0x31, 0x03, 0x18, 0x18, 0xc7, 0xff, + 0xbf, 0xfc, 0x31, 0x03, 0x18, 0x18, 0xc7, 0xff, + 0xbf, 0xfc, 0x31, 0x01, 0x18, 0x18, 0xc0, 0xc6, + 0x06, 0x30, + // '$' (0x24) 11x20, offset 36-64, at +1/-17 + // in regular row-major format + 0x04, 0x03, 0xe1, 0xff, 0x72, 0x6c, 0x47, 0x88, + 0xf1, 0x07, 0x20, 0x7e, 0x03, 0xf0, 0x17, 0x02, + 0x3c, 0x47, 0x88, 0xf1, 0x1b, 0x26, 0x7f, 0xc3, + 0xe0, 0x10, 0x02, 0x00, + // '%' (0x25) 20x17, offset 64-107, at +1/-16 + // in regular row-major format + 0x00, 0x06, 0x03, 0xc0, 0x40, 0x7e, 0x0c, 0x0e, + 0x70, 0x80, 0xc3, 0x18, 0x0c, 0x31, 0x00, 0xe7, + 0x30, 0x07, 0xe6, 0x00, 0x3c, 0x40, 0x00, 0x0c, + 0x7c, 0x00, 0x8f, 0xe0, 0x19, 0xc7, 0x01, 0x18, + 0x30, 0x31, 0x83, 0x02, 0x1c, 0x70, 0x40, 0xfe, + 0x04, 0x07, 0xc0, + // '&' (0x26) 14x17, offset 107-137, at +1/-16 + // in regular row-major format + 0x0f, 0x00, 0x7e, 0x03, 0x9c, 0x0c, 0x30, 0x30, + 0xc0, 0xe7, 0x01, 0xf8, 0x03, 0x80, 0x3e, 0x01, + 0xcc, 0x6e, 0x19, 0xb0, 0x7c, 0xc0, 0xf3, 0x03, + 0xce, 0x1f, 0x9f, 0xe6, 0x1e, 0x1c, + // ''' (0x27) 2x6, offset 137-139, at +1/-16 + // in regular row-major format + 0xff, 0xa0, + // '(' (0x28) 5x23, offset 139-154, at +2/-17 + // in regular row-major format + 0x08, 0x8c, 0x66, 0x31, 0x98, 0xc6, 0x31, 0x8c, + 0x63, 0x08, 0x63, 0x08, 0x61, 0x0c, 0x20, + // ')' (0x29) 5x23, offset 154-169, at +1/-17 + // in regular row-major format + 0x82, 0x18, 0xc3, 0x18, 0xc3, 0x18, 0xc6, 0x31, + 0x8c, 0x62, 0x31, 0x88, 0xc4, 0x62, 0x00, + // '*' (0x2a) 7x7, offset 169-176, at +1/-17 + // in regular row-major format + 0x10, 0x23, 0x5b, 0xe3, 0x8d, 0x91, 0x00, + // '+' (0x2b) 10x11, offset 176-190, at +2/-10 + // in regular row-major format + 0x0c, 0x03, 0x00, 0xc0, 0x30, 0xff, 0xff, 0xf0, + 0xc0, 0x30, 0x0c, 0x03, 0x00, 0xc0, + // ',' (0x2c) 2x6, offset 190-192, at +2/-1 + // in regular row-major format + 0xf5, 0x60, + // '-' (0x2d) 6x2, offset 192-194, at +1/-7 + // in regular row-major format + 0xff, 0xf0, + // '.' (0x2e) 2x2, offset 194-195, at +2/-1 + // in regular row-major format + 0xf0, + // '/' (0x2f) 7x18, offset 195-211, at +0/-17 + // in regular row-major format + 0x02, 0x0c, 0x10, 0x20, 0xc1, 0x02, 0x0c, 0x10, + 0x20, 0xc1, 0x02, 0x0c, 0x10, 0x20, 0xc1, 0x00, + // '0' (0x30) 11x17, offset 211-235, at +1/-16 + // in regular row-major format + 0x1f, 0x07, 0xf1, 0xc7, 0x30, 0x6e, 0x0f, 0x80, + 0xf0, 0x1e, 0x03, 0xc0, 0x78, 0x0f, 0x01, 0xe0, + 0x3c, 0x0e, 0xc1, 0x9c, 0x71, 0xfc, 0x1f, 0x00, + // '1' (0x31) 5x17, offset 235-246, at +3/-16 + // in regular row-major format + 0x08, 0xcf, 0xff, 0x8c, 0x63, 0x18, 0xc6, 0x31, + 0x8c, 0x63, 0x18, + // '2' (0x32) 11x17, offset 246-270, at +1/-16 + // in regular row-major format + 0x1f, 0x0f, 0xf9, 0x87, 0x60, 0x7c, 0x06, 0x00, + 0xc0, 0x18, 0x07, 0x01, 0xc0, 0xf0, 0x78, 0x1c, + 0x06, 0x00, 0x80, 0x30, 0x07, 0xff, 0xff, 0xe0, + // '3' (0x33) 11x17, offset 270-294, at +1/-16 + // in regular row-major format + 0x3f, 0x0f, 0xf3, 0x87, 0x60, 0x6c, 0x0c, 0x01, + 0x80, 0x70, 0x7c, 0x0f, 0x80, 0x18, 0x01, 0x80, + 0x3c, 0x07, 0x80, 0xd8, 0x73, 0xfc, 0x1f, 0x00, + // '4' (0x34) 11x17, offset 294-318, at +1/-16 + // in regular row-major format + 0x01, 0x80, 0x70, 0x0e, 0x03, 0xc0, 0xd8, 0x1b, + 0x06, 0x61, 0x8c, 0x21, 0x8c, 0x33, 0x06, 0x7f, + 0xff, 0xfe, 0x03, 0x00, 0x60, 0x0c, 0x01, 0x80, + // '5' (0x35) 11x17, offset 318-342, at +1/-16 + // in regular row-major format + 0x3f, 0xcf, 0xf9, 0x80, 0x30, 0x06, 0x00, 0xde, + 0x1f, 0xe7, 0x0e, 0x00, 0xe0, 0x0c, 0x01, 0x80, + 0x30, 0x07, 0x81, 0xf8, 0x73, 0xfc, 0x1f, 0x00, + // '6' (0x36) 11x17, offset 342-366, at +1/-16 + // in regular row-major format + 0x0f, 0x07, 0xf9, 0xc3, 0x30, 0x74, 0x01, 0x80, + 0x33, 0xc7, 0xfe, 0xf0, 0xdc, 0x1f, 0x01, 0xe0, + 0x3c, 0x06, 0xc1, 0xdc, 0x71, 0xfc, 0x1f, 0x00, + // '7' (0x37) 11x17, offset 366-390, at +1/-16 + // in regular row-major format + 0xff, 0xff, 0xfc, 0x01, 0x00, 0x60, 0x18, 0x02, + 0x00, 0xc0, 0x30, 0x06, 0x01, 0x80, 0x30, 0x04, + 0x01, 0x80, 0x30, 0x06, 0x01, 0x80, 0x30, 0x00, + // '8' (0x38) 11x17, offset 390-414, at +1/-16 + // in regular row-major format + 0x1f, 0x07, 0xf1, 0xc7, 0x30, 0x66, 0x0c, 0xc1, + 0x8c, 0x61, 0xfc, 0x3f, 0x8e, 0x3b, 0x01, 0xe0, + 0x3c, 0x07, 0x80, 0xd8, 0x31, 0xfc, 0x1f, 0x00, + // '9' (0x39) 11x17, offset 414-438, at +1/-16 + // in regular row-major format + 0x1f, 0x07, 0xf1, 0xc7, 0x70, 0x6c, 0x07, 0x80, + 0xf0, 0x1e, 0x07, 0x61, 0xef, 0xfc, 0x79, 0x80, + 0x30, 0x05, 0x81, 0x98, 0x73, 0xfc, 0x1e, 0x00, + // ':' (0x3a) 2x13, offset 438-442, at +2/-12 + // in regular row-major format + 0xf0, 0x00, 0x03, 0xc0, + // ';' (0x3b) 2x16, offset 442-446, at +2/-11 + // in regular row-major format + 0xf0, 0x00, 0x0f, 0x56, + // '<' (0x3c) 12x12, offset 446-464, at +1/-11 + // in regular row-major format + 0x00, 0x00, 0x07, 0x01, 0xe0, 0xf8, 0x3c, 0x0f, + 0x00, 0xe0, 0x07, 0xc0, 0x0f, 0x00, 0x3c, 0x00, + 0xf0, 0x01, + // '=' (0x3d) 12x6, offset 464-473, at +1/-8 + // in regular row-major format + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, + // '>' (0x3e) 12x12, offset 473-491, at +1/-11 + // in regular row-major format + 0x00, 0x0e, 0x00, 0x78, 0x01, 0xf0, 0x07, 0xc0, + 0x0f, 0x00, 0x70, 0x1e, 0x0f, 0x03, 0xc0, 0xf0, + 0x08, 0x00, + // '?' (0x3f) 10x18, offset 491-514, at +2/-17 + // in regular row-major format + 0x1f, 0x1f, 0xee, 0x1b, 0x03, 0xc0, 0xc0, 0x30, + 0x0c, 0x06, 0x03, 0x81, 0xc0, 0xe0, 0x30, 0x0c, + 0x03, 0x00, 0x00, 0x00, 0x0c, 0x03, 0x00, + // '@' (0x40) 22x21, offset 514-572, at +1/-17 + // in regular row-major format + 0x00, 0xfe, 0x00, 0x0f, 0xfe, 0x00, 0xf0, 0x3e, + 0x07, 0x00, 0x3c, 0x38, 0x00, 0x30, 0xc1, 0xe0, + 0x66, 0x0f, 0xd9, 0xd8, 0x61, 0xc3, 0xc3, 0x07, + 0x0f, 0x1c, 0x1c, 0x3c, 0x60, 0x60, 0xf1, 0x81, + 0x83, 0xc6, 0x06, 0x1b, 0x18, 0x38, 0xee, 0x71, + 0xe7, 0x18, 0xfd, 0xf8, 0x71, 0xe7, 0xc0, 0xe0, + 0x00, 0x01, 0xe0, 0x00, 0x01, 0xff, 0xc0, 0x01, + 0xfc, 0x00, + // 'A' (0x41) 16x18, offset 572-608, at +0/-17 + // in regular row-major format + 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x07, 0xe0, + 0x06, 0x60, 0x06, 0x60, 0x0e, 0x70, 0x0c, 0x30, + 0x0c, 0x30, 0x1c, 0x38, 0x18, 0x18, 0x1f, 0xf8, + 0x3f, 0xfc, 0x30, 0x1c, 0x30, 0x0c, 0x70, 0x0e, + 0x60, 0x06, 0x60, 0x06, + // 'B' (0x42) 13x18, offset 608-638, at +2/-17 + // in regular row-major format + 0xff, 0xc7, 0xff, 0x30, 0x19, 0x80, 0x6c, 0x03, + 0x60, 0x1b, 0x00, 0xd8, 0x0c, 0xff, 0xc7, 0xff, + 0x30, 0x0d, 0x80, 0x3c, 0x01, 0xe0, 0x0f, 0x00, + 0x78, 0x06, 0xff, 0xf7, 0xfe, 0x00, + // 'C' (0x43) 15x18, offset 638-672, at +1/-17 + // in regular row-major format + 0x07, 0xe0, 0x3f, 0xf0, 0xe0, 0x73, 0x80, 0x66, + 0x00, 0x6c, 0x00, 0x30, 0x00, 0x60, 0x00, 0xc0, + 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x06, 0x00, + 0x6c, 0x00, 0xdc, 0x03, 0x1e, 0x0e, 0x1f, 0xf8, + 0x0f, 0xc0, + // 'D' (0x44) 14x18, offset 672-704, at +2/-17 + // in regular row-major format + 0xff, 0x83, 0xff, 0x8c, 0x07, 0x30, 0x0e, 0xc0, + 0x1b, 0x00, 0x7c, 0x00, 0xf0, 0x03, 0xc0, 0x0f, + 0x00, 0x3c, 0x00, 0xf0, 0x03, 0xc0, 0x1f, 0x00, + 0x6c, 0x03, 0xb0, 0x1c, 0xff, 0xe3, 0xff, 0x00, + // 'E' (0x45) 12x18, offset 704-731, at +2/-17 + // in regular row-major format + 0xff, 0xff, 0xff, 0xc0, 0x0c, 0x00, 0xc0, 0x0c, + 0x00, 0xc0, 0x0c, 0x00, 0xff, 0xef, 0xfe, 0xc0, + 0x0c, 0x00, 0xc0, 0x0c, 0x00, 0xc0, 0x0c, 0x00, + 0xff, 0xff, 0xff, + // 'F' (0x46) 11x18, offset 731-756, at +2/-17 + // in regular row-major format + 0xff, 0xff, 0xff, 0x00, 0x60, 0x0c, 0x01, 0x80, + 0x30, 0x06, 0x00, 0xff, 0xdf, 0xfb, 0x00, 0x60, + 0x0c, 0x01, 0x80, 0x30, 0x06, 0x00, 0xc0, 0x18, + 0x00, + // 'G' (0x47) 16x18, offset 756-792, at +1/-17 + // in regular row-major format + 0x07, 0xf0, 0x1f, 0xfc, 0x3c, 0x1e, 0x70, 0x06, + 0x60, 0x03, 0xe0, 0x00, 0xc0, 0x00, 0xc0, 0x00, + 0xc0, 0x7f, 0xc0, 0x7f, 0xc0, 0x03, 0xc0, 0x03, + 0x60, 0x03, 0x60, 0x07, 0x30, 0x0f, 0x3c, 0x1f, + 0x1f, 0xfb, 0x07, 0xe1, + // 'H' (0x48) 13x18, offset 792-822, at +2/-17 + // in regular row-major format + 0xc0, 0x1e, 0x00, 0xf0, 0x07, 0x80, 0x3c, 0x01, + 0xe0, 0x0f, 0x00, 0x78, 0x03, 0xff, 0xff, 0xff, + 0xf0, 0x07, 0x80, 0x3c, 0x01, 0xe0, 0x0f, 0x00, + 0x78, 0x03, 0xc0, 0x1e, 0x00, 0xc0, + // 'I' (0x49) 2x18, offset 822-827, at +2/-17 + // in regular row-major format + 0xff, 0xff, 0xff, 0xff, 0xf0, + // 'J' (0x4a) 9x18, offset 827-848, at +1/-17 + // in regular row-major format + 0x01, 0x80, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, + 0x03, 0x01, 0x80, 0xc0, 0x60, 0x3c, 0x1e, 0x0f, + 0x07, 0xc7, 0x7f, 0x1f, 0x00, + // 'K' (0x4b) 14x18, offset 848-880, at +2/-17 + // in regular row-major format + 0xc0, 0x3b, 0x01, 0xcc, 0x0e, 0x30, 0x70, 0xc3, + 0x83, 0x1c, 0x0c, 0xe0, 0x33, 0x80, 0xde, 0x03, + 0xdc, 0x0e, 0x38, 0x30, 0x60, 0xc1, 0xc3, 0x03, + 0x8c, 0x06, 0x30, 0x1c, 0xc0, 0x3b, 0x00, 0x60, + // 'L' (0x4c) 10x18, offset 880-903, at +2/-17 + // in regular row-major format + 0xc0, 0x30, 0x0c, 0x03, 0x00, 0xc0, 0x30, 0x0c, + 0x03, 0x00, 0xc0, 0x30, 0x0c, 0x03, 0x00, 0xc0, + 0x30, 0x0c, 0x03, 0x00, 0xff, 0xff, 0xf0, + // 'M' (0x4d) 16x18, offset 903-939, at +2/-17 + // in regular row-major format + 0xe0, 0x07, 0xe0, 0x07, 0xf0, 0x0f, 0xf0, 0x0f, + 0xd0, 0x0f, 0xd8, 0x1b, 0xd8, 0x1b, 0xd8, 0x1b, + 0xcc, 0x33, 0xcc, 0x33, 0xcc, 0x33, 0xc6, 0x63, + 0xc6, 0x63, 0xc6, 0x63, 0xc3, 0xc3, 0xc3, 0xc3, + 0xc3, 0xc3, 0xc1, 0x83, + // 'N' (0x4e) 13x18, offset 939-969, at +2/-17 + // in regular row-major format + 0xe0, 0x1f, 0x00, 0xfc, 0x07, 0xe0, 0x3d, 0x81, + 0xee, 0x0f, 0x30, 0x79, 0xc3, 0xc6, 0x1e, 0x18, + 0xf0, 0xe7, 0x83, 0x3c, 0x1d, 0xe0, 0x6f, 0x01, + 0xf8, 0x0f, 0xc0, 0x3e, 0x01, 0xc0, + // 'O' (0x4f) 17x18, offset 969-1008, at +1/-17 + // in regular row-major format + 0x03, 0xe0, 0x0f, 0xfc, 0x0f, 0x07, 0x86, 0x00, + 0xc6, 0x00, 0x33, 0x00, 0x1b, 0x00, 0x07, 0x80, + 0x03, 0xc0, 0x01, 0xe0, 0x00, 0xf0, 0x00, 0x78, + 0x00, 0x36, 0x00, 0x33, 0x00, 0x18, 0xc0, 0x18, + 0x78, 0x3c, 0x1f, 0xfc, 0x03, 0xf8, 0x00, + // 'P' (0x50) 12x18, offset 1008-1035, at +2/-17 + // in regular row-major format + 0xff, 0x8f, 0xfe, 0xc0, 0x6c, 0x03, 0xc0, 0x3c, + 0x03, 0xc0, 0x3c, 0x07, 0xff, 0xef, 0xfc, 0xc0, + 0x0c, 0x00, 0xc0, 0x0c, 0x00, 0xc0, 0x0c, 0x00, + 0xc0, 0x0c, 0x00, + // 'Q' (0x51) 17x19, offset 1035-1076, at +1/-17 + // in regular row-major format + 0x03, 0xe0, 0x0f, 0xfc, 0x0f, 0x07, 0x86, 0x00, + 0xc6, 0x00, 0x33, 0x00, 0x1b, 0x00, 0x07, 0x80, + 0x03, 0xc0, 0x01, 0xe0, 0x00, 0xf0, 0x00, 0x78, + 0x00, 0x36, 0x00, 0x33, 0x01, 0x98, 0xc0, 0xfc, + 0x78, 0x3c, 0x1f, 0xff, 0x03, 0xf9, 0x80, 0x00, + 0x40, + // 'R' (0x52) 14x18, offset 1076-1108, at +2/-17 + // in regular row-major format + 0xff, 0xc3, 0xff, 0xcc, 0x03, 0xb0, 0x06, 0xc0, + 0x1b, 0x00, 0x6c, 0x01, 0xb0, 0x0c, 0xff, 0xe3, + 0xff, 0xcc, 0x03, 0xb0, 0x06, 0xc0, 0x1b, 0x00, + 0x6c, 0x01, 0xb0, 0x06, 0xc0, 0x1b, 0x00, 0x70, + // 'S' (0x53) 14x18, offset 1108-1140, at +1/-17 + // in regular row-major format + 0x0f, 0xe0, 0x7f, 0xc3, 0x83, 0x9c, 0x07, 0x60, + 0x0d, 0x80, 0x06, 0x00, 0x1e, 0x00, 0x3f, 0x80, + 0x3f, 0xc0, 0x0f, 0x80, 0x07, 0xc0, 0x0f, 0x00, + 0x3e, 0x00, 0xde, 0x0e, 0x3f, 0xf0, 0x3f, 0x80, + // 'T' (0x54) 12x18, offset 1140-1167, at +1/-17 + // in regular row-major format + 0xff, 0xff, 0xff, 0x06, 0x00, 0x60, 0x06, 0x00, + 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, + 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, + 0x06, 0x00, 0x60, + // 'U' (0x55) 13x18, offset 1167-1197, at +2/-17 + // in regular row-major format + 0xc0, 0x1e, 0x00, 0xf0, 0x07, 0x80, 0x3c, 0x01, + 0xe0, 0x0f, 0x00, 0x78, 0x03, 0xc0, 0x1e, 0x00, + 0xf0, 0x07, 0x80, 0x3c, 0x01, 0xe0, 0x0f, 0x80, + 0xee, 0x0e, 0x3f, 0xe0, 0x7c, 0x00, + // 'V' (0x56) 15x18, offset 1197-1231, at +0/-17 + // in regular row-major format + 0x60, 0x06, 0xc0, 0x1d, 0xc0, 0x31, 0x80, 0x63, + 0x01, 0xc7, 0x03, 0x06, 0x06, 0x0c, 0x1c, 0x1c, + 0x30, 0x18, 0x60, 0x31, 0xc0, 0x73, 0x00, 0x66, + 0x00, 0xdc, 0x01, 0xf0, 0x01, 0xe0, 0x03, 0xc0, + 0x07, 0x00, + // 'W' (0x57) 22x18, offset 1231-1281, at +0/-17 + // in regular row-major format + 0xe0, 0x30, 0x1d, 0x80, 0xe0, 0x76, 0x07, 0x81, + 0xd8, 0x1e, 0x06, 0x70, 0x7c, 0x18, 0xc1, 0xb0, + 0xe3, 0x0c, 0xc3, 0x8c, 0x33, 0x0c, 0x38, 0xc6, + 0x30, 0x67, 0x18, 0xc1, 0x98, 0x67, 0x06, 0x61, + 0xd8, 0x1d, 0x83, 0x60, 0x3c, 0x0d, 0x80, 0xf0, + 0x3e, 0x03, 0xc0, 0x70, 0x0f, 0x01, 0xc0, 0x18, + 0x07, 0x00, + // 'X' (0x58) 15x18, offset 1281-1315, at +0/-17 + // in regular row-major format + 0x70, 0x0e, 0x60, 0x38, 0xe0, 0x60, 0xe1, 0xc0, + 0xc3, 0x01, 0xcc, 0x01, 0xf8, 0x01, 0xe0, 0x03, + 0x80, 0x07, 0x80, 0x1f, 0x00, 0x33, 0x00, 0xe7, + 0x03, 0x86, 0x06, 0x0e, 0x1c, 0x0e, 0x70, 0x0c, + 0xc0, 0x1c, + // 'Y' (0x59) 16x18, offset 1315-1351, at +0/-17 + // in regular row-major format + 0x60, 0x06, 0x70, 0x0e, 0x30, 0x1c, 0x38, 0x18, + 0x1c, 0x38, 0x0c, 0x30, 0x0e, 0x70, 0x06, 0x60, + 0x03, 0xc0, 0x03, 0xc0, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x80, 0x01, 0x80, + // 'Z' (0x5a) 13x18, offset 1351-1381, at +1/-17 + // in regular row-major format + 0xff, 0xff, 0xff, 0xc0, 0x0e, 0x00, 0xe0, 0x0e, + 0x00, 0x60, 0x07, 0x00, 0x70, 0x07, 0x00, 0x30, + 0x03, 0x80, 0x38, 0x03, 0x80, 0x18, 0x01, 0xc0, + 0x1c, 0x00, 0xff, 0xff, 0xff, 0xc0, + // '[' (0x5b) 4x23, offset 1381-1393, at +2/-17 + // in regular row-major format + 0xff, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcf, 0xf0, + // '\' (0x5c) 7x18, offset 1393-1409, at +0/-17 + // in regular row-major format + 0x81, 0x81, 0x02, 0x06, 0x04, 0x08, 0x18, 0x10, + 0x20, 0x60, 0x40, 0x81, 0x81, 0x02, 0x06, 0x04, + // ']' (0x5d) 4x23, offset 1409-1421, at +1/-17 + // in regular row-major format + 0xff, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x3f, 0xf0, + // '^' (0x5e) 9x9, offset 1421-1432, at +1/-16 + // in regular row-major format + 0x0c, 0x0e, 0x05, 0x86, 0xc3, 0x21, 0x19, 0x8c, + 0x83, 0xc1, 0x80, + // '_' (0x5f) 15x1, offset 1432-1434, at -1/+4 + // in regular row-major format + 0xff, 0xfe, + // '`' (0x60) 5x4, offset 1434-1437, at +1/-17 + // in regular row-major format + 0xe3, 0x8c, 0x30, + // 'a' (0x61) 12x13, offset 1437-1457, at +1/-12 + // in regular row-major format + 0x3f, 0x07, 0xf8, 0xe1, 0xcc, 0x0c, 0x00, 0xc0, + 0x1c, 0x3f, 0xcf, 0x8c, 0xc0, 0xcc, 0x0c, 0xe3, + 0xc7, 0xef, 0x3c, 0x70, + // 'b' (0x62) 12x18, offset 1457-1484, at +1/-17 + // in regular row-major format + 0xc0, 0x0c, 0x00, 0xc0, 0x0c, 0x00, 0xc0, 0x0c, + 0xf8, 0xdf, 0xcf, 0x0e, 0xe0, 0x7c, 0x03, 0xc0, + 0x3c, 0x03, 0xc0, 0x3c, 0x03, 0xe0, 0x6f, 0x0e, + 0xdf, 0xcc, 0xf8, + // 'c' (0x63) 10x13, offset 1484-1501, at +1/-12 + // in regular row-major format + 0x1f, 0x0f, 0xe7, 0x1b, 0x83, 0xc0, 0x30, 0x0c, + 0x03, 0x00, 0xc0, 0x38, 0x37, 0x1c, 0xfe, 0x1f, + 0x00, + // 'd' (0x64) 11x18, offset 1501-1526, at +1/-17 + // in regular row-major format + 0x00, 0x60, 0x0c, 0x01, 0x80, 0x30, 0x06, 0x3c, + 0xcf, 0xfb, 0x8f, 0xe0, 0xf8, 0x0f, 0x01, 0xe0, + 0x3c, 0x07, 0x80, 0xf8, 0x3b, 0x8f, 0x3f, 0x63, + 0xcc, + // 'e' (0x65) 11x13, offset 1526-1544, at +1/-12 + // in regular row-major format + 0x1f, 0x07, 0xf1, 0xc7, 0x70, 0x3c, 0x07, 0xff, + 0xff, 0xfe, 0x00, 0xc0, 0x1c, 0x0d, 0xc3, 0x1f, + 0xe1, 0xf0, + // 'f' (0x66) 5x18, offset 1544-1556, at +1/-17 + // in regular row-major format + 0x3b, 0xd8, 0xc6, 0x7f, 0xec, 0x63, 0x18, 0xc6, + 0x31, 0x8c, 0x63, 0x00, + // 'g' (0x67) 11x18, offset 1556-1581, at +1/-12 + // in regular row-major format + 0x1e, 0x67, 0xfd, 0xc7, 0xf0, 0x7c, 0x07, 0x80, + 0xf0, 0x1e, 0x03, 0xc0, 0x7c, 0x1d, 0xc7, 0x9f, + 0xb1, 0xe6, 0x00, 0xc0, 0x3e, 0x0e, 0x7f, 0xc7, + 0xe0, + // 'h' (0x68) 10x18, offset 1581-1604, at +1/-17 + // in regular row-major format + 0xc0, 0x30, 0x0c, 0x03, 0x00, 0xc0, 0x33, 0xcd, + 0xfb, 0xc7, 0xe0, 0xf0, 0x3c, 0x0f, 0x03, 0xc0, + 0xf0, 0x3c, 0x0f, 0x03, 0xc0, 0xf0, 0x30, + // 'i' (0x69) 2x18, offset 1604-1609, at +2/-17 + // in regular row-major format + 0xf0, 0x3f, 0xff, 0xff, 0xf0, + // 'j' (0x6a) 4x23, offset 1609-1621, at +0/-17 + // in regular row-major format + 0x33, 0x00, 0x03, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x3f, 0xe0, + // 'k' (0x6b) 11x18, offset 1621-1646, at +1/-17 + // in regular row-major format + 0xc0, 0x18, 0x03, 0x00, 0x60, 0x0c, 0x01, 0x83, + 0x30, 0xc6, 0x30, 0xcc, 0x1b, 0x83, 0xf0, 0x77, + 0x0c, 0x61, 0x8e, 0x30, 0xe6, 0x0c, 0xc1, 0xd8, + 0x18, + // 'l' (0x6c) 2x18, offset 1646-1651, at +1/-17 + // in regular row-major format + 0xff, 0xff, 0xff, 0xff, 0xf0, + // 'm' (0x6d) 17x13, offset 1651-1679, at +1/-12 + // in regular row-major format + 0xcf, 0x1f, 0x6f, 0xdf, 0xfc, 0x78, 0xfc, 0x18, + 0x3c, 0x0c, 0x1e, 0x06, 0x0f, 0x03, 0x07, 0x81, + 0x83, 0xc0, 0xc1, 0xe0, 0x60, 0xf0, 0x30, 0x78, + 0x18, 0x3c, 0x0c, 0x18, + // 'n' (0x6e) 10x13, offset 1679-1696, at +1/-12 + // in regular row-major format + 0xcf, 0x37, 0xef, 0x1f, 0x83, 0xc0, 0xf0, 0x3c, + 0x0f, 0x03, 0xc0, 0xf0, 0x3c, 0x0f, 0x03, 0xc0, + 0xc0, + // 'o' (0x6f) 11x13, offset 1696-1714, at +1/-12 + // in regular row-major format + 0x1f, 0x07, 0xf1, 0xc7, 0x70, 0x7c, 0x07, 0x80, + 0xf0, 0x1e, 0x03, 0xc0, 0x7c, 0x1d, 0xc7, 0x1f, + 0xc1, 0xf0, + // 'p' (0x70) 12x17, offset 1714-1740, at +1/-12 + // in regular row-major format + 0xcf, 0x8d, 0xfc, 0xf0, 0xee, 0x06, 0xc0, 0x3c, + 0x03, 0xc0, 0x3c, 0x03, 0xc0, 0x3e, 0x07, 0xf0, + 0xef, 0xfc, 0xcf, 0x8c, 0x00, 0xc0, 0x0c, 0x00, + 0xc0, 0x00, + // 'q' (0x71) 11x17, offset 1740-1764, at +1/-12 + // in regular row-major format + 0x1e, 0x67, 0xfd, 0xc7, 0xf0, 0x7c, 0x07, 0x80, + 0xf0, 0x1e, 0x03, 0xc0, 0x7c, 0x1d, 0xc7, 0x9f, + 0xf1, 0xe6, 0x00, 0xc0, 0x18, 0x03, 0x00, 0x60, + // 'r' (0x72) 6x13, offset 1764-1774, at +1/-12 + // in regular row-major format + 0xcf, 0x7f, 0x38, 0xc3, 0x0c, 0x30, 0xc3, 0x0c, + 0x30, 0xc0, + // 's' (0x73) 10x13, offset 1774-1791, at +1/-12 + // in regular row-major format + 0x3e, 0x1f, 0xee, 0x1b, 0x00, 0xc0, 0x3c, 0x07, + 0xf0, 0x3e, 0x01, 0xf0, 0x3e, 0x1d, 0xfe, 0x3e, + 0x00, + // 't' (0x74) 5x16, offset 1791-1801, at +1/-15 + // in regular row-major format + 0x63, 0x19, 0xff, 0xb1, 0x8c, 0x63, 0x18, 0xc6, + 0x31, 0xe7, + // 'u' (0x75) 10x13, offset 1801-1818, at +1/-12 + // in regular row-major format + 0xc0, 0xf0, 0x3c, 0x0f, 0x03, 0xc0, 0xf0, 0x3c, + 0x0f, 0x03, 0xc0, 0xf0, 0x7e, 0x3d, 0xfb, 0x3c, + 0xc0, + // 'v' (0x76) 12x13, offset 1818-1838, at +0/-12 + // in regular row-major format + 0xe0, 0x66, 0x06, 0x60, 0x67, 0x0c, 0x30, 0xc3, + 0x0c, 0x39, 0x81, 0x98, 0x19, 0x81, 0xf0, 0x0f, + 0x00, 0xe0, 0x0e, 0x00, + // 'w' (0x77) 17x13, offset 1838-1866, at +0/-12 + // in regular row-major format + 0xc1, 0xc1, 0xb0, 0xe1, 0xd8, 0x70, 0xcc, 0x2c, + 0x66, 0x36, 0x31, 0x9b, 0x18, 0xcd, 0x98, 0x64, + 0x6c, 0x16, 0x36, 0x0f, 0x1a, 0x07, 0x8f, 0x03, + 0x83, 0x80, 0xc1, 0xc0, + // 'x' (0x78) 11x13, offset 1866-1884, at +0/-12 + // in regular row-major format + 0x60, 0xee, 0x18, 0xc6, 0x0c, 0xc1, 0xf0, 0x1c, + 0x01, 0x80, 0x78, 0x1b, 0x03, 0x30, 0xc7, 0x30, + 0x66, 0x06, + // 'y' (0x79) 11x18, offset 1884-1909, at +0/-12 + // in regular row-major format + 0xe0, 0x6c, 0x0d, 0x83, 0x38, 0x63, 0x0c, 0x63, + 0x0e, 0x60, 0xcc, 0x1b, 0x03, 0x60, 0x3c, 0x07, + 0x00, 0xe0, 0x18, 0x03, 0x00, 0xe0, 0x78, 0x0e, + 0x00, + // 'z' (0x7a) 10x13, offset 1909-1926, at +1/-12 + // in regular row-major format + 0xff, 0xff, 0xf0, 0x18, 0x0c, 0x07, 0x03, 0x81, + 0xc0, 0x60, 0x30, 0x18, 0x0e, 0x03, 0xff, 0xff, + 0xc0, + // '{' (0x7b) 5x23, offset 1926-1941, at +1/-17 + // in regular row-major format + 0x19, 0xcc, 0x63, 0x18, 0xc6, 0x31, 0x99, 0x86, + 0x18, 0xc6, 0x31, 0x8c, 0x63, 0x1c, 0x60, + // '|' (0x7c) 2x23, offset 1941-1947, at +2/-17 + // in regular row-major format + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, + // '}' (0x7d) 5x23, offset 1947-1962, at +2/-17 + // in regular row-major format + 0xc7, 0x18, 0xc6, 0x31, 0x8c, 0x63, 0x0c, 0x33, + 0x31, 0x8c, 0x63, 0x18, 0xc6, 0x73, 0x00, +}; + + +static const uint8_t FreeMono9pt7b_generic[] = { + // ' ' (0x20) 0x0, offset 0-0, at +0/+1 + // in regular row-major format + // '!' (0x21) 2x11, offset 0-3, at +4/-10 + // in regular row-major format + 0xaa, 0xa8, 0x0c, + // '"' (0x22) 6x5, offset 3-7, at +2/-10 + // in regular row-major format + 0xed, 0x24, 0x92, 0x48, + // '#' (0x23) 7x12, offset 7-18, at +2/-10 + // in regular row-major format + 0x24, 0x48, 0x91, 0x2f, 0xe4, 0x89, 0x7f, 0x28, + 0x51, 0x22, 0x40, + // '$' (0x24) 8x12, offset 18-30, at +1/-10 + // in regular row-major format + 0x08, 0x3e, 0x62, 0x40, 0x30, 0x0e, 0x01, 0x81, + 0xc3, 0xbe, 0x08, 0x08, + // '%' (0x25) 7x11, offset 30-40, at +2/-10 + // in regular row-major format + 0x71, 0x12, 0x23, 0x80, 0x23, 0xb8, 0x0e, 0x22, + 0x44, 0x70, + // '&' (0x26) 7x10, offset 40-49, at +2/-9 + // in regular row-major format + 0x38, 0x81, 0x02, 0x06, 0x1a, 0x65, 0x46, 0xc8, + 0xec, + // ''' (0x27) 3x5, offset 49-51, at +4/-10 + // in regular row-major format + 0xe9, 0x24, + // '(' (0x28) 2x13, offset 51-55, at +5/-10 + // in regular row-major format + 0x5a, 0xaa, 0xa9, 0x40, + // ')' (0x29) 2x13, offset 55-59, at +4/-10 + // in regular row-major format + 0xa9, 0x55, 0x5a, 0x80, + // '*' (0x2a) 7x7, offset 59-66, at +2/-10 + // in regular row-major format + 0x10, 0x22, 0x4b, 0xe3, 0x05, 0x11, 0x00, + // '+' (0x2b) 7x7, offset 66-73, at +2/-8 + // in regular row-major format + 0x10, 0x20, 0x47, 0xf1, 0x02, 0x04, 0x00, + // ',' (0x2c) 3x5, offset 73-75, at +2/-1 + // in regular row-major format + 0x6b, 0x48, + // '-' (0x2d) 9x1, offset 75-77, at +1/-5 + // in regular row-major format + 0xff, 0x00, + // '.' (0x2e) 2x2, offset 77-78, at +4/-1 + // in regular row-major format + 0xf0, + // '/' (0x2f) 7x13, offset 78-90, at +2/-11 + // in regular row-major format + 0x02, 0x08, 0x10, 0x60, 0x81, 0x04, 0x08, 0x20, + 0x41, 0x02, 0x08, 0x00, + // '0' (0x30) 7x11, offset 90-100, at +2/-10 + // in regular row-major format + 0x38, 0x8a, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0x82, + 0x88, 0xe0, + // '1' (0x31) 5x11, offset 100-107, at +3/-10 + // in regular row-major format + 0x27, 0x28, 0x42, 0x10, 0x84, 0x21, 0x3e, + // '2' (0x32) 7x11, offset 107-117, at +2/-10 + // in regular row-major format + 0x38, 0x8a, 0x08, 0x10, 0x20, 0x82, 0x08, 0x61, + 0x03, 0xf8, + // '3' (0x33) 8x11, offset 117-128, at +1/-10 + // in regular row-major format + 0x7c, 0x06, 0x02, 0x02, 0x1c, 0x06, 0x01, 0x01, + 0x01, 0x42, 0x3c, + // '4' (0x34) 6x11, offset 128-137, at +3/-10 + // in regular row-major format + 0x18, 0xa2, 0x92, 0x8a, 0x28, 0xbf, 0x08, 0x21, + 0xc0, + // '5' (0x35) 7x11, offset 137-147, at +2/-10 + // in regular row-major format + 0x7c, 0x81, 0x03, 0xe4, 0x40, 0x40, 0x81, 0x03, + 0x88, 0xe0, + // '6' (0x36) 7x11, offset 147-157, at +2/-10 + // in regular row-major format + 0x1e, 0x41, 0x04, 0x0b, 0x98, 0xb0, 0xc1, 0xc2, + 0x88, 0xe0, + // '7' (0x37) 7x11, offset 157-167, at +2/-10 + // in regular row-major format + 0xfe, 0x04, 0x08, 0x20, 0x40, 0x82, 0x04, 0x08, + 0x20, 0x40, + // '8' (0x38) 7x11, offset 167-177, at +2/-10 + // in regular row-major format + 0x38, 0x8a, 0x0c, 0x14, 0x47, 0x11, 0x41, 0x83, + 0x8c, 0xe0, + // '9' (0x39) 7x11, offset 177-187, at +2/-10 + // in regular row-major format + 0x38, 0x8a, 0x1c, 0x18, 0x68, 0xce, 0x81, 0x04, + 0x13, 0xc0, + // ':' (0x3a) 2x8, offset 187-189, at +4/-7 + // in regular row-major format + 0xf0, 0x0f, + // ';' (0x3b) 3x11, offset 189-194, at +3/-7 + // in regular row-major format + 0x6c, 0x00, 0xd2, 0xd2, 0x00, + // '<' (0x3c) 8x8, offset 194-202, at +1/-8 + // in regular row-major format + 0x03, 0x04, 0x18, 0x60, 0x60, 0x18, 0x04, 0x03, + // '=' (0x3d) 9x4, offset 202-207, at +1/-6 + // in regular row-major format + 0xff, 0x80, 0x00, 0x1f, 0xf0, + // '>' (0x3e) 9x8, offset 207-216, at +1/-8 + // in regular row-major format + 0x40, 0x18, 0x03, 0x00, 0x60, 0x20, 0x60, 0xc0, + 0x80, + // '?' (0x3f) 7x10, offset 216-225, at +2/-9 + // in regular row-major format + 0x3d, 0x84, 0x08, 0x30, 0xc2, 0x00, 0x00, 0x00, + 0x30, + // '@' (0x40) 8x12, offset 225-237, at +2/-10 + // in regular row-major format + 0x3c, 0x46, 0x82, 0x8e, 0xb2, 0xa2, 0xa2, 0x9f, + 0x80, 0x80, 0x40, 0x3c, + // 'A' (0x41) 11x10, offset 237-251, at +0/-9 + // in regular row-major format + 0x3c, 0x01, 0x40, 0x28, 0x09, 0x01, 0x10, 0x42, + 0x0f, 0xc1, 0x04, 0x40, 0x9e, 0x3c, + // 'B' (0x42) 9x10, offset 251-263, at +1/-9 + // in regular row-major format + 0xfe, 0x21, 0x90, 0x48, 0x67, 0xe2, 0x09, 0x02, + 0x81, 0x41, 0xff, 0x80, + // 'C' (0x43) 9x10, offset 263-275, at +1/-9 + // in regular row-major format + 0x3e, 0xb0, 0xf0, 0x30, 0x08, 0x04, 0x02, 0x00, + 0x80, 0x60, 0x8f, 0x80, + // 'D' (0x44) 9x10, offset 275-287, at +1/-9 + // in regular row-major format + 0xfe, 0x21, 0x90, 0x68, 0x14, 0x0a, 0x05, 0x02, + 0x83, 0x43, 0x7f, 0x00, + // 'E' (0x45) 9x10, offset 287-299, at +1/-9 + // in regular row-major format + 0xff, 0x20, 0x90, 0x08, 0x87, 0xc2, 0x21, 0x00, + 0x81, 0x40, 0xff, 0xc0, + // 'F' (0x46) 9x10, offset 299-311, at +1/-9 + // in regular row-major format + 0xff, 0xa0, 0x50, 0x08, 0x87, 0xc2, 0x21, 0x00, + 0x80, 0x40, 0x78, 0x00, + // 'G' (0x47) 10x10, offset 311-324, at +1/-9 + // in regular row-major format + 0x1e, 0x98, 0x6c, 0x0a, 0x00, 0x80, 0x20, 0xf8, + 0x0b, 0x02, 0x60, 0x87, 0xc0, + // 'H' (0x48) 9x10, offset 324-336, at +1/-9 + // in regular row-major format + 0xe3, 0xa0, 0x90, 0x48, 0x27, 0xf2, 0x09, 0x04, + 0x82, 0x41, 0x71, 0xc0, + // 'I' (0x49) 5x10, offset 336-343, at +3/-9 + // in regular row-major format + 0xf9, 0x08, 0x42, 0x10, 0x84, 0x27, 0xc0, + // 'J' (0x4a) 8x10, offset 343-353, at +2/-9 + // in regular row-major format + 0x1f, 0x02, 0x02, 0x02, 0x02, 0x02, 0x82, 0x82, + 0xc6, 0x78, + // 'K' (0x4b) 9x10, offset 353-365, at +1/-9 + // in regular row-major format + 0xe3, 0xa1, 0x11, 0x09, 0x05, 0x83, 0x21, 0x08, + 0x84, 0x41, 0x70, 0xc0, + // 'L' (0x4c) 8x10, offset 365-375, at +2/-9 + // in regular row-major format + 0xe0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, + 0x41, 0xff, + // 'M' (0x4d) 11x10, offset 375-389, at +0/-9 + // in regular row-major format + 0xe0, 0xec, 0x19, 0x45, 0x28, 0xa4, 0xa4, 0x94, + 0x91, 0x12, 0x02, 0x40, 0x5c, 0x1c, + // 'N' (0x4e) 9x10, offset 389-401, at +1/-9 + // in regular row-major format + 0xc3, 0xb0, 0x94, 0x4a, 0x24, 0x92, 0x49, 0x14, + 0x8a, 0x43, 0x70, 0x80, + // 'O' (0x4f) 9x10, offset 401-413, at +1/-9 + // in regular row-major format + 0x1e, 0x31, 0x90, 0x50, 0x18, 0x0c, 0x06, 0x02, + 0x82, 0x63, 0x0f, 0x00, + // 'P' (0x50) 8x10, offset 413-423, at +1/-9 + // in regular row-major format + 0xfe, 0x43, 0x41, 0x41, 0x42, 0x7c, 0x40, 0x40, + 0x40, 0xf0, + // 'Q' (0x51) 9x13, offset 423-438, at +1/-9 + // in regular row-major format + 0x1c, 0x31, 0x90, 0x50, 0x18, 0x0c, 0x06, 0x02, + 0x82, 0x63, 0x1f, 0x04, 0x07, 0x92, 0x30, + // 'R' (0x52) 9x10, offset 438-450, at +1/-9 + // in regular row-major format + 0xfe, 0x21, 0x90, 0x48, 0x24, 0x23, 0xe1, 0x10, + 0x84, 0x41, 0x70, 0xc0, + // 'S' (0x53) 7x10, offset 450-459, at +2/-9 + // in regular row-major format + 0x3a, 0xcd, 0x0a, 0x03, 0x01, 0x80, 0xc1, 0xc7, + 0x78, + // 'T' (0x54) 9x10, offset 459-471, at +1/-9 + // in regular row-major format + 0xff, 0xc4, 0x62, 0x21, 0x00, 0x80, 0x40, 0x20, + 0x10, 0x08, 0x1f, 0x00, + // 'U' (0x55) 9x10, offset 471-483, at +1/-9 + // in regular row-major format + 0xe3, 0xa0, 0x90, 0x48, 0x24, 0x12, 0x09, 0x04, + 0x82, 0x22, 0x0e, 0x00, + // 'V' (0x56) 11x10, offset 483-497, at +0/-9 + // in regular row-major format + 0xf1, 0xe8, 0x10, 0x82, 0x10, 0x42, 0x10, 0x22, + 0x04, 0x80, 0x50, 0x0c, 0x00, 0x80, + // 'W' (0x57) 11x10, offset 497-511, at +0/-9 + // in regular row-major format + 0xf1, 0xe8, 0x09, 0x11, 0x25, 0x44, 0xa8, 0x55, + 0x0c, 0xa1, 0x8c, 0x31, 0x84, 0x30, + // 'X' (0x58) 9x10, offset 511-523, at +1/-9 + // in regular row-major format + 0xe3, 0xa0, 0x88, 0x82, 0x80, 0x80, 0xc0, 0x90, + 0x44, 0x41, 0x71, 0xc0, + // 'Y' (0x59) 9x10, offset 523-535, at +1/-9 + // in regular row-major format + 0xe3, 0xa0, 0x88, 0x82, 0x81, 0x40, 0x40, 0x20, + 0x10, 0x08, 0x1f, 0x00, + // 'Z' (0x5a) 7x10, offset 535-544, at +2/-9 + // in regular row-major format + 0xfd, 0x0a, 0x20, 0x81, 0x04, 0x10, 0x21, 0x83, + 0xfc, + // '[' (0x5b) 2x13, offset 544-548, at +5/-10 + // in regular row-major format + 0xea, 0xaa, 0xaa, 0xc0, + // '\' (0x5c) 7x13, offset 548-560, at +2/-11 + // in regular row-major format + 0x80, 0x81, 0x03, 0x02, 0x04, 0x04, 0x08, 0x08, + 0x10, 0x10, 0x20, 0x20, + // ']' (0x5d) 2x13, offset 560-564, at +4/-10 + // in regular row-major format + 0xd5, 0x55, 0x55, 0xc0, + // '^' (0x5e) 7x5, offset 564-569, at +2/-10 + // in regular row-major format + 0x10, 0x51, 0x22, 0x28, 0x20, + // '_' (0x5f) 11x1, offset 569-571, at +0/+2 + // in regular row-major format + 0xff, 0xe0, + // '`' (0x60) 3x3, offset 571-573, at +3/-11 + // in regular row-major format + 0x88, 0x80, + // 'a' (0x61) 9x8, offset 573-582, at +1/-7 + // in regular row-major format + 0x7e, 0x00, 0x80, 0x47, 0xec, 0x14, 0x0a, 0x0c, + 0xfb, + // 'b' (0x62) 9x11, offset 582-595, at +1/-10 + // in regular row-major format + 0xc0, 0x20, 0x10, 0x0b, 0xc6, 0x12, 0x05, 0x02, + 0x81, 0x40, 0xb0, 0xb7, 0x80, + // 'c' (0x63) 7x8, offset 595-602, at +2/-7 + // in regular row-major format + 0x3a, 0x8e, 0x0c, 0x08, 0x10, 0x10, 0x9e, + // 'd' (0x64) 9x11, offset 602-615, at +1/-10 + // in regular row-major format + 0x03, 0x00, 0x80, 0x47, 0xa4, 0x34, 0x0a, 0x05, + 0x02, 0x81, 0x21, 0x8f, 0x60, + // 'e' (0x65) 8x8, offset 615-623, at +1/-7 + // in regular row-major format + 0x3c, 0x43, 0x81, 0xff, 0x80, 0x80, 0x61, 0x3e, + // 'f' (0x66) 6x11, offset 623-632, at +3/-10 + // in regular row-major format + 0x3d, 0x04, 0x3e, 0x41, 0x04, 0x10, 0x41, 0x0f, + 0x80, + // 'g' (0x67) 9x11, offset 632-645, at +1/-7 + // in regular row-major format + 0x3d, 0xa1, 0xa0, 0x50, 0x28, 0x14, 0x09, 0x0c, + 0x7a, 0x01, 0x01, 0x87, 0x80, + // 'h' (0x68) 9x11, offset 645-658, at +1/-10 + // in regular row-major format + 0xc0, 0x20, 0x10, 0x0b, 0xc6, 0x32, 0x09, 0x04, + 0x82, 0x41, 0x20, 0xb8, 0xe0, + // 'i' (0x69) 7x10, offset 658-667, at +2/-9 + // in regular row-major format + 0x10, 0x01, 0xc0, 0x81, 0x02, 0x04, 0x08, 0x11, + 0xfc, + // 'j' (0x6a) 5x13, offset 667-676, at +3/-9 + // in regular row-major format + 0x10, 0x3e, 0x10, 0x84, 0x21, 0x08, 0x42, 0x3f, + 0x00, + // 'k' (0x6b) 8x11, offset 676-687, at +2/-10 + // in regular row-major format + 0xc0, 0x40, 0x40, 0x4f, 0x44, 0x58, 0x70, 0x48, + 0x44, 0x42, 0xc7, + // 'l' (0x6c) 7x11, offset 687-697, at +2/-10 + // in regular row-major format + 0x70, 0x20, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10, + 0x23, 0xf8, + // 'm' (0x6d) 9x8, offset 697-706, at +1/-7 + // in regular row-major format + 0xb7, 0x64, 0x62, 0x31, 0x18, 0x8c, 0x46, 0x23, + 0x91, + // 'n' (0x6e) 9x8, offset 706-715, at +1/-7 + // in regular row-major format + 0x5e, 0x31, 0x90, 0x48, 0x24, 0x12, 0x09, 0x05, + 0xc7, + // 'o' (0x6f) 9x8, offset 715-724, at +1/-7 + // in regular row-major format + 0x3e, 0x31, 0xa0, 0x30, 0x18, 0x0c, 0x05, 0x8c, + 0x7c, + // 'p' (0x70) 9x11, offset 724-737, at +1/-7 + // in regular row-major format + 0xde, 0x30, 0x90, 0x28, 0x14, 0x0a, 0x05, 0x84, + 0xbc, 0x40, 0x20, 0x38, 0x00, + // 'q' (0x71) 9x11, offset 737-750, at +1/-7 + // in regular row-major format + 0x3d, 0xa1, 0xa0, 0x50, 0x28, 0x14, 0x09, 0x0c, + 0x7a, 0x01, 0x00, 0x80, 0xe0, + // 'r' (0x72) 7x8, offset 750-757, at +3/-7 + // in regular row-major format + 0xce, 0xa1, 0x82, 0x04, 0x08, 0x10, 0x7c, + // 's' (0x73) 7x8, offset 757-764, at +2/-7 + // in regular row-major format + 0x3a, 0x8d, 0x0b, 0x80, 0xf0, 0x70, 0xde, + // 't' (0x74) 8x10, offset 764-774, at +2/-9 + // in regular row-major format + 0x40, 0x40, 0xfc, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x41, 0x3e, + // 'u' (0x75) 8x8, offset 774-782, at +1/-7 + // in regular row-major format + 0xc3, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43, 0x3d, + // 'v' (0x76) 9x8, offset 782-791, at +1/-7 + // in regular row-major format + 0xe3, 0xa0, 0x90, 0x84, 0x42, 0x20, 0xa0, 0x50, + 0x10, + // 'w' (0x77) 9x8, offset 791-800, at +1/-7 + // in regular row-major format + 0xe3, 0xc0, 0x92, 0x4b, 0x25, 0x92, 0xa9, 0x98, + 0x44, + // 'x' (0x78) 9x8, offset 800-809, at +1/-7 + // in regular row-major format + 0xe3, 0x31, 0x05, 0x01, 0x01, 0x41, 0x11, 0x05, + 0xc7, + // 'y' (0x79) 9x11, offset 809-822, at +1/-7 + // in regular row-major format + 0xe3, 0xa0, 0x90, 0x84, 0x42, 0x40, 0xa0, 0x60, + 0x10, 0x10, 0x08, 0x3e, 0x00, + // 'z' (0x7a) 7x8, offset 822-829, at +2/-7 + // in regular row-major format + 0xfd, 0x08, 0x20, 0x82, 0x08, 0x10, 0xbf, + // '{' (0x7b) 3x13, offset 829-834, at +4/-10 + // in regular row-major format + 0x29, 0x24, 0xa2, 0x49, 0x26, + // '|' (0x7c) 1x13, offset 834-836, at +5/-10 + // in regular row-major format + 0xff, 0xf8, + // '}' (0x7d) 3x13, offset 836-841, at +4/-10 + // in regular row-major format + 0x89, 0x24, 0x8a, 0x49, 0x2c, +}; + + +static const uint8_t FreeMono12pt7b_generic[] = { + // ' ' (0x20) 0x0, offset 0-0, at +0/+1 + // in regular row-major format + // '!' (0x21) 3x15, offset 0-6, at +6/-14 + // in regular row-major format + 0x49, 0x24, 0x92, 0x48, 0x01, 0xf8, + // '"' (0x22) 8x7, offset 6-13, at +3/-14 + // in regular row-major format + 0xe7, 0xe7, 0x67, 0x42, 0x42, 0x42, 0x42, + // '#' (0x23) 10x16, offset 13-33, at +2/-14 + // in regular row-major format + 0x09, 0x02, 0x41, 0x10, 0x44, 0x11, 0x1f, 0xf1, + 0x10, 0x4c, 0x12, 0x3f, 0xe1, 0x20, 0x48, 0x12, + 0x04, 0x81, 0x20, 0x48, + // '$' (0x24) 10x17, offset 33-55, at +2/-14 + // in regular row-major format + 0x04, 0x07, 0xa2, 0x19, 0x02, 0x40, 0x10, 0x03, + 0x00, 0x3c, 0x00, 0x80, 0x10, 0x06, 0x01, 0xe0, + 0xa7, 0xc0, 0x40, 0x10, 0x04, 0x00, + // '%' (0x25) 10x15, offset 55-74, at +2/-14 + // in regular row-major format + 0x3c, 0x19, 0x84, 0x21, 0x08, 0x66, 0x0f, 0x00, + 0x0c, 0x1c, 0x78, 0x01, 0xe0, 0xcc, 0x21, 0x08, + 0x43, 0x30, 0x78, + // '&' (0x26) 9x12, offset 74-88, at +3/-11 + // in regular row-major format + 0x3e, 0x30, 0x10, 0x08, 0x02, 0x03, 0x03, 0x47, + 0x14, 0x8a, 0x43, 0x11, 0x8f, 0x60, + // ''' (0x27) 3x7, offset 88-91, at +5/-14 + // in regular row-major format + 0xfd, 0xa4, 0x90, + // '(' (0x28) 3x18, offset 91-98, at +7/-14 + // in regular row-major format + 0x05, 0x25, 0x24, 0x92, 0x48, 0x92, 0x24, + // ')' (0x29) 3x18, offset 98-105, at +4/-14 + // in regular row-major format + 0x11, 0x24, 0x89, 0x24, 0x92, 0x92, 0x90, + // '*' (0x2a) 9x9, offset 105-116, at +3/-14 + // in regular row-major format + 0x00, 0x04, 0x02, 0x11, 0x07, 0xf0, 0xc0, 0x50, + 0x48, 0x42, 0x00, + // '+' (0x2b) 9x11, offset 116-129, at +3/-11 + // in regular row-major format + 0x08, 0x04, 0x02, 0x01, 0x00, 0x87, 0xfc, 0x20, + 0x10, 0x08, 0x04, 0x02, 0x00, + // ',' (0x2c) 5x7, offset 129-134, at +3/-3 + // in regular row-major format + 0x3b, 0x9c, 0xce, 0x62, 0x00, + // '-' (0x2d) 11x1, offset 134-136, at +2/-6 + // in regular row-major format + 0xff, 0xe0, + // '.' (0x2e) 3x3, offset 136-138, at +5/-2 + // in regular row-major format + 0xff, 0x80, + // '/' (0x2f) 9x18, offset 138-159, at +3/-15 + // in regular row-major format + 0x00, 0x80, 0xc0, 0x40, 0x20, 0x20, 0x10, 0x10, + 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x01, 0x01, + 0x00, 0x80, 0x80, 0x40, 0x00, + // '0' (0x30) 9x15, offset 159-176, at +3/-14 + // in regular row-major format + 0x1c, 0x31, 0x90, 0x58, 0x38, 0x0c, 0x06, 0x03, + 0x01, 0x80, 0xc0, 0x60, 0x30, 0x34, 0x13, 0x18, + 0x70, + // '1' (0x31) 7x14, offset 176-189, at +4/-13 + // in regular row-major format + 0x30, 0xe1, 0x44, 0x81, 0x02, 0x04, 0x08, 0x10, + 0x20, 0x40, 0x81, 0x1f, 0xc0, + // '2' (0x32) 9x15, offset 189-206, at +2/-14 + // in regular row-major format + 0x1e, 0x10, 0x90, 0x68, 0x10, 0x08, 0x0c, 0x04, + 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x0e, 0x07, + 0xfe, + // '3' (0x33) 10x15, offset 206-225, at +2/-14 + // in regular row-major format + 0x3e, 0x10, 0x40, 0x08, 0x02, 0x00, 0x80, 0x40, + 0xe0, 0x04, 0x00, 0x80, 0x10, 0x04, 0x01, 0x00, + 0xd8, 0x63, 0xe0, + // '4' (0x34) 8x15, offset 225-240, at +3/-14 + // in regular row-major format + 0x06, 0x0a, 0x0a, 0x12, 0x22, 0x22, 0x42, 0x42, + 0x82, 0x82, 0xff, 0x02, 0x02, 0x02, 0x0f, + // '5' (0x35) 9x15, offset 240-257, at +3/-14 + // in regular row-major format + 0x7f, 0x20, 0x10, 0x08, 0x04, 0x02, 0xf1, 0x8c, + 0x03, 0x00, 0x80, 0x40, 0x20, 0x18, 0x16, 0x18, + 0xf0, + // '6' (0x36) 9x15, offset 257-274, at +3/-14 + // in regular row-major format + 0x0f, 0x8c, 0x08, 0x08, 0x04, 0x04, 0x02, 0x79, + 0x46, 0xc1, 0xe0, 0x60, 0x28, 0x14, 0x19, 0x08, + 0x78, + // '7' (0x37) 8x15, offset 274-289, at +3/-14 + // in regular row-major format + 0xff, 0x81, 0x81, 0x02, 0x02, 0x02, 0x02, 0x04, + 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, + // '8' (0x38) 9x15, offset 289-306, at +3/-14 + // in regular row-major format + 0x3e, 0x31, 0xb0, 0x70, 0x18, 0x0c, 0x05, 0x8c, + 0x38, 0x63, 0x40, 0x60, 0x30, 0x18, 0x1b, 0x18, + 0xf8, + // '9' (0x39) 9x15, offset 306-323, at +3/-14 + // in regular row-major format + 0x3c, 0x31, 0x30, 0x50, 0x28, 0x0c, 0x0f, 0x06, + 0x85, 0x3c, 0x80, 0x40, 0x40, 0x20, 0x20, 0x63, + 0xe0, + // ':' (0x3a) 3x10, offset 323-327, at +5/-9 + // in regular row-major format + 0xff, 0x80, 0x07, 0xfc, + // ';' (0x3b) 5x13, offset 327-336, at +3/-9 + // in regular row-major format + 0x39, 0xce, 0x00, 0x00, 0x06, 0x33, 0x98, 0xc4, + 0x00, + // '<' (0x3c) 11x11, offset 336-352, at +2/-11 + // in regular row-major format + 0x00, 0xc0, 0x60, 0x18, 0x0c, 0x06, 0x01, 0x80, + 0x0c, 0x00, 0x60, 0x03, 0x00, 0x30, 0x01, 0x00, + // '=' (0x3d) 12x4, offset 352-358, at +1/-8 + // in regular row-major format + 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, + // '>' (0x3e) 11x11, offset 358-374, at +2/-11 + // in regular row-major format + 0xc0, 0x06, 0x00, 0x30, 0x01, 0x80, 0x18, 0x01, + 0x80, 0xc0, 0x30, 0x18, 0x0c, 0x02, 0x00, 0x00, + // '?' (0x3f) 9x14, offset 374-390, at +3/-13 + // in regular row-major format + 0x3e, 0x60, 0xa0, 0x20, 0x10, 0x08, 0x08, 0x18, + 0x10, 0x08, 0x00, 0x00, 0x00, 0x01, 0xc0, 0xe0, + // '@' (0x40) 9x16, offset 390-408, at +3/-14 + // in regular row-major format + 0x1c, 0x31, 0x10, 0x50, 0x28, 0x14, 0x3a, 0x25, + 0x22, 0x91, 0x4c, 0xa3, 0xf0, 0x08, 0x02, 0x01, + 0x80, 0x7c, + // 'A' (0x41) 14x14, offset 408-433, at +0/-13 + // in regular row-major format + 0x3f, 0x00, 0x0c, 0x00, 0x48, 0x01, 0x20, 0x04, + 0x40, 0x21, 0x00, 0x84, 0x04, 0x08, 0x1f, 0xe0, + 0x40, 0x82, 0x01, 0x08, 0x04, 0x20, 0x13, 0xe1, + 0xf0, + // 'B' (0x42) 11x14, offset 433-453, at +2/-13 + // in regular row-major format + 0xff, 0x08, 0x11, 0x01, 0x20, 0x24, 0x04, 0x81, + 0x1f, 0xc2, 0x06, 0x40, 0x68, 0x05, 0x00, 0xa0, + 0x14, 0x05, 0xff, 0x00, + // 'C' (0x43) 10x14, offset 453-471, at +2/-13 + // in regular row-major format + 0x1e, 0x48, 0x74, 0x05, 0x01, 0x80, 0x20, 0x08, + 0x02, 0x00, 0x80, 0x20, 0x04, 0x01, 0x01, 0x30, + 0x87, 0xc0, + // 'D' (0x44) 10x14, offset 471-489, at +2/-13 + // in regular row-major format + 0xfe, 0x10, 0x44, 0x09, 0x02, 0x40, 0x50, 0x14, + 0x05, 0x01, 0x40, 0x50, 0x14, 0x0d, 0x02, 0x41, + 0x3f, 0x80, + // 'E' (0x45) 11x14, offset 489-509, at +2/-13 + // in regular row-major format + 0xff, 0xc8, 0x09, 0x01, 0x20, 0x04, 0x00, 0x88, + 0x1f, 0x02, 0x20, 0x40, 0x08, 0x01, 0x00, 0xa0, + 0x14, 0x03, 0xff, 0xc0, + // 'F' (0x46) 11x14, offset 509-529, at +2/-13 + // in regular row-major format + 0xff, 0xe8, 0x05, 0x00, 0xa0, 0x04, 0x00, 0x88, + 0x1f, 0x02, 0x20, 0x40, 0x08, 0x01, 0x00, 0x20, + 0x04, 0x01, 0xf0, 0x00, + // 'G' (0x47) 11x14, offset 529-549, at +2/-13 + // in regular row-major format + 0x1f, 0x46, 0x19, 0x01, 0x60, 0x28, 0x01, 0x00, + 0x20, 0x04, 0x00, 0x83, 0xf0, 0x0b, 0x01, 0x20, + 0x23, 0x0c, 0x3e, 0x00, + // 'H' (0x48) 10x14, offset 549-567, at +2/-13 + // in regular row-major format + 0xe1, 0xd0, 0x24, 0x09, 0x02, 0x40, 0x90, 0x27, + 0xf9, 0x02, 0x40, 0x90, 0x24, 0x09, 0x02, 0x40, + 0xb8, 0x70, + // 'I' (0x49) 7x14, offset 567-580, at +4/-13 + // in regular row-major format + 0xfe, 0x20, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10, + 0x20, 0x40, 0x81, 0x1f, 0xc0, + // 'J' (0x4a) 11x14, offset 580-600, at +2/-13 + // in regular row-major format + 0x0f, 0xe0, 0x10, 0x02, 0x00, 0x40, 0x08, 0x01, + 0x00, 0x20, 0x04, 0x80, 0x90, 0x12, 0x02, 0x40, + 0xc6, 0x30, 0x7c, 0x00, + // 'K' (0x4b) 12x14, offset 600-621, at +2/-13 + // in regular row-major format + 0xf1, 0xe4, 0x0c, 0x41, 0x04, 0x20, 0x44, 0x04, + 0x80, 0x5c, 0x06, 0x60, 0x43, 0x04, 0x10, 0x40, + 0x84, 0x08, 0x40, 0xcf, 0x07, + // 'L' (0x4c) 11x14, offset 621-641, at +2/-13 + // in regular row-major format + 0xf8, 0x04, 0x00, 0x80, 0x10, 0x02, 0x00, 0x40, + 0x08, 0x01, 0x00, 0x20, 0x04, 0x04, 0x80, 0x90, + 0x12, 0x03, 0xff, 0xc0, + // 'M' (0x4d) 13x14, offset 641-664, at +1/-13 + // in regular row-major format + 0xe0, 0x3b, 0x01, 0x94, 0x14, 0xa0, 0xa4, 0x89, + 0x24, 0x49, 0x14, 0x48, 0xa2, 0x45, 0x12, 0x10, + 0x90, 0x04, 0x80, 0x24, 0x01, 0x78, 0x3c, + // 'N' (0x4e) 12x14, offset 664-685, at +1/-13 + // in regular row-major format + 0xe0, 0xf6, 0x02, 0x50, 0x25, 0x02, 0x48, 0x24, + 0xc2, 0x44, 0x24, 0x22, 0x43, 0x24, 0x12, 0x40, + 0xa4, 0x0a, 0x40, 0x6f, 0x06, + // 'O' (0x4f) 12x14, offset 685-706, at +1/-13 + // in regular row-major format + 0x0f, 0x03, 0x0c, 0x60, 0x64, 0x02, 0x80, 0x18, + 0x01, 0x80, 0x18, 0x01, 0x80, 0x18, 0x01, 0x40, + 0x26, 0x06, 0x30, 0xc0, 0xf0, + // 'P' (0x50) 10x14, offset 706-724, at +2/-13 + // in regular row-major format + 0xff, 0x10, 0x64, 0x05, 0x01, 0x40, 0x50, 0x34, + 0x19, 0xfc, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, + 0x3e, 0x00, + // 'Q' (0x51) 12x17, offset 724-750, at +1/-13 + // in regular row-major format + 0x0f, 0x03, 0x0c, 0x60, 0x64, 0x02, 0x80, 0x18, + 0x01, 0x80, 0x18, 0x01, 0x80, 0x18, 0x01, 0x40, + 0x26, 0x06, 0x30, 0xc1, 0xf0, 0x0c, 0x01, 0xf1, + 0x30, 0xe0, + // 'R' (0x52) 12x14, offset 750-771, at +2/-13 + // in regular row-major format + 0xff, 0x04, 0x18, 0x40, 0xc4, 0x04, 0x40, 0x44, + 0x0c, 0x41, 0x87, 0xe0, 0x43, 0x04, 0x10, 0x40, + 0x84, 0x04, 0x40, 0x4f, 0x03, + // 'S' (0x53) 10x14, offset 771-789, at +2/-13 + // in regular row-major format + 0x1f, 0x48, 0x34, 0x05, 0x01, 0x40, 0x08, 0x01, + 0xc0, 0x0e, 0x00, 0x40, 0x18, 0x06, 0x01, 0xe1, + 0xa7, 0xc0, + // 'T' (0x54) 11x14, offset 789-809, at +2/-13 + // in regular row-major format + 0xff, 0xf0, 0x86, 0x10, 0x82, 0x00, 0x40, 0x08, + 0x01, 0x00, 0x20, 0x04, 0x00, 0x80, 0x10, 0x02, + 0x00, 0x40, 0x7f, 0x00, + // 'U' (0x55) 12x14, offset 809-830, at +1/-13 + // in regular row-major format + 0xf0, 0xf4, 0x02, 0x40, 0x24, 0x02, 0x40, 0x24, + 0x02, 0x40, 0x24, 0x02, 0x40, 0x24, 0x02, 0x40, + 0x22, 0x04, 0x30, 0xc0, 0xf0, + // 'V' (0x56) 14x14, offset 830-855, at +0/-13 + // in regular row-major format + 0xf8, 0x7c, 0x80, 0x22, 0x01, 0x04, 0x04, 0x10, + 0x20, 0x40, 0x80, 0x82, 0x02, 0x10, 0x08, 0x40, + 0x11, 0x00, 0x48, 0x01, 0xa0, 0x03, 0x00, 0x0c, + 0x00, + // 'W' (0x57) 14x14, offset 855-880, at +0/-13 + // in regular row-major format + 0xf8, 0x7c, 0x80, 0x22, 0x00, 0x88, 0xc2, 0x23, + 0x10, 0x8e, 0x42, 0x29, 0x09, 0x24, 0x24, 0x90, + 0x91, 0x41, 0x85, 0x06, 0x14, 0x18, 0x70, 0x60, + 0x80, + // 'X' (0x58) 12x14, offset 880-901, at +1/-13 + // in regular row-major format + 0xf0, 0xf2, 0x06, 0x30, 0x41, 0x08, 0x09, 0x80, + 0x50, 0x06, 0x00, 0x60, 0x0d, 0x00, 0x88, 0x10, + 0xc2, 0x04, 0x60, 0x2f, 0x0f, + // 'Y' (0x59) 12x14, offset 901-922, at +1/-13 + // in regular row-major format + 0xf0, 0xf2, 0x02, 0x10, 0x41, 0x04, 0x08, 0x80, + 0x50, 0x05, 0x00, 0x20, 0x02, 0x00, 0x20, 0x02, + 0x00, 0x20, 0x02, 0x01, 0xfc, + // 'Z' (0x5a) 9x14, offset 922-938, at +3/-13 + // in regular row-major format + 0xff, 0x40, 0xa0, 0x90, 0x40, 0x40, 0x40, 0x20, + 0x20, 0x20, 0x10, 0x50, 0x30, 0x18, 0x0f, 0xfc, + // '[' (0x5b) 3x18, offset 938-945, at +7/-14 + // in regular row-major format + 0xf2, 0x49, 0x24, 0x92, 0x49, 0x24, 0x9c, + // '\' (0x5c) 9x18, offset 945-966, at +3/-15 + // in regular row-major format + 0x80, 0x60, 0x10, 0x08, 0x02, 0x01, 0x00, 0x40, + 0x20, 0x08, 0x04, 0x01, 0x00, 0x80, 0x20, 0x10, + 0x04, 0x02, 0x00, 0x80, 0x40, + // ']' (0x5d) 3x18, offset 966-973, at +5/-14 + // in regular row-major format + 0xe4, 0x92, 0x49, 0x24, 0x92, 0x49, 0x3c, + // '^' (0x5e) 9x6, offset 973-980, at +3/-14 + // in regular row-major format + 0x08, 0x0c, 0x09, 0x0c, 0x4c, 0x14, 0x04, + // '_' (0x5f) 14x1, offset 980-982, at +0/+3 + // in regular row-major format + 0xff, 0xfc, + // '`' (0x60) 4x4, offset 982-984, at +4/-15 + // in regular row-major format + 0x84, 0x21, + // 'a' (0x61) 10x10, offset 984-997, at +2/-9 + // in regular row-major format + 0x3e, 0x00, 0x60, 0x08, 0x02, 0x3f, 0x98, 0x28, + 0x0a, 0x02, 0xc3, 0x9f, 0x30, + // 'b' (0x62) 13x15, offset 997-1022, at +0/-14 + // in regular row-major format + 0xe0, 0x01, 0x00, 0x08, 0x00, 0x40, 0x02, 0x00, + 0x13, 0xe0, 0xa0, 0x86, 0x02, 0x20, 0x09, 0x00, + 0x48, 0x02, 0x40, 0x13, 0x01, 0x14, 0x1b, 0x9f, + 0x00, + // 'c' (0x63) 11x10, offset 1022-1036, at +2/-9 + // in regular row-major format + 0x1f, 0x4c, 0x19, 0x01, 0x40, 0x28, 0x01, 0x00, + 0x20, 0x02, 0x00, 0x60, 0x43, 0xf0, + // 'd' (0x64) 11x15, offset 1036-1057, at +2/-14 + // in regular row-major format + 0x00, 0xc0, 0x08, 0x01, 0x00, 0x20, 0x04, 0x3c, + 0x98, 0x52, 0x06, 0x80, 0x50, 0x0a, 0x01, 0x40, + 0x24, 0x0c, 0xc2, 0x87, 0x98, + // 'e' (0x65) 10x10, offset 1057-1070, at +2/-9 + // in regular row-major format + 0x3f, 0x18, 0x68, 0x06, 0x01, 0xff, 0xe0, 0x08, + 0x03, 0x00, 0x60, 0xc7, 0xc0, + // 'f' (0x66) 9x15, offset 1070-1087, at +4/-14 + // in regular row-major format + 0x0f, 0x98, 0x08, 0x04, 0x02, 0x07, 0xf8, 0x80, + 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x03, + 0xf8, + // 'g' (0x67) 11x14, offset 1087-1107, at +2/-9 + // in regular row-major format + 0x1e, 0x6c, 0x39, 0x03, 0x40, 0x28, 0x05, 0x00, + 0xa0, 0x12, 0x06, 0x61, 0x43, 0xc8, 0x01, 0x00, + 0x20, 0x08, 0x3e, 0x00, + // 'h' (0x68) 10x15, offset 1107-1126, at +2/-14 + // in regular row-major format + 0xc0, 0x10, 0x04, 0x01, 0x00, 0x40, 0x13, 0x87, + 0x11, 0x82, 0x40, 0x90, 0x24, 0x09, 0x02, 0x40, + 0x90, 0x2e, 0x1c, + // 'i' (0x69) 9x15, offset 1126-1143, at +3/-14 + // in regular row-major format + 0x08, 0x04, 0x02, 0x00, 0x00, 0x03, 0xc0, 0x20, + 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x80, 0x43, + 0xfe, + // 'j' (0x6a) 7x19, offset 1143-1160, at +3/-14 + // in regular row-major format + 0x04, 0x08, 0x10, 0x00, 0x1f, 0xc0, 0x81, 0x02, + 0x04, 0x08, 0x10, 0x20, 0x40, 0x81, 0x02, 0x0b, + 0xe0, + // 'k' (0x6b) 12x15, offset 1160-1183, at +1/-14 + // in regular row-major format + 0xe0, 0x02, 0x00, 0x20, 0x02, 0x00, 0x20, 0x02, + 0x3c, 0x21, 0x02, 0x60, 0x2c, 0x03, 0x80, 0x24, + 0x02, 0x20, 0x21, 0x02, 0x08, 0xe1, 0xf0, + // 'l' (0x6c) 9x15, offset 1183-1200, at +3/-14 + // in regular row-major format + 0x78, 0x04, 0x02, 0x01, 0x00, 0x80, 0x40, 0x20, + 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x80, 0x43, + 0xfe, + // 'm' (0x6d) 13x10, offset 1200-1217, at +1/-9 + // in regular row-major format + 0xdc, 0xe3, 0x19, 0x90, 0x84, 0x84, 0x24, 0x21, + 0x21, 0x09, 0x08, 0x48, 0x42, 0x42, 0x17, 0x18, + 0xc0, + // 'n' (0x6e) 12x10, offset 1217-1232, at +1/-9 + // in regular row-major format + 0x67, 0x83, 0x84, 0x20, 0x22, 0x02, 0x20, 0x22, + 0x02, 0x20, 0x22, 0x02, 0x20, 0x2f, 0x07, + // 'o' (0x6f) 11x10, offset 1232-1246, at +2/-9 + // in regular row-major format + 0x1f, 0x04, 0x11, 0x01, 0x40, 0x18, 0x03, 0x00, + 0x60, 0x0a, 0x02, 0x20, 0x83, 0xe0, + // 'p' (0x70) 12x14, offset 1246-1267, at +1/-9 + // in regular row-major format + 0xcf, 0x85, 0x06, 0x60, 0x24, 0x01, 0x40, 0x14, + 0x01, 0x40, 0x16, 0x02, 0x50, 0x44, 0xf8, 0x40, + 0x04, 0x00, 0x40, 0x0f, 0x00, + // 'q' (0x71) 11x14, offset 1267-1287, at +2/-9 + // in regular row-major format + 0x1e, 0x6c, 0x3b, 0x03, 0x40, 0x28, 0x05, 0x00, + 0xa0, 0x12, 0x06, 0x61, 0x43, 0xc8, 0x01, 0x00, + 0x20, 0x04, 0x03, 0xc0, + // 'r' (0x72) 10x10, offset 1287-1300, at +3/-9 + // in regular row-major format + 0xe3, 0x8b, 0x13, 0x80, 0x80, 0x20, 0x08, 0x02, + 0x00, 0x80, 0x20, 0x3f, 0x80, + // 's' (0x73) 10x10, offset 1300-1313, at +2/-9 + // in regular row-major format + 0x1f, 0x58, 0x34, 0x05, 0x80, 0x1e, 0x00, 0x60, + 0x06, 0x01, 0xc0, 0xaf, 0xc0, + // 't' (0x74) 11x14, offset 1313-1333, at +1/-13 + // in regular row-major format + 0x20, 0x04, 0x00, 0x80, 0x10, 0x0f, 0xf0, 0x40, + 0x08, 0x01, 0x00, 0x20, 0x04, 0x00, 0x80, 0x10, + 0x03, 0x04, 0x3f, 0x00, + // 'u' (0x75) 11x10, offset 1333-1347, at +2/-9 + // in regular row-major format + 0xc1, 0xc8, 0x09, 0x01, 0x20, 0x24, 0x04, 0x80, + 0x90, 0x12, 0x02, 0x61, 0xc7, 0xcc, + // 'v' (0x76) 13x10, offset 1347-1364, at +1/-9 + // in regular row-major format + 0xf8, 0xf9, 0x01, 0x08, 0x10, 0x60, 0x81, 0x08, + 0x08, 0x40, 0x22, 0x01, 0x20, 0x05, 0x00, 0x30, + 0x00, + // 'w' (0x77) 13x10, offset 1364-1381, at +1/-9 + // in regular row-major format + 0xf0, 0x7a, 0x01, 0x10, 0x08, 0x8c, 0x42, 0x62, + 0x12, 0x90, 0xa5, 0x05, 0x18, 0x28, 0xc0, 0x86, + 0x00, + // 'x' (0x78) 12x10, offset 1381-1396, at +1/-9 + // in regular row-major format + 0x78, 0xf3, 0x04, 0x18, 0x80, 0xd0, 0x06, 0x00, + 0x70, 0x09, 0x81, 0x0c, 0x20, 0x6f, 0x8f, + // 'y' (0x79) 12x14, offset 1396-1417, at +1/-9 + // in regular row-major format + 0xf0, 0xf2, 0x02, 0x20, 0x41, 0x04, 0x10, 0x80, + 0x88, 0x09, 0x00, 0x50, 0x06, 0x00, 0x20, 0x04, + 0x00, 0x40, 0x08, 0x0f, 0xe0, + // 'z' (0x7a) 9x10, offset 1417-1429, at +3/-9 + // in regular row-major format + 0xff, 0x41, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x40, 0xbf, 0xc0, + // '{' (0x7b) 5x18, offset 1429-1441, at +5/-14 + // in regular row-major format + 0x19, 0x08, 0x42, 0x10, 0x84, 0x64, 0x18, 0x42, + 0x10, 0x84, 0x20, 0xc0, + // '|' (0x7c) 1x18, offset 1441-1444, at +7/-14 + // in regular row-major format + 0xff, 0xff, 0xc0, + // '}' (0x7d) 5x18, offset 1444-1456, at +5/-14 + // in regular row-major format + 0xc1, 0x08, 0x42, 0x10, 0x84, 0x10, 0x4c, 0x42, + 0x10, 0x84, 0x26, 0x00, +}; + + +static const uint8_t FreeMono18pt7b_generic[] = { + // ' ' (0x20) 0x0, offset 0-0, at +0/+1 + // in regular row-major format + // '!' (0x21) 4x22, offset 0-11, at +8/-21 + // in regular row-major format + 0x27, 0x77, 0x77, 0x77, 0x77, 0x22, 0x22, 0x20, + 0x00, 0x6f, 0xf6, + // '"' (0x22) 11x10, offset 11-25, at +5/-20 + // in regular row-major format + 0xf1, 0xfe, 0x3f, 0xc7, 0xf8, 0xff, 0x1e, 0xc3, + 0x98, 0x33, 0x06, 0x60, 0xcc, 0x18, + // '#' (0x23) 14x24, offset 25-67, at +3/-21 + // in regular row-major format + 0x04, 0x20, 0x10, 0x80, 0x42, 0x01, 0x08, 0x04, + 0x20, 0x10, 0x80, 0x42, 0x01, 0x10, 0x04, 0x41, + 0xff, 0xf0, 0x44, 0x02, 0x10, 0x08, 0x40, 0x21, + 0x0f, 0xff, 0xc2, 0x10, 0x08, 0x40, 0x21, 0x00, + 0x84, 0x02, 0x10, 0x08, 0x40, 0x23, 0x00, 0x88, + 0x02, 0x20, + // '$' (0x24) 13x26, offset 67-110, at +4/-22 + // in regular row-major format + 0x02, 0x00, 0x10, 0x00, 0x80, 0x1f, 0xa3, 0x07, + 0x10, 0x09, 0x00, 0x48, 0x00, 0x40, 0x03, 0x00, + 0x0c, 0x00, 0x3c, 0x00, 0x1e, 0x00, 0x18, 0x00, + 0x20, 0x01, 0x80, 0x0c, 0x00, 0x70, 0x05, 0xe0, + 0xc9, 0xf8, 0x01, 0x00, 0x08, 0x00, 0x40, 0x02, + 0x00, 0x10, 0x00, + // '%' (0x25) 15x21, offset 110-150, at +3/-20 + // in regular row-major format + 0x1e, 0x00, 0x42, 0x01, 0x02, 0x02, 0x04, 0x04, + 0x08, 0x08, 0x10, 0x08, 0x40, 0x0f, 0x00, 0x00, + 0x1e, 0x01, 0xf0, 0x1f, 0x01, 0xe0, 0x0e, 0x00, + 0x00, 0x3c, 0x00, 0x86, 0x02, 0x06, 0x04, 0x04, + 0x08, 0x08, 0x10, 0x30, 0x10, 0xc0, 0x1e, 0x00, + // '&' (0x26) 12x18, offset 150-177, at +4/-17 + // in regular row-major format + 0x0f, 0xc1, 0x00, 0x20, 0x02, 0x00, 0x20, 0x02, + 0x00, 0x10, 0x01, 0x00, 0x08, 0x03, 0xc0, 0x6c, + 0x3c, 0x62, 0x82, 0x68, 0x34, 0x81, 0xcc, 0x08, + 0x61, 0xc3, 0xe7, + // ''' (0x27) 4x10, offset 177-182, at +8/-20 + // in regular row-major format + 0xff, 0xff, 0xf6, 0x66, 0x66, + // '(' (0x28) 5x25, offset 182-198, at +10/-20 + // in regular row-major format + 0x08, 0xc4, 0x62, 0x31, 0x8c, 0xc6, 0x31, 0x8c, + 0x63, 0x18, 0xc3, 0x18, 0xc2, 0x18, 0xc3, 0x18, + // ')' (0x29) 5x25, offset 198-214, at +6/-20 + // in regular row-major format + 0x86, 0x10, 0xc2, 0x18, 0xc6, 0x10, 0xc6, 0x31, + 0x8c, 0x63, 0x18, 0x8c, 0x62, 0x31, 0x98, 0x80, + // '*' (0x2a) 13x12, offset 214-234, at +4/-20 + // in regular row-major format + 0x02, 0x00, 0x10, 0x00, 0x80, 0x04, 0x0c, 0x21, + 0x9d, 0x70, 0x1c, 0x00, 0xa0, 0x0d, 0x80, 0xc6, + 0x04, 0x10, 0x40, 0x80, + // '+' (0x2b) 15x17, offset 234-266, at +3/-17 + // in regular row-major format + 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, + 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0xff, + 0xfe, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, + 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x01, 0x00, + // ',' (0x2c) 7x10, offset 266-275, at +5/-4 + // in regular row-major format + 0x3e, 0x78, 0xf3, 0xc7, 0x8e, 0x18, 0x70, 0xc1, + 0x80, + // '-' (0x2d) 15x1, offset 275-277, at +3/-9 + // in regular row-major format + 0xff, 0xfe, + // '.' (0x2e) 5x5, offset 277-281, at +8/-4 + // in regular row-major format + 0x77, 0xff, 0xf7, 0x00, + // '/' (0x2f) 13x26, offset 281-324, at +4/-22 + // in regular row-major format + 0x00, 0x08, 0x00, 0xc0, 0x04, 0x00, 0x60, 0x02, + 0x00, 0x30, 0x01, 0x00, 0x18, 0x00, 0x80, 0x0c, + 0x00, 0x40, 0x02, 0x00, 0x20, 0x01, 0x00, 0x10, + 0x00, 0x80, 0x08, 0x00, 0x40, 0x04, 0x00, 0x20, + 0x02, 0x00, 0x10, 0x01, 0x00, 0x08, 0x00, 0x80, + 0x04, 0x00, 0x00, + // '0' (0x30) 13x21, offset 324-359, at +4/-20 + // in regular row-major format + 0x0f, 0x81, 0x82, 0x08, 0x08, 0x80, 0x24, 0x01, + 0x60, 0x0e, 0x00, 0x30, 0x01, 0x80, 0x0c, 0x00, + 0x60, 0x03, 0x00, 0x18, 0x00, 0xc0, 0x06, 0x00, + 0x30, 0x03, 0x40, 0x12, 0x00, 0x88, 0x08, 0x60, + 0xc0, 0xf8, 0x00, + // '1' (0x31) 13x21, offset 359-394, at +4/-20 + // in regular row-major format + 0x06, 0x00, 0x70, 0x06, 0x80, 0x64, 0x06, 0x20, + 0x31, 0x00, 0x08, 0x00, 0x40, 0x02, 0x00, 0x10, + 0x00, 0x80, 0x04, 0x00, 0x20, 0x01, 0x00, 0x08, + 0x00, 0x40, 0x02, 0x00, 0x10, 0x00, 0x80, 0x04, + 0x0f, 0xff, 0x80, + // '2' (0x32) 13x21, offset 394-429, at +3/-20 + // in regular row-major format + 0x0f, 0x80, 0xc3, 0x08, 0x04, 0x80, 0x24, 0x00, + 0x80, 0x04, 0x00, 0x20, 0x02, 0x00, 0x10, 0x01, + 0x00, 0x10, 0x01, 0x80, 0x18, 0x01, 0x80, 0x18, + 0x01, 0x80, 0x18, 0x01, 0x80, 0x58, 0x03, 0x80, + 0x1f, 0xff, 0x80, + // '3' (0x33) 14x21, offset 429-466, at +3/-20 + // in regular row-major format + 0x0f, 0xc0, 0xc0, 0x86, 0x01, 0x00, 0x02, 0x00, + 0x08, 0x00, 0x20, 0x00, 0x80, 0x04, 0x00, 0x20, + 0x0f, 0x00, 0x06, 0x00, 0x04, 0x00, 0x08, 0x00, + 0x10, 0x00, 0x40, 0x01, 0x00, 0x04, 0x00, 0x2c, + 0x01, 0x9c, 0x0c, 0x0f, 0xc0, + // '4' (0x34) 12x21, offset 466-498, at +4/-20 + // in regular row-major format + 0x01, 0xc0, 0x14, 0x02, 0x40, 0x64, 0x04, 0x40, + 0xc4, 0x08, 0x41, 0x84, 0x10, 0x42, 0x04, 0x20, + 0x44, 0x04, 0x40, 0x48, 0x04, 0xff, 0xf0, 0x04, + 0x00, 0x40, 0x04, 0x00, 0x40, 0x04, 0x07, 0xf0, + // '5' (0x35) 14x21, offset 498-535, at +3/-20 + // in regular row-major format + 0x3f, 0xf0, 0x80, 0x02, 0x00, 0x08, 0x00, 0x20, + 0x00, 0x80, 0x02, 0x00, 0x0b, 0xf0, 0x30, 0x30, + 0x00, 0x60, 0x00, 0x80, 0x01, 0x00, 0x04, 0x00, + 0x10, 0x00, 0x40, 0x01, 0x00, 0x0e, 0x00, 0x2c, + 0x01, 0x0c, 0x18, 0x0f, 0xc0, + // '6' (0x36) 12x21, offset 535-567, at +5/-20 + // in regular row-major format + 0x01, 0xf0, 0x60, 0x18, 0x03, 0x00, 0x20, 0x04, + 0x00, 0x40, 0x0c, 0x00, 0x80, 0x08, 0xf8, 0x98, + 0x4a, 0x02, 0xe0, 0x3c, 0x01, 0x80, 0x14, 0x01, + 0x40, 0x14, 0x03, 0x20, 0x21, 0x0c, 0x0f, 0x80, + // '7' (0x37) 12x21, offset 567-599, at +4/-20 + // in regular row-major format + 0xff, 0xf8, 0x01, 0x80, 0x18, 0x03, 0x00, 0x20, + 0x02, 0x00, 0x20, 0x04, 0x00, 0x40, 0x04, 0x00, + 0xc0, 0x08, 0x00, 0x80, 0x18, 0x01, 0x00, 0x10, + 0x01, 0x00, 0x30, 0x02, 0x00, 0x20, 0x02, 0x00, + // '8' (0x38) 13x21, offset 599-634, at +4/-20 + // in regular row-major format + 0x0f, 0x81, 0x83, 0x10, 0x05, 0x80, 0x38, 0x00, + 0xc0, 0x06, 0x00, 0x30, 0x03, 0x40, 0x11, 0x83, + 0x07, 0xf0, 0x60, 0xc4, 0x01, 0x60, 0x0e, 0x00, + 0x30, 0x01, 0x80, 0x0e, 0x00, 0xd0, 0x04, 0x60, + 0xc1, 0xfc, 0x00, + // '9' (0x39) 12x21, offset 634-666, at +5/-20 + // in regular row-major format + 0x1f, 0x03, 0x08, 0x40, 0x4c, 0x02, 0x80, 0x28, + 0x02, 0x80, 0x18, 0x03, 0xc0, 0x74, 0x05, 0x21, + 0x91, 0xf1, 0x00, 0x10, 0x03, 0x00, 0x20, 0x02, + 0x00, 0x40, 0x0c, 0x01, 0x80, 0x60, 0xf8, 0x00, + // ':' (0x3a) 5x15, offset 666-676, at +8/-14 + // in regular row-major format + 0x77, 0xff, 0xf7, 0x00, 0x00, 0x00, 0x1d, 0xff, + 0xfd, 0xc0, + // ';' (0x3b) 7x20, offset 676-694, at +5/-14 + // in regular row-major format + 0x1c, 0x7c, 0xf9, 0xf1, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0xf1, 0xe3, 0x8f, 0x1c, 0x38, 0xe1, 0xc3, + 0x06, 0x00, + // '<' (0x3c) 15x16, offset 694-724, at +3/-17 + // in regular row-major format + 0x00, 0x06, 0x00, 0x18, 0x00, 0xe0, 0x07, 0x00, + 0x38, 0x01, 0xc0, 0x06, 0x00, 0x38, 0x00, 0xe0, + 0x00, 0x70, 0x00, 0x38, 0x00, 0x18, 0x00, 0x1c, + 0x00, 0x0e, 0x00, 0x07, 0x00, 0x03, + // '=' (0x3d) 17x6, offset 724-737, at +2/-12 + // in regular row-major format + 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0xff, 0xfc, + // '>' (0x3e) 15x16, offset 737-767, at +3/-17 + // in regular row-major format + 0xc0, 0x00, 0xc0, 0x00, 0xe0, 0x00, 0x70, 0x00, + 0x38, 0x00, 0x1c, 0x00, 0x0c, 0x00, 0x0e, 0x00, + 0x0e, 0x00, 0x70, 0x03, 0x80, 0x0c, 0x00, 0x70, + 0x03, 0x80, 0x1c, 0x00, 0x60, 0x00, + // '?' (0x3f) 12x20, offset 767-797, at +5/-19 + // in regular row-major format + 0x3f, 0x8e, 0x0c, 0x80, 0x28, 0x01, 0x80, 0x10, + 0x01, 0x00, 0x10, 0x02, 0x00, 0xc0, 0x38, 0x06, + 0x00, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0e, 0x01, 0xf0, 0x1f, 0x00, 0xe0, + // '@' (0x40) 13x23, offset 797-835, at +4/-20 + // in regular row-major format + 0x0f, 0x01, 0x86, 0x08, 0x08, 0x80, 0x24, 0x01, + 0x40, 0x0a, 0x00, 0x50, 0x1e, 0x83, 0x14, 0x20, + 0xa2, 0x05, 0x10, 0x28, 0x81, 0x46, 0x0a, 0x18, + 0x50, 0x3f, 0x80, 0x04, 0x00, 0x10, 0x00, 0x80, + 0x02, 0x00, 0x18, 0x18, 0x3f, 0x00, + // 'A' (0x41) 21x20, offset 835-888, at +0/-19 + // in regular row-major format + 0x1f, 0xf0, 0x00, 0x06, 0x80, 0x00, 0x34, 0x00, + 0x01, 0x30, 0x00, 0x18, 0x80, 0x00, 0x86, 0x00, + 0x04, 0x30, 0x00, 0x60, 0x80, 0x02, 0x06, 0x00, + 0x10, 0x10, 0x01, 0x80, 0x80, 0x08, 0x06, 0x00, + 0x7f, 0xf0, 0x06, 0x00, 0x80, 0x20, 0x06, 0x01, + 0x00, 0x10, 0x18, 0x00, 0xc0, 0x80, 0x06, 0x04, + 0x00, 0x11, 0xfc, 0x0f, 0xf0, + // 'B' (0x42) 18x20, offset 888-933, at +1/-19 + // in regular row-major format + 0xff, 0xf8, 0x04, 0x01, 0x01, 0x00, 0x20, 0x40, + 0x04, 0x10, 0x01, 0x04, 0x00, 0x41, 0x00, 0x10, + 0x40, 0x08, 0x10, 0x0c, 0x07, 0xff, 0x01, 0x00, + 0x70, 0x40, 0x06, 0x10, 0x00, 0x84, 0x00, 0x11, + 0x00, 0x04, 0x40, 0x01, 0x10, 0x00, 0x44, 0x00, + 0x21, 0x00, 0x33, 0xff, 0xf8, + // 'C' (0x43) 17x20, offset 933-976, at +2/-19 + // in regular row-major format + 0x03, 0xf1, 0x06, 0x0e, 0x8c, 0x01, 0xc4, 0x00, + 0x64, 0x00, 0x12, 0x00, 0x0a, 0x00, 0x01, 0x00, + 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, + 0x00, 0x08, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, + 0x80, 0x00, 0x20, 0x01, 0x88, 0x01, 0x83, 0x03, + 0x80, 0x7e, 0x00, + // 'D' (0x44) 16x20, offset 976-1016, at +2/-19 + // in regular row-major format + 0xff, 0xe0, 0x20, 0x18, 0x20, 0x0c, 0x20, 0x04, + 0x20, 0x02, 0x20, 0x02, 0x20, 0x01, 0x20, 0x01, + 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, + 0x20, 0x01, 0x20, 0x01, 0x20, 0x02, 0x20, 0x02, + 0x20, 0x04, 0x20, 0x0c, 0x20, 0x18, 0xff, 0xe0, + // 'E' (0x45) 17x20, offset 1016-1059, at +1/-19 + // in regular row-major format + 0xff, 0xff, 0x08, 0x00, 0x84, 0x00, 0x42, 0x00, + 0x21, 0x00, 0x10, 0x80, 0x00, 0x40, 0x00, 0x20, + 0x40, 0x10, 0x20, 0x0f, 0xf0, 0x04, 0x08, 0x02, + 0x04, 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, 0x02, + 0x20, 0x01, 0x10, 0x00, 0x88, 0x00, 0x44, 0x00, + 0x3f, 0xff, 0xf0, + // 'F' (0x46) 17x20, offset 1059-1102, at +1/-19 + // in regular row-major format + 0xff, 0xff, 0x88, 0x00, 0x44, 0x00, 0x22, 0x00, + 0x11, 0x00, 0x08, 0x80, 0x00, 0x40, 0x00, 0x20, + 0x40, 0x10, 0x20, 0x0f, 0xf0, 0x04, 0x08, 0x02, + 0x04, 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, + 0x20, 0x00, 0x10, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x1f, 0xf8, 0x00, + // 'G' (0x47) 17x20, offset 1102-1145, at +2/-19 + // in regular row-major format + 0x03, 0xf9, 0x06, 0x07, 0x84, 0x00, 0xc4, 0x00, + 0x24, 0x00, 0x12, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, + 0x0f, 0xf8, 0x00, 0x14, 0x00, 0x09, 0x00, 0x04, + 0x80, 0x02, 0x20, 0x01, 0x18, 0x00, 0x83, 0x01, + 0xc0, 0x7f, 0x00, + // 'H' (0x48) 16x20, offset 1145-1185, at +2/-19 + // in regular row-major format + 0xfc, 0x3f, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, + 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, + 0x20, 0x04, 0x3f, 0xfc, 0x20, 0x04, 0x20, 0x04, + 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, + 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0xfc, 0x3f, + // 'I' (0x49) 13x20, offset 1185-1218, at +4/-19 + // in regular row-major format + 0xff, 0xf8, 0x10, 0x00, 0x80, 0x04, 0x00, 0x20, + 0x01, 0x00, 0x08, 0x00, 0x40, 0x02, 0x00, 0x10, + 0x00, 0x80, 0x04, 0x00, 0x20, 0x01, 0x00, 0x08, + 0x00, 0x40, 0x02, 0x00, 0x10, 0x00, 0x81, 0xff, + 0xf0, + // 'J' (0x4a) 17x20, offset 1218-1261, at +3/-19 + // in regular row-major format + 0x03, 0xff, 0x80, 0x04, 0x00, 0x02, 0x00, 0x01, + 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, + 0x10, 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x10, + 0x01, 0x08, 0x00, 0x84, 0x00, 0x42, 0x00, 0x21, + 0x00, 0x10, 0x80, 0x10, 0x20, 0x18, 0x0c, 0x18, + 0x01, 0xf0, 0x00, + // 'K' (0x4b) 18x20, offset 1261-1306, at +1/-19 + // in regular row-major format + 0xff, 0x1f, 0x84, 0x01, 0x81, 0x00, 0xc0, 0x40, + 0x60, 0x10, 0x30, 0x04, 0x18, 0x01, 0x0c, 0x00, + 0x46, 0x00, 0x13, 0x00, 0x05, 0xf0, 0x01, 0xc6, + 0x00, 0x60, 0xc0, 0x10, 0x18, 0x04, 0x06, 0x01, + 0x00, 0xc0, 0x40, 0x30, 0x10, 0x04, 0x04, 0x01, + 0x81, 0x00, 0x23, 0xfc, 0x0f, + // 'L' (0x4c) 15x20, offset 1306-1344, at +3/-19 + // in regular row-major format + 0xff, 0x80, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, + 0x80, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, + 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, + 0x01, 0x00, 0x42, 0x00, 0x84, 0x01, 0x08, 0x02, + 0x10, 0x04, 0x20, 0x0f, 0xff, 0xf0, + // 'M' (0x4d) 19x20, offset 1344-1392, at +1/-19 + // in regular row-major format + 0xf0, 0x01, 0xe7, 0x00, 0x70, 0xa0, 0x0a, 0x16, + 0x03, 0x42, 0x40, 0x48, 0x4c, 0x19, 0x08, 0x82, + 0x21, 0x10, 0x44, 0x23, 0x18, 0x84, 0x22, 0x10, + 0x86, 0xc2, 0x10, 0x50, 0x42, 0x0e, 0x08, 0x41, + 0xc1, 0x08, 0x00, 0x21, 0x00, 0x04, 0x20, 0x00, + 0x84, 0x00, 0x10, 0x80, 0x02, 0x7f, 0x03, 0xf0, + // 'N' (0x4e) 18x20, offset 1392-1437, at +1/-19 + // in regular row-major format + 0xf8, 0x1f, 0xc6, 0x00, 0x41, 0xc0, 0x10, 0x50, + 0x04, 0x12, 0x01, 0x04, 0xc0, 0x41, 0x10, 0x10, + 0x46, 0x04, 0x10, 0x81, 0x04, 0x10, 0x41, 0x04, + 0x10, 0x40, 0x84, 0x10, 0x31, 0x04, 0x04, 0x41, + 0x01, 0x90, 0x40, 0x24, 0x10, 0x05, 0x04, 0x01, + 0xc1, 0x00, 0x31, 0xfc, 0x0c, + // 'O' (0x4f) 17x20, offset 1437-1480, at +2/-19 + // in regular row-major format + 0x03, 0xe0, 0x06, 0x0c, 0x04, 0x01, 0x04, 0x00, + 0x46, 0x00, 0x32, 0x00, 0x0b, 0x00, 0x05, 0x00, + 0x01, 0x80, 0x00, 0xc0, 0x00, 0x60, 0x00, 0x30, + 0x00, 0x18, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x04, + 0xc0, 0x06, 0x20, 0x02, 0x08, 0x02, 0x03, 0x06, + 0x00, 0x7c, 0x00, + // 'P' (0x50) 16x20, offset 1480-1520, at +1/-19 + // in regular row-major format + 0xff, 0xf0, 0x10, 0x0c, 0x10, 0x02, 0x10, 0x03, + 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x03, + 0x10, 0x06, 0x10, 0x0c, 0x1f, 0xf0, 0x10, 0x00, + 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, + 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0xff, 0xc0, + // 'Q' (0x51) 17x24, offset 1520-1571, at +2/-19 + // in regular row-major format + 0x03, 0xe0, 0x06, 0x0c, 0x04, 0x01, 0x04, 0x00, + 0x46, 0x00, 0x32, 0x00, 0x0b, 0x00, 0x07, 0x00, + 0x01, 0x80, 0x00, 0xc0, 0x00, 0x60, 0x00, 0x30, + 0x00, 0x18, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x04, + 0xc0, 0x06, 0x20, 0x02, 0x08, 0x02, 0x03, 0x06, + 0x00, 0xfc, 0x00, 0x30, 0x00, 0x30, 0x00, 0x7f, + 0xc6, 0x38, 0x1e, + // 'R' (0x52) 19x20, offset 1571-1619, at +1/-19 + // in regular row-major format + 0xff, 0xf0, 0x02, 0x01, 0x80, 0x40, 0x08, 0x08, + 0x01, 0x81, 0x00, 0x10, 0x20, 0x02, 0x04, 0x00, + 0x40, 0x80, 0x18, 0x10, 0x06, 0x02, 0x03, 0x80, + 0x7f, 0xc0, 0x08, 0x18, 0x01, 0x01, 0x80, 0x20, + 0x18, 0x04, 0x01, 0x80, 0x80, 0x10, 0x10, 0x03, + 0x02, 0x00, 0x20, 0x40, 0x06, 0x7f, 0x80, 0x70, + // 'S' (0x53) 14x20, offset 1619-1654, at +3/-19 + // in regular row-major format + 0x0f, 0xc8, 0x61, 0xe2, 0x01, 0x90, 0x02, 0x40, + 0x09, 0x00, 0x04, 0x00, 0x08, 0x00, 0x38, 0x00, + 0x3e, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x0c, 0x00, + 0x18, 0x00, 0x60, 0x01, 0x80, 0x0f, 0x00, 0x2b, + 0x03, 0x23, 0xf0, + // 'T' (0x54) 15x20, offset 1654-1692, at +3/-19 + // in regular row-major format + 0xff, 0xff, 0x02, 0x06, 0x04, 0x0c, 0x08, 0x18, + 0x10, 0x20, 0x20, 0x00, 0x40, 0x00, 0x80, 0x01, + 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, + 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x01, 0x00, + 0x02, 0x00, 0x04, 0x01, 0xff, 0xc0, + // 'U' (0x55) 17x20, offset 1692-1735, at +2/-19 + // in regular row-major format + 0xfc, 0x1f, 0x90, 0x01, 0x08, 0x00, 0x84, 0x00, + 0x42, 0x00, 0x21, 0x00, 0x10, 0x80, 0x08, 0x40, + 0x04, 0x20, 0x02, 0x10, 0x01, 0x08, 0x00, 0x84, + 0x00, 0x42, 0x00, 0x21, 0x00, 0x10, 0x80, 0x08, + 0x40, 0x04, 0x10, 0x04, 0x0c, 0x06, 0x03, 0x06, + 0x00, 0x7c, 0x00, + // 'V' (0x56) 21x20, offset 1735-1788, at +0/-19 + // in regular row-major format + 0xfe, 0x03, 0xf8, 0x80, 0x02, 0x04, 0x00, 0x10, + 0x30, 0x01, 0x80, 0x80, 0x08, 0x06, 0x00, 0xc0, + 0x30, 0x06, 0x00, 0x80, 0x20, 0x06, 0x03, 0x00, + 0x30, 0x10, 0x00, 0x80, 0x80, 0x06, 0x0c, 0x00, + 0x10, 0x40, 0x00, 0x86, 0x00, 0x06, 0x20, 0x00, + 0x11, 0x00, 0x00, 0xd8, 0x00, 0x06, 0x80, 0x00, + 0x1c, 0x00, 0x00, 0xe0, 0x00, + // 'W' (0x57) 19x20, offset 1788-1836, at +1/-19 + // in regular row-major format + 0xfc, 0x0f, 0xe8, 0x00, 0x19, 0x00, 0x03, 0x10, + 0x00, 0x62, 0x00, 0x08, 0x41, 0x81, 0x08, 0x28, + 0x21, 0x05, 0x04, 0x21, 0xa0, 0x84, 0x36, 0x30, + 0x84, 0x46, 0x08, 0x88, 0xc1, 0x31, 0x18, 0x24, + 0x12, 0x04, 0x82, 0x40, 0xb0, 0x48, 0x14, 0x09, + 0x02, 0x80, 0xa0, 0x30, 0x1c, 0x06, 0x03, 0x80, + // 'X' (0x58) 19x20, offset 1836-1884, at +1/-19 + // in regular row-major format + 0x7e, 0x0f, 0xc2, 0x00, 0x60, 0x60, 0x0c, 0x06, + 0x03, 0x00, 0x60, 0xc0, 0x0c, 0x10, 0x00, 0xc6, + 0x00, 0x0d, 0x80, 0x00, 0xa0, 0x00, 0x1c, 0x00, + 0x03, 0x80, 0x00, 0xd8, 0x00, 0x11, 0x00, 0x06, + 0x30, 0x01, 0x83, 0x00, 0x60, 0x30, 0x08, 0x06, + 0x03, 0x00, 0x60, 0xc0, 0x06, 0x7f, 0x07, 0xf0, + // 'Y' (0x59) 17x20, offset 1884-1927, at +2/-19 + // in regular row-major format + 0xfc, 0x1f, 0x98, 0x03, 0x04, 0x01, 0x03, 0x01, + 0x80, 0xc1, 0x80, 0x20, 0x80, 0x18, 0xc0, 0x04, + 0x40, 0x03, 0x60, 0x00, 0xe0, 0x00, 0x20, 0x00, + 0x10, 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, + 0x03, 0xff, 0x80, + // 'Z' (0x5a) 13x20, offset 1927-1960, at +4/-19 + // in regular row-major format + 0xff, 0xf4, 0x00, 0xa0, 0x09, 0x00, 0x48, 0x04, + 0x40, 0x40, 0x02, 0x00, 0x20, 0x02, 0x00, 0x10, + 0x01, 0x00, 0x10, 0x00, 0x80, 0x08, 0x04, 0x80, + 0x24, 0x01, 0x40, 0x0c, 0x00, 0x60, 0x03, 0xff, + 0xf0, + // '[' (0x5b) 5x25, offset 1960-1976, at +10/-20 + // in regular row-major format + 0xfc, 0x21, 0x08, 0x42, 0x10, 0x84, 0x21, 0x08, + 0x42, 0x10, 0x84, 0x21, 0x08, 0x42, 0x10, 0xf8, + // '\' (0x5c) 13x26, offset 1976-2019, at +4/-22 + // in regular row-major format + 0x80, 0x02, 0x00, 0x10, 0x00, 0xc0, 0x02, 0x00, + 0x18, 0x00, 0x40, 0x03, 0x00, 0x08, 0x00, 0x40, + 0x01, 0x00, 0x08, 0x00, 0x20, 0x01, 0x00, 0x04, + 0x00, 0x20, 0x00, 0x80, 0x04, 0x00, 0x10, 0x00, + 0x80, 0x02, 0x00, 0x10, 0x00, 0x40, 0x02, 0x00, + 0x08, 0x00, 0x40, + // ']' (0x5d) 5x25, offset 2019-2035, at +6/-20 + // in regular row-major format + 0xf8, 0x42, 0x10, 0x84, 0x21, 0x08, 0x42, 0x10, + 0x84, 0x21, 0x08, 0x42, 0x10, 0x84, 0x21, 0xf8, + // '^' (0x5e) 13x9, offset 2035-2050, at +4/-20 + // in regular row-major format + 0x02, 0x00, 0x38, 0x03, 0x60, 0x11, 0x01, 0x8c, + 0x18, 0x31, 0x80, 0xd8, 0x03, 0x80, 0x08, + // '_' (0x5f) 21x1, offset 2050-2053, at +0/+4 + // in regular row-major format + 0xff, 0xff, 0xf8, + // '`' (0x60) 6x5, offset 2053-2057, at +5/-21 + // in regular row-major format + 0xc1, 0x83, 0x06, 0x0c, + // 'a' (0x61) 16x15, offset 2057-2087, at +3/-14 + // in regular row-major format + 0x0f, 0xc0, 0x70, 0x30, 0x00, 0x10, 0x00, 0x08, + 0x00, 0x08, 0x00, 0x08, 0x0f, 0xf8, 0x30, 0x08, + 0x40, 0x08, 0x80, 0x08, 0x80, 0x08, 0x80, 0x08, + 0x80, 0x38, 0x60, 0xe8, 0x3f, 0x8f, + // 'b' (0x62) 18x21, offset 2087-2135, at +1/-20 + // in regular row-major format + 0xf0, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x40, + 0x00, 0x10, 0x00, 0x04, 0x00, 0x01, 0x0f, 0x80, + 0x4c, 0x18, 0x14, 0x01, 0x06, 0x00, 0x21, 0x80, + 0x08, 0x40, 0x01, 0x10, 0x00, 0x44, 0x00, 0x11, + 0x00, 0x04, 0x40, 0x01, 0x18, 0x00, 0x86, 0x00, + 0x21, 0xc0, 0x10, 0x5c, 0x18, 0xf1, 0xf8, 0x00, + // 'c' (0x63) 15x15, offset 2135-2164, at +3/-14 + // in regular row-major format + 0x07, 0xe4, 0x30, 0x78, 0x80, 0x32, 0x00, 0x24, + 0x00, 0x50, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, + 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x12, 0x00, + 0xc3, 0x07, 0x01, 0xf8, 0x00, + // 'd' (0x64) 18x21, offset 2164-2212, at +2/-20 + // in regular row-major format + 0x00, 0x1e, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x00, 0x80, 0x7c, 0x20, + 0x60, 0xc8, 0x20, 0x0a, 0x10, 0x01, 0x84, 0x00, + 0x62, 0x00, 0x08, 0x80, 0x02, 0x20, 0x00, 0x88, + 0x00, 0x22, 0x00, 0x08, 0xc0, 0x06, 0x10, 0x01, + 0x82, 0x00, 0xe0, 0x60, 0xe8, 0x0f, 0xe3, 0xc0, + // 'e' (0x65) 16x15, offset 2212-2242, at +2/-14 + // in regular row-major format + 0x07, 0xe0, 0x1c, 0x18, 0x30, 0x0c, 0x60, 0x06, + 0x40, 0x03, 0xc0, 0x03, 0xc0, 0x01, 0xff, 0xff, + 0xc0, 0x00, 0xc0, 0x00, 0x40, 0x00, 0x60, 0x00, + 0x30, 0x03, 0x0c, 0x0e, 0x03, 0xf0, + // 'f' (0x66) 14x21, offset 2242-2279, at +4/-20 + // in regular row-major format + 0x03, 0xfc, 0x18, 0x00, 0x80, 0x02, 0x00, 0x08, + 0x00, 0x20, 0x0f, 0xff, 0x82, 0x00, 0x08, 0x00, + 0x20, 0x00, 0x80, 0x02, 0x00, 0x08, 0x00, 0x20, + 0x00, 0x80, 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, + 0x80, 0x02, 0x00, 0xff, 0xf0, + // 'g' (0x67) 17x22, offset 2279-2326, at +2/-14 + // in regular row-major format + 0x0f, 0xc7, 0x9c, 0x3a, 0x18, 0x07, 0x08, 0x01, + 0x8c, 0x00, 0xc4, 0x00, 0x22, 0x00, 0x11, 0x00, + 0x08, 0x80, 0x04, 0x40, 0x02, 0x10, 0x03, 0x08, + 0x01, 0x82, 0x01, 0x40, 0xc3, 0x20, 0x3f, 0x10, + 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x7f, 0x00, + // 'h' (0x68) 17x21, offset 2326-2371, at +1/-20 + // in regular row-major format + 0xf0, 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x80, 0x00, 0x47, 0xc0, 0x2c, + 0x18, 0x1c, 0x04, 0x0c, 0x01, 0x04, 0x00, 0x82, + 0x00, 0x41, 0x00, 0x20, 0x80, 0x10, 0x40, 0x08, + 0x20, 0x04, 0x10, 0x02, 0x08, 0x01, 0x04, 0x00, + 0x82, 0x00, 0x47, 0xc0, 0xf8, + // 'i' (0x69) 14x22, offset 2371-2410, at +4/-21 + // in regular row-major format + 0x06, 0x00, 0x18, 0x00, 0x60, 0x01, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1f, 0x80, 0x02, 0x00, + 0x08, 0x00, 0x20, 0x00, 0x80, 0x02, 0x00, 0x08, + 0x00, 0x20, 0x00, 0x80, 0x02, 0x00, 0x08, 0x00, + 0x20, 0x00, 0x80, 0x02, 0x03, 0xff, 0xf0, + // 'j' (0x6a) 10x29, offset 2410-2447, at +5/-21 + // in regular row-major format + 0x03, 0x00, 0xc0, 0x30, 0x0c, 0x00, 0x00, 0x00, + 0x03, 0xff, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00, + 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x10, 0x04, + 0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, + 0x10, 0x08, 0x06, 0xfe, 0x00, + // 'k' (0x6b) 16x21, offset 2447-2489, at +2/-20 + // in regular row-major format + 0xf0, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, + 0x10, 0x00, 0x10, 0x00, 0x10, 0xfe, 0x10, 0x30, + 0x10, 0xe0, 0x11, 0xc0, 0x13, 0x00, 0x16, 0x00, + 0x1e, 0x00, 0x1b, 0x00, 0x11, 0x80, 0x10, 0xc0, + 0x10, 0x60, 0x10, 0x30, 0x10, 0x18, 0x10, 0x1c, + 0xf0, 0x3f, + // 'l' (0x6c) 14x21, offset 2489-2526, at +4/-20 + // in regular row-major format + 0x7e, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x02, + 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x02, 0x00, + 0x08, 0x00, 0x20, 0x00, 0x80, 0x02, 0x00, 0x08, + 0x00, 0x20, 0x00, 0x80, 0x02, 0x00, 0x08, 0x00, + 0x20, 0x00, 0x80, 0xff, 0xfc, + // 'm' (0x6d) 19x15, offset 2526-2562, at +1/-14 + // in regular row-major format + 0xef, 0x9e, 0x07, 0x1e, 0x20, 0xc1, 0x82, 0x10, + 0x20, 0x42, 0x04, 0x08, 0x40, 0x81, 0x08, 0x10, + 0x21, 0x02, 0x04, 0x20, 0x40, 0x84, 0x08, 0x10, + 0x81, 0x02, 0x10, 0x20, 0x42, 0x04, 0x08, 0x40, + 0x81, 0x3e, 0x1c, 0x38, + // 'n' (0x6e) 17x15, offset 2562-2594, at +1/-14 + // in regular row-major format + 0x71, 0xf0, 0x0b, 0x06, 0x07, 0x01, 0x03, 0x00, + 0x41, 0x00, 0x20, 0x80, 0x10, 0x40, 0x08, 0x20, + 0x04, 0x10, 0x02, 0x08, 0x01, 0x04, 0x00, 0x82, + 0x00, 0x41, 0x00, 0x20, 0x80, 0x13, 0xf0, 0x3e, + // 'o' (0x6f) 15x15, offset 2594-2623, at +3/-14 + // in regular row-major format + 0x07, 0xc0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x24, + 0x00, 0x50, 0x00, 0x60, 0x00, 0xc0, 0x01, 0x80, + 0x03, 0x00, 0x05, 0x00, 0x12, 0x00, 0x22, 0x00, + 0x83, 0x06, 0x01, 0xf0, 0x00, + // 'p' (0x70) 18x22, offset 2623-2673, at +1/-14 + // in regular row-major format + 0xf1, 0xfc, 0x05, 0xc1, 0x81, 0xc0, 0x10, 0x60, + 0x02, 0x18, 0x00, 0xc4, 0x00, 0x11, 0x00, 0x04, + 0x40, 0x01, 0x10, 0x00, 0x44, 0x00, 0x11, 0x80, + 0x08, 0x60, 0x02, 0x14, 0x01, 0x04, 0xc1, 0x81, + 0x0f, 0x80, 0x40, 0x00, 0x10, 0x00, 0x04, 0x00, + 0x01, 0x00, 0x00, 0x40, 0x00, 0x10, 0x00, 0x3f, + 0xc0, 0x00, + // 'q' (0x71) 18x22, offset 2673-2723, at +2/-14 + // in regular row-major format + 0x0f, 0xe3, 0xc6, 0x0e, 0x86, 0x00, 0xe1, 0x00, + 0x18, 0xc0, 0x06, 0x20, 0x00, 0x88, 0x00, 0x22, + 0x00, 0x08, 0x80, 0x02, 0x20, 0x00, 0x84, 0x00, + 0x61, 0x00, 0x18, 0x20, 0x0a, 0x06, 0x0c, 0x80, + 0x7c, 0x20, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, + 0x80, 0x00, 0x20, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x0f, 0xf0, + // 'r' (0x72) 15x15, offset 2723-2752, at +3/-14 + // in regular row-major format + 0xf8, 0x7c, 0x11, 0x8c, 0x2c, 0x00, 0x70, 0x00, + 0xc0, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, + 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, + 0x01, 0x00, 0x3f, 0xfc, 0x00, + // 's' (0x73) 13x15, offset 2752-2777, at +4/-14 + // in regular row-major format + 0x0f, 0xd1, 0x83, 0x98, 0x04, 0x80, 0x24, 0x00, + 0x30, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x30, 0x00, + 0xe0, 0x03, 0x00, 0x1c, 0x01, 0xf0, 0x1a, 0x7f, + 0x00, + // 't' (0x74) 16x20, offset 2777-2817, at +1/-19 + // in regular row-major format + 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, + 0x08, 0x00, 0xff, 0xfc, 0x08, 0x00, 0x08, 0x00, + 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, + 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, + 0x08, 0x00, 0x08, 0x01, 0x06, 0x0f, 0x03, 0xf8, + // 'u' (0x75) 17x15, offset 2817-2849, at +1/-14 + // in regular row-major format + 0xf0, 0x3e, 0x08, 0x01, 0x04, 0x00, 0x82, 0x00, + 0x41, 0x00, 0x20, 0x80, 0x10, 0x40, 0x08, 0x20, + 0x04, 0x10, 0x02, 0x08, 0x01, 0x04, 0x00, 0x82, + 0x00, 0x41, 0x00, 0xe0, 0x41, 0xd0, 0x1f, 0x8e, + // 'v' (0x76) 19x15, offset 2849-2885, at +1/-14 + // in regular row-major format + 0xfe, 0x0f, 0xe2, 0x00, 0x20, 0x60, 0x0c, 0x0c, + 0x01, 0x80, 0x80, 0x20, 0x18, 0x0c, 0x01, 0x01, + 0x00, 0x30, 0x60, 0x02, 0x08, 0x00, 0x41, 0x00, + 0x0c, 0x60, 0x00, 0x88, 0x00, 0x19, 0x00, 0x01, + 0x40, 0x00, 0x38, 0x00, + // 'w' (0x77) 19x15, offset 2885-2921, at +1/-14 + // in regular row-major format + 0xfc, 0x07, 0xe4, 0x00, 0x10, 0x80, 0x02, 0x18, + 0x20, 0xc3, 0x0e, 0x18, 0x21, 0x42, 0x04, 0x28, + 0x40, 0x8d, 0x88, 0x19, 0x93, 0x03, 0x22, 0x60, + 0x2c, 0x68, 0x05, 0x85, 0x00, 0xa0, 0xa0, 0x1c, + 0x1c, 0x01, 0x81, 0x80, + // 'x' (0x78) 17x15, offset 2921-2953, at +2/-14 + // in regular row-major format + 0x7c, 0x1f, 0x18, 0x03, 0x06, 0x03, 0x01, 0x83, + 0x00, 0x63, 0x00, 0x1b, 0x00, 0x07, 0x00, 0x03, + 0x80, 0x03, 0x60, 0x03, 0x18, 0x03, 0x06, 0x03, + 0x01, 0x83, 0x00, 0x61, 0x00, 0x33, 0xf0, 0x7e, + // 'y' (0x79) 17x22, offset 2953-3000, at +2/-14 + // in regular row-major format + 0xfc, 0x1f, 0x90, 0x01, 0x8c, 0x00, 0x86, 0x00, + 0xc1, 0x80, 0x40, 0xc0, 0x60, 0x20, 0x20, 0x18, + 0x30, 0x04, 0x10, 0x03, 0x08, 0x00, 0x8c, 0x00, + 0x64, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x07, 0x00, + 0x01, 0x00, 0x01, 0x80, 0x00, 0x80, 0x00, 0xc0, + 0x00, 0x60, 0x00, 0x20, 0x07, 0xfe, 0x00, + // 'z' (0x7a) 13x15, offset 3000-3025, at +4/-14 + // in regular row-major format + 0xff, 0xf4, 0x01, 0x20, 0x09, 0x00, 0x80, 0x08, + 0x00, 0x80, 0x08, 0x00, 0xc0, 0x04, 0x00, 0x40, + 0x04, 0x00, 0x40, 0x14, 0x00, 0xa0, 0x07, 0xff, + 0xe0, + // '{' (0x7b) 8x25, offset 3025-3050, at +6/-20 + // in regular row-major format + 0x07, 0x0c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x30, 0xc0, 0x30, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0c, + 0x07, + // '|' (0x7c) 1x25, offset 3050-3054, at +10/-20 + // in regular row-major format + 0xff, 0xff, 0xff, 0x80, + // '}' (0x7d) 8x25, offset 3054-3079, at +7/-20 + // in regular row-major format + 0xe0, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x08, 0x07, 0x0c, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x30, + 0xe0, +}; + + +static const uint8_t FreeMono24pt7b_generic[] = { + // ' ' (0x20) 0x0, offset 0-0, at +0/+1 + // in regular row-major format + // '!' (0x21) 5x30, offset 0-19, at +11/-28 + // in regular row-major format + 0x73, 0x9c, 0xe7, 0x39, 0xce, 0x73, 0x9c, 0xe7, + 0x10, 0x84, 0x21, 0x08, 0x00, 0x00, 0x00, 0x03, + 0xbf, 0xff, 0xb8, + // '"' (0x22) 16x14, offset 19-47, at +6/-28 + // in regular row-major format + 0xfe, 0x7f, 0x7c, 0x3e, 0x7c, 0x3e, 0x7c, 0x3e, + 0x7c, 0x3e, 0x7c, 0x3e, 0x7c, 0x3e, 0x7c, 0x3e, + 0x3c, 0x3e, 0x38, 0x1c, 0x38, 0x1c, 0x38, 0x1c, + 0x38, 0x1c, 0x38, 0x1c, + // '#' (0x23) 19x32, offset 47-123, at +4/-29 + // in regular row-major format + 0x01, 0x86, 0x00, 0x30, 0xc0, 0x06, 0x18, 0x00, + 0xc3, 0x00, 0x18, 0x60, 0x03, 0x0c, 0x00, 0x61, + 0x80, 0x0c, 0x70, 0x01, 0x8c, 0x00, 0x61, 0x80, + 0x0c, 0x30, 0x3f, 0xff, 0xf7, 0xff, 0xfe, 0x06, + 0x18, 0x00, 0xc3, 0x00, 0x18, 0x60, 0x03, 0x0c, + 0x00, 0x61, 0x80, 0x0c, 0x30, 0x7f, 0xff, 0xef, + 0xff, 0xfc, 0x06, 0x18, 0x00, 0xc7, 0x00, 0x38, + 0xc0, 0x06, 0x18, 0x00, 0xc3, 0x00, 0x18, 0x60, + 0x03, 0x0c, 0x00, 0x61, 0x80, 0x0c, 0x30, 0x01, + 0x86, 0x00, 0x30, 0xc0, + // '$' (0x24) 18x33, offset 123-198, at +5/-29 + // in regular row-major format + 0x00, 0xc0, 0x00, 0x30, 0x00, 0x0c, 0x00, 0x0f, + 0xc0, 0x0f, 0xfd, 0x87, 0x03, 0xe3, 0x80, 0x39, + 0xc0, 0x06, 0x60, 0x01, 0x98, 0x00, 0x06, 0x00, + 0x01, 0xc0, 0x00, 0x38, 0x00, 0x07, 0xc0, 0x00, + 0x7f, 0x80, 0x03, 0xf8, 0x00, 0x0f, 0x80, 0x00, + 0x60, 0x00, 0x1c, 0x00, 0x03, 0x80, 0x00, 0xf0, + 0x00, 0x3c, 0x00, 0x1f, 0x80, 0x0e, 0xfc, 0x0f, + 0x37, 0xff, 0x80, 0x7f, 0x80, 0x03, 0x00, 0x00, + 0xc0, 0x00, 0x30, 0x00, 0x0c, 0x00, 0x03, 0x00, + 0x00, 0xc0, 0x00, + // '%' (0x25) 20x29, offset 198-271, at +4/-27 + // in regular row-major format + 0x07, 0x80, 0x01, 0xfe, 0x00, 0x38, 0x70, 0x03, + 0x03, 0x00, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, + 0x18, 0x06, 0x01, 0x80, 0x30, 0x30, 0x03, 0x87, + 0x00, 0x1f, 0xe0, 0x30, 0x78, 0x1f, 0x00, 0x1f, + 0x80, 0x0f, 0xc0, 0x07, 0xe0, 0x03, 0xf0, 0x00, + 0xf8, 0x00, 0x0c, 0x01, 0xe0, 0x00, 0x7f, 0x80, + 0x0e, 0x1c, 0x00, 0xc0, 0xc0, 0x18, 0x06, 0x01, + 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x0c, + 0x0e, 0x00, 0xe1, 0xc0, 0x07, 0xf8, 0x00, 0x1e, + 0x00, + // '&' (0x26) 18x25, offset 271-328, at +5/-23 + // in regular row-major format + 0x03, 0xec, 0x01, 0xff, 0x00, 0xe1, 0x00, 0x70, + 0x00, 0x18, 0x00, 0x06, 0x00, 0x01, 0x80, 0x00, + 0x30, 0x00, 0x0c, 0x00, 0x01, 0x80, 0x00, 0x60, + 0x00, 0x7c, 0x00, 0x3b, 0x83, 0xd8, 0x60, 0xfe, + 0x0c, 0x33, 0x03, 0x98, 0xc0, 0x66, 0x30, 0x0d, + 0x8c, 0x03, 0xc3, 0x00, 0x70, 0x60, 0x1c, 0x1c, + 0x0f, 0x03, 0x87, 0x7c, 0x7f, 0x9f, 0x07, 0x80, + 0x00, + // ''' (0x27) 7x14, offset 328-341, at +11/-28 + // in regular row-major format + 0xfe, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x3c, + 0x70, 0xe1, 0xc3, 0x87, 0x00, + // '(' (0x28) 7x34, offset 341-371, at +14/-27 + // in regular row-major format + 0x06, 0x1c, 0x30, 0xe1, 0x87, 0x0e, 0x18, 0x70, + 0xe1, 0xc3, 0x0e, 0x1c, 0x38, 0x70, 0xe1, 0xc3, + 0x87, 0x0e, 0x0c, 0x1c, 0x38, 0x70, 0x60, 0xe1, + 0xc1, 0x83, 0x83, 0x06, 0x06, 0x04, + // ')' (0x29) 7x34, offset 371-401, at +8/-27 + // in regular row-major format + 0xc1, 0xc1, 0x83, 0x83, 0x07, 0x0e, 0x0c, 0x1c, + 0x38, 0x70, 0xe0, 0xe1, 0xc3, 0x87, 0x0e, 0x1c, + 0x38, 0x70, 0xe1, 0x87, 0x0e, 0x1c, 0x30, 0x61, + 0xc3, 0x0e, 0x18, 0x70, 0xc1, 0x00, + // '*' (0x2a) 18x16, offset 401-437, at +5/-27 + // in regular row-major format + 0x00, 0xc0, 0x00, 0x30, 0x00, 0x0c, 0x00, 0x03, + 0x00, 0x00, 0xc0, 0x10, 0x30, 0x3f, 0x8c, 0x7c, + 0xff, 0xfc, 0x07, 0xf8, 0x00, 0x78, 0x00, 0x1f, + 0x00, 0x0c, 0xc0, 0x06, 0x18, 0x03, 0x87, 0x00, + 0xc0, 0xc0, 0x60, 0x18, + // '+' (0x2b) 20x22, offset 437-492, at +4/-23 + // in regular row-major format + 0x00, 0x60, 0x00, 0x06, 0x00, 0x00, 0x60, 0x00, + 0x06, 0x00, 0x00, 0x60, 0x00, 0x06, 0x00, 0x00, + 0x60, 0x00, 0x06, 0x00, 0x00, 0x60, 0x00, 0x06, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x60, + 0x00, 0x06, 0x00, 0x00, 0x60, 0x00, 0x06, 0x00, + 0x00, 0x60, 0x00, 0x06, 0x00, 0x00, 0x60, 0x00, + 0x06, 0x00, 0x00, 0x60, 0x00, 0x06, 0x00, + // ',' (0x2c) 9x14, offset 492-508, at +6/-6 + // in regular row-major format + 0x1f, 0x8f, 0x87, 0xc7, 0xc3, 0xe1, 0xe1, 0xf0, + 0xf0, 0x78, 0x38, 0x3c, 0x1c, 0x0e, 0x06, 0x00, + // '-' (0x2d) 22x2, offset 508-514, at +3/-13 + // in regular row-major format + 0x7f, 0xff, 0xfd, 0xff, 0xff, 0xf0, + // '.' (0x2e) 7x6, offset 514-520, at +11/-4 + // in regular row-major format + 0x7d, 0xff, 0xff, 0xff, 0xef, 0x80, + // '/' (0x2f) 18x35, offset 520-599, at +5/-30 + // in regular row-major format + 0x00, 0x00, 0xc0, 0x00, 0x70, 0x00, 0x18, 0x00, + 0x06, 0x00, 0x03, 0x00, 0x00, 0xc0, 0x00, 0x60, + 0x00, 0x18, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x01, + 0x80, 0x00, 0x60, 0x00, 0x30, 0x00, 0x0c, 0x00, + 0x06, 0x00, 0x01, 0x80, 0x00, 0xc0, 0x00, 0x30, + 0x00, 0x18, 0x00, 0x06, 0x00, 0x03, 0x80, 0x00, + 0xc0, 0x00, 0x70, 0x00, 0x18, 0x00, 0x0e, 0x00, + 0x03, 0x00, 0x01, 0xc0, 0x00, 0x60, 0x00, 0x38, + 0x00, 0x0c, 0x00, 0x07, 0x00, 0x01, 0x80, 0x00, + 0x60, 0x00, 0x30, 0x00, 0x0c, 0x00, 0x00, + // '0' (0x30) 18x30, offset 599-667, at +5/-28 + // in regular row-major format + 0x03, 0xf0, 0x03, 0xff, 0x01, 0xe1, 0xe0, 0xe0, + 0x18, 0x30, 0x03, 0x1c, 0x00, 0xe6, 0x00, 0x19, + 0x80, 0x06, 0xe0, 0x01, 0xf0, 0x00, 0x3c, 0x00, + 0x0f, 0x00, 0x03, 0xc0, 0x00, 0xf0, 0x00, 0x3c, + 0x00, 0x0f, 0x00, 0x03, 0xc0, 0x00, 0xf0, 0x00, + 0x3c, 0x00, 0x0f, 0x00, 0x03, 0xc0, 0x00, 0xf8, + 0x00, 0x76, 0x00, 0x19, 0x80, 0x06, 0x70, 0x03, + 0x8c, 0x00, 0xc3, 0x80, 0x60, 0x78, 0x78, 0x0f, + 0xfc, 0x00, 0xfc, 0x00, + // '1' (0x31) 16x29, offset 667-725, at +6/-28 + // in regular row-major format + 0x03, 0x80, 0x07, 0x80, 0x0f, 0x80, 0x1d, 0x80, + 0x39, 0x80, 0x71, 0x80, 0xe1, 0x80, 0xc1, 0x80, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0xff, 0xff, + 0xff, 0xff, + // '2' (0x32) 18x29, offset 725-791, at +5/-28 + // in regular row-major format + 0x03, 0xf0, 0x03, 0xff, 0x01, 0xc0, 0xe0, 0xc0, + 0x1c, 0x60, 0x03, 0xb8, 0x00, 0x6c, 0x00, 0x0f, + 0x00, 0x03, 0x00, 0x00, 0xc0, 0x00, 0x30, 0x00, + 0x18, 0x00, 0x06, 0x00, 0x03, 0x00, 0x01, 0x80, + 0x00, 0xc0, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, + 0x00, 0x0c, 0x00, 0x06, 0x00, 0x03, 0x00, 0x01, + 0x80, 0x00, 0xc0, 0x00, 0x60, 0x00, 0x30, 0x00, + 0xd0, 0x00, 0x38, 0x00, 0x0f, 0xff, 0xff, 0xff, + 0xff, 0xc0, + // '3' (0x33) 19x30, offset 791-863, at +5/-28 + // in regular row-major format + 0x03, 0xf8, 0x01, 0xff, 0xc0, 0x70, 0x3c, 0x18, + 0x01, 0xc6, 0x00, 0x18, 0x00, 0x01, 0x80, 0x00, + 0x30, 0x00, 0x06, 0x00, 0x00, 0xc0, 0x00, 0x18, + 0x00, 0x06, 0x00, 0x01, 0xc0, 0x00, 0x70, 0x01, + 0xfc, 0x00, 0x3f, 0x00, 0x00, 0x78, 0x00, 0x03, + 0x80, 0x00, 0x38, 0x00, 0x03, 0x00, 0x00, 0x30, + 0x00, 0x06, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x00, + 0x03, 0x00, 0x00, 0xd8, 0x00, 0x3b, 0x80, 0x0e, + 0x3e, 0x07, 0x81, 0xff, 0xe0, 0x07, 0xe0, 0x00, + // '4' (0x34) 16x28, offset 863-919, at +6/-27 + // in regular row-major format + 0x00, 0x3c, 0x00, 0x7c, 0x00, 0x6c, 0x00, 0xcc, + 0x00, 0x8c, 0x01, 0x8c, 0x03, 0x0c, 0x03, 0x0c, + 0x06, 0x0c, 0x04, 0x0c, 0x0c, 0x0c, 0x08, 0x0c, + 0x10, 0x0c, 0x30, 0x0c, 0x20, 0x0c, 0x60, 0x0c, + 0x40, 0x0c, 0x80, 0x0c, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, + 0x00, 0x0c, 0x00, 0x0c, 0x00, 0xff, 0x00, 0xff, + // '5' (0x35) 19x29, offset 919-988, at +5/-27 + // in regular row-major format + 0x3f, 0xff, 0x07, 0xff, 0xe0, 0xc0, 0x00, 0x18, + 0x00, 0x03, 0x00, 0x00, 0x60, 0x00, 0x0c, 0x00, + 0x01, 0x80, 0x00, 0x30, 0x00, 0x06, 0x00, 0x00, + 0xc7, 0xe0, 0x1f, 0xff, 0x03, 0x80, 0x70, 0x00, + 0x03, 0x00, 0x00, 0x30, 0x00, 0x06, 0x00, 0x00, + 0x60, 0x00, 0x0c, 0x00, 0x01, 0x80, 0x00, 0x30, + 0x00, 0x06, 0x00, 0x00, 0xc0, 0x00, 0x30, 0x00, + 0x06, 0xc0, 0x01, 0xdc, 0x00, 0x71, 0xf0, 0x3c, + 0x0f, 0xff, 0x00, 0x3f, 0x00, + // '6' (0x36) 18x30, offset 988-1056, at +6/-28 + // in regular row-major format + 0x00, 0x3f, 0x80, 0x3f, 0xf0, 0x3e, 0x00, 0x1e, + 0x00, 0x0e, 0x00, 0x07, 0x00, 0x03, 0x80, 0x00, + 0xc0, 0x00, 0x70, 0x00, 0x18, 0x00, 0x06, 0x00, + 0x03, 0x80, 0x00, 0xc1, 0xf8, 0x31, 0xff, 0x0c, + 0xf0, 0xf3, 0x70, 0x0c, 0xd8, 0x01, 0xbc, 0x00, + 0x6e, 0x00, 0x0f, 0x80, 0x03, 0xc0, 0x00, 0xd8, + 0x00, 0x36, 0x00, 0x0d, 0x80, 0x03, 0x30, 0x01, + 0x8e, 0x00, 0x61, 0xc0, 0x30, 0x38, 0x38, 0x07, + 0xfc, 0x00, 0x7c, 0x00, + // '7' (0x37) 18x28, offset 1056-1119, at +5/-27 + // in regular row-major format + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x0f, 0x00, + 0x03, 0xc0, 0x01, 0xc0, 0x00, 0x60, 0x00, 0x18, + 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0xc0, 0x00, + 0x30, 0x00, 0x18, 0x00, 0x06, 0x00, 0x01, 0x80, + 0x00, 0xc0, 0x00, 0x30, 0x00, 0x0c, 0x00, 0x06, + 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, 0x30, 0x00, + 0x0c, 0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0x60, + 0x00, 0x18, 0x00, 0x0c, 0x00, 0x03, 0x00, + // '8' (0x38) 18x30, offset 1119-1187, at +5/-28 + // in regular row-major format + 0x03, 0xf0, 0x03, 0xff, 0x03, 0xc0, 0xf1, 0xc0, + 0x0e, 0x60, 0x01, 0xb8, 0x00, 0x7c, 0x00, 0x0f, + 0x00, 0x03, 0xc0, 0x00, 0xf0, 0x00, 0x36, 0x00, + 0x18, 0xc0, 0x0c, 0x1c, 0x0e, 0x03, 0xff, 0x00, + 0xff, 0xc0, 0x70, 0x38, 0x30, 0x03, 0x18, 0x00, + 0x66, 0x00, 0x1b, 0x00, 0x03, 0xc0, 0x00, 0xf0, + 0x00, 0x3c, 0x00, 0x0f, 0x00, 0x03, 0x60, 0x01, + 0x98, 0x00, 0xe3, 0x00, 0x70, 0x70, 0x38, 0x0f, + 0xfc, 0x00, 0xfc, 0x00, + // '9' (0x39) 18x30, offset 1187-1255, at +6/-28 + // in regular row-major format + 0x07, 0xe0, 0x03, 0xfe, 0x01, 0xc1, 0xc0, 0xc0, + 0x38, 0x60, 0x07, 0x18, 0x00, 0xcc, 0x00, 0x1b, + 0x00, 0x06, 0xc0, 0x01, 0xb0, 0x00, 0x3c, 0x00, + 0x1f, 0x00, 0x07, 0x60, 0x03, 0xd8, 0x01, 0xb3, + 0x00, 0xcc, 0xf0, 0xf3, 0x0f, 0xf8, 0xc1, 0xf8, + 0x30, 0x00, 0x1c, 0x00, 0x06, 0x00, 0x01, 0x80, + 0x00, 0xe0, 0x00, 0x30, 0x00, 0x1c, 0x00, 0x0e, + 0x00, 0x07, 0x00, 0x07, 0x80, 0x07, 0xc0, 0xff, + 0xc0, 0x1f, 0xc0, 0x00, + // ':' (0x3a) 7x21, offset 1255-1274, at +11/-19 + // in regular row-major format + 0x7d, 0xff, 0xff, 0xff, 0xef, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0xff, 0xff, + 0xff, 0xf7, 0xc0, + // ';' (0x3b) 10x27, offset 1274-1308, at +7/-19 + // in regular row-major format + 0x0f, 0x87, 0xf1, 0xfc, 0x7f, 0x1f, 0xc3, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0xf1, 0xf8, 0x7c, 0x3f, 0x0f, 0x83, 0xe0, + 0xf0, 0x7c, 0x1e, 0x07, 0x81, 0xc0, 0xf0, 0x38, + 0x04, 0x00, + // '<' (0x3c) 22x22, offset 1308-1369, at +3/-23 + // in regular row-major format + 0x00, 0x00, 0x18, 0x00, 0x01, 0xe0, 0x00, 0x1e, + 0x00, 0x00, 0xe0, 0x00, 0x0f, 0x00, 0x00, 0xf0, + 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x07, 0x00, + 0x00, 0x78, 0x00, 0x07, 0x80, 0x00, 0x0f, 0x00, + 0x00, 0x1e, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x1e, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x20, + // '=' (0x3d) 24x9, offset 1369-1396, at +2/-17 + // in regular row-major format + 0x7f, 0xff, 0xff, 0x7f, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, + 0x7f, 0xff, 0xff, + // '>' (0x3e) 21x22, offset 1396-1454, at +4/-23 + // in regular row-major format + 0xc0, 0x00, 0x07, 0x80, 0x00, 0x0f, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x38, 0x00, 0x00, 0xf0, 0x00, + 0x01, 0xe0, 0x00, 0x03, 0xc0, 0x00, 0x07, 0x80, + 0x00, 0x0e, 0x00, 0x00, 0x3c, 0x00, 0x01, 0xe0, + 0x00, 0x3c, 0x00, 0x07, 0x80, 0x00, 0xf0, 0x00, + 0x1e, 0x00, 0x01, 0xe0, 0x00, 0x3c, 0x00, 0x07, + 0x80, 0x00, 0xf0, 0x00, 0x0e, 0x00, 0x00, 0x60, + 0x00, 0x00, + // '?' (0x3f) 17x28, offset 1454-1514, at +6/-26 + // in regular row-major format + 0x07, 0xf0, 0x1f, 0xfe, 0x3e, 0x07, 0x98, 0x00, + 0xec, 0x00, 0x36, 0x00, 0x0f, 0x00, 0x06, 0x00, + 0x03, 0x00, 0x01, 0x80, 0x01, 0xc0, 0x00, 0xc0, + 0x01, 0xc0, 0x03, 0xc0, 0x07, 0xc0, 0x07, 0x00, + 0x03, 0x00, 0x01, 0x80, 0x00, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x80, 0x07, 0xe0, 0x03, 0xf0, 0x01, + 0xf8, 0x00, 0x78, 0x00, + // '@' (0x40) 18x32, offset 1514-1586, at +5/-28 + // in regular row-major format + 0x03, 0xf0, 0x03, 0xff, 0x01, 0xe0, 0xe0, 0xe0, + 0x1c, 0x30, 0x03, 0x1c, 0x00, 0x66, 0x00, 0x19, + 0x80, 0x06, 0xc0, 0x01, 0xb0, 0x07, 0xec, 0x07, + 0xfb, 0x03, 0xc6, 0xc1, 0xc1, 0xb0, 0xe0, 0x6c, + 0x30, 0x1b, 0x0c, 0x06, 0xc3, 0x01, 0xb0, 0xc0, + 0x6c, 0x18, 0x1b, 0x07, 0x86, 0xc0, 0xff, 0xf0, + 0x0f, 0xfc, 0x00, 0x03, 0x00, 0x00, 0x60, 0x00, + 0x18, 0x00, 0x07, 0x00, 0x00, 0xc0, 0x00, 0x38, + 0x00, 0x07, 0x80, 0xc0, 0xff, 0xf0, 0x0f, 0xe0, + // 'A' (0x41) 28x26, offset 1586-1677, at +0/-25 + // in regular row-major format + 0x07, 0xff, 0x00, 0x00, 0x7f, 0xf0, 0x00, 0x00, + 0x1b, 0x00, 0x00, 0x01, 0x98, 0x00, 0x00, 0x11, + 0x80, 0x00, 0x03, 0x0c, 0x00, 0x00, 0x30, 0xc0, + 0x00, 0x06, 0x0c, 0x00, 0x00, 0x60, 0x60, 0x00, + 0x06, 0x06, 0x00, 0x00, 0xc0, 0x30, 0x00, 0x0c, + 0x03, 0x00, 0x00, 0x80, 0x30, 0x00, 0x18, 0x01, + 0x80, 0x01, 0x80, 0x18, 0x00, 0x3f, 0xff, 0x80, + 0x03, 0xff, 0xfc, 0x00, 0x20, 0x00, 0xc0, 0x06, + 0x00, 0x06, 0x00, 0x60, 0x00, 0x60, 0x0c, 0x00, + 0x06, 0x00, 0xc0, 0x00, 0x30, 0x0c, 0x00, 0x03, + 0x01, 0x80, 0x00, 0x18, 0x7f, 0xc0, 0x3f, 0xf7, + 0xfc, 0x03, 0xff, + // 'B' (0x42) 22x26, offset 1677-1749, at +3/-25 + // in regular row-major format + 0xff, 0xff, 0x03, 0xff, 0xff, 0x01, 0x80, 0x0e, + 0x06, 0x00, 0x1c, 0x18, 0x00, 0x38, 0x60, 0x00, + 0x61, 0x80, 0x01, 0x86, 0x00, 0x06, 0x18, 0x00, + 0x38, 0x60, 0x01, 0xc1, 0x80, 0x1e, 0x07, 0xff, + 0xe0, 0x1f, 0xff, 0xc0, 0x60, 0x03, 0xc1, 0x80, + 0x03, 0x86, 0x00, 0x06, 0x18, 0x00, 0x1c, 0x60, + 0x00, 0x31, 0x80, 0x00, 0xc6, 0x00, 0x03, 0x18, + 0x00, 0x0c, 0x60, 0x00, 0x61, 0x80, 0x03, 0x86, + 0x00, 0x1c, 0xff, 0xff, 0xe3, 0xff, 0xfe, 0x00, + // 'C' (0x43) 22x28, offset 1749-1826, at +3/-26 + // in regular row-major format + 0x00, 0xfc, 0x00, 0x0f, 0xfe, 0x60, 0xf0, 0x3d, + 0x87, 0x00, 0x3e, 0x38, 0x00, 0x38, 0xc0, 0x00, + 0xe7, 0x00, 0x01, 0x98, 0x00, 0x06, 0x60, 0x00, + 0x03, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x30, 0x00, + 0x00, 0xc0, 0x00, 0x03, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x30, 0x00, 0x00, 0xc0, 0x00, 0x03, 0x00, + 0x00, 0x0c, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, + 0x00, 0x01, 0xc0, 0x00, 0x03, 0x80, 0x00, 0xc7, + 0x00, 0x06, 0x0e, 0x00, 0x70, 0x1e, 0x07, 0x80, + 0x3f, 0xfc, 0x00, 0x1f, 0x80, + // 'D' (0x44) 22x26, offset 1826-1898, at +3/-25 + // in regular row-major format + 0xff, 0xfe, 0x03, 0xff, 0xfe, 0x03, 0x00, 0x3c, + 0x0c, 0x00, 0x38, 0x30, 0x00, 0x70, 0xc0, 0x00, + 0xc3, 0x00, 0x03, 0x8c, 0x00, 0x06, 0x30, 0x00, + 0x1c, 0xc0, 0x00, 0x33, 0x00, 0x00, 0xcc, 0x00, + 0x03, 0x30, 0x00, 0x0c, 0xc0, 0x00, 0x33, 0x00, + 0x00, 0xcc, 0x00, 0x03, 0x30, 0x00, 0x0c, 0xc0, + 0x00, 0x33, 0x00, 0x01, 0x8c, 0x00, 0x06, 0x30, + 0x00, 0x30, 0xc0, 0x01, 0xc3, 0x00, 0x0e, 0x0c, + 0x00, 0xf0, 0xff, 0xff, 0x83, 0xff, 0xf8, 0x00, + // 'E' (0x45) 22x26, offset 1898-1970, at +3/-25 + // in regular row-major format + 0xff, 0xff, 0xfb, 0xff, 0xff, 0xe1, 0x80, 0x01, + 0x86, 0x00, 0x06, 0x18, 0x00, 0x18, 0x60, 0x00, + 0x61, 0x80, 0x01, 0x86, 0x00, 0x00, 0x18, 0x0c, + 0x00, 0x60, 0x30, 0x01, 0x80, 0xc0, 0x07, 0xff, + 0x00, 0x1f, 0xfc, 0x00, 0x60, 0x30, 0x01, 0x80, + 0xc0, 0x06, 0x03, 0x00, 0x18, 0x00, 0x00, 0x60, + 0x00, 0x01, 0x80, 0x00, 0xc6, 0x00, 0x03, 0x18, + 0x00, 0x0c, 0x60, 0x00, 0x31, 0x80, 0x00, 0xc6, + 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + // 'F' (0x46) 22x26, offset 1970-2042, at +3/-25 + // in regular row-major format + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x80, 0x00, + 0xc6, 0x00, 0x03, 0x18, 0x00, 0x0c, 0x60, 0x00, + 0x31, 0x80, 0x00, 0xc6, 0x00, 0x00, 0x18, 0x0c, + 0x00, 0x60, 0x30, 0x01, 0x80, 0xc0, 0x07, 0xff, + 0x00, 0x1f, 0xfc, 0x00, 0x60, 0x30, 0x01, 0x80, + 0xc0, 0x06, 0x03, 0x00, 0x18, 0x00, 0x00, 0x60, + 0x00, 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x60, 0x00, 0x01, 0x80, 0x00, 0x06, + 0x00, 0x00, 0xff, 0xf0, 0x03, 0xff, 0xc0, 0x00, + // 'G' (0x47) 23x28, offset 2042-2123, at +3/-26 + // in regular row-major format + 0x00, 0xff, 0x00, 0x07, 0xff, 0x98, 0x1e, 0x03, + 0xf0, 0x70, 0x01, 0xe1, 0x80, 0x01, 0xc6, 0x00, + 0x01, 0x9c, 0x00, 0x03, 0x30, 0x00, 0x00, 0x60, + 0x00, 0x01, 0xc0, 0x00, 0x03, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x60, 0x03, 0xff, 0xc0, 0x07, + 0xff, 0x80, 0x00, 0x1b, 0x00, 0x00, 0x37, 0x00, + 0x00, 0x66, 0x00, 0x00, 0xcc, 0x00, 0x01, 0x8c, + 0x00, 0x03, 0x1c, 0x00, 0x06, 0x1e, 0x00, 0x0c, + 0x0f, 0x00, 0xf8, 0x0f, 0xff, 0xc0, 0x03, 0xfc, + 0x00, + // 'H' (0x48) 23x26, offset 2123-2198, at +3/-25 + // in regular row-major format + 0x7f, 0x01, 0xfc, 0xfe, 0x03, 0xf8, 0x60, 0x00, + 0xc0, 0xc0, 0x01, 0x81, 0x80, 0x03, 0x03, 0x00, + 0x06, 0x06, 0x00, 0x0c, 0x0c, 0x00, 0x18, 0x18, + 0x00, 0x30, 0x30, 0x00, 0x60, 0x60, 0x00, 0xc0, + 0xff, 0xff, 0x81, 0xff, 0xff, 0x03, 0x00, 0x06, + 0x06, 0x00, 0x0c, 0x0c, 0x00, 0x18, 0x18, 0x00, + 0x30, 0x30, 0x00, 0x60, 0x60, 0x00, 0xc0, 0xc0, + 0x01, 0x81, 0x80, 0x03, 0x03, 0x00, 0x06, 0x06, + 0x00, 0x0c, 0x0c, 0x00, 0x18, 0xff, 0x01, 0xff, + 0xfe, 0x03, 0xfc, + // 'I' (0x49) 16x26, offset 2198-2250, at +6/-25 + // in regular row-major format + 0xff, 0xff, 0xff, 0xff, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, + 0xff, 0xff, 0xff, 0xff, + // 'J' (0x4a) 23x27, offset 2250-2328, at +4/-25 + // in regular row-major format + 0x00, 0xff, 0xfe, 0x01, 0xff, 0xfc, 0x00, 0x03, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x0c, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x30, 0x00, 0x00, 0x60, 0x00, + 0x00, 0xc0, 0x00, 0x01, 0x80, 0x00, 0x03, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x30, 0x60, 0x00, 0x60, 0xc0, 0x00, + 0xc1, 0x80, 0x01, 0x83, 0x00, 0x03, 0x06, 0x00, + 0x06, 0x0c, 0x00, 0x0c, 0x18, 0x00, 0x30, 0x38, + 0x00, 0x60, 0x38, 0x01, 0x80, 0x3c, 0x0e, 0x00, + 0x3f, 0xf8, 0x00, 0x0f, 0xc0, 0x00, + // 'K' (0x4b) 24x26, offset 2328-2406, at +3/-25 + // in regular row-major format + 0xff, 0x81, 0xfe, 0xff, 0x81, 0xfe, 0x18, 0x00, + 0x30, 0x18, 0x00, 0xe0, 0x18, 0x01, 0xc0, 0x18, + 0x03, 0x80, 0x18, 0x07, 0x00, 0x18, 0x0e, 0x00, + 0x18, 0x18, 0x00, 0x18, 0x70, 0x00, 0x18, 0xe0, + 0x00, 0x19, 0xe0, 0x00, 0x1b, 0xf8, 0x00, 0x1f, + 0x1c, 0x00, 0x1c, 0x06, 0x00, 0x18, 0x03, 0x00, + 0x18, 0x03, 0x80, 0x18, 0x01, 0x80, 0x18, 0x00, + 0xc0, 0x18, 0x00, 0xc0, 0x18, 0x00, 0x60, 0x18, + 0x00, 0x60, 0x18, 0x00, 0x70, 0x18, 0x00, 0x30, + 0xff, 0x80, 0x3f, 0xff, 0x80, 0x1f, + // 'L' (0x4c) 21x26, offset 2406-2475, at +4/-25 + // in regular row-major format + 0xff, 0xf0, 0x07, 0xff, 0x80, 0x01, 0x80, 0x00, + 0x0c, 0x00, 0x00, 0x60, 0x00, 0x03, 0x00, 0x00, + 0x18, 0x00, 0x00, 0xc0, 0x00, 0x06, 0x00, 0x00, + 0x30, 0x00, 0x01, 0x80, 0x00, 0x0c, 0x00, 0x00, + 0x60, 0x00, 0x03, 0x00, 0x00, 0x18, 0x00, 0x00, + 0xc0, 0x00, 0x06, 0x00, 0x18, 0x30, 0x00, 0xc1, + 0x80, 0x06, 0x0c, 0x00, 0x30, 0x60, 0x01, 0x83, + 0x00, 0x0c, 0x18, 0x00, 0x60, 0xc0, 0x03, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xc0, + // 'M' (0x4d) 26x26, offset 2475-2560, at +1/-25 + // in regular row-major format + 0xfc, 0x00, 0x0f, 0xff, 0x00, 0x03, 0xf3, 0x60, + 0x01, 0xb0, 0xd8, 0x00, 0x6c, 0x33, 0x00, 0x33, + 0x0c, 0xc0, 0x0c, 0xc3, 0x38, 0x07, 0x30, 0xc6, + 0x01, 0x8c, 0x31, 0xc0, 0xe3, 0x0c, 0x30, 0x30, + 0xc3, 0x0c, 0x0c, 0x30, 0xc1, 0x86, 0x0c, 0x30, + 0x61, 0x83, 0x0c, 0x0c, 0xc0, 0xc3, 0x03, 0x30, + 0x30, 0xc0, 0x78, 0x0c, 0x30, 0x1e, 0x03, 0x0c, + 0x03, 0x00, 0xc3, 0x00, 0x00, 0x30, 0xc0, 0x00, + 0x0c, 0x30, 0x00, 0x03, 0x0c, 0x00, 0x00, 0xc3, + 0x00, 0x00, 0x30, 0xc0, 0x00, 0x0c, 0xff, 0x00, + 0x3f, 0xff, 0xc0, 0x0f, 0xf0, + // 'N' (0x4e) 24x26, offset 2560-2638, at +2/-25 + // in regular row-major format + 0xfc, 0x00, 0xff, 0xfc, 0x00, 0xff, 0x1e, 0x00, + 0x0c, 0x1f, 0x00, 0x0c, 0x1b, 0x00, 0x0c, 0x19, + 0x80, 0x0c, 0x19, 0xc0, 0x0c, 0x18, 0xc0, 0x0c, + 0x18, 0x60, 0x0c, 0x18, 0x60, 0x0c, 0x18, 0x30, + 0x0c, 0x18, 0x38, 0x0c, 0x18, 0x18, 0x0c, 0x18, + 0x0c, 0x0c, 0x18, 0x0e, 0x0c, 0x18, 0x06, 0x0c, + 0x18, 0x03, 0x0c, 0x18, 0x03, 0x0c, 0x18, 0x01, + 0x8c, 0x18, 0x01, 0xcc, 0x18, 0x00, 0xcc, 0x18, + 0x00, 0x6c, 0x18, 0x00, 0x7c, 0x18, 0x00, 0x3c, + 0x7f, 0x80, 0x1c, 0x7f, 0x80, 0x1c, + // 'O' (0x4f) 24x28, offset 2638-2722, at +2/-26 + // in regular row-major format + 0x00, 0x7e, 0x00, 0x01, 0xff, 0xc0, 0x07, 0x81, + 0xe0, 0x0e, 0x00, 0x70, 0x1c, 0x00, 0x38, 0x38, + 0x00, 0x1c, 0x30, 0x00, 0x0c, 0x70, 0x00, 0x0e, + 0x60, 0x00, 0x06, 0x60, 0x00, 0x06, 0xc0, 0x00, + 0x03, 0xc0, 0x00, 0x03, 0xc0, 0x00, 0x03, 0xc0, + 0x00, 0x03, 0xc0, 0x00, 0x03, 0xc0, 0x00, 0x03, + 0xc0, 0x00, 0x03, 0xc0, 0x00, 0x03, 0x60, 0x00, + 0x06, 0x60, 0x00, 0x06, 0x70, 0x00, 0x0e, 0x30, + 0x00, 0x0c, 0x38, 0x00, 0x1c, 0x1c, 0x00, 0x38, + 0x0e, 0x00, 0x70, 0x07, 0x81, 0xe0, 0x03, 0xff, + 0xc0, 0x00, 0x7e, 0x00, + // 'P' (0x50) 21x26, offset 2722-2791, at +3/-25 + // in regular row-major format + 0xff, 0xff, 0x07, 0xff, 0xfe, 0x06, 0x00, 0x78, + 0x30, 0x00, 0xe1, 0x80, 0x03, 0x0c, 0x00, 0x0c, + 0x60, 0x00, 0x63, 0x00, 0x03, 0x18, 0x00, 0x18, + 0xc0, 0x01, 0xc6, 0x00, 0x0c, 0x30, 0x00, 0xc1, + 0x80, 0x1e, 0x0f, 0xff, 0xc0, 0x7f, 0xf8, 0x03, + 0x00, 0x00, 0x18, 0x00, 0x00, 0xc0, 0x00, 0x06, + 0x00, 0x00, 0x30, 0x00, 0x01, 0x80, 0x00, 0x0c, + 0x00, 0x00, 0x60, 0x00, 0x03, 0x00, 0x00, 0xff, + 0xf0, 0x07, 0xff, 0x80, 0x00, + // 'Q' (0x51) 24x32, offset 2791-2887, at +2/-26 + // in regular row-major format + 0x00, 0x7e, 0x00, 0x01, 0xff, 0x80, 0x07, 0x81, + 0xe0, 0x0e, 0x00, 0x70, 0x1c, 0x00, 0x38, 0x38, + 0x00, 0x1c, 0x30, 0x00, 0x0c, 0x70, 0x00, 0x0e, + 0x60, 0x00, 0x06, 0x60, 0x00, 0x06, 0xc0, 0x00, + 0x03, 0xc0, 0x00, 0x03, 0xc0, 0x00, 0x03, 0xc0, + 0x00, 0x03, 0xc0, 0x00, 0x03, 0xc0, 0x00, 0x03, + 0xc0, 0x00, 0x03, 0xc0, 0x00, 0x03, 0x60, 0x00, + 0x06, 0x60, 0x00, 0x06, 0x70, 0x00, 0x0e, 0x30, + 0x00, 0x0c, 0x18, 0x00, 0x1c, 0x0c, 0x00, 0x38, + 0x06, 0x00, 0x70, 0x03, 0x81, 0xe0, 0x00, 0xff, + 0xc0, 0x00, 0x7e, 0x00, 0x00, 0xe0, 0x00, 0x03, + 0xff, 0x87, 0x07, 0xff, 0xfe, 0x07, 0x00, 0xf8, + // 'R' (0x52) 24x26, offset 2887-2965, at +3/-25 + // in regular row-major format + 0xff, 0xfe, 0x00, 0xff, 0xff, 0x80, 0x18, 0x03, + 0xc0, 0x18, 0x00, 0xe0, 0x18, 0x00, 0x60, 0x18, + 0x00, 0x30, 0x18, 0x00, 0x30, 0x18, 0x00, 0x30, + 0x18, 0x00, 0x30, 0x18, 0x00, 0x70, 0x18, 0x00, + 0x60, 0x18, 0x01, 0xc0, 0x18, 0x07, 0x80, 0x1f, + 0xff, 0x00, 0x1f, 0xfc, 0x00, 0x18, 0x0e, 0x00, + 0x18, 0x07, 0x00, 0x18, 0x03, 0x80, 0x18, 0x01, + 0xc0, 0x18, 0x00, 0xe0, 0x18, 0x00, 0x60, 0x18, + 0x00, 0x30, 0x18, 0x00, 0x30, 0x18, 0x00, 0x18, + 0xff, 0x80, 0x1f, 0xff, 0x80, 0x0f, + // 'S' (0x53) 20x28, offset 2965-3035, at +4/-26 + // in regular row-major format + 0x03, 0xf8, 0x00, 0xff, 0xe6, 0x1e, 0x07, 0xe3, + 0x80, 0x1e, 0x30, 0x00, 0xe6, 0x00, 0x06, 0x60, + 0x00, 0x66, 0x00, 0x06, 0x60, 0x00, 0x07, 0x00, + 0x00, 0x30, 0x00, 0x01, 0xc0, 0x00, 0x0f, 0xc0, + 0x00, 0x3f, 0xc0, 0x00, 0x3f, 0x80, 0x00, 0x1c, + 0x00, 0x00, 0xe0, 0x00, 0x07, 0x00, 0x00, 0x30, + 0x00, 0x03, 0xc0, 0x00, 0x3c, 0x00, 0x03, 0xe0, + 0x00, 0x7e, 0x00, 0x06, 0xf8, 0x01, 0xed, 0xe0, + 0x7c, 0xcf, 0xff, 0x00, 0x3f, 0xc0, + // 'T' (0x54) 22x26, offset 3035-3107, at +3/-25 + // in regular row-major format + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x03, 0x00, + 0xf0, 0x0c, 0x03, 0xc0, 0x30, 0x0f, 0x00, 0xc0, + 0x3c, 0x03, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x30, + 0x00, 0x00, 0xc0, 0x00, 0x03, 0x00, 0x00, 0x0c, + 0x00, 0x00, 0x30, 0x00, 0x00, 0xc0, 0x00, 0x03, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x30, 0x00, 0x00, + 0xc0, 0x00, 0x03, 0x00, 0x00, 0x0c, 0x00, 0x00, + 0x30, 0x00, 0x00, 0xc0, 0x00, 0x03, 0x00, 0x00, + 0x0c, 0x00, 0x0f, 0xff, 0xc0, 0x3f, 0xff, 0x00, + // 'U' (0x55) 23x27, offset 3107-3185, at +3/-25 + // in regular row-major format + 0xff, 0x01, 0xff, 0xfe, 0x03, 0xfc, 0xc0, 0x00, + 0x61, 0x80, 0x00, 0xc3, 0x00, 0x01, 0x86, 0x00, + 0x03, 0x0c, 0x00, 0x06, 0x18, 0x00, 0x0c, 0x30, + 0x00, 0x18, 0x60, 0x00, 0x30, 0xc0, 0x00, 0x61, + 0x80, 0x00, 0xc3, 0x00, 0x01, 0x86, 0x00, 0x03, + 0x0c, 0x00, 0x06, 0x18, 0x00, 0x0c, 0x30, 0x00, + 0x18, 0x60, 0x00, 0x30, 0xc0, 0x00, 0x61, 0x80, + 0x00, 0xc3, 0x80, 0x03, 0x83, 0x00, 0x06, 0x07, + 0x00, 0x1c, 0x07, 0x00, 0x70, 0x07, 0x83, 0xc0, + 0x07, 0xff, 0x00, 0x03, 0xf8, 0x00, + // 'V' (0x56) 28x26, offset 3185-3276, at +0/-25 + // in regular row-major format + 0x7f, 0xc0, 0x3f, 0xf7, 0xfc, 0x03, 0xff, 0x18, + 0x00, 0x01, 0x80, 0xc0, 0x00, 0x30, 0x0c, 0x00, + 0x03, 0x00, 0x60, 0x00, 0x30, 0x06, 0x00, 0x06, + 0x00, 0x60, 0x00, 0x60, 0x03, 0x00, 0x0c, 0x00, + 0x30, 0x00, 0xc0, 0x03, 0x80, 0x0c, 0x00, 0x18, + 0x01, 0x80, 0x01, 0x80, 0x18, 0x00, 0x0c, 0x03, + 0x00, 0x00, 0xc0, 0x30, 0x00, 0x0e, 0x03, 0x00, + 0x00, 0x60, 0x60, 0x00, 0x06, 0x06, 0x00, 0x00, + 0x30, 0xc0, 0x00, 0x03, 0x0c, 0x00, 0x00, 0x30, + 0x80, 0x00, 0x01, 0x98, 0x00, 0x00, 0x19, 0x80, + 0x00, 0x00, 0xf0, 0x00, 0x00, 0x0f, 0x00, 0x00, + 0x00, 0xe0, 0x00, + // 'W' (0x57) 26x26, offset 3276-3361, at +1/-25 + // in regular row-major format + 0xff, 0x80, 0x7f, 0xff, 0xe0, 0x1f, 0xf3, 0x00, + 0x00, 0x30, 0xc0, 0x00, 0x0c, 0x30, 0x00, 0x03, + 0x0c, 0x03, 0x80, 0xc3, 0x01, 0xe0, 0x30, 0x60, + 0x78, 0x0c, 0x18, 0x1f, 0x02, 0x06, 0x04, 0xc0, + 0x81, 0x83, 0x30, 0x60, 0x60, 0xcc, 0x18, 0x18, + 0x31, 0x86, 0x06, 0x18, 0x61, 0x81, 0x86, 0x18, + 0x60, 0x71, 0x87, 0x18, 0x0c, 0x40, 0xc6, 0x03, + 0x30, 0x31, 0x00, 0xcc, 0x0c, 0xc0, 0x33, 0x01, + 0xb0, 0x0d, 0x80, 0x6c, 0x03, 0x60, 0x1b, 0x00, + 0xd8, 0x06, 0xc0, 0x34, 0x00, 0xf0, 0x07, 0x00, + 0x3c, 0x01, 0xc0, 0x0e, 0x00, + // 'X' (0x58) 24x26, offset 3361-3439, at +2/-25 + // in regular row-major format + 0x7f, 0x00, 0xff, 0x7f, 0x00, 0xff, 0x18, 0x00, + 0x18, 0x0c, 0x00, 0x38, 0x0e, 0x00, 0x70, 0x07, + 0x00, 0x60, 0x03, 0x00, 0xc0, 0x01, 0x81, 0x80, + 0x01, 0xc3, 0x80, 0x00, 0xe7, 0x00, 0x00, 0x76, + 0x00, 0x00, 0x3c, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x3c, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x66, 0x00, + 0x00, 0xc3, 0x00, 0x01, 0x81, 0x80, 0x03, 0x81, + 0xc0, 0x07, 0x00, 0xe0, 0x06, 0x00, 0x60, 0x0c, + 0x00, 0x30, 0x18, 0x00, 0x18, 0x38, 0x00, 0x1c, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, + // 'Y' (0x59) 24x26, offset 3439-3517, at +2/-25 + // in regular row-major format + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x18, 0x00, + 0x18, 0x0c, 0x00, 0x30, 0x0e, 0x00, 0x70, 0x06, + 0x00, 0x60, 0x03, 0x00, 0xc0, 0x03, 0x81, 0xc0, + 0x01, 0x81, 0x80, 0x00, 0xc3, 0x00, 0x00, 0xe7, + 0x00, 0x00, 0x66, 0x00, 0x00, 0x3c, 0x00, 0x00, + 0x3c, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, + 0x07, 0xff, 0xe0, 0x07, 0xff, 0xe0, + // 'Z' (0x5a) 18x26, offset 3517-3576, at +5/-25 + // in regular row-major format + 0x7f, 0xff, 0x9f, 0xff, 0xe6, 0x00, 0x19, 0x80, + 0x0c, 0x60, 0x07, 0x18, 0x03, 0x86, 0x00, 0xc1, + 0x80, 0x70, 0x00, 0x38, 0x00, 0x0c, 0x00, 0x07, + 0x00, 0x03, 0x80, 0x00, 0xc0, 0x00, 0x60, 0x00, + 0x38, 0x00, 0x1c, 0x00, 0x06, 0x00, 0x03, 0x80, + 0x31, 0xc0, 0x0c, 0x60, 0x03, 0x30, 0x00, 0xdc, + 0x00, 0x3e, 0x00, 0x0f, 0x00, 0x03, 0xff, 0xff, + 0xff, 0xff, 0xf0, + // '[' (0x5b) 7x34, offset 3576-3606, at +13/-27 + // in regular row-major format + 0xff, 0xff, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc1, + 0x83, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0x83, + 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0x83, 0x06, + 0x0c, 0x18, 0x30, 0x60, 0xff, 0xfc, + // '\' (0x5c) 18x35, offset 3606-3685, at +5/-30 + // in regular row-major format + 0xc0, 0x00, 0x30, 0x00, 0x06, 0x00, 0x01, 0x80, + 0x00, 0x30, 0x00, 0x0c, 0x00, 0x01, 0x80, 0x00, + 0x60, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x60, + 0x00, 0x18, 0x00, 0x03, 0x00, 0x00, 0xc0, 0x00, + 0x18, 0x00, 0x06, 0x00, 0x00, 0xc0, 0x00, 0x30, + 0x00, 0x06, 0x00, 0x01, 0x80, 0x00, 0x30, 0x00, + 0x0c, 0x00, 0x03, 0x80, 0x00, 0x60, 0x00, 0x1c, + 0x00, 0x03, 0x00, 0x00, 0xe0, 0x00, 0x18, 0x00, + 0x07, 0x00, 0x00, 0xc0, 0x00, 0x30, 0x00, 0x06, + 0x00, 0x01, 0x80, 0x00, 0x30, 0x00, 0x0c, + // ']' (0x5d) 7x34, offset 3685-3715, at +8/-27 + // in regular row-major format + 0xff, 0xfc, 0x18, 0x30, 0x60, 0xc1, 0x83, 0x06, + 0x0c, 0x18, 0x30, 0x60, 0xc1, 0x83, 0x06, 0x0c, + 0x18, 0x30, 0x60, 0xc1, 0x83, 0x06, 0x0c, 0x18, + 0x30, 0x60, 0xc1, 0x83, 0xff, 0xfc, + // '^' (0x5e) 18x12, offset 3715-3742, at +5/-28 + // in regular row-major format + 0x00, 0x40, 0x00, 0x30, 0x00, 0x1e, 0x00, 0x0e, + 0xc0, 0x07, 0x38, 0x01, 0x87, 0x00, 0xc0, 0xc0, + 0x60, 0x18, 0x38, 0x03, 0x1c, 0x00, 0xe6, 0x00, + 0x1f, 0x00, 0x03, + // '_' (0x5f) 28x2, offset 3742-3749, at +0/+5 + // in regular row-major format + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + // '`' (0x60) 8x7, offset 3749-3756, at +7/-29 + // in regular row-major format + 0xc0, 0xe0, 0x70, 0x3c, 0x0e, 0x07, 0x03, + // 'a' (0x61) 22x22, offset 3756-3817, at +3/-20 + // in regular row-major format + 0x01, 0xfc, 0x00, 0x7f, 0xfc, 0x01, 0xc0, 0x3c, + 0x00, 0x00, 0x30, 0x00, 0x00, 0x60, 0x00, 0x01, + 0x80, 0x00, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x60, 0x0f, 0xf9, 0x81, 0xff, 0xfe, 0x0f, 0x80, + 0x38, 0x70, 0x00, 0x63, 0x80, 0x01, 0x8c, 0x00, + 0x06, 0x30, 0x00, 0x18, 0xc0, 0x00, 0xe3, 0x00, + 0x07, 0x86, 0x00, 0x76, 0x1e, 0x07, 0x9f, 0x3f, + 0xf8, 0x7c, 0x3f, 0x80, 0x00, + // 'b' (0x62) 23x29, offset 3817-3901, at +2/-27 + // in regular row-major format + 0xf8, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x60, 0x00, + 0x00, 0xc0, 0x00, 0x01, 0x80, 0x00, 0x03, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x0c, 0x1f, 0x80, 0x18, + 0xff, 0xc0, 0x33, 0x81, 0xc0, 0x6e, 0x01, 0xc0, + 0xf0, 0x00, 0xc1, 0xe0, 0x01, 0xc3, 0x80, 0x01, + 0x87, 0x00, 0x03, 0x8c, 0x00, 0x03, 0x18, 0x00, + 0x06, 0x30, 0x00, 0x0c, 0x60, 0x00, 0x18, 0xc0, + 0x00, 0x31, 0x80, 0x00, 0x63, 0x80, 0x01, 0x87, + 0x00, 0x03, 0x0f, 0x00, 0x0e, 0x1f, 0x00, 0x38, + 0x37, 0x00, 0xe3, 0xe7, 0x03, 0x87, 0xc7, 0xfe, + 0x00, 0x03, 0xf0, 0x00, + // 'c' (0x63) 21x22, offset 3901-3959, at +4/-20 + // in regular row-major format + 0x01, 0xfc, 0x00, 0x3f, 0xf9, 0x83, 0xc0, 0xfc, + 0x38, 0x01, 0xe3, 0x00, 0x07, 0x38, 0x00, 0x19, + 0x80, 0x00, 0xdc, 0x00, 0x06, 0xc0, 0x00, 0x06, + 0x00, 0x00, 0x30, 0x00, 0x01, 0x80, 0x00, 0x0c, + 0x00, 0x00, 0x60, 0x00, 0x03, 0x80, 0x00, 0x0c, + 0x00, 0x00, 0x70, 0x00, 0x01, 0x80, 0x00, 0xc7, + 0x00, 0x1e, 0x1e, 0x03, 0xc0, 0x7f, 0xfc, 0x00, + 0xff, 0x00, + // 'd' (0x64) 24x29, offset 3959-4046, at +3/-27 + // in regular row-major format + 0x00, 0x00, 0xf8, 0x00, 0x00, 0xf8, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x18, 0x01, 0xf8, 0x18, + 0x07, 0xfe, 0x18, 0x0f, 0x07, 0x98, 0x1c, 0x01, + 0xd8, 0x38, 0x00, 0xf8, 0x70, 0x00, 0x78, 0x60, + 0x00, 0x38, 0xe0, 0x00, 0x38, 0xc0, 0x00, 0x18, + 0xc0, 0x00, 0x18, 0xc0, 0x00, 0x18, 0xc0, 0x00, + 0x18, 0xc0, 0x00, 0x18, 0xc0, 0x00, 0x18, 0x60, + 0x00, 0x38, 0x60, 0x00, 0x38, 0x70, 0x00, 0x78, + 0x38, 0x00, 0xd8, 0x1c, 0x01, 0xd8, 0x0f, 0x07, + 0x9f, 0x07, 0xfe, 0x1f, 0x01, 0xf8, 0x00, + // 'e' (0x65) 21x22, offset 4046-4104, at +3/-20 + // in regular row-major format + 0x01, 0xfc, 0x00, 0x3f, 0xf8, 0x07, 0x80, 0xf0, + 0x70, 0x01, 0xc3, 0x00, 0x07, 0x30, 0x00, 0x19, + 0x80, 0x00, 0x78, 0x00, 0x03, 0xc0, 0x00, 0x1f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x0c, + 0x00, 0x00, 0x60, 0x00, 0x01, 0x80, 0x00, 0x0c, + 0x00, 0x00, 0x30, 0x00, 0x01, 0xc0, 0x00, 0xc7, + 0x00, 0x0e, 0x1e, 0x03, 0xe0, 0x3f, 0xfc, 0x00, + 0x7f, 0x00, + // 'f' (0x66) 19x28, offset 4104-4171, at +6/-27 + // in regular row-major format + 0x00, 0x7f, 0xc0, 0x3f, 0xfc, 0x0e, 0x00, 0x03, + 0x80, 0x00, 0x60, 0x00, 0x0c, 0x00, 0x01, 0x80, + 0x00, 0x30, 0x00, 0xff, 0xff, 0x9f, 0xff, 0xf0, + 0x18, 0x00, 0x03, 0x00, 0x00, 0x60, 0x00, 0x0c, + 0x00, 0x01, 0x80, 0x00, 0x30, 0x00, 0x06, 0x00, + 0x00, 0xc0, 0x00, 0x18, 0x00, 0x03, 0x00, 0x00, + 0x60, 0x00, 0x0c, 0x00, 0x01, 0x80, 0x00, 0x30, + 0x00, 0x06, 0x00, 0x00, 0xc0, 0x03, 0xff, 0xfc, + 0x7f, 0xff, 0x80, + // 'g' (0x67) 23x30, offset 4171-4258, at +3/-20 + // in regular row-major format + 0x01, 0xf8, 0x00, 0x0f, 0xfc, 0x7c, 0x38, 0x1c, + 0xf8, 0xe0, 0x0d, 0x83, 0x00, 0x0f, 0x0e, 0x00, + 0x1e, 0x18, 0x00, 0x1c, 0x70, 0x00, 0x38, 0xc0, + 0x00, 0x31, 0x80, 0x00, 0x63, 0x00, 0x00, 0xc6, + 0x00, 0x01, 0x8c, 0x00, 0x03, 0x18, 0x00, 0x06, + 0x18, 0x00, 0x1c, 0x30, 0x00, 0x38, 0x30, 0x00, + 0xf0, 0x70, 0x03, 0x60, 0x78, 0x1c, 0xc0, 0x3f, + 0xf1, 0x80, 0x1f, 0x83, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x0c, 0x00, 0x00, 0x18, 0x00, 0x00, 0x30, + 0x00, 0x00, 0xc0, 0x00, 0x03, 0x80, 0x00, 0x0e, + 0x00, 0x3f, 0xf8, 0x00, 0x7f, 0xc0, 0x00, + // 'h' (0x68) 23x28, offset 4258-4339, at +3/-27 + // in regular row-major format + 0xf8, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x60, 0x00, + 0x00, 0xc0, 0x00, 0x01, 0x80, 0x00, 0x03, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x0c, 0x3f, 0x00, 0x18, + 0xff, 0x80, 0x37, 0x03, 0x80, 0x7c, 0x03, 0x80, + 0xf0, 0x03, 0x81, 0xc0, 0x03, 0x03, 0x00, 0x06, + 0x06, 0x00, 0x0c, 0x0c, 0x00, 0x18, 0x18, 0x00, + 0x30, 0x30, 0x00, 0x60, 0x60, 0x00, 0xc0, 0xc0, + 0x01, 0x81, 0x80, 0x03, 0x03, 0x00, 0x06, 0x06, + 0x00, 0x0c, 0x0c, 0x00, 0x18, 0x18, 0x00, 0x30, + 0x30, 0x00, 0x63, 0xfc, 0x07, 0xff, 0xf8, 0x0f, + 0xf0, + // 'i' (0x69) 18x29, offset 4339-4405, at +5/-28 + // in regular row-major format + 0x01, 0xc0, 0x00, 0x70, 0x00, 0x1c, 0x00, 0x07, + 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x03, 0xfc, + 0x00, 0x03, 0x00, 0x00, 0xc0, 0x00, 0x30, 0x00, + 0x0c, 0x00, 0x03, 0x00, 0x00, 0xc0, 0x00, 0x30, + 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0xc0, 0x00, + 0x30, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0xc0, + 0x00, 0x30, 0x00, 0x0c, 0x03, 0xff, 0xff, 0xff, + 0xff, 0xc0, + // 'j' (0x6a) 14x38, offset 4405-4472, at +6/-28 + // in regular row-major format + 0x00, 0x70, 0x01, 0xc0, 0x07, 0x00, 0x1c, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0xff, 0xff, 0xff, 0xc0, 0x03, 0x00, 0x0c, 0x00, + 0x30, 0x00, 0xc0, 0x03, 0x00, 0x0c, 0x00, 0x30, + 0x00, 0xc0, 0x03, 0x00, 0x0c, 0x00, 0x30, 0x00, + 0xc0, 0x03, 0x00, 0x0c, 0x00, 0x30, 0x00, 0xc0, + 0x03, 0x00, 0x0c, 0x00, 0x30, 0x00, 0xc0, 0x03, + 0x00, 0x0c, 0x00, 0x70, 0x03, 0x80, 0x1c, 0xff, + 0xe3, 0xff, 0x00, + // 'k' (0x6b) 22x28, offset 4472-4549, at +4/-27 + // in regular row-major format + 0xf8, 0x00, 0x03, 0xe0, 0x00, 0x01, 0x80, 0x00, + 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x00, + 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x18, 0x1f, + 0xe0, 0x60, 0x7f, 0x81, 0x80, 0x60, 0x06, 0x07, + 0x00, 0x18, 0x38, 0x00, 0x61, 0xc0, 0x01, 0x8e, + 0x00, 0x06, 0x70, 0x00, 0x1b, 0x80, 0x00, 0x7f, + 0x00, 0x01, 0xce, 0x00, 0x06, 0x1c, 0x00, 0x18, + 0x38, 0x00, 0x60, 0x70, 0x01, 0x80, 0xe0, 0x06, + 0x01, 0xc0, 0x18, 0x03, 0x80, 0x60, 0x07, 0x0f, + 0x80, 0x7f, 0xfe, 0x01, 0xff, + // 'l' (0x6c) 18x28, offset 4549-4612, at +5/-27 + // in regular row-major format + 0x3f, 0xc0, 0x0f, 0xf0, 0x00, 0x0c, 0x00, 0x03, + 0x00, 0x00, 0xc0, 0x00, 0x30, 0x00, 0x0c, 0x00, + 0x03, 0x00, 0x00, 0xc0, 0x00, 0x30, 0x00, 0x0c, + 0x00, 0x03, 0x00, 0x00, 0xc0, 0x00, 0x30, 0x00, + 0x0c, 0x00, 0x03, 0x00, 0x00, 0xc0, 0x00, 0x30, + 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0xc0, 0x00, + 0x30, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0xc0, + 0x00, 0x30, 0x0f, 0xff, 0xff, 0xff, 0xff, + // 'm' (0x6d) 28x21, offset 4612-4686, at +0/-20 + // in regular row-major format + 0x00, 0xf0, 0x3c, 0x0f, 0x9f, 0x87, 0xe0, 0xfb, + 0x1c, 0xc7, 0x01, 0xe0, 0xd8, 0x38, 0x1c, 0x07, + 0x01, 0x81, 0x80, 0x60, 0x18, 0x18, 0x06, 0x01, + 0x81, 0x80, 0x60, 0x18, 0x18, 0x06, 0x01, 0x81, + 0x80, 0x60, 0x18, 0x18, 0x06, 0x01, 0x81, 0x80, + 0x60, 0x18, 0x18, 0x06, 0x01, 0x81, 0x80, 0x60, + 0x18, 0x18, 0x06, 0x01, 0x81, 0x80, 0x60, 0x18, + 0x18, 0x06, 0x01, 0x81, 0x80, 0x60, 0x18, 0x18, + 0x06, 0x01, 0x8f, 0xe0, 0x7c, 0x1f, 0xfe, 0x07, + 0xc1, 0xf0, + // 'n' (0x6e) 23x21, offset 4686-4747, at +2/-20 + // in regular row-major format + 0x00, 0x1f, 0x00, 0xf8, 0xff, 0x81, 0xf3, 0x83, + 0x80, 0x6c, 0x03, 0x80, 0xf0, 0x03, 0x81, 0xc0, + 0x03, 0x03, 0x00, 0x06, 0x06, 0x00, 0x0c, 0x0c, + 0x00, 0x18, 0x18, 0x00, 0x30, 0x30, 0x00, 0x60, + 0x60, 0x00, 0xc0, 0xc0, 0x01, 0x81, 0x80, 0x03, + 0x03, 0x00, 0x06, 0x06, 0x00, 0x0c, 0x0c, 0x00, + 0x18, 0x18, 0x00, 0x30, 0x30, 0x00, 0x67, 0xfc, + 0x03, 0xff, 0xf8, 0x07, 0xe0, + // 'o' (0x6f) 22x22, offset 4747-4808, at +3/-20 + // in regular row-major format + 0x00, 0xfc, 0x00, 0x1f, 0xfe, 0x00, 0xf0, 0x3c, + 0x07, 0x00, 0x38, 0x38, 0x00, 0x71, 0xc0, 0x00, + 0xe6, 0x00, 0x01, 0x98, 0x00, 0x06, 0xc0, 0x00, + 0x0f, 0x00, 0x00, 0x3c, 0x00, 0x00, 0xf0, 0x00, + 0x03, 0xc0, 0x00, 0x0f, 0x00, 0x00, 0x36, 0x00, + 0x01, 0x98, 0x00, 0x06, 0x70, 0x00, 0x38, 0xe0, + 0x01, 0xc1, 0xc0, 0x0e, 0x03, 0xc0, 0xf0, 0x07, + 0xff, 0x80, 0x03, 0xf0, 0x00, + // 'p' (0x70) 23x30, offset 4808-4895, at +2/-20 + // in regular row-major format + 0x00, 0x3f, 0x01, 0xf1, 0xff, 0x83, 0xe7, 0x03, + 0x80, 0xd8, 0x01, 0x81, 0xe0, 0x01, 0x83, 0xc0, + 0x03, 0x87, 0x00, 0x03, 0x0e, 0x00, 0x07, 0x18, + 0x00, 0x06, 0x30, 0x00, 0x0c, 0x60, 0x00, 0x18, + 0xc0, 0x00, 0x31, 0x80, 0x00, 0x63, 0x00, 0x00, + 0xc7, 0x00, 0x03, 0x0e, 0x00, 0x06, 0x1e, 0x00, + 0x18, 0x36, 0x00, 0x70, 0x67, 0x03, 0xc0, 0xc7, + 0xfe, 0x01, 0x83, 0xf0, 0x03, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x60, 0x00, 0x00, 0xc0, 0x00, + 0x0f, 0xfc, 0x00, 0x1f, 0xf8, 0x00, 0x00, + // 'q' (0x71) 24x30, offset 4895-4985, at +3/-20 + // in regular row-major format + 0x01, 0xf8, 0x00, 0x07, 0xff, 0x1f, 0x0f, 0x07, + 0x9f, 0x1c, 0x01, 0xd8, 0x38, 0x00, 0x78, 0x70, + 0x00, 0x78, 0x60, 0x00, 0x38, 0xe0, 0x00, 0x38, + 0xc0, 0x00, 0x18, 0xc0, 0x00, 0x18, 0xc0, 0x00, + 0x18, 0xc0, 0x00, 0x18, 0xc0, 0x00, 0x18, 0xc0, + 0x00, 0x18, 0x60, 0x00, 0x38, 0x70, 0x00, 0x78, + 0x30, 0x00, 0x78, 0x1c, 0x01, 0xd8, 0x0f, 0x07, + 0x98, 0x07, 0xff, 0x18, 0x01, 0xfc, 0x18, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x18, 0x00, 0x03, 0xff, 0x00, + 0x03, 0xff, + // 'r' (0x72) 21x20, offset 4985-5038, at +5/-19 + // in regular row-major format + 0x7e, 0x03, 0xc3, 0xf0, 0x7f, 0x81, 0x8f, 0x0e, + 0x0c, 0xe0, 0x00, 0x7e, 0x00, 0x03, 0xc0, 0x00, + 0x1c, 0x00, 0x00, 0xc0, 0x00, 0x06, 0x00, 0x00, + 0x30, 0x00, 0x01, 0x80, 0x00, 0x0c, 0x00, 0x00, + 0x60, 0x00, 0x03, 0x00, 0x00, 0x18, 0x00, 0x00, + 0xc0, 0x00, 0x06, 0x00, 0x00, 0x30, 0x00, 0x3f, + 0xff, 0xc1, 0xff, 0xfe, 0x00, + // 's' (0x73) 18x22, offset 5038-5088, at +5/-20 + // in regular row-major format + 0x07, 0xf0, 0x07, 0xff, 0x63, 0xc0, 0xf9, 0xc0, + 0x0e, 0x60, 0x01, 0x98, 0x00, 0x66, 0x00, 0x19, + 0xc0, 0x00, 0x38, 0x00, 0x07, 0xc0, 0x00, 0x7f, + 0xc0, 0x00, 0x7c, 0x00, 0x03, 0x80, 0x00, 0x70, + 0x00, 0x0f, 0x00, 0x03, 0xc0, 0x00, 0xf8, 0x00, + 0x7f, 0x00, 0x3b, 0xf0, 0x3c, 0xdf, 0xfe, 0x00, + 0xfe, 0x00, + // 't' (0x74) 21x27, offset 5088-5159, at +3/-25 + // in regular row-major format + 0x0c, 0x00, 0x00, 0x60, 0x00, 0x03, 0x00, 0x00, + 0x18, 0x00, 0x00, 0xc0, 0x00, 0x06, 0x00, 0x03, + 0xff, 0xfe, 0x1f, 0xff, 0xf0, 0x0c, 0x00, 0x00, + 0x60, 0x00, 0x03, 0x00, 0x00, 0x18, 0x00, 0x00, + 0xc0, 0x00, 0x06, 0x00, 0x00, 0x30, 0x00, 0x01, + 0x80, 0x00, 0x0c, 0x00, 0x00, 0x60, 0x00, 0x03, + 0x00, 0x00, 0x18, 0x00, 0x00, 0xc0, 0x00, 0x06, + 0x00, 0x00, 0x30, 0x00, 0x00, 0xc0, 0x07, 0x07, + 0x01, 0xf0, 0x1f, 0xff, 0x00, 0x3f, 0x80, + // 'u' (0x75) 23x21, offset 5159-5220, at +3/-19 + // in regular row-major format + 0xf8, 0x03, 0xf1, 0xf0, 0x07, 0xe0, 0x60, 0x00, + 0xc0, 0xc0, 0x01, 0x81, 0x80, 0x03, 0x03, 0x00, + 0x06, 0x06, 0x00, 0x0c, 0x0c, 0x00, 0x18, 0x18, + 0x00, 0x30, 0x30, 0x00, 0x60, 0x60, 0x00, 0xc0, + 0xc0, 0x01, 0x81, 0x80, 0x03, 0x03, 0x00, 0x06, + 0x06, 0x00, 0x0c, 0x0c, 0x00, 0x38, 0x18, 0x00, + 0xf0, 0x18, 0x03, 0x60, 0x38, 0x3c, 0xf8, 0x3f, + 0xf1, 0xf0, 0x1f, 0x00, 0x00, + // 'v' (0x76) 26x20, offset 5220-5285, at +1/-19 + // in regular row-major format + 0x7f, 0xc0, 0xff, 0xdf, 0xf0, 0x3f, 0xf0, 0xc0, + 0x00, 0xc0, 0x30, 0x00, 0x30, 0x06, 0x00, 0x1c, + 0x01, 0x80, 0x06, 0x00, 0x30, 0x01, 0x80, 0x0c, + 0x00, 0xc0, 0x03, 0x80, 0x30, 0x00, 0x60, 0x18, + 0x00, 0x18, 0x06, 0x00, 0x03, 0x03, 0x00, 0x00, + 0xc0, 0xc0, 0x00, 0x18, 0x30, 0x00, 0x06, 0x18, + 0x00, 0x00, 0xc6, 0x00, 0x00, 0x33, 0x00, 0x00, + 0x0e, 0xc0, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x78, + 0x00, + // 'w' (0x77) 26x20, offset 5285-5350, at +1/-19 + // in regular row-major format + 0x7f, 0x00, 0x3f, 0xdf, 0xc0, 0x0f, 0xf1, 0x80, + 0x00, 0x20, 0x60, 0x00, 0x18, 0x18, 0x00, 0x06, + 0x06, 0x03, 0x01, 0x80, 0x81, 0xe0, 0x60, 0x30, + 0x78, 0x10, 0x0c, 0x1e, 0x0c, 0x03, 0x0c, 0xc3, + 0x00, 0xc3, 0x30, 0xc0, 0x10, 0xcc, 0x30, 0x06, + 0x61, 0x98, 0x01, 0x98, 0x66, 0x00, 0x66, 0x19, + 0x80, 0x0b, 0x03, 0x60, 0x03, 0xc0, 0xd0, 0x00, + 0xf0, 0x1c, 0x00, 0x38, 0x07, 0x00, 0x0e, 0x01, + 0xc0, + // 'x' (0x78) 24x20, offset 5350-5410, at +2/-19 + // in regular row-major format + 0x3f, 0x81, 0xfe, 0x3f, 0x81, 0xfe, 0x0c, 0x00, + 0x38, 0x06, 0x00, 0x70, 0x03, 0x00, 0xe0, 0x01, + 0x81, 0xc0, 0x00, 0xc3, 0x80, 0x00, 0x67, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x18, 0x00, 0x00, 0x3c, + 0x00, 0x00, 0x67, 0x00, 0x00, 0xc3, 0x80, 0x01, + 0x81, 0xc0, 0x03, 0x00, 0xe0, 0x06, 0x00, 0x70, + 0x0c, 0x00, 0x38, 0x18, 0x00, 0x1c, 0x7f, 0x81, + 0xff, 0x7f, 0x81, 0xff, + // 'y' (0x79) 24x29, offset 5410-5497, at +2/-19 + // in regular row-major format + 0x7f, 0x00, 0xff, 0x7f, 0x00, 0xff, 0x18, 0x00, + 0x0c, 0x18, 0x00, 0x18, 0x0c, 0x00, 0x18, 0x0c, + 0x00, 0x30, 0x06, 0x00, 0x30, 0x06, 0x00, 0x60, + 0x03, 0x00, 0x60, 0x03, 0x00, 0xc0, 0x01, 0x80, + 0xc0, 0x01, 0x81, 0x80, 0x00, 0xc1, 0x80, 0x00, + 0xc3, 0x00, 0x00, 0x63, 0x00, 0x00, 0x66, 0x00, + 0x00, 0x36, 0x00, 0x00, 0x34, 0x00, 0x00, 0x3c, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x30, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x60, 0x00, 0x00, 0xc0, + 0x00, 0x7f, 0xfc, 0x00, 0x7f, 0xfc, 0x00, + // 'z' (0x7a) 17x20, offset 5497-5540, at +6/-19 + // in regular row-major format + 0xff, 0xff, 0x7f, 0xff, 0xb0, 0x01, 0x98, 0x01, + 0xcc, 0x01, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, + 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xe0, 0x00, + 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, + 0x60, 0x03, 0x70, 0x01, 0xb0, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xf0, + // '{' (0x7b) 11x34, offset 5540-5587, at +8/-27 + // in regular row-major format + 0x00, 0xe0, 0x7c, 0x0c, 0x03, 0x00, 0x60, 0x0c, + 0x01, 0x80, 0x30, 0x06, 0x00, 0xc0, 0x18, 0x03, + 0x00, 0x60, 0x0c, 0x03, 0x00, 0xe0, 0xf0, 0x1e, + 0x00, 0x70, 0x06, 0x00, 0x60, 0x0c, 0x01, 0x80, + 0x30, 0x06, 0x00, 0xc0, 0x18, 0x03, 0x00, 0x60, + 0x0c, 0x01, 0x80, 0x18, 0x03, 0xe0, 0x1c, + // '|' (0x7c) 2x34, offset 5587-5596, at +13/-27 + // in regular row-major format + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf0, + // '}' (0x7d) 11x34, offset 5596-5643, at +9/-27 + // in regular row-major format + 0xe0, 0x1f, 0x00, 0x60, 0x06, 0x00, 0xc0, 0x18, + 0x03, 0x00, 0x60, 0x0c, 0x01, 0x80, 0x30, 0x06, + 0x00, 0xc0, 0x18, 0x01, 0x80, 0x38, 0x01, 0xe0, + 0x3c, 0x1c, 0x03, 0x00, 0xc0, 0x18, 0x03, 0x00, + 0x60, 0x0c, 0x01, 0x80, 0x30, 0x06, 0x00, 0xc0, + 0x18, 0x03, 0x00, 0xc0, 0xf8, 0x1c, 0x00, +}; + + +static const uint8_t TomThumb_generic[] = { + // ' ' (0x20) 8x1, offset 0-1, at +0/-5 + // in regular row-major format + 0x00, + // '!' (0x21) 8x5, offset 1-6, at +0/-5 + // in regular row-major format + 0x80, 0x80, 0x80, 0x00, 0x80, + // '"' (0x22) 8x2, offset 6-8, at +0/-5 + // in regular row-major format + 0xa0, 0xa0, + // '#' (0x23) 8x5, offset 8-13, at +0/-5 + // in regular row-major format + 0xa0, 0xe0, 0xa0, 0xe0, 0xa0, + // '$' (0x24) 8x5, offset 13-18, at +0/-5 + // in regular row-major format + 0x60, 0xc0, 0x60, 0xc0, 0x40, + // '%' (0x25) 8x5, offset 18-23, at +0/-5 + // in regular row-major format + 0x80, 0x20, 0x40, 0x80, 0x20, + // '&' (0x26) 8x5, offset 23-28, at +0/-5 + // in regular row-major format + 0xc0, 0xc0, 0xe0, 0xa0, 0x60, + // ''' (0x27) 8x2, offset 28-30, at +0/-5 + // in regular row-major format + 0x80, 0x80, + // '(' (0x28) 8x5, offset 30-35, at +0/-5 + // in regular row-major format + 0x40, 0x80, 0x80, 0x80, 0x40, + // ')' (0x29) 8x5, offset 35-40, at +0/-5 + // in regular row-major format + 0x80, 0x40, 0x40, 0x40, 0x80, + // '*' (0x2a) 8x3, offset 40-43, at +0/-5 + // in regular row-major format + 0xa0, 0x40, 0xa0, + // '+' (0x2b) 8x3, offset 43-46, at +0/-4 + // in regular row-major format + 0x40, 0xe0, 0x40, + // ',' (0x2c) 8x2, offset 46-48, at +0/-2 + // in regular row-major format + 0x40, 0x80, + // '-' (0x2d) 8x1, offset 48-49, at +0/-3 + // in regular row-major format + 0xe0, + // '.' (0x2e) 8x1, offset 49-50, at +0/-1 + // in regular row-major format + 0x80, + // '/' (0x2f) 8x5, offset 50-55, at +0/-5 + // in regular row-major format + 0x20, 0x20, 0x40, 0x80, 0x80, + // '0' (0x30) 8x5, offset 55-60, at +0/-5 + // in regular row-major format + 0x60, 0xa0, 0xa0, 0xa0, 0xc0, + // '1' (0x31) 8x5, offset 60-65, at +0/-5 + // in regular row-major format + 0x40, 0xc0, 0x40, 0x40, 0x40, + // '2' (0x32) 8x5, offset 65-70, at +0/-5 + // in regular row-major format + 0xc0, 0x20, 0x40, 0x80, 0xe0, + // '3' (0x33) 8x5, offset 70-75, at +0/-5 + // in regular row-major format + 0xc0, 0x20, 0x40, 0x20, 0xc0, + // '4' (0x34) 8x5, offset 75-80, at +0/-5 + // in regular row-major format + 0xa0, 0xa0, 0xe0, 0x20, 0x20, + // '5' (0x35) 8x5, offset 80-85, at +0/-5 + // in regular row-major format + 0xe0, 0x80, 0xc0, 0x20, 0xc0, + // '6' (0x36) 8x5, offset 85-90, at +0/-5 + // in regular row-major format + 0x60, 0x80, 0xe0, 0xa0, 0xe0, + // '7' (0x37) 8x5, offset 90-95, at +0/-5 + // in regular row-major format + 0xe0, 0x20, 0x40, 0x80, 0x80, + // '8' (0x38) 8x5, offset 95-100, at +0/-5 + // in regular row-major format + 0xe0, 0xa0, 0xe0, 0xa0, 0xe0, + // '9' (0x39) 8x5, offset 100-105, at +0/-5 + // in regular row-major format + 0xe0, 0xa0, 0xe0, 0x20, 0xc0, + // ':' (0x3a) 8x3, offset 105-108, at +0/-4 + // in regular row-major format + 0x80, 0x00, 0x80, + // ';' (0x3b) 8x4, offset 108-112, at +0/-4 + // in regular row-major format + 0x40, 0x00, 0x40, 0x80, + // '<' (0x3c) 8x5, offset 112-117, at +0/-5 + // in regular row-major format + 0x20, 0x40, 0x80, 0x40, 0x20, + // '=' (0x3d) 8x3, offset 117-120, at +0/-4 + // in regular row-major format + 0xe0, 0x00, 0xe0, + // '>' (0x3e) 8x5, offset 120-125, at +0/-5 + // in regular row-major format + 0x80, 0x40, 0x20, 0x40, 0x80, + // '?' (0x3f) 8x5, offset 125-130, at +0/-5 + // in regular row-major format + 0xe0, 0x20, 0x40, 0x00, 0x40, + // '@' (0x40) 8x5, offset 130-135, at +0/-5 + // in regular row-major format + 0x40, 0xa0, 0xe0, 0x80, 0x60, + // 'A' (0x41) 8x5, offset 135-140, at +0/-5 + // in regular row-major format + 0x40, 0xa0, 0xe0, 0xa0, 0xa0, + // 'B' (0x42) 8x5, offset 140-145, at +0/-5 + // in regular row-major format + 0xc0, 0xa0, 0xc0, 0xa0, 0xc0, + // 'C' (0x43) 8x5, offset 145-150, at +0/-5 + // in regular row-major format + 0x60, 0x80, 0x80, 0x80, 0x60, + // 'D' (0x44) 8x5, offset 150-155, at +0/-5 + // in regular row-major format + 0xc0, 0xa0, 0xa0, 0xa0, 0xc0, + // 'E' (0x45) 8x5, offset 155-160, at +0/-5 + // in regular row-major format + 0xe0, 0x80, 0xe0, 0x80, 0xe0, + // 'F' (0x46) 8x5, offset 160-165, at +0/-5 + // in regular row-major format + 0xe0, 0x80, 0xe0, 0x80, 0x80, + // 'G' (0x47) 8x5, offset 165-170, at +0/-5 + // in regular row-major format + 0x60, 0x80, 0xe0, 0xa0, 0x60, + // 'H' (0x48) 8x5, offset 170-175, at +0/-5 + // in regular row-major format + 0xa0, 0xa0, 0xe0, 0xa0, 0xa0, + // 'I' (0x49) 8x5, offset 175-180, at +0/-5 + // in regular row-major format + 0xe0, 0x40, 0x40, 0x40, 0xe0, + // 'J' (0x4a) 8x5, offset 180-185, at +0/-5 + // in regular row-major format + 0x20, 0x20, 0x20, 0xa0, 0x40, + // 'K' (0x4b) 8x5, offset 185-190, at +0/-5 + // in regular row-major format + 0xa0, 0xa0, 0xc0, 0xa0, 0xa0, + // 'L' (0x4c) 8x5, offset 190-195, at +0/-5 + // in regular row-major format + 0x80, 0x80, 0x80, 0x80, 0xe0, + // 'M' (0x4d) 8x5, offset 195-200, at +0/-5 + // in regular row-major format + 0xa0, 0xe0, 0xe0, 0xa0, 0xa0, + // 'N' (0x4e) 8x5, offset 200-205, at +0/-5 + // in regular row-major format + 0xa0, 0xe0, 0xe0, 0xe0, 0xa0, + // 'O' (0x4f) 8x5, offset 205-210, at +0/-5 + // in regular row-major format + 0x40, 0xa0, 0xa0, 0xa0, 0x40, + // 'P' (0x50) 8x5, offset 210-215, at +0/-5 + // in regular row-major format + 0xc0, 0xa0, 0xc0, 0x80, 0x80, + // 'Q' (0x51) 8x5, offset 215-220, at +0/-5 + // in regular row-major format + 0x40, 0xa0, 0xa0, 0xe0, 0x60, + // 'R' (0x52) 8x5, offset 220-225, at +0/-5 + // in regular row-major format + 0xc0, 0xa0, 0xe0, 0xc0, 0xa0, + // 'S' (0x53) 8x5, offset 225-230, at +0/-5 + // in regular row-major format + 0x60, 0x80, 0x40, 0x20, 0xc0, + // 'T' (0x54) 8x5, offset 230-235, at +0/-5 + // in regular row-major format + 0xe0, 0x40, 0x40, 0x40, 0x40, + // 'U' (0x55) 8x5, offset 235-240, at +0/-5 + // in regular row-major format + 0xa0, 0xa0, 0xa0, 0xa0, 0x60, + // 'V' (0x56) 8x5, offset 240-245, at +0/-5 + // in regular row-major format + 0xa0, 0xa0, 0xa0, 0x40, 0x40, + // 'W' (0x57) 8x5, offset 245-250, at +0/-5 + // in regular row-major format + 0xa0, 0xa0, 0xe0, 0xe0, 0xa0, + // 'X' (0x58) 8x5, offset 250-255, at +0/-5 + // in regular row-major format + 0xa0, 0xa0, 0x40, 0xa0, 0xa0, + // 'Y' (0x59) 8x5, offset 255-260, at +0/-5 + // in regular row-major format + 0xa0, 0xa0, 0x40, 0x40, 0x40, + // 'Z' (0x5a) 8x5, offset 260-265, at +0/-5 + // in regular row-major format + 0xe0, 0x20, 0x40, 0x80, 0xe0, + // '[' (0x5b) 8x5, offset 265-270, at +0/-5 + // in regular row-major format + 0xe0, 0x80, 0x80, 0x80, 0xe0, + // '\' (0x5c) 8x3, offset 270-273, at +0/-4 + // in regular row-major format + 0x80, 0x40, 0x20, + // ']' (0x5d) 8x5, offset 273-278, at +0/-5 + // in regular row-major format + 0xe0, 0x20, 0x20, 0x20, 0xe0, + // '^' (0x5e) 8x2, offset 278-280, at +0/-5 + // in regular row-major format + 0x40, 0xa0, + // '_' (0x5f) 8x1, offset 280-281, at +0/-1 + // in regular row-major format + 0xe0, + // '`' (0x60) 8x2, offset 281-283, at +0/-5 + // in regular row-major format + 0x80, 0x40, + // 'a' (0x61) 8x4, offset 283-287, at +0/-4 + // in regular row-major format + 0xc0, 0x60, 0xa0, 0xe0, + // 'b' (0x62) 8x5, offset 287-292, at +0/-5 + // in regular row-major format + 0x80, 0xc0, 0xa0, 0xa0, 0xc0, + // 'c' (0x63) 8x4, offset 292-296, at +0/-4 + // in regular row-major format + 0x60, 0x80, 0x80, 0x60, + // 'd' (0x64) 8x5, offset 296-301, at +0/-5 + // in regular row-major format + 0x20, 0x60, 0xa0, 0xa0, 0x60, + // 'e' (0x65) 8x4, offset 301-305, at +0/-4 + // in regular row-major format + 0x60, 0xa0, 0xc0, 0x60, + // 'f' (0x66) 8x5, offset 305-310, at +0/-5 + // in regular row-major format + 0x20, 0x40, 0xe0, 0x40, 0x40, + // 'g' (0x67) 8x5, offset 310-315, at +0/-4 + // in regular row-major format + 0x60, 0xa0, 0xe0, 0x20, 0x40, + // 'h' (0x68) 8x5, offset 315-320, at +0/-5 + // in regular row-major format + 0x80, 0xc0, 0xa0, 0xa0, 0xa0, + // 'i' (0x69) 8x5, offset 320-325, at +0/-5 + // in regular row-major format + 0x80, 0x00, 0x80, 0x80, 0x80, + // 'j' (0x6a) 8x6, offset 325-331, at +0/-5 + // in regular row-major format + 0x20, 0x00, 0x20, 0x20, 0xa0, 0x40, + // 'k' (0x6b) 8x5, offset 331-336, at +0/-5 + // in regular row-major format + 0x80, 0xa0, 0xc0, 0xc0, 0xa0, + // 'l' (0x6c) 8x5, offset 336-341, at +0/-5 + // in regular row-major format + 0xc0, 0x40, 0x40, 0x40, 0xe0, + // 'm' (0x6d) 8x4, offset 341-345, at +0/-4 + // in regular row-major format + 0xe0, 0xe0, 0xe0, 0xa0, + // 'n' (0x6e) 8x4, offset 345-349, at +0/-4 + // in regular row-major format + 0xc0, 0xa0, 0xa0, 0xa0, + // 'o' (0x6f) 8x4, offset 349-353, at +0/-4 + // in regular row-major format + 0x40, 0xa0, 0xa0, 0x40, + // 'p' (0x70) 8x5, offset 353-358, at +0/-4 + // in regular row-major format + 0xc0, 0xa0, 0xa0, 0xc0, 0x80, + // 'q' (0x71) 8x5, offset 358-363, at +0/-4 + // in regular row-major format + 0x60, 0xa0, 0xa0, 0x60, 0x20, + // 'r' (0x72) 8x4, offset 363-367, at +0/-4 + // in regular row-major format + 0x60, 0x80, 0x80, 0x80, + // 's' (0x73) 8x4, offset 367-371, at +0/-4 + // in regular row-major format + 0x60, 0xc0, 0x60, 0xc0, + // 't' (0x74) 8x5, offset 371-376, at +0/-5 + // in regular row-major format + 0x40, 0xe0, 0x40, 0x40, 0x60, + // 'u' (0x75) 8x4, offset 376-380, at +0/-4 + // in regular row-major format + 0xa0, 0xa0, 0xa0, 0x60, + // 'v' (0x76) 8x4, offset 380-384, at +0/-4 + // in regular row-major format + 0xa0, 0xa0, 0xe0, 0x40, + // 'w' (0x77) 8x4, offset 384-388, at +0/-4 + // in regular row-major format + 0xa0, 0xe0, 0xe0, 0xe0, + // 'x' (0x78) 8x4, offset 388-392, at +0/-4 + // in regular row-major format + 0xa0, 0x40, 0x40, 0xa0, + // 'y' (0x79) 8x5, offset 392-397, at +0/-4 + // in regular row-major format + 0xa0, 0xa0, 0x60, 0x20, 0x40, + // 'z' (0x7a) 8x4, offset 397-401, at +0/-4 + // in regular row-major format + 0xe0, 0x60, 0xc0, 0xe0, + // '{' (0x7b) 8x5, offset 401-406, at +0/-5 + // in regular row-major format + 0x60, 0x40, 0x80, 0x40, 0x60, + // '|' (0x7c) 8x5, offset 406-411, at +0/-5 + // in regular row-major format + 0x80, 0x80, 0x00, 0x80, 0x80, + // '}' (0x7d) 8x5, offset 411-416, at +0/-5 + // in regular row-major format + 0xc0, 0x40, 0x20, 0x40, 0xc0, +}; + + +static const uint8_t Org_01_generic[] = { + // ' ' (0x20) 0x0, offset 0-0, at +0/+1 + // in regular row-major format + // '!' (0x21) 1x5, offset 0-1, at +0/-4 + // in regular row-major format + 0xe8, + // '"' (0x22) 3x1, offset 1-2, at +0/-4 + // in regular row-major format + 0xa0, + // '#' (0x23) 5x5, offset 2-6, at +0/-4 + // in regular row-major format + 0x57, 0xd5, 0xf5, 0x00, + // '$' (0x24) 5x5, offset 6-10, at +0/-4 + // in regular row-major format + 0xfd, 0x3e, 0x5f, 0x80, + // '%' (0x25) 5x5, offset 10-14, at +0/-4 + // in regular row-major format + 0x88, 0x88, 0x88, 0x80, + // '&' (0x26) 5x5, offset 14-18, at +0/-4 + // in regular row-major format + 0xf4, 0xbf, 0x2e, 0x80, + // ''' (0x27) 1x1, offset 18-19, at +0/-4 + // in regular row-major format + 0x80, + // '(' (0x28) 2x5, offset 19-21, at +0/-4 + // in regular row-major format + 0x6a, 0x40, + // ')' (0x29) 2x5, offset 21-23, at +0/-4 + // in regular row-major format + 0x95, 0x80, + // '*' (0x2a) 3x3, offset 23-25, at +0/-3 + // in regular row-major format + 0xaa, 0x80, + // '+' (0x2b) 3x3, offset 25-27, at +0/-3 + // in regular row-major format + 0x5d, 0x00, + // ',' (0x2c) 1x2, offset 27-28, at +0/+0 + // in regular row-major format + 0xc0, + // '-' (0x2d) 4x1, offset 28-29, at +0/-2 + // in regular row-major format + 0xf0, + // '.' (0x2e) 1x1, offset 29-30, at +0/+0 + // in regular row-major format + 0x80, + // '/' (0x2f) 5x5, offset 30-34, at +0/-4 + // in regular row-major format + 0x08, 0x88, 0x88, 0x00, + // '0' (0x30) 5x5, offset 34-38, at +0/-4 + // in regular row-major format + 0xfc, 0x63, 0x1f, 0x80, + // '1' (0x31) 1x5, offset 38-39, at +0/-4 + // in regular row-major format + 0xf8, + // '2' (0x32) 5x5, offset 39-43, at +0/-4 + // in regular row-major format + 0xf8, 0x7f, 0x0f, 0x80, + // '3' (0x33) 5x5, offset 43-47, at +0/-4 + // in regular row-major format + 0xf8, 0x7e, 0x1f, 0x80, + // '4' (0x34) 5x5, offset 47-51, at +0/-4 + // in regular row-major format + 0x8c, 0x7e, 0x10, 0x80, + // '5' (0x35) 5x5, offset 51-55, at +0/-4 + // in regular row-major format + 0xfc, 0x3e, 0x1f, 0x80, + // '6' (0x36) 5x5, offset 55-59, at +0/-4 + // in regular row-major format + 0xfc, 0x3f, 0x1f, 0x80, + // '7' (0x37) 5x5, offset 59-63, at +0/-4 + // in regular row-major format + 0xf8, 0x42, 0x10, 0x80, + // '8' (0x38) 5x5, offset 63-67, at +0/-4 + // in regular row-major format + 0xfc, 0x7f, 0x1f, 0x80, + // '9' (0x39) 5x5, offset 67-71, at +0/-4 + // in regular row-major format + 0xfc, 0x7e, 0x1f, 0x80, + // ':' (0x3a) 1x4, offset 71-72, at +0/-3 + // in regular row-major format + 0x90, + // ';' (0x3b) 1x4, offset 72-73, at +0/-3 + // in regular row-major format + 0xb0, + // '<' (0x3c) 3x5, offset 73-75, at +0/-4 + // in regular row-major format + 0x2a, 0x22, + // '=' (0x3d) 4x3, offset 75-77, at +0/-3 + // in regular row-major format + 0xf0, 0xf0, + // '>' (0x3e) 3x5, offset 77-79, at +0/-4 + // in regular row-major format + 0x88, 0xa8, + // '?' (0x3f) 5x5, offset 79-83, at +0/-4 + // in regular row-major format + 0xf8, 0x4e, 0x02, 0x00, + // '@' (0x40) 5x5, offset 83-87, at +0/-4 + // in regular row-major format + 0xfd, 0x6f, 0x0f, 0x80, + // 'A' (0x41) 5x5, offset 87-91, at +0/-4 + // in regular row-major format + 0xfc, 0x7f, 0x18, 0x80, + // 'B' (0x42) 5x5, offset 91-95, at +0/-4 + // in regular row-major format + 0xf4, 0x7d, 0x1f, 0x00, + // 'C' (0x43) 5x5, offset 95-99, at +0/-4 + // in regular row-major format + 0xfc, 0x21, 0x0f, 0x80, + // 'D' (0x44) 5x5, offset 99-103, at +0/-4 + // in regular row-major format + 0xf4, 0x63, 0x1f, 0x00, + // 'E' (0x45) 5x5, offset 103-107, at +0/-4 + // in regular row-major format + 0xfc, 0x3f, 0x0f, 0x80, + // 'F' (0x46) 5x5, offset 107-111, at +0/-4 + // in regular row-major format + 0xfc, 0x3f, 0x08, 0x00, + // 'G' (0x47) 5x5, offset 111-115, at +0/-4 + // in regular row-major format + 0xfc, 0x2f, 0x1f, 0x80, + // 'H' (0x48) 5x5, offset 115-119, at +0/-4 + // in regular row-major format + 0x8c, 0x7f, 0x18, 0x80, + // 'I' (0x49) 5x5, offset 119-123, at +0/-4 + // in regular row-major format + 0xf9, 0x08, 0x4f, 0x80, + // 'J' (0x4a) 5x5, offset 123-127, at +0/-4 + // in regular row-major format + 0x78, 0x85, 0x2f, 0x80, + // 'K' (0x4b) 5x5, offset 127-131, at +0/-4 + // in regular row-major format + 0x8d, 0xb1, 0x68, 0x80, + // 'L' (0x4c) 5x5, offset 131-135, at +0/-4 + // in regular row-major format + 0x84, 0x21, 0x0f, 0x80, + // 'M' (0x4d) 5x5, offset 135-139, at +0/-4 + // in regular row-major format + 0xfd, 0x6b, 0x5a, 0x80, + // 'N' (0x4e) 5x5, offset 139-143, at +0/-4 + // in regular row-major format + 0xfc, 0x63, 0x18, 0x80, + // 'O' (0x4f) 5x5, offset 143-147, at +0/-4 + // in regular row-major format + 0xfc, 0x63, 0x1f, 0x80, + // 'P' (0x50) 5x5, offset 147-151, at +0/-4 + // in regular row-major format + 0xfc, 0x7f, 0x08, 0x00, + // 'Q' (0x51) 5x5, offset 151-155, at +0/-4 + // in regular row-major format + 0xfc, 0x63, 0x3f, 0x80, + // 'R' (0x52) 5x5, offset 155-159, at +0/-4 + // in regular row-major format + 0xfc, 0x7f, 0x29, 0x00, + // 'S' (0x53) 5x5, offset 159-163, at +0/-4 + // in regular row-major format + 0xfc, 0x3e, 0x1f, 0x80, + // 'T' (0x54) 5x5, offset 163-167, at +0/-4 + // in regular row-major format + 0xf9, 0x08, 0x42, 0x00, + // 'U' (0x55) 5x5, offset 167-171, at +0/-4 + // in regular row-major format + 0x8c, 0x63, 0x1f, 0x80, + // 'V' (0x56) 5x5, offset 171-175, at +0/-4 + // in regular row-major format + 0x8c, 0x62, 0xa2, 0x00, + // 'W' (0x57) 5x5, offset 175-179, at +0/-4 + // in regular row-major format + 0xad, 0x6b, 0x5f, 0x80, + // 'X' (0x58) 5x5, offset 179-183, at +0/-4 + // in regular row-major format + 0x8a, 0x88, 0xa8, 0x80, + // 'Y' (0x59) 5x5, offset 183-187, at +0/-4 + // in regular row-major format + 0x8c, 0x54, 0x42, 0x00, + // 'Z' (0x5a) 5x5, offset 187-191, at +0/-4 + // in regular row-major format + 0xf8, 0x7f, 0x0f, 0x80, + // '[' (0x5b) 2x5, offset 191-193, at +0/-4 + // in regular row-major format + 0xea, 0xc0, + // '\' (0x5c) 5x5, offset 193-197, at +0/-4 + // in regular row-major format + 0x82, 0x08, 0x20, 0x80, + // ']' (0x5d) 2x5, offset 197-199, at +0/-4 + // in regular row-major format + 0xd5, 0xc0, + // '^' (0x5e) 3x2, offset 199-200, at +0/-4 + // in regular row-major format + 0x54, + // '_' (0x5f) 5x1, offset 200-201, at +0/+1 + // in regular row-major format + 0xf8, + // '`' (0x60) 1x1, offset 201-202, at +0/-4 + // in regular row-major format + 0x80, + // 'a' (0x61) 4x4, offset 202-204, at +0/-3 + // in regular row-major format + 0xf1, 0xff, + // 'b' (0x62) 4x5, offset 204-207, at +0/-4 + // in regular row-major format + 0x8f, 0x99, 0xf0, + // 'c' (0x63) 4x4, offset 207-209, at +0/-3 + // in regular row-major format + 0xf8, 0x8f, + // 'd' (0x64) 4x5, offset 209-212, at +0/-4 + // in regular row-major format + 0x1f, 0x99, 0xf0, + // 'e' (0x65) 4x4, offset 212-214, at +0/-3 + // in regular row-major format + 0xff, 0x8f, + // 'f' (0x66) 3x5, offset 214-216, at +0/-4 + // in regular row-major format + 0x6b, 0xa4, + // 'g' (0x67) 4x5, offset 216-219, at +0/-3 + // in regular row-major format + 0xf9, 0x9f, 0x10, + // 'h' (0x68) 4x5, offset 219-222, at +0/-4 + // in regular row-major format + 0x8f, 0x99, 0x90, + // 'i' (0x69) 1x4, offset 222-223, at +0/-3 + // in regular row-major format + 0xf0, + // 'j' (0x6a) 2x5, offset 223-225, at +0/-3 + // in regular row-major format + 0x55, 0xc0, + // 'k' (0x6b) 4x5, offset 225-228, at +0/-4 + // in regular row-major format + 0x8a, 0xf9, 0x90, + // 'l' (0x6c) 1x5, offset 228-229, at +0/-4 + // in regular row-major format + 0xf8, + // 'm' (0x6d) 5x4, offset 229-232, at +0/-3 + // in regular row-major format + 0xfd, 0x63, 0x10, + // 'n' (0x6e) 4x4, offset 232-234, at +0/-3 + // in regular row-major format + 0xf9, 0x99, + // 'o' (0x6f) 4x4, offset 234-236, at +0/-3 + // in regular row-major format + 0xf9, 0x9f, + // 'p' (0x70) 4x5, offset 236-239, at +0/-3 + // in regular row-major format + 0xf9, 0x9f, 0x80, + // 'q' (0x71) 4x5, offset 239-242, at +0/-3 + // in regular row-major format + 0xf9, 0x9f, 0x20, + // 'r' (0x72) 4x4, offset 242-244, at +0/-3 + // in regular row-major format + 0xf8, 0x88, + // 's' (0x73) 4x4, offset 244-246, at +0/-3 + // in regular row-major format + 0x47, 0x1f, + // 't' (0x74) 5x5, offset 246-250, at +0/-4 + // in regular row-major format + 0x27, 0xc8, 0x42, 0x00, + // 'u' (0x75) 4x4, offset 250-252, at +0/-3 + // in regular row-major format + 0x99, 0x9f, + // 'v' (0x76) 4x4, offset 252-254, at +0/-3 + // in regular row-major format + 0x99, 0x97, + // 'w' (0x77) 5x4, offset 254-257, at +0/-3 + // in regular row-major format + 0x8c, 0x6b, 0xf0, + // 'x' (0x78) 4x4, offset 257-259, at +0/-3 + // in regular row-major format + 0x96, 0x69, + // 'y' (0x79) 4x5, offset 259-262, at +0/-3 + // in regular row-major format + 0x99, 0x9f, 0x10, + // 'z' (0x7a) 4x4, offset 262-264, at +0/-3 + // in regular row-major format + 0x2e, 0x8f, + // '{' (0x7b) 3x5, offset 264-266, at +0/-4 + // in regular row-major format + 0x2b, 0x22, + // '|' (0x7c) 1x5, offset 266-267, at +0/-4 + // in regular row-major format + 0xf8, + // '}' (0x7d) 3x5, offset 267-269, at +0/-4 + // in regular row-major format + 0x89, 0xa8, +}; + + +static const uint8_t OpenSansLight10_generic[] = { + // ' ' (0x20) 1x1, offset 0-1, at +0/+0 + // in regular row-major format + 0x00, + // '!' (0x21) 3x7, offset 1-4, at +0/-7 + // in regular row-major format + 0x49, 0x20, 0x10, + // '"' (0x22) 3x3, offset 4-6, at +1/-7 + // in regular row-major format + 0xd8, 0x00, + // '#' (0x23) 7x7, offset 6-13, at +0/-7 + // in regular row-major format + 0x28, 0x51, 0xf2, 0x4f, 0x8a, 0x14, 0x00, + // '$' (0x24) 5x9, offset 13-19, at +1/-8 + // in regular row-major format + 0x03, 0xb1, 0x86, 0x29, 0x5c, 0x00, + // '%' (0x25) 7x7, offset 19-26, at +1/-7 + // in regular row-major format + 0xc9, 0x52, 0xc7, 0x63, 0x4a, 0x93, 0x00, + // '&' (0x26) 7x7, offset 26-33, at +1/-7 + // in regular row-major format + 0x61, 0x22, 0x82, 0x0a, 0x13, 0x3e, 0x00, + // ''' (0x27) 3x3, offset 33-35, at +0/-7 + // in regular row-major format + 0x90, 0x00, + // '(' (0x28) 4x9, offset 35-40, at +0/-7 + // in regular row-major format + 0x44, 0x88, 0x88, 0x84, 0x40, + // ')' (0x29) 4x9, offset 40-45, at +0/-7 + // in regular row-major format + 0x44, 0x22, 0x22, 0x24, 0x40, + // '*' (0x2a) 5x4, offset 45-48, at +1/-7 + // in regular row-major format + 0x42, 0x19, 0x20, + // '+' (0x2b) 5x5, offset 48-52, at +1/-6 + // in regular row-major format + 0x02, 0x3c, 0x80, 0x00, + // ',' (0x2c) 2x2, offset 52-53, at +0/-1 + // in regular row-major format + 0xa0, + // '-' (0x2d) 4x1, offset 53-54, at +0/-3 + // in regular row-major format + 0xe0, + // '.' (0x2e) 3x1, offset 54-55, at +0/-1 + // in regular row-major format + 0x40, + // '/' (0x2f) 4x7, offset 55-59, at +0/-7 + // in regular row-major format + 0x22, 0x44, 0x48, 0x80, + // '0' (0x30) 5x7, offset 59-64, at +1/-7 + // in regular row-major format + 0x64, 0xa5, 0x29, 0x49, 0x80, + // '1' (0x31) 3x7, offset 64-67, at +1/-7 + // in regular row-major format + 0x59, 0x24, 0x80, + // '2' (0x32) 5x7, offset 67-72, at +1/-7 + // in regular row-major format + 0xe0, 0x84, 0x44, 0x43, 0xc0, + // '3' (0x33) 6x7, offset 72-78, at +0/-7 + // in regular row-major format + 0x78, 0x20, 0x8c, 0x08, 0x27, 0x80, + // '4' (0x34) 7x7, offset 78-85, at +0/-7 + // in regular row-major format + 0x18, 0x51, 0x22, 0x4f, 0xc1, 0x02, 0x00, + // '5' (0x35) 5x7, offset 85-90, at +1/-7 + // in regular row-major format + 0xf4, 0x21, 0xe1, 0x0b, 0xc0, + // '6' (0x36) 5x7, offset 90-95, at +1/-7 + // in regular row-major format + 0x74, 0x3d, 0x29, 0x49, 0xc0, + // '7' (0x37) 5x7, offset 95-100, at +1/-7 + // in regular row-major format + 0xf0, 0x84, 0x42, 0x21, 0x00, + // '8' (0x38) 5x7, offset 100-105, at +1/-7 + // in regular row-major format + 0xf4, 0xa4, 0xc9, 0x4b, 0xc0, + // '9' (0x39) 5x7, offset 105-110, at +1/-7 + // in regular row-major format + 0xe4, 0xa5, 0x2f, 0x0b, 0x80, + // ':' (0x3a) 3x5, offset 110-112, at +0/-5 + // in regular row-major format + 0x40, 0x04, + // ';' (0x3b) 2x6, offset 112-114, at +0/-5 + // in regular row-major format + 0x80, 0x20, + // '<' (0x3c) 5x5, offset 114-118, at +1/-6 + // in regular row-major format + 0x13, 0x20, 0xc1, 0x00, + // '=' (0x3d) 5x3, offset 118-120, at +1/-5 + // in regular row-major format + 0xf0, 0x3c, + // '>' (0x3e) 5x5, offset 120-124, at +1/-6 + // in regular row-major format + 0x83, 0x04, 0xc8, 0x00, + // '?' (0x3f) 5x7, offset 124-129, at +0/-7 + // in regular row-major format + 0x60, 0x84, 0x44, 0x01, 0x00, + // '@' (0x40) 8x8, offset 129-137, at +1/-7 + // in regular row-major format + 0x7c, 0x82, 0xba, 0xca, 0xca, 0xbe, 0x80, 0x78, + // 'A' (0x41) 7x7, offset 137-144, at +0/-7 + // in regular row-major format + 0x10, 0x60, 0xc2, 0x47, 0x90, 0xa1, 0x00, + // 'B' (0x42) 5x7, offset 144-149, at +1/-7 + // in regular row-major format + 0xf4, 0xa5, 0xc9, 0x4b, 0xc0, + // 'C' (0x43) 6x7, offset 149-155, at +1/-7 + // in regular row-major format + 0x72, 0x08, 0x20, 0x82, 0x07, 0x00, + // 'D' (0x44) 6x7, offset 155-161, at +1/-7 + // in regular row-major format + 0xf2, 0x28, 0xa2, 0x8a, 0x2f, 0x00, + // 'E' (0x45) 5x7, offset 161-166, at +1/-7 + // in regular row-major format + 0xf4, 0x21, 0xe8, 0x43, 0xc0, + // 'F' (0x46) 5x7, offset 166-171, at +1/-7 + // in regular row-major format + 0xf4, 0x21, 0xe8, 0x42, 0x00, + // 'G' (0x47) 6x7, offset 171-177, at +1/-7 + // in regular row-major format + 0x7a, 0x08, 0x26, 0x8a, 0x27, 0x80, + // 'H' (0x48) 6x7, offset 177-183, at +1/-7 + // in regular row-major format + 0x8a, 0x28, 0xbe, 0x8a, 0x28, 0x80, + // 'I' (0x49) 2x7, offset 183-185, at +1/-7 + // in regular row-major format + 0xaa, 0xa8, + // 'J' (0x4a) 3x9, offset 185-189, at -1/-7 + // in regular row-major format + 0x49, 0x24, 0x92, 0xc0, + // 'K' (0x4b) 6x7, offset 189-195, at +1/-7 + // in regular row-major format + 0x8a, 0x4a, 0x38, 0xa2, 0x48, 0x80, + // 'L' (0x4c) 5x7, offset 195-200, at +1/-7 + // in regular row-major format + 0x84, 0x21, 0x08, 0x43, 0xc0, + // 'M' (0x4d) 8x7, offset 200-207, at +1/-7 + // in regular row-major format + 0x82, 0x82, 0xc6, 0xaa, 0xaa, 0xaa, 0x92, + // 'N' (0x4e) 6x7, offset 207-213, at +1/-7 + // in regular row-major format + 0x82, 0x2c, 0xaa, 0x9a, 0x60, 0x80, + // 'O' (0x4f) 7x7, offset 213-220, at +1/-7 + // in regular row-major format + 0x79, 0x0a, 0x14, 0x28, 0x50, 0x9e, 0x00, + // 'P' (0x50) 5x7, offset 220-225, at +1/-7 + // in regular row-major format + 0xf4, 0xa5, 0x2f, 0x42, 0x00, + // 'Q' (0x51) 7x9, offset 225-233, at +1/-7 + // in regular row-major format + 0x79, 0x0a, 0x14, 0x28, 0x50, 0x9e, 0x04, 0x08, + // 'R' (0x52) 6x7, offset 233-239, at +1/-7 + // in regular row-major format + 0xf2, 0x49, 0x3c, 0xa2, 0x48, 0x80, + // 'S' (0x53) 5x7, offset 239-244, at +1/-7 + // in regular row-major format + 0xe4, 0x20, 0xc1, 0x0b, 0x80, + // 'T' (0x54) 6x7, offset 244-250, at +0/-7 + // in regular row-major format + 0xf8, 0x82, 0x08, 0x20, 0x82, 0x00, + // 'U' (0x55) 6x7, offset 250-256, at +1/-7 + // in regular row-major format + 0x8a, 0x28, 0xa2, 0x8a, 0x27, 0x00, + // 'V' (0x56) 7x7, offset 256-263, at +0/-7 + // in regular row-major format + 0x85, 0x09, 0x22, 0x43, 0x06, 0x08, 0x00, + // 'W' (0x57) 10x7, offset 263-272, at +0/-7 + // in regular row-major format + 0x88, 0xa6, 0x25, 0x51, 0x54, 0x55, 0x08, 0x82, + 0x20, + // 'X' (0x58) 6x7, offset 272-278, at +0/-7 + // in regular row-major format + 0x89, 0x45, 0x08, 0x51, 0x48, 0x80, + // 'Y' (0x59) 6x7, offset 278-284, at +0/-7 + // in regular row-major format + 0x89, 0x45, 0x08, 0x20, 0x82, 0x00, + // 'Z' (0x5a) 7x7, offset 284-291, at +0/-7 + // in regular row-major format + 0x78, 0x10, 0x41, 0x02, 0x08, 0x3f, 0x00, + // '[' (0x5b) 3x9, offset 291-295, at +1/-7 + // in regular row-major format + 0x92, 0x49, 0x24, 0x80, + // '\' (0x5c) 4x7, offset 295-299, at +0/-7 + // in regular row-major format + 0x88, 0x44, 0x42, 0x20, + // ']' (0x5d) 3x9, offset 299-303, at +0/-7 + // in regular row-major format + 0x49, 0x24, 0x92, 0x40, + // '^' (0x5e) 7x4, offset 303-307, at +0/-7 + // in regular row-major format + 0x10, 0x61, 0x20, 0x00, + // '_' (0x5f) 5x1, offset 307-308, at +0/+1 + // in regular row-major format + 0xf0, + // '`' (0x60) 3x2, offset 308-309, at +2/-8 + // in regular row-major format + 0x88, + // 'a' (0x61) 5x5, offset 309-313, at +0/-5 + // in regular row-major format + 0x70, 0x9d, 0x26, 0x00, + // 'b' (0x62) 5x7, offset 313-318, at +1/-7 + // in regular row-major format + 0x04, 0x3d, 0x29, 0x49, 0xc0, + // 'c' (0x63) 5x5, offset 318-322, at +1/-5 + // in regular row-major format + 0x74, 0x21, 0x0f, 0x00, + // 'd' (0x64) 5x7, offset 322-327, at +1/-7 + // in regular row-major format + 0x00, 0xbd, 0x29, 0x4b, 0x80, + // 'e' (0x65) 4x5, offset 327-330, at +1/-5 + // in regular row-major format + 0xea, 0xe8, 0xe0, + // 'f' (0x66) 5x7, offset 330-335, at +0/-7 + // in regular row-major format + 0x72, 0x38, 0x84, 0x21, 0x00, + // 'g' (0x67) 6x7, offset 335-341, at +0/-5 + // in regular row-major format + 0x7a, 0x47, 0x10, 0x72, 0x27, 0x00, + // 'h' (0x68) 5x7, offset 341-346, at +1/-7 + // in regular row-major format + 0x04, 0x3d, 0x29, 0x48, 0x00, + // 'i' (0x69) 3x7, offset 346-349, at +0/-7 + // in regular row-major format + 0x40, 0x24, 0x80, + // 'j' (0x6a) 3x9, offset 349-353, at -1/-7 + // in regular row-major format + 0x40, 0x24, 0x92, 0xc0, + // 'k' (0x6b) 5x7, offset 353-358, at +1/-7 + // in regular row-major format + 0x04, 0x25, 0x4c, 0x50, 0x40, + // 'l' (0x6c) 3x7, offset 358-361, at +0/-7 + // in regular row-major format + 0x09, 0x24, 0x80, + // 'm' (0x6d) 8x5, offset 361-366, at +1/-5 + // in regular row-major format + 0x6e, 0x92, 0x92, 0x92, 0x10, + // 'n' (0x6e) 5x5, offset 366-370, at +1/-5 + // in regular row-major format + 0x74, 0xa5, 0x20, 0x00, + // 'o' (0x6f) 5x5, offset 370-374, at +1/-5 + // in regular row-major format + 0xf4, 0xa5, 0x2f, 0x00, + // 'p' (0x70) 5x7, offset 374-379, at +1/-5 + // in regular row-major format + 0x74, 0xa5, 0x2f, 0x40, 0x00, + // 'q' (0x71) 5x7, offset 379-384, at +1/-5 + // in regular row-major format + 0xe4, 0xa5, 0x2f, 0x08, 0x00, + // 'r' (0x72) 4x5, offset 384-387, at +1/-5 + // in regular row-major format + 0x68, 0x88, 0x00, + // 's' (0x73) 5x5, offset 387-391, at +0/-5 + // in regular row-major format + 0x74, 0x18, 0x27, 0x00, + // 't' (0x74) 4x6, offset 391-394, at +0/-6 + // in regular row-major format + 0x0e, 0x44, 0x46, + // 'u' (0x75) 5x5, offset 394-398, at +1/-5 + // in regular row-major format + 0x04, 0xa5, 0x2e, 0x00, + // 'v' (0x76) 6x5, offset 398-402, at +0/-5 + // in regular row-major format + 0x8a, 0x25, 0x14, 0x20, + // 'w' (0x77) 8x5, offset 402-407, at +0/-5 + // in regular row-major format + 0x92, 0x92, 0x6c, 0x6c, 0x44, + // 'x' (0x78) 6x5, offset 407-411, at +0/-5 + // in regular row-major format + 0x51, 0x42, 0x14, 0x88, + // 'y' (0x79) 6x7, offset 411-417, at +0/-5 + // in regular row-major format + 0x8a, 0x25, 0x14, 0x20, 0x8c, 0x00, + // 'z' (0x7a) 6x5, offset 417-421, at +0/-5 + // in regular row-major format + 0x78, 0x42, 0x10, 0xf8, + // '{' (0x7b) 5x9, offset 421-427, at +0/-7 + // in regular row-major format + 0x22, 0x10, 0x84, 0x21, 0x08, 0x20, + // '|' (0x7c) 2x9, offset 427-430, at +2/-7 + // in regular row-major format + 0xaa, 0xaa, 0x80, +}; + + +static const uint8_t OpenSansLight12_generic[] = { + // ' ' (0x20) 1x1, offset 0-1, at +0/+0 + // in regular row-major format + 0x00, + // '!' (0x21) 2x9, offset 1-4, at +1/-9 + // in regular row-major format + 0xaa, 0xa8, 0x80, + // '"' (0x22) 3x3, offset 4-6, at +1/-9 + // in regular row-major format + 0xd8, 0x00, + // '#' (0x23) 9x9, offset 6-17, at +0/-9 + // in regular row-major format + 0x12, 0x0a, 0x1f, 0xc4, 0x82, 0x47, 0xf0, 0xa0, + 0x50, 0x48, 0x00, + // '$' (0x24) 6x10, offset 17-25, at +1/-9 + // in regular row-major format + 0x21, 0xca, 0x28, 0x70, 0xa2, 0x8a, 0xf0, 0x80, + // '%' (0x25) 9x9, offset 25-36, at +1/-9 + // in regular row-major format + 0xc2, 0x52, 0x29, 0x15, 0xeb, 0x57, 0xa8, 0x94, + 0x4a, 0x43, 0x00, + // '&' (0x26) 9x9, offset 36-47, at +1/-9 + // in regular row-major format + 0x70, 0x24, 0x12, 0x0a, 0x06, 0x04, 0x92, 0x29, + 0x08, 0x7a, 0x00, + // ''' (0x27) 3x3, offset 47-49, at +0/-9 + // in regular row-major format + 0x48, 0x00, + // '(' (0x28) 4x11, offset 49-55, at +0/-9 + // in regular row-major format + 0x24, 0x48, 0x88, 0x88, 0x44, 0x20, + // ')' (0x29) 4x11, offset 55-61, at +0/-9 + // in regular row-major format + 0x84, 0x42, 0x22, 0x22, 0x44, 0x80, + // '*' (0x2a) 6x5, offset 61-65, at +1/-9 + // in regular row-major format + 0x20, 0x8f, 0x94, 0x50, + // '+' (0x2b) 6x7, offset 65-71, at +1/-8 + // in regular row-major format + 0x20, 0x82, 0x3e, 0x20, 0x82, 0x00, + // ',' (0x2c) 3x3, offset 71-73, at +0/-1 + // in regular row-major format + 0x4a, 0x00, + // '-' (0x2d) 3x1, offset 73-74, at +1/-3 + // in regular row-major format + 0xc0, + // '.' (0x2e) 2x1, offset 74-75, at +1/-1 + // in regular row-major format + 0x80, + // '/' (0x2f) 5x9, offset 75-81, at +0/-9 + // in regular row-major format + 0x10, 0x88, 0x44, 0x21, 0x10, 0x80, + // '0' (0x30) 6x9, offset 81-88, at +1/-9 + // in regular row-major format + 0x72, 0x28, 0xa2, 0x8a, 0x28, 0xa2, 0x70, + // '1' (0x31) 4x9, offset 88-93, at +1/-9 + // in regular row-major format + 0x26, 0x22, 0x22, 0x22, 0x20, + // '2' (0x32) 6x9, offset 93-100, at +1/-9 + // in regular row-major format + 0x72, 0x20, 0x82, 0x10, 0x84, 0x20, 0xf8, + // '3' (0x33) 6x9, offset 100-107, at +1/-9 + // in regular row-major format + 0x72, 0x20, 0x82, 0x70, 0x20, 0x82, 0xf0, + // '4' (0x34) 8x9, offset 107-116, at +0/-9 + // in regular row-major format + 0x08, 0x14, 0x14, 0x24, 0x44, 0x44, 0xfe, 0x04, + 0x04, + // '5' (0x35) 6x9, offset 116-123, at +1/-9 + // in regular row-major format + 0xfa, 0x08, 0x20, 0xf0, 0x20, 0x82, 0xf0, + // '6' (0x36) 6x9, offset 123-130, at +1/-9 + // in regular row-major format + 0x39, 0x08, 0x3c, 0x8a, 0x28, 0xa2, 0x70, + // '7' (0x37) 6x9, offset 130-137, at +1/-9 + // in regular row-major format + 0xf8, 0x20, 0x84, 0x10, 0x82, 0x08, 0x40, + // '8' (0x38) 6x9, offset 137-144, at +1/-9 + // in regular row-major format + 0x72, 0x28, 0xa2, 0x72, 0x28, 0xa2, 0x70, + // '9' (0x39) 6x9, offset 144-151, at +1/-9 + // in regular row-major format + 0x72, 0x28, 0xa2, 0x89, 0xe0, 0x84, 0xe0, + // ':' (0x3a) 2x6, offset 151-153, at +1/-6 + // in regular row-major format + 0x80, 0x20, + // ';' (0x3b) 3x8, offset 153-156, at +0/-6 + // in regular row-major format + 0x40, 0x00, 0x90, + // '<' (0x3c) 6x6, offset 156-161, at +1/-8 + // in regular row-major format + 0x08, 0xc4, 0x30, 0x30, 0x20, + // '=' (0x3d) 6x3, offset 161-164, at +1/-6 + // in regular row-major format + 0xf8, 0x0f, 0x80, + // '>' (0x3e) 6x6, offset 164-169, at +1/-8 + // in regular row-major format + 0x81, 0x81, 0x06, 0x62, 0x00, + // '?' (0x3f) 6x9, offset 169-176, at +0/-9 + // in regular row-major format + 0x70, 0x20, 0x82, 0x10, 0x80, 0x00, 0x40, + // '@' (0x40) 10x10, offset 176-189, at +1/-9 + // in regular row-major format + 0x3e, 0x10, 0x49, 0xea, 0x8a, 0xa2, 0xa8, 0xaa, + 0x2a, 0x7c, 0xc0, 0x0f, 0x80, + // 'A' (0x41) 8x9, offset 189-198, at +0/-9 + // in regular row-major format + 0x10, 0x10, 0x28, 0x28, 0x44, 0x7c, 0x44, 0x82, + 0x82, + // 'B' (0x42) 7x9, offset 198-206, at +1/-9 + // in regular row-major format + 0xf9, 0x0a, 0x14, 0x2f, 0x90, 0xa1, 0x42, 0xf8, + // 'C' (0x43) 7x9, offset 206-214, at +1/-9 + // in regular row-major format + 0x38, 0x82, 0x04, 0x08, 0x10, 0x20, 0x60, 0x78, + // 'D' (0x44) 7x9, offset 214-222, at +1/-9 + // in regular row-major format + 0xf1, 0x1a, 0x14, 0x28, 0x50, 0xa1, 0x44, 0xf0, + // 'E' (0x45) 6x9, offset 222-229, at +1/-9 + // in regular row-major format + 0xfa, 0x08, 0x20, 0xfa, 0x08, 0x20, 0xf8, + // 'F' (0x46) 6x9, offset 229-236, at +1/-9 + // in regular row-major format + 0xfa, 0x08, 0x20, 0xfa, 0x08, 0x20, 0x80, + // 'G' (0x47) 8x9, offset 236-245, at +1/-9 + // in regular row-major format + 0x3c, 0x40, 0x80, 0x80, 0x8e, 0x82, 0x82, 0x42, + 0x3e, + // 'H' (0x48) 8x9, offset 245-254, at +1/-9 + // in regular row-major format + 0x82, 0x82, 0x82, 0x82, 0xfe, 0x82, 0x82, 0x82, + 0x82, + // 'I' (0x49) 2x9, offset 254-257, at +1/-9 + // in regular row-major format + 0xaa, 0xaa, 0x80, + // 'J' (0x4a) 4x11, offset 257-263, at -1/-9 + // in regular row-major format + 0x22, 0x22, 0x22, 0x22, 0x22, 0xc0, + // 'K' (0x4b) 7x9, offset 263-271, at +1/-9 + // in regular row-major format + 0x85, 0x12, 0x45, 0x0e, 0x12, 0x24, 0x44, 0x84, + // 'L' (0x4c) 6x9, offset 271-278, at +1/-9 + // in regular row-major format + 0x82, 0x08, 0x20, 0x82, 0x08, 0x20, 0xf8, + // 'M' (0x4d) 9x9, offset 278-289, at +1/-9 + // in regular row-major format + 0x81, 0x61, 0xb0, 0xd4, 0xaa, 0x55, 0x2a, 0x65, + 0x32, 0x91, 0x00, + // 'N' (0x4e) 8x9, offset 289-298, at +1/-9 + // in regular row-major format + 0x82, 0xc2, 0xa2, 0xa2, 0x92, 0x8a, 0x8a, 0x86, + 0x82, + // 'O' (0x4f) 8x9, offset 298-307, at +1/-9 + // in regular row-major format + 0x38, 0x44, 0x82, 0x82, 0x82, 0x82, 0x82, 0x44, + 0x38, + // 'P' (0x50) 6x9, offset 307-314, at +1/-9 + // in regular row-major format + 0xf2, 0x28, 0xa2, 0x8b, 0xc8, 0x20, 0x80, + // 'Q' (0x51) 8x11, offset 314-325, at +1/-9 + // in regular row-major format + 0x38, 0x44, 0x82, 0x82, 0x82, 0x82, 0x82, 0x44, + 0x38, 0x08, 0x04, + // 'R' (0x52) 7x9, offset 325-333, at +1/-9 + // in regular row-major format + 0xf1, 0x12, 0x24, 0x4f, 0x12, 0x22, 0x44, 0x84, + // 'S' (0x53) 6x9, offset 333-340, at +1/-9 + // in regular row-major format + 0x7a, 0x08, 0x20, 0x70, 0x20, 0x82, 0xf0, + // 'T' (0x54) 7x9, offset 340-348, at +0/-9 + // in regular row-major format + 0xfc, 0x20, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10, + // 'U' (0x55) 8x9, offset 348-357, at +1/-9 + // in regular row-major format + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x44, + 0x78, + // 'V' (0x56) 8x9, offset 357-366, at +0/-9 + // in regular row-major format + 0x82, 0x82, 0x44, 0x44, 0x44, 0x28, 0x28, 0x28, + 0x10, + // 'W' (0x57) 12x9, offset 366-380, at +0/-9 + // in regular row-major format + 0x84, 0x24, 0xc4, 0x4a, 0x44, 0xa4, 0x4a, 0x43, + 0x18, 0x31, 0x83, 0x18, 0x20, 0x80, + // 'X' (0x58) 7x9, offset 380-388, at +0/-9 + // in regular row-major format + 0x84, 0x91, 0x21, 0x81, 0x06, 0x12, 0x24, 0x84, + // 'Y' (0x59) 7x9, offset 388-396, at +0/-9 + // in regular row-major format + 0x84, 0x91, 0x21, 0x43, 0x02, 0x04, 0x08, 0x10, + // 'Z' (0x5a) 8x9, offset 396-405, at +0/-9 + // in regular row-major format + 0x7c, 0x04, 0x08, 0x08, 0x10, 0x20, 0x20, 0x40, + 0xfe, + // '[' (0x5b) 4x11, offset 405-411, at +1/-9 + // in regular row-major format + 0xe8, 0x88, 0x88, 0x88, 0x88, 0xe0, + // '\' (0x5c) 5x9, offset 411-417, at +0/-9 + // in regular row-major format + 0x84, 0x10, 0x84, 0x10, 0x82, 0x10, + // ']' (0x5d) 4x11, offset 417-423, at +0/-9 + // in regular row-major format + 0xe2, 0x22, 0x22, 0x22, 0x22, 0xe0, + // '^' (0x5e) 6x5, offset 423-427, at +1/-9 + // in regular row-major format + 0x21, 0x45, 0x22, 0x88, + // '_' (0x5f) 6x1, offset 427-428, at +0/+1 + // in regular row-major format + 0xf8, + // '`' (0x60) 4x2, offset 428-429, at +2/-9 + // in regular row-major format + 0x44, + // 'a' (0x61) 5x6, offset 429-433, at +1/-6 + // in regular row-major format + 0x70, 0xbd, 0x29, 0x78, + // 'b' (0x62) 6x9, offset 433-440, at +1/-9 + // in regular row-major format + 0x82, 0x08, 0x3c, 0x8a, 0x28, 0xa2, 0x70, + // 'c' (0x63) 6x6, offset 440-445, at +1/-6 + // in regular row-major format + 0x72, 0x08, 0x20, 0x81, 0xc0, + // 'd' (0x64) 6x9, offset 445-452, at +1/-9 + // in regular row-major format + 0x08, 0x20, 0x9e, 0x8a, 0x28, 0xa2, 0x78, + // 'e' (0x65) 6x6, offset 452-457, at +1/-6 + // in regular row-major format + 0x72, 0x2f, 0xa0, 0x81, 0xe0, + // 'f' (0x66) 5x9, offset 457-463, at +0/-9 + // in regular row-major format + 0x32, 0x11, 0xe4, 0x21, 0x08, 0x40, + // 'g' (0x67) 7x9, offset 463-471, at +0/-6 + // in regular row-major format + 0x7c, 0x91, 0x23, 0x84, 0x0f, 0x21, 0x42, 0x78, + // 'h' (0x68) 6x9, offset 471-478, at +1/-9 + // in regular row-major format + 0x82, 0x08, 0x3c, 0x8a, 0x28, 0xa2, 0x88, + // 'i' (0x69) 2x9, offset 478-481, at +1/-9 + // in regular row-major format + 0x82, 0xaa, 0x80, + // 'j' (0x6a) 3x12, offset 481-486, at +0/-9 + // in regular row-major format + 0x40, 0x24, 0x92, 0x49, 0x40, + // 'k' (0x6b) 6x9, offset 486-493, at +1/-9 + // in regular row-major format + 0x82, 0x08, 0x24, 0xa3, 0x0a, 0x24, 0x88, + // 'l' (0x6c) 2x9, offset 493-496, at +1/-9 + // in regular row-major format + 0xaa, 0xaa, 0x80, + // 'm' (0x6d) 10x6, offset 496-504, at +1/-6 + // in regular row-major format + 0xf7, 0x22, 0x28, 0x8a, 0x22, 0x88, 0xa2, 0x20, + // 'n' (0x6e) 6x6, offset 504-509, at +1/-6 + // in regular row-major format + 0xf2, 0x28, 0xa2, 0x8a, 0x20, + // 'o' (0x6f) 6x6, offset 509-514, at +1/-6 + // in regular row-major format + 0x72, 0x28, 0xa2, 0x89, 0xc0, + // 'p' (0x70) 6x9, offset 514-521, at +1/-6 + // in regular row-major format + 0xf2, 0x28, 0xa2, 0x8b, 0xc8, 0x20, 0x80, + // 'q' (0x71) 6x9, offset 521-528, at +1/-6 + // in regular row-major format + 0x7a, 0x28, 0xa2, 0x89, 0xe0, 0x82, 0x08, + // 'r' (0x72) 5x6, offset 528-532, at +1/-6 + // in regular row-major format + 0xf4, 0x21, 0x08, 0x40, + // 's' (0x73) 5x6, offset 532-536, at +1/-6 + // in regular row-major format + 0xf4, 0x30, 0x61, 0x78, + // 't' (0x74) 5x8, offset 536-541, at +0/-8 + // in regular row-major format + 0x42, 0x3c, 0x84, 0x21, 0x0e, + // 'u' (0x75) 6x6, offset 541-546, at +1/-6 + // in regular row-major format + 0x8a, 0x28, 0xa2, 0x89, 0xe0, + // 'v' (0x76) 7x6, offset 546-552, at +0/-6 + // in regular row-major format + 0x85, 0x09, 0x22, 0x43, 0x06, 0x00, + // 'w' (0x77) 10x6, offset 552-560, at +0/-6 + // in regular row-major format + 0x88, 0xa2, 0x25, 0x51, 0x54, 0x62, 0x08, 0x80, + // 'x' (0x78) 7x6, offset 560-566, at +0/-6 + // in regular row-major format + 0x48, 0x90, 0xc1, 0x84, 0x89, 0x00, + // 'y' (0x79) 7x9, offset 566-574, at +0/-6 + // in regular row-major format + 0x85, 0x09, 0x22, 0x43, 0x06, 0x08, 0x10, 0xc0, + // 'z' (0x7a) 5x6, offset 574-578, at +1/-6 + // in regular row-major format + 0xf0, 0x88, 0x88, 0x78, + // '{' (0x7b) 5x11, offset 578-585, at +0/-9 + // in regular row-major format + 0x32, 0x10, 0x84, 0x21, 0x08, 0x42, 0x0c, + // '|' (0x7c) 2x12, offset 585-588, at +3/-9 + // in regular row-major format + 0xaa, 0xaa, 0xaa, +}; + + +static const uint8_t OpenSansLight14_generic[] = { + // ' ' (0x20) 1x1, offset 0-1, at +0/+0 + // in regular row-major format + 0x00, + // '!' (0x21) 2x10, offset 1-4, at +1/-10 + // in regular row-major format + 0xaa, 0xa8, 0x20, + // '"' (0x22) 4x4, offset 4-6, at +1/-10 + // in regular row-major format + 0xaa, 0xaa, + // '#' (0x23) 10x10, offset 6-19, at +0/-10 + // in regular row-major format + 0x12, 0x04, 0x81, 0x21, 0xfe, 0x12, 0x09, 0x0f, + 0xf0, 0x90, 0x24, 0x09, 0x00, + // '$' (0x24) 7x12, offset 19-30, at +1/-11 + // in regular row-major format + 0x20, 0xf2, 0x85, 0x0e, 0x0e, 0x0a, 0x12, 0x24, + 0x51, 0xe1, 0x00, + // '%' (0x25) 10x10, offset 30-43, at +1/-10 + // in regular row-major format + 0xe2, 0x24, 0x89, 0x42, 0x50, 0x9b, 0xbb, 0x21, + 0x48, 0x52, 0x24, 0x88, 0xe0, + // '&' (0x26) 10x10, offset 43-56, at +1/-10 + // in regular row-major format + 0x38, 0x11, 0x04, 0x41, 0x20, 0x30, 0x14, 0x08, + 0x92, 0x18, 0x86, 0x1e, 0x40, + // ''' (0x27) 2x4, offset 56-57, at +1/-10 + // in regular row-major format + 0xaa, + // '(' (0x28) 4x12, offset 57-63, at +1/-10 + // in regular row-major format + 0x44, 0x88, 0x88, 0x88, 0x88, 0x44, + // ')' (0x29) 4x12, offset 63-69, at +0/-10 + // in regular row-major format + 0x44, 0x22, 0x22, 0x22, 0x22, 0x44, + // '*' (0x2a) 7x6, offset 69-75, at +1/-11 + // in regular row-major format + 0x20, 0x43, 0xb1, 0x85, 0x09, 0x00, + // '+' (0x2b) 7x7, offset 75-82, at +1/-9 + // in regular row-major format + 0x00, 0x40, 0x87, 0xe2, 0x04, 0x00, 0x00, + // ',' (0x2c) 3x4, offset 82-84, at +0/-2 + // in regular row-major format + 0x49, 0x40, + // '-' (0x2d) 4x1, offset 84-85, at +1/-4 + // in regular row-major format + 0xe0, + // '.' (0x2e) 2x1, offset 85-86, at +1/-1 + // in regular row-major format + 0x80, + // '/' (0x2f) 6x10, offset 86-94, at +0/-10 + // in regular row-major format + 0x08, 0x41, 0x04, 0x20, 0x84, 0x10, 0x42, 0x00, + // '0' (0x30) 7x10, offset 94-103, at +1/-10 + // in regular row-major format + 0x79, 0x9a, 0x14, 0x28, 0x50, 0xa1, 0x42, 0xcc, + 0xf0, + // '1' (0x31) 5x10, offset 103-110, at +1/-10 + // in regular row-major format + 0x32, 0x84, 0x21, 0x08, 0x42, 0x10, 0x80, + // '2' (0x32) 7x10, offset 110-119, at +1/-10 + // in regular row-major format + 0x79, 0x10, 0x10, 0x20, 0x82, 0x08, 0x20, 0x81, + 0xf8, + // '3' (0x33) 7x10, offset 119-128, at +1/-10 + // in regular row-major format + 0x79, 0x08, 0x10, 0x47, 0x01, 0x81, 0x02, 0x0d, + 0xf0, + // '4' (0x34) 9x10, offset 128-140, at +0/-10 + // in regular row-major format + 0x04, 0x06, 0x05, 0x04, 0x82, 0x42, 0x23, 0xfc, + 0x08, 0x04, 0x02, 0x00, + // '5' (0x35) 7x10, offset 140-149, at +1/-10 + // in regular row-major format + 0x79, 0x02, 0x04, 0x0f, 0x80, 0x81, 0x02, 0x05, + 0xf0, + // '6' (0x36) 7x10, offset 149-158, at +1/-10 + // in regular row-major format + 0x38, 0x82, 0x04, 0x0f, 0x90, 0xa1, 0x42, 0x44, + 0xf0, + // '7' (0x37) 7x10, offset 158-167, at +1/-10 + // in regular row-major format + 0xfc, 0x08, 0x10, 0x40, 0x82, 0x04, 0x10, 0x20, + 0x80, + // '8' (0x38) 7x10, offset 167-176, at +1/-10 + // in regular row-major format + 0x79, 0x0a, 0x12, 0x43, 0x09, 0x21, 0x42, 0x84, + 0xf0, + // '9' (0x39) 7x10, offset 176-185, at +1/-10 + // in regular row-major format + 0x79, 0x12, 0x14, 0x28, 0x4f, 0x81, 0x02, 0x09, + 0xe0, + // ':' (0x3a) 2x8, offset 185-187, at +1/-8 + // in regular row-major format + 0x80, 0x02, + // ';' (0x3b) 3x10, offset 187-191, at +0/-8 + // in regular row-major format + 0x40, 0x00, 0x12, 0x40, + // '<' (0x3c) 7x7, offset 191-198, at +1/-9 + // in regular row-major format + 0x04, 0x31, 0x84, 0x06, 0x03, 0x01, 0x00, + // '=' (0x3d) 7x3, offset 198-201, at +1/-7 + // in regular row-major format + 0xfc, 0x03, 0xf0, + // '>' (0x3e) 7x7, offset 201-208, at +1/-9 + // in regular row-major format + 0x80, 0xc0, 0x60, 0x21, 0x8c, 0x20, 0x00, + // '?' (0x3f) 6x10, offset 208-216, at +0/-10 + // in regular row-major format + 0x78, 0x20, 0x82, 0x10, 0x82, 0x00, 0x00, 0x80, + // '@' (0x40) 11x11, offset 216-232, at +1/-10 + // in regular row-major format + 0x1f, 0x0c, 0x11, 0x01, 0x47, 0x29, 0x25, 0x44, + 0xa8, 0x94, 0xec, 0x80, 0x08, 0x00, 0xf8, 0x00, + // 'A' (0x41) 9x10, offset 232-244, at +0/-10 + // in regular row-major format + 0x08, 0x0c, 0x06, 0x04, 0x82, 0x41, 0x21, 0xf8, + 0x84, 0x81, 0x40, 0x80, + // 'B' (0x42) 8x10, offset 244-254, at +1/-10 + // in regular row-major format + 0xfc, 0x82, 0x82, 0x86, 0xf8, 0x86, 0x82, 0x82, + 0x82, 0xfc, + // 'C' (0x43) 9x10, offset 254-266, at +1/-10 + // in regular row-major format + 0x3e, 0x30, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, + 0x00, 0x40, 0x1f, 0x00, + // 'D' (0x44) 9x10, offset 266-278, at +1/-10 + // in regular row-major format + 0xfc, 0x41, 0x20, 0x50, 0x28, 0x14, 0x0a, 0x05, + 0x02, 0x86, 0x7e, 0x00, + // 'E' (0x45) 7x10, offset 278-287, at +1/-10 + // in regular row-major format + 0xfd, 0x02, 0x04, 0x0f, 0xd0, 0x20, 0x40, 0x81, + 0xf8, + // 'F' (0x46) 7x10, offset 287-296, at +1/-10 + // in regular row-major format + 0xfd, 0x02, 0x04, 0x0f, 0xd0, 0x20, 0x40, 0x81, + 0x00, + // 'G' (0x47) 9x10, offset 296-308, at +1/-10 + // in regular row-major format + 0x1e, 0x30, 0xa0, 0x10, 0x08, 0x04, 0x7a, 0x05, + 0x02, 0x41, 0x1f, 0x80, + // 'H' (0x48) 9x10, offset 308-320, at +1/-10 + // in regular row-major format + 0x81, 0x40, 0xa0, 0x50, 0x2f, 0xf4, 0x0a, 0x05, + 0x02, 0x81, 0x40, 0x80, + // 'I' (0x49) 3x10, offset 320-324, at +1/-10 + // in regular row-major format + 0x92, 0x49, 0x24, 0x90, + // 'J' (0x4a) 4x13, offset 324-331, at -1/-10 + // in regular row-major format + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xc0, + // 'K' (0x4b) 8x10, offset 331-341, at +1/-10 + // in regular row-major format + 0x84, 0x84, 0x88, 0x90, 0xa0, 0xd0, 0x88, 0x88, + 0x84, 0x82, + // 'L' (0x4c) 7x10, offset 341-350, at +1/-10 + // in regular row-major format + 0x81, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x81, + 0xf8, + // 'M' (0x4d) 11x10, offset 350-364, at +1/-10 + // in regular row-major format + 0xc0, 0xd8, 0x1a, 0x85, 0x50, 0xaa, 0x15, 0x24, + 0xa4, 0x94, 0x62, 0x8c, 0x51, 0x08, + // 'N' (0x4e) 9x10, offset 364-376, at +1/-10 + // in regular row-major format + 0x81, 0x60, 0xa8, 0x52, 0x29, 0x14, 0x4a, 0x25, + 0x0a, 0x83, 0x40, 0x80, + // 'O' (0x4f) 10x10, offset 376-389, at +1/-10 + // in regular row-major format + 0x3e, 0x10, 0x48, 0x0a, 0x02, 0x80, 0xa0, 0x28, + 0x0a, 0x02, 0x41, 0x0f, 0x80, + // 'P' (0x50) 7x10, offset 389-398, at +1/-10 + // in regular row-major format + 0xf9, 0x0a, 0x14, 0x28, 0x5f, 0x20, 0x40, 0x81, + 0x00, + // 'Q' (0x51) 10x12, offset 398-413, at +1/-10 + // in regular row-major format + 0x3e, 0x10, 0x48, 0x0a, 0x02, 0x80, 0xa0, 0x28, + 0x0a, 0x02, 0x41, 0x0f, 0x80, 0x40, 0x0c, + // 'R' (0x52) 8x10, offset 413-423, at +1/-10 + // in regular row-major format + 0xf8, 0x84, 0x84, 0x84, 0x84, 0xf8, 0x88, 0x88, + 0x84, 0x84, + // 'S' (0x53) 7x10, offset 423-432, at +1/-10 + // in regular row-major format + 0x79, 0x02, 0x04, 0x06, 0x03, 0x01, 0x02, 0x05, + 0xf0, + // 'T' (0x54) 8x10, offset 432-442, at +0/-10 + // in regular row-major format + 0xfe, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, + // 'U' (0x55) 9x10, offset 442-454, at +1/-10 + // in regular row-major format + 0x81, 0x40, 0xa0, 0x50, 0x28, 0x14, 0x0a, 0x05, + 0x02, 0x42, 0x1e, 0x00, + // 'V' (0x56) 9x10, offset 454-466, at +0/-10 + // in regular row-major format + 0x81, 0x40, 0x90, 0x88, 0x42, 0x41, 0x20, 0x90, + 0x30, 0x18, 0x04, 0x00, + // 'W' (0x57) 13x10, offset 466-483, at +0/-10 + // in regular row-major format + 0x84, 0x12, 0x31, 0x11, 0x88, 0x94, 0x44, 0x92, + 0x14, 0xa0, 0xa5, 0x06, 0x18, 0x10, 0x80, 0x84, + 0x00, + // 'X' (0x58) 9x10, offset 483-495, at +0/-10 + // in regular row-major format + 0x41, 0x21, 0x09, 0x03, 0x01, 0x80, 0xc0, 0x90, + 0x48, 0x42, 0x40, 0x80, + // 'Y' (0x59) 8x10, offset 495-505, at +0/-10 + // in regular row-major format + 0x82, 0x44, 0x44, 0x28, 0x28, 0x10, 0x10, 0x10, + 0x10, 0x10, + // 'Z' (0x5a) 7x10, offset 505-514, at +1/-10 + // in regular row-major format + 0xfc, 0x08, 0x20, 0x81, 0x04, 0x10, 0x20, 0x81, + 0xf8, + // '[' (0x5b) 4x12, offset 514-520, at +1/-10 + // in regular row-major format + 0xe8, 0x88, 0x88, 0x88, 0x88, 0x8e, + // '\' (0x5c) 6x10, offset 520-528, at +0/-10 + // in regular row-major format + 0x81, 0x04, 0x10, 0x20, 0x81, 0x04, 0x10, 0x20, + // ']' (0x5d) 4x12, offset 528-534, at +0/-10 + // in regular row-major format + 0xe2, 0x22, 0x22, 0x22, 0x22, 0x2e, + // '^' (0x5e) 7x6, offset 534-540, at +1/-10 + // in regular row-major format + 0x10, 0x61, 0x22, 0x48, 0x50, 0x80, + // '_' (0x5f) 7x1, offset 540-541, at +0/+1 + // in regular row-major format + 0xfc, + // '`' (0x60) 3x2, offset 541-542, at +3/-10 + // in regular row-major format + 0x88, + // 'a' (0x61) 6x8, offset 542-548, at +1/-8 + // in regular row-major format + 0x70, 0x20, 0x9e, 0x8a, 0x29, 0xba, + // 'b' (0x62) 7x11, offset 548-558, at +1/-11 + // in regular row-major format + 0x81, 0x02, 0x05, 0xcc, 0x50, 0xa1, 0x42, 0x85, + 0x8a, 0xe0, + // 'c' (0x63) 6x8, offset 558-564, at +1/-8 + // in regular row-major format + 0x39, 0x08, 0x20, 0x82, 0x0c, 0x1e, + // 'd' (0x64) 7x11, offset 564-574, at +1/-11 + // in regular row-major format + 0x04, 0x08, 0x13, 0xa8, 0xd0, 0xa1, 0x42, 0x85, + 0x19, 0xd0, + // 'e' (0x65) 7x8, offset 574-581, at +1/-8 + // in regular row-major format + 0x79, 0x0a, 0x17, 0xe8, 0x10, 0x30, 0x3c, + // 'f' (0x66) 6x11, offset 581-590, at +0/-11 + // in regular row-major format + 0x39, 0x04, 0x3c, 0x41, 0x04, 0x10, 0x41, 0x04, + 0x00, + // 'g' (0x67) 8x11, offset 590-601, at +0/-8 + // in regular row-major format + 0x3e, 0x44, 0x44, 0x44, 0x38, 0x40, 0x40, 0x7c, + 0x82, 0x82, 0x7c, + // 'h' (0x68) 7x11, offset 601-611, at +1/-11 + // in regular row-major format + 0x81, 0x02, 0x05, 0xcc, 0x50, 0xa1, 0x42, 0x85, + 0x0a, 0x10, + // 'i' (0x69) 2x10, offset 611-614, at +1/-10 + // in regular row-major format + 0x8a, 0xaa, 0xa0, + // 'j' (0x6a) 4x13, offset 614-621, at -1/-10 + // in regular row-major format + 0x20, 0x22, 0x22, 0x22, 0x22, 0x22, 0xc0, + // 'k' (0x6b) 7x11, offset 621-631, at +1/-11 + // in regular row-major format + 0x81, 0x02, 0x04, 0x48, 0x92, 0x28, 0x68, 0x91, + 0x12, 0x10, + // 'l' (0x6c) 2x11, offset 631-634, at +1/-11 + // in regular row-major format + 0xaa, 0xaa, 0xa8, + // 'm' (0x6d) 11x8, offset 634-645, at +1/-8 + // in regular row-major format + 0xbb, 0x99, 0x8a, 0x11, 0x42, 0x28, 0x45, 0x08, + 0xa1, 0x14, 0x22, + // 'n' (0x6e) 7x8, offset 645-652, at +1/-8 + // in regular row-major format + 0xb9, 0x8a, 0x14, 0x28, 0x50, 0xa1, 0x42, + // 'o' (0x6f) 7x8, offset 652-659, at +1/-8 + // in regular row-major format + 0x79, 0x0a, 0x14, 0x28, 0x50, 0xa1, 0x3c, + // 'p' (0x70) 7x11, offset 659-669, at +1/-8 + // in regular row-major format + 0xb9, 0x8a, 0x14, 0x28, 0x50, 0xb1, 0x5c, 0x81, + 0x02, 0x00, + // 'q' (0x71) 7x11, offset 669-679, at +1/-8 + // in regular row-major format + 0x75, 0x1a, 0x14, 0x28, 0x50, 0xa3, 0x3a, 0x04, + 0x08, 0x10, + // 'r' (0x72) 5x8, offset 679-684, at +1/-8 + // in regular row-major format + 0xb6, 0x21, 0x08, 0x42, 0x10, + // 's' (0x73) 6x8, offset 684-690, at +1/-8 + // in regular row-major format + 0x7a, 0x08, 0x18, 0x18, 0x20, 0xbc, + // 't' (0x74) 6x10, offset 690-698, at +0/-10 + // in regular row-major format + 0x01, 0x0f, 0x10, 0x41, 0x04, 0x10, 0x40, 0xe0, + // 'u' (0x75) 7x8, offset 698-705, at +1/-8 + // in regular row-major format + 0x85, 0x0a, 0x14, 0x28, 0x50, 0xa3, 0x3a, + // 'v' (0x76) 7x8, offset 705-712, at +0/-8 + // in regular row-major format + 0x85, 0x09, 0x22, 0x44, 0x86, 0x0c, 0x08, + // 'w' (0x77) 11x8, offset 712-723, at +0/-8 + // in regular row-major format + 0x84, 0x51, 0x89, 0x32, 0x25, 0x45, 0x28, 0xa5, + 0x08, 0xc1, 0x08, + // 'x' (0x78) 8x8, offset 723-731, at +0/-8 + // in regular row-major format + 0x44, 0x44, 0x28, 0x10, 0x10, 0x28, 0x44, 0x44, + // 'y' (0x79) 7x11, offset 731-741, at +0/-8 + // in regular row-major format + 0x85, 0x09, 0x22, 0x44, 0x86, 0x0c, 0x10, 0x20, + 0x43, 0x00, + // 'z' (0x7a) 5x8, offset 741-746, at +1/-8 + // in regular row-major format + 0xf0, 0x88, 0x44, 0x22, 0x1e, + // '{' (0x7b) 6x12, offset 746-755, at +0/-10 + // in regular row-major format + 0x18, 0x82, 0x08, 0x20, 0x8c, 0x08, 0x20, 0x82, + 0x06, + // '|' (0x7c) 3x14, offset 755-761, at +3/-11 + // in regular row-major format + 0x92, 0x49, 0x24, 0x92, 0x49, 0x00, +}; + + +static const uint8_t OpenSansLight16_generic[] = { + // ' ' (0x20) 1x1, offset 0-1, at +0/+0 + // in regular row-major format + 0x00, + // '!' (0x21) 3x12, offset 1-6, at +1/-12 + // in regular row-major format + 0x92, 0x49, 0x24, 0x03, 0x60, + // '"' (0x22) 5x4, offset 6-9, at +1/-12 + // in regular row-major format + 0x94, 0xa5, 0x20, + // '#' (0x23) 11x12, offset 9-26, at +0/-12 + // in regular row-major format + 0x09, 0x01, 0x20, 0x44, 0x08, 0x87, 0xfc, 0x24, + 0x04, 0x87, 0xfc, 0x22, 0x04, 0x40, 0x90, 0x12, + 0x00, + // '$' (0x24) 8x13, offset 26-39, at +1/-12 + // in regular row-major format + 0x10, 0x3c, 0x50, 0x90, 0x90, 0x50, 0x38, 0x1c, + 0x12, 0x12, 0x94, 0x78, 0x10, + // '%' (0x25) 12x12, offset 39-57, at +1/-12 + // in regular row-major format + 0x60, 0x89, 0x10, 0x91, 0x08, 0xa0, 0x92, 0x09, + 0x5c, 0x65, 0x20, 0x92, 0x0a, 0x21, 0x12, 0x11, + 0x22, 0x0c, + // '&' (0x26) 11x12, offset 57-74, at +1/-12 + // in regular row-major format + 0x38, 0x08, 0x81, 0x10, 0x22, 0x02, 0x80, 0x60, + 0x12, 0x24, 0x24, 0x82, 0x90, 0x23, 0x0c, 0x3e, + 0x40, + // ''' (0x27) 2x4, offset 74-75, at +1/-12 + // in regular row-major format + 0xaa, + // '(' (0x28) 4x15, offset 75-83, at +1/-12 + // in regular row-major format + 0x44, 0x88, 0x88, 0x88, 0x88, 0x88, 0x84, 0x40, + // ')' (0x29) 4x15, offset 83-91, at +0/-12 + // in regular row-major format + 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x40, + // '*' (0x2a) 8x7, offset 91-98, at +1/-13 + // in regular row-major format + 0x10, 0x10, 0x12, 0xfc, 0x28, 0x28, 0x44, + // '+' (0x2b) 8x7, offset 98-105, at +1/-10 + // in regular row-major format + 0x10, 0x10, 0x10, 0xfe, 0x10, 0x10, 0x10, + // ',' (0x2c) 3x4, offset 105-107, at +0/-2 + // in regular row-major format + 0x49, 0x40, + // '-' (0x2d) 4x1, offset 107-108, at +1/-5 + // in regular row-major format + 0xe0, + // '.' (0x2e) 3x2, offset 108-109, at +1/-2 + // in regular row-major format + 0xd8, + // '/' (0x2f) 6x12, offset 109-118, at +0/-12 + // in regular row-major format + 0x08, 0x41, 0x04, 0x20, 0x82, 0x08, 0x41, 0x04, + 0x20, + // '0' (0x30) 8x12, offset 118-130, at +1/-12 + // in regular row-major format + 0x38, 0x44, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x44, 0x38, + // '1' (0x31) 4x12, offset 130-136, at +2/-12 + // in regular row-major format + 0x26, 0xa2, 0x22, 0x22, 0x22, 0x22, + // '2' (0x32) 8x12, offset 136-148, at +1/-12 + // in regular row-major format + 0x78, 0x84, 0x04, 0x04, 0x04, 0x04, 0x08, 0x10, + 0x20, 0x40, 0x80, 0xfe, + // '3' (0x33) 8x12, offset 148-160, at +1/-12 + // in regular row-major format + 0x78, 0x84, 0x02, 0x02, 0x04, 0x78, 0x04, 0x02, + 0x02, 0x02, 0x04, 0xf8, + // '4' (0x34) 10x12, offset 160-175, at +0/-12 + // in regular row-major format + 0x02, 0x01, 0x80, 0xa0, 0x48, 0x12, 0x08, 0x84, + 0x21, 0x08, 0xff, 0x80, 0x80, 0x20, 0x08, + // '5' (0x35) 8x12, offset 175-187, at +1/-12 + // in regular row-major format + 0x7c, 0x40, 0x40, 0x40, 0x80, 0xf8, 0x06, 0x02, + 0x02, 0x02, 0x84, 0x78, + // '6' (0x36) 8x12, offset 187-199, at +1/-12 + // in regular row-major format + 0x1c, 0x60, 0x40, 0x80, 0x80, 0xbc, 0xc2, 0x82, + 0x82, 0x82, 0x46, 0x3c, + // '7' (0x37) 8x12, offset 199-211, at +1/-12 + // in regular row-major format + 0xfe, 0x02, 0x04, 0x04, 0x04, 0x08, 0x08, 0x10, + 0x10, 0x10, 0x20, 0x20, + // '8' (0x38) 8x12, offset 211-223, at +1/-12 + // in regular row-major format + 0x38, 0x44, 0x82, 0x82, 0x4c, 0x30, 0x4c, 0x82, + 0x82, 0x82, 0xc6, 0x7c, + // '9' (0x39) 8x12, offset 223-235, at +1/-12 + // in regular row-major format + 0x78, 0xc4, 0x82, 0x82, 0x82, 0x86, 0x7a, 0x02, + 0x02, 0x04, 0x0c, 0x70, + // ':' (0x3a) 3x9, offset 235-239, at +1/-9 + // in regular row-major format + 0xd8, 0x00, 0x06, 0xc0, + // ';' (0x3b) 3x11, offset 239-244, at +1/-9 + // in regular row-major format + 0xd8, 0x00, 0x04, 0x92, 0x00, + // '<' (0x3c) 8x7, offset 244-251, at +1/-10 + // in regular row-major format + 0x02, 0x0c, 0x30, 0xc0, 0x60, 0x1c, 0x02, + // '=' (0x3d) 8x4, offset 251-255, at +1/-8 + // in regular row-major format + 0xfe, 0x00, 0x00, 0xfe, + // '>' (0x3e) 8x7, offset 255-262, at +1/-10 + // in regular row-major format + 0x80, 0x60, 0x18, 0x06, 0x0c, 0x70, 0x80, + // '?' (0x3f) 7x12, offset 262-273, at +0/-12 + // in regular row-major format + 0x78, 0x08, 0x10, 0x20, 0x41, 0x04, 0x10, 0x20, + 0x00, 0x81, 0x00, + // '@' (0x40) 13x14, offset 273-296, at +1/-12 + // in regular row-major format + 0x0f, 0x81, 0x82, 0x10, 0x08, 0x8f, 0x28, 0x89, + 0x48, 0x4a, 0x42, 0x52, 0x12, 0x91, 0x94, 0x77, + 0x20, 0x00, 0x80, 0x02, 0x00, 0x0f, 0x80, + // 'A' (0x41) 11x12, offset 296-313, at +0/-12 + // in regular row-major format + 0x04, 0x01, 0x80, 0x30, 0x09, 0x01, 0x20, 0x22, + 0x08, 0x41, 0xf8, 0x40, 0x88, 0x11, 0x02, 0x40, + 0x20, + // 'B' (0x42) 8x12, offset 313-325, at +2/-12 + // in regular row-major format + 0xf8, 0x86, 0x82, 0x82, 0x84, 0xf8, 0x86, 0x82, + 0x82, 0x82, 0x86, 0xf8, + // 'C' (0x43) 10x12, offset 325-340, at +1/-12 + // in regular row-major format + 0x1f, 0x08, 0x04, 0x02, 0x00, 0x80, 0x20, 0x08, + 0x02, 0x00, 0x80, 0x10, 0x06, 0x00, 0x7c, + // 'D' (0x44) 9x12, offset 340-354, at +2/-12 + // in regular row-major format + 0xf8, 0x43, 0x20, 0x90, 0x28, 0x14, 0x0a, 0x05, + 0x02, 0x81, 0x41, 0x21, 0x9f, 0x00, + // 'E' (0x45) 7x12, offset 354-365, at +2/-12 + // in regular row-major format + 0xfd, 0x02, 0x04, 0x08, 0x1f, 0xa0, 0x40, 0x81, + 0x02, 0x07, 0xe0, + // 'F' (0x46) 7x12, offset 365-376, at +2/-12 + // in regular row-major format + 0xfd, 0x02, 0x04, 0x08, 0x10, 0x3f, 0x40, 0x81, + 0x02, 0x04, 0x00, + // 'G' (0x47) 11x12, offset 376-393, at +1/-12 + // in regular row-major format + 0x1f, 0x86, 0x01, 0x00, 0x40, 0x08, 0x01, 0x00, + 0x21, 0xf4, 0x02, 0x80, 0x48, 0x08, 0x81, 0x0f, + 0xc0, + // 'H' (0x48) 9x12, offset 393-407, at +2/-12 + // in regular row-major format + 0x81, 0x40, 0xa0, 0x50, 0x28, 0x17, 0xfa, 0x05, + 0x02, 0x81, 0x40, 0xa0, 0x50, 0x20, + // 'I' (0x49) 3x12, offset 407-412, at +1/-12 + // in regular row-major format + 0x49, 0x24, 0x92, 0x49, 0x20, + // 'J' (0x4a) 4x15, offset 412-420, at -1/-12 + // in regular row-major format + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xc0, + // 'K' (0x4b) 8x12, offset 420-432, at +2/-12 + // in regular row-major format + 0x84, 0x84, 0x88, 0x90, 0xa0, 0xe0, 0xa0, 0x90, + 0x88, 0x88, 0x84, 0x82, + // 'L' (0x4c) 7x12, offset 432-443, at +2/-12 + // in regular row-major format + 0x81, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x81, + 0x02, 0x07, 0xe0, + // 'M' (0x4d) 11x12, offset 443-460, at +2/-12 + // in regular row-major format + 0x80, 0x50, 0x1b, 0x03, 0x60, 0x6a, 0x15, 0x42, + 0xa8, 0x54, 0x92, 0x92, 0x51, 0x8a, 0x31, 0x44, + 0x20, + // 'N' (0x4e) 9x12, offset 460-474, at +2/-12 + // in regular row-major format + 0x81, 0x40, 0xb0, 0x54, 0x29, 0x14, 0x8a, 0x25, + 0x12, 0x85, 0x41, 0xa0, 0xd0, 0x20, + // 'O' (0x4f) 11x12, offset 474-491, at +1/-12 + // in regular row-major format + 0x1e, 0x0c, 0x31, 0x02, 0x40, 0x28, 0x05, 0x00, + 0xa0, 0x14, 0x02, 0x80, 0x48, 0x11, 0x86, 0x0f, + 0x00, + // 'P' (0x50) 7x12, offset 491-502, at +2/-12 + // in regular row-major format + 0xf9, 0x1a, 0x14, 0x28, 0x51, 0xbc, 0x40, 0x81, + 0x02, 0x04, 0x00, + // 'Q' (0x51) 11x15, offset 502-523, at +1/-12 + // in regular row-major format + 0x1e, 0x0c, 0x31, 0x02, 0x40, 0x28, 0x05, 0x00, + 0xa0, 0x14, 0x02, 0x80, 0x48, 0x11, 0x86, 0x0f, + 0x00, 0x20, 0x02, 0x00, 0x60, + // 'R' (0x52) 9x12, offset 523-537, at +2/-12 + // in regular row-major format + 0xf8, 0x42, 0x20, 0x90, 0x48, 0x24, 0x23, 0xe1, + 0x10, 0x88, 0x42, 0x20, 0x90, 0x40, + // 'S' (0x53) 8x12, offset 537-549, at +1/-12 + // in regular row-major format + 0x3c, 0xc2, 0x80, 0x80, 0xc0, 0x30, 0x0c, 0x02, + 0x02, 0x02, 0x06, 0xfc, + // 'T' (0x54) 9x12, offset 549-563, at +0/-12 + // in regular row-major format + 0xff, 0x04, 0x02, 0x01, 0x00, 0x80, 0x40, 0x20, + 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, + // 'U' (0x55) 9x12, offset 563-577, at +2/-12 + // in regular row-major format + 0x81, 0x40, 0xa0, 0x50, 0x28, 0x14, 0x0a, 0x05, + 0x02, 0x81, 0x40, 0xb0, 0xc7, 0x80, + // 'V' (0x56) 10x12, offset 577-592, at +0/-12 + // in regular row-major format + 0x80, 0xa0, 0x24, 0x11, 0x04, 0x41, 0x08, 0x82, + 0x20, 0x48, 0x14, 0x05, 0x00, 0x80, 0x20, + // 'W' (0x57) 15x12, offset 592-615, at +0/-12 + // in regular row-major format + 0x83, 0x04, 0x86, 0x11, 0x0c, 0x22, 0x28, 0x44, + 0x48, 0x84, 0x92, 0x09, 0x24, 0x14, 0x28, 0x28, + 0x50, 0x30, 0xc0, 0x61, 0x80, 0x81, 0x00, + // 'X' (0x58) 10x12, offset 615-630, at +0/-12 + // in regular row-major format + 0x41, 0x10, 0x42, 0x20, 0x48, 0x14, 0x02, 0x01, + 0x40, 0x50, 0x22, 0x08, 0x84, 0x12, 0x02, + // 'Y' (0x59) 9x12, offset 630-644, at +0/-12 + // in regular row-major format + 0x81, 0x21, 0x10, 0x84, 0x82, 0x40, 0xc0, 0x60, + 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, + // 'Z' (0x5a) 8x12, offset 644-656, at +1/-12 + // in regular row-major format + 0xfe, 0x02, 0x04, 0x04, 0x08, 0x10, 0x10, 0x20, + 0x40, 0x40, 0x80, 0xfe, + // '[' (0x5b) 5x15, offset 656-666, at +1/-12 + // in regular row-major format + 0xf4, 0x21, 0x08, 0x42, 0x10, 0x84, 0x21, 0x08, + 0x43, 0xc0, + // '\' (0x5c) 6x12, offset 666-675, at +0/-12 + // in regular row-major format + 0x81, 0x04, 0x10, 0x20, 0x82, 0x08, 0x10, 0x41, + 0x02, + // ']' (0x5d) 5x15, offset 675-685, at +0/-12 + // in regular row-major format + 0xf0, 0x84, 0x21, 0x08, 0x42, 0x10, 0x84, 0x21, + 0x0b, 0xc0, + // '^' (0x5e) 8x7, offset 685-692, at +1/-12 + // in regular row-major format + 0x10, 0x28, 0x28, 0x44, 0x44, 0x82, 0x82, + // '_' (0x5f) 8x1, offset 692-693, at +0/+1 + // in regular row-major format + 0xfe, + // '`' (0x60) 4x3, offset 693-695, at +3/-13 + // in regular row-major format + 0x84, 0x20, + // 'a' (0x61) 7x9, offset 695-703, at +1/-9 + // in regular row-major format + 0x78, 0x18, 0x10, 0x27, 0xd0, 0xa1, 0x46, 0x74, + // 'b' (0x62) 8x13, offset 703-716, at +2/-13 + // in regular row-major format + 0x00, 0x00, 0x00, 0x00, 0x78, 0x84, 0x82, 0x02, + 0x02, 0x02, 0x82, 0x84, 0x78, + // 'c' (0x63) 7x9, offset 716-724, at +1/-9 + // in regular row-major format + 0x3c, 0x82, 0x04, 0x08, 0x10, 0x20, 0x20, 0x3c, + // 'd' (0x64) 9x13, offset 724-739, at +1/-13 + // in regular row-major format + 0x01, 0x00, 0x80, 0x40, 0x23, 0xd2, 0x1a, 0x0d, + 0x02, 0x81, 0x40, 0xa0, 0xc8, 0x63, 0xd0, + // 'e' (0x65) 8x9, offset 739-748, at +1/-9 + // in regular row-major format + 0x38, 0x44, 0x82, 0x82, 0xfe, 0x80, 0x80, 0x40, + 0x3c, + // 'f' (0x66) 7x13, offset 748-760, at +0/-13 + // in regular row-major format + 0x1c, 0x40, 0x81, 0x0f, 0x84, 0x08, 0x10, 0x20, + 0x40, 0x81, 0x02, 0x00, + // 'g' (0x67) 9x13, offset 760-775, at +0/-9 + // in regular row-major format + 0x3f, 0x22, 0x10, 0x88, 0x44, 0x41, 0xe0, 0x80, + 0x80, 0x3e, 0x20, 0xa0, 0x58, 0x47, 0xc0, + // 'h' (0x68) 8x13, offset 775-788, at +1/-13 + // in regular row-major format + 0x80, 0x80, 0x80, 0x80, 0xbc, 0xc4, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, + // 'i' (0x69) 2x12, offset 788-791, at +1/-12 + // in regular row-major format + 0xa2, 0xaa, 0xaa, + // 'j' (0x6a) 4x16, offset 791-799, at -1/-12 + // in regular row-major format + 0x22, 0x02, 0x22, 0x22, 0x22, 0x22, 0x22, 0x2e, + // 'k' (0x6b) 8x13, offset 799-812, at +1/-13 + // in regular row-major format + 0x80, 0x80, 0x80, 0x80, 0x84, 0x88, 0x90, 0x90, + 0xb0, 0xd0, 0x88, 0x84, 0x82, + // 'l' (0x6c) 3x13, offset 812-817, at +1/-13 + // in regular row-major format + 0x92, 0x49, 0x24, 0x92, 0x48, + // 'm' (0x6d) 13x9, offset 817-832, at +1/-9 + // in regular row-major format + 0xb9, 0xe6, 0x31, 0x20, 0x85, 0x04, 0x28, 0x21, + 0x41, 0x0a, 0x08, 0x50, 0x42, 0x82, 0x10, + // 'n' (0x6e) 8x9, offset 832-841, at +1/-9 + // in regular row-major format + 0xbc, 0xc4, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, + // 'o' (0x6f) 8x9, offset 841-850, at +1/-9 + // in regular row-major format + 0x38, 0x44, 0x82, 0x82, 0x82, 0x82, 0x82, 0x44, + 0x38, + // 'p' (0x70) 8x13, offset 850-863, at +2/-9 + // in regular row-major format + 0x78, 0x84, 0x82, 0x02, 0x02, 0x02, 0x82, 0x84, + 0x78, 0x00, 0x00, 0x00, 0x00, + // 'q' (0x71) 9x13, offset 863-878, at +1/-9 + // in regular row-major format + 0x3d, 0x21, 0xa0, 0xd0, 0x28, 0x14, 0x0a, 0x0c, + 0x86, 0x3d, 0x00, 0x80, 0x40, 0x20, 0x10, + // 'r' (0x72) 6x9, offset 878-885, at +1/-9 + // in regular row-major format + 0xbb, 0x08, 0x20, 0x82, 0x08, 0x20, 0x80, + // 's' (0x73) 6x9, offset 885-892, at +1/-9 + // in regular row-major format + 0x7a, 0x08, 0x30, 0x30, 0x20, 0x82, 0xf0, + // 't' (0x74) 6x11, offset 892-901, at +0/-11 + // in regular row-major format + 0x41, 0x0f, 0x10, 0x41, 0x04, 0x10, 0x41, 0x03, + 0x80, + // 'u' (0x75) 8x9, offset 901-910, at +1/-9 + // in regular row-major format + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x46, + 0x7a, + // 'v' (0x76) 8x9, offset 910-919, at +0/-9 + // in regular row-major format + 0x82, 0x82, 0x44, 0x44, 0x44, 0x28, 0x28, 0x28, + 0x10, + // 'w' (0x77) 13x9, offset 919-934, at +0/-9 + // in regular row-major format + 0x82, 0x12, 0x31, 0x11, 0x88, 0x92, 0x44, 0x92, + 0x14, 0xa0, 0xc3, 0x06, 0x18, 0x10, 0x80, + // 'x' (0x78) 9x9, offset 934-945, at +0/-9 + // in regular row-major format + 0x42, 0x12, 0x09, 0x03, 0x01, 0x80, 0xc0, 0x90, + 0x84, 0x42, 0x00, + // 'y' (0x79) 8x13, offset 945-958, at +0/-9 + // in regular row-major format + 0x82, 0x82, 0x44, 0x44, 0x44, 0x28, 0x28, 0x28, + 0x10, 0x10, 0x20, 0x20, 0xc0, + // 'z' (0x7a) 6x9, offset 958-965, at +1/-9 + // in regular row-major format + 0xf8, 0x21, 0x04, 0x21, 0x04, 0x20, 0xf8, + // '{' (0x7b) 5x15, offset 965-975, at +1/-12 + // in regular row-major format + 0x31, 0x10, 0x84, 0x21, 0x10, 0x42, 0x10, 0x84, + 0x10, 0xc0, + // '|' (0x7c) 2x17, offset 975-980, at +4/-13 + // in regular row-major format + 0xaa, 0xaa, 0xaa, 0xaa, 0x80, +}; + + +const Font Fonts[] = { + { + "Mono9", + (uint8_t *)FreeMono9pt7b_generic, + (GFXglyph *)FreeMono9pt7bGlyphs, + 0x20, 0x7e, 18 + }, + { + "Mono12", + (uint8_t *)FreeMono12pt7b_generic, + (GFXglyph *)FreeMono12pt7bGlyphs, + 0x20, 0x7e, 24 + }, + { + "Mono18", + (uint8_t *)FreeMono18pt7b_generic, + (GFXglyph *)FreeMono18pt7bGlyphs, + 0x20, 0x7e, 35 + }, + { + "Mono24", + (uint8_t *)FreeMono24pt7b_generic, + (GFXglyph *)FreeMono24pt7bGlyphs, + 0x20, 0x7e, 47 + }, + { + "TomThumb", + (uint8_t *)TomThumb_generic, + (GFXglyph *)TomThumbGlyphs, + 0x20, 0x7e, 6 + }, + { + "Sans9", + (uint8_t *)FreeSans9pt7b_generic, + (GFXglyph *)FreeSans9pt7bGlyphs, + 0x20, 0x7e, 22 + }, + { + "Sans12", + (uint8_t *)FreeSans12pt7b_generic, + (GFXglyph *)FreeSans12pt7bGlyphs, + 0x20, 0x7e, 22 + }, + { + "SansLight10", + (uint8_t *)OpenSansLight10_generic, + (GFXglyph *)OpenSansLight10Glyphs, + 0x20, 0x7d, 14 + }, + { + "SansLight12", + (uint8_t *)OpenSansLight12_generic, + (GFXglyph *)OpenSansLight12Glyphs, + 0x20, 0x7d, 17 + }, + { + "SansLight14", + (uint8_t *)OpenSansLight14_generic, + (GFXglyph *)OpenSansLight14Glyphs, + 0x20, 0x7d, 20 + }, + { + "SansLight16", + (uint8_t *)OpenSansLight16_generic, + (GFXglyph *)OpenSansLight16Glyphs, + 0x20, 0x7d, 23 + }, + { + "Org01", + (uint8_t *)Org_01_generic, + (GFXglyph *)Org_01Glyphs, + 0x20, 0x7e, 7 + }, +}; diff --git a/drv/display/fonts_generic.h b/drv/display/fonts_generic.h new file mode 100644 index 0000000..266150e --- /dev/null +++ b/drv/display/fonts_generic.h @@ -0,0 +1,27 @@ +#ifndef FONTS_SSD1306_H +#define FONTS_SSD1306_H + +#include "font.h" + +typedef enum { + font_nativedbl = -2, + font_native = -1, + font_mono9 = 0, + font_mono12, + font_mono18, + font_mono24, + font_tomthumb, + font_sans9, + font_sans12, + font_sanslight10, + font_sanslight12, + font_sanslight14, + font_sanslight16, + font_org01, + font_numfonts +} fontid_t; + +extern const Font Fonts[]; +extern const uint8_t Font6x8[]; +extern const uint16_t SizeofFont6x8; +#endif diff --git a/drv/display/hd44780u.cpp b/drv/display/hd44780u.cpp index 0c616d5..4afa239 100644 --- a/drv/display/hd44780u.cpp +++ b/drv/display/hd44780u.cpp @@ -99,7 +99,7 @@ int HD44780U::init() } -int HD44780U::clear() +void HD44780U::clear() { log_dbug(TAG,"clear"); m_posx = 0; @@ -107,8 +107,8 @@ int HD44780U::clear() m_posinv = false; bzero(m_data,sizeof(m_data)); int r = writeCmd(CMD_CLR_DISP); + log_dbug(TAG,"clear %d",r); vTaskDelay(2); // not good but needed... - return r; } @@ -188,11 +188,9 @@ int HD44780U::setBlink(bool blink) } -int HD44780U::setDim(uint8_t d) +int HD44780U::setBrightness(uint8_t d) { - if (d > 1) - return -1; - return setOn(d); + return setOn(d != 0); } @@ -214,7 +212,7 @@ void HD44780U::setDisplay(bool on, bool cursor, bool blink) } -int HD44780U::write(const char *t, int n) +void HD44780U::write(const char *t, int n) { log_dbug(TAG,"write('%s',%d) at %u/%u",t,n,m_posx,m_posy); while (*t && (n != 0)) { @@ -230,13 +228,12 @@ int HD44780U::write(const char *t, int n) if (c == 0260) c = 0xdf; if (writeData(c)) - return 1; + return; } --n; ++t; } log_dbug(TAG,"pos %u/%u",m_posx,m_posy); - return 0; } @@ -395,7 +392,7 @@ uint8_t HD44780U::readBusy() } -int HD44780U::clrEol() +void HD44780U::clrEol() { uint8_t x = m_posx; log_dbug(TAG,"clrEol() y=%u",(unsigned)m_posy); @@ -404,7 +401,6 @@ int HD44780U::clrEol() while (m_posx < m_maxx); m_posx = x; log_dbug(TAG,"clrEol(): done"); - return 0; } #endif diff --git a/drv/display/hd44780u.h b/drv/display/hd44780u.h index 8da6034..fd0ecfd 100644 --- a/drv/display/hd44780u.h +++ b/drv/display/hd44780u.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021, Thomas Maier-Komor + * Copyright (C) 2021-2023, Thomas Maier-Komor * Atrium Firmware Package for ESP * * This program is free software: you can redistribute it and/or modify @@ -38,21 +38,21 @@ class HD44780U : public TextDisplay bool hasChar(char c) const override; int init(); - int write(const char *, int = -1) override; + void write(const char *, int = -1) override; int writeHex(uint8_t h, bool c) override; - int clear() override; - int clrEol(); + void clear() override; + void clrEol(); int setBlink(bool) override; int setCursor(bool blink) override; - int setDim(uint8_t) override; + int setBrightness(uint8_t) override; int setOn(bool) override; void setDisplay(bool on, bool cursor, bool blink); int setPos(uint16_t x, uint16_t y = 0) override; - uint8_t maxDim() const override + uint8_t maxBrightness() const override { return 1; } - uint8_t charsPerLine() const override + uint16_t charsPerLine() const override { return m_maxx; } - uint8_t numLines() const override + uint16_t numLines() const override { return m_maxy; } private: @@ -64,7 +64,6 @@ class HD44780U : public TextDisplay uint32_t m_lcmd = 0; // time-stamp of last command uint8_t m_disp = 0; bool m_posinv = false; - uint8_t m_posx = 0, m_posy = 0; uint8_t m_maxx, m_maxy; char m_data[80]; }; diff --git a/drv/display/ssd130x.cpp b/drv/display/ssd130x.cpp new file mode 100644 index 0000000..018fa21 --- /dev/null +++ b/drv/display/ssd130x.cpp @@ -0,0 +1,641 @@ +/* + * Copyright (C) 2021-2023, Thomas Maier-Komor + * Atrium Firmware Package for ESP + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "ssd130x.h" +#include "log.h" +#include "profiling.h" + +#include "fonts_ssd1306.h" +#include +#include + +#include +#include + +#define CHAR_WIDTH 6 +#define CHAR_HEIGHT 8 + +#define CTRL_CMD1 0x00 // command and data +#define CTRL_CMDN 0x80 // command with more commands +#define CTRL_CMDC 0xc0 // continuation command +#define CTRL_DATA 0x00 // data only + +#define CMD_NOP 0xe3 + +#define TAG MODULE_SSD130X + + + +SSD130X::~SSD130X() +{ + free(m_disp); +} + + +void SSD130X::clear() +{ + uint8_t numpg = m_height >> 3; + uint8_t pg = 0; + do { + uint8_t *at = m_disp + m_width * pg; + uint8_t *pge = at + m_width; + do { + if (*at) + break; + ++at; + } while (at != pge); + if (at != pge) { + bzero(at, pge-at); + m_dirty |= 1 << pg; + } + } while (++pg != numpg); + m_posx = 0; + m_posy = 0; + log_dbug(TAG,"clear: dirty %x",m_dirty); +} + + +void SSD130X::fillRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, int32_t col) +{ + log_dbug(TAG,"fillRect(%u,%u,%u,%u)",x,y,w,h); + if ((x > m_width) || (y >= m_height)) + return; + if ((x+w) > m_width) + w = m_width - x; + if ((y+h) > m_height) + h = m_height - y; + for (int i = x; i < x+w; ++i) { + uint16_t y0 = y; + uint16_t h0 = h; + do { + if (((y & 7) == 0) && (h0 >= 8)) { + drawByte(i,y0,0xff); + y0 += 8; + h0 -= 8; + } else { + setPixel(i,y0); + ++y0; + --h0; + } + } while (h0 > 0); + } +} + + +uint16_t SSD130X::fontHeight() const +{ + switch (m_font) { + case -1: return 8; + case -2: return 16; + default: + return Fonts[m_font].yAdvance; + } +} + + +/* +void SSD130X::clrEol() +{ + clearRect(m_posx,m_posy,m_width-m_posx,fontHeight()); +} +*/ + + +uint16_t SSD130X::charsPerLine() const +{ + if (m_font == font_nativedbl) + return m_width/CHAR_WIDTH<<1; + return m_width/CHAR_WIDTH; +} + + +uint16_t SSD130X::numLines() const +{ + return m_height/fontHeight(); +} + + +/* +int SSD130X::setFont(const char *fn) +{ + if (0 == strcasecmp(fn,"native")) { + m_font = (fontid_t)-1; + return 0; + } + if (0 == strcasecmp(fn,"nativedbl")) { + m_font = (fontid_t)-2; + return 0; + } + for (int i = 0; i < font_numfonts; ++i) { + if (0 == strcasecmp(Fonts[i].name,fn)) { + m_font = (fontid_t)i; + return 0; + } + } + return -1; +} +*/ + + +int SSD130X::readByte(uint8_t x, uint8_t y, uint8_t *b) +{ + if ((x >= m_width) || (y >= m_height)) { + log_dbug(TAG,"off display %u,%u",x,y); + return 1; + } + uint8_t shift = y & 7; + uint8_t pg = y >> 3; + uint16_t idx = pg * m_width + x; + uint8_t b0 = m_disp[idx]; + if (shift) { + b0 >>= shift; + idx += m_width; + if (idx < (m_width*m_height)) { + uint8_t b1 = m_disp[idx]; + b1 <<= (8-shift); + b0 |= b1; + } + } + *b = b0; + return 0; +} + + +int SSD130X::drawMasked(uint8_t x, uint8_t y, uint8_t b, uint8_t m) +{ + uint8_t o; + if (readByte(x,y,&o)) + return 1; + o &= ~m; + o |= (b & m); + return drawByte(x,y,o); +} + + +static uint16_t scaleDouble(uint8_t byte) +{ + uint16_t r = 0; + uint16_t m = 1; + for (uint8_t b = 0; b < 8; ++b) { + if (byte & (1<> 3; + unsigned off = pg * m_width + x; + uint8_t shl = y & 7; + uint16_t b0 = (uint16_t)b << shl; + uint8_t b1 = (uint8_t)(b0 >> 8); + if (b1) + m_disp[off+m_width] |= b1; + m_disp[off] |= (uint8_t)(b0&0xff); +// log_dbug(TAG,"drawBits %x at %u",b0,off); + return 0; +} + + +int SSD130X::drawByte(uint8_t x, uint8_t y, uint8_t b) +{ + uint8_t pg = y >> 3; + uint16_t idx = pg * m_width + x; + if ((x >= m_width) || (y >= m_height)) { + log_dbug(TAG,"off display %u,%u=%u pg=%u",(unsigned)x,(unsigned)y,(unsigned)idx,(unsigned)pg); + return 1; + } + uint8_t shift = y & 7; + if (shift != 0) { + uint16_t idx2 = idx + m_width; + if (idx2 >= (m_width*m_height)) + return 1; + m_dirty |= 1<<(pg+1); + uint16_t w = (uint16_t) b << shift; + uint16_t m = 0xff << shift; + m = ~m; + uint8_t b0 = (m_disp[idx] & m) | (w & 0xFF); + if (b0 != m_disp[idx]) { + m_disp[idx] = b0; + m_dirty |= 1<> 8)) | (w >> 8); + idx = idx2; + } + if (m_disp[idx] != b) { + m_dirty |= 1<= SizeofFont6x8) + return 1; + for (int c = 0; c < 6; ++c) + drawByte(x++, m_posy, Font6x8[idx+c]); + m_posx = x; + return 0; + } else if (m_font == -2) { + if (c < 32) + return 1; + uint16_t idx = (c - 32)*6; + if (idx >= SizeofFont6x8) + return 1; + for (int c = 0; c < 6; ++c) { + uint16_t w = scaleDouble(Font6x8[idx+c]); + drawByte(x, m_posy, w & 0xff); + drawByte(x, m_posy+8, w >> 8); + ++x; + drawByte(x, m_posy, w & 0xff); + drawByte(x, m_posy+8, w >> 8); + ++x; + } + m_posx = x; + return 0; + } + const Font *font = Fonts+(int)m_font; + if ((font < Fonts) || (font >= Fonts+(int)font_numfonts)) { + log_dbug(TAG,"invalid font"); + return 1; + } + if ((c < font->first) || (c > font->last)) + return 1; + uint8_t ch = c - font->first; + const uint8_t *off = font->bitmap + font->glyph[ch].bitmapOffset; + uint8_t w = font->glyph[ch].width; + uint8_t h = font->glyph[ch].height; + int8_t dx = font->glyph[ch].xOffset; + int8_t dy = font->glyph[ch].yOffset; + uint8_t a = font->glyph[ch].xAdvance; + log_dbug(TAG,"drawChar('%c') at %u/%u %ux%u",c,m_posx,m_posy,w,h); +// log_info(TAG,"%d/%d %+d/%+d, adv %u len %u",(int)w,(int)h,(int)dx,(int)dy,a,l); +// clearRect(m_posx,m_posy,dx+w,a); +// drawBitmap(m_posx+dx,m_posy+dy+font->yAdvance,w,h,off); + drawBitmapNative(m_posx+dx,m_posy+dy+font->yAdvance-1,w,h,off); + m_posx += a; + + return 0; +} + + +void SSD130X::drawBitmap(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *data, int32_t fg, int32_t bg) +{ + unsigned len = w*h; + log_dbug(TAG,"drawBitmap(%u,%u,%u,%u,%d,%d)",x,y,w,h,fg,bg); + unsigned idx = 0; + uint8_t b = 0; + while (idx != len) { + if ((idx & 7) == 0) + b = data[idx>>3]; + int32_t col = b & 0x80 ? fg : bg; + if (col != -2) + setPixel(x+idx%w,y+idx/w,col); + b<<=1; + ++idx; + } +} + + +void SSD130X::drawHLine(uint16_t x, uint16_t y, uint16_t n, int32_t col) +{ + if ((x + n > m_width) || (y >= m_height) || (col != 1)) + return; + if ((x + n) > m_width) + n = m_width - x; + uint8_t pg = y >> 3; + uint16_t off = x + pg * m_width; + uint8_t m = 1 << (y & 7); + uint8_t *p = m_disp+off; + do { + m |= *p; + if (*p != m) { + *p = m; + m_dirty |= (1 << pg); + } + ++p; + } while (--n); +} + + +void SSD130X::drawVLine(uint16_t x, uint16_t y, uint16_t n, int32_t col) +{ + if ((x >= m_width) || (y >= m_height) || (col != 1)) + return; + if ((y + n) > m_height) + n = m_height - y; + while (n) { + uint8_t pg = y >> 3; + uint16_t off = x + pg * m_width; + uint8_t shift = y & 7; + uint8_t m = 0; + if ((shift == 0) && (n >= 8)) { + m = 0xff; + n -= 8; + y += 8; + } else { + m = 0; + do { + m |= (1 << shift); + --n; + ++y; + ++shift; + } while ((shift < 8) && (n != 0)); + } + uint8_t *p = m_disp + off; + uint8_t v = *p | m; + if (v != *p) { + *p = v; + m_dirty |= (1<> 3; + uint8_t byte = data[b]; + unsigned bitst = off & 7; + uint8_t got = 8-bitst; + byte >>= bitst; + if (got < numb) + byte |= data[b+1] << got; +// log_dbug(TAG,"getBits(%u,%u): %x",off,numb,byte); + return byte; +} + + +void SSD130X::drawBitmapNative(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *data) +{ + static const uint8_t masks[] = {0x1,0x3,0x7,0xf,0x1f,0x3f,0x7f}; + unsigned len = w*h; + uint16_t bitoff = 0; + log_dbug(TAG,"drawBitmapNative(%u,%u,%u,%u) %u/%u",x,y,w,h,len,len/8); + for (uint8_t x0 = x; x0 < x+w; ++x0) { + uint8_t yoff = y; + uint8_t numb = h; + while (numb) { +// log_dbug(TAG,"numb=%u",numb); + uint8_t byte = getBits(data,bitoff,numb); + if (numb >= 8) { +// log_dbug(TAG,"byte %x at %u/%u",byte,x0,y+yoff); + if (byte) + drawByte(x0,yoff,byte); + numb -= 8; + yoff += 8; + bitoff += 8; + } else { + byte &= masks[numb-1]; + if (byte) { +// drawBits(x0,yoff,byte,numb); + uint8_t pg = yoff >> 3; + unsigned off = pg * m_width + x0; + uint8_t shl = yoff & 7; + uint16_t b0 = (uint16_t)byte << shl; + m_disp[off] |= (uint8_t)(b0&0xff); + uint8_t b1 = (uint8_t)(b0 >> 8); + if (b1) + m_disp[off+m_width] |= b1; + } + bitoff += numb; + break; + } + } + } +} + + +void SSD130X::pClrPixel(uint16_t x, uint16_t y) +{ +// log_dbug(TAG,"clrPixel(%u,%u)",(unsigned)x,(unsigned)y); + if ((x < m_width) && (y < m_height)) { + uint8_t pg = y >> 3; + uint8_t *p = m_disp + pg * m_width + x; + uint8_t bit = 1 << (y & 7); + uint8_t b = *p; + if ((b & bit) != 0) { + *p = b & ~bit; + m_dirty |= (1 << pg); + } + } +} + + +void SSD130X::pSetPixel(uint16_t x, uint16_t y) +{ +// log_dbug(TAG,"setPixel(%u,%u)",(unsigned)x,(unsigned)y); + if ((x < m_width) && (y < m_height)) { + uint8_t pg = y >> 3; + uint8_t *p = m_disp + pg * m_width + x; + uint8_t bit = 1 << (y & 7); + uint8_t b = *p; + if ((b & bit) == 0) { + *p = b | bit; + m_dirty |= (1 << pg); + } + } +} + + +void SSD130X::setPixel(uint16_t x, uint16_t y, int32_t col) +{ +// log_dbug(TAG,"setPixel(%u,%u)",(unsigned)x,(unsigned)y); + if ((x < m_width) && (y < m_height)) { + uint8_t pg = y >> 3; + uint8_t *p = m_disp + pg * m_width + x; + uint8_t bit = 1 << (y & 7); + uint8_t b = *p; + if ((b & bit) == 0) { + if (col == 1) { + *p = b | bit; + m_dirty |= (1 << pg); + } + } else { + if (col == 0) { + m_dirty &= ~(1 << pg); + } + } + } +} + + +int SSD130X::clearRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h) +{ + log_dbug(TAG,"clearRect(%u,%u,%u,%u)",x,y,w,h); + if ((x > m_width) || (y >= m_height)) + return 1; + for (int i = x; i < x+w; ++i) { + uint16_t y0 = y; + uint16_t h0 = h; + do { + if (((y & 7) == 0) && (h0 >= 8)) { + drawByte(i,y0,0); + y0 += 8; + h0 -= 8; + } else { + pClrPixel(i,y0); + ++y0; + --h0; + } + } while (h0 > 0); + } + return 0; +} + + +/* +int SSD130X::drawRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, int32_t col) +{ + log_dbug(TAG,"drawRect(%u,%u,%u,%u)",x,y,w,h); + drawHLine(x,y,w,col); + drawHLine(x,y+h-1,w,col); + drawVLine(x,y,h,col); + drawVLine(x+w-1,y,h,col); + return 0; +} +*/ + + +int SSD130X::writeHex(uint8_t h, bool comma) +{ + log_dbug(TAG,"writeHex %x",h); + char c = h; + if (h < 10) + c += '0'; + else + c += 'A' - 10; + if (drawChar(c)) + return 1; + if (comma) { + if (drawChar('.')) + return 1; + } + return 0; +} + + +/* +int SSD130X::setPos(uint16_t x, uint16_t y) +{ + log_dbug(TAG,"setPos(%u/%u)",x,y); + x *= CHAR_WIDTH; + y *= fontHeight(); + if ((x >= m_width-(CHAR_WIDTH)) || (y > m_height-fontHeight())) { + log_dbug(TAG,"invalid pos %u/%u",x,y); + return 1; + } + log_dbug(TAG,"setPos %u/%u",x,y); + m_posx = x; + m_posy = y; + return 0; +} +*/ + + +/* +void SSD130X::write(const char *text, int len) +{ + log_dbug(TAG,"write %s",text); + size_t n = 0; + while (len) { + char c = *text++; + if (c == 0) + return n; + drawChar(c); + ++n; + --len; + } + return n; +} +*/ diff --git a/drv/display/ssd130x.h b/drv/display/ssd130x.h new file mode 100644 index 0000000..4321ae8 --- /dev/null +++ b/drv/display/ssd130x.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2021-2023, Thomas Maier-Komor + * Atrium Firmware Package for ESP + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SSD130X_H +#define SSD130X_H + +#include "display.h" +#include "fonts_ssd1306.h" + +class SSD130X : public MatrixDisplay +{ + public: + SSD130X() + : MatrixDisplay(cs_mono) + { } + + ~SSD130X(); + void clear(); + uint16_t fontHeight() const; +// int clrEol(); + uint16_t charsPerLine() const; + uint16_t numLines() const; +// int setFont(unsigned); +// int setFont(const char *fn); + void drawBitmap(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *data, int32_t fg, int32_t bg); + void drawHLine(uint16_t x, uint16_t y, uint16_t n, int32_t col = -1) override; + void drawVLine(uint16_t x, uint16_t y, uint16_t n, int32_t col = -1) override; +// void drawRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, int32_t col = -1) override; + void fillRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, int32_t col = -1) override; + void setPixel(uint16_t x, uint16_t y, int32_t col = -1) override; + int writeHex(uint8_t h, bool comma); +// int setPos(uint16_t x, uint16_t y); + //void write(const char *text, int len); + + bool hasAlpha() const override + { return true; } + + bool hasChar(char) const override + { return true; } + + protected: + void pClrPixel(uint16_t x, uint16_t y); + void pSetPixel(uint16_t x, uint16_t y); + int clearRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h); + int readByte(uint8_t x, uint8_t y, uint8_t *b); + int drawMasked(uint8_t x, uint8_t y, uint8_t b, uint8_t m); + int drawBits(uint8_t x, uint8_t y, uint8_t b, uint8_t n); + int drawByte(uint8_t x, uint8_t y, uint8_t b); + int drawChar(char c); + void drawBitmapNative(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *data); + + uint8_t *m_disp = 0; + uint8_t m_dirty = 0xff; +}; + + + +#endif + diff --git a/drv/i2c/ht16k33.cpp b/drv/i2c/ht16k33.cpp index a5bf4c2..3916953 100644 --- a/drv/i2c/ht16k33.cpp +++ b/drv/i2c/ht16k33.cpp @@ -117,7 +117,11 @@ int HT16K33::setPos(uint8_t x, uint8_t y) int HT16K33::write(uint8_t v) { - log_dbug(TAG,"write(%x)",v); + log_dbug(TAG,"write(0x%x) @%u",v,m_pos); + if ((v == '\r') || (v == '\n')) { + m_pos = 0; + return 0; + } if (m_pos >= m_digits) return 1; uint8_t off = m_pos; @@ -135,7 +139,7 @@ int HT16K33::write(uint8_t v) int HT16K33::write(uint8_t *v, unsigned n) { - log_dbug(TAG,"write(%x...)",*v); + log_dbug(TAG,"write(%x,%u)",*v,n); if (m_pos >= m_digits) return 1; uint8_t off = m_pos; diff --git a/drv/i2c/ina2xx.cpp b/drv/i2c/ina2xx.cpp index 9eda606..05bf014 100644 --- a/drv/i2c/ina2xx.cpp +++ b/drv/i2c/ina2xx.cpp @@ -219,8 +219,9 @@ static int sample_cfg(long l) return 14; case 128: return 15; + default: + return -1; } - return -1; } diff --git a/drv/i2c/ssd1306.cpp b/drv/i2c/ssd1306.cpp index 6b3fcc7..7be3768 100644 --- a/drv/i2c/ssd1306.cpp +++ b/drv/i2c/ssd1306.cpp @@ -55,17 +55,19 @@ SSD1306::SSD1306(uint8_t bus, uint8_t addr) } -SSD1306::~SSD1306() +/* +SSD130X::~SSD130X() { free(m_disp); } +*/ int SSD1306::init(uint8_t maxx, uint8_t maxy, uint8_t hwcfg) { log_info(TAG,"init(%u,%u)",maxx,maxy); - m_maxx = maxx; - m_maxy = maxy; + m_width = maxx; + m_height = maxy; uint32_t dsize = maxx * maxy; m_disp = (uint8_t *) malloc(dsize); // two dimensional array of n pages each of n columns. if (m_disp == 0) { @@ -77,7 +79,7 @@ int SSD1306::init(uint8_t maxx, uint8_t maxy, uint8_t hwcfg) 0x00, // command 0xae, // display off 0xd5, 0x80, // oszi freq (default), clock div=1 (optional) - 0xa8, (uint8_t)(m_maxy-1), // MUX + 0xa8, (uint8_t)(m_height-1), // MUX 0xd3, 0x00, // display offset (optional) 0x40, // display start line (optional) 0x8d, 0x14, // enable charge pump @@ -95,7 +97,7 @@ int SSD1306::init(uint8_t maxx, uint8_t maxy, uint8_t hwcfg) if (i2c_write(m_bus,setup,sizeof(setup),1,1)) return 1; clear(); - sync(); + flush(); setOn(true); initOK(); log_info(TAG,"ready"); @@ -120,20 +122,21 @@ int SSD1306::setInvert(bool inv) } -int SSD1306::setContrast(uint8_t contrast) +int SSD1306::setBrightness(uint8_t contrast) { uint8_t cmd[] = { m_addr, 0x00, 0x81, contrast }; return i2c_write(m_bus,cmd,sizeof(cmd),1,1); } -int SSD1306::clear() +/* +void SSD1306::clear() { - uint8_t numpg = m_maxy >> 3; + uint8_t numpg = m_height >> 3; uint8_t pg = 0; do { - uint8_t *at = m_disp + m_maxx * pg; - uint8_t *pge = at + m_maxx; + uint8_t *at = m_disp + m_width * pg; + uint8_t *pge = at + m_width; do { if (*at) break; @@ -147,8 +150,8 @@ int SSD1306::clear() m_posx = 0; m_posy = 0; log_dbug(TAG,"clear: dirty %x",m_dirty); - return 0; } +*/ uint8_t SSD1306::fontHeight() const @@ -162,25 +165,26 @@ uint8_t SSD1306::fontHeight() const } +/* int SSD1306::clrEol() { - clearRect(m_posx,m_posy,m_maxx-m_posx,fontHeight()); - return 0; + return fillRect(m_posx,m_posy,m_width-m_posx,fontHeight(),m_colbg); } -uint8_t SSD1306::charsPerLine() const +uint16_t SSD1306::charsPerLine() const { if (m_font == font_nativedbl) - return m_maxx/CHAR_WIDTH<<1; - return m_maxx/CHAR_WIDTH; + return m_width/CHAR_WIDTH<<1; + return m_width/CHAR_WIDTH; } -uint8_t SSD1306::numLines() const +uint16_t SSD1306::numLines() const { - return m_maxy/fontHeight(); + return m_height/fontHeight(); } +*/ int SSD1306::setFont(const char *fn) @@ -203,15 +207,15 @@ int SSD1306::setFont(const char *fn) } -int SSD1306::sync() +void SSD1306::flush() { if (m_dirty == 0) - return 0; + return; PROFILE_FUNCTION(); - uint8_t cmd[] = { m_addr, 0x00, 0xb0, 0x21, 0x00, (uint8_t)(m_maxx-1) }; + uint8_t cmd[] = { m_addr, 0x00, 0xb0, 0x21, 0x00, (uint8_t)(m_width-1) }; uint8_t pfx[] = { m_addr, 0x40 }; - uint8_t numpg = m_maxy / 8 + ((m_maxy & 7) != 0); - unsigned pgs = m_maxx; + uint8_t numpg = m_height / 8 + ((m_height & 7) != 0); + unsigned pgs = m_width; if (pgs == 128) { if (m_dirty == 0xff) { i2c_write(m_bus,cmd,sizeof(cmd),1,1); @@ -239,24 +243,23 @@ int SSD1306::sync() } m_dirty = 0; } - return 0; } int SSD1306::readByte(uint8_t x, uint8_t y, uint8_t *b) { - if ((x >= m_maxx) || (y >= m_maxy)) { + if ((x >= m_width) || (y >= m_height)) { log_dbug(TAG,"off display %u,%u",x,y); return 1; } uint8_t shift = y & 7; uint8_t pg = y >> 3; - uint16_t idx = pg * m_maxx + x; + uint16_t idx = pg * m_width + x; uint8_t b0 = m_disp[idx]; if (shift) { b0 >>= shift; - idx += m_maxx; - if (idx < (m_maxx*m_maxy)) { + idx += m_width; + if (idx < (m_width*m_height)) { uint8_t b1 = m_disp[idx]; b1 <<= (8-shift); b0 |= b1; @@ -278,6 +281,7 @@ int SSD1306::drawMasked(uint8_t x, uint8_t y, uint8_t b, uint8_t m) } +/* static uint16_t scaleDouble(uint8_t byte) { uint16_t r = 0; @@ -294,6 +298,7 @@ static uint16_t scaleDouble(uint8_t byte) } return r; } +*/ /* @@ -321,12 +326,12 @@ int SSD1306::drawBits(uint8_t x, uint8_t y, uint8_t b, uint8_t n) b &= masks[n-1]; // log_dbug(TAG,"drawBits(%u,%u,%x,%u)",x,y,b,n); uint8_t pg = y >> 3; - unsigned off = pg * m_maxx + x; + unsigned off = pg * m_width + x; uint8_t shl = y & 7; uint16_t b0 = (uint16_t)b << shl; uint8_t b1 = (uint8_t)(b0 >> 8); if (b1) - m_disp[off+m_maxx] |= b1; + m_disp[off+m_width] |= b1; m_disp[off] |= (uint8_t)(b0&0xff); // log_dbug(TAG,"drawBits %x at %u",b0,off); return 0; @@ -336,15 +341,15 @@ int SSD1306::drawBits(uint8_t x, uint8_t y, uint8_t b, uint8_t n) int SSD1306::drawByte(uint8_t x, uint8_t y, uint8_t b) { uint8_t pg = y >> 3; - uint16_t idx = pg * m_maxx + x; - if ((x >= m_maxx) || (y >= m_maxy)) { + uint16_t idx = pg * m_width + x; + if ((x >= m_width) || (y >= m_height)) { log_dbug(TAG,"off display %u,%u=%u pg=%u",(unsigned)x,(unsigned)y,(unsigned)idx,(unsigned)pg); return 1; } uint8_t shift = y & 7; if (shift != 0) { - uint16_t idx2 = idx + m_maxx; - if (idx2 >= (m_maxx*m_maxy)) + uint16_t idx2 = idx + m_width; + if (idx2 >= (m_width*m_height)) return 1; m_dirty |= 1<<(pg+1); uint16_t w = (uint16_t) b << shift; @@ -366,6 +371,7 @@ int SSD1306::drawByte(uint8_t x, uint8_t y, uint8_t b) } +/* int SSD1306::drawChar(char c) { PROFILE_FUNCTION(); @@ -458,23 +464,21 @@ int SSD1306::drawChar(char c) } -int SSD1306::drawBitmap(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *data) +void SSD1306::drawBitmap(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *data, int32_t fg, int32_t bg) { unsigned len = w*h; - log_dbug(TAG,"drawBitmap(%u,%u,%u,%u) %u/%u",x,y,w,h,len,len/8); + log_dbug(TAG,"drawBitmap(%u,%u,%u,%u,%d,%d)",x,y,w,h,fg,bg); unsigned idx = 0; uint8_t b = 0; while (idx != len) { if ((idx & 7) == 0) b = data[idx>>3]; - if (b&0x80) - setPixel(x+idx%w,y+idx/w); - else - clrPixel(x+idx%w,y+idx/w); + int32_t col = b & 0x80 ? fg : bg; + if (col != -1) + setPixel(x+idx%w,y+idx/w,col); b<<=1; ++idx; } - return 0; } @@ -516,13 +520,13 @@ int SSD1306::drawBitmap_ssd1306(uint16_t x, uint16_t y, uint16_t w, uint16_t h, if (byte) { // drawBits(x0,yoff,byte,numb); uint8_t pg = yoff >> 3; - unsigned off = pg * m_maxx + x0; + unsigned off = pg * m_width + x0; uint8_t shl = yoff & 7; uint16_t b0 = (uint16_t)byte << shl; m_disp[off] |= (uint8_t)(b0&0xff); uint8_t b1 = (uint8_t)(b0 >> 8); if (b1) - m_disp[off+m_maxx] |= b1; + m_disp[off+m_width] |= b1; } bitoff += numb; break; @@ -533,12 +537,12 @@ int SSD1306::drawBitmap_ssd1306(uint16_t x, uint16_t y, uint16_t w, uint16_t h, } -int SSD1306::clrPixel(uint16_t x, uint16_t y) +int SSD1306::pClrPixel(uint16_t x, uint16_t y) { -// log_dbug(TAG,"setPixel(%u,%u)",(unsigned)x,(unsigned)y); - if ((x < m_maxx) && (y < m_maxy)) { +// log_dbug(TAG,"clrPixel(%u,%u)",(unsigned)x,(unsigned)y); + if ((x < m_width) && (y < m_height)) { uint8_t pg = y >> 3; - uint8_t *p = m_disp + pg * m_maxx + x; + uint8_t *p = m_disp + pg * m_width + x; uint8_t bit = 1 << (y & 7); uint8_t b = *p; if ((b & bit) != 0) { @@ -551,12 +555,12 @@ int SSD1306::clrPixel(uint16_t x, uint16_t y) } -int SSD1306::setPixel(uint16_t x, uint16_t y) +int SSD1306::pSetPixel(uint16_t x, uint16_t y) { // log_dbug(TAG,"setPixel(%u,%u)",(unsigned)x,(unsigned)y); - if ((x < m_maxx) && (y < m_maxy)) { + if ((x < m_width) && (y < m_height)) { uint8_t pg = y >> 3; - uint8_t *p = m_disp + pg * m_maxx + x; + uint8_t *p = m_disp + pg * m_width + x; uint8_t bit = 1 << (y & 7); uint8_t b = *p; if ((b & bit) == 0) { @@ -569,12 +573,37 @@ int SSD1306::setPixel(uint16_t x, uint16_t y) } -void SSD1306::drawHLine(uint8_t x, uint8_t y, uint8_t n) +int SSD1306::setPixel(uint16_t x, uint16_t y, int32_t col) { - if ((x + n > m_maxx) || (y >= m_maxy)) +// log_dbug(TAG,"setPixel(%u,%u)",(unsigned)x,(unsigned)y); + if ((x < m_width) && (y < m_height)) { + uint8_t pg = y >> 3; + uint8_t *p = m_disp + pg * m_width + x; + uint8_t bit = 1 << (y & 7); + uint8_t b = *p; + if (col) { + if ((b & bit) == 0) { + *p = b | bit; + m_dirty |= (1 << pg); + } + } else { + if ((b & bit) != 0) { + *p = b & ~bit; + m_dirty |= (1 << pg); + } + } + return 0; + } + return -1; +} + + +void SSD1306::drawHLine(uint8_t x, uint8_t y, uint8_t n, int32_t col) +{ + if ((x + n > m_width) || (y >= m_height) || (col != 1)) return; uint8_t pg = y >> 3; - uint16_t off = x + pg * m_maxx; + uint16_t off = x + pg * m_width; uint8_t m = 1 << (y & 7); uint8_t *p = m_disp+off; do { @@ -588,11 +617,13 @@ void SSD1306::drawHLine(uint8_t x, uint8_t y, uint8_t n) } -void SSD1306::drawVLine(uint8_t x, uint8_t y, uint8_t n) +void SSD1306::drawVLine(uint8_t x, uint8_t y, uint8_t n, int32_t col) { + if ((x >= m_width) || (y >= m_height) || (col != 1)) + return; while (n) { uint8_t pg = y >> 3; - uint16_t off = x + pg * m_maxx; + uint16_t off = x + pg * m_width; uint8_t shift = y & 7; uint8_t m = 0; if ((shift == 0) && (n >= 8)) { @@ -621,7 +652,7 @@ void SSD1306::drawVLine(uint8_t x, uint8_t y, uint8_t n) int SSD1306::clearRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h) { log_dbug(TAG,"clearRect(%u,%u,%u,%u)",x,y,w,h); - if ((x > m_maxx) || (y >= m_maxy)) + if ((x > m_width) || (y >= m_height)) return 1; for (int i = x; i < x+w; ++i) { uint16_t y0 = y; @@ -640,15 +671,17 @@ int SSD1306::clearRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h) } return 0; } +*/ -int SSD1306::drawRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h) +/* +int SSD1306::drawRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, int32_t col) { log_dbug(TAG,"drawRect(%u,%u,%u,%u)",x,y,w,h); - drawHLine(x,y,w); - drawHLine(x,y+h-1,w); - drawVLine(x,y,h); - drawVLine(x+w-1,y,h); + drawHLine(x,y,w,col); + drawHLine(x,y+h-1,w,col); + drawVLine(x,y,h,col); + drawVLine(x+w-1,y,h,col); return 0; } @@ -676,7 +709,7 @@ int SSD1306::setPos(uint16_t x, uint16_t y) log_dbug(TAG,"setPos(%u/%u)",x,y); x *= CHAR_WIDTH; y *= fontHeight(); - if ((x >= m_maxx-(CHAR_WIDTH)) || (y > m_maxy-fontHeight())) { + if ((x >= m_width-(CHAR_WIDTH)) || (y > m_height-fontHeight())) { log_dbug(TAG,"invalid pos %u/%u",x,y); return 1; } @@ -701,6 +734,7 @@ int SSD1306::write(const char *text, int len) } return n; } +*/ SSD1306 *SSD1306::create(uint8_t bus, uint8_t addr) diff --git a/drv/i2c/ssd1306.h b/drv/i2c/ssd1306.h index 85aac2a..c0a2516 100644 --- a/drv/i2c/ssd1306.h +++ b/drv/i2c/ssd1306.h @@ -19,11 +19,11 @@ #ifndef SSD1306_H #define SSD1306_H -#include "display.h" +#include "ssd130x.h" #include "fonts_ssd1306.h" #include "i2cdrv.h" -class SSD1306 : public DotMatrix, public I2CDevice +class SSD1306 : public SSD130X, public I2CDevice { public: enum hwcfg_t : uint8_t { @@ -33,19 +33,17 @@ class SSD1306 : public DotMatrix, public I2CDevice }; SSD1306(uint8_t bus, uint8_t addr); - ~SSD1306(); static SSD1306 *create(uint8_t bus, uint8_t addr); int init(uint8_t maxx, uint8_t maxy, uint8_t options); - int drawBitmap(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *data) override; - int drawRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h) override; - int clearRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h) override; +// int drawBitmap(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *data, int32_t fg, int32_t bg) override; +// int drawRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, int32_t col) override; + /* int write(const char *t, int n) override; int writeHex(uint8_t, bool) override; int clear() override; int clrEol() override; - int sync() override; uint16_t maxX() const override { return m_maxx; } @@ -64,53 +62,48 @@ class SSD1306 : public DotMatrix, public I2CDevice return 0; } - int setFont(int f) override + int setFont(unsigned f) override { m_font = (fontid_t) f; return 0; } + */ + void flush() override; int setFont(const char *) override; - int setContrast(uint8_t contrast) override; - int setPos(uint16_t x, uint16_t y) override; + int setBrightness(uint8_t contrast) override; +// int setPos(uint16_t x, uint16_t y) override; int setInvert(bool inv) override; int setOn(bool on) override; - const char *drvName() const - { return "ssd1306"; } - - bool hasAlpha() const override - { return true; } +// uint16_t numLines() const override; +// uint16_t charsPerLine() const override; - bool hasChar(char) const override - { return true; } +// void setPixel(uint16_t x, uint16_t y, int32_t col) override; - uint8_t numLines() const override; - uint8_t charsPerLine() const override; + const char *drvName() const + { return "ssd1306"; } static SSD1306 *getInstance() { return Instance; } - int setPixel(uint16_t x, uint16_t y) override; - int clrPixel(uint16_t x, uint16_t y) override; - int setDim(uint8_t c) override - { return setContrast(c); } - uint8_t maxDim() const override + uint8_t maxBrightness() const override { return 255; } private: - int drawBitmap_ssd1306(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *data); +// int drawBitmap_ssd1306(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *data); int drawByte(uint8_t x, uint8_t y, uint8_t b); int drawBits(uint8_t x, uint8_t y, uint8_t b, uint8_t n); - void drawHLine(uint8_t x, uint8_t y, uint8_t n); - void drawVLine(uint8_t x, uint8_t y, uint8_t n); +// void drawHLine(uint16_t x, uint16_t y, uint16_t n); +// void drawVLine(uint8_t x, uint8_t y, uint8_t n); int drawChar(char c); int readByte(uint8_t x, uint8_t y, uint8_t *b); int drawMasked(uint8_t x, uint8_t y, uint8_t b, uint8_t m); uint8_t fontHeight() const; static SSD1306 *Instance; - uint8_t *m_disp = 0; - uint8_t m_maxx = 0, m_maxy = 0, m_posx = 0, m_posy = 0, m_dirty = 0xff; +// uint8_t m_maxx = 0, m_maxy = 0, m_posx = 0, m_posy = 0; +// uint8_t *m_disp = 0; +// uint8_t m_dirty = 0xff; fontid_t m_font = font_native; }; diff --git a/drv/spi/CMakeLists.txt b/drv/spi/CMakeLists.txt index fe37adf..687cd4b 100644 --- a/drv/spi/CMakeLists.txt +++ b/drv/spi/CMakeLists.txt @@ -2,6 +2,8 @@ set(COMPONENT_SRCS spidrv.cpp sx1276.cpp ssd1309.cpp + ili9341.cpp + xpt2046.cpp ) set(COMPONENT_REQUIRES actions display env logging nvm xio) set(COMPONENT_ADD_INCLUDEDIRS .) diff --git a/drv/spi/ili9341.cpp b/drv/spi/ili9341.cpp new file mode 100644 index 0000000..e0faa3c --- /dev/null +++ b/drv/spi/ili9341.cpp @@ -0,0 +1,1134 @@ +/* + * Copyright (C) 2023, Thomas Maier-Komor + * Atrium Firmware Package for ESP + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#ifdef CONFIG_ILI9341 + +#include "ili9341.h" +#include "log.h" +#include "profiling.h" +#include "terminal.h" + +#include +#include + +#include +#include + +#define TAG MODULE_ILI9341 + +#if IDF_VERSION >= 50 +#define ets_delay_us esp_rom_delay_us +#endif + +#if 1 +#define log_devel log_dbug +#else +#define log_devel(...) +#endif + +#define SPI_MAX_TX 4096 + +#define CHAR_WIDTH 6 +#define CHAR_HEIGHT 8 + +#define CMD_NOP 0x00 +#define CMD_RESET 0x01 // software reset +#define CMD_RDINFO 0x04 // read display identification information +#define CMD_RDDST 0x09 // read display status +#define CMD_RDDPM 0x0a // read display power mode +#define CMD_RDMADCTL 0x0b // read display madctl +#define CMD_RDDCOLMOD 0x0c // read display pixel format +#define CMD_RDIMGFMT 0x0d // read display image format +#define CMD_RDSIGMD 0x0e // read display signal mode +#define CMD_RDDSDR 0x0f // read BIST result +#define CMD_SLEEPIN 0x10 // enter sleep mode +#define CMD_SLEEPOUT 0x11 // exit sleep mode +#define CMD_PARTMDON 0x12 // partial mode on +#define CMD_NORMMDON 0x13 // normal mode on +#define CMD_INVOFF 0x20 // display inversion off +#define CMD_INVON 0x21 // display inversion on +#define CMD_GAMSET 0x26 // gamma set +#define CMD_DISPOFF 0x28 // display off +#define CMD_DISPON 0x29 // display on +#define CMD_CASET 0x2a // column address set +#define CMD_PASET 0x2b // page address set +#define CMD_RAMWR 0x2c // memory write +#define CMD_COLORSET 0x2d // color set +#define CMD_MEMRD 0x2e // memory read +#define CMD_PARTAREA 0x30 // partial area +#define CMD_VSCRLDEF 0x33 // vertial scrolling definition +#define CMD_TEAROFF 0x34 // tearing effect line off +#define CMD_TEARON 0x35 // tearing effect line on +#define CMD_MADCTL 0x36 // memory access control +#define CMD_VSCRLST 0x37 // vertial scrolling start address +#define CMD_IDMOFF 0x38 // idle mode off +#define CMD_IDMON 0x39 // idle mode on +#define CMD_COLMOD 0x3a // colmod: pixel format set +#define CMD_WRMEMC 0x3c // write memory continue +#define CMD_RDMEMC 0x3e // read memory continue +#define CMD_SETTEAR 0x44 // set tear scanline +#define CMD_GETSL 0x45 // get scanline +#define CMD_WRBRIGHT 0x51 // write brightness +#define CMD_RDBRIGHT 0x52 // read brightness +#define CMD_WRCTRLD 0x53 // write CTRL display +#define CMD_RDCTRLD 0x54 // read CTRL display +#define CMD_WRCADBR 0x55 // write content adaptive brightness control +#define CMD_RDCADBR 0x56 // read content adaptive brightness control +#define CMD_WRMINBR 0x5e // write CABC minimum brightness +#define CMD_RDMINBR 0x5f // read CABC minimum brightness +#define CMD_FRMCTR1 0x81 // frame control normal +#define CMD_ETMOD 0x87 // enter mode +#define CMD_DISCTRL 0xb6 +#define CMD_PWCTRL1 0xc0 +#define CMD_PWCTRL2 0xc1 +#define CMD_PWCTRLA 0xcb +#define CMD_PWCTRLB 0xcf +#define CMD_VMCTRL1 0xc5 +#define CMD_VMCTRL2 0xc7 +#define CMD_RDID1 0xda // read ID1 +#define CMD_RDID2 0xdb // read ID2 +#define CMD_RDID3 0xdc // read ID3 +#define CMD_PGAMCTRL 0xe0 // positive gamma correction +#define CMD_NGAMCTRL 0xe1 // negative gamma correction +#define CMD_TIMCTRLA 0xe8 +#define CMD_TIMCTRLB 0xea +#define CMD_PWRSEQ 0xed +#define CMD_IFCTL 0xf6 + +#define MADCTL_T2B 0x00 +#define MADCTL_L2R 0x00 +#define MADCTL_NRM 0x00 +#define MADCTL_RGB 0x00 +#define MADCTL_RL2R 0x00 + +#define MADCTL_B2T 0x80 +#define MADCTL_R2L 0x40 +#define MADCTL_REV 0x20 +#define MADCTL_RR2L 0x04 +#define MADCTL_MY (1<<7) +#define MADCTL_MX (1<<6) +#define MADCTL_MV (1<<5) +#define MADCTL_ML (1<<4) +#define MADCTL_BGR (1<<3) +#define MADCTL_MH (1<<2) + + +struct CmdName { + uint8_t id; + const char *name; +}; + +CmdName CmdNames[] = { + { CMD_NOP, "NOP" }, + { CMD_RESET, "RESET" }, + { CMD_RDINFO, "RDINFO" }, + { CMD_RDDST, "RDDST" }, + { CMD_RDDPM, "RDDPM" }, + { CMD_RDMADCTL, "RDMADCTL" }, + { CMD_RDDCOLMOD, "RDDCOLMOD" }, + { CMD_RDIMGFMT, "RDIMGFMT" }, + { CMD_RDSIGMD, "RDSIGMD" }, + { CMD_RDDSDR, "RDDSDR" }, + { CMD_SLEEPIN, "SLEEPIN" }, + { CMD_SLEEPOUT, "SLEEPOUT" }, + { CMD_PARTMDON, "PARTMDON" }, + { CMD_NORMMDON, "NORMMDON" }, + { CMD_INVOFF, "INVOFF" }, + { CMD_INVON, "INVON" }, + { CMD_GAMSET, "GAMSET" }, + { CMD_DISPOFF, "DISPOFF" }, + { CMD_DISPON, "DISPON" }, + { CMD_CASET, "CASET" }, + { CMD_PASET, "PASET" }, + { CMD_RAMWR, "RAMWR" }, + { CMD_COLORSET, "COLORSET" }, + { CMD_MEMRD, "MEMRD" }, + { CMD_PARTAREA, "PARTAREA" }, + { CMD_VSCRLDEF, "VSCRLDEF" }, + { CMD_TEAROFF, "TEAROFF" }, + { CMD_TEARON, "TEARON" }, + { CMD_MADCTL, "MADCTL" }, + { CMD_VSCRLST, "VSCRLST" }, + { CMD_IDMOFF, "IDMOFF" }, + { CMD_IDMON, "IDMON" }, + { CMD_COLMOD, "COLMOD" }, + { CMD_WRMEMC, "WRMEMC" }, + { CMD_RDMEMC, "RDMEMC" }, + { CMD_SETTEAR, "SETTEAR" }, + { CMD_GETSL, "GETSL" }, + { CMD_WRBRIGHT, "WRBRIGHT" }, + { CMD_RDBRIGHT, "RDBRIGHT" }, + { CMD_WRCTRLD, "WRCTRLD" }, + { CMD_RDCTRLD, "RDCTRLD" }, + { CMD_WRCADBR, "WRCADBR" }, + { CMD_RDCADBR, "RDCADBR" }, + { CMD_WRMINBR, "WRMINBR" }, + { CMD_RDMINBR, "RDMINBR" }, + { CMD_FRMCTR1, "FRMCTR1" }, + { CMD_ETMOD, "ETMOD" }, + { CMD_DISCTRL, "DISCTRL" }, + { CMD_PWCTRL1, "PWCTRL1" }, + { CMD_PWCTRL2, "PWCTRL2" }, + { CMD_PWCTRLA, "PWCTRLA" }, + { CMD_PWCTRLB, "PWCTRLB" }, + { CMD_VMCTRL1, "VMCTRL1" }, + { CMD_VMCTRL2, "VMCTRL2" }, + { CMD_RDID1, "RDID1" }, + { CMD_RDID2, "RDID2" }, + { CMD_RDID3, "RDID3" }, + { CMD_PGAMCTRL, "PGAMCTRL" }, + { CMD_NGAMCTRL, "NGAMCTRL" }, + { CMD_TIMCTRLA, "TIMCTRLA" }, + { CMD_TIMCTRLB, "TIMCTRLB" }, + { CMD_PWRSEQ, "PWRSEQ" }, + { CMD_IFCTL, "IFCTL" }, + +}; + +ILI9341 *ILI9341::Instance = 0; + + +ILI9341::ILI9341(uint8_t cs, uint8_t dc, int8_t reset, SemaphoreHandle_t sem, spi_device_handle_t hdl) +: MatrixDisplay(cs_bgr16) +, SpiDevice(drvName(), cs) +, m_hdl(hdl) +, m_sem(sem) +, m_dc((gpio_num_t)dc) +, m_reset((gpio_num_t)reset) +{ + writeCmd(CMD_RESET); + vTaskDelay(10/portTICK_PERIOD_MS); + uint8_t id[4]; + readRegs(CMD_RDINFO,id,sizeof(id)); + log_info(TAG,"display info %02x,%02x,%02x",id[1],id[2],id[3]); + setOn(false); + uint8_t a0xed[] = {0x55, 0x01, 0x23, 0x01}; + writeCmdArg(CMD_PWRSEQ,a0xed,sizeof(a0xed)); + uint8_t a0xe8[] = {0x85, 0x00, 0x78}; + writeCmdArg(CMD_TIMCTRLA,a0xe8,sizeof(a0xe8)); + uint8_t a0xea[] = {0x00, 0x00}; + writeCmdArg(CMD_TIMCTRLB,a0xea,sizeof(a0xea)); + writeCmdArg(CMD_PWCTRL1,0x21); + writeCmdArg(CMD_PWCTRL2,0x10); + uint8_t vcom[] = { 0x31, 0x3c }; + writeCmdArg(CMD_VMCTRL1,vcom,sizeof(vcom)); + writeCmdArg(CMD_VMCTRL2,0x86); + writeCmdArg(CMD_COLMOD,0x5); + writeCmd(CMD_INVOFF); + writeCmd(CMD_IDMON); + uint8_t colmod[2]; + readRegs(CMD_RDDCOLMOD,colmod,sizeof(colmod)); + log_info(TAG,"colmod 0x%02x",colmod[1]); + sleepOut(); + setOn(true); +} + + +ILI9341::~ILI9341() +{ + free(m_temp); + free(m_os); +} + + +void ILI9341::checkPowerMode() +{ + uint8_t dpm[3]; + readRegs(CMD_RDDPM,dpm,sizeof(dpm)); + log_info(TAG,"booster %s, idle %s, partial %s, sleep %s, normal %s, display %s" + , dpm[2] & 0x80 ? "on" : "off" + , dpm[2] & 0x40 ? "on" : "off" + , dpm[2] & 0x20 ? "on" : "off" + , dpm[2] & 0x10 ? "on" : "off" + , dpm[2] & 0x8 ? "on" : "off" + , dpm[2] & 0x4 ? "on" : "off" + ); +} + + +inline void ILI9341::setC() +{ + gpio_set_level(m_dc,0); +} + + +inline void ILI9341::setD() +{ + gpio_set_level(m_dc,1); +} + + +#ifdef CONFIG_IDF_TARGET_ESP8266 +ILI9341 *ILI9341::create(spi_host_device_t host, int8_t cs, int8_t dc, int8_t reset) +#else +ILI9341 *ILI9341::create(spi_host_device_t host, spi_device_interface_config_t &cfg, int8_t dc, int8_t reset) +#endif +{ + assert(sizeof(wchar_t) == sizeof(uint16_t)); // needed for wmemset + if (Instance) { + log_warn(TAG,"instance already exists"); + return 0; + } + if ((dc < 0) || (reset < 0)) + return 0; + log_dbug(TAG,"create with cs=%d, dc=%d, reset=%d",cfg.spics_io_num,dc,reset); + if (esp_err_t e = gpio_set_direction((gpio_num_t)dc,GPIO_MODE_OUTPUT)) { + log_warn(TAG,"cannot set gpio%d to output: %s",dc,esp_err_to_name(e)); + return 0; + } + gpio_set_level((gpio_num_t)dc,0); + if (esp_err_t e = gpio_set_direction((gpio_num_t)cfg.spics_io_num,GPIO_MODE_OUTPUT)) { + log_warn(TAG,"cannot set gpio%d to output: %s",cfg.spics_io_num,esp_err_to_name(e)); + return 0; + } + if (reset >= 0) { + if (esp_err_t e = gpio_set_direction((gpio_num_t)reset,GPIO_MODE_OUTPUT)) { + log_warn(TAG,"cannot set gpio%d to output: %s",reset,esp_err_to_name(e)); + return 0; + } + log_dbug(TAG,"reset triggered"); + gpio_set_level((gpio_num_t)reset,0); + ets_delay_us(100); // reset-pulse >= 10us + gpio_set_level((gpio_num_t)reset,1); + vTaskDelay(120); // wait 120ms after reset + } + SemaphoreHandle_t sem = xSemaphoreCreateBinary(); + cfg.command_bits = 0; + cfg.address_bits = 0; + cfg.cs_ena_pretrans = 0; + cfg.clock_speed_hz = SPI_MASTER_FREQ_8M; // maximum: 10MHz + cfg.queue_size = 8; + cfg.post_cb = spidrv_post_cb_relsem; + spi_device_handle_t hdl; + if (esp_err_t e = spi_bus_add_device(host,&cfg,&hdl)) { + log_warn(TAG,"device add failed: %s",esp_err_to_name(e)); + return 0; + } + Instance = new ILI9341(cfg.spics_io_num, dc, reset, sem, hdl); + return Instance; +} + + +void ILI9341::reset() +{ + log_dbug(TAG,"reset triggered"); + gpio_set_level(m_reset,0); + ets_delay_us(15); // reset-pulse >= 10us + gpio_set_level(m_reset,1); + vTaskDelay(5); // wait 5ms after reset +} + + +void ILI9341::sleepIn() +{ + if (writeCmd(CMD_SLEEPIN)) + log_warn(TAG,"sleep-in failed"); + vTaskDelay(120); // wait 120ms to reach sleep +} + + +void ILI9341::sleepOut() +{ + log_dbug(TAG,"request sleep-out"); + writeCmd(CMD_SLEEPOUT); + vTaskDelay(10); // wait >= 5ms after sleep-out +} + + +int ILI9341::init(uint16_t maxx, uint16_t maxy, uint8_t options) +{ + log_info(TAG,"init(%u,%u)",maxx,maxy); + if (maxx < maxy) + writeCmdArg(CMD_MADCTL,0x48); + else + writeCmdArg(CMD_MADCTL,0x28); + uint8_t madctl[2]; + readRegs(CMD_RDMADCTL,madctl,sizeof(madctl)); + log_info(TAG,"madctl: 0x%02x",madctl[1]); + m_width = maxx; + m_height = maxy; + unsigned foss = maxx*maxy<<1; + m_temp = (uint16_t *) heap_caps_malloc(SPI_MAX_TX, MALLOC_CAP_DMA); + if (m_temp == 0) { + log_error(TAG,"Out of memory."); + return 1; + } + m_oss = 32 << 10; + m_os = (uint16_t *) heap_caps_malloc(m_oss, MALLOC_CAP_DMA); + if (m_os == 0) { + m_oss = heap_caps_get_largest_free_block(MALLOC_CAP_DMA); + m_os = (uint16_t *) heap_caps_malloc(m_oss, MALLOC_CAP_DMA); + if (m_os == 0) { + m_oss = 16 << 10; + m_os = (uint16_t *) malloc(m_oss); + if (m_os == 0) { + m_oss = 8 << 10; + m_os = (uint16_t *) malloc(m_oss); + if (m_os == 0) { + log_warn(TAG,"No memory for off-screen rendering."); + m_oss = 0; + } + } + } + } else if (m_oss == foss) { + log_dbug(TAG,"full off-screen buffer"); + m_fos = true; + m_osx = 0; + m_osy = 0; + m_osw = maxx; + m_osh = maxy; + } + log_dbug(TAG,"off-screen buffer: %u Bytes",m_oss); +// checkPowerMode(); + writeCmd(CMD_IDMOFF); + initOK(); + log_info(TAG,"ready"); + return 0; +} + + +int ILI9341::setOn(bool on) +{ + log_dbug(TAG,"setOn(%d)",on); + return writeCmd(on ? CMD_DISPON : CMD_DISPOFF); +} + +int ILI9341::setInvert(bool inv) +{ + log_dbug(TAG,"invert(%d)",inv); + return writeCmd(inv ? CMD_INVON : CMD_INVOFF); +} + + +int ILI9341::setBrightness(uint8_t v) +{ + log_dbug(TAG,"setBrightness(%u)",v); + return writeCmdArg(CMD_WRBRIGHT,v); +} + + +uint8_t ILI9341::fontHeight() const +{ + switch (m_font) { + case -1: return 8; + case -2: return 16; + default: + return Fonts[m_font].yAdvance; + } +} + +void ILI9341::flush() +{ + log_dbug(TAG,"flush %ux%u",m_width,m_height); + PROFILE_FUNCTION(); + if (m_os) + commitOffScreen(); +} + + +/* + * @param bg: -1: read from device, -2: do not init + */ +int ILI9341::setupOffScreen(uint16_t x, uint16_t y, uint16_t w, uint16_t h, int32_t bg) +{ + log_dbug(TAG,"setupOffScreen(%u,%u,%u,%u,%x)",x,y,w,h,bg); + if ((x+w > m_width) || (y+h > m_height) || (w*h<<1 > m_oss)) + return -1; + if (m_fos) + return 0; + m_osx = x; + m_osy = y; + m_osw = w; + m_osh = h; + if (bg >= 0) { + wchar_t f = bg; + wmemset((wchar_t*)m_os,f,w*h); + if ((w*h) & 1) + m_os[(w*h<<1)-1] = (uint16_t)(bg & 0xffff); + } else { + // read screen content + uint8_t caset[] = { (uint8_t)(x>>8), (uint8_t)(x&0xff), (uint8_t)((x+w-1)>>8), (uint8_t)((x+w-1)&0xff) }; + writeCmdArg(CMD_CASET,caset,sizeof(caset)); + uint8_t paset[] = { (uint8_t)(y>>8), (uint8_t)(y&0xff), (uint8_t)((y+h-1)>>8), (uint8_t)((y+h-1)&0xff) }; + writeCmdArg(CMD_PASET,paset,sizeof(paset)); + writeCmd(CMD_MEMRD); + readData((uint8_t*)m_os,w*h*2); + } + return 0; +} + + +void ILI9341::commitOffScreen() +{ + PROFILE_FUNCTION(); + log_dbug(TAG,"commitOffScreen() %u/%u->%u/%u",m_osx,m_osy,m_osx+m_osw,m_osy+m_osh); + uint8_t caset[] = { (uint8_t)(m_osx>>8), (uint8_t)(m_osx&0xff), (uint8_t)((m_osx+m_osw-1)>>8), (uint8_t)((m_osx+m_osw-1)&0xff) }; + writeCmdArg(CMD_CASET,caset,sizeof(caset)); + uint8_t paset[] = { (uint8_t)(m_osy>>8), (uint8_t)(m_osy&0xff), (uint8_t)((m_osy+m_osh-1)>>8), (uint8_t)((m_osy+m_osh-1)&0xff) }; + writeCmdArg(CMD_PASET,paset,sizeof(paset)); + writeCmd(CMD_RAMWR); + // TODO: full-off-screen is in non-DMA - i.e. could be one transaction + uint32_t n = m_osw*m_osh<<1; + uint32_t t = n > SPI_MAX_TX ? SPI_MAX_TX : n; + writeData((uint8_t*)m_os,t); + uint32_t off = 0; + n -= t; + while (n) { + off += t; + t = n > SPI_MAX_TX ? SPI_MAX_TX : n; + writeCmd(CMD_WRMEMC); + writeData((uint8_t*)m_os+off,t); + n -= t; + } +} + + +void ILI9341::drawBitmap(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *data, int32_t fg, int32_t bg) +{ + log_dbug(TAG,"drawBitmap(%u,%u,%u,%u,...,%x,%x)",x,y,w,h,fg,bg); + if ((x >= m_width) || (y >= m_height)) + return; + if ((x + w) > m_width) + w = m_width - x; + if ((y + h) > m_height) + h = m_height - x; + if ((w == 0) || (h == 0)) + return; + uint16_t fgc = fg >= 0 ? (uint16_t)(fg & 0xffff) : m_colfg; + unsigned len = w*h; + unsigned idx = 0; + uint8_t b = 0; + if ((x >= m_osx) && (x+w < m_osx+m_osw) && (y >= m_osy) && (y < m_osy+m_osh)) { + if (bg == -2) { + while (idx != len) { + if ((idx & 7) == 0) + b = data[idx>>3]; + if (b&0x80) + m_os[(x+idx%w-m_osx)+(y+idx/w-m_osy)*m_osw] = fgc; + b<<=1; + ++idx; + } + } else { + uint16_t bgc = bg >= 0 ? (uint16_t)(bg & 0xffff) : m_colbg; + while (idx != len) { + if ((idx & 7) == 0) + b = data[idx>>3]; + m_os[(x+idx%w-m_osx)+(y+idx/w-m_osy)*m_osw] = b&0x80 ? fgc : bgc; + b<<=1; + ++idx; + } + } + } else if (bg == -2) { + while (idx != len) { + if ((idx & 7) == 0) + b = data[idx>>3]; + if (b&0x80) + setPixel(x+idx%w,y+idx/w,fgc); + b<<=1; + ++idx; + } + } else { + uint16_t bgc = bg >= 0 ? (uint16_t)(bg & 0xffff) : m_colbg; + while (idx != len) { + if ((idx & 7) == 0) + b = data[idx>>3]; + setPixel(x+idx%w,y+idx/w,b&0x80?fgc:bgc); + b<<=1; + ++idx; + } + } + +} + + +void ILI9341::setPixel(uint16_t x, uint16_t y, int32_t col) +{ +// log_devel(TAG,"setPixel(%u,%u,%x) temp %u/%u+%u/%u",(unsigned)x,(unsigned)y,col,m_osx,m_osy,m_osw,m_osh); + if ((x >= m_width) || (y >= m_height) || (col < 0) || (col > UINT16_MAX)) + return; + uint16_t c = col >= 0 ? (uint16_t)(col & 0xffff) : m_colfg; + if ((x >= m_osx) && (x < m_osx+m_osw) && (y >= m_osy) && (y < m_osy+m_osh)) { + m_os[(x-m_osx)+(y-m_osy)*m_osw] = c; + } else { + log_devel(TAG,"setPixel(%u,%u,%x) offscreen temp %u/%u+%u/%u",(unsigned)x,(unsigned)y,col,m_osx,m_osy,m_osw,m_osh); + uint8_t caset[] = { (uint8_t)(x>>8), (uint8_t)(x&0xff), (uint8_t)((x+1)>>8), (uint8_t)((x+1)&0xff) }; + writeCmdArg(CMD_CASET,caset,sizeof(caset)); + uint8_t paset[] = { (uint8_t)(y>>8), (uint8_t)(y&0xff), (uint8_t)((y+1)>>8), (uint8_t)((y+1)&0xff) }; + writeCmdArg(CMD_PASET,paset,sizeof(paset)); + writeCmd(CMD_RAMWR); + writeData((uint8_t*)&c,2); + } +} + + +void ILI9341::drawHLine(uint16_t x, uint16_t y, uint16_t n, int32_t col) +{ + log_dbug(TAG,"drawHLine(%d,%d,%u,%x)",x,y,n,col); + if (x >= m_width) + return; + if ((x + n) > m_width) + n = m_width-x; + uint16_t c = col >= 0 ? (uint16_t) (col & 0xffff) : m_colfg; + fillRect(x,y,n,1,c); +} + + +void ILI9341::drawVLine(uint16_t x, uint16_t y, uint16_t n, int32_t col) +{ + log_dbug(TAG,"drawVLine(%d,%d,%u,%x)",x,y,n,col); + if (y >= m_height) + return; + if ((y + n) > m_height) + n = m_height - y; + uint16_t c = col >= 0 ? (uint16_t) (col & 0xffff) : m_colfg; + fillRect(x,y,1,n,c); +} + + +int32_t ILI9341::getColor(color_t c) const +{ + switch (c) { + case WHITE: return 0xffff; + case BLACK: return 0x0000; + case BLUE: return 0xfc00; + case RED: return 0x03c0; + case GREEN: return 0x007f; +// case PURPLE: return 0xffc0; + case YELLOW: return 0x03ff; + case CYAN: return 0xfc7f; + case MAGENTA: return 0x0fc0; + default: return -1; + } +} + + +void ILI9341::fillRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, int32_t c) +{ + PROFILE_FUNCTION(); + log_dbug(TAG,"fillRect(%d,%d,%d,%d,%x)",x,y,w,h,c); + uint16_t col = c == -1 ? m_colfg : (uint16_t)(c&0xffff); + if ((x >= m_osx) && (y >= m_osy) && (x+w < m_osx+m_osw) && (y+w < m_osy+m_osh)) { + for (uint16_t j = y; j < y+h; ++j) { + for (uint16_t i = x; i < x+w; ++i) + m_os[(j-m_osy) * m_osw + i - m_osx] = col; + } + } else { + uint8_t caset[] = { (uint8_t)(x>>8), (uint8_t)(x&0xff), (uint8_t)((x+w-1)>>8), (uint8_t)((x+w-1)&0xff) }; + writeCmdArg(CMD_CASET,caset,sizeof(caset)); + uint8_t paset[] = { (uint8_t)(y>>8), (uint8_t)(y&0xff), (uint8_t)((y+h-1)>>8), (uint8_t)((y+h-1)&0xff) }; + writeCmdArg(CMD_PASET,paset,sizeof(paset)); + writeCmd(CMD_RAMWR); + unsigned n = w*h; + unsigned b = (n*2 > SPI_MAX_TX) ? (SPI_MAX_TX>>1) : n; + log_dbug(TAG,"n=%u, b=%u",n,b); + wmemset((wchar_t*)m_temp,col,b); + setD(); + do { + unsigned s = ((n<<1) > SPI_MAX_TX) ? SPI_MAX_TX : n<<1; + writeBytes((uint8_t*)m_temp,s); + n -= (s >> 1); + } while (n); + } +} + + +int ILI9341::readRegs(uint8_t reg, uint8_t *data, uint8_t num) +{ + if (Modules[TAG]) { + const char *cmd = "???"; + for (auto &c : CmdNames) { + if (c.id == reg) { + cmd = c.name; + break; + } + } + log_dbug(TAG,"0x%02x/CMD_%s",reg,cmd); + } + assert(num > 1); + bzero(data,num); + setC(); + spi_transaction_t *t = getTransaction(); + bzero(t,sizeof(*t)); + t->user = m_sem; + if (num <= 4) { + t->tx_data[0] = reg; + t->flags = SPI_TRANS_USE_RXDATA|SPI_TRANS_USE_TXDATA; + } else { + uint8_t *txbuf = (uint8_t*)alloca(num); + bzero(txbuf,num); + txbuf[0] = reg; + t->tx_buffer = txbuf; + } + t->rx_buffer = data; + t->length = num << 3; + t->rxlength = num << 3; + if (esp_err_t e = spi_device_queue_trans(m_hdl,t,portMAX_DELAY)) { + log_warn(TAG,"error queuing read: %s",esp_err_to_name(e)); + return -1; + } + if (pdTRUE != xSemaphoreTake(m_sem,MUTEX_ABORT_TIMEOUT)) + abort_on_mutex(m_sem,"ili9341"); + if (num <= 4) + memcpy(data,t->rx_data,num); + log_hex(TAG,data,num,"read regs %u@0x%02x:",num,reg); + return 0; +} + + +/* + * The text is assumed to fit into the off-screen rendering buffer. + * No control-chars may be handed to this function. + */ +unsigned ILI9341::drawChars(const char *at, const char *e, int32_t fg, int32_t bg) +{ + log_devel(TAG,"drawChars(%s,%d,%x,%x)",at,e-at,fg,bg); + uint16_t x = m_osx; + while (at != e) { + x += drawChar(x,m_osy,*at,fg,bg); + ++at; + } + return x; +} + +unsigned ILI9341::drawText(uint16_t x, uint16_t y, const char *txt, int n, int32_t fg, int32_t bg) +{ + log_dbug(TAG,"drawText(%d,%d,'%s')",x,y,txt); + if (n < 0) + n = strlen(txt); + const Font *font = Fonts+(int)m_font; + uint16_t h= font->yAdvance; + uint16_t a = 0; + const char *at = txt, *e = txt + n; + while (at != e) { + char c = *at; + if (c == '\n') { + x = 0; + y += h; + ++at; + } + if (c == 0) + return a; + uint16_t da = 0; + const char *st = at; + while (at != e) { + c = *at; + if (c == 0) + break; + if (c == '\n') + break; + uint16_t cw = charWidth(c); + if (m_posx + cw > m_width) // TODO fix + return a; + if (((da + cw) * h<<1) > m_oss) + break; + da += cw; + ++at; + } + if ((da * h << 1 > m_oss) || (st == at)) { + // too big for off-screen rendering + break; + } + if (!m_fos) + setupOffScreen(x+a,y,da,h,bg == -1 ? m_colbg : bg); + drawChars(st,at,fg,bg); + a += da; + if (!m_fos) + commitOffScreen(); + } + if (at != e) + log_dbug(TAG,"drawText on screen"); + while (at != e) { + if (*at == '\n') { + x = 0; + y += fontHeight(); + ++at; + } + if (*at == 0) + break; + x += drawChar(x,y,*at,fg,bg); + ++at; + } + return a; +#if 0 + uint16_t width = 0; + const char *e = txt + n; + const char *at = txt; + while (at != e) { + char c = *at++; + if ((c < font->first) || (c > font->last)) + continue; + if (c == '\n') { + height += font->yAdvance; + } else { + uint8_t ch = c - font->first; + if (x + font->glyph[ch].xAdvance > m_width) + break; + width += font->glyph[ch].xAdvance; + } + } + e = at; + at = txt; + while (at != e) { + // TODO + uint8_t c = *at++; + const uint8_t *data = font->bitmap + font->glyph[c].bitmapOffset; + } + return a; +#endif +} + + +int ILI9341::writeCmd(uint8_t v) +{ + if (Modules[TAG]) { + const char *cmd = "???"; + for (auto &c : CmdNames) { + if (c.id == v) { + cmd = c.name; + break; + } + } + log_devel(TAG,"writeCmd 0x%02x/CMD_%s",v,cmd); + } +#if 0 + setC(); + spi_transaction_t t; + bzero(&t,sizeof(t)); + t.user = m_sem; + t.cmd = v; + if (esp_err_t e = spi_device_queue_trans(m_hdl,&t,1)) { + log_warn(TAG,"error queuing writeCmd: %s",esp_err_to_name(e)); + return -1; + } + if (pdTRUE != xSemaphoreTake(m_sem,MUTEX_ABORT_TIMEOUT)) + abort_on_mutex(m_sem,"ili9341"); +#else + setC(); + writeByte(v); +#endif + return 0; +} + + +int ILI9341::writeCmdArg(uint8_t v, uint8_t a) +{ + if (Modules[TAG]) { + const char *cmd = "???"; + for (auto &c : CmdNames) { + if (c.id == v) { + cmd = c.name; + break; + } + } + log_dbug(TAG,"writeCmdArg 0x%02x/CMD_%s 0x%02x",v,cmd,a); + } +#if 0 + setC(); + spi_transaction_t t; + bzero(&t,sizeof(t)); + t.user = m_sem; + t.cmd = v; + t.length = 8; + t.tx_data[0] = v; + t.flags = SPI_TRANS_USE_TXDATA; + if (esp_err_t e = spi_device_queue_trans(m_hdl,&t,1)) { + log_warn(TAG,"error queuing writeCmdArg: %s",esp_err_to_name(e)); + return -1; + } + if (pdTRUE != xSemaphoreTake(m_sem,MUTEX_ABORT_TIMEOUT)) + abort_on_mutex(m_sem,"ili9341"); +#else + setC(); + writeByte(v); + setD(); + writeByte(a); +#endif + return 0; +} + + +int ILI9341::writeCmdArg(uint8_t v, uint8_t *a, size_t n) +{ + if (Modules[TAG]) { + const char *cmd = "???"; + for (auto &c : CmdNames) { + if (c.id == v) { + cmd = c.name; + break; + } + } + log_hex(TAG,a,n,"writeCmdArg 0x%02x/CMD_%s",v,cmd); + } +#if 0 + setC(); + spi_transaction_t t; + bzero(&t,sizeof(t)); + t.user = m_sem; + t.cmd = v; + t.length = n << 3; + if (n <= 4) { + t.flags = SPI_TRANS_USE_TXDATA; + memcpy(t.tx_data,a,n); + } else { + t.tx_buffer = a; + } + if (esp_err_t e = spi_device_queue_trans(m_hdl,&t,1)) { + log_warn(TAG,"error queuing writeCmdArg: %s",esp_err_to_name(e)); + return -1; + } + if (pdTRUE != xSemaphoreTake(m_sem,MUTEX_ABORT_TIMEOUT)) + abort_on_mutex(m_sem,"ili9341"); +#else + setC(); + writeByte(v); + setD(); + writeBytes(a,n); +#endif + return 0; +} + + +int ILI9341::writeData(uint8_t v) +{ + setD(); + return writeByte(v); +} + + +int ILI9341::writeData(uint8_t *v, unsigned len) +{ + setD(); + return writeBytes(v,len); +} + + +int ILI9341::readData(uint8_t *v, unsigned len) +{ + setD(); + return readBytes(v,len); +} + + +int ILI9341::readBytes(uint8_t *data, unsigned len) +{ + // TODO test + log_devel(TAG,"readBytes %p: %u",data,len); + assert(data); + esp_err_t e = 0; + size_t off = 0; + spi_device_acquire_bus(m_hdl,portMAX_DELAY); + while (len) { + spi_transaction_t *t = getTransaction(); + bzero(t,sizeof(*t)); + t->tx_buffer = data + off; + t->rx_buffer = data + off; + if (len > SPI_MAX_TX) { + t->length = SPI_MAX_TX<<3; + t->rxlength = SPI_MAX_TX<<3; + t->flags = SPI_TRANS_CS_KEEP_ACTIVE; + len -= SPI_MAX_TX; + off += SPI_MAX_TX; + } else { + t->length = len<<3; + t->rxlength = len<<3; + len = 0; + t->user = m_sem; + } + log_devel(TAG,"readBytes %d@%p",t->length>>3,t->tx_buffer); + e = spi_device_queue_trans(m_hdl,t,portMAX_DELAY); + if (e) { + log_warn(TAG,"error queuing readBytes: %s",esp_err_to_name(e)); + return -1; + } + } + if (pdTRUE != xSemaphoreTake(m_sem,MUTEX_ABORT_TIMEOUT*4)) + abort_on_mutex(m_sem,"ili9341"); + return 0; + +} + + +int ILI9341::writeByte(uint8_t v) +{ + spi_transaction_t *t = getTransaction(); + bzero(t,sizeof(*t)); +// t->user = m_sem; + t->cmd = v; + t->length = 8; + t->flags = SPI_TRANS_USE_TXDATA; + t->tx_data[0] = v; + if (esp_err_t e = spi_device_queue_trans(m_hdl,t,portMAX_DELAY)) { + log_warn(TAG,"error queuing writeByte: %s",esp_err_to_name(e)); + return -1; + } +// if (pdTRUE != xSemaphoreTake(m_sem,MUTEX_ABORT_TIMEOUT)) +// abort_on_mutex(m_sem,"ili9341"); +// log_dbug(TAG,"writeB 0x%02x",v); + return 0; +} + + +spi_transaction_t *ILI9341::getTransaction() +{ + while (m_xtrans == 0xff) { + spi_transaction_t *r; + esp_err_t x = spi_device_get_trans_result(m_hdl,&r,portMAX_DELAY); + if (x == 0) { + int id = r - m_trans; + if ((id >= 0) && (id < 8)) + m_xtrans &= ~(1<rxlength = 8; + t->flags = SPI_TRANS_USE_RXDATA; + t->tx_buffer = data; + if (end-data > SPI_MAX_TX) { + t->length = SPI_MAX_TX<<3; + data += SPI_MAX_TX; + } else { + t->length = len<<3; + t->user = m_sem; + len = 0; + data = end; + } +// log_devel(TAG,"writeBytes %d@%p",t.length>>3,t.tx_buffer); + e = spi_device_queue_trans(m_hdl,t,portMAX_DELAY); + if (e) + break; + } + if (e == 0) { + if (pdTRUE != xSemaphoreTake(m_sem,MUTEX_ABORT_TIMEOUT*4)) + abort_on_mutex(m_sem,"ili9341"); + } else { + log_warn(TAG,"error queuing writeBytes: %s",esp_err_to_name(e)); + } + return 0; +} + + +const char *ILI9341::exeCmd(struct Terminal &t, int argc, const char **argv) +{ + if (argc == 0) + return 0; + unsigned arg2 = 0x100; + if (argc >= 2) { + char *e; + long l = strtol(argv[1],&e,0); + if ((*e == 0) && (l >= 0) && (l <= UINT8_MAX)) + arg2 = l; + } + if (!strcmp(argv[0],"info")) { + uint8_t v[3]; + readRegs(CMD_RDINFO,v,sizeof(v)); + } else if (!strcmp(argv[0],"status")) { + uint8_t v[5]; + readRegs(CMD_RDDST,v,sizeof(v)); + t.printf("booster is %s\n",v[2]&128?"on":"off"); + t.printf("row is %s\n",v[2]&64?"bottom-to-top":"top-to-bottom"); + t.printf("column is %s\n",v[2]&32?"right-to-left":"left-to-right"); + t.printf("reverse is %s\n",v[2]&16?"on":"off"); + t.printf("refresh is %s\n",v[2]&8?"bottom-to-top":"top-to-bottom"); + t.printf("refresh is %s\n",v[2]&2?"right-to-left":"left-to-right"); + t.printf("color is %s\n",v[2]&4?"BGR":"RGB"); + } else if (!strcmp(argv[0],"bright")) { + if ((argc == 1) || (arg2 == 0x100)) { + uint8_t v[2]; + readRegs(CMD_RDBRIGHT,v,sizeof(v)); + t.printf("brightness %u\n",v[1]); + } else { + writeCmdArg(CMD_WRBRIGHT,arg2); +// t.printf("brightness %u",arg2); + } + } else if (!strcmp(argv[0],"mode")) { + uint8_t v[2]; + readRegs(CMD_RDDPM,v,sizeof(v)); + t.printf("display is %s\n",v[1]&4?"on":"off"); + t.printf("sleep is %s\n",v[1]&16?"on":"off"); + t.printf("idle is %s\n",v[1]&64?"on":"off"); + t.printf("booster is %s\n",v[1]&128?"on":"off"); + } else if (!strcmp(argv[0],"madctl")) { + if ((argc == 1) || (arg2 == 0x100)) { + uint8_t v[2]; + readRegs(CMD_RDMADCTL,v,sizeof(v)); + t.printf("madctl=0x%x,%x,%x\n",v[0],v[1]); + t.printf("%s, %s\n",v[1]&128?"bottom-to-top":"top-to-bottom",v[1]&64?"right-to-left":"left-to-right"); + t.printf("reverse is %s\n",v[1]&32?"on":"off"); + t.printf("refresh is %s\n",v[1]&16?"bottom-to-top":"top-to-bottom"); + t.printf("color is %s\n",v[1]&8?"BGR":"RGB"); + t.printf("refresh is %s\n",v[1]&4?"right-to-left":"left-to-right"); + } else { + writeCmdArg(CMD_MADCTL,arg2); + } + } else if (!strcmp(argv[0],"colmod")) { + if ((argc == 1) || (arg2 == 0x100)) { + uint8_t colmod[2]; + readRegs(CMD_RDDCOLMOD,colmod,sizeof(colmod)); + log_info(TAG,"colmod 0x%02x",colmod[1]); + } else { + writeCmdArg(CMD_COLMOD,arg2); + } + } else { + char *e; + long l = strtol(argv[0],&e,0); + uint8_t arg1 = 0; + if ((*e == 0) && (l >= 0) && (l <= UINT8_MAX)) { + arg1 = (uint8_t) l; + } else { + arg1 = 0; + for (const auto &c : CmdNames) { + if (0 == strcasecmp(c.name,argv[0])) { + arg1 = c.id; + break; + } + } + } + if (arg1) { + if (arg2 == 0x100) + writeCmd(arg1); + else + writeCmdArg(arg1,arg2); + } else { + return "Invalid argument #1."; + } + } + return 0; + } + +#endif + diff --git a/drv/spi/ili9341.h b/drv/spi/ili9341.h new file mode 100644 index 0000000..e7dfd5b --- /dev/null +++ b/drv/spi/ili9341.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2023, Thomas Maier-Komor + * Atrium Firmware Package for ESP + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ILI9341_H +#define ILI9341_H + +#ifdef ESP32 +#include "display.h" +#include "spidrv.h" + +#include +#include + +#include + + +class ILI9341 : public MatrixDisplay, public SpiDevice +{ + public: + ~ILI9341(); + + typedef spi_host_device_t spi_host_t; + static ILI9341 *create(spi_host_t host, spi_device_interface_config_t &cfg, int8_t dc, int8_t reset); + int init(uint16_t maxx, uint16_t maxy, uint8_t options); + + void fillRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, int32_t c = -1) override; + void drawBitmap(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *data, int32_t fg = -1, int32_t bg = -1) override; + void setPixel(uint16_t x, uint16_t y, int32_t c) override; + const char *exeCmd(struct Terminal &, int argc, const char **argv) override; + void flush() override; + int32_t getColor(color_t) const override; + + int setFont(unsigned f) override + { + m_font = (fontid_t) f; + return 0; + } + + int setBrightness(uint8_t contrast) override; + int setInvert(bool inv) override; + int setOn(bool on) override; + + const char *drvName() const + { return "ili9341"; } + + bool hasAlpha() const override + { return true; } + + bool hasChar(char) const override + { return true; } + + static ILI9341 *getInstance() + { return Instance; } + + void drawHLine(uint16_t x, uint16_t y, uint16_t n, int32_t col = -1) override; + void drawVLine(uint16_t x, uint16_t y, uint16_t n, int32_t col = -1) override; + unsigned drawText(uint16_t x, uint16_t y, const char *txt, int n, int32_t fg, int32_t bg) override; + + private: + ILI9341(uint8_t cs, uint8_t cd, int8_t r, SemaphoreHandle_t sem, spi_device_handle_t hdl); + uint8_t fontHeight() const; + static void postCallback(spi_transaction_t *t); + void setC(); + void setD(); + void sleepIn(); + void sleepOut(); + void reset(); + int readRegs(uint8_t reg, uint8_t *data, uint8_t num); + int readBytes(uint8_t *data, unsigned len); + int writeByte(uint8_t); + int writeBytes(uint8_t *data, unsigned len); + int readData(uint8_t *data, unsigned len); + int writeData(uint8_t data); + int writeData(uint8_t *data, unsigned len); + int writeCmd(uint8_t v); + int writeCmdArg(uint8_t v, uint8_t a); + int writeCmdArg(uint8_t v, uint8_t *a, size_t n); + void checkPowerMode(); + unsigned drawChars(const char *at, const char *e, int32_t fg, int32_t bg); + void drawBitmapOffScr(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *data, int32_t fg, int32_t bg); + int setupOffScreen(uint16_t x, uint16_t y, uint16_t w, uint16_t h, int32_t bg); + void commitOffScreen(); + + static int readRegs(spi_device_handle_t hdl, uint8_t reg, uint8_t num, uint8_t *data, SemaphoreHandle_t); + spi_transaction_t *getTransaction(); + + static ILI9341 *Instance; + uint32_t m_oss = 0; + uint16_t m_colfg = 0xffff, m_colbg = 0; // foreground/background color + uint16_t *m_os = 0, *m_temp = 0; + uint16_t m_osx = 0xffff, m_osy = 0xffff, m_osw, m_osh; + spi_device_handle_t m_hdl; + SemaphoreHandle_t m_sem; + spi_transaction_t m_trans[8]; + uint8_t m_xtrans = 0; + bool m_fos = false; // full off-screen memory + gpio_num_t m_dc, m_reset; +}; + + +#endif // ESP32 +#endif diff --git a/drv/spi/spidrv.cpp b/drv/spi/spidrv.cpp index 27c6951..d99911d 100644 --- a/drv/spi/spidrv.cpp +++ b/drv/spi/spidrv.cpp @@ -93,6 +93,33 @@ void SpiDevice::updateName() } } +#ifdef ESP32 +IRAM_ATTR void spidrv_post_cb_relsem(spi_transaction_t *t) +{ + SemaphoreHandle_t sem = (SemaphoreHandle_t) t->user; + if (sem) // not every transaction wants to release the semaphore + xSemaphoreGive(sem); +} + +int spidrv_read_regs(spi_device_handle_t hdl, uint8_t reg, uint8_t num, uint8_t *data, SemaphoreHandle_t sem) +{ + spi_transaction_t t; + bzero(&t,sizeof(t)); + t.user = sem; + t.addr = reg; + t.length = num<<3; + t.rxlength = num<<3; + t.rx_buffer = data; + if (esp_err_t e = spi_device_queue_trans(hdl,&t,1)) { + log_warn(TAG,"error queuing read: %s",esp_err_to_name(e)); + return -1; + } + if (pdTRUE != xSemaphoreTake(sem,MUTEX_ABORT_TIMEOUT)) + abort_on_mutex(sem,"ili9341"); + log_hex(TAG,data,num,"read regs %u@%u:",num,reg); + return 0; +} +#endif //ESP32 #endif diff --git a/drv/spi/spidrv.h b/drv/spi/spidrv.h index 5ceadda..49f39ba 100644 --- a/drv/spi/spidrv.h +++ b/drv/spi/spidrv.h @@ -22,6 +22,9 @@ #include #include +#include +#include + #ifdef CONFIG_IDF_TARGET_ESP8266 #include #else @@ -82,6 +85,15 @@ class SpiDevice }; +extern "C" { #endif // __cplusplus +#ifdef ESP32 +void spidrv_post_cb_relsem(spi_transaction_t *t); +int spidrv_read_regs(spi_device_handle_t hdl, uint8_t reg, uint8_t num, uint8_t *data, SemaphoreHandle_t); +#endif + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus #endif diff --git a/drv/spi/ssd1309.cpp b/drv/spi/ssd1309.cpp index c830fc8..c4bac3c 100644 --- a/drv/spi/ssd1309.cpp +++ b/drv/spi/ssd1309.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022, Thomas Maier-Komor + * Copyright (C) 2022-2023, Thomas Maier-Komor * Atrium Firmware Package for ESP * * This program is free software: you can redistribute it and/or modify @@ -69,12 +69,6 @@ SSD1309::SSD1309(spi_host_t host, int8_t cs, uint8_t dc, int8_t reset, struct sp } -SSD1309::~SSD1309() -{ - free(m_disp); -} - - inline void SSD1309::setC() { gpio_set_level(m_dc,0); @@ -137,12 +131,12 @@ int SSD1309::init(uint16_t maxx, uint16_t maxy, uint8_t hwcfg) gpio_set_level(m_reset,1); ets_delay_us(100); } - m_maxx = maxx; - m_maxy = maxy; + m_width = maxx; + m_height = maxy; uint32_t dsize = maxx * maxy; m_disp = (uint8_t *) malloc(dsize); // two dimensional array of n pages each of n columns. if (m_disp == 0) { - log_error(TAG,"out of memory"); + log_error(TAG,"Out of memory."); return 1; } /* works, but column 127 is at offset 0. Related to a1 command? @@ -150,7 +144,7 @@ int SSD1309::init(uint16_t maxx, uint16_t maxy, uint8_t hwcfg) uint8_t setup[] = { 0xae, // display off 0xd5, 0x80, // oszi freq (default), clock div=1 (optional) - 0xa8, (uint8_t)(m_maxy-1), // MUX + 0xa8, (uint8_t)(m_height-1), // MUX 0xd3, 0x00, // display offset (optional) 0x40, // display start line (optional) 0x8d, 0x14, // enable charge pump @@ -174,7 +168,7 @@ int SSD1309::init(uint16_t maxx, uint16_t maxy, uint8_t hwcfg) uint8_t setup[] = { 0xae, // display off 0xd5, 0x80, // oszi freq (default), clock div=1 (optional) - 0xa8, (uint8_t)(m_maxy-1), // MUX + 0xa8, (uint8_t)(m_height-1), // MUX 0xd3, 0x00, // display offset (optional) 0x40, // display start line (optional) 0x8d, 0x14, // enable charge pump @@ -200,7 +194,7 @@ int SSD1309::init(uint16_t maxx, uint16_t maxy, uint8_t hwcfg) // display off 0xae, // MUX - 0xa8, (uint8_t)(m_maxy-1), + 0xa8, (uint8_t)(m_height-1), // display offset (optional) 0xd3, 0x00, // display start line (optional) @@ -240,7 +234,7 @@ int SSD1309::init(uint16_t maxx, uint16_t maxy, uint8_t hwcfg) return 1; } clear(); - sync(); + flush(); setOn(true); initOK(); log_info(TAG,"ready"); @@ -260,19 +254,20 @@ int SSD1309::setInvert(bool inv) } -int SSD1309::setContrast(uint8_t contrast) +int SSD1309::setBrightness(uint8_t contrast) { return writeWord(0x81,contrast); } -int SSD1309::clear() +/* +void SSD1309::clear() { - uint8_t numpg = m_maxy >> 3; + uint8_t numpg = m_height >> 3; uint8_t pg = 0; do { - uint8_t *at = m_disp + m_maxx * pg; - uint8_t *pge = at + m_maxx; + uint8_t *at = m_disp + m_width * pg; + uint8_t *pge = at + m_width; do { if (*at) break; @@ -286,8 +281,8 @@ int SSD1309::clear() m_posx = 0; m_posy = 0; log_dbug(TAG,"clear: dirty %x",m_dirty); - return 0; } +*/ uint8_t SSD1309::fontHeight() const @@ -301,9 +296,10 @@ uint8_t SSD1309::fontHeight() const } +/* int SSD1309::clrEol() { - clearRect(m_posx,m_posy,m_maxx-m_posx,fontHeight()); + clearRect(m_posx,m_posy,m_width-m_posx,fontHeight()); return 0; } @@ -311,14 +307,14 @@ int SSD1309::clrEol() uint8_t SSD1309::charsPerLine() const { if (m_font == font_nativedbl) - return m_maxx/CHAR_WIDTH<<1; - return m_maxx/CHAR_WIDTH; + return m_width/CHAR_WIDTH<<1; + return m_width/CHAR_WIDTH; } uint8_t SSD1309::numLines() const { - return m_maxy/fontHeight(); + return m_height/fontHeight(); } @@ -340,32 +336,33 @@ int SSD1309::setFont(const char *fn) } return -1; } +*/ -int SSD1309::sync() +void SSD1309::flush() { if (m_dirty == 0) - return 0; + return; PROFILE_FUNCTION(); //writeByte(0xb0); -// uint8_t cmd[] = { 0x22, 0x00, (uint8_t)(m_maxx-1) }; +// uint8_t cmd[] = { 0x22, 0x00, (uint8_t)(m_width-1) }; uint8_t cmd[] = { 0x00, 0x01, 0xb0 }; - uint8_t numpg = m_maxy / 8 + ((m_maxy & 7) != 0); - unsigned pgs = m_maxx; + uint8_t numpg = m_height / 8 + ((m_height & 7) != 0); + unsigned pgs = m_width; if (pgs == 128) { if (m_dirty == 0xff) { writeBytes(cmd,sizeof(cmd)); setD(); writeBytes(m_disp,128*8); setC(); -// log_dbug(TAG,"sync 0-7"); +// log_dbug(TAG,"flush 0-7"); m_dirty = 0; } else if (m_dirty == 0xf) { writeBytes(cmd,sizeof(cmd)); setD(); writeBytes(m_disp,128*4); setC(); -// log_dbug(TAG,"sync 0-3"); +// log_dbug(TAG,"flush 0-3"); m_dirty = 0; } } @@ -377,15 +374,15 @@ int SSD1309::sync() setD(); writeBytes(m_disp+p*pgs,pgs); setC(); -// log_dbug(TAG,"sync %u",p); +// log_dbug(TAG,"flush %u",p); } } m_dirty = 0; } - return 0; } +/* static uint16_t scaleDouble(uint8_t byte) { uint16_t r = 0; @@ -402,6 +399,7 @@ static uint16_t scaleDouble(uint8_t byte) } return r; } +*/ /* @@ -429,12 +427,12 @@ int SSD1309::drawBits(uint16_t x, uint16_t y, uint8_t b, uint8_t n) b &= masks[n]; // log_dbug(TAG,"drawBits(%u,%u,%x,%u)",x,y,b,n); uint8_t pg = y >> 3; - unsigned off = pg * m_maxx + x; + unsigned off = pg * m_width + x; uint8_t shl = y & 7; uint16_t b0 = (uint16_t)b << shl; uint8_t b1 = (uint8_t)(b0 >> 8); if (b1) - m_disp[off+m_maxx] |= b1; + m_disp[off+m_width] |= b1; m_disp[off] |= (uint8_t)(b0&0xff); // log_dbug(TAG,"drawBits %x at %u",b0,off); return 0; @@ -444,15 +442,15 @@ int SSD1309::drawBits(uint16_t x, uint16_t y, uint8_t b, uint8_t n) int SSD1309::drawByte(uint16_t x, uint16_t y, uint8_t b) { uint8_t pg = y >> 3; - uint16_t idx = pg * m_maxx + x; - if ((x >= m_maxx) || (y >= m_maxy)) { + uint16_t idx = pg * m_width + x; + if ((x >= m_width) || (y >= m_height)) { log_dbug(TAG,"off display %u,%u=%u pg=%u",(unsigned)x,(unsigned)y,(unsigned)idx,(unsigned)pg); return 1; } uint8_t shift = y & 7; if (shift != 0) { - uint16_t idx2 = idx + m_maxx; - if (idx2 >= (m_maxx*m_maxy)) + uint16_t idx2 = idx + m_width; + if (idx2 >= (m_width*m_height)) return 1; m_dirty |= 1<<(pg+1); uint16_t w = (uint16_t) b << shift; @@ -474,6 +472,7 @@ int SSD1309::drawByte(uint16_t x, uint16_t y, uint8_t b) } +/* int SSD1309::drawChar(char c) { PROFILE_FUNCTION(); @@ -559,14 +558,14 @@ int SSD1309::drawChar(char c) // log_info(TAG,"%d/%d %+d/%+d, adv %u len %u",(int)w,(int)h,(int)dx,(int)dy,a,l); // clearRect(m_posx,m_posy,dx+w,a); // drawBitmap(m_posx+dx,m_posy+dy+font->yAdvance,w,h,off); - drawBitmap_ssd1309(m_posx+dx,m_posy+dy+font->yAdvance-1,w,h,off); + drawBitmapNative(m_posx+dx,m_posy+dy+font->yAdvance-1,w,h,off); m_posx += a; return 0; } -int SSD1309::drawBitmap(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *data) +int SSD1309::drawBitmap(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *data, int32_t fg, int32_t bg) { unsigned len = w*h; log_dbug(TAG,"drawBitmap(%u,%u,%u,%u) %u/%u",x,y,w,h,len,len/8); @@ -575,15 +574,13 @@ int SSD1309::drawBitmap(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const ui while (idx != len) { if ((idx & 7) == 0) b = data[idx>>3]; - if (b&0x80) - setPixel(x+idx%w,y+idx/w); - else - clrPixel(x+idx%w,y+idx/w); + setPixel(x+idx%w,y+idx/w,b&0x80?fg:bg); b<<=1; ++idx; } return 0; } +*/ static uint8_t getBits(const uint8_t *data, unsigned off, uint8_t numb) @@ -624,13 +621,13 @@ int SSD1309::drawBitmap_ssd1309(uint16_t x, uint16_t y, uint16_t w, uint16_t h, if (byte) { // drawBits(x0,yoff,byte,numb); uint8_t pg = yoff >> 3; - unsigned off = pg * m_maxx + x0; + unsigned off = pg * m_width + x0; uint8_t shl = yoff & 7; uint16_t b0 = (uint16_t)byte << shl; m_disp[off] |= (uint8_t)(b0&0xff); uint8_t b1 = (uint8_t)(b0 >> 8); if (b1) - m_disp[off+m_maxx] |= b1; + m_disp[off+m_width] |= b1; } bitoff += numb; break; @@ -641,12 +638,13 @@ int SSD1309::drawBitmap_ssd1309(uint16_t x, uint16_t y, uint16_t w, uint16_t h, } +/* int SSD1309::clrPixel(uint16_t x, uint16_t y) { // log_dbug(TAG,"setPixel(%u,%u)",(unsigned)x,(unsigned)y); - if ((x < m_maxx) && (y < m_maxy)) { + if ((x < m_width) && (y < m_height)) { uint8_t pg = y >> 3; - uint8_t *p = m_disp + pg * m_maxx + x; + uint8_t *p = m_disp + pg * m_width + x; uint8_t bit = 1 << (y & 7); uint8_t b = *p; if ((b & bit) != 0) { @@ -662,9 +660,9 @@ int SSD1309::clrPixel(uint16_t x, uint16_t y) int SSD1309::setPixel(uint16_t x, uint16_t y) { // log_dbug(TAG,"setPixel(%u,%u)",(unsigned)x,(unsigned)y); - if ((x < m_maxx) && (y < m_maxy)) { + if ((x < m_width) && (y < m_height)) { uint8_t pg = y >> 3; - uint8_t *p = m_disp + pg * m_maxx + x; + uint8_t *p = m_disp + pg * m_width + x; uint8_t bit = 1 << (y & 7); uint8_t b = *p; if ((b & bit) == 0) { @@ -679,10 +677,10 @@ int SSD1309::setPixel(uint16_t x, uint16_t y) void SSD1309::drawHLine(uint16_t x, uint16_t y, uint16_t n) { - if ((x + n > m_maxx) || (y >= m_maxy)) + if ((x + n > m_width) || (y >= m_height)) return; uint8_t pg = y >> 3; - uint16_t off = x + pg * m_maxx; + uint16_t off = x + pg * m_width; uint8_t m = 1 << (y & 7); uint8_t *p = m_disp+off; do { @@ -700,7 +698,7 @@ void SSD1309::drawVLine(uint16_t x, uint16_t y, uint16_t n) { while (n) { uint8_t pg = y >> 3; - uint16_t off = x + pg * m_maxx; + uint16_t off = x + pg * m_width; uint8_t shift = y & 7; uint8_t m = 0; if ((shift == 0) && (n >= 8)) { @@ -729,7 +727,7 @@ void SSD1309::drawVLine(uint16_t x, uint16_t y, uint16_t n) int SSD1309::clearRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h) { log_dbug(TAG,"clearRect(%u,%u,%u,%u)",x,y,w,h); - if ((x > m_maxx) || (y >= m_maxy)) + if ((x > m_width) || (y >= m_height)) return 1; for (int i = x; i < x+w; ++i) { uint16_t y0 = y; @@ -760,7 +758,7 @@ int SSD1309::drawRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h) // x=0 is visible at x=1 drawVLine(x,y,h); drawVLine(x+w-1,y,h); -// log_hex(TAG,m_disp,m_maxx*m_maxy/8,"frame"); +// log_hex(TAG,m_disp,m_width*m_height/8,"frame"); return 0; } @@ -788,7 +786,7 @@ int SSD1309::setPos(uint16_t x, uint16_t y) log_dbug(TAG,"setPos(%u/%u)",x,y); x *= CHAR_WIDTH; y *= fontHeight(); - if ((x >= m_maxx-(CHAR_WIDTH)) || (y > m_maxy-fontHeight())) { + if ((x >= m_width-(CHAR_WIDTH)) || (y > m_height-fontHeight())) { log_dbug(TAG,"invalid pos %u/%u",x,y); return 1; } @@ -813,6 +811,7 @@ int SSD1309::write(const char *text, int len) } return n; } +*/ IRAM_ATTR void SSD1309::postCallback(spi_transaction_t *t) @@ -836,7 +835,7 @@ int SSD1309::writeBytes(uint8_t *data, unsigned len) return -1; } if (pdTRUE != xSemaphoreTake(m_sem,MUTEX_ABORT_TIMEOUT)) - abort_on_mutex(m_sem,"sx1276"); + abort_on_mutex(m_sem,"ssd1309"); // log_hex(TAG,data,len,"writeBytes"); return 0; // spi_transaction_t *r = &t; @@ -863,7 +862,7 @@ int SSD1309::writeByte(uint8_t v) return -1; } if (pdTRUE != xSemaphoreTake(m_sem,MUTEX_ABORT_TIMEOUT)) - abort_on_mutex(m_sem,"sx1276"); + abort_on_mutex(m_sem,"ssd1309"); log_dbug(TAG,"writeB 0x%02x",v); return 0; #endif @@ -884,7 +883,7 @@ int SSD1309::writeWord(uint8_t b0, uint8_t b1) return -1; } if (pdTRUE != xSemaphoreTake(m_sem,MUTEX_ABORT_TIMEOUT)) - abort_on_mutex(m_sem,"sx1276"); + abort_on_mutex(m_sem,"ssd1309"); log_dbug(TAG,"writeW 0x%02x, 0x%02x",b0,b1); return 0; } diff --git a/drv/spi/ssd1309.h b/drv/spi/ssd1309.h index f6e96fd..d9827df 100644 --- a/drv/spi/ssd1309.h +++ b/drv/spi/ssd1309.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022, Thomas Maier-Komor + * Copyright (C) 2022-2023, Thomas Maier-Komor * Atrium Firmware Package for ESP * * This program is free software: you can redistribute it and/or modify @@ -19,7 +19,7 @@ #ifndef SSD1309_H #define SSD1309_H -#include "display.h" +#include "ssd130x.h" #include "fonts_ssd1306.h" #include "spidrv.h" @@ -29,7 +29,7 @@ #include -class SSD1309 : public DotMatrix, public SpiDevice +class SSD1309 : public SSD130X, public SpiDevice { public: enum hwcfg_t : uint8_t { @@ -38,8 +38,6 @@ class SSD1309 : public DotMatrix, public SpiDevice hwc_rlmap = 0x20, // right-to-left mapping }; - ~SSD1309(); - #ifdef CONFIG_IDF_TARGET_ESP8266 static SSD1309 *create(spi_host_t host, int8_t dc, int8_t reset); #else @@ -47,15 +45,15 @@ class SSD1309 : public DotMatrix, public SpiDevice static SSD1309 *create(spi_host_t host, spi_device_interface_config_t &cfg, int8_t dc, int8_t reset); #endif int init(uint16_t maxx, uint16_t maxy, uint8_t options); - int drawBitmap(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *data) override; - int drawRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h) override; - int clearRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h) override; + /* + int drawBitmap(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *data, int32_t fg, int32_t bg) override; + void drawRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, int32_t col) override; int write(const char *t, int n) override; int writeHex(uint8_t, bool) override; int clear() override; - int clrEol() override; - int sync() override; +// int clrEol() override; + int flush() override; uint16_t maxX() const override { return m_maxx; } @@ -81,8 +79,11 @@ class SSD1309 : public DotMatrix, public SpiDevice } int setFont(const char *) override; - int setContrast(uint8_t contrast) override; - int setPos(uint16_t x, uint16_t y) override; + */ + + void flush() override; + int setBrightness(uint8_t contrast) override; + //int setPos(uint16_t x, uint16_t y) override; int setInvert(bool inv) override; int setOn(bool on) override; const char *drvName() const @@ -94,14 +95,15 @@ class SSD1309 : public DotMatrix, public SpiDevice bool hasChar(char) const override { return true; } - uint8_t numLines() const override; - uint8_t charsPerLine() const override; +// uint16_t numLines() const override; +// uint16_t charsPerLine() const override; static SSD1309 *getInstance() { return Instance; } - int setPixel(uint16_t x, uint16_t y) override; - int clrPixel(uint16_t x, uint16_t y) override; +// void setPixel(uint16_t x, uint16_t y, int32_t v) override; +// int setPixel(uint16_t x, uint16_t y); +// int clrPixel(uint16_t x, uint16_t y); private: SSD1309(spi_host_t host, int8_t cs, uint8_t cd, int8_t r, struct spi_device_t *); @@ -122,10 +124,11 @@ class SSD1309 : public DotMatrix, public SpiDevice int writeBytes(uint8_t *data, unsigned len); static SSD1309 *Instance; - uint8_t *m_disp = 0; +// uint8_t *m_disp = 0; SemaphoreHandle_t m_sem = 0; gpio_num_t m_dc, m_reset; - uint8_t m_maxx = 0, m_maxy = 0, m_posx = 0, m_posy = 0, m_dirty = 0xff; +// uint8_t m_maxx = 0, m_maxy = 0, m_posx = 0, m_posy = 0, m_dirty = 0xff; +// uint8_t m_dirty = 0xff; fontid_t m_font = font_native; }; diff --git a/drv/spi/xpt2046.cpp b/drv/spi/xpt2046.cpp new file mode 100644 index 0000000..d5074f4 --- /dev/null +++ b/drv/spi/xpt2046.cpp @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2023, Thomas Maier-Komor + * Atrium Firmware Package for ESP + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#ifdef CONFIG_XPT2046 + +#define TAG MODULE_XPT2046 + +#include "cyclic.h" +#include "env.h" +#include "event.h" +#include "log.h" +#include "nvm.h" +#include "terminal.h" +#include "xpt2046.h" + +#include + +#define BIT_START 0x80 +#define BIT_PD_REF 0x01 +#define BIT_PD_ADC 0x02 +#define BIT_PD_BOTH 0x03 +#define BIT_SER 0x04 +#define BIT_A0 0x10 +#define BIT_A1 0x20 +#define BIT_A2 0x40 +#define REG_X (BIT_START|BIT_A2|BIT_A0) +#define REG_Y (BIT_START|BIT_A0) +#define REG_Z1 (BIT_START|BIT_A1|BIT_A0) +#define REG_Z2 (BIT_START|BIT_A2) + + +XPT2046 *XPT2046::Instance = 0; + + +XPT2046::XPT2046(uint8_t cs, int8_t intr, spi_device_handle_t hdl) +: SpiDevice(drvName(), cs) +, m_rx("rawx") +, m_ry("rawy") +, m_rz("rawz") +, m_a0("a0","%") +, m_a1("a1","%") +, m_p("p",false) +, m_hdl(hdl) +, m_sem(xSemaphoreCreateBinary()) +{ + m_evp = event_register(m_name,"`pressed"); + m_evr = event_register(m_name,"`released"); + if (intr >= 0) { + gpio_num_t i = (gpio_num_t) intr; + gpio_pad_select_gpio(i); + gpio_set_direction(i,GPIO_MODE_INPUT); + if (esp_err_t e = gpio_set_intr_type(i,GPIO_INTR_NEGEDGE)) { + log_warn(TAG,"failed to set interrupt type: %s",esp_err_to_name(e)); + } else if (esp_err_t e = gpio_isr_handler_add(i,intrHandler,(void*)this)) { + log_warn(TAG,"failed to attach interrupt handler: %s",esp_err_to_name(e)); + } + } + char tag[16]; + sprintf(tag,"xpt2046@%u",cs); + uint16_t *data = 0; + size_t n = sizeof(data); + if (0 == nvm_read_blob(tag,(uint8_t**)&data,&n)) { + m_lx = data[0]; + m_ux = data[1]; + m_ly = data[2]; + m_uy = data[3]; + m_lz = data[4]; + m_uz = data[5]; + } +} + + +void XPT2046::attach(EnvObject *root) +{ + root->add(&m_rx); + root->add(&m_ry); + root->add(&m_rz); + root->add(&m_a0); + root->add(&m_a1); + root->add(&m_p); +} + + +XPT2046 *XPT2046::create(spi_host_device_t host, spi_device_interface_config_t &cfg, int8_t intr) +{ + cfg.clock_speed_hz = SPI_MASTER_FREQ_8M; // maximum: ???MHz + cfg.post_cb = spidrv_post_cb_relsem; + cfg.queue_size = 1; + spi_device_handle_t hdl; + if (esp_err_t e = spi_bus_add_device(host,&cfg,&hdl)) { + log_warn(TAG,"device add failed: %s",esp_err_to_name(e)); + return 0; + } + Instance = new XPT2046(cfg.spics_io_num, intr, hdl); + return Instance; +} + + +unsigned XPT2046::cyclic(void *arg) +{ + XPT2046 *drv = (XPT2046 *) arg; + if ((drv->m_pwst == pw_on) || (drv->m_pwreq != pw_inv)) + drv->readRegs(); + if (drv->m_pwst == pw_on) + return 50; + if (drv->m_pwst == pw_sleep) + return 100; + return 200; +} + + +const char *XPT2046::exeCmd(struct Terminal &t, int argc, const char **args) +{ + if (argc == 0) { + const char *pwr[] = { "invalid", "off", "sleep", "on" }; + t.printf("x: %u..%u, y: %u..%u\n",m_lx,m_ux,m_ly,m_uy); + t.printf("z: release < %u, pressed > %u\n",m_lz,m_uz); + t.printf("power: %s\n",pwr[m_pwst]); + } else if (argc == 1) { + if (!strcmp(args[0],"sleep")) { + m_pwreq = pw_sleep; + } else if (!strcmp(args[0],"off")) { + m_pwreq = pw_off; + } else if (!strcmp(args[0],"on")) { + m_pwreq = pw_on; + } else if (!strcmp(args[0],"persist")) { + persist(); + } else if (!strcmp(args[0],"-h")) { + t.printf("valid commands are: on, sleep, off, persist\n"); + } else { + return "Invalid argumet #1."; + } + } else { + return "Invalid argumet #1."; + } + return 0; +} + + +void XPT2046::persist() +{ + char tag[16]; + sprintf(tag,"xpt2046@%u",m_cs); + uint16_t data[] = { + m_lx, m_ux, m_ly, m_uy, m_lz, m_uz + }; + nvm_store_blob(tag,(uint8_t*)data,sizeof(data)); +} + + +int XPT2046::init() +{ + cyclic_add_task(m_name,cyclic,this,0); + return 0; +} + + +void XPT2046::intrHandler(void *arg) +{ + XPT2046 *drv = (XPT2046 *) arg; + drv->m_pwst = pw_on; +} + + +void XPT2046::readRegs() +{ + unsigned x = 0, y = 0, z = 0; + uint8_t pflags = 0; + switch (m_pwreq) { + case pw_inv: + break; + case pw_sleep: + pflags = BIT_PD_ADC; + m_pwst = pw_sleep; + m_pwreq = pw_inv; + break; + case pw_off: + pflags = BIT_PD_BOTH; + m_pwst = pw_off; + m_pwreq = pw_inv; + break; + case pw_on: + m_pwst = pw_on; + m_pwreq = pw_inv; + break; + } + for (unsigned i = 0; i < 8; ++i) { + uint8_t txbuf[] = + { REG_X, 0x00 + , REG_Y, 0x00 + , REG_Z1, 0x00 + , 0x00 // terminating byte needed for readback + }; + if (i == 7) + txbuf[4] |= pflags; + uint8_t rxbuf[sizeof(txbuf)]; + spi_transaction_t t; + bzero(&t,sizeof(t)); + t.user = m_sem; + t.tx_buffer = txbuf; + t.rx_buffer = rxbuf; + t.length = sizeof(txbuf) << 3; + t.rxlength = sizeof(txbuf) << 3; + if (esp_err_t e = spi_device_queue_trans(m_hdl,&t,portMAX_DELAY)) { + log_warn(TAG,"error queuing read: %s",esp_err_to_name(e)); + } else { + if (pdTRUE != xSemaphoreTake(m_sem,MUTEX_ABORT_TIMEOUT)) + abort_on_mutex(m_sem,"ili9341"); +// log_hex(TAG,rxbuf,sizeof(rxbuf),"read regs"); + } + x += (rxbuf[1] << 4) | (rxbuf[2] >> 4); + y += (rxbuf[3] << 4) | (rxbuf[4] >> 4); + z += (rxbuf[5] << 4) | (rxbuf[6] >> 4); + } + x >>= 3; + y >>= 3; + z >>= 3; + if (z > m_uz) { + if ((m_lx == 0) || (x < m_lx)) + m_lx = x; + if ((m_ux == 0) || (x > m_ux)) + m_ux = x; + if ((m_ly == 0) || (y < m_ly)) + m_ly = y; + if ((m_uy == 0) || (y > m_uy)) + m_uy = y; + if (!m_pressed) { + m_pressed = true; + m_p.set(true); + event_trigger(m_evp); + } + float a0 = ((float)(x-m_lx))/((float)(m_ux-m_lx))*100.0; + m_a0.set(a0); + assert(a0 <= 100); + float a1 = ((float)(y-m_ly))/((float)(m_uy-m_ly))*100.0; + assert(a1 <= 100); + m_a1.set(a1); + } else if (z < m_lz) { + if (m_pressed) { + m_pressed = false; + m_p.set(false); + event_trigger(m_evr); + m_a0.set(0); + m_a1.set(0); + } + } + m_rx.set(x); + m_ry.set(y); + m_rz.set(z); + log_dbug(TAG,"x=%u y=%u, z=%u",x,y,z); +} + + +void XPT2046::sleep(void *arg) +{ + XPT2046 *drv = (XPT2046 *) arg; + drv->m_pwreq = pw_sleep; +} + + +void XPT2046::wake(void *arg) +{ + XPT2046 *drv = (XPT2046 *) arg; + drv->m_pwreq = pw_on; +} + + +#endif // CONFIG_XPT2046 diff --git a/drv/spi/xpt2046.h b/drv/spi/xpt2046.h new file mode 100644 index 0000000..ecbfe9b --- /dev/null +++ b/drv/spi/xpt2046.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2023, Thomas Maier-Komor + * Atrium Firmware Package for ESP + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XPT2046_H +#define XPT2046_H + +#include "spidrv.h" + +#include +#include + + +class XPT2046 : public SpiDevice +{ + public: + static XPT2046 *create(spi_host_device_t host, spi_device_interface_config_t &cfg, int8_t intr); + + const char *drvName() const override + { return "xpt2046"; } + + void attach(class EnvObject *) override; + int init() override; + const char *exeCmd(struct Terminal &, int argc, const char **argv) override; + void sleep(); + void persist(); + + private: + XPT2046(uint8_t cs, int8_t intr, spi_device_handle_t hdl); + void readRegs(); + static unsigned cyclic(void *); + static void intrHandler(void *); + static void sleep(void *); + static void wake(void *); + + typedef enum power_state_e { pw_inv = 0, pw_off = 1, pw_sleep = 2, pw_on = 3 } pwst_t; + EnvNumber m_rx, m_ry, m_rz, m_a0, m_a1; + EnvBool m_p; + event_t m_evp, m_evr; + uint16_t m_lx = 0, m_ux = 0, m_ly = 0, m_uy = 0; + uint16_t m_lz = 90, m_uz = 110; + spi_device_handle_t m_hdl; + SemaphoreHandle_t m_sem; + pwst_t m_pwreq = pw_inv, m_pwst = pw_on; + bool m_pressed = false, m_wake = false; + static XPT2046 *Instance; +}; + + +#endif + diff --git a/drv/xio/esp32_io.cpp b/drv/xio/esp32_io.cpp index 5f411a3..279ddcc 100644 --- a/drv/xio/esp32_io.cpp +++ b/drv/xio/esp32_io.cpp @@ -66,6 +66,15 @@ struct CoreIO1 : public XioCluster int set_lvl(uint8_t io, xio_lvl_t v) override; const char *getName() const override; unsigned numIOs() const override; +#if defined CONFIG_IDF_TARGET_ESP32 + #define COREIO1_NUMIO 8 +#elif defined CONFIG_IDF_TARGET_ESP32S2 + #define COREIO1_NUMIO 15 +#elif defined CONFIG_IDF_TARGET_ESP32S3 + #define COREIO1_NUMIO 17 +#else +#error unknown device +#endif }; @@ -93,7 +102,7 @@ unsigned CoreIO0::numIOs() const unsigned CoreIO1::numIOs() const { - return 8; + return COREIO1_NUMIO; } @@ -336,7 +345,7 @@ int CoreIO0::get_dir(uint8_t num) const int CoreIO1::get_dir(uint8_t num) const { - if (num >= 8) + if (num >= COREIO1_NUMIO) return -1; if (GPIO.pin[num+32].pad_driver) return xio_cfg_io_od; @@ -464,7 +473,7 @@ int CoreIO0::setm(uint32_t v, uint32_t m) int CoreIO1::setm(uint32_t v, uint32_t m) { - if (m >> 8) + if (m >> COREIO1_NUMIO) return -EINVAL; if ((v ^ m) & v) return -EINVAL; @@ -491,7 +500,7 @@ int CoreIO0::set_intr(uint8_t gpio, xio_intrhdlr_t hdlr, void *arg) int CoreIO1::set_intr(uint8_t gpio, xio_intrhdlr_t hdlr, void *arg) { - if (gpio >= 8) { + if (gpio >= COREIO1_NUMIO) { log_warn(TAG,"set intr: invalid gpio%u",gpio+32); return -EINVAL; } @@ -523,7 +532,7 @@ int CoreIO0::intr_enable(uint8_t gpio) int CoreIO1::intr_enable(uint8_t gpio) { - if (gpio >= 8) { + if (gpio >= COREIO1_NUMIO) { log_warn(TAG,"enable intr: invalid gpio%u",gpio); return -EINVAL; } @@ -554,7 +563,7 @@ int CoreIO0::intr_disable(uint8_t gpio) int CoreIO1::intr_disable(uint8_t gpio) { - if (gpio >= 8) { + if (gpio >= COREIO1_NUMIO) { log_warn(TAG,"disable intr: invalid gpio%u",gpio); return -EINVAL; } @@ -574,7 +583,7 @@ int coreio_config(uint8_t num, xio_cfg_t cfg) if (num < 32) return GpioCluster0.config(num,cfg); num -= 32; - if (num < 8) + if (num < COREIO1_NUMIO) return GpioCluster1.config(num,cfg); return -1; } @@ -585,7 +594,7 @@ int coreio_lvl_get(uint8_t num) if (num < 32) return GpioCluster0.get_lvl(num); num -= 32; - if (num < 8) + if (num < COREIO1_NUMIO) return GpioCluster1.get_lvl(num); return -1; } @@ -596,7 +605,7 @@ int coreio_lvl_hi(uint8_t num) if (num < 32) return GpioCluster0.set_hi(num); num -= 32; - if (num < 8) + if (num < COREIO1_NUMIO) return GpioCluster1.set_hi(num); return -1; } @@ -607,7 +616,7 @@ int coreio_lvl_lo(uint8_t num) if (num < 32) return GpioCluster0.set_lo(num); num -=32; - if (num < 8) + if (num < COREIO1_NUMIO) return GpioCluster1.set_lo(num); return -1; } @@ -618,7 +627,7 @@ int coreio_lvl_set(uint8_t num, xio_lvl_t l) if (num < 32) return GpioCluster0.set_lvl(num,l); num -= 32; - if (num < 8) + if (num < COREIO1_NUMIO) return GpioCluster1.set_lvl(num,l); return -1; } diff --git a/hwcfg.wfc b/hwcfg.wfc index a306512..cff0d1a 100644 --- a/hwcfg.wfc +++ b/hwcfg.wfc @@ -371,9 +371,9 @@ message GpioConfig { string name = 1; sint8 gpio = 2 [ unset = -1 ]; - // bit 1,0: gpio_mode_t: disable, input, output, output_od + // bit 1,0: gpio_mode_t: input, output, output_od // bit 4..2: gpio_int_type_t - // {0=none, 1=pos dge, 2=neg edge, 3=both edge} + // {0=none, 1=pos edge, 2=neg edge, 3=both edges} // {4=lolevel, 5=hilevel}: currently unused // bit 5: set initial level // bit 6: init level @@ -398,6 +398,9 @@ enum disp_t // monochrom displays dt_ssd1306 = 32; // I2C dt_ssd1309 = 33; // 4-wire spi + + // TFT displays + dt_ili9341 = 64; } @@ -415,6 +418,8 @@ enum spidrv_t spidrv_invalid = 0; spidrv_sx1276 = 1; spidrv_ssd1309 = 2; + spidrv_ili9341 = 3; + spidrv_xpt2046 = 4; } diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 39ebe41..ada93be 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -19,7 +19,6 @@ idf_component_register( HttpResp.cpp HttpServer.cpp i2c.cpp - inetd.cpp influx.cpp leds.cpp ledstrip.cpp diff --git a/main/Kconfig b/main/Kconfig index ac1042f..c644180 100644 --- a/main/Kconfig +++ b/main/Kconfig @@ -231,7 +231,7 @@ config USB_DIAGLOG output diagnostic log to USB serial connections config USB_CONSOLE - depends on ESP_CONSOLE_USB_SERIAL_JTAG || TINYUSB_CDC_ENABLED + depends on ESP_CONSOLE_USB_SERIAL_JTAG || ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG || TINYUSB_CDC_ENABLED bool "diag output to USB serial" default true help @@ -471,6 +471,20 @@ config SSD1309 help dirver for 4-wire SPI attached SSD1309 display +config ILI9341 + bool "ILI9341" + default false + depends on SPI && (IDF_TARGET_ESP32 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C3) + help + dirver for 4-wire SPI attached ILI9341 display + +config XPT2046 + bool "XPT2046" + default true + depends on SPI + help + driver fot XPT2046 touch controller, often found on TFT displays + config HCSR04 bool "HC-SR04" default false diff --git a/main/adc.cpp b/main/adc.cpp index 284535d..c5ee6b2 100644 --- a/main/adc.cpp +++ b/main/adc.cpp @@ -210,7 +210,11 @@ static unsigned adc_cyclic_cb(void *arg) } -#if defined CONFIG_IDF_TARGET_ESP32S3 || defined CONFIG_IDF_TARGET_ESP32C3 +// S2 support seems to be broken +// S3 had trouble, too - what config is causing this issue? +//#if defined CONFIG_IDF_TARGET_ESP32S2 || defined CONFIG_IDF_TARGET_ESP32S3 || defined CONFIG_IDF_TARGET_ESP32C3 +//#if defined CONFIG_IDF_TARGET_ESP32S3 || defined CONFIG_IDF_TARGET_ESP32C3 +#if defined CONFIG_IDF_TARGET_ESP32C3 static unsigned temp_cyclic(void *arg) { float celsius; diff --git a/main/alarms.cpp b/main/alarms.cpp index 91682da..799f448 100644 --- a/main/alarms.cpp +++ b/main/alarms.cpp @@ -85,11 +85,11 @@ static unsigned alarms_loop(void *) static uint8_t last_m = 0xf0; uint8_t h,m,s,d,md,mon; unsigned y; - if ((0 != get_time_of_day(&h,&m,&s,&d,&md,&mon,&y)) || (m == last_m)) + if (!Enabled->get()) + return 1000; + if ((0 != get_time_of_day(&h,&m,&s,&d,&md,&mon,&y)) || (s != 0) || (m == last_m)) return 300; last_m = m; - if (!Config.actions_enable()) - return 2000; //dbug("alarmclock() check %s %u:%02u",WeekDay_str((WeekDay)d),h,m); const vector &atactions = Config.at_actions(); for (size_t i = 0; i < atactions.size(); ++i) { diff --git a/main/console.cpp b/main/console.cpp index f8ddc1b..2f9dab2 100644 --- a/main/console.cpp +++ b/main/console.cpp @@ -31,15 +31,24 @@ #include "log.h" #include "shell.h" #include "swcfg.h" +#include "terminal.h" using namespace std; #define TAG MODULE_CON +#ifndef CONFIG_CONSOLE_STACK_SIZE +#define CONFIG_CONSOLE_STACK_SIZE 4096 +#endif + +#ifndef PRO_CPU_NUM +#define PRO_CPU_NUM 0 +#endif -static void console_task(void *con) +void console_task(void *con) { Terminal *term = (Terminal *)con; + log_info(TAG,"started console on %s",term->type()); for (;;) { shell(*term); } @@ -49,12 +58,6 @@ static void console_task(void *con) #ifdef CONFIG_UART_CONSOLE #include "uart_terminal.h" -#if IDF_VERSION > 32 || defined CONFIG_IDF_TARGET_ESP32 -#define DRIVER_ARG 0,0 -#else -#define DRIVER_ARG 0 -#endif - static inline void uart_console_setup(void) { int rx = HWConf.system().console_rx(); @@ -64,11 +67,9 @@ static inline void uart_console_setup(void) con->init(rx,tx); if (!Config.has_pass_hash()) con->setPrivLevel(1); - BaseType_t r = xTaskCreatePinnedToCore(console_task, "tty", 4096, con, 8, 0, PRO_CPU_NUM); + BaseType_t r = xTaskCreatePinnedToCore(console_task, "ttyS", CONFIG_CONSOLE_STACK_SIZE, con, 8, 0, PRO_CPU_NUM); if (r != pdPASS) - log_error(TAG,"create task: %s",esp_err_to_name(r)); - else - log_info(TAG,"console on UART %d/%d",rx,tx); + log_warn(TAG,"failed to create task for uart ttyS: %d",r); } } #else @@ -76,7 +77,7 @@ static inline void uart_console_setup(void) #endif // CONFIG_UART_CONSOLE -#if defined CONFIG_USB_CONSOLE && defined CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG +#if defined CONFIG_USB_CONSOLE && (defined CONFIG_IDF_TARGET_ESP32C3 || defined CONFIG_IDF_TARGET_ESP32S3) #include "jtag_terminal.h" static inline void jtag_console_setup(void) @@ -85,11 +86,9 @@ static inline void jtag_console_setup(void) if (JtagTerminal *con = new JtagTerminal(true)) { if (!Config.has_pass_hash()) con->setPrivLevel(1); - BaseType_t r = xTaskCreatePinnedToCore(console_task, "jtagtty", 4096, con, 8, 0, PRO_CPU_NUM); + BaseType_t r = xTaskCreatePinnedToCore(console_task, "ttyJ", CONFIG_CONSOLE_STACK_SIZE, con, 8, 0, PRO_CPU_NUM); if (r != pdPASS) - log_error(TAG,"create task: %s",esp_err_to_name(r)); - else - log_info(TAG,"console on JTAG"); + log_warn(TAG,"failed to create task for uart ttyJ: %d",r); } } } @@ -106,11 +105,9 @@ static inline void cdc_console_setup(void) if (CdcTerminal *con = CdcTerminal::create(true)) { if (!Config.has_pass_hash()) con->setPrivLevel(1); - BaseType_t r = xTaskCreatePinnedToCore(console_task, "cdctty", 4096, con, 8, 0, PRO_CPU_NUM); + BaseType_t r = xTaskCreatePinnedToCore(console_task, "ttyU", CONFIG_CONSOLE_STACK_SIZE, con, 8, 0, PRO_CPU_NUM); if (r != pdPASS) - log_error(TAG,"create task: %s",esp_err_to_name(r)); - else - log_info(TAG,"console on CDC"); + log_warn(TAG,"failed to create task for uart ttyU: %d",r); } } #else diff --git a/main/displays.cpp b/main/displays.cpp index a273b60..2524f9e 100644 --- a/main/displays.cpp +++ b/main/displays.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021, Thomas Maier-Komor + * Copyright (C) 2021-2023, Thomas Maier-Komor * Atrium Firmware Package for ESP * * This program is free software: you can redistribute it and/or modify @@ -24,6 +24,7 @@ #include "globals.h" #include "hwcfg.h" #include "log.h" +#include "ili9341.h" #include "MAX7219.h" #include "pcf8574.h" #include "hd44780u.h" @@ -33,7 +34,7 @@ #define TAG MODULE_DISP -int display_setup() +void display_setup() { if (HWConf.has_max7219()) { // 5V level adjustment necessary @@ -48,46 +49,50 @@ int display_setup() const DisplayConfig &c = HWConf.display(); if (!c.has_type() || !c.has_maxx()) { log_warn(TAG,"incomplete config"); - return 1; + return; } disp_t t = c.type(); - uint8_t maxx = c.maxx(); - uint8_t maxy = c.maxy(); + uint16_t maxx = c.maxx(); + uint16_t maxy = c.maxy(); if (LedCluster *l = LedCluster::getInstance()) { new SegmentDisplay(l,(SegmentDisplay::addrmode_t)t,maxx,maxy); #ifdef CONFIG_PCF8574 } else if (t == dt_pcf8574_hd44780u) { - PCF8574 *dev = PCF8574::getInstance(); - if (dev == 0) { - log_warn(TAG,"no pcf8574 found"); - return 1; + bool ok = false; + if (PCF8574 *dev = PCF8574::getInstance()) { + if (HD44780U *hd = new HD44780U(dev,maxx,maxy)) { + hd->init(); + ok = true; + } } - HD44780U *hd = new HD44780U(dev,maxx,maxy); - hd->init(); + if (!ok) + log_warn(TAG,"no pcf8574/hd44780u found"); #endif #ifdef CONFIG_SSD1306 } else if (t == dt_ssd1306) { - SSD1306 *dev = SSD1306::getInstance(); - if (dev == 0) { + if (SSD1306 *dev = SSD1306::getInstance()) + dev->init(maxx,maxy,c.options()); + else log_warn(TAG,"no ssd1306 found"); - return 1; - } - dev->init(maxx,maxy,c.options()); #endif #ifdef CONFIG_SSD1309 } else if (t == dt_ssd1309) { - SSD1309 *dev = SSD1309::getInstance(); - if (dev == 0) { - log_warn(TAG,"no ssd1306 found"); - return 1; - } - dev->init(maxx,maxy,c.options()); + if (SSD1309 *dev = SSD1309::getInstance()) + dev->init(maxx,maxy,c.options()); + else + log_warn(TAG,"no ssd1309 found"); +#endif +#ifdef CONFIG_ILI9341 + } else if (t == dt_ili9341) { + if (ILI9341 *dev = ILI9341::getInstance()) + dev->init(maxx,maxy,c.options()); + else + log_warn(TAG,"no ili9341 found"); #endif } else { log_warn(TAG,"display configured, but no LED cluster available"); } } - return 0; } #endif diff --git a/main/gpios.cpp b/main/gpios.cpp index 3be1287..5f96c72 100644 --- a/main/gpios.cpp +++ b/main/gpios.cpp @@ -330,7 +330,7 @@ const char *gpio(Terminal &term, int argc, const char *args[]) const char *n = c->getName(); unsigned num = c->numIOs(); assert(n); - term.printf("cluster %s: %u IOs\n",n,c->numIOs()); + term.printf("cluster %s: %u IOs\n",n,num); for (int i = 0; i < num; ++i) { int d = c->get_dir(i); int o = d == 2 ? c->get_out(i) : -1; diff --git a/main/inetd.cpp b/main/inetd.cpp deleted file mode 100644 index c7ee072..0000000 --- a/main/inetd.cpp +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Copyright (C) 2018-2022, Thomas Maier-Komor - * Atrium Firmware Package for ESP - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - -#ifdef CONFIG_SOCKET_API - -#include "globals.h" -#include "inetd.h" -#include "log.h" -#include "lwtcp.h" -#include "netsvc.h" -#include "shell.h" -#include "support.h" -#include "terminal.h" -#include "wifi.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined CONFIG_IDF_TARGET_ESP32 || defined CONFIG_IDF_TARGET_ESP32S3 -#include -#elif defined CONFIG_IDF_TARGET_ESP32S2 -#include -#define APP_CPU_NUM 0 -#elif defined CONFIG_IDF_TARGET_ESP32C3 -#include -#define APP_CPU_NUM 0 -#else -#define PRO_CPU_NUM 0 -#endif - -#define TCP_TIMEOUT 60 - - -struct InetArg -{ - InetArg *next; - const char *name; -#ifdef CONFIG_MDNS - const char *service; -#endif - void (*session)(void*); - uint16_t port, stack; - uint8_t prio; - inet_mode_t mode; - int sock; -}; - - -#define TAG MODULE_INETD - -static InetArg *Ports = 0; -static bool Started = false; -static fd_set PortFDs; -static int MaxFD = -1; - - -static int create_udp_socket(int port) -{ - int s = socket(AF_INET,SOCK_DGRAM,port); - int on = 1; - if (-1 == setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on))) - log_warn(TAG,"unable to enable broadcast reception: %s",strneterr(s)); - struct sockaddr_in6 addr; - bzero(&addr,sizeof(addr)); - addr.sin6_family = AF_INET6; - addr.sin6_port = htons(port); - if (-1 == bind(s,(struct sockaddr *)&addr,sizeof(addr))) - log_warn(TAG,"unable to bind socket: %s",strneterr(s)); - else - log_dbug(TAG,"created UDP/%u",port); - return s; -} - - -static int create_bcast_socket(int port) -{ - int s = create_udp_socket(port); - int on = 1; - if (-1 == setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on))) - log_warn(TAG,"unable to enable broadcast reception: %s",strneterr(s)); - else - log_dbug(TAG,"set bcast %u, socket %d",port,s); - return s; -} - - -static int create_tcp_socket(int port) -{ - log_dbug(TAG,"create TCP %u",port); - int sock = socket(AF_INET6,SOCK_STREAM,0); - if (sock < 0) { - log_error(TAG,"create socket: %s",strneterr(sock)); - return -1; - } - if (-1 == fcntl(sock,F_SETFL,O_NONBLOCK)) { - log_error(TAG,"unable to set to non-blocking: %s/%s",strneterr(sock),strerror(errno)); - close(sock); - return -1; - } - struct sockaddr_in6 server_addr; - bzero(&server_addr,sizeof(server_addr)); - server_addr.sin6_family = AF_INET6; - server_addr.sin6_port = htons(port); - if (bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { - log_error(TAG,"error binding server socket: %s",strneterr(sock)); - } else if (listen(sock, 1) < 0) { - log_error(TAG,"listen failed with %s/%s",strneterr(sock),strerror(errno)); - } else { - log_info(TAG,"listening on TCP6/%d",port); - return sock; - } - close(sock); - return -1; -} - - -static void init_port(InetArg *p) -{ - if (p->sock != -1) { - close(p->sock); - p->sock = -1; - } - int s; - switch (p->mode) { - case m_sock: - s = p->sock; - break; - case m_tcp: - s = create_tcp_socket(p->port); - break; - case m_udp: - s = create_udp_socket(p->port); - break; - case m_bcast: - s = create_bcast_socket(p->port); - break; - default: - s = -1; - } - if (s != -1) { - p->sock = s; - FD_SET(s,&PortFDs); - if (s > MaxFD) - MaxFD = s; -#ifdef CONFIG_MDNS - if (p->port) - mdns_service_add(p->name, p->service, p->mode == m_tcp ? "_tcp" : "_udp", p->port, 0, 0); -#endif - } -} - -void inet_server(void *ignored) -{ - //log_dbug(TAG,"maximum fd number: %d",MaxFD); - for (;;) { - Started = true; - - fd_set rfds = PortFDs; - int n = lwip_select(MaxFD,&rfds,0,0,0); - if (n == -1) { - log_dbug(TAG,"errno %d",errno); - if (errno != 0) { - log_warn(TAG,"select failed: %s",strerror(errno)); - vTaskDelay(200/portTICK_PERIOD_MS); - } - continue; - } - log_dbug(TAG,"%d new connection",n); - InetArg *p = Ports; - while (p) { - if (FD_ISSET(p->sock,&rfds) != 0) - break; - p = p->next; - } - if (p == 0) { - log_warn(TAG,"fd not found"); - vTaskDelay(200/portTICK_PERIOD_MS); - continue; - } - int sock = p->sock; - assert(p->name); - assert(strlen(p->name) < 16); - log_dbug(TAG,"service %s",p->name); - if (p->mode == m_tcp) { - struct sockaddr_in6 client_addr; - unsigned socklen = sizeof(client_addr); - sock = accept(sock, (struct sockaddr *)&client_addr, &socklen); - if (sock < 0) { - // TODO: what is a better way to deal with error: no more processes - log_error(TAG,"error accepting"); - continue; - } - log_dbug(TAG,"accepted from %s:%d",inet6_ntoa(client_addr.sin6_addr),client_addr.sin6_port); - struct timeval tv; - tv.tv_sec = TCP_TIMEOUT; - tv.tv_usec = 0; - if (0 > setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv))) - log_warn(TAG,"set receive timeout: %s",strneterr(sock)); - } else { - log_warn(TAG,"invalid mode"); - } - char name[configMAX_TASK_NAME_LEN+8]; - snprintf(name,sizeof(name),"%s%02d",p->name,sock); - name[configMAX_TASK_NAME_LEN] = 0; - LwTcp *tcp = new LwTcp(sock); - BaseType_t r = xTaskCreatePinnedToCore(p->session,name,p->stack,(void*) tcp,p->prio,NULL,APP_CPU_NUM); - if (r != pdPASS) { - close(sock); - log_warn(TAG,"create task: %s",esp_err_to_name(r)); - vTaskDelay(1000/portTICK_PERIOD_MS); - } - vTaskDelay(100/portTICK_PERIOD_MS); - } -} - - -int listen_port(int port, inet_mode_t mode, void (*session)(LwTcp *), const char *name, const char *service, unsigned prio, unsigned stack) -{ - // inetd version - if (Started) { - log_error(TAG,"inetd already started"); - return 1; - } - InetArg *a = new InetArg; - a->prio = prio; - a->session = (void (*)(void*))session; - a->name = name; -#ifdef CONFIG_MDNS - a->service = service; -#endif - a->stack = stack; - if (mode == m_sock) { - a->sock = port; - a->port = 0; - } else { - a->port = port; - a->sock = -1; - } - a->mode = mode; - a->next = Ports; - Ports = a; - log_dbug(TAG,"listen %s on %u",name,port); - return 0; -} - - -void inetd_setup(void) -{ - log_dbug(TAG,"init"); - FD_ZERO(&PortFDs); - InetArg *p = Ports; - while (p) { - init_port(p); - p = p->next; - } - ++MaxFD; - BaseType_t r = xTaskCreatePinnedToCore(&inet_server, "inetd", 2560, 0, 5, NULL, PRO_CPU_NUM); - if (r != pdPASS) - log_error(TAG,"create inetd: %s",esp_err_to_name(r)); -} - - -const char *inetadm(Terminal &term, int argc, const char *args[]) -{ - if (argc == 2) { - if (!strcmp(args[1],"-l")) { - InetArg *p = Ports; - term.printf("%-10s %5s status\n","service","port"); - while (p) { - term.printf("%-10s %5u %s\n",p->name,p->port,p->sock == -1 ? "off" : "on"); - p = p->next; - } - return 0; - } - return "Invalid argument #1.";; - } - if (argc != 3) - return "Invalid number of arguments."; - long l = strtol(args[2],0,0); - InetArg *p = Ports; - while (p) { - if ((p->port == l) || (!strcmp(p->name,args[2]))) - break; - p = p->next; - } - if (p == 0) - return "Invalid argument #1.";; - if (!strcmp(args[1],"-e")) { - if (p->sock != -1) { - return "Already enabled."; - } - init_port(p); - return 0; - } - if (!strcmp(args[1],"-d")) { - if (p->sock == -1) { - return "Already disabled."; - } - FD_CLR(p->sock,&PortFDs); - close(p->sock); - p->sock = -1; - term.println("disabled service"); -#ifdef CONFIG_MDNS - mdns_service_remove(p->service, p->mode == m_tcp ? "_tcp" : "_udp"); -#endif - return 0; - } - return "Invalid argument #1.";; -} - -#endif diff --git a/main/luaext.cpp b/main/luaext.cpp index bf86d9c..772fab0 100644 --- a/main/luaext.cpp +++ b/main/luaext.cpp @@ -60,14 +60,14 @@ using namespace std; struct LuaFns { LuaFns(const char *m, const LuaFn *f) - : module(m) + : cluster(m) , fns(f) , next(List) { List = this; } - const char *module; + const char *cluster; const LuaFn *fns; LuaFns *next; static LuaFns *List; @@ -322,7 +322,7 @@ static int f_getvar(lua_State *L) } else { estring str; strstream ss(str); - e->toStream(ss); + e->writeValue(ss); lua_pushstring(L,str.c_str()); } return 1; @@ -494,9 +494,9 @@ static const LuaFn CoreFunctions[] = { int xlua_add_funcs(const char *name, const LuaFn *f) { - new LuaFns(name,f); if (LS == 0) - return 0; + xlua_init(); + new LuaFns(name,f); while (f->name) { lua_pushcfunction(LS,f->func); lua_setglobal(LS,f->name); @@ -600,7 +600,7 @@ const char *xluac(Terminal &t, int argc, const char *args[]) if (0 == strcmp(args[1],"-i")) { LuaFns *fn = LuaFns::List; while (fn) { - t.printf("%s functions:\n",fn->module); + t.printf("%s functions:\n",fn->cluster); const LuaFn *f = fn->fns; while (f->name) { t.printf("%-16s: %s\n",f->name,f->descr); diff --git a/main/mqtt.cpp b/main/mqtt.cpp index 029020f..5e1fe03 100644 --- a/main/mqtt.cpp +++ b/main/mqtt.cpp @@ -95,7 +95,7 @@ static int mqtt_pub_int(const char *t, const char *v, int len, int retain, int q #define TAG MODULE_MQTT static struct MqttClient *Client = 0; static void mqtt_pub_rtdata(void *); -#ifndef CONFIG_IDF_TARGET_ESP8266 +#if LWIP_TCPIP_CORE_LOCKING == 0 static sys_sem_t LwipSem = 0; #endif @@ -415,7 +415,7 @@ static err_t send_sub(const char *t, bool commit, bool lock) assert(request+sizeof(request)==b); log_dbug(TAG,"subscribe '%s', pkgid=%u",t,pkgid); Client->subs.insert(make_pair(pkgid,t)); -#ifdef CONFIG_IDF_TARGET_ESP8266 +#if LWIP_TCPIP_CORE_LOCKING == 1 if (lock) LWIP_LOCK(); uint8_t flags = TCP_WRITE_FLAG_COPY; @@ -703,7 +703,10 @@ static err_t handle_connect(void *arg, struct tcp_pcb *pcb, err_t x) assert(b-tmp == sizeof(tmp)); if (Client->pcb == 0) Client->pcb = pcb; - assert(pcb == Client->pcb); + if (pcb != Client->pcb) { + tcp_close(pcb); + return 0; + } log_devel(TAG,"connect write %d",sizeof(tmp)); err_t e = tcp_write(pcb,tmp,sizeof(tmp),TCP_WRITE_FLAG_COPY); if (e) { @@ -716,7 +719,7 @@ static err_t handle_connect(void *arg, struct tcp_pcb *pcb, err_t x) } -#ifndef CONFIG_IDF_TARGET_ESP8266 +#if LWIP_TCPIP_CORE_LOCKING == 0 // executed in LwIP context void mqtt_ping_fn(void *arg) { @@ -739,7 +742,7 @@ static void mqtt_ping() return; log_dbug(TAG,"ping"); Lock lock(Client->mtx,__FUNCTION__); -#ifdef CONFIG_IDF_TARGET_ESP8266 +#if LWIP_TCPIP_CORE_LOCKING == 1 uint8_t request[] = { PINGREQ, 0 }; LWIP_LOCK(); err_t e = tcp_write(Client->pcb,request,sizeof(request),TCP_WRITE_FLAG_COPY); @@ -813,7 +816,7 @@ static int mqtt_pub_int(const char *t, const char *v, int len, int retain, int q } memcpy(b,v,len); log_devel(TAG,"publish %s %.*s",t,len,v); -#ifdef CONFIG_IDF_TARGET_ESP8266 +#if LWIP_TCPIP_CORE_LOCKING == 1 uint8_t flags = TCP_WRITE_FLAG_COPY; if (more) flags |= TCP_WRITE_FLAG_MORE; @@ -933,7 +936,7 @@ static void mqtt_pub_uptime(void * = 0) } } -#ifndef CONFIG_IDF_TARGET_ESP8266 +#if LWIP_TCPIP_CORE_LOCKING == 0 static void mqtt_tcpout_fn(void *) { tcp_output(Client->pcb); @@ -949,6 +952,8 @@ static void mqtt_pub_rtdata(void *) mqtt_start(); return; } + if (Client->pcb == 0) + return; mqtt_pub_uptime(); rtd_lock(); for (EnvElement *e : RTData->getChilds()) { @@ -965,7 +970,7 @@ static void mqtt_pub_rtdata(void *) } } rtd_unlock(); -#ifdef CONFIG_IDF_TARGET_ESP8266 +#if LWIP_TCPIP_CORE_LOCKING == 1 LWIP_LOCK(); tcp_output(Client->pcb); LWIP_UNLOCK(); @@ -1002,7 +1007,7 @@ int MqttClient::subscribe(const char *topic, void (*callback)(const char *,const return 0; } -#ifndef CONFIG_IDF_TARGET_ESP8266 +#if LWIP_TCPIP_CORE_LOCKING == 0 // executed in LwIP context void mqtt_stop_fn(void *arg) { @@ -1013,6 +1018,7 @@ void mqtt_stop_fn(void *arg) log_warn(TAG,"write DISCONNECT %d",e); else tcp_output(Client->pcb); + Client->state = stopped; Client->pcb = 0; e = tcp_close(pcb); xSemaphoreGive(LwipSem); @@ -1026,7 +1032,7 @@ void mqtt_stop(void *arg) log_dbug(TAG,"stop"); Lock lock(Client->mtx,__FUNCTION__); if (Client->pcb != 0) { -#ifdef CONFIG_IDF_TARGET_ESP8266 +#if LWIP_TCPIP_CORE_LOCKING == 1 uint8_t request[] { DISCONNECT, 0 }; LWIP_LOCK(); err_t e = tcp_write(Client->pcb,request,sizeof(request),TCP_WRITE_FLAG_COPY); @@ -1035,6 +1041,7 @@ void mqtt_stop(void *arg) else tcp_output(Client->pcb); struct tcp_pcb *pcb = Client->pcb; + Client->state = stopped; Client->pcb = 0; e = tcp_close(pcb); LWIP_UNLOCK(); @@ -1047,7 +1054,6 @@ void mqtt_stop(void *arg) #ifdef FEATURE_KEEPALIVE Client->recv_ts = 0; #endif - Client->state = stopped; } @@ -1164,7 +1170,7 @@ void mqtt_setup(void) Client->keepalive = Config.mqtt().keepalive(); cyclic_add_task("mqtt",mqtt_cyclic,0,0); #endif -#ifndef CONFIG_IDF_TARGET_ESP8266 +#if LWIP_TCPIP_CORE_LOCKING == 0 LwipSem = xSemaphoreCreateBinary(); #endif diff --git a/main/screen.cpp b/main/screen.cpp index 0684331..b4be8f7 100644 --- a/main/screen.cpp +++ b/main/screen.cpp @@ -114,6 +114,8 @@ static void switch_mode(void *arg) Ctx->mode = cm_date; } else if (0 == strcmp("stopwatch",m)) { Ctx->mode = cm_stopwatch; + } else if (0 == strcmp("lua",m)) { + Ctx->mode = cm_lua; } else { int idx = RTData->getIndex((const char *) arg); if (idx == -1) { @@ -133,9 +135,9 @@ static void bright_set(void *arg) { if (arg) { long l = strtol((const char *)arg, 0, 0); - int m = Ctx->disp->maxDim(); + int m = Ctx->disp->maxBrightness(); if ((l >= 0) && (l <= m)) - Ctx->disp->setDim(l); + Ctx->disp->setBrightness(l); else log_warn(TAG,"maximum brightness %u",l); } @@ -157,14 +159,14 @@ void Screen::display_time() { uint8_t h=0,m=0,s=0; unsigned y=0; - bool colon = disp->hasChar(':'); if (get_time_of_day(&h,&m,&s,0,0,0,&y)) { - if (colon) - disp->write("--:--:--"); - else - disp->write("--.--.--"); - return; + disp->write("--:--:--"); + } else { + char str[12]; + sprintf(str,"%02u:%02u:%02u",h,m,s); + disp->write(str); } + /* disp->writeHex(h/10); disp->writeHex(h%10,!colon); if (colon) @@ -177,6 +179,7 @@ void Screen::display_time() disp->writeHex(s/10); disp->writeHex(s%10); } + */ } @@ -188,6 +191,10 @@ void Screen::display_date() disp->write("--.--.----"); return; } + char str[12]; + sprintf(str,"%u.%u.%u",day,mon,year); + disp->write(str); + /* disp->writeHex(day/10); disp->writeHex(day%10,true); disp->writeHex(mon/10); @@ -201,22 +208,24 @@ void Screen::display_date() disp->writeHex(year/10); disp->writeHex(year%10); } + */ } void Screen::display_version() { - if (DotMatrix *dm = disp->toDotMatrix()) { - dm->drawRect(1,0,dm->maxX()-2,dm->maxY()); - dm->setXY(10,1); + if (MatrixDisplay *dm = disp->toMatrixDisplay()) { + assert(dm->maxX()); + dm->drawRect(1,1,dm->maxX()-2,dm->maxY()-2); dm->setFont(font_sanslight16); + dm->setPos(10,2); dm->write("Atrium"); dm->setFont(font_sanslight12); - dm->setXY(10,23); + dm->setPos(10,24); const char *sp = strchr(Version,' '); dm->write(Version,sp-Version); if (dm->maxY() >= 48) { - dm->setXY(10,48); + dm->setPos(10,48); dm->setFont(font_tomthumb); dm->write("(C) 2021-2023, T.Maier-Komor"); } @@ -235,7 +244,7 @@ void Screen::display_version() return; disp->setPos(0,1); if (cpl >= 20) - disp->write("(C) 2021 Maier-Komor"); + disp->write("(C) 2023 Maier-Komor"); else disp->write("(C) Maier-Komor"); if (nl > 2) @@ -250,7 +259,7 @@ void Screen::display_version() void Screen::display_sw() { PROFILE_FUNCTION(); - bool colon = disp->hasChar(':'); +// bool colon = disp->hasChar(':'); uint32_t dt; if (sw_pause) { dt = sw_pause; @@ -270,51 +279,24 @@ void Screen::display_sw() uint8_t m = dt / 60; dt -= m * 60; uint8_t s = dt; + char str[16]; if (digits >= 8) { - disp->writeHex(h/10); - disp->writeHex(h%10,!colon); - if (colon) - disp->write(":"); - disp->writeHex(m/10); - disp->writeHex(m%10,!colon); - if (colon) - disp->write(":"); - disp->writeHex(s/10); - disp->writeHex(s%10,true); - disp->writeHex(dsec); - disp->writeHex(hsec); + sprintf(str,"%02u:%02u:%02u.%u%u",h,m,s,dsec,hsec); } else if (digits == 6) { if (h) { - disp->writeHex(h/10); - disp->writeHex(h%10,true); - disp->writeHex(m/10); - disp->writeHex(m%10,true); - disp->writeHex(s/10); - disp->writeHex(s%10); + sprintf(str,"%02u:%02u:%02u",h,m,s); } else { - disp->writeHex(m/10); - disp->writeHex(m%10,true); - disp->writeHex(s/10); - disp->writeHex(s%10,true); - disp->writeHex(dsec); - disp->writeHex(hsec); + sprintf(str,"%02u:%02u.%u%u",m,s,dsec,hsec); } } else if (h != 0) { - disp->writeHex(h/10); - disp->writeHex(h%10,true); - disp->writeHex(m/10); - disp->writeHex(m%10); + sprintf(str,"%02u:%02u",h,m); } else if (m != 0) { - disp->writeHex(m/10); - disp->writeHex(m%10,true); - disp->writeHex(s/10); - disp->writeHex(s%10); + sprintf(str,"%02u:%02u",m,s); } else { - disp->writeHex(s/10); - disp->writeHex(s%10,true); - disp->writeHex(dsec); - disp->writeHex(hsec); + sprintf(str,"%02u.%u%u",s,dsec,hsec); } + disp->write(str); + disp->clrEol(); } @@ -331,6 +313,7 @@ static unsigned clock_iter(void *arg) { bool alpha = Ctx->disp->hasAlpha(); Screen *Ctx = (Screen *)arg; + MatrixDisplay *dm = Ctx->disp->toMatrixDisplay(); if (Ctx->modech) { Ctx->disp->clear(); Ctx->modech = false; @@ -369,24 +352,22 @@ static unsigned clock_iter(void *arg) } if (text) { log_dbug(TAG,"mode %s",text); - DotMatrix *dm = Ctx->disp->toDotMatrix(); if (dm) { dm->setFont(font_sanslight10); - dm->setXY(3,4); + dm->setPos(3,4); } else { Ctx->disp->setPos(0,0); } Ctx->disp->write(text); if (dm) { dm->setFont(nextFont); - dm->setXY(3,12); } } if (Ctx->disp->numLines() > 1) { Ctx->disp->setPos(0,1); Ctx->modestart -= 1000; } - Ctx->disp->sync(); + Ctx->disp->flush(); return 50; } } @@ -395,8 +376,12 @@ static unsigned clock_iter(void *arg) return 50; unsigned d = 100; // Ctx->disp->setPos(0,Ctx->disp->numLines() > 1 ? 1 : 0); - Ctx->disp->write("\r"); - Ctx->disp->clrEol(); + if (dm) { + dm->setPos(10,20); + } else { + Ctx->disp->write("\r"); + Ctx->disp->clrEol(); + } double v = 0; const char *fmt = 0, *dim = 0; switch (Ctx->mode) { @@ -419,12 +404,11 @@ static unsigned clock_iter(void *arg) uint32_t ut = uptime(); time_t now; time(&now); - if ((now > 3600*24*365*30) && (ut - Ctx->modestart > 1000)) { + if ((now > 3600*24*365*30) && (ut - Ctx->modestart > 3000)) { Ctx->mode = cm_time; Ctx->modech = true; - return 20; } - return 500; + return 200; } break; case cm_stopwatch: @@ -475,7 +459,7 @@ static unsigned clock_iter(void *arg) } } } - Ctx->disp->sync(); + Ctx->disp->flush(); return d; } @@ -485,7 +469,7 @@ int luax_disp_max_x(lua_State *L) { if (TextDisplay *disp = TextDisplay::getFirst()) { - if (DotMatrix *dm = disp->toDotMatrix()) { + if (MatrixDisplay *dm = disp->toMatrixDisplay()) { lua_pushinteger(L, dm->maxX()); return 1; } @@ -499,7 +483,7 @@ int luax_disp_max_x(lua_State *L) int luax_disp_max_y(lua_State *L) { if (TextDisplay *disp = TextDisplay::getFirst()) { - if (DotMatrix *dm = disp->toDotMatrix()) { + if (MatrixDisplay *dm = disp->toMatrixDisplay()) { lua_pushinteger(L, dm->maxY()); return 1; } @@ -530,10 +514,12 @@ int luax_disp_draw_rect(lua_State *L) int y = luaL_checkinteger(L,2); int w = luaL_checkinteger(L,3); int h = luaL_checkinteger(L,4); - if (TextDisplay *disp = TextDisplay::getFirst()) - if (DotMatrix *dm = disp->toDotMatrix()) - if (-1 != dm->drawRect(x,y,w,h)) - return 0; + if (TextDisplay *disp = TextDisplay::getFirst()) { + if (MatrixDisplay *dm = disp->toMatrixDisplay()) { + dm->drawRect(x,y,w,h); + return 0; + } + } lua_pushstring(L,"no dot-matrix"); lua_error(L); return 0; @@ -544,8 +530,9 @@ int luax_disp_set_font(lua_State *L) { const char *fn = luaL_checkstring(L,1); if (TextDisplay *disp = TextDisplay::getFirst()) - if (-1 != disp->setFont(fn)) - return 0; + if (MatrixDisplay *md = disp->toMatrixDisplay()) + if (-1 != md->setFont(fn)) + return 0; lua_pushstring(L,"invalid font"); lua_error(L); return 0; @@ -556,11 +543,11 @@ int luax_disp_write(lua_State *L) { const char *txt = luaL_checkstring(L,1); if (TextDisplay *disp = TextDisplay::getFirst()) { - if (-1 != disp->write(txt)) - return 0; + disp->write(txt); + } else { + lua_pushstring(L,"Invalid argument."); + lua_error(L); } - lua_pushstring(L,"Invalid argument."); - lua_error(L); return 0; } @@ -586,21 +573,147 @@ static const LuaFn Functions[] = { { 0, 0, 0 } }; +static int luax_fb_setbgcol(lua_State *L) +{ + if (MatrixDisplay *md = Ctx->disp->toMatrixDisplay()) { + if (lua_isinteger(L,1)) + md->setBgColorVal(lua_tointeger(L,1)); + else if (lua_isstring(L,1)) + md->setBgColor(color_get(lua_tostring(L,1))); + return 0; + } + lua_pushliteral(L,"fb_setbgcol: no display."); + lua_error(L); + return 0; +} + + +static int luax_fb_setfgcol(lua_State *L) +{ + if (MatrixDisplay *md = Ctx->disp->toMatrixDisplay()) { + if (lua_isinteger(L,1)) + md->setFgColorVal(lua_tointeger(L,1)); + else if (lua_isstring(L,1)) + md->setFgColor(color_get(lua_tostring(L,1))); + return 0; + } + lua_pushliteral(L,"fb_setfgcol: no display."); + lua_error(L); + return 0; +} + + +static int luax_fb_setfont(lua_State *L) +{ + if (MatrixDisplay *md = Ctx->disp->toMatrixDisplay()) { + if (const char *fn = lua_tostring(L,1)) { + md->setFont(fn); + } else { + md->setFont(lua_tointeger(L,1)); + } + return 0; + } + lua_pushliteral(L,"fb_setfgcol: no display."); + lua_error(L); + return 0; +} + + +static int luax_fb_drawrect(lua_State *L) +{ + if (MatrixDisplay *md = Ctx->disp->toMatrixDisplay()) { + int x = luaL_checkinteger(L,1); + int y = luaL_checkinteger(L,2); + int w = luaL_checkinteger(L,3); + int h = luaL_checkinteger(L,4); + int32_t fgc = -1; + if (lua_isinteger(L,5)) + fgc = lua_tointeger(L,5); + else if (lua_isstring(L,5)) + fgc = md->getColor(color_get(lua_tostring(L,5))); + md->drawRect(x,y,w,h,fgc); + return 0; + } + lua_pushliteral(L,"fb_drawrect: no display."); + lua_error(L); + return 0; +} + + +static int luax_fb_drawtext(lua_State *L) +{ + if (MatrixDisplay *md = Ctx->disp->toMatrixDisplay()) { + int x = luaL_checkinteger(L,1); + int y = luaL_checkinteger(L,2); + const char *text = luaL_checkstring(L,3); + int32_t fgc = -1; + // int before string! 0xff is recognized as string otherwise + if (lua_isinteger(L,4)) + fgc = lua_tointeger(L,4); + else if (lua_isstring(L,4)) + fgc = md->getColor(color_get(lua_tostring(L,4))); + int32_t bgc = -1; + if (lua_isinteger(L,5)) + bgc = lua_tointeger(L,5); + else if (lua_isstring(L,5)) + bgc = md->getColor(color_get(lua_tostring(L,5))); + md->drawText(x,y,text,-1,fgc,bgc); + return 0; + } + lua_pushliteral(L,"fb_drawtext: no display."); + lua_error(L); + return 0; +} + + +static int luax_fb_fillrect(lua_State *L) +{ + if (MatrixDisplay *md = Ctx->disp->toMatrixDisplay()) { + int x = luaL_checkinteger(L,1); + int y = luaL_checkinteger(L,2); + int w = luaL_checkinteger(L,3); + int h = luaL_checkinteger(L,4); + int32_t col = -1; + if (lua_isinteger(L,5)) + col = lua_tointeger(L,5); + else if (lua_isstring(L,5)) + col = md->getColor(color_get(lua_tostring(L,5))); + md->fillRect(x,y,w,h,col); + return 0; + } + lua_pushliteral(L,"fb_drawrect: no display."); + lua_error(L); + return 0; +} + + +static const LuaFn FbFunctions[] = { + { "fb_drawrect", luax_fb_drawrect, "draw rectangle" }, + { "fb_drawtext", luax_fb_drawtext, "draw text string" }, + { "fb_fillrect", luax_fb_fillrect, "fill rectangle" }, + { "fb_setbgcol", luax_fb_setbgcol, "set background color" }, + { "fb_setfgcol", luax_fb_setfgcol, "set foreground color" }, + { "fb_setfont", luax_fb_setfont, "set font" }, + { 0, 0, 0 }, +}; + + #endif -int screen_setup() +void screen_setup() { TextDisplay *d = TextDisplay::getFirst(); if (d == 0) - return 0; + return; Ctx = new Screen; Ctx->disp = d; Ctx->digits = d->charsPerLine(); + Ctx->modestart = uptime(); d->setCursor(false); d->setBlink(false); action_add("display!set_mode",switch_mode,0,"switch to next or specified display mode"); - if (d->maxDim() > 1) { + if (d->maxBrightness() > 1) { action_add("display!set_bright",bright_set,0,"set brightness to argument value"); } action_add("display!off",shutdown,Ctx,"clock: turn off"); @@ -610,16 +723,17 @@ int screen_setup() action_add("sw!pause",sw_pause,Ctx,"stopwatch pause/resume"); shutdown(Ctx); poweron(Ctx); - d->setDim(d->maxDim()); + d->setBrightness(d->maxBrightness()); Ctx->mode = cm_version; Ctx->modech = true; d->clear(); cyclic_add_task("display", clock_iter, Ctx); #ifdef CONFIG_LUA xlua_add_funcs("screen",Functions); // TODO display mode Lua is missing + if (Ctx->disp->toMatrixDisplay()) + xlua_add_funcs("fb",FbFunctions); // TODO display mode Lua is missing #endif log_info(TAG,"ready"); - return 0; } #endif diff --git a/main/shell.cpp b/main/shell.cpp index cdbd162..a42d8d6 100644 --- a/main/shell.cpp +++ b/main/shell.cpp @@ -1144,7 +1144,7 @@ static const char *hwconf(Terminal &term, int argc, const char *args[]) HWConf.set_magic(0xAE54EDCB); #endif } else if (!strcmp("nvxxd",args[1])) { - size_t s; + size_t s = 0; uint8_t *buf = 0; if (int e = nvm_read_blob("hw.cfg",&buf,&s)) { return esp_err_to_name(e); @@ -1945,7 +1945,7 @@ static const char *config(Terminal &term, int argc, const char *args[]) } else if (!strcmp(args[1],"xxd")) { return xxdSettings(term); } else if (!strcmp(args[1],"nvxxd")) { - size_t s; + size_t s = 0; uint8_t *buf = 0; if (int e = nvm_read_blob("node.cfg",&buf,&s)) return e ? "Failed." : 0; diff --git a/main/spi.cpp b/main/spi.cpp index 239fab4..684f6f7 100644 --- a/main/spi.cpp +++ b/main/spi.cpp @@ -23,11 +23,13 @@ #include "env.h" #include "hwcfg.h" #include "globals.h" +#include "ili9341.h" #include "log.h" #include "spidrv.h" #include "ssd1309.h" #include "sx1276.h" #include "terminal.h" +#include "xpt2046.h" #ifdef CONFIG_IDF_TARGET_ESP8266 @@ -71,6 +73,16 @@ static void spi_init_device(spi_host_device_t host, spidrv_t drv, int8_t cs, int case spidrv_ssd1309: SSD1309::create(host,cfg,cd,reset); break; +#endif +#ifdef CONFIG_ILI9341 + case spidrv_ili9341: + ILI9341::create(host,cfg,cd,reset); + break; +#endif +#ifdef CONFIG_XPT2046 + case spidrv_xpt2046: + XPT2046::create(host,cfg,intr); + break; #endif default: log_warn(TAG,"unknown device SPI device type %d",drv); @@ -84,7 +96,7 @@ const char *spicmd(Terminal &term, int argc, const char *args[]) if (argc == 1) { term.println("bus name"); while (s) { - term.printf("%3d %s\n",s->getCS(),s->getName()); + term.printf("%3d %s\n",s->getCS(),s->getName()); s = s->getNext(); } return 0; @@ -105,7 +117,7 @@ void spi_setup() spi_bus_config_t cfg; bzero(&cfg,sizeof(cfg)); // cfg.max_transfer_sz = 0; // use defaults - cfg.max_transfer_sz = 512; + cfg.max_transfer_sz = 4096; cfg.flags = SPICOMMON_BUSFLAG_MASTER; // cfg.intr_flags = ESP_INTR_FLAG_IRAM; if (c.has_miso()) { diff --git a/main/startup.cpp b/main/startup.cpp index f1c90d9..ef3b05c 100644 --- a/main/startup.cpp +++ b/main/startup.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2022, Thomas Maier-Komor + * Copyright (C) 2018-2023, Thomas Maier-Komor * Atrium Firmware Package for ESP * * This program is free software: you can redistribute it and/or modify @@ -16,11 +16,7 @@ * along with this program. If not, see . */ -#include - -#include -#include -#include +#include #ifdef ESP8266 #ifdef ESP32 @@ -47,26 +43,6 @@ extern "C" { #include #endif -#include -#include - -#ifdef CONFIG_IDF_TARGET_ESP8266 -#include -#include -#elif defined CONFIG_IDF_TARGET_ESP32 -#include -#elif defined CONFIG_IDF_TARGET_ESP32S3 -#include -#endif - -#ifdef CONFIG_VERIFY_HEAP -#define verify_heap() if (!heap_caps_check_integrity_all(true)){printf("corrupt heap\n");heap_caps_dump_all();abort();} -#else -#define verify_heap() -#endif - -#include - #include "cyclic.h" #include "event.h" #include "fs.h" @@ -86,30 +62,31 @@ extern "C" { #include "env.h" #include "wifi.h" -#include - -#ifndef CHIP_FEATURE_EMB_FLASH -#define CHIP_FEATURE_EMB_FLASH 0 +#ifdef CONFIG_IDF_TARGET_ESP8266 +#include +#include +#elif defined CONFIG_IDF_TARGET_ESP32 +#include +#elif defined CONFIG_IDF_TARGET_ESP32S3 +#include #endif -#ifndef CHIP_FEATURE_BLE -#define CHIP_FEATURE_BLE 0 +#ifdef CONFIG_VERIFY_HEAP +#define verify_heap() if (!heap_caps_check_integrity_all(true)){printf("corrupt heap\n");heap_caps_dump_all();abort();} +#else +#define verify_heap() #endif -#ifndef CHIP_FEATURE_BT -#define CHIP_FEATURE_BT 0 -#endif +#define TAG MODULE_INIT -#if IDF_VERSION > 32 -#define DRIVER_ARG 0,0 -#else -#define DRIVER_ARG 0 +#ifdef CONFIG_FREERTOS_UNICORE +#if defined CONFIG_IDF_TARGET_ESP32 || defined CONFIG_IDF_TARGET_ESP32S3 +//#error multi-core supported required on multi-core micro-controllers +#endif #endif using namespace std; -#define TAG MODULE_INIT - void action_setup(); void adc_setup(); void alarms_setup(); @@ -180,16 +157,31 @@ static void system_info() } esp_chip_info_t ci; esp_chip_info(&ci); - log_info(TAG,"ESP%u (rev %d) with %d core%s @ %uMHz%s%s%s%s" + log_info(TAG,"ESP%u (rev %d) with %d core%s @ %uMHz%s" +#ifdef CHIP_FEATURE_BT + "%s" +#endif +#ifdef CHIP_FEATURE_BLE + "%s" +#endif +#ifdef CHIP_FEATURE_EMB_FLASH + "%s" +#endif , ci.model ? 32 : 8266 , ci.revision , ci.cores , ci.cores > 1 ? "s" : "" , mhz , ci.features & CHIP_FEATURE_WIFI_BGN ? ", WiFi" : "" +#ifdef CHIP_FEATURE_BT , ci.features & CHIP_FEATURE_BT ? ", BT" : "" +#endif +#ifdef CHIP_FEATURE_BLE , ci.features & CHIP_FEATURE_BLE ? ", BT/LE" : "" +#endif +#ifdef CHIP_FEATURE_EMB_FLASH , ci.features & CHIP_FEATURE_EMB_FLASH ? ", flash" : "" +#endif ); if (uint32_t spiram = heap_caps_get_free_size(MALLOC_CAP_SPIRAM)) log_info(TAG,"%ukB SPI RAM",spiram>>10); @@ -268,7 +260,6 @@ unsigned cyclic_check_heap(void *) } #endif - extern "C" void app_main() { diff --git a/main/syslog.cpp b/main/syslog.cpp index 3a503da..704e865 100644 --- a/main/syslog.cpp +++ b/main/syslog.cpp @@ -222,15 +222,14 @@ void sendall(void * = 0) m->flags &= ~sending_flag; if (r) { event_trigger_nd(Ctx->ev); - goto done; -#if 0 +#if CONFIG_IDF_TARGET_ESP32S2 if (x) { vTaskDelay(10); // needed for UDP stack to catch up lock.lock(); continue; - } else - break; + } #endif + goto done; } lock.lock(); m->flags |= sent_flag; diff --git a/main/telnet.cpp b/main/telnet.cpp index 2c70cf0..5b27100 100644 --- a/main/telnet.cpp +++ b/main/telnet.cpp @@ -308,16 +308,16 @@ static void telnet_session(LwTcp *con) } -#ifdef CONFIG_IDF_TARGET_ESP32 -#define stack_size 4096 -#else +#ifdef CONFIG_IDF_TARGET_ESP8266 #define stack_size 2560 +#else +#define stack_size 4096 #endif void telnet_setup() { - listen_port(TELNET_PORT,m_tcp,telnet_session,"telnet","telnet",5,4096); + listen_port(TELNET_PORT,m_tcp,telnet_session,"telnet","telnet",5,stack_size); } diff --git a/main/udpctrl.cpp b/main/udpctrl.cpp index 426980a..d54ad6c 100644 --- a/main/udpctrl.cpp +++ b/main/udpctrl.cpp @@ -106,7 +106,7 @@ static void recv_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, const char name[12]; ++Ctx->Cmds; snprintf(name,sizeof(name),"udpctrl%u",Ctx->Cmds); - BaseType_t r = xTaskCreatePinnedToCore(udpctrl_session,"udpctrl",stacksize,(void*)c,8,NULL,APP_CPU_NUM); + BaseType_t r = xTaskCreatePinnedToCore(udpctrl_session,name,stacksize,(void*)c,8,NULL,APP_CPU_NUM); if (r != pdPASS) { log_warn(TAG,"create task %s: %d",name,r); pbuf_free(p); diff --git a/projects/esp32-c3_4m b/projects/esp32-c3_4m index 34483fd..41d3f96 100644 --- a/projects/esp32-c3_4m +++ b/projects/esp32-c3_4m @@ -579,9 +579,13 @@ CONFIG_FATFS_CODEPAGE_437=y # CONFIG_FATFS_CODEPAGE_949 is not set # CONFIG_FATFS_CODEPAGE_950 is not set CONFIG_FATFS_CODEPAGE=437 -CONFIG_FATFS_LFN_NONE=y +# CONFIG_FATFS_LFN_NONE is not set # CONFIG_FATFS_LFN_HEAP is not set -# CONFIG_FATFS_LFN_STACK is not set +CONFIG_FATFS_LFN_STACK=y +CONFIG_FATFS_MAX_LFN=63 +CONFIG_FATFS_API_ENCODING_ANSI_OEM=y +# CONFIG_FATFS_API_ENCODING_UTF_16 is not set +# CONFIG_FATFS_API_ENCODING_UTF_8 is not set CONFIG_FATFS_FS_LOCK=0 CONFIG_FATFS_TIMEOUT_MS=10000 CONFIG_FATFS_PER_FILE_CACHE=y @@ -1290,7 +1294,11 @@ CONFIG_APDS9930=y CONFIG_SGP30=y CONFIG_CCS811B=y CONFIG_BH1750=y -# CONFIG_SPI is not set +CONFIG_SPI=y +# CONFIG_SX1276 is not set +CONFIG_SSD1309=y +CONFIG_ILI9341=y +CONFIG_XPT2046=y CONFIG_HCSR04=y CONFIG_DIMMER=y CONFIG_RGBLEDS=y diff --git a/projects/esp32-s2_4m b/projects/esp32-s2_4m index fd0588b..f909cba 100644 --- a/projects/esp32-s2_4m +++ b/projects/esp32-s2_4m @@ -273,6 +273,7 @@ CONFIG_ESP32S2_INSTRUCTION_CACHE_8KB=y # CONFIG_ESP32S2_INSTRUCTION_CACHE_16KB is not set # CONFIG_ESP32S2_INSTRUCTION_CACHE_LINE_16B is not set CONFIG_ESP32S2_INSTRUCTION_CACHE_LINE_32B=y +# CONFIG_ESP32S2_DATA_CACHE_0KB is not set CONFIG_ESP32S2_DATA_CACHE_8KB=y # CONFIG_ESP32S2_DATA_CACHE_16KB is not set # CONFIG_ESP32S2_DATA_CACHE_LINE_16B is not set @@ -281,38 +282,7 @@ CONFIG_ESP32S2_DATA_CACHE_LINE_32B=y # CONFIG_ESP32S2_DATA_CACHE_WRAP is not set # end of Cache config -CONFIG_ESP32S2_SPIRAM_SUPPORT=y - -# -# SPI RAM config -# -CONFIG_SPIRAM_TYPE_AUTO=y -# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set -# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set -# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set -CONFIG_SPIRAM_SIZE=-1 -CONFIG_SPIRAM_CLK_IO=30 -CONFIG_SPIRAM_CS_IO=26 -# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set -# CONFIG_SPIRAM_RODATA is not set -# CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY is not set -# CONFIG_SPIRAM_SPEED_80M is not set -CONFIG_SPIRAM_SPEED_40M=y -# CONFIG_SPIRAM_SPEED_26M is not set -# CONFIG_SPIRAM_SPEED_20M is not set -CONFIG_SPIRAM=y -CONFIG_SPIRAM_BOOT_INIT=y -CONFIG_SPIRAM_IGNORE_NOTFOUND=y -# CONFIG_SPIRAM_USE_MEMMAP is not set -# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set -CONFIG_SPIRAM_USE_MALLOC=y -CONFIG_SPIRAM_MEMTEST=y -CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384 -# CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP is not set -CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=32768 -# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set -# end of SPI RAM config - +# CONFIG_ESP32S2_SPIRAM_SUPPORT is not set # CONFIG_ESP32S2_TRAX is not set CONFIG_ESP32S2_TRACEMEM_RESERVE_DRAM=0x0 # CONFIG_ESP32S2_ULP_COPROC_ENABLED is not set @@ -425,9 +395,9 @@ CONFIG_ESP32S2_UNIVERSAL_MAC_ADDRESSES=2 # # Sleep Config # +# CONFIG_ESP_SLEEP_POWER_DOWN_FLASH is not set CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND=y # CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND is not set -CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND=y CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y # CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU is not set # end of Sleep Config @@ -554,15 +524,14 @@ CONFIG_ESP32_WIFI_ENABLED=y CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10 CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32 CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y +# CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER is not set CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0 CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=16 -CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=32 CONFIG_ESP32_WIFI_CSI_ENABLED=y CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y CONFIG_ESP32_WIFI_TX_BA_WIN=6 CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y CONFIG_ESP32_WIFI_RX_BA_WIN=6 -# CONFIG_ESP32_WIFI_AMSDU_TX_ENABLED is not set CONFIG_ESP32_WIFI_NVS_ENABLED=y CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752 CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32 @@ -628,7 +597,6 @@ CONFIG_FATFS_LFN_NONE=y CONFIG_FATFS_FS_LOCK=0 CONFIG_FATFS_TIMEOUT_MS=10000 CONFIG_FATFS_PER_FILE_CACHE=y -CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y # CONFIG_FATFS_USE_FASTSEEK is not set # end of FAT Filesystem support @@ -762,10 +730,10 @@ CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y # CONFIG_LWIP_LOCAL_HOSTNAME="espressif" # CONFIG_LWIP_NETIF_API is not set -# CONFIG_LWIP_TCPIP_CORE_LOCKING is not set +CONFIG_LWIP_TCPIP_CORE_LOCKING=y CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y # CONFIG_LWIP_L2_TO_L3_COPY is not set -# CONFIG_LWIP_IRAM_OPTIMIZATION is not set +CONFIG_LWIP_IRAM_OPTIMIZATION=y CONFIG_LWIP_TIMERS_ONDEMAND=y CONFIG_LWIP_MAX_SOCKETS=10 # CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set @@ -905,7 +873,6 @@ CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y # mbedTLS # CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y -# CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC is not set # CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set # CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y @@ -1212,7 +1179,6 @@ CONFIG_TINYUSB_DESC_BCD_DEVICE=0x0100 CONFIG_TINYUSB_DESC_MANUFACTURER_STRING="Espressif Systems" CONFIG_TINYUSB_DESC_PRODUCT_STRING="Espressif Device" CONFIG_TINYUSB_DESC_SERIAL_STRING="123456" -CONFIG_TINYUSB_DESC_CDC_STRING="Espressif CDC Device" # end of Descriptor configuration # @@ -1224,9 +1190,7 @@ CONFIG_TINYUSB_DESC_CDC_STRING="Espressif CDC Device" # # Communication Device Class (CDC) # -CONFIG_TINYUSB_CDC_ENABLED=y -CONFIG_TINYUSB_CDC_RX_BUFSIZE=64 -CONFIG_TINYUSB_CDC_TX_BUFSIZE=64 +# CONFIG_TINYUSB_CDC_ENABLED is not set # end of Communication Device Class (CDC) # end of TinyUSB Stack @@ -1306,8 +1270,8 @@ CONFIG_WFC_TARGET="esp32" # # software services # -CONFIG_CONSOLE_UART_TX=16 -CONFIG_CONSOLE_UART_RX=17 +CONFIG_CONSOLE_UART_TX=43 +CONFIG_CONSOLE_UART_RX=44 CONFIG_UART_CONSOLE=y CONFIG_HWCONF_DYNAMIC=y CONFIG_LUA=y @@ -1327,6 +1291,7 @@ CONFIG_OTA=y CONFIG_UDNS=y CONFIG_MQTT=y CONFIG_HTTP=y +# CONFIG_FTP is not set CONFIG_TELNET=y CONFIG_SYSLOG=y CONFIG_INFLUX=y @@ -1338,7 +1303,7 @@ CONFIG_WPS=y # # filesystem support # -# CONFIG_FATFS is not set +CONFIG_FATFS=y CONFIG_ROMFS=y CONFIG_ROMFS_VFS=y CONFIG_ROMFS_VFS_NUMFDS=4 @@ -1348,7 +1313,6 @@ CONFIG_USB_HOST_FS=y # # hardware support # -CONFIG_USB_CONSOLE=y CONFIG_GPIOS=y CONFIG_IOEXTENDERS=y CONFIG_LEDS=y @@ -1382,6 +1346,7 @@ CONFIG_BH1750=y CONFIG_SPI=y # CONFIG_SX1276 is not set CONFIG_SSD1309=y +CONFIG_XPT2046=y CONFIG_HCSR04=y CONFIG_DIMMER=y CONFIG_RGBLEDS=y @@ -1445,11 +1410,10 @@ CONFIG_STACK_CHECK_NONE=y CONFIG_ESP32_APPTRACE_DEST_NONE=y CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y CONFIG_ADC2_DISABLE_DAC=y -CONFIG_DEFAULT_PSRAM_CLK_IO=30 -CONFIG_DEFAULT_PSRAM_CS_IO=26 # CONFIG_EVENT_LOOP_PROFILING is not set CONFIG_POST_EVENTS_FROM_ISR=y CONFIG_POST_EVENTS_FROM_IRAM_ISR=y +# CONFIG_ESP_SYSTEM_PD_FLASH is not set # CONFIG_ESP32C3_LIGHTSLEEP_GPIO_RESET_WORKAROUND is not set CONFIG_IPC_TASK_STACK_SIZE=2048 CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y @@ -1551,11 +1515,8 @@ CONFIG_USB_DESC_BCDDEVICE=0x0100 CONFIG_USB_DESC_MANUFACTURER_STRING="Espressif Systems" CONFIG_USB_DESC_PRODUCT_STRING="Espressif Device" CONFIG_USB_DESC_SERIAL_STRING="123456" -CONFIG_USB_DESC_CDC_STRING="Espressif CDC Device" # CONFIG_USB_MSC_ENABLED is not set -CONFIG_USB_CDC_ENABLED=y -CONFIG_USB_CDC_RX_BUFSIZE=64 -CONFIG_USB_CDC_TX_BUFSIZE=64 +# CONFIG_USB_CDC_ENABLED is not set CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y CONFIG_SUPPORT_TERMIOS=y CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1 diff --git a/projects/esp32-s3_4m b/projects/esp32-s3_4m index 50038cc..e09cb60 100644 --- a/projects/esp32-s3_4m +++ b/projects/esp32-s3_4m @@ -1366,7 +1366,11 @@ CONFIG_APDS9930=y CONFIG_SGP30=y CONFIG_CCS811B=y CONFIG_BH1750=y -# CONFIG_SPI is not set +CONFIG_SPI=y +# CONFIG_SX1276 is not set +# CONFIG_SSD1309 is not set +# CONFIG_ILI9341 is not set +CONFIG_XPT2046=y CONFIG_HCSR04=y CONFIG_DIMMER=y # CONFIG_RGBLEDS is not set diff --git a/projects/esp32-s3_8m b/projects/esp32-s3_8m index 8a59594..284faa2 100644 --- a/projects/esp32-s3_8m +++ b/projects/esp32-s3_8m @@ -314,8 +314,8 @@ CONFIG_SPIRAM_TYPE_AUTO=y CONFIG_SPIRAM_SIZE=-1 CONFIG_SPIRAM_CLK_IO=30 CONFIG_SPIRAM_CS_IO=26 -CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y -CONFIG_SPIRAM_RODATA=y +# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set +# CONFIG_SPIRAM_RODATA is not set # CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY is not set # CONFIG_SPIRAM_SPEED_120M is not set # CONFIG_SPIRAM_SPEED_80M is not set @@ -456,7 +456,7 @@ CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y # # RTC Clock Config # -# CONFIG_RTC_CLOCK_BBPLL_POWER_ON_WITH_USB is not set +CONFIG_RTC_CLOCK_BBPLL_POWER_ON_WITH_USB=y # end of RTC Clock Config # end of Hardware Settings @@ -602,18 +602,15 @@ CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=7 # # Core dump # -# CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH is not set -CONFIG_ESP_COREDUMP_ENABLE_TO_UART=y +CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y +# CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set # CONFIG_ESP_COREDUMP_ENABLE_TO_NONE is not set # CONFIG_ESP_COREDUMP_DATA_FORMAT_BIN is not set CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF=y CONFIG_ESP_COREDUMP_CHECKSUM_CRC32=y +CONFIG_ESP_COREDUMP_CHECK_BOOT=y CONFIG_ESP_COREDUMP_ENABLE=y CONFIG_ESP_COREDUMP_MAX_TASKS_NUM=64 -CONFIG_ESP_COREDUMP_UART_DELAY=0 -CONFIG_ESP_COREDUMP_DECODE_INFO=y -# CONFIG_ESP_COREDUMP_DECODE_DISABLE is not set -CONFIG_ESP_COREDUMP_DECODE="info" # end of Core dump # @@ -642,9 +639,13 @@ CONFIG_FATFS_CODEPAGE_437=y # CONFIG_FATFS_CODEPAGE_949 is not set # CONFIG_FATFS_CODEPAGE_950 is not set CONFIG_FATFS_CODEPAGE=437 -CONFIG_FATFS_LFN_NONE=y +# CONFIG_FATFS_LFN_NONE is not set # CONFIG_FATFS_LFN_HEAP is not set -# CONFIG_FATFS_LFN_STACK is not set +CONFIG_FATFS_LFN_STACK=y +CONFIG_FATFS_MAX_LFN=63 +CONFIG_FATFS_API_ENCODING_ANSI_OEM=y +# CONFIG_FATFS_API_ENCODING_UTF_16 is not set +# CONFIG_FATFS_API_ENCODING_UTF_8 is not set CONFIG_FATFS_FS_LOCK=0 CONFIG_FATFS_TIMEOUT_MS=10000 CONFIG_FATFS_PER_FILE_CACHE=y @@ -1237,7 +1238,6 @@ CONFIG_TINYUSB_DESC_BCD_DEVICE=0x0100 CONFIG_TINYUSB_DESC_MANUFACTURER_STRING="Espressif Systems" CONFIG_TINYUSB_DESC_PRODUCT_STRING="Espressif Device" CONFIG_TINYUSB_DESC_SERIAL_STRING="123456" -CONFIG_TINYUSB_DESC_CDC_STRING="Espressif CDC Device" # end of Descriptor configuration # @@ -1249,9 +1249,7 @@ CONFIG_TINYUSB_DESC_CDC_STRING="Espressif CDC Device" # # Communication Device Class (CDC) # -CONFIG_TINYUSB_CDC_ENABLED=y -CONFIG_TINYUSB_CDC_RX_BUFSIZE=64 -CONFIG_TINYUSB_CDC_TX_BUFSIZE=64 +# CONFIG_TINYUSB_CDC_ENABLED is not set # end of Communication Device Class (CDC) # end of TinyUSB Stack @@ -1331,8 +1329,8 @@ CONFIG_WFC_TARGET="esp32" # # software services # -CONFIG_CONSOLE_UART_TX=-1 -CONFIG_CONSOLE_UART_RX=-1 +CONFIG_CONSOLE_UART_TX=0 +CONFIG_CONSOLE_UART_RX=0 CONFIG_UART_CONSOLE=y CONFIG_HWCONF_DYNAMIC=y CONFIG_LUA=y @@ -1368,13 +1366,13 @@ CONFIG_FATFS=y CONFIG_ROMFS=y CONFIG_ROMFS_VFS=y CONFIG_ROMFS_VFS_NUMFDS=4 -CONFIG_USB_HOST_FS=y +# CONFIG_USB_HOST_FS is not set # end of filesystem support # # hardware support # -CONFIG_USB_DIAGLOG=y +# CONFIG_USB_DIAGLOG is not set CONFIG_USB_CONSOLE=y CONFIG_GPIOS=y CONFIG_IOEXTENDERS=y @@ -1409,6 +1407,8 @@ CONFIG_BH1750=y CONFIG_SPI=y # CONFIG_SX1276 is not set CONFIG_SSD1309=y +CONFIG_ILI9341=y +CONFIG_XPT2046=y CONFIG_HCSR04=y CONFIG_DIMMER=y CONFIG_RGBLEDS=y @@ -1420,7 +1420,7 @@ CONFIG_TLC5947=y # CONFIG_DEVEL=y # CONFIG_VERIFY_HEAP is not set -# CONFIG_FUNCTION_TIMING is not set +CONFIG_FUNCTION_TIMING=y # end of development tools and experimental/alpha drivers (disable all) # end of Atrium # end of Component config @@ -1504,18 +1504,14 @@ CONFIG_TASK_WDT_TIMEOUT_S=5 CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y # CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set CONFIG_TIMER_TASK_STACK_SIZE=3584 -# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set -CONFIG_ESP32_ENABLE_COREDUMP_TO_UART=y +CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH=y +# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set # CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE is not set # CONFIG_ESP32_COREDUMP_DATA_FORMAT_BIN is not set CONFIG_ESP32_COREDUMP_DATA_FORMAT_ELF=y CONFIG_ESP32_COREDUMP_CHECKSUM_CRC32=y CONFIG_ESP32_ENABLE_COREDUMP=y CONFIG_ESP32_CORE_DUMP_MAX_TASKS_NUM=64 -CONFIG_ESP32_CORE_DUMP_UART_DELAY=0 -CONFIG_ESP32_CORE_DUMP_DECODE_INFO=y -# CONFIG_ESP32_CORE_DUMP_DECODE_DISABLE is not set -CONFIG_ESP32_CORE_DUMP_DECODE="info" CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND=150 CONFIG_MB_MASTER_DELAY_MS_CONVERT=200 CONFIG_MB_QUEUE_LENGTH=20 @@ -1574,11 +1570,8 @@ CONFIG_USB_DESC_BCDDEVICE=0x0100 CONFIG_USB_DESC_MANUFACTURER_STRING="Espressif Systems" CONFIG_USB_DESC_PRODUCT_STRING="Espressif Device" CONFIG_USB_DESC_SERIAL_STRING="123456" -CONFIG_USB_DESC_CDC_STRING="Espressif CDC Device" # CONFIG_USB_MSC_ENABLED is not set -CONFIG_USB_CDC_ENABLED=y -CONFIG_USB_CDC_RX_BUFSIZE=64 -CONFIG_USB_CDC_TX_BUFSIZE=64 +# CONFIG_USB_CDC_ENABLED is not set CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y CONFIG_SUPPORT_TERMIOS=y CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1 diff --git a/projects/esp32_4m b/projects/esp32_4m index ddd6b2f..a23b54b 100644 --- a/projects/esp32_4m +++ b/projects/esp32_4m @@ -592,9 +592,13 @@ CONFIG_FATFS_CODEPAGE_437=y # CONFIG_FATFS_CODEPAGE_949 is not set # CONFIG_FATFS_CODEPAGE_950 is not set CONFIG_FATFS_CODEPAGE=437 -CONFIG_FATFS_LFN_NONE=y +# CONFIG_FATFS_LFN_NONE is not set # CONFIG_FATFS_LFN_HEAP is not set -# CONFIG_FATFS_LFN_STACK is not set +CONFIG_FATFS_LFN_STACK=y +CONFIG_FATFS_MAX_LFN=63 +CONFIG_FATFS_API_ENCODING_ANSI_OEM=y +# CONFIG_FATFS_API_ENCODING_UTF_16 is not set +# CONFIG_FATFS_API_ENCODING_UTF_8 is not set CONFIG_FATFS_FS_LOCK=0 CONFIG_FATFS_TIMEOUT_MS=10000 CONFIG_FATFS_PER_FILE_CACHE=y @@ -652,7 +656,7 @@ CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1 CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y # CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set # CONFIG_FREERTOS_ASSERT_DISABLE is not set -CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536 +CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=2048 CONFIG_FREERTOS_ISR_STACKSIZE=2096 # CONFIG_FREERTOS_LEGACY_HOOKS is not set CONFIG_FREERTOS_MAX_TASK_NAME_LEN=8 @@ -1308,6 +1312,8 @@ CONFIG_CCS811B=y CONFIG_BH1750=y CONFIG_SPI=y CONFIG_SSD1309=y +CONFIG_ILI9341=y +CONFIG_XPT2046=y CONFIG_HCSR04=y CONFIG_DIMMER=y CONFIG_RGBLEDS=y diff --git a/projects/esp32_8m_full b/projects/esp32_8m_full index 19526e9..3e16967 100644 --- a/projects/esp32_8m_full +++ b/projects/esp32_8m_full @@ -1412,6 +1412,8 @@ CONFIG_BH1750=y CONFIG_SPI=y CONFIG_SX1276=y CONFIG_SSD1309=y +CONFIG_ILI9341=y +CONFIG_XPT2046=y CONFIG_HCSR04=y CONFIG_DIMMER=y CONFIG_RGBLEDS=y