diff --git a/CMakeLists.txt b/CMakeLists.txt index 68a677b..64a3afb 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,8 +60,14 @@ if (NOT DEFINED CPACK_PACKAGE_CONTACT) endif() if (NOT DEFINED CPACK_PACKAGE_DESCRIPTION_SUMMARY) -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY - "GENOA™ LCD display Interface library") + # Conditionally set the description summary based on the selected version + if (USE_OLED_VERSION) + set(CPACK_PACKAGE_DESCRIPTION_SUMMARY + "SP7 LCD display Interface library") + else() + set(CPACK_PACKAGE_DESCRIPTION_SUMMARY + "GENOA™ LCD display Interface library") + endif() endif() set(CPACK_PACKAGE_FILE_NAME "lcdlib_lib32-${BUILD_VERSION_STRING}") @@ -81,7 +87,24 @@ else () endif () include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) -set(LCDLIB_SRC_LIST ${LCDLIB_SRC_LIST} "${SRC_DIR}/lcdlib_common.c") +# Conditionally include source and header files based on the selected version +if (USE_OLED_VERSION) + set(LCDLIB_SRC_LIST + "${SRC_DIR}/lcdlib_common_oled.c" + ) + set(LCD_INC_LIST + "${INC_DIR}/lcdlib_common_oled.h" + ) + message(STATUS "Building the OLED version of lcdlib") +else() + set(LCDLIB_SRC_LIST + "${SRC_DIR}/lcdlib_common.c" + ) + set(LCD_INC_LIST + "${INC_DIR}/lcdlib_common.h" + ) + message(STATUS "Building the legacy version of lcdlib") +endif() #set(LCD_TOOL "lcdlib_tool") diff --git a/include/lcdlib/lcdlib_common_oled.h b/include/lcdlib/lcdlib_common_oled.h new file mode 100644 index 0000000..0550b60 --- /dev/null +++ b/include/lcdlib/lcdlib_common_oled.h @@ -0,0 +1,47 @@ +#ifdef __cplusplus +extern "C" +{ +#endif +#ifndef INCLUDE_LCDLIB_COMMON_OLED_H_ +#define INCLUDE_LCDLIB_COMMON_OLED_H_ + +/* Error Code */ +#define LCD_ERR_OPEN 0x80 +#define LCD_ERR_OPEN_I2C 0x81 +#define LCD_ERR_SET_CURSOR 0x82 +#define LCD_ERR_BAD_PARAM 0x83 +#define LCD_ERR_CLEAR_SCREEN 0x84 +#define LCD_ERR_WRITE 0x85 +#define LCD_ERR_IOCTL 0x86 +#define LCD_ERR_READ 0x87 + +#define LINE_HEIGHT_PX 9 +#define CHARACTER_WIDTH_PX 6 +#define CHARACTER_HEIGHT_PX 8 + +#define OLED_HEIGHT_PX 64 +#define OLED_WIDTH_PX 128 +#define OLED_HEIGHT_BYTES 64 +#define OLED_WIDTH_BYTES 64 + + /* LCD Message type */ + typedef enum + { + POST_CODE = 1, + BMC_IPADDR, + BMC_VER, + BIOS_VER, + HPM_FPGA + } LCD_msgType_t; + + int lcdlib_open_dev(void); + int lcdlib_close_dev(void); + int lcdlib_write_string(LCD_msgType_t msgType, unsigned char *buffer, int str_len); + int lcdlib_clearScreen(void); + + extern const unsigned char font6x8_ascii[128][6]; + +#endif // INCLUDE_LCDLIB_COMMON_OLED_H_ +#ifdef __cplusplus +} +#endif diff --git a/src/lcdlib/lcdlib_common_oled.c b/src/lcdlib/lcdlib_common_oled.c new file mode 100644 index 0000000..fe50a90 --- /dev/null +++ b/src/lcdlib/lcdlib_common_oled.c @@ -0,0 +1,404 @@ +/* +Author: Jacob Levinson +AMD 2024 +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +// #define LCD_DEBUG +#ifdef LCD_DEBUG +#define print_err(fmt, args...) \ + do \ + { \ + FILE *log_file = fopen("/tmp/lcd_debug.log", "a"); \ + if (log_file) \ + { \ + fprintf(log_file, fmt, ##args); \ + fclose(log_file); \ + } \ + else \ + { \ + printf("Error opening log file\n"); \ + } \ + } while (0) +#else +#define print_err(fmt, args...) +#endif + +static int fb_fd = -1; +static unsigned char *fb_buffer = NULL; + +static void load_glyph(char c, unsigned char glyph[CHARACTER_WIDTH_PX]) +{ + if (c < 32 || c > 127) + { + // If the character is out of the supported range, load a blank glyph + memset(glyph, 0, CHARACTER_WIDTH_PX); + } + else + { + // Load the glyph from the font array + memcpy(glyph, font6x8_ascii[c], CHARACTER_WIDTH_PX); + } +} + +static int lcdlib_clear_rows(int y, int rows) +{ + if (fb_fd < 0 || !fb_buffer) + { + return -1; + } + + // Read the current framebuffer content into the buffer + lseek(fb_fd, 0, SEEK_SET); + ssize_t bytes_read = read(fb_fd, fb_buffer, OLED_WIDTH_BYTES * OLED_HEIGHT_BYTES); + if (bytes_read != OLED_WIDTH_BYTES * OLED_HEIGHT_BYTES) + { + print_err("Error: failed to read framebuffer content\n"); + free(fb_buffer); + fb_buffer = NULL; + close(fb_fd); + fb_fd = -1; + return LCD_ERR_READ; + } + + // Calculate the starting offset based on the y coordinate + int offset = y * OLED_WIDTH_PX / 2; + + // Iterate over the rows to clear them + for (int i = 0; i < rows; i++) + { + // Clear one row (128 pixels or 64 bytes) + memset(fb_buffer + offset, 0, OLED_WIDTH_PX / 2); + + // Move to the next row + offset += OLED_WIDTH_PX / 2; + } + + // Write the cleared buffer to the framebuffer device + lseek(fb_fd, 0, SEEK_SET); + ssize_t bytes_written = write(fb_fd, fb_buffer, OLED_WIDTH_BYTES * OLED_HEIGHT_BYTES); + if (bytes_written != OLED_WIDTH_BYTES * OLED_HEIGHT_BYTES) + { + print_err("Error: failed to write framebuffer content\n"); + return LCD_ERR_WRITE; + } + + return 0; +} + +static int lcdlib_fb_write_string(int x, int y, const char *str, int str_len) +{ + if (fb_fd < 0 || !fb_buffer) + { + return -1; + } + + print_err("2 Writing string to display at (%d, %d): %.*s\n", x, y, str_len, str); + + // Read the current framebuffer content into the buffer + lseek(fb_fd, 0, SEEK_SET); + ssize_t bytes_read = read(fb_fd, fb_buffer, OLED_WIDTH_BYTES * OLED_HEIGHT_BYTES); + if (bytes_read != OLED_WIDTH_BYTES * OLED_HEIGHT_BYTES) + { + print_err("Error: failed to read framebuffer content\n"); + free(fb_buffer); + fb_buffer = NULL; + close(fb_fd); + fb_fd = -1; + return LCD_ERR_READ; + } + + int offset = y * OLED_WIDTH_PX / 2 + x / 2; // Calculate the position in the buffer + + // Clear Line to be written: + lcdlib_clear_rows(y, LINE_HEIGHT_PX); + + // 128 pixels in each line, each pixel is 4 bits (1 nibble) + for (int k = 0; k < str_len && *str; k++) + { + unsigned char glyph[CHARACTER_WIDTH_PX]; // 6x8 glyphs + load_glyph(*str, glyph); // Load glyph for character + + for (int i = 0; i < CHARACTER_HEIGHT_PX; i++) + { // Iterate over rows of the glyph + for (int j = 0; j < CHARACTER_WIDTH_PX; j++) + { // Iterate over columns of the glyph + int byte_index = offset + i * OLED_WIDTH_BYTES + j / 2; // Correct byte in the buffer + int pixel_value = (glyph[j] >> i) & 1 ? 0xF : 0x0; + + if (j % 2 == 0) + { + // Even column, modify the high nibble (4 bits) + fb_buffer[byte_index] = (fb_buffer[byte_index] & 0x0F) | (pixel_value << 4); + } + else + { + // Odd column, modify the low nibble (4 bits) + fb_buffer[byte_index] = (fb_buffer[byte_index] & 0xF0) | pixel_value; + } + } + } + + offset += CHARACTER_WIDTH_PX / 2; // Move to the next character position (6 pixels, 3 bytes) + str++; + } + + // Write the buffer to the framebuffer device + lseek(fb_fd, 0, SEEK_SET); + ssize_t bytes_written = write(fb_fd, fb_buffer, OLED_WIDTH_BYTES * OLED_HEIGHT_BYTES); + if (bytes_written != OLED_WIDTH_BYTES * OLED_HEIGHT_BYTES) + { + print_err("Error: failed to write framebuffer content\n"); + return LCD_ERR_WRITE; + } + + return 0; +} + +int lcdlib_open_dev(void) +{ + fb_fd = open("/dev/fb0", O_RDWR); + if (fb_fd < 0) + { + print_err("Error: cannot open framebuffer device\n"); + return -1; + } + + // Allocate buffer to hold one frame + fb_buffer = (unsigned char *)malloc(OLED_WIDTH_BYTES * OLED_HEIGHT_BYTES); + if (!fb_buffer) + { + print_err("Error: cannot allocate framebuffer memory\n"); + close(fb_fd); + return -1; + } + + // Read the current framebuffer content into the buffer + lseek(fb_fd, 0, SEEK_SET); + ssize_t bytes_read = read(fb_fd, fb_buffer, OLED_WIDTH_BYTES * OLED_HEIGHT_BYTES); + if (bytes_read != OLED_WIDTH_BYTES * OLED_HEIGHT_BYTES) + { + print_err("Error: failed to read framebuffer content\n"); + free(fb_buffer); + fb_buffer = NULL; + close(fb_fd); + fb_fd = -1; + return LCD_ERR_READ; + } + + return 0; +} +int lcdlib_close_dev(void) +{ + if (fb_fd >= 0) + { + close(fb_fd); + fb_fd = -1; + } + + if (fb_buffer) + { + free(fb_buffer); + fb_buffer = NULL; + } + + return 0; +} + +int lcdlib_write_string(LCD_msgType_t msgType, unsigned char *buffer, int str_len) +{ + int x = 0; + int y = (msgType - 1) * LINE_HEIGHT_PX; // First msgType (POST_CODE) = 1, each line uses 9 PX + print_err("1 Writing string to display at (%d, %d): %s\n", x, y, buffer); + + // Maximum allowable string length + int max_length = OLED_WIDTH_PX / CHARACTER_WIDTH_PX; + + // Allocate memory for the copied string + unsigned char *copied_buffer = (unsigned char *)malloc(str_len + 1); + if (!copied_buffer) + { + print_err("Error: failed to allocate memory for string copy\n"); + return -1; // or appropriate error code + } + + // Copy the input string to the copied buffer + strncpy((char *)copied_buffer, (char *)buffer, str_len); + copied_buffer[str_len] = '\0'; // Ensure null-termination + + // Check if the string is too long + if (str_len > max_length) + { + print_err("String too long: %d, truncating to %d characters\n", str_len, max_length); + copied_buffer[max_length] = '\0'; // Truncate the string to the maximum length + str_len = max_length; // Adjust the string length + } + + // Safely pass the copied buffer to other function + int result = lcdlib_fb_write_string(x, y, (char *)copied_buffer, str_len); + + // Free the allocated memory after use + free(copied_buffer); + + return result; +} + +int lcdlib_clearScreen(void) +{ + if (fb_fd < 0 || !fb_buffer) + { + return -1; + } + print_err("Clearing LCD screen\n"); + // Clear buffer and write to the framebuffer device + memset(fb_buffer, 0, OLED_WIDTH_BYTES * OLED_HEIGHT_BYTES); + lseek(fb_fd, 0, SEEK_SET); + ssize_t bytes_written = write(fb_fd, fb_buffer, OLED_WIDTH_BYTES * OLED_HEIGHT_BYTES); + if (bytes_written != OLED_WIDTH_BYTES * OLED_HEIGHT_BYTES) + { + print_err("Error: failed to clear the framebuffer content"); + return LCD_ERR_WRITE; + } + + return 0; +} + +// Font Author: Jacob Levinson +const unsigned char font6x8_ascii[128][6] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x00 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x01 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x02 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x03 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x04 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x05 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x06 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x07 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x08 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x09 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0A + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0B + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0C + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0D + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0E + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0F + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x10 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x11 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x12 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x13 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x14 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x15 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x16 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x17 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x18 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x19 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1A + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1B + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1C + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1D + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1E + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1F + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x20 (' ') + {0x00, 0x00, 0xDF, 0x00, 0x00, 0x00}, // 0x21 ('!') + {0x00, 0x03, 0x00, 0x03, 0x00, 0x00}, // 0x22 ('"') + {0x24, 0xFF, 0x24, 0xFF, 0x24, 0x00}, // 0x23 ('#') + {0x26, 0x49, 0xFF, 0x49, 0x32, 0x00}, // 0x24 ('$') + {0xC3, 0x23, 0x18, 0xC4, 0xC3, 0x00}, // 0x25 ('%') + {0x7A, 0x85, 0x8A, 0x70, 0x40, 0x00}, // 0x26 ('&') + {0x00, 0x00, 0x03, 0x00, 0x00, 0x00}, // 0x27 (''') + {0x18, 0x66, 0x81, 0x81, 0x00, 0x00}, // 0x28 ('(') + {0x81, 0x81, 0x66, 0x18, 0x00, 0x00}, // 0x29 (')') + {0x22, 0x14, 0x0F, 0x14, 0x22, 0x00}, // 0x2A ('*') + {0x10, 0x10, 0x7C, 0x10, 0x10, 0x00}, // 0x2B ('+') + {0x00, 0x80, 0x60, 0x00, 0x00, 0x00}, // 0x2C (',') + {0x00, 0x10, 0x10, 0x10, 0x00, 0x00}, // 0x2D ('-') + {0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00}, // 0x2E ('.') + {0xC0, 0x20, 0x18, 0x04, 0x03, 0x00}, // 0x2F ('/') + {0x7E, 0xE1, 0x99, 0x87, 0x7E, 0x00}, // 0x30 ('0') + {0x82, 0x81, 0xFF, 0x80, 0x80, 0x00}, // 0x31 ('1') + {0xC2, 0xA1, 0x91, 0x89, 0x86, 0x00}, // 0x32 ('2') + {0x43, 0x81, 0x89, 0x95, 0x63, 0x00}, // 0x33 ('3') + {0x0F, 0x08, 0x08, 0x08, 0xFF, 0x00}, // 0x34 ('4') + {0x4F, 0x89, 0x89, 0x89, 0x71, 0x00}, // 0x35 ('5') + {0x7E, 0x89, 0x89, 0x89, 0x72, 0x00}, // 0x36 ('6') + {0x01, 0xF1, 0x09, 0x05, 0x03, 0x00}, // 0x37 ('7') + {0x76, 0x89, 0x89, 0x89, 0x76, 0x00}, // 0x38 ('8') + {0x46, 0x89, 0x89, 0x89, 0x7E, 0x00}, // 0x39 ('9') + {0x00, 0x00, 0xC3, 0xC3, 0x00, 0x00}, // 0x3A (':') + {0x00, 0x80, 0x68, 0x00, 0x00, 0x00}, // 0x3B (';') + {0x08, 0x14, 0x22, 0x41, 0x00, 0x00}, // 0x3C ('<') + {0x14, 0x14, 0x14, 0x14, 0x14, 0x00}, // 0x3D ('=') + {0x41, 0x22, 0x14, 0x08, 0x00, 0x00}, // 0x3E ('>') + {0x06, 0x01, 0xB1, 0x09, 0x06, 0x00}, // 0x3F ('?') + {0x7E, 0x89, 0x95, 0xA9, 0x7E, 0x00}, // 0x40 ('@') + {0xFE, 0x11, 0x11, 0x11, 0xFE, 0x00}, // 0x41 ('A') + {0xFF, 0x89, 0x89, 0x89, 0x76, 0x00}, // 0x42 ('B') + {0x7E, 0x81, 0x81, 0x81, 0x81, 0x00}, // 0x43 ('C') + {0xFF, 0x81, 0x81, 0x81, 0x7E, 0x00}, // 0x44 ('D') + {0xFF, 0x89, 0x89, 0x89, 0x81, 0x00}, // 0x45 ('E') + {0xFF, 0x09, 0x09, 0x09, 0x01, 0x00}, // 0x46 ('F') + {0x7E, 0x81, 0x91, 0x91, 0x72, 0x00}, // 0x47 ('G') + {0xFF, 0x08, 0x08, 0x08, 0xFF, 0x00}, // 0x48 ('H') + {0x81, 0x81, 0xFF, 0x81, 0x81, 0x00}, // 0x49 ('I') + {0x60, 0x82, 0x82, 0x7E, 0x02, 0x00}, // 0x4A ('J') + {0xFF, 0x08, 0x14, 0x22, 0xC1, 0x00}, // 0x4B ('K') + {0xFF, 0x80, 0x80, 0x80, 0x80, 0x00}, // 0x4C ('L') + {0xFF, 0x06, 0x0C, 0x06, 0xFF, 0x00}, // 0x4D ('M') + {0xFF, 0x06, 0x18, 0x60, 0xFF, 0x00}, // 0x4E ('N') + {0x7E, 0x81, 0x81, 0x81, 0x7E, 0x00}, // 0x4F ('O') + {0xFF, 0x09, 0x09, 0x09, 0x06, 0x00}, // 0x50 ('P') + {0x3E, 0x41, 0x41, 0x41, 0xBE, 0x00}, // 0x51 ('Q') + {0xFF, 0x19, 0x29, 0x49, 0x86, 0x00}, // 0x52 ('R') + {0x46, 0x89, 0x89, 0x89, 0x72, 0x00}, // 0x53 ('S') + {0x01, 0x01, 0xFF, 0x01, 0x01, 0x00}, // 0x54 ('T') + {0x7F, 0x80, 0x80, 0x80, 0x7F, 0x00}, // 0x55 ('U') + {0x07, 0x38, 0xC0, 0x38, 0x07, 0x00}, // 0x56 ('V') + {0x7F, 0x80, 0x70, 0x80, 0x7F, 0x00}, // 0x57 ('W') + {0xC3, 0x24, 0x18, 0x24, 0xC3, 0x00}, // 0x58 ('X') + {0x07, 0x08, 0xF0, 0x08, 0x07, 0x00}, // 0x59 ('Y') + {0xE1, 0x91, 0x89, 0x85, 0x83, 0x00}, // 0x5A ('Z') + {0x00, 0xFF, 0x81, 0x00, 0x00, 0x00}, // 0x5B ('[') + {0x03, 0x04, 0x18, 0x20, 0xC0, 0x00}, // 0x5C ('\') + {0x00, 0x81, 0xFF, 0x00, 0x00, 0x00}, // 0x5D (']') + {0x04, 0x02, 0x01, 0x02, 0x04, 0x00}, // 0x5E ('^') + {0x00, 0x00, 0x80, 0x80, 0x80, 0x80}, // 0x5F ('_') + {0x00, 0x00, 0x01, 0x02, 0x00, 0x00}, // 0x60 ('`') + {0x70, 0x88, 0x88, 0x70, 0x80, 0x00}, // 0x61 ('a') + {0xFF, 0x90, 0x90, 0x90, 0x60, 0x00}, // 0x62 ('b') + {0x70, 0x88, 0x88, 0x88, 0x88, 0x00}, // 0x63 ('c') + {0x60, 0x90, 0x90, 0x90, 0xFF, 0x00}, // 0x64 ('d') + {0x70, 0xA8, 0xA8, 0xA8, 0xB0, 0x00}, // 0x65 ('e') + {0x08, 0x08, 0xFF, 0x09, 0x09, 0x00}, // 0x66 ('f') + {0x40, 0x98, 0xA4, 0xA4, 0x78, 0x00}, // 0x67 ('g') + {0xFF, 0x08, 0x08, 0x08, 0xF0, 0x00}, // 0x68 ('h') + {0x00, 0x00, 0xF4, 0x00, 0x00, 0x00}, // 0x69 ('i') + {0x40, 0x80, 0x80, 0x80, 0x7D, 0x00}, // 0x6A ('j') + {0xFF, 0x10, 0x28, 0x44, 0x80, 0x00}, // 0x6B ('k') + {0x00, 0x00, 0xFF, 0x80, 0x00, 0x00}, // 0x6C ('l') + {0xF8, 0x08, 0x30, 0x08, 0xF8, 0x00}, // 0x6D ('m') + {0xF0, 0x08, 0x08, 0x08, 0xF0, 0x00}, // 0x6E ('n') + {0x70, 0x88, 0x88, 0x88, 0x70, 0x00}, // 0x6F ('o') + {0x00, 0xFC, 0x12, 0x12, 0x0C, 0x00}, // 0x70 ('p') + {0x06, 0x09, 0x09, 0xFF, 0x80, 0x00}, // 0x71 ('q') + {0x08, 0xF0, 0x08, 0x08, 0x10, 0x00}, // 0x72 ('r') + {0x90, 0xA8, 0xA8, 0xA8, 0x48, 0x00}, // 0x73 ('s') + {0x08, 0x08, 0xFF, 0x88, 0x48, 0x00}, // 0x74 ('t') + {0x78, 0x80, 0x80, 0x80, 0x78, 0x00}, // 0x75 ('u') + {0x18, 0x60, 0x80, 0x60, 0x18, 0x00}, // 0x76 ('v') + {0x38, 0xC0, 0x60, 0xC0, 0x38, 0x00}, // 0x77 ('w') + {0x88, 0x50, 0x20, 0x50, 0x88, 0x00}, // 0x78 ('x') + {0x40, 0x98, 0xA0, 0xA0, 0x78, 0x00}, // 0x79 ('y') + {0x88, 0xC8, 0xA8, 0x98, 0x88, 0x00}, // 0x7A ('z') + {0x10, 0x10, 0x6C, 0x82, 0x82, 0x00}, // 0x7B ('{') + {0x00, 0x00, 0xFF, 0x00, 0x00, 0x00}, // 0x7C ('|') + {0x82, 0x82, 0x6C, 0x10, 0x10, 0x00}, // 0x7D ('}') + {0x08, 0x04, 0x08, 0x10, 0x08, 0x00}, // 0x7E ('~') + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x7F +}; \ No newline at end of file