├── pico_files ├── root │ ├── main.py │ └── boot.py ├── root_eigenmath │ ├── main.py │ └── boot.py ├── examples │ ├── refresh.py │ ├── mandelbrot.py │ ├── rotation.py │ └── wave.py └── modules │ ├── default_style.py │ ├── colorer.py │ ├── vt.py │ ├── highlighter.py │ ├── picocalc_system.py │ ├── sdcard.py │ └── picocalc.py ├── flash_nuke.uf2 ├── imgs ├── rotation.jpg ├── framebuffer.jpg ├── framebuffer2.jpg └── picocalc_example.png ├── .vscode └── settings.json ├── picocalc_micropython_NOfilesystem_pico.uf2 ├── picocalc_micropython_NOfilesystem_pico2.uf2 ├── picocalc_micropython_NOfilesystem_pico2w.uf2 ├── picocalc_micropython_withfilesystem_pico.uf2 ├── picocalc_micropython_withfilesystem_pico2.uf2 ├── picocalc_micropython_withfilesystem_pico2w.uf2 ├── picocalc_micropython_ulab_eigenmath_NOfilesystem_pico2.uf2 ├── picocalc_micropython_ulab_eigenmath_withfilesystem_pico2.uf2 ├── vtterminal ├── micropython.mk ├── micropython.cmake ├── vtterminal.h └── vtterminal.c ├── picocalcdisplay ├── micropython.mk ├── picocalcdisplay.h ├── micropython.cmake ├── picocalcdisplay.c └── font6x8e500.h └── README.md /pico_files/root/main.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #now all the init has been moved to boot.py -------------------------------------------------------------------------------- /pico_files/root_eigenmath/main.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #now all the init has been moved to boot.py -------------------------------------------------------------------------------- /flash_nuke.uf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenodante/PicoCalc-micropython-driver/HEAD/flash_nuke.uf2 -------------------------------------------------------------------------------- /imgs/rotation.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenodante/PicoCalc-micropython-driver/HEAD/imgs/rotation.jpg -------------------------------------------------------------------------------- /imgs/framebuffer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenodante/PicoCalc-micropython-driver/HEAD/imgs/framebuffer.jpg -------------------------------------------------------------------------------- /imgs/framebuffer2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenodante/PicoCalc-micropython-driver/HEAD/imgs/framebuffer2.jpg -------------------------------------------------------------------------------- /imgs/picocalc_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenodante/PicoCalc-micropython-driver/HEAD/imgs/picocalc_example.png -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "stdint.h": "c", 4 | "string.h": "c" 5 | } 6 | } -------------------------------------------------------------------------------- /picocalc_micropython_NOfilesystem_pico.uf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenodante/PicoCalc-micropython-driver/HEAD/picocalc_micropython_NOfilesystem_pico.uf2 -------------------------------------------------------------------------------- /picocalc_micropython_NOfilesystem_pico2.uf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenodante/PicoCalc-micropython-driver/HEAD/picocalc_micropython_NOfilesystem_pico2.uf2 -------------------------------------------------------------------------------- /picocalc_micropython_NOfilesystem_pico2w.uf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenodante/PicoCalc-micropython-driver/HEAD/picocalc_micropython_NOfilesystem_pico2w.uf2 -------------------------------------------------------------------------------- /picocalc_micropython_withfilesystem_pico.uf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenodante/PicoCalc-micropython-driver/HEAD/picocalc_micropython_withfilesystem_pico.uf2 -------------------------------------------------------------------------------- /picocalc_micropython_withfilesystem_pico2.uf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenodante/PicoCalc-micropython-driver/HEAD/picocalc_micropython_withfilesystem_pico2.uf2 -------------------------------------------------------------------------------- /picocalc_micropython_withfilesystem_pico2w.uf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenodante/PicoCalc-micropython-driver/HEAD/picocalc_micropython_withfilesystem_pico2w.uf2 -------------------------------------------------------------------------------- /picocalc_micropython_ulab_eigenmath_NOfilesystem_pico2.uf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenodante/PicoCalc-micropython-driver/HEAD/picocalc_micropython_ulab_eigenmath_NOfilesystem_pico2.uf2 -------------------------------------------------------------------------------- /picocalc_micropython_ulab_eigenmath_withfilesystem_pico2.uf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenodante/PicoCalc-micropython-driver/HEAD/picocalc_micropython_ulab_eigenmath_withfilesystem_pico2.uf2 -------------------------------------------------------------------------------- /vtterminal/micropython.mk: -------------------------------------------------------------------------------- 1 | VTTERMINAL_MOD_DIR := $(USERMOD_DIR) 2 | 3 | # Add all C files to SRC_USERMOD. 4 | SRC_USERMOD += $(VTTERMINAL_MOD_DIR)/vtterminal.c 5 | 6 | # We can add our module folder to include paths if needed 7 | # This is not actually needed in this example. 8 | CFLAGS_USERMOD += -I$(VTTERMINAL_MOD_DIR) 9 | -------------------------------------------------------------------------------- /picocalcdisplay/micropython.mk: -------------------------------------------------------------------------------- 1 | PICOCALCDISPLAY_MOD_DIR := $(USERMOD_DIR) 2 | 3 | # Add all C files to SRC_USERMOD. 4 | SRC_USERMOD += $(PICOCALCDISPLAY_MOD_DIR)/picocalcdisplay.c 5 | 6 | # We can add our module folder to include paths if needed 7 | # This is not actually needed in this example. 8 | CFLAGS_USERMOD += -I$(PICOCALCDISPLAY_MOD_DIR) 9 | -------------------------------------------------------------------------------- /picocalcdisplay/picocalcdisplay.h: -------------------------------------------------------------------------------- 1 | #ifndef _PICOCALCDISPLAY_H 2 | #define _PICOCALCDISPLAY_H 3 | 4 | #define DISPLAY_WIDTH 320 5 | #define DISPLAY_HEIGHT 320 6 | 7 | //cs;sck;mosi;miso;dc;bl; 8 | //13 10 11 12 14 0 9 | 10 | 11 | #define CLK_PIN 10 12 | #define MOSI_PIN 11 13 | #define CS_PIN 13 14 | #define DC_PIN 14 15 | #define RST_PIN 15 16 | #define SPI_DISP spi1 17 | 18 | 19 | 20 | 21 | 22 | #endif // ILI9488_H -------------------------------------------------------------------------------- /vtterminal/micropython.cmake: -------------------------------------------------------------------------------- 1 | # Create an INTERFACE library for our C module. 2 | add_library(usermod_vtterminal INTERFACE) 3 | 4 | # Add our source files to the lib 5 | target_sources(usermod_vtterminal INTERFACE 6 | ${CMAKE_CURRENT_LIST_DIR}/vtterminal.c 7 | ) 8 | 9 | # Add the current directory as an include directory. 10 | target_include_directories(usermod_vtterminal INTERFACE 11 | ${CMAKE_CURRENT_LIST_DIR} 12 | ) 13 | 14 | # Link our INTERFACE library to the usermod target. 15 | target_link_libraries(usermod INTERFACE usermod_vtterminal) 16 | -------------------------------------------------------------------------------- /picocalcdisplay/micropython.cmake: -------------------------------------------------------------------------------- 1 | # Create an INTERFACE library for our C module. 2 | add_library(usermod_picocalcdisplay INTERFACE) 3 | 4 | # Add our source files to the lib 5 | target_sources(usermod_picocalcdisplay INTERFACE 6 | ${CMAKE_CURRENT_LIST_DIR}/picocalcdisplay.c 7 | ) 8 | 9 | # Add the current directory as an include directory. 10 | target_include_directories(usermod_picocalcdisplay INTERFACE 11 | ${CMAKE_CURRENT_LIST_DIR} 12 | ) 13 | 14 | # Link our INTERFACE library to the usermod target. 15 | target_link_libraries(usermod INTERFACE usermod_picocalcdisplay) 16 | -------------------------------------------------------------------------------- /vtterminal/vtterminal.h: -------------------------------------------------------------------------------- 1 | #ifndef _VTTERMINAL_H 2 | #define _VTTERMINAL_H 3 | 4 | 5 | #define CH_W 6 6 | #define CH_H 8 7 | 8 | #define SC_W 53 9 | #define SC_H 40 10 | #define SC_PIXEL_WIDTH 320 11 | #define SC_PIXEL_HEIGHT 320 12 | 13 | #define clBlack 0 14 | #define clRed 1 15 | #define clGreen 2 16 | #define clYellow 3 17 | #define clBlue 4 18 | #define clMagenta 5 19 | #define clCyan 6 20 | #define clWhite 7 21 | 22 | #define G0TABLE CP437 23 | #define G1TABLE font6x8G1 24 | #endif -------------------------------------------------------------------------------- /pico_files/examples/refresh.py: -------------------------------------------------------------------------------- 1 | from picocalc import display,keyboard,terminal 2 | 3 | 4 | terminal.dryBuffer() 5 | 6 | 7 | terminal.wr("\x1b[?25l") # hide cursor 8 | terminal.stopRefresh() 9 | i=0 10 | temp =bytearray(1) 11 | 12 | def processKey(): 13 | # Read a key from the keyboard 14 | if keyboard.readinto(temp): 15 | key = temp[0] 16 | if key == ord('E') or key == ord('e'): 17 | return True 18 | return False 19 | 20 | while(True): 21 | while not display.isScreenUpdateDone(): 22 | pass 23 | if processKey(): 24 | break 25 | display.fill(i) 26 | i+=1 27 | if i>15: 28 | i=0 29 | terminal.wr("\x1b[40;1HPress \'E\' to break...") 30 | display.show() 31 | 32 | 33 | terminal.recoverRefresh() 34 | display.fill(0) #clean the screen 35 | display.restLUT() 36 | terminal.wr("\x1b[2J\x1b[H")#move the cursor to the top, and clear the terminal buffer 37 | 38 | terminal.wr("\x1b[?25h") # show cursor -------------------------------------------------------------------------------- /pico_files/modules/default_style.py: -------------------------------------------------------------------------------- 1 | syntax_style = { 2 | "def": "\x1b[37;44m", # white on deep blue 3 | "class": "\x1b[37;45m", # white on magenta 4 | "if": "\x1b[37;46m", # white on cyan 5 | "elif": "\x1b[37;46m", 6 | "else": "\x1b[37;46m", 7 | "while": "\x1b[37;46m", 8 | "for": "\x1b[37;46m", 9 | "in": "\x1b[37;46m", 10 | "True": "\x1b[36m", # bright cyan text only 11 | "False": "\x1b[31m", # bright red text only 12 | "import": "\x1b[37;44m", 13 | "from": "\x1b[37;44m", 14 | "as": "\x1b[37;44m", 15 | "return": "\x1b[37;45m", 16 | "pass": "\x1b[37;45m", 17 | "break": "\x1b[37;45m", 18 | "try": "\x1b[37;46m", 19 | "except": "\x1b[37;46m", 20 | "raise": "\x1b[37;46m", 21 | "and": "\x1b[37;46m", 22 | "or": "\x1b[37;46m", 23 | "not": "\x1b[37;46m", 24 | "#": "\x1b[32m", # bright green text only 25 | "string": "\x1b[33m", # yellow on black 26 | "multiline": "\x1b[32m" 27 | } -------------------------------------------------------------------------------- /pico_files/modules/colorer.py: -------------------------------------------------------------------------------- 1 | """ 2 | Limited Colorama Port to Micropython 3 | Written by: Laika, 4/19/2025 4 | 5 | Allows for coloring using Fore, Back, and Style like Colorama 6 | Autoreset functionality is also supplied by shadowing print 7 | """ 8 | import sys 9 | import builtins 10 | 11 | # kind of a misnomer, is module level 12 | _global_autoreset = False 13 | 14 | class Fore: 15 | BLACK = "\033[30m" 16 | RED = "\033[31m" 17 | GREEN = "\033[32m" 18 | YELLOW = "\033[33m" 19 | BLUE = "\033[34m" 20 | MAGENTA = "\033[35m" 21 | CYAN = "\033[36m" 22 | WHITE = "\033[37m" 23 | RESET = "\033[39m" 24 | 25 | class Back: 26 | BLACK = "\033[40m" 27 | RED = "\033[41m" 28 | GREEN = "\033[42m" 29 | YELLOW = "\033[43m" 30 | BLUE = "\033[44m" 31 | MAGENTA = "\033[45m" 32 | CYAN = "\033[46m" 33 | WHITE = "\033[47m" 34 | RESET = "\033[49m" 35 | 36 | class Style: 37 | BRIGHT = "\033[1m" 38 | DIM = "\033[2m" 39 | NORMAL = "\033[22m" 40 | UNDERLINE = "\033[4m" 41 | RESET_ALL = "\033[0m" 42 | 43 | def autoreset(state): 44 | """Set the autoreset state for the library.""" 45 | global _global_autoreset 46 | _global_autoreset = state 47 | 48 | def print(*args, sep=' ', end='\n', file=sys.stdout): 49 | """Custom print function that respects the global autoreset setting.""" 50 | global _global_autoreset 51 | text = sep.join(map(str, args)) 52 | if _global_autoreset: 53 | text += Style.RESET_ALL 54 | builtins.print(text, end=end, file=file) 55 | 56 | -------------------------------------------------------------------------------- /pico_files/root/boot.py: -------------------------------------------------------------------------------- 1 | import picocalc 2 | from picocalc import PicoDisplay, PicoKeyboard, PicoSD, PicoSpeaker 3 | import os 4 | import vt 5 | import sys 6 | # Separated imports because Micropython is super finnicky 7 | from picocalc_system import run, files, memory, disk 8 | 9 | from pye import pye_edit 10 | 11 | try: 12 | pc_display = PicoDisplay(320, 320) 13 | pc_keyboard = PicoKeyboard() 14 | # Mount SD card to /sd on boot 15 | pc_sd = PicoSD() 16 | pc_sd.mount() 17 | pcs_L = PicoSpeaker(26) 18 | pcs_R = PicoSpeaker(27) 19 | pc_terminal = vt.vt(pc_display, pc_keyboard, sd=pc_sd()) 20 | 21 | _usb = sys.stdout # 22 | 23 | def usb_debug(msg): 24 | if isinstance(msg, str): 25 | _usb.write(msg) 26 | else: 27 | _usb.write(str(msg)) 28 | _usb.write('\r\n') 29 | picocalc.usb_debug = usb_debug 30 | 31 | picocalc.display = pc_display 32 | picocalc.keyboard = pc_keyboard 33 | picocalc.terminal = pc_terminal 34 | picocalc.sd = pc_sd 35 | 36 | def edit(*args, tab_size=2, undo=50): 37 | #dry the key buffer before editing 38 | pc_terminal.dryBuffer() 39 | return pye_edit(args, tab_size=tab_size, undo=undo, io_device=pc_terminal) 40 | picocalc.edit = edit 41 | 42 | os.dupterm(pc_terminal) 43 | pc_sd.check_mount() 44 | #usb_debug("boot.py done.") 45 | 46 | except Exception as e: 47 | import sys 48 | sys.print_exception(e) 49 | try: 50 | os.dupterm(None).write(b"[boot.py error]\n") 51 | except: 52 | pass 53 | -------------------------------------------------------------------------------- /pico_files/root_eigenmath/boot.py: -------------------------------------------------------------------------------- 1 | import picocalc 2 | from picocalc import PicoDisplay, PicoKeyboard, PicoSD, PicoSpeaker 3 | import os 4 | import vt 5 | import sys 6 | # Separated imports because Micropython is super finnicky 7 | from picocalc_system import run, files, memory, disk 8 | import eigenmath 9 | from pye import pye_edit 10 | import builtins 11 | import gc 12 | try: 13 | em=eigenmath.EigenMath(300*1024) 14 | pc_display = PicoDisplay(320, 320) 15 | pc_keyboard = PicoKeyboard() 16 | # Mount SD card to /sd on boot 17 | pc_sd = PicoSD() 18 | pc_sd.mount() 19 | pcs_L = PicoSpeaker(26) 20 | pcs_R = PicoSpeaker(27) 21 | pc_terminal = vt.vt(pc_display, pc_keyboard, sd=pc_sd()) 22 | 23 | _usb = sys.stdout # 24 | 25 | def usb_debug(msg): 26 | if isinstance(msg, str): 27 | _usb.write(msg) 28 | else: 29 | _usb.write(str(msg)) 30 | _usb.write('\r\n') 31 | picocalc.usb_debug = usb_debug 32 | 33 | picocalc.display = pc_display 34 | picocalc.keyboard = pc_keyboard 35 | picocalc.terminal = pc_terminal 36 | picocalc.sd = pc_sd 37 | builtins.em=em 38 | def edit(*args, tab_size=2, undo=50): 39 | #dry the key buffer before editing 40 | pc_terminal.dryBuffer() 41 | return pye_edit(args, tab_size=tab_size, undo=undo, io_device=pc_terminal) 42 | picocalc.edit = edit 43 | 44 | os.dupterm(pc_terminal) 45 | pc_sd.check_mount() 46 | #usb_debug("boot.py done.") 47 | 48 | except Exception as e: 49 | import sys 50 | sys.print_exception(e) 51 | try: 52 | os.dupterm(None).write(b"[boot.py error]\n") 53 | except: 54 | pass 55 | gc.collect() 56 | -------------------------------------------------------------------------------- /pico_files/examples/mandelbrot.py: -------------------------------------------------------------------------------- 1 | from picocalc import display, terminal,keyboard 2 | import time 3 | import micropython 4 | display.switchPredefinedLUT('pico8') 5 | MAX_ITER = 16 6 | 7 | # fixed-point 8 | FIXED_SHIFT = 10 # =*1024 9 | FIXED_ONE = 1 << FIXED_SHIFT 10 | 11 | @micropython.viper 12 | def mandelbrot_pixel(cx: int, cy: int, max_iter: int, fixed_shift: int) -> int: 13 | zx = 0 14 | zy = 0 15 | for i in range(max_iter): 16 | zx2 = (zx * zx) >> fixed_shift 17 | zy2 = (zy * zy) >> fixed_shift 18 | if zx2 + zy2 > (4 << fixed_shift): 19 | return i 20 | zxy = (zx * zy) >> (fixed_shift - 1) 21 | zy = zxy + cy 22 | zx = zx2 - zy2 + cx 23 | return max_iter 24 | 25 | @micropython.native 26 | def render_mandelbrot(scale=1024, center_x=0, center_y=0): 27 | span_x = (3 * FIXED_ONE) * FIXED_ONE // scale 28 | span_y = (3 * FIXED_ONE) * FIXED_ONE // scale 29 | max_iter = 16 30 | 31 | for y in range(312): 32 | cy = center_y - (span_y // 2) + (y * span_y) // 320 33 | for x in range(320): 34 | cx = center_x - (span_x // 2) + (x * span_x) // 320 35 | m = mandelbrot_pixel(cx, cy, max_iter, FIXED_SHIFT) 36 | if m == max_iter: 37 | color = 0 38 | else: 39 | color = (m % 15) + 1 40 | display.pixel(x, y, color) 41 | 42 | 43 | terminal.dryBuffer() 44 | #terminal.stopRefresh() 45 | terminal.wr("\x1b[?25l") # hide cursor 46 | temp =bytearray(1) 47 | for zoom in range(1024, 8192, 64): # from 1x to 8x zoom 48 | render_mandelbrot(scale=zoom, center_x=0, center_y=0) 49 | terminal.wr("\x1b[40;1HPress any key to break...") 50 | #display.show() # show in manual refresh mode 51 | if keyboard.readinto(temp): 52 | break 53 | time.sleep(0.1) 54 | 55 | 56 | #terminal.wr("\x1b[40;1HPress any key to continue...") 57 | #terminal.rd() 58 | del temp,MAX_ITER, FIXED_SHIFT, FIXED_ONE, render_mandelbrot 59 | display.fill(0) #clean the screen 60 | display.restLUT() 61 | terminal.wr("\x1b[2J\x1b[H")#move the cursor to the top, and clear the terminal buffer 62 | #terminal.recoverRefresh() 63 | terminal.wr("\x1b[?25h") # show cursor -------------------------------------------------------------------------------- /pico_files/examples/rotation.py: -------------------------------------------------------------------------------- 1 | import math 2 | from picocalc import display,terminal 3 | 4 | # ------------------------------------------------------------------ 5 | # VT100 palette index (4 bit, format: BRIGHT R G B) 6 | # bit3 = BRIGHT (1 = bright version), bit2 = Red, bit1 = Green, bit0 = Blue 7 | # 0: Black 1: Red 2: Green 3: Yellow 8 | # 4: Blue 5: Magenta 6: Cyan 7: White 9 | # 8: Bright Black(Gray) 9: Bright Red 10: Bright Green 11: Bright Yellow 10 | # 12: Bright Blue 13: Bright Magenta 14: Bright Cyan 15: Bright White 11 | # ------------------------------------------------------------------ 12 | 13 | def rgb(r, g, b): 14 | 15 | bright = 1 if max(r, g, b) > 127 else 0 16 | red = 1 if r > 127 else 0 17 | green = 1 if g > 127 else 0 18 | blue = 1 if b > 127 else 0 19 | return (bright << 3) | (red << 2) | (green << 1) | blue 20 | 21 | def rotation(width, height, fun, fb): 22 | 23 | w2 = width // 2 24 | h2 = height // 2 25 | 26 | fb.fill(0) 27 | 28 | m = n = 0 29 | 30 | for x in range(w2): 31 | p = int(math.sqrt(w2*w2 - x*x)) 32 | for v in range(2 * p): 33 | z = v - p 34 | r_val = math.sqrt(x*x + z*z) / w2 35 | q = fun(r_val) 36 | y = round(z/3 + q * h2) 37 | 38 | c = rgb(int(r_val*255), int((1-r_val)*255), 128) 39 | 40 | if v == 0: 41 | m = n = y 42 | draw = True 43 | elif y > m: 44 | m = y 45 | draw = True 46 | elif y < n: 47 | n = y 48 | draw = True 49 | else: 50 | draw = False 51 | 52 | if draw: 53 | # 对称画两点 54 | fb.pixel(w2 - x, h2 - y, c) 55 | fb.pixel(w2 + x, h2 - y, c) 56 | 57 | 58 | WIDTH, HEIGHT = 320,312 59 | 60 | 61 | 62 | def my_fun(r): 63 | return (r - 1) * math.sin(r * 24) 64 | #return 2.5 * (1 - r) * (1 - r) + 2 * r * r * 0.7 - 1.5 65 | #return (math.sin(r * 2 * math.pi) + 1) / 2 66 | 67 | 68 | terminal.dryBuffer() 69 | #terminal.stopRefresh() 70 | terminal.wr("\x1b[?25l") # hide cursor 71 | # Execute rotation drawing 72 | rotation(WIDTH, HEIGHT, my_fun, display) 73 | 74 | terminal.wr("\x1b[40;1HPress any key to continue...") 75 | terminal.rd() 76 | display.fill(0) #clean the screen 77 | terminal.wr("\x1b[2J\x1b[H")#move the cursor to the top, and clear the terminal buffer 78 | 79 | del WIDTH 80 | del HEIGHT 81 | 82 | 83 | 84 | #terminal.recoverRefresh() 85 | terminal.wr("\x1b[?25h") # show cursor 86 | 87 | -------------------------------------------------------------------------------- /pico_files/modules/vt.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | import uio 3 | import vtterminal 4 | from micropython import const 5 | import time 6 | import uos 7 | from picocalc_system import screenshot_bmp 8 | 9 | sc_char_width = const(53) 10 | sc_char_height = const(40) 11 | 12 | def ensure_nested_dir(path): 13 | parts = path.split("/") 14 | current = "" 15 | for part in parts: 16 | if not part: 17 | continue 18 | current = current + "/" + part if current else part 19 | try: 20 | uos.stat(current) 21 | except OSError: 22 | uos.mkdir(current) 23 | 24 | 25 | 26 | class vt(uio.IOBase): 27 | 28 | 29 | def __init__(self,framebuf,keyboard,screencaptureKey=0x15,sd=None,captureFolder="/"): #ctrl+U for screen capture 30 | if sd != None: 31 | if not captureFolder.startswith("/"): 32 | captureFolder = "/"+captureFolder 33 | captureFolder = '/sd'+captureFolder 34 | if not captureFolder.endswith("/"): 35 | captureFolder = captureFolder+"/" 36 | self.captureFolder = captureFolder 37 | ensure_nested_dir(self.captureFolder) 38 | 39 | self.framebuf = framebuf 40 | self.sd = sd 41 | self.keyboardInput = bytearray(30) 42 | self.outputBuffer = deque((), 30) 43 | vtterminal.init(self.framebuf) 44 | self.keyboard = keyboard 45 | self.screencaptureKey = screencaptureKey 46 | 47 | def screencapture(self): 48 | if self.sd: 49 | filename = "{}screen_{}.bmp".format(self.captureFolder, time.ticks_ms()) 50 | #with open(filename, "wb") as f: 51 | # f.write(self.framebuf.buffer) 52 | screenshot_bmp(self.framebuf.buffer, filename) 53 | return True 54 | return False 55 | 56 | def dryBuffer(self): 57 | self.outputBuffer = deque((), 30) 58 | 59 | 60 | def stopRefresh(self): 61 | self.framebuf.stopRefresh() 62 | 63 | def recoverRefresh(self): 64 | self.framebuf.recoverRefresh() 65 | 66 | def wr(self,input): 67 | #print("WR:", repr(input)) 68 | for c in input: 69 | if ord(c) == 0x07: 70 | pass 71 | else: 72 | vtterminal.printChar(ord(c)) 73 | return len(input) 74 | 75 | def write(self, buf): 76 | return self.wr(buf.decode()) 77 | 78 | def get_screen_size(self): 79 | return[sc_char_height,sc_char_width] 80 | 81 | def _updateInternalBuffer(self): 82 | s = vtterminal.read() 83 | if s: 84 | try: 85 | self.outputBuffer.extend(ord(ch) for ch in s) 86 | except TypeError: 87 | raise ValueError("vtterminal.read() must return str") 88 | except ValueError: 89 | raise ValueError("Non-ASCII character in vtterminal.read()") 90 | 91 | n = self.keyboard.readinto(self.keyboardInput) 92 | if n: 93 | keys = bytes(self.keyboardInput[:n]) 94 | if self.screencaptureKey in keys: 95 | self.screencapture() 96 | self.outputBuffer.extend(self.keyboardInput[:n]) 97 | 98 | def rd(self): 99 | while not self.outputBuffer: 100 | self._updateInternalBuffer() 101 | 102 | return chr(self.outputBuffer.popleft()) 103 | 104 | 105 | def rd_raw(self): 106 | return self.rd() 107 | 108 | def readinto(self, buf): 109 | self._updateInternalBuffer() 110 | count = 0 111 | buf_len = len(buf) 112 | for i in range(buf_len): 113 | if self.outputBuffer: 114 | buf[i] = self.outputBuffer.popleft() 115 | count += 1 116 | else: 117 | break 118 | return count if count > 0 else None 119 | -------------------------------------------------------------------------------- /pico_files/modules/highlighter.py: -------------------------------------------------------------------------------- 1 | import micropython 2 | 3 | 4 | _RESET = "\x1b[0m" 5 | 6 | 7 | DELIMITERS = " \t\n+-*/=<>()[]{}:,;\"'#" 8 | 9 | COMPOUND_DELIMITERS = ["==", "!=", "<=", ">=", "->", "+=", "-=", "*=", "/="] 10 | 11 | class Highlighter: 12 | def __init__(self, syntax_style=None, max_tokens=300): 13 | self.syntax_style = syntax_style 14 | self.max_tokens = max_tokens 15 | self.token_boundaries = bytearray(max_tokens * 2) 16 | self.token_types = bytearray(max_tokens) 17 | 18 | @micropython.native 19 | def highlight_line(self, line): 20 | code_part, comment_part = self._strip_comment(line) 21 | token_count = self._tokenize(code_part) 22 | result = self._build_highlighted_output(code_part, token_count) 23 | if comment_part: 24 | comment_style = self.syntax_style.get("#", "") 25 | if comment_style: 26 | result += comment_style + comment_part + _RESET 27 | else: 28 | result += comment_part 29 | 30 | return result 31 | 32 | def _tokenize(self, text): 33 | i = 0 34 | token_idx = 0 35 | text_len = len(text) 36 | in_str = False 37 | str_char = None 38 | start_pos = 0 39 | 40 | TOKEN_NORMAL = 0 41 | TOKEN_STRING = 1 42 | 43 | while i < text_len and token_idx < self.max_tokens: 44 | char = text[i] 45 | if in_str: 46 | if char == str_char and (i == 0 or text[i-1] != '\\'): 47 | in_str = False 48 | self.token_boundaries[token_idx*2] = start_pos 49 | self.token_boundaries[token_idx*2+1] = i + 1 50 | self.token_types[token_idx] = TOKEN_STRING 51 | token_idx += 1 52 | start_pos = i + 1 53 | i += 1 54 | continue 55 | 56 | if char in "\"'": 57 | if start_pos < i: 58 | self.token_boundaries[token_idx*2] = start_pos 59 | self.token_boundaries[token_idx*2+1] = i 60 | self.token_types[token_idx] = TOKEN_NORMAL 61 | token_idx += 1 62 | in_str = True 63 | str_char = char 64 | start_pos = i 65 | i += 1 66 | continue 67 | is_compound = False 68 | if i < text_len - 1: 69 | possible_compound = text[i:i+2] 70 | if possible_compound in COMPOUND_DELIMITERS: 71 | if start_pos < i: 72 | self.token_boundaries[token_idx*2] = start_pos 73 | self.token_boundaries[token_idx*2+1] = i 74 | self.token_types[token_idx] = TOKEN_NORMAL 75 | token_idx += 1 76 | self.token_boundaries[token_idx*2] = i 77 | self.token_boundaries[token_idx*2+1] = i + 2 78 | self.token_types[token_idx] = TOKEN_NORMAL 79 | token_idx += 1 80 | start_pos = i + 2 81 | i += 2 82 | is_compound = True 83 | continue 84 | if not is_compound and char in DELIMITERS: 85 | if start_pos < i: 86 | self.token_boundaries[token_idx*2] = start_pos 87 | self.token_boundaries[token_idx*2+1] = i 88 | self.token_types[token_idx] = TOKEN_NORMAL 89 | token_idx += 1 90 | 91 | self.token_boundaries[token_idx*2] = i 92 | self.token_boundaries[token_idx*2+1] = i + 1 93 | self.token_types[token_idx] = TOKEN_NORMAL 94 | token_idx += 1 95 | 96 | start_pos = i + 1 97 | 98 | i += 1 99 | if start_pos < text_len and token_idx < self.max_tokens: 100 | self.token_boundaries[token_idx*2] = start_pos 101 | self.token_boundaries[token_idx*2+1] = text_len 102 | self.token_types[token_idx] = TOKEN_NORMAL 103 | token_idx += 1 104 | 105 | return token_idx 106 | 107 | def _build_highlighted_output(self, text, token_count): 108 | result = "" 109 | TOKEN_NORMAL = 0 110 | TOKEN_STRING = 1 111 | 112 | for i in range(token_count): 113 | start = self.token_boundaries[i*2] 114 | end = self.token_boundaries[i*2+1] 115 | token = text[start:end] 116 | token_type = self.token_types[i] 117 | if token_type == TOKEN_STRING: 118 | style = self.syntax_style.get("string", "") 119 | if style: 120 | result += style + token + _RESET 121 | else: 122 | result += token 123 | else: 124 | style = self.syntax_style.get(token) 125 | if style: 126 | result += style + token + _RESET 127 | else: 128 | result += token 129 | 130 | return result 131 | 132 | def _strip_comment(self, line): 133 | in_str = False 134 | esc = False 135 | quote = None 136 | 137 | for i, ch in enumerate(line): 138 | if esc: 139 | esc = False 140 | continue 141 | if ch == "\\": 142 | esc = True 143 | continue 144 | if ch in ("'", '"'): 145 | if not in_str: 146 | in_str, quote = True, ch 147 | elif ch == quote: 148 | in_str = False 149 | elif ch == "#" and not in_str: 150 | return line[:i], line[i:] 151 | 152 | return line, "" 153 | 154 | 155 | -------------------------------------------------------------------------------- /pico_files/modules/picocalc_system.py: -------------------------------------------------------------------------------- 1 | """ 2 | PicoCalc system functions for micropython 3 | Written by: Laika, 4/19/2025 4 | 5 | Requires sdcard.py from the official Micropython repository 6 | https://github.com/micropython/micropython-lib/blob/master/micropython/drivers/storage/sdcard/sdcard.py 7 | 8 | Features various system functions such as mounting and unmounting the PicoCalc's SD card, a nicer run utility, and an ls utility 9 | 10 | """ 11 | import os 12 | import uos 13 | import machine 14 | import sdcard 15 | import gc 16 | from micropython import const 17 | import picocalc 18 | from colorer import Fore, Back, Style, print, autoreset 19 | 20 | autoreset(True) 21 | 22 | 23 | def human_readable_size(size): 24 | """ 25 | Returns input size in bytes in a human-readable format 26 | 27 | Inputs: size in bytes 28 | Outputs: size in closest human-readable unit 29 | """ 30 | for unit in ['bytes', 'KB', 'MB', 'GB', 'TB']: 31 | if size < 1024: 32 | return f"{size:.2f} {unit}" 33 | size /= 1024 34 | # Fallthrough isnt even possible to be needed on the PicoCalc, neither is TB, but its a universal function 35 | return f"{size:.2f} PB" 36 | 37 | def is_dir(path): 38 | """ 39 | Helper function to shittily replace os.path.exists (not in micropython) 40 | Absolutely not a good replacement, but decent enough for seeing if the SD is mounted 41 | 42 | Inputs: path to check for 43 | Outputs: boolean if path is found 44 | """ 45 | # List the root directory to check for the existence of the desired path 46 | try: 47 | directories = os.listdir('/') 48 | return path.lstrip('/') in directories 49 | except OSError: 50 | return False 51 | 52 | def prepare_for_launch(keep_vars=( "gc", "__name__")): 53 | for k in list(globals()): 54 | if k not in keep_vars: 55 | del globals()[k] 56 | gc.collect() 57 | 58 | #provided by _burr_ 59 | def screenshot_bmp(buffer, filename, width=320, height=320, palette=None): 60 | FILE_HEADER_SIZE = const(14) 61 | INFO_HEADER_SIZE = const(40) 62 | PALETTE_SIZE = const(16 * 4) # 16 colors × 4 bytes (BGRA) 63 | 64 | # Default VT100 16-color palette 65 | if palette is None: 66 | lut = picocalc.display.getLUT() #get memoryview of the current LUT 67 | palette = [] 68 | for i in range(16): 69 | raw = lut[i] 70 | raw = ((raw & 0xFF) << 8) | (raw >> 8) 71 | 72 | r = ((raw >> 11) & 0x1F) << 3 73 | g = ((raw >> 5) & 0x3F) << 2 74 | b = (raw & 0x1F) << 3 75 | palette.append((r, g, b)) 76 | ''' 77 | palette = [ 78 | (0x00, 0x00, 0x00), # 0 black 79 | (0x80, 0x00, 0x00), # 1 red 80 | (0x00, 0x80, 0x00), # 2 green 81 | (0x80, 0x80, 0x00), # 3 yellow 82 | (0x00, 0x00, 0x80), # 4 blue 83 | (0x80, 0x00, 0x80), # 5 magenta 84 | (0x00, 0x80, 0x80), # 6 cyan 85 | (0xc0, 0xc0, 0xc0), # 7 white (light gray) 86 | (0x80, 0x80, 0x80), # 8 bright black (dark gray) 87 | (0xff, 0x00, 0x00), # 9 bright red 88 | (0x00, 0xff, 0x00), # 10 bright green 89 | (0xff, 0xff, 0x00), # 11 bright yellow 90 | (0x00, 0x00, 0xff), # 12 bright blue 91 | (0xff, 0x00, 0xff), # 13 bright magenta 92 | (0x00, 0xff, 0xff), # 14 bright cyan 93 | (0xff, 0xff, 0xff), # 15 bright white 94 | ] 95 | ''' 96 | row_bytes = ((width + 1) // 2 + 3) & ~3 # align to 4-byte boundary 97 | pixel_data_size = row_bytes * height 98 | file_size = FILE_HEADER_SIZE + INFO_HEADER_SIZE + PALETTE_SIZE + pixel_data_size 99 | pixel_data_offset = FILE_HEADER_SIZE + INFO_HEADER_SIZE + PALETTE_SIZE 100 | 101 | with open(filename, "wb") as f: 102 | # BMP file header 103 | f.write(b'BM') 104 | f.write(file_size.to_bytes(4, 'little')) 105 | f.write((0).to_bytes(4, 'little')) # Reserved 106 | f.write(pixel_data_offset.to_bytes(4, 'little')) 107 | 108 | # DIB header 109 | f.write(INFO_HEADER_SIZE.to_bytes(4, 'little')) 110 | f.write(width.to_bytes(4, 'little')) 111 | f.write(height.to_bytes(4, 'little')) 112 | f.write((1).to_bytes(2, 'little')) # Planes 113 | f.write((4).to_bytes(2, 'little')) # Bits per pixel 114 | f.write((0).to_bytes(4, 'little')) # No compression 115 | f.write(pixel_data_size.to_bytes(4, 'little')) 116 | f.write((0).to_bytes(4, 'little')) # X pixels per meter 117 | f.write((0).to_bytes(4, 'little')) # Y pixels per meter 118 | f.write((16).to_bytes(4, 'little')) # Colors in palette 119 | f.write((0).to_bytes(4, 'little')) # Important colors 120 | 121 | # Palette (BGRA) 122 | for r, g, b in palette: 123 | f.write(bytes([b, g, r, 0])) 124 | 125 | # Pixel data (bottom-up) 126 | for row in range(height - 1, -1, -1): 127 | start = row * ((width + 1) // 2) 128 | row_data = buffer[start:start + ((width + 1) // 2)] 129 | f.write(row_data) 130 | f.write(bytes(row_bytes - len(row_data))) # Padding 131 | 132 | 133 | def run(filename): 134 | """ 135 | Simple run utility. 136 | Attempts to run python file provided by filename, returns when done. 137 | 138 | Inputs: python file filename/filepath 139 | Outputs: None, runs file 140 | """ 141 | try: 142 | exec(open(filename).read(), globals()) 143 | except OSError: 144 | print(f"Failed to open file: {filename}") 145 | except Exception as e: 146 | print(f"An error occurred: {e}") 147 | return 148 | 149 | def files(directory="/"): 150 | """ 151 | Basic ls port. 152 | 153 | Inputs: directory/filepath to list files and directories in 154 | Outputs: Print of all files and directories contained, along with size 155 | """ 156 | try: 157 | # List entries in the specified directory 158 | entries = uos.listdir(directory) 159 | except OSError as e: 160 | print(f"Error accessing directory {directory}: {e}") 161 | return 162 | 163 | print(f"\nContents of directory: {directory}\n") 164 | for entry in entries: 165 | try: 166 | # Construct the full path 167 | full_path = directory.rstrip("/") + "/" + entry 168 | stat = uos.stat(full_path) 169 | size = stat[6] 170 | 171 | # Check if entry is a directory or a file 172 | if stat[0] & 0x4000: # Directory 173 | print(f"{entry:<25} ") 174 | else: # File 175 | readable_size = human_readable_size(size) 176 | print(f"{entry:<25} {readable_size:<9}") 177 | except OSError as e: 178 | print(f"Error accessing {entry}: {e}") 179 | return 180 | 181 | def memory(): 182 | gc.collect() 183 | # Get the available and free RAM 184 | free_memory = gc.mem_free() 185 | allocated_memory = gc.mem_alloc() 186 | 187 | # Total memory is the sum of free and allocated memory 188 | total_memory = free_memory + allocated_memory 189 | 190 | human_readable_total = human_readable_size(total_memory) 191 | human_readable_free = human_readable_size(free_memory) 192 | 193 | print(f"Total RAM: {human_readable_total}") 194 | print(f"Free RAM: {human_readable_free}") 195 | 196 | def disk(): 197 | """ 198 | Prints available flash and SD card space (if mounted) as well as totals 199 | 200 | Input: None 201 | Outputs: None, prints disk statuses 202 | """ 203 | filesystem_paths = ['/', '/sd'] 204 | for path in filesystem_paths: 205 | if is_dir(path) or path == '/': 206 | if path == '/sd': 207 | # Indicate SD card status 208 | print("SD card mounted.") 209 | print("Indexing SD Card, Please Wait.") 210 | try: 211 | fs_stat = os.statvfs(path) 212 | block_size = fs_stat[1] 213 | total_blocks = fs_stat[2] 214 | free_blocks = fs_stat[3] 215 | total_size = total_blocks * block_size 216 | free_size = free_blocks * block_size 217 | human_readable_total = human_readable_size(total_size) 218 | human_readable_free = human_readable_size(free_size) 219 | 220 | if path == '/': 221 | print(f"Total filesystem size: {human_readable_total}") 222 | print(f"Free filesystem space: {human_readable_free}") 223 | else: 224 | print(f"Total SD size: {human_readable_total}") 225 | print(f"Free SD space: {human_readable_free}") 226 | 227 | except OSError: 228 | print(f"Unexpected error accessing filesystem at '{path}'.") 229 | 230 | else: 231 | if path == '/sd': 232 | print("No SD Card Mounted.") -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # MicroPython Drivers for PicoCalc 4 | ![REPL](./imgs/framebuffer.jpg) 5 | ## Build Instructions 6 | 7 | ``` 8 | Folder structure: 9 | 10 | | 11 | |- micropython # Clone the MicroPython repo here 12 | | |- ports 13 | | |- rp2 14 | | |- build # Create this build folder 15 | | |- modules # Place all py files from pico_files/modules/ 16 | | 17 | |- PicoCalc-micropython-driver # Driver modules 18 | | |- picocalcdisplay 19 | | |- vtterminal 20 | | 21 | |- Any additional modules (e.g., ulab, etc.) 22 | ``` 23 | 24 | Copy all files from pico_files/modules/ to micropython/ports/rp2/modules/ folder 25 | Build MicroPython as usual, while including user modules: 26 | ```sh 27 | cd micropython/ports/rp2 28 | git submodule update --init --recursive 29 | mkdir build && cd build 30 | cmake .. \ 31 | -DUSER_C_MODULES="Path/To/PicoCalc-micropython-driver/picocalcdisplay/micropython.cmake;Path/To/PicoCalc-micropython-driver/vtterminal/micropython.cmake" \ 32 | -DMICROPY_BOARD=[TARGET_BOARD] 33 | ``` 34 | 35 | Supported `TARGET_BOARD` values: 36 | - `RPI_PICO` 37 | - `RPI_PICO2` 38 | - `RPI_PICO2_W` 39 | 40 | (Other boards are untested.) 41 | 42 | --- 43 | 44 | ## Installation 45 | ### With filesystem 46 | The uf2 file already included file system and main.py, boot.py. Just flash it and remove the usb link to the pico module, tune on the picocalc.(The auto reboot seems to be broken, after copy finished, the usb driver won't disappear. That's ok, let me check how to fix it >_<>) 47 | - **NO FILE COPY NEEDED!! The old file system will be destroyed!** 48 | 49 | - picocalc_micropython_ulab_eigenmath_withfilesystem_pico2.uf2 (you could use it with your pico 2 or pico 2w module) 50 | Included ulab, eigenmath port (https://github.com/zenodante/eigenmath_micropython), make picocalc a full function advanced calculator! 51 | - picocalc_micropython_withfilesystem_pico.uf2 (for pico) 52 | Only REPL, code editor 53 | - picocalc_micropython_withfilesystem_pico2.uf2 (for pico 2) 54 | Only REPL, code editor 55 | - picocalc_micropython_withfilesystem_pico2w.uf2 (for pico 2w) 56 | Only REPL, code editor 57 | 58 | ### Without filesystem uf2 59 | the filesystem in the pico module is safe, it won't be overwrite during your firmware upgrade. 60 | - picocalc_micropython_NOfilesystem_pico.uf2 61 | - picocalc_micropython_NOfilesystem_pico2.uf2 62 | - picocalc_micropython_NOfilesystem_pico2w.uf2 63 | - Flash the compiled `.uf2` to your Pico as usual. 64 | - **Place only `main.py,boot.py` from pico_files/root/ in the pico root directory.** 65 | - Copy '/examples/' to pico root (if you want) 66 | - **Delete all existing `.py` files in `/lib`** (e.g., `fbconsole.py`, `picocalc.py`, etc.). 67 | > These modules are already *frozen* into the firmware! 68 | 69 | Using Thonny is the easiest method for file transfer and interaction. 70 | 71 | If the flash nuke is needed, flash as normal, however **DO NOT UNPLUG** until the on-board light flashes to indicate it is done. 72 | --- 73 | 74 | ## Features 75 | 76 | ### ✅ Keyboard Driver 77 | Fully functional and tested. Works seamlessly with vt100 terminal emulator. 78 | 79 | ### ✅ ILI9488 Display Driver (C module + Python interface) 80 | - C module supports high-speed 1/2/4/8-bit LUT drawing and 16-bit 565RGB. 81 | - Python wrapper uses `framebuf` interface and handles display swapping. 82 | - Display updates now run on `core1` for a smoother REPL experience. 83 | 84 | ### ✅ screen capture 85 | - Using ctrl + u to capture screen buffer into your sd card. currently only at the root of the sd card 86 | The Data is in raw type. For default 16 color framebuff copy, it is 50kB each. Left pixel in high 4 bit. 87 | Standard vt 100 16 color map may use to rebuild the image. I will upload a python script to convert it. 88 | 89 | ### ✅ Speaker Driver 90 | Enabled by LaikaSpaceDawg! 91 | 92 | 93 | --- 94 | 95 | ## Usage Notes 96 | 97 | #### Working with WIFI on picoW/2W 98 | The wifi chip connect to the rp2040/2350 via spi1, which shared with LCD. As we autorefresh the lcd on core1, it is necessary to stop the auto refresh function first via the function: 99 | pc_terminal.stopRefresh(), after wifi finish its work, use pc_terminal.recoverRefresh() to recover the LCD refreshing. 100 | 101 | ### Internal code editor 102 | You can launch the built-in Python code editor by calling: 103 | ```python 104 | edit("abc.py") 105 | ``` 106 | ![editor](./imgs/framebuffer2.jpg) 107 | Editor is based on [robert-hh/Micropython-Editor](https://github.com/robert-hh/Micropython-Editor) 108 | Now with keyword highlighting support. 109 | ### run examples 110 | Copy examples folder under pico_files to your pico module root. 111 | Run it via command 112 | ```python 113 | run('/examples/rotation.py') 114 | ``` 115 | ![nice picture made by ポテト](./imgs/picocalc_example.png) 116 | 117 | 118 | 119 | ### Using eigenmath 120 | 121 | I initialize Eigenmath early during system startup because it requires a contiguous 300kB block from the MicroPython heap. If we delay this allocation until later stages of the boot process, heap fragmentation may prevent us from obtaining such a large continuous memory region. Therefore, we allocate it at the beginning. So there is a special boot.py in root_eigenmath folder. If you are using the picocalc_micropython_ulab_eigenmath_withfilesystem_pico2.uf2, it is already included. 122 | ```python 123 | #import eigenmath #not necessary, init in the boot 124 | #em = eigenmath.EigenMath(300*1024) #the internal heap size, eigenmath needs A LOT OF RAM. It will be released after you delete the em instance 125 | em.status() #show current resource status 126 | em.run("d(sin(x),x)") #do math calculation, check the eigenmath manual for more details 127 | em.reset() #reset the internal sources 128 | 129 | #if you don't need it anymore 130 | del builtins.em #del the eigenmath from root 131 | gc.collect() 132 | ``` 133 | 134 | ## color and screen frame buffer 135 | 136 | 137 | 138 | ### Accessing the Display 139 | 140 | The screen is exposed via `picocalc.display`, which is an instance of the `PicoDisplay` class (a subclass of `framebuf`). You can use **all** standard `framebuf` methods to draw on it. 141 | 142 | ### VT100 Emulator Mode 143 | 144 | - Runs in **4-bit color (16 colors)** mode to save limited RAM (≈50 KB). 145 | - Uses an **internal color lookup table (LUT)** to map logical VT100 colors to the actual RGB565 values sent to the panel. 146 | 147 | ### Color Lookup Table (LUT) 148 | 149 | - **Reset to the default VT100 palette** 150 | ```python 151 | picocalc.display.resetLUT() 152 | ``` 153 | - **Switch to a predefined LUT** 154 | ```python 155 | picocalc.display.switchPredefinedLUT("name") 156 | ``` 157 | Available presets: `"vt100"`, `"pico8"` (more coming soon). 158 | 159 | ### Inspecting and Modifying the LUT 160 | 161 | - **Get the current LUT** 162 | ```python 163 | lut = picocalc.display.getLUT() 164 | ``` 165 | Returns a 256-entry, big-endian 16-bit array you can read from or write to directly. 166 | 167 | - **Note on color format** 168 | - The display expects **RGB565** values. 169 | - Because of SPI byte‐order, you must **swap high/low bytes** when writing back to the LUT. 170 | 171 | - **Set a custom LUT** 172 | ```python 173 | picocalc.display.setLUT(custom_array) 174 | ``` 175 | Accepts up to 256 16-bit elements to override the existing table. 176 | 177 | > **Example usage:** see `examples/mandelbrot.py`. 178 | 179 | ### Core Usage & Refresh Modes 180 | 181 | By default: 182 | 183 | - **Core 0** runs the MicroPython VM. 184 | - **Core 1** continuously performs color conversion and refreshes the screen in the background. 185 | 186 | You can switch to **passive refresh mode**: 187 | Please refer the /examples/refresh.py for more details. 188 | ```python 189 | # stop auto refresh 190 | picocalc.display.stopRefresh() 191 | # recover auto refresh 192 | picocalc.display.recoverRefresh() 193 | # manually update the screen by core 0, default is done by core 1, so you could use all core 0 for other logic 194 | picocalc.display.show(0) 195 | # wait the manual refresh function release the vram. If you use the manual refuresh function 196 | picocalc.display.isScreenUpdateDone() 197 | ``` 198 | 199 | - In passive mode, the screen only updates when you explicitly call: 200 | ```python 201 | picocalc.display.show(core=1) 202 | ``` 203 | - The `show()` method takes a `core` argument (`0` or `1`) to choose which core handles color conversion and DMA ping‐pong buffer setup. 204 | ``` 205 | 206 | 207 | 208 | The REPL and editor both run inside a VT100 terminal emulator, based on 209 | [ht-deko/vt100_stm32](https://github.com/ht-deko/vt100_stm32), with bug fixes and additional features. 210 | 211 | --- 212 | 213 | ## Credits 214 | - [robert-hh/Micropython-Editor](https://github.com/robert-hh/Micropython-Editor) 215 | - [ht-deko/vt100_stm32](https://github.com/ht-deko/vt100_stm32) 216 | - `sdcard.py` is from the official MicroPython repository: [micropython-lib/sdcard.py](https://github.com/micropython/micropython-lib/blob/master/micropython/drivers/storage/sdcard/sdcard.py) 217 | - `flash_nuke.uf2` is from the Raspberry Pi Documentation: [Resetting Flash Memory](https://www.raspberrypi.com/documentation/microcontrollers/pico-series.html#resetting-flash-memory) 218 | -------------------------------------------------------------------------------- /pico_files/examples/wave.py: -------------------------------------------------------------------------------- 1 | from picocalc import display,keyboard,terminal 2 | import math 3 | import micropython 4 | import gc 5 | from array import array 6 | import time 7 | # Enable full optimizations 8 | micropython.opt_level(3) 9 | 10 | # Initialize a 320×320, 4-bit grayscale framebuffer 11 | WIDTH, HEIGHT = 320, 312 12 | 13 | 14 | # Precompute constants 15 | GRID = 15 16 | GRID_POINTS = GRID * GRID 17 | HALF_WIDTH = WIDTH // 2 18 | HALF_HEIGHT = HEIGHT // 2 19 | FOCAL_LEN = 100 20 | MAX_COLOR = 15 21 | 22 | # Viewport boundaries for culling 23 | VIEWPORT_MIN_X = -20 24 | VIEWPORT_MAX_X = WIDTH + 20 25 | VIEWPORT_MIN_Y = -20 26 | VIEWPORT_MAX_Y = HEIGHT + 20 27 | 28 | # --- PRE-ALLOCATE ALL MEMORY STRUCTURES --- 29 | 30 | # Pre-allocate coords array 31 | coords = array('f', [0.0] * GRID) 32 | for i in range(GRID): 33 | coords[i] = ((i / (GRID-1)) * 2 - 1) * 1.2 34 | 35 | # Pre-allocate grid points - store as flat arrays for better memory efficiency 36 | grid_x = array('f', [0.0] * GRID_POINTS) 37 | grid_y = array('f', [0.0] * GRID_POINTS) 38 | grid_r = array('f', [0.0] * GRID_POINTS) 39 | 40 | # Fill the grid arrays 41 | idx = 0 42 | for gy in coords: 43 | for gx in coords: 44 | grid_x[idx] = gx 45 | grid_y[idx] = gy 46 | grid_r[idx] = math.sqrt(gx*gx + gy*gy) 47 | idx += 1 48 | 49 | 50 | 51 | # Pre-allocate arrays for projected coordinates 52 | proj_x = array('i', [0] * GRID_POINTS) 53 | proj_y = array('i', [0] * GRID_POINTS) 54 | proj_size = array('i', [0] * GRID_POINTS) 55 | proj_depth = array('f', [0.0] * GRID_POINTS) 56 | proj_color = array('i', [0] * GRID_POINTS) 57 | proj_visible = array('b', [0] * GRID_POINTS) # 0 = invisible, 1 = visible 58 | 59 | # Pre-allocate draw order array (indices into the projection arrays) 60 | draw_order = array('i', list(range(GRID_POINTS))) 61 | 62 | # Pre-allocate sine lookup table for faster sine calculations 63 | SIN_LUT_SIZE = 256 64 | sin_lut = array('f', [0.0] * SIN_LUT_SIZE) 65 | for i in range(SIN_LUT_SIZE): 66 | sin_lut[i] = math.sin(i * 2 * math.pi / SIN_LUT_SIZE) 67 | 68 | # Pre-allocate the sorting key array 69 | # This will hold depth values for the stable sorting algorithm 70 | sort_keys = array('f', [0.0] * GRID_POINTS) 71 | 72 | @micropython.native 73 | def fast_sin(angle: float) -> float: 74 | # Fast sine approximation using lookup table 75 | index = int((angle % (2 * math.pi)) * SIN_LUT_SIZE / (2 * math.pi)) 76 | return sin_lut[index & (SIN_LUT_SIZE - 1)] 77 | 78 | # Simplified bubble sort for depth sorting - avoid creating new data structures 79 | @micropython.native 80 | def depth_sort(visible_count): 81 | # Copy depths to sort_keys array for items that are visible 82 | for i in range(visible_count): 83 | idx = draw_order[i] 84 | sort_keys[i] = proj_depth[idx] 85 | 86 | # Simple bubble sort - works well for mostly-sorted data as in 3D scenes 87 | for i in range(visible_count): 88 | for j in range(visible_count - i - 1): 89 | if sort_keys[j] < sort_keys[j + 1]: 90 | # Swap the sort keys 91 | sort_keys[j], sort_keys[j + 1] = sort_keys[j + 1], sort_keys[j] 92 | # Swap the indices in draw_order 93 | draw_order[j], draw_order[j + 1] = draw_order[j + 1], draw_order[j] 94 | 95 | # Combined rotation and perspective projection with viewport culling 96 | @micropython.native 97 | def transform_points(amplitude: float, freq: float, phase: float, 98 | cam_dist: float, cx: float, sx: float, cy: float, sy: float): 99 | # Reset visibility count 100 | visible_count = 0 101 | 102 | # Process all grid points 103 | for i in range(int(GRID_POINTS)): 104 | # Get original coordinates 105 | x0 = grid_x[i] 106 | y0 = grid_y[i] 107 | r = grid_r[i] 108 | 109 | # Compute height 110 | z0 = amplitude * fast_sin(r * 2 * math.pi * freq + phase) 111 | 112 | # Apply rotations - implemented inline to avoid function calls 113 | # First rotate around Y (horizontal rotation around center) 114 | x1 = z0 * sy + x0 * cy 115 | z1 = z0 * cy - x0 * sy 116 | 117 | # Then rotate around X (vertical tilt/pitch) 118 | y2 = y0 * cx - z1 * sx 119 | z2 = y0 * sx + z1 * cx 120 | 121 | # Store rotated point 122 | #point_x[i] = x1 123 | #point_y[i] = y2 124 | #point_z[i] = z2 125 | 126 | # Apply perspective projection 127 | z_adj = z2 + cam_dist 128 | if z_adj <= 0.001: 129 | z_adj = 0.001 130 | 131 | inv_z = FOCAL_LEN / z_adj 132 | px = int(x1 * inv_z) + HALF_WIDTH 133 | py = int(y2 * inv_z) + HALF_HEIGHT 134 | 135 | # Check if point is within viewport 136 | if (px < VIEWPORT_MIN_X or px > VIEWPORT_MAX_X or 137 | py < VIEWPORT_MIN_Y or py > VIEWPORT_MAX_Y): 138 | proj_visible[i] = 0 # Not visible 139 | continue 140 | 141 | # Store projected coordinates 142 | proj_x[i] = px 143 | proj_y[i] = py 144 | proj_size[i] = max(1, int(inv_z * 4)) 145 | proj_depth[i] = z_adj 146 | 147 | # Calculate color based on height (z2 is the rotated z value) 148 | color = int(((z2 / amplitude) + 1) * 0.5 * MAX_COLOR) 149 | proj_color[i] = max(0, min(MAX_COLOR, color)) 150 | 151 | # Mark as visible and add to draw order 152 | proj_visible[i] = 1 153 | draw_order[visible_count] = i 154 | visible_count += 1 155 | 156 | return visible_count 157 | 158 | # Main drawing function - completely rewritten to avoid memory allocations 159 | @micropython.native 160 | def draw_wave(amplitude, freq, phase, cam_dist, pitch, yaw): 161 | # Clear framebuffer 162 | 163 | 164 | # Precompute rotation values 165 | cx, sx = math.cos(pitch), math.sin(pitch) 166 | cy, sy = math.cos(yaw), math.sin(yaw) 167 | 168 | 169 | # Transform all points - apply rotation, projection, and viewport culling 170 | visible_count = transform_points(amplitude, freq, phase, cam_dist, cx, sx, cy, sy) 171 | 172 | # Skip sorting and drawing if no points are visible 173 | if visible_count == 0: 174 | return 175 | 176 | # Sort points by depth 177 | depth_sort(visible_count) 178 | while not display.isScreenUpdateDone(): 179 | pass # Wait for previous screen update to finish 180 | # Draw points in back-to-front order 181 | display.fill(0) 182 | terminal.wr("\x1b[39;1Hvisible"+str(visible_count)) 183 | for i in range(visible_count): 184 | # Get index from draw order 185 | idx = draw_order[i] 186 | 187 | # Skip if not visible (should not happen due to how visible_count works, but just in case) 188 | if not proj_visible[idx]: 189 | continue 190 | 191 | # Draw the point as a filled rectangle 192 | x = proj_x[idx] 193 | y = proj_y[idx] 194 | size = proj_size[idx] 195 | color = proj_color[idx] 196 | 197 | half_size = size // 2 198 | display.fill_rect(x - half_size, y - half_size, size, size, color) 199 | 200 | def processKey(): 201 | # Read a key from the keyboard 202 | if keyboard.readinto(temp): 203 | key = temp[0] 204 | if key == ord('E') or key == ord('e'): 205 | return True 206 | return False 207 | 208 | terminal.dryBuffer() 209 | 210 | 211 | terminal.wr("\x1b[?25l") # hide cursor 212 | terminal.stopRefresh() 213 | 214 | gamma = 2.2 215 | # Predefine an array of 16 zeros (type 'H') 216 | color_lut = array('H', [0] * 16) 217 | for i in range(16): 218 | # normalized position [0..1] 219 | f = i / 15 220 | # gamma-corrected channel value [0..31] 221 | v = int(31 * (f ** (1 / gamma)) + 0.5) 222 | # red & blue channels for purple, green remains 0 223 | r5 = v 224 | g6 = 0 225 | b5 = v 226 | # pack into RGB565 format 227 | rgb565 = (r5 << 11) | (g6 << 5) | b5 228 | # swap bytes (low byte first) 229 | swapped = ((rgb565 & 0xFF) << 8) | (rgb565 >> 8) 230 | color_lut[i] = swapped 231 | 232 | display.setLUT(color_lut) 233 | temp =bytearray(30) 234 | amp = 0.5 # Amplitude of the wave 235 | freq = 0.5 # Frequency of the wave 236 | phase = 0.0 # Phase shift of the wave 237 | cam_dist = 10.0 # Camera distance from the wave 238 | pitch = 0.1 # Pitch rotation 239 | yaw = 0.1 # Yaw rotation 240 | 241 | while(True): 242 | phase += 0.05 # Increment phase for animation 243 | if phase > 2 * math.pi: 244 | phase -= 2 * math.pi # Reset phase to keep it within bounds 245 | if processKey(): 246 | break 247 | draw_wave(amp, freq, phase, cam_dist, pitch, yaw) 248 | terminal.wr("\x1b[40;1HPress \'E\' to break...") 249 | display.show(0) # show in manual refresh mode 250 | #time.sleep(0.03) 251 | 252 | 253 | #terminal.wr("\x1b[40;1HPress any key to continue...") 254 | #terminal.rd() 255 | #del WIDTH, HEIGHT, GRID, GRID_POINTS, HALF_WIDTH, HALF_HEIGHT, FOCAL_LEN, MAX_COLOR 256 | #del VIEWPORT_MIN_X, VIEWPORT_MAX_X, VIEWPORT_MIN_Y, VIEWPORT_MAX_Y 257 | #del fast_sin, depth_sort, transform_points, draw_wave 258 | #del coords, grid_x, grid_y, grid_r 259 | #del proj_x, proj_y, proj_size, proj_depth, proj_color, proj_visible 260 | #del draw_order, sort_keys, sin_lut 261 | #del temp, amp, freq, phase, cam_dist, pitch, yaw 262 | #del color_lut,gamma 263 | gc.collect() # Run garbage collector to free up memory 264 | terminal.recoverRefresh() 265 | display.fill(0) #clean the screen 266 | display.restLUT() 267 | terminal.wr("\x1b[2J\x1b[H")#move the cursor to the top, and clear the terminal buffer 268 | 269 | terminal.wr("\x1b[?25h") # show cursor -------------------------------------------------------------------------------- /pico_files/modules/sdcard.py: -------------------------------------------------------------------------------- 1 | """ 2 | MicroPython driver for SD cards using SPI bus. 3 | 4 | Requires an SPI bus and a CS pin. Provides readblocks and writeblocks 5 | methods so the device can be mounted as a filesystem. 6 | 7 | Example usage on pyboard: 8 | 9 | import pyb, sdcard, os 10 | sd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X5) 11 | pyb.mount(sd, '/sd2') 12 | os.listdir('/') 13 | 14 | Example usage on ESP8266: 15 | 16 | import machine, sdcard, os 17 | sd = sdcard.SDCard(machine.SPI(1), machine.Pin(15)) 18 | os.mount(sd, '/sd') 19 | os.listdir('/') 20 | 21 | """ 22 | 23 | from micropython import const 24 | import time 25 | 26 | 27 | _CMD_TIMEOUT = const(100) 28 | 29 | _R1_IDLE_STATE = const(1 << 0) 30 | # R1_ERASE_RESET = const(1 << 1) 31 | _R1_ILLEGAL_COMMAND = const(1 << 2) 32 | # R1_COM_CRC_ERROR = const(1 << 3) 33 | # R1_ERASE_SEQUENCE_ERROR = const(1 << 4) 34 | # R1_ADDRESS_ERROR = const(1 << 5) 35 | # R1_PARAMETER_ERROR = const(1 << 6) 36 | _TOKEN_CMD25 = const(0xFC) 37 | _TOKEN_STOP_TRAN = const(0xFD) 38 | _TOKEN_DATA = const(0xFE) 39 | 40 | 41 | class SDCard: 42 | def __init__(self, spi, cs, baudrate=1320000): 43 | self.spi = spi 44 | self.cs = cs 45 | 46 | self.cmdbuf = bytearray(6) 47 | self.dummybuf = bytearray(512) 48 | self.tokenbuf = bytearray(1) 49 | for i in range(512): 50 | self.dummybuf[i] = 0xFF 51 | self.dummybuf_memoryview = memoryview(self.dummybuf) 52 | 53 | # initialise the card 54 | self.init_card(baudrate) 55 | 56 | def init_spi(self, baudrate): 57 | try: 58 | master = self.spi.MASTER 59 | except AttributeError: 60 | # on ESP8266 61 | self.spi.init(baudrate=baudrate, phase=0, polarity=0) 62 | else: 63 | # on pyboard 64 | self.spi.init(master, baudrate=baudrate, phase=0, polarity=0) 65 | 66 | def init_card(self, baudrate): 67 | # init CS pin 68 | self.cs.init(self.cs.OUT, value=1) 69 | 70 | # init SPI bus; use low data rate for initialisation 71 | self.init_spi(100000) 72 | 73 | # clock card at least 100 cycles with cs high 74 | for i in range(16): 75 | self.spi.write(b"\xff") 76 | 77 | # CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts) 78 | for _ in range(5): 79 | if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE: 80 | break 81 | else: 82 | raise OSError("no SD card") 83 | 84 | # CMD8: determine card version 85 | r = self.cmd(8, 0x01AA, 0x87, 4) 86 | if r == _R1_IDLE_STATE: 87 | self.init_card_v2() 88 | elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND): 89 | self.init_card_v1() 90 | else: 91 | raise OSError("couldn't determine SD card version") 92 | 93 | # get the number of sectors 94 | # CMD9: response R2 (R1 byte + 16-byte block read) 95 | if self.cmd(9, 0, 0, 0, False) != 0: 96 | raise OSError("no response from SD card") 97 | csd = bytearray(16) 98 | self.readinto(csd) 99 | if csd[0] & 0xC0 == 0x40: # CSD version 2.0 100 | self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024 101 | elif csd[0] & 0xC0 == 0x00: # CSD version 1.0 (old, <=2GB) 102 | c_size = (csd[6] & 0b11) << 10 | csd[7] << 2 | csd[8] >> 6 103 | c_size_mult = (csd[9] & 0b11) << 1 | csd[10] >> 7 104 | read_bl_len = csd[5] & 0b1111 105 | capacity = (c_size + 1) * (2 ** (c_size_mult + 2)) * (2**read_bl_len) 106 | self.sectors = capacity // 512 107 | else: 108 | raise OSError("SD card CSD format not supported") 109 | # print('sectors', self.sectors) 110 | 111 | # CMD16: set block length to 512 bytes 112 | if self.cmd(16, 512, 0) != 0: 113 | raise OSError("can't set 512 block size") 114 | 115 | # set to high data rate now that it's initialised 116 | self.init_spi(baudrate) 117 | 118 | def init_card_v1(self): 119 | for i in range(_CMD_TIMEOUT): 120 | time.sleep_ms(50) 121 | self.cmd(55, 0, 0) 122 | if self.cmd(41, 0, 0) == 0: 123 | # SDSC card, uses byte addressing in read/write/erase commands 124 | self.cdv = 512 125 | # print("[SDCard] v1 card") 126 | return 127 | raise OSError("timeout waiting for v1 card") 128 | 129 | def init_card_v2(self): 130 | for i in range(_CMD_TIMEOUT): 131 | time.sleep_ms(50) 132 | self.cmd(58, 0, 0, 4) 133 | self.cmd(55, 0, 0) 134 | if self.cmd(41, 0x40000000, 0) == 0: 135 | self.cmd(58, 0, 0, -4) # 4-byte response, negative means keep the first byte 136 | ocr = self.tokenbuf[0] # get first byte of response, which is OCR 137 | if not ocr & 0x40: 138 | # SDSC card, uses byte addressing in read/write/erase commands 139 | self.cdv = 512 140 | else: 141 | # SDHC/SDXC card, uses block addressing in read/write/erase commands 142 | self.cdv = 1 143 | # print("[SDCard] v2 card") 144 | return 145 | raise OSError("timeout waiting for v2 card") 146 | 147 | def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False): 148 | self.cs(0) 149 | 150 | # create and send the command 151 | buf = self.cmdbuf 152 | buf[0] = 0x40 | cmd 153 | buf[1] = arg >> 24 154 | buf[2] = arg >> 16 155 | buf[3] = arg >> 8 156 | buf[4] = arg 157 | buf[5] = crc 158 | self.spi.write(buf) 159 | 160 | if skip1: 161 | self.spi.readinto(self.tokenbuf, 0xFF) 162 | 163 | # wait for the response (response[7] == 0) 164 | for i in range(_CMD_TIMEOUT): 165 | self.spi.readinto(self.tokenbuf, 0xFF) 166 | response = self.tokenbuf[0] 167 | if not (response & 0x80): 168 | # this could be a big-endian integer that we are getting here 169 | # if final<0 then store the first byte to tokenbuf and discard the rest 170 | if final < 0: 171 | self.spi.readinto(self.tokenbuf, 0xFF) 172 | final = -1 - final 173 | for j in range(final): 174 | self.spi.write(b"\xff") 175 | if release: 176 | self.cs(1) 177 | self.spi.write(b"\xff") 178 | return response 179 | 180 | # timeout 181 | self.cs(1) 182 | self.spi.write(b"\xff") 183 | return -1 184 | 185 | def readinto(self, buf): 186 | self.cs(0) 187 | 188 | # read until start byte (0xff) 189 | for i in range(_CMD_TIMEOUT): 190 | self.spi.readinto(self.tokenbuf, 0xFF) 191 | if self.tokenbuf[0] == _TOKEN_DATA: 192 | break 193 | time.sleep_ms(1) 194 | else: 195 | self.cs(1) 196 | raise OSError("timeout waiting for response") 197 | 198 | # read data 199 | mv = self.dummybuf_memoryview 200 | if len(buf) != len(mv): 201 | mv = mv[: len(buf)] 202 | self.spi.write_readinto(mv, buf) 203 | 204 | # read checksum 205 | self.spi.write(b"\xff") 206 | self.spi.write(b"\xff") 207 | 208 | self.cs(1) 209 | self.spi.write(b"\xff") 210 | 211 | def write(self, token, buf): 212 | self.cs(0) 213 | 214 | # send: start of block, data, checksum 215 | self.spi.read(1, token) 216 | self.spi.write(buf) 217 | self.spi.write(b"\xff") 218 | self.spi.write(b"\xff") 219 | 220 | # check the response 221 | if (self.spi.read(1, 0xFF)[0] & 0x1F) != 0x05: 222 | self.cs(1) 223 | self.spi.write(b"\xff") 224 | return 225 | 226 | # wait for write to finish 227 | while self.spi.read(1, 0xFF)[0] == 0: 228 | pass 229 | 230 | self.cs(1) 231 | self.spi.write(b"\xff") 232 | 233 | def write_token(self, token): 234 | self.cs(0) 235 | self.spi.read(1, token) 236 | self.spi.write(b"\xff") 237 | # wait for write to finish 238 | while self.spi.read(1, 0xFF)[0] == 0x00: 239 | pass 240 | 241 | self.cs(1) 242 | self.spi.write(b"\xff") 243 | 244 | def readblocks(self, block_num, buf): 245 | # workaround for shared bus, required for (at least) some Kingston 246 | # devices, ensure MOSI is high before starting transaction 247 | self.spi.write(b"\xff") 248 | 249 | nblocks = len(buf) // 512 250 | assert nblocks and not len(buf) % 512, "Buffer length is invalid" 251 | if nblocks == 1: 252 | # CMD17: set read address for single block 253 | if self.cmd(17, block_num * self.cdv, 0, release=False) != 0: 254 | # release the card 255 | self.cs(1) 256 | raise OSError(5) # EIO 257 | # receive the data and release card 258 | self.readinto(buf) 259 | else: 260 | # CMD18: set read address for multiple blocks 261 | if self.cmd(18, block_num * self.cdv, 0, release=False) != 0: 262 | # release the card 263 | self.cs(1) 264 | raise OSError(5) # EIO 265 | offset = 0 266 | mv = memoryview(buf) 267 | while nblocks: 268 | # receive the data and release card 269 | self.readinto(mv[offset : offset + 512]) 270 | offset += 512 271 | nblocks -= 1 272 | if self.cmd(12, 0, 0xFF, skip1=True): 273 | raise OSError(5) # EIO 274 | 275 | def writeblocks(self, block_num, buf): 276 | # workaround for shared bus, required for (at least) some Kingston 277 | # devices, ensure MOSI is high before starting transaction 278 | self.spi.write(b"\xff") 279 | 280 | nblocks, err = divmod(len(buf), 512) 281 | assert nblocks and not err, "Buffer length is invalid" 282 | if nblocks == 1: 283 | # CMD24: set write address for single block 284 | if self.cmd(24, block_num * self.cdv, 0) != 0: 285 | raise OSError(5) # EIO 286 | 287 | # send the data 288 | self.write(_TOKEN_DATA, buf) 289 | else: 290 | # CMD25: set write address for first block 291 | if self.cmd(25, block_num * self.cdv, 0) != 0: 292 | raise OSError(5) # EIO 293 | # send the data 294 | offset = 0 295 | mv = memoryview(buf) 296 | while nblocks: 297 | self.write(_TOKEN_CMD25, mv[offset : offset + 512]) 298 | offset += 512 299 | nblocks -= 1 300 | self.write_token(_TOKEN_STOP_TRAN) 301 | 302 | def ioctl(self, op, arg): 303 | if op == 4: # get number of blocks 304 | return self.sectors 305 | if op == 5: # get block size in bytes 306 | return 512 307 | -------------------------------------------------------------------------------- /pico_files/modules/picocalc.py: -------------------------------------------------------------------------------- 1 | import framebuf 2 | import picocalcdisplay 3 | from micropython import const 4 | import machine 5 | from machine import Pin, I2C, PWM, SPI 6 | from collections import deque 7 | import time 8 | import sdcard 9 | import uos 10 | import array 11 | from colorer import Fore, Back, Style, print, autoreset 12 | sd = None 13 | keyboard, display = None, None 14 | terminal = None 15 | edit = None 16 | usb_debug = None 17 | 18 | _REG_VER = const(0x01) # fw version 19 | _REG_CFG = const(0x02) # config 20 | _REG_INT = const(0x03) # interrupt status 21 | _REG_KEY = const(0x04) # key status 22 | _REG_BKL = const(0x05) # backlight 23 | _REG_DEB = const(0x06) # debounce cfg 24 | _REG_FRQ = const(0x07) # poll freq cfg 25 | _REG_RST = const(0x08) # reset 26 | _REG_FIF = const(0x09) # fifo 27 | _REG_BK2 = const(0x0A) # backlight 2 28 | _REG_BAT = const(0x0B) # battery 29 | _REG_DIR = const(0x0C) # gpio direction 30 | _REG_PUE = const(0x0D) # gpio input pull enable 31 | _REG_PUD = const(0x0E) # gpio input pull direction 32 | _REG_GIO = const(0x0F) # gpio value 33 | _REG_GIC = const(0x10) # gpio interrupt config 34 | _REG_GIN = const(0x11) # gpio interrupt status 35 | _KEY_COUNT_MASK = const(0x1F) 36 | _WRITE_MASK = const(1 << 7) 37 | _StateIdle = const(0) 38 | _StatePress = const(1) 39 | _StateLongPress = const(2) 40 | _StateRelease = const(3) 41 | 42 | ''' 43 | import uctypes 44 | from uctypes import struct, OBJ, NATIVE_UINTPTR, UINT16, UINT8, LITTLE_ENDIAN 45 | from uctypes import addressof 46 | 47 | W2, H2 = 320, 320 48 | buf2 = bytearray(W2 * H2/2) 49 | 50 | # typedef struct _mp_obj_framebuf_t { 51 | # mp_obj_base_t base; // offset 0, 4 bytes 52 | # mp_obj_t buf_obj; // offset 4, 4 bytes 53 | # void *buf; // offset 8, 4 bytes 54 | # uint16_t width; // offset 12, 2 bytes 55 | # uint16_t height; // offset 14, 2 bytes 56 | # uint16_t stride; // offset 16, 2 bytes 57 | # uint8_t format; // offset 18, 1 byte 58 | # } mp_obj_framebuf_t; 59 | layout = { 60 | 'buf_obj': (OBJ, 4), 61 | 'buf_ptr': (NATIVE_UINTPTR, 8), 62 | 'width': (UINT16 | LITTLE_ENDIAN, 12), 63 | 'height': (UINT16 | LITTLE_ENDIAN, 14), 64 | 'stride': (UINT16 | LITTLE_ENDIAN, 16), 65 | 'format': (UINT8, 18), 66 | } 67 | 68 | 69 | fb_s = struct(addressof(display), layout) 70 | fb_s.buf_obj = buf2 71 | fb_s.buf_ptr = addressof(buf2) 72 | 73 | #fb_s.width = W2 74 | #fb_s.height = H2 75 | #fb_s.stride = W2 76 | 77 | #fb_s.format = framebuf.GS8 78 | 79 | 80 | 81 | ''' 82 | class PicoDisplay(framebuf.FrameBuffer): 83 | def __init__(self, width, height,color_type = framebuf.GS4_HMSB): 84 | self.width = width 85 | self.height = height 86 | if color_type == framebuf.GS4_HMSB: 87 | buffer = bytearray(self.width * self.height//2) # 4bpp mono 88 | elif color_type == framebuf.RGB565: 89 | buffer = bytearray(self.width * self.height*2) 90 | elif color_type == framebuf.GS8: 91 | buffer = bytearray(self.width * self.height) 92 | elif color_type == framebuf.GS2_HMSB: 93 | buffer = bytearray(self.width * self.height//4) 94 | elif color_type == framebuf.MONO_HMSB: 95 | buffer = bytearray(self.width * self.height//8) 96 | 97 | 98 | super().__init__(buffer, self.width, self.height, color_type) 99 | picocalcdisplay.init(buffer,color_type,True) 100 | 101 | def restLUT(self): 102 | picocalcdisplay.resetLUT(0) 103 | 104 | def switchPredefinedLUT(self, name='vt100'): 105 | if name == 'vt100': 106 | picocalcdisplay.resetLUT(0) 107 | 108 | elif name == 'pico8': 109 | picocalcdisplay.resetLUT(1) 110 | else: 111 | raise ValueError("Unknown LUT name. Use 'vt100' or 'pico8'.") 112 | 113 | def getLUT(self): 114 | return picocalcdisplay.getLUTview().cast("H") 115 | 116 | def setLUT(self,lut): 117 | if not (isinstance(lut, array.array)): 118 | raise TypeError("LUT must be an array of type 'H' (unsigned short)") 119 | picocalcdisplay.setLUT(lut) 120 | 121 | def stopRefresh(self): 122 | picocalcdisplay.stopAutoUpdate() 123 | 124 | def recoverRefresh(self): 125 | picocalcdisplay.startAutoUpdate() 126 | 127 | def text(self,c, x0, y0, color): 128 | picocalcdisplay.drawTxt6x8(c,x0,y0,color) 129 | 130 | def show(self,core=1): 131 | picocalcdisplay.update(core) 132 | 133 | def isScreenUpdateDone(self): 134 | return picocalcdisplay.isScreenUpdateDone() 135 | 136 | class PicoKeyboard: 137 | def __init__(self,sclPin=7,sdaPin=6,address=0x1f): 138 | self.hardwarekeyBuf = deque((),30) 139 | self.i2c = I2C(1,scl=Pin(sclPin),sda=Pin(sdaPin),freq=10000) 140 | #self.i2c.scan() 141 | self.ignor = True 142 | self.address = address 143 | self.temp=bytearray(2) 144 | self.reset() 145 | self.isShift = False 146 | self.isCtrl = False 147 | self.isAlt = False 148 | 149 | def ignor_mod(self): 150 | self.ignor = True 151 | 152 | def write_cmd(self,cmd): 153 | self.i2c.writeto(self.address,bytearray([cmd])) 154 | 155 | def read_reg16(self,reg): 156 | self.temp[0]=reg 157 | self.i2c.writeto(self.address,self.temp[0:1]) 158 | self.i2c.readfrom_into(self.address,self.temp) 159 | return self.temp 160 | 161 | def read_reg8(self,reg): 162 | self.i2c.writeto(self.address, bytes(reg)) 163 | #self.temp[0]=reg 164 | #self.i2c.writeto(self.address,self.temp[0:1]) 165 | return self.i2c.readfrom(self.address, 1)[0] 166 | #self.i2c.readfrom_into(self.address,memoryview(self.temp)[0:1]) 167 | #return self.temp 168 | 169 | def write_reg(self,reg,value): 170 | self.temp[0]=reg| _WRITE_MASK 171 | self.temp[1]=value 172 | self.i2c.writeto(self.address,self.temp) 173 | 174 | def enable_report_mods(self): 175 | currentCFG = self.read_reg8(_REG_CFG) 176 | self.temp[0]=currentCFG | (0x01<<6) 177 | self.write_reg(_REG_CFG,self.temp[0:1]) 178 | 179 | def disable_report_mods(self): 180 | currentCFG = self.read_reg8(_REG_CFG) 181 | self.temp[0]=currentCFG & (~(0x01<<6)) 182 | self.write_reg(_REG_CFG,self.temp[0:1]) 183 | 184 | def enable_use_mods(self): 185 | currentCFG = self.read_reg8(_REG_CFG) 186 | self.temp[0]=currentCFG | (0x01<<7) 187 | self.write_reg(_REG_CFG,self.temp[0:1]) 188 | 189 | def disable_use_mods(self): 190 | currentCFG = self.read_reg8(_REG_CFG) 191 | self.temp[0]=currentCFG & (~(0x01<<7)) 192 | self.write_reg(_REG_CFG,self.temp[0:1]) 193 | 194 | def reset(self): 195 | self.write_cmd(_REG_RST) 196 | time.sleep_ms(100) 197 | 198 | def keyCount(self): 199 | buf = self.read_reg16(_REG_KEY) 200 | return (buf[0] & _KEY_COUNT_MASK) 201 | 202 | def keyEvent(self): 203 | if (self.keyCount() == 0): 204 | return None 205 | else: 206 | buf = self.read_reg16(_REG_FIF) 207 | return buf 208 | 209 | def backlight(self): 210 | return self.read_reg8(_REG_BKL) 211 | 212 | def setBacklight(self,value): 213 | self.write_reg(_REG_BKL,value) 214 | 215 | def backlight_keyboard(self): 216 | return self.read_reg8(_REG_BK2) 217 | 218 | def setBacklight_keyboard(self,value): 219 | self.write_reg(_REG_BK2,value) 220 | 221 | def battery(self): 222 | return self.read_reg16(_REG_BAT) 223 | 224 | def readinto(self, buf): 225 | 226 | numkeysInhardware = self.keyCount()#how many keys in hardware 227 | if numkeysInhardware != 0: 228 | for i in range(numkeysInhardware): 229 | keyGot=self.keyEvent() 230 | state = keyGot[0] 231 | key = keyGot[1] 232 | if state == _StatePress or state == _StateLongPress: 233 | 234 | if key == 0xa2 or key == 0xa3: 235 | self.isShift = True 236 | elif key == 0xa5: 237 | self.isCtrl = True 238 | elif key == 0xa1: 239 | self.isAlt = True 240 | else: 241 | #check current shift/ctrl/alt state 242 | modifier=b'' 243 | if self.isShift and self.isAlt and (not self.isCtrl): 244 | modifier=b';4' 245 | elif self.isShift and self.isCtrl and (not self.isAlt): 246 | modifier=b';6' 247 | elif self.isAlt and self.isCtrl and (not self.isShift): 248 | modifier=b';7' 249 | elif self.isShift and self.isCtrl and self.isAlt: 250 | modifier=b';8' 251 | elif self.isAlt and (not self.isCtrl) and (not self.isShift): 252 | modifier=b';3' 253 | elif (not self.isAlt) and self.isCtrl and (not self.isShift): 254 | modifier=b';5' 255 | elif (not self.isAlt) and (not self.isCtrl) and self.isShift: 256 | modifier=b';2' 257 | 258 | if key >=0xB4 and key <= 0xB7: 259 | #direction keys 260 | #self.hardwarekeyBuf.append(0x1b) 261 | #self.hardwarekeyBuf.append(ord('[')) 262 | if modifier != b'': 263 | parameters = b'1' 264 | else: 265 | parameters = b'' 266 | if key == 0xB4: 267 | self.hardwarekeyBuf.extend(b'\x1b['+parameters+modifier+b'D') 268 | elif key == 0xB5: 269 | self.hardwarekeyBuf.extend(b'\x1b['+parameters+modifier+b'A') 270 | elif key == 0xB6: 271 | self.hardwarekeyBuf.extend(b'\x1b['+parameters+modifier+b'B') 272 | elif key == 0xB7: 273 | self.hardwarekeyBuf.extend(b'\x1b['+parameters+modifier+b'C') 274 | elif key == 0x0A: 275 | self.hardwarekeyBuf.append(ord('\r')) 276 | #self.hardwarekeyBuf.append(ord('\n')) #return key 277 | elif key == 0xB1: # KEY_ESC 278 | self.hardwarekeyBuf.extend(b'\x1b\x1b') 279 | elif key == 0xD2: #KEY_HOME 280 | self.hardwarekeyBuf.extend(b'\x1b[H') 281 | elif key == 0xD5: #end 282 | self.hardwarekeyBuf.extend(b'\x1b[F') 283 | elif key == 0x08: #backspace 284 | self.hardwarekeyBuf.append(0x7F) 285 | elif key == 0xD4: #delete 286 | self.hardwarekeyBuf.extend(b'\x1b[3'+modifier+b'~') 287 | else: 288 | if self.isAlt == True: 289 | if key !=ord(' ') and key!=ord(',') and key!=ord('.'): 290 | self.hardwarekeyBuf.extend(b'\x1b')#to match the vt100 terminal style 291 | self.hardwarekeyBuf.append(key) 292 | elif self.isCtrl == True: 293 | self.hardwarekeyBuf.append(key&0x1F) 294 | else: 295 | self.hardwarekeyBuf.append(key) 296 | else: 297 | if key == 0xa2 or key == 0xa3: 298 | self.isShift = False 299 | elif key == 0xa5: 300 | self.isCtrl = False 301 | elif key == 0xa1: 302 | self.isAlt = False 303 | #self.hardwarekeyBuf.append(key[:]) 304 | #now deside how many keys to send to buf 305 | requestedkeys = len(buf) 306 | keysLeft = requestedkeys 307 | if len(self.hardwarekeyBuf)==0: #after read in the key, still no key in buffer 308 | return None 309 | #print("init buf") 310 | #print(buf) 311 | #print("hardware key buf size") 312 | #print(len(self.hardwarekeyBuf)) 313 | while keysLeft > 0: 314 | 315 | #fill all keys until key list is empty 316 | if len(self.hardwarekeyBuf) == 0: 317 | break #all keys has been read and process 318 | 319 | key = self.hardwarekeyBuf.popleft()#remove the processed key from key list 320 | buf[-keysLeft]=key 321 | keysLeft -=1 322 | 323 | #print("read buff") 324 | #print(buf) 325 | #print(requestedkeys-keysLeft) 326 | if requestedkeys-keysLeft == 0: 327 | return None 328 | else: 329 | return (requestedkeys-keysLeft) 330 | 331 | class PicoSD: 332 | """ 333 | Example class for SD card configuration and management by LaikaSpaceDawg. 334 | This class handles the mounting and unmounting of the SD card, as well as checking its status. 335 | Also demonstrates basic uColorama usage for colored output. 336 | """ 337 | def __init__(self, mount_point="/sd", sck_pin=18, mosi_pin=19, miso_pin=16, cs_pin=17, spi_bus=0, baudrate=1000000): 338 | """ 339 | Initialize SD card configuration. 340 | 341 | :param mount_point: Directory to mount the SD card to. 342 | :param sck_pin: GPIO pin connected to SCK. 343 | :param mosi_pin: GPIO pin connected to MOSI. 344 | :param miso_pin: GPIO pin connected to MISO. 345 | :param cs_pin: GPIO pin connected to CS. 346 | :param spi_bus: SPI bus to be used. 347 | :param baudrate: SPI communication speed. 348 | """ 349 | self.mount_point = mount_point 350 | self.sck_pin = sck_pin 351 | self.mosi_pin = mosi_pin 352 | self.miso_pin = miso_pin 353 | self.cs_pin = cs_pin 354 | self.spi_bus = spi_bus 355 | self.baudrate = baudrate 356 | self.sd = None 357 | 358 | # Attempt to mount the SD card on initialization 359 | self.mount() 360 | 361 | def __call__(self): 362 | """Allow the SDManager object to be called like a function to get the SDCard object.""" 363 | if self.sd: 364 | return self.sd 365 | 366 | def mount(self): 367 | """ 368 | Mount the SD card. 369 | """ 370 | if self.sd is None: 371 | try: 372 | self.sd = sdcard.SDCard( 373 | machine.SPI(self.spi_bus, baudrate=self.baudrate, polarity=0, phase=0, 374 | sck=machine.Pin(self.sck_pin), 375 | mosi=machine.Pin(self.mosi_pin), 376 | miso=machine.Pin(self.miso_pin)), 377 | machine.Pin(self.cs_pin) 378 | ) 379 | uos.mount(self.sd, self.mount_point) 380 | print(f"{Fore.GREEN}SD card mounted successfully at", self.mount_point) 381 | except Exception as e: 382 | print(f"{Fore.RED}Failed to mount SD card: {e}") 383 | self.sd = None 384 | else: 385 | print(f"{Fore.YELLOW}SD card is already mounted.") 386 | 387 | def unmount(self): 388 | """ 389 | Unmount the SD card. 390 | """ 391 | if self.sd is not None: 392 | try: 393 | uos.umount(self.mount_point) 394 | self.sd = None 395 | print(f"SD card unmounted from {self.mount_point}.") 396 | except Exception as e: 397 | print(f"{Fore.RED}Failed to unmount SD card: {e}") 398 | else: 399 | print("No SD card is mounted to unmount.") 400 | 401 | def check_mount(self): 402 | """ 403 | Check if the SD card is mounted. 404 | """ 405 | try: 406 | if uos.stat(self.mount_point): 407 | print(f"{Fore.GREEN}SD card is mounted at {self.mount_point}.") 408 | except OSError: 409 | print(f"{Fore.RED}No SD card is mounted at {self.mount_point}.") 410 | 411 | # Frequency definitions for musical notes 412 | NOTE_FREQUENCIES = { 413 | 'B1': 31, 'C2': 33, 'CS2': 35, 'D2': 37, 'DS2': 39, 'E2': 41, 'F2': 44, 'FS2': 46, 414 | 'G2': 49, 'GS2': 52, 'A2': 55, 'AS2': 58, 'B2': 62, 'C3': 65, 'CS3': 69, 'D3': 73, 415 | 'DS3': 78, 'E3': 82, 'F3': 87, 'FS3': 93, 'G3': 98, 'GS3': 104, 'A3': 110, 'AS3': 117, 416 | 'B3': 123, 'C4': 131, 'CS4': 139, 'D4': 147, 'DS4': 156, 'E4': 165, 'F4': 175, 417 | 'FS4': 185, 'G4': 196, 'GS4': 208, 'A4': 220, 'AS4': 233, 'B4': 247, 'C5': 262, 418 | 'CS5': 277, 'D5': 294, 'DS5': 311, 'E5': 330, 'F5': 349, 'FS5': 370, 'G5': 392, 419 | 'GS5': 415, 'A5': 440, 'AS5': 466, 'B5': 494, 'C6': 523, 'CS6': 554, 'D6': 587, 420 | 'DS6': 622, 'E6': 659, 'F6': 698, 'FS6': 740, 'G6': 784, 'GS6': 831, 'A6': 880, 421 | 'AS6': 932, 'B6': 988, 'C7': 1047, 'CS7': 1109, 'D7': 1175, 'DS7': 1245, 'E7': 1319, 422 | 'F7': 1397, 'FS7': 1480, 'G7': 1568, 'GS7': 1661, 'A7': 1760, 'AS7': 1865, 'B7': 1976, 423 | 'C8': 2093, 'CS8': 2217, 'D8': 2349, 'DS8': 2489, 'E8': 2637, 'F8': 2794, 'FS8': 2960, 424 | 'G8': 3136, 'GS8': 3322, 'A8': 3520, 'AS8': 3729, 'B8': 3951, 'C9': 4186, 'CS9': 4435, 425 | 'D9': 4699, 'DS9': 4978, 'P': 0 # 'P' is for pause 426 | } 427 | 428 | class PicoSpeaker: 429 | def __init__(self, pin_number): 430 | self.buzzer_pin = Pin(pin_number) 431 | self.pwm = None 432 | 433 | def tone(self, tone, duration): 434 | """ 435 | Play a tone given by a note string from NOTE_FREQUENCIES or directly as a frequency number. 436 | 437 | :param tone: Either a note string ("A4", "C5", etc.) or a frequency in Hz. 438 | :param duration: Duration in seconds for which to play the tone. 439 | Written by @LaikaSpaceDawg (https://github.com/LaikaSpaceDawg/PicoCalc-micropython) 440 | """ 441 | frequency = 0 442 | 443 | if isinstance(tone, str) and tone.upper() in NOTE_FREQUENCIES: 444 | frequency = NOTE_FREQUENCIES[tone.upper()] 445 | elif isinstance(tone, (int, float)): 446 | frequency = tone 447 | 448 | if frequency > 0: 449 | self.pwm = PWM(self.buzzer_pin) 450 | self.pwm.freq(frequency) 451 | self.pwm.duty_u16(32768) 452 | time.sleep(duration * 0.9) 453 | if self.pwm: 454 | self.pwm.deinit() 455 | time.sleep(duration * 0.1) 456 | 457 | def tones(self, notes_durations): 458 | """ 459 | Play a sequence of notes with their respective durations. 460 | 461 | :param notes_durations: List of tuples where each tuple contains a note and its duration. 462 | e.g., [("A4", 0.5), ("C5", 0.5)] 463 | """ 464 | for tone, duration in notes_durations: 465 | self.tone(tone, duration) 466 | 467 | def rtttl(self, text): 468 | """ 469 | Convert RTTTL formatted string into frequency-duration pairs. 470 | Provided by: @GraphicHealer (https://github.com/GraphicHealer/MicroPython-RTTTL) 471 | """ 472 | try: 473 | title, defaults, song = text.split(':') 474 | d, o, b = defaults.split(',') 475 | d = int(d.split('=')[1]) 476 | o = int(o.split('=')[1]) 477 | b = int(b.split('=')[1]) 478 | whole = (60000 / b) * 4 479 | noteList = song.split(',') 480 | except: 481 | return 'Please enter a valid RTTTL string.' 482 | 483 | notes = 'abcdefgp' 484 | outList = [] 485 | 486 | for note in noteList: 487 | index = 0 488 | for i in note: 489 | if i in notes: 490 | index = note.find(i) 491 | break 492 | 493 | length = note[0:index] 494 | value = note[index:].replace('#', 's').replace('.', '') 495 | 496 | if not any(char.isdigit() for char in value): 497 | value += str(o) 498 | if 'p' in value: 499 | value = 'p' 500 | 501 | if length == '': 502 | length = d 503 | else: 504 | length = int(length) 505 | 506 | length = whole / length 507 | 508 | if '.' in note: 509 | length += length / 2 510 | 511 | outList.append((NOTE_FREQUENCIES[value.upper()], length)) 512 | 513 | return outList 514 | 515 | def play_rtttl(self, rtttl_string): 516 | """ 517 | Play RTTTL formatted song. 518 | Provided by: @GraphicHealer (https://github.com/GraphicHealer/MicroPython-RTTTL) 519 | """ 520 | tune = self.rtttl(rtttl_string) 521 | 522 | if type(tune) is not list: 523 | print(tune) 524 | return 525 | 526 | for freqc, msec in tune: 527 | self._play_frequency(freqc, msec * 0.001) -------------------------------------------------------------------------------- /picocalcdisplay/picocalcdisplay.c: -------------------------------------------------------------------------------- 1 | #include "picocalcdisplay.h" 2 | // Include MicroPython API. 3 | #include "py/runtime.h" 4 | 5 | // Used to get the time in the Timer class example. 6 | #include "py/mphal.h" 7 | #include "py/gc.h" 8 | #include "py/misc.h" 9 | #include 10 | #include 11 | #include 12 | #include "hardware/spi.h" 13 | #include "hardware/dma.h" 14 | #include "hardware/gpio.h" 15 | #include "pico/stdlib.h" 16 | #include "pico/multicore.h" 17 | #include "hardware/sync.h" 18 | #include "font6x8e500.h" 19 | 20 | 21 | #define SWRESET 0x01 22 | #define SLPOUT 0x11 23 | #define INVON 0x21 24 | #define DISPON 0x29 25 | #define CASET 0x2A 26 | #define RASET 0x2B 27 | #define RAMWR 0x2C 28 | #define TEON 0x35 29 | #define MADCTL 0x36 // Memory Data Access Control 30 | #define COLMOD 0x3A// 31 | #define FRMCTR1 0xB1 32 | #define INVCTR 0xB4 33 | #define ETMOD 0xB7 34 | #define CECTRL1 0xB9 35 | #define PWCTR1 0xC0 36 | #define PWCTR2 0xC1 37 | #define PWCTR3 0xC2 38 | #define VMCTR1 0xC5 39 | #define PGAMCTRL 0xE0 40 | #define NGAMCTRL 0xE1 41 | #define CORE1_STACK_SIZE 1024 42 | uint32_t core1_stack[CORE1_STACK_SIZE]; 43 | 44 | static uint st_dma; 45 | static uint8_t *frameBuff; 46 | static volatile bool oneShotisDone=true; 47 | static volatile bool autoUpdate; 48 | static uint16_t lineBuffA[64]; 49 | static uint16_t lineBuffB[64]; 50 | void (*pColorUpdate)(uint8_t *, uint32_t, const uint16_t *); 51 | void (*pSetPixel)(int32_t,int32_t,uint16_t); 52 | static uint8_t currentTextY; 53 | static uint8_t currentTextX; 54 | static const uint8_t *currentTextTable; 55 | static uint16_t LUT[256] = {0}; // Look-Up Table for 4bpp to RGB565 conversion 56 | 57 | static const uint16_t pico8LUT[16]={ 58 | 0x0000, 0x4A19, 0x2A79, 0x2A04, 0x86AA, 0xA95A, 0x18C6, 0x9DFF, 59 | 0x09F8, 0x00FD, 0x64FF, 0x2607, 0x7F2D, 0xB383, 0xB5FB, 0x75FE 60 | }; 61 | static const uint16_t defaultLUT[256] = { 62 | //0x0000, 0x4A19, 0x2A79, 0x2A04, 0x86AA, 0xA95A, 0x18C6, 0x9DFF, 63 | //0x09F8, 0x00FD, 0x64FF, 0x2607, 0x7F2D, 0xB383, 0xB5FB, 0x75FE 64 | 0x0000, 0x0080, 0x0004, 0x0084, 0x1000, 0x1080, 0x1004, 0x18C6, 65 | 0x1084, 0x00F8, 0xE007, 0xE0FF, 0x1F00, 0x1FF8, 0xFF07, 0xFFFF, 66 | 0x0000, 0x0B00, 0x1000, 0x1500, 0x1A00, 0x1F00, 0xE002, 0xEB02, 67 | 0xF002, 0xF502, 0xFA02, 0xFF02, 0x2004, 0x2B04, 0x3004, 0x3504, 68 | 0x3A04, 0x3F04, 0x6005, 0x6B05, 0x7005, 0x7505, 0x7A05, 0x7F05, 69 | 0xA006, 0xAB06, 0xB006, 0xB506, 0xBA06, 0xBF06, 0xE007, 0xEB07, 70 | 0xF007, 0xF507, 0xFA07, 0xFF07, 0x0058, 0x0B58, 0x1058, 0x1558, 71 | 0x1A58, 0x1F58, 0xE05A, 0xEB5A, 0xF05A, 0xF55A, 0xFA5A, 0xFF5A, 72 | 0x205C, 0x2B5C, 0x305C, 0x355C, 0x3A5C, 0x3F5C, 0x605D, 0x6B5D, 73 | 0x705D, 0x755D, 0x7A5D, 0x7F5D, 0xA05E, 0xAB5E, 0xB05E, 0xB55E, 74 | 0xBA5E, 0xBF5E, 0xE05F, 0xEB5F, 0xF05F, 0xF55F, 0xFA5F, 0xFF5F, 75 | 0x0080, 0x0B80, 0x1080, 0x1580, 0x1A80, 0x1F80, 0xE082, 0xEB82, 76 | 0xF082, 0xF582, 0xFA82, 0xFF82, 0x2084, 0x2B84, 0x3084, 0x3584, 77 | 0x3A84, 0x3F84, 0x6085, 0x6B85, 0x7085, 0x7585, 0x7A85, 0x7F85, 78 | 0xA086, 0xAB86, 0xB086, 0xB586, 0xBA86, 0xBF86, 0xE087, 0xEB87, 79 | 0xF087, 0xF587, 0xFA87, 0xFF87, 0x00A8, 0x0BA8, 0x10A8, 0x15A8, 80 | 0x1AA8, 0x1FA8, 0xE0AA, 0xEBAA, 0xF0AA, 0xF5AA, 0xFAAA, 0xFFAA, 81 | 0x20AC, 0x2BAC, 0x30AC, 0x35AC, 0x3AAC, 0x3FAC, 0x60AD, 0x6BAD, 82 | 0x70AD, 0x75AD, 0x7AAD, 0x7FAD, 0xA0AE, 0xABAE, 0xB0AE, 0xB5AE, 83 | 0xBAAE, 0xBFAE, 0xE0AF, 0xEBAF, 0xF0AF, 0xF5AF, 0xFAAF, 0xFFAF, 84 | 0x00D0, 0x0BD0, 0x10D0, 0x15D0, 0x1AD0, 0x1FD0, 0xE0D2, 0xEBD2, 85 | 0xF0D2, 0xF5D2, 0xFAD2, 0xFFD2, 0x20D4, 0x2BD4, 0x30D4, 0x35D4, 86 | 0x3AD4, 0x3FD4, 0x60D5, 0x6BD5, 0x70D5, 0x75D5, 0x7AD5, 0x7FD5, 87 | 0xA0D6, 0xABD6, 0xB0D6, 0xB5D6, 0xBAD6, 0xBFD6, 0xE0D7, 0xEBD7, 88 | 0xF0D7, 0xF5D7, 0xFAD7, 0xFFD7, 0x00F8, 0x0BF8, 0x10F8, 0x15F8, 89 | 0x1AF8, 0x1FF8, 0xE0FA, 0xEBFA, 0xF0FA, 0xF5FA, 0xFAFA, 0xFFFA, 90 | 0x20FC, 0x2BFC, 0x30FC, 0x35FC, 0x3AFC, 0x3FFC, 0x60FD, 0x6BFD, 91 | 0x70FD, 0x75FD, 0x7AFD, 0x7FFD, 0xA0FE, 0xABFE, 0xB0FE, 0xB5FE, 92 | 0xBAFE, 0xBFFE, 0xE0FF, 0xEBFF, 0xF0FF, 0xF5FF, 0xFAFF, 0xFFFF, 93 | 0x4108, 0x8210, 0xE318, 0x2421, 0x8631, 0xC739, 0x2842, 0x694A, 94 | 0xCB5A, 0x0C63, 0x6D6B, 0xAE73, 0x1084, 0x518C, 0xB294, 0xF39C, 95 | 0x55AD, 0x96B5, 0xF7BD, 0x38C6, 0x9AD6, 0xDBDE, 0x3CE7, 0x7DEF, 96 | };//standar vt100 color table with byte sweep 97 | 98 | 99 | static void Write_dma(const uint8_t *src, size_t len); 100 | static void command(uint8_t com, size_t len, const char *data) ; 101 | void RGB565Update(uint8_t *frameBuff,uint32_t length, const uint16_t *LUT); 102 | void LUT8Update(uint8_t *frameBuff, uint32_t length, const uint16_t *LUT); 103 | void LUT4Update(uint8_t *frameBuff, uint32_t length, const uint16_t *LUT); 104 | void LUT2Update(uint8_t *frameBuff, uint32_t length, const uint16_t *LUT); 105 | void LUT1Update(uint8_t *frameBuff, uint32_t length, const uint16_t *LUT); 106 | //void core1_main(void); 107 | void setpixelRGB565(int32_t x, int32_t y,uint16_t color); 108 | void setpixelLUT8(int32_t x, int32_t y,uint16_t color); 109 | void setpixelLUT4(int32_t x, int32_t y,uint16_t color); 110 | void setpixelLUT2(int32_t x, int32_t y,uint16_t color); 111 | void setpixelLUT1(int32_t x, int32_t y,uint16_t color); 112 | 113 | /* 114 | #define FRAMEBUF_MVLSB (0) 115 | #define FRAMEBUF_RGB565 (1) 116 | #define FRAMEBUF_GS2_HMSB (5) 117 | #define FRAMEBUF_GS4_HMSB (2) 118 | #define FRAMEBUF_GS8 (6) 119 | #define FRAMEBUF_MHLSB (3) 120 | #define FRAMEBUF_MHMSB (4) 121 | */ 122 | static void core1_main(void); 123 | static void core1_singleShot(void); 124 | 125 | static void core1_main(void) { 126 | //multicore_lockout_victim_init(); 127 | //static int frame = 0; 128 | while (1) { 129 | //if (++frame % 100 == 0) { 130 | // printf("Core1 alive: %d\n", frame); 131 | //} 132 | if (autoUpdate){ 133 | pColorUpdate(frameBuff,DISPLAY_HEIGHT*DISPLAY_WIDTH, LUT); 134 | } 135 | sleep_ms(5); 136 | 137 | } 138 | } 139 | 140 | static void core1_singleShot(void){ 141 | pColorUpdate(frameBuff,DISPLAY_HEIGHT*DISPLAY_WIDTH, LUT); 142 | oneShotisDone=true; 143 | } 144 | 145 | void setpixelRGB565(int32_t x, int32_t y,uint16_t color){ 146 | ((uint16_t *)frameBuff)[x + DISPLAY_WIDTH*y]= color; 147 | } 148 | 149 | void setpixelLUT8(int32_t x, int32_t y,uint16_t color){ 150 | ((uint8_t *)frameBuff)[x + DISPLAY_WIDTH*y]= (uint8_t)color; 151 | } 152 | 153 | void setpixelLUT4(int32_t x, int32_t y,uint16_t color){ 154 | uint8_t *pixel = &((uint8_t *)frameBuff)[(x + (DISPLAY_WIDTH*y))>>1]; 155 | 156 | if (x&0x01) { 157 | *pixel = ((uint8_t)color & 0x0f) | (*pixel & 0xf0); 158 | } else { 159 | *pixel = ((uint8_t)color << 4) | (*pixel & 0x0f); 160 | } 161 | } 162 | 163 | void setpixelLUT2(int32_t x, int32_t y,uint16_t color){ 164 | uint8_t *pixel = &((uint8_t *)frameBuff)[(x + (DISPLAY_WIDTH*y))>>2]; 165 | uint8_t shift = (x & 0x3) << 1; 166 | uint8_t mask = 0x3 << shift; 167 | color = ((uint8_t)color & 0x3) << shift; 168 | *pixel = color | (*pixel & (~mask)); 169 | } 170 | 171 | void setpixelLUT1(int32_t x, int32_t y,uint16_t color){ 172 | size_t index = (x + y * DISPLAY_WIDTH) >> 3; 173 | unsigned int offset = x & 0x07; 174 | ((uint8_t *)frameBuff)[index] = (((uint8_t *)frameBuff)[index] & ~(0x01 << offset)) | ((color != 0) << offset); 175 | } 176 | 177 | static mp_obj_t pd_resetLUT(mp_obj_t index){ 178 | uint32_t lutIdx = mp_obj_get_int(index); 179 | switch(lutIdx){ 180 | case 0: // Default LUT 181 | memcpy(LUT, (uint16_t *)defaultLUT, 256 * sizeof(uint16_t)); 182 | break; 183 | case 1: // Pico-8 LUT 184 | memcpy(LUT, (uint16_t *)pico8LUT, 16 * sizeof(uint16_t)); 185 | break; 186 | 187 | } 188 | return mp_const_none; 189 | } 190 | static MP_DEFINE_CONST_FUN_OBJ_1(pd_resetLUT_obj, pd_resetLUT); 191 | 192 | 193 | 194 | static mp_obj_t pd_getLUTview(void) { 195 | 196 | 197 | 198 | return mp_obj_new_memoryview('H', 256, (void *)LUT); 199 | 200 | } 201 | static MP_DEFINE_CONST_FUN_OBJ_0(pd_getLUTview_obj, pd_getLUTview); 202 | 203 | 204 | static mp_obj_t pd_init(mp_obj_t fb_obj, mp_obj_t color_type, mp_obj_t autoR){ 205 | mp_buffer_info_t buf_info; 206 | mp_get_buffer_raise(fb_obj, &buf_info, MP_BUFFER_READ); 207 | frameBuff=(uint8_t *)buf_info.buf; 208 | autoUpdate = mp_obj_is_true(autoR); 209 | 210 | int32_t colorType = mp_obj_get_int(color_type); 211 | memcpy(LUT, (uint16_t *)defaultLUT, 256 * sizeof(uint16_t)); 212 | currentTextY = 8; 213 | currentTextX = 6; 214 | currentTextTable=CP437_display; 215 | switch (colorType){ 216 | case 1: //565 217 | pColorUpdate = RGB565Update; 218 | pSetPixel = setpixelRGB565; 219 | break; 220 | case 2: //16 color 221 | pColorUpdate = LUT4Update; 222 | pSetPixel = setpixelLUT4; 223 | break; 224 | case 4: //2 color 225 | pColorUpdate = LUT1Update; 226 | pSetPixel = setpixelLUT1; 227 | break; 228 | case 5: //4 color 229 | pColorUpdate = LUT2Update; 230 | pSetPixel = setpixelLUT2; 231 | break; 232 | case 6: //256 color 233 | pColorUpdate = LUT8Update; 234 | pSetPixel = setpixelLUT8; 235 | break; 236 | 237 | } 238 | //spi init 239 | spi_init(SPI_DISP, 40000000); 240 | gpio_set_function(CLK_PIN, GPIO_FUNC_SPI); 241 | gpio_set_function(MOSI_PIN, GPIO_FUNC_SPI); 242 | 243 | gpio_init(CS_PIN); 244 | gpio_put(CS_PIN, 1); 245 | gpio_set_dir(CS_PIN, GPIO_OUT); 246 | 247 | gpio_init(DC_PIN); 248 | gpio_set_dir(DC_PIN, GPIO_OUT); 249 | 250 | gpio_init(RST_PIN); 251 | gpio_put(RST_PIN, 0); 252 | gpio_set_dir(RST_PIN, GPIO_OUT); 253 | //DMA init 254 | st_dma = dma_claim_unused_channel(true); 255 | dma_channel_config config = dma_channel_get_default_config(st_dma); 256 | channel_config_set_transfer_data_size(&config, DMA_SIZE_8); 257 | channel_config_set_bswap(&config, false); 258 | channel_config_set_dreq(&config, spi_get_dreq(SPI_DISP, true)); 259 | dma_channel_configure(st_dma, &config, &spi_get_hw(SPI_DISP)->dr, NULL, 0, false); 260 | gpio_put(RST_PIN, 0); 261 | sleep_ms(20); 262 | gpio_put(RST_PIN, 1); 263 | sleep_ms(10); 264 | command(SWRESET,0,NULL); 265 | sleep_ms(10); 266 | command(0xF0,1,"\xC3"); 267 | command(0xF0,1,"\x96"); 268 | command(MADCTL,1,"\x48"); 269 | command(COLMOD,1,"\x55"); //pixel format rgb565 270 | command(FRMCTR1,1,"\xA0"); 271 | command(INVCTR,1,"\x00"); 272 | command(ETMOD,1,"\xC6"); 273 | command(CECTRL1,2,"\x02\xE0"); 274 | command(PWCTR1,2,"\x80\x06"); 275 | command(PWCTR2,1,"\x15"); 276 | command(PWCTR3,1,"\xA7"); 277 | command(VMCTR1,1,"\x04"); 278 | command(0xE8,8,"\x40\x8A\x00\x00\x29\x19\xAA\x33"); 279 | command(PGAMCTRL,14,"\xF0\x06\x0F\x05\x04\x20\x37\x33\x4C\x37\x13\x14\x2B\x31"); 280 | command(NGAMCTRL,14,"\xF0\x11\x1B\x11\x0F\x0A\x37\x43\x4C\x37\x13\x13\x2C\x32"); 281 | 282 | command(0xF0,1,"\x3C"); 283 | command(0xF0,1,"\x69"); 284 | command(INVON,0,NULL); 285 | command(CASET,4,"\x00\x00\x01\x3F"); 286 | command(RASET,4,"\x00\x00\x01\x3F"); 287 | command(SLPOUT,0,NULL); 288 | sleep_ms(120); 289 | pColorUpdate(frameBuff,DISPLAY_HEIGHT*DISPLAY_WIDTH, LUT); 290 | command(DISPON,0,NULL); 291 | sleep_ms(120); 292 | command(RAMWR,0,NULL); 293 | 294 | //sleep_ms(100); 295 | //pColorUpdate(frameBuff,DISPLAY_HEIGHT*DISPLAY_WIDTH, LUT); 296 | //sleep_ms(10); 297 | if (autoUpdate==true){ 298 | multicore_reset_core1(); 299 | multicore_launch_core1_with_stack(core1_main, core1_stack, CORE1_STACK_SIZE); 300 | } 301 | //multicore_launch_core1_with_stack(core1_main, core1_stack, CORE1_STACK_SIZE); 302 | 303 | return mp_const_true; 304 | } 305 | static MP_DEFINE_CONST_FUN_OBJ_3(pd_init_obj, pd_init); 306 | 307 | 308 | 309 | 310 | 311 | 312 | static mp_obj_t drawTxt6x8(mp_uint_t n_args, const mp_obj_t *args){ 313 | // extract arguments 314 | 315 | const char *str = mp_obj_str_get_str(args[0]); 316 | int x0 = mp_obj_get_int(args[1]); 317 | int y0 = mp_obj_get_int(args[2]); 318 | uint16_t color = mp_obj_get_int(args[3]); 319 | int x; 320 | int y; 321 | 322 | // loop over chars 323 | for (; *str; ++str) { 324 | // get char and make sure its in range of font 325 | int chr = *(uint8_t *)str; 326 | if (chr < 16 ) { 327 | chr = 32; 328 | } 329 | // get char data 330 | const uint8_t *chr_data = ¤tTextTable[(chr - 16) * currentTextY]; 331 | // loop over char data 332 | y = y0; 333 | 334 | for (; y < y0+currentTextY; y++) { 335 | 336 | if (0 <= y && y < DISPLAY_HEIGHT) { 337 | x = x0; 338 | uint8_t line_data = *chr_data++; 339 | for (;x sizeof(LUT)) { 361 | bufLen = sizeof(LUT); 362 | } 363 | memcpy(LUT,buf_info.buf,bufLen* sizeof(uint16_t)); 364 | 365 | return mp_const_true; 366 | } 367 | static MP_DEFINE_CONST_FUN_OBJ_1(setLUT_obj, pd_setLUT); 368 | 369 | static mp_obj_t startAutoUpdate(void){ 370 | autoUpdate = true; 371 | multicore_reset_core1(); 372 | multicore_launch_core1_with_stack(core1_main, core1_stack, CORE1_STACK_SIZE); 373 | return mp_const_true; 374 | } 375 | static MP_DEFINE_CONST_FUN_OBJ_0(startAutoUpdate_obj, startAutoUpdate); 376 | 377 | 378 | static mp_obj_t stopAutoUpdate(void){ 379 | autoUpdate = false; 380 | multicore_reset_core1(); 381 | //wait until possible dma is done 382 | while (dma_channel_is_busy(st_dma)){ 383 | tight_loop_contents(); 384 | } 385 | return mp_const_true; 386 | } 387 | static MP_DEFINE_CONST_FUN_OBJ_0(stopAutoUpdate_obj, stopAutoUpdate); 388 | 389 | 390 | static void Write_dma(const uint8_t *src, size_t len) { 391 | while (dma_channel_is_busy(st_dma)); 392 | dma_channel_set_trans_count(st_dma, len, false); 393 | dma_channel_set_read_addr(st_dma, src, true); 394 | } 395 | 396 | 397 | static void command(uint8_t com, size_t len, const char *data) { 398 | 399 | gpio_put(CS_PIN, 0); 400 | gpio_put(DC_PIN, 0); // command mode 401 | spi_write_blocking(SPI_DISP,&com, 1); 402 | if(data) { 403 | gpio_put(DC_PIN, 1); // data mode 404 | spi_write_blocking(SPI_DISP,(const uint8_t*)data, len); 405 | } 406 | gpio_put(CS_PIN, 1); 407 | } 408 | 409 | 410 | 411 | 412 | static mp_obj_t pd_update(mp_obj_t core){ 413 | int coreNum = mp_obj_get_int(core); 414 | if (autoUpdate==false){//only work when autoUpdate is false 415 | if (coreNum == 0){ 416 | oneShotisDone=false; 417 | pColorUpdate(frameBuff,DISPLAY_HEIGHT*DISPLAY_WIDTH, LUT); 418 | oneShotisDone=true; 419 | }else{ 420 | //single shot core 1 update 421 | while(oneShotisDone==false); 422 | oneShotisDone=false; 423 | multicore_reset_core1(); 424 | multicore_launch_core1_with_stack(core1_singleShot, core1_stack, CORE1_STACK_SIZE); 425 | } 426 | } 427 | return mp_const_true; 428 | } 429 | static MP_DEFINE_CONST_FUN_OBJ_1(pd_update_obj, pd_update); 430 | 431 | static mp_obj_t pd_isScreenUpdateDone(void){ 432 | if (autoUpdate==false){ 433 | return mp_obj_new_bool(oneShotisDone); 434 | }else{ 435 | return mp_obj_new_bool(true); //always true when autoUpdate is true 436 | } 437 | } 438 | static MP_DEFINE_CONST_FUN_OBJ_0(pd_isScreenUpdateDone_obj, pd_isScreenUpdateDone); 439 | 440 | void RGB565Update(uint8_t *frameBuff,uint32_t length,const uint16_t *LUT) { 441 | //gpio_put(CS_PIN, 1); 442 | //gpio_put(CS_PIN, 0); 443 | while (dma_channel_is_busy(st_dma)); 444 | uint8_t cmd = RAMWR; 445 | gpio_put(CS_PIN, 0); 446 | gpio_put(DC_PIN, 0); // command mode 447 | 448 | spi_write_blocking(SPI_DISP,&cmd, 1); 449 | 450 | gpio_put(DC_PIN, 1); // data mode 451 | Write_dma((const uint8_t*)frameBuff, length*2); 452 | while (dma_channel_is_busy(st_dma)); 453 | while (spi_get_hw(SPI_DISP)->sr & SPI_SSPSR_BSY_BITS) { 454 | tight_loop_contents(); 455 | } 456 | gpio_put(CS_PIN, 1); 457 | } 458 | 459 | void LUT8Update(uint8_t *frameBuff, uint32_t length, const uint16_t *LUT){ 460 | while (dma_channel_is_busy(st_dma)); 461 | //uint16_t lineBuffA[64]; 462 | //uint16_t lineBuffB[64]; 463 | uint16_t *currentLineBuff=lineBuffA; 464 | uint16_t *updateLineBuff=lineBuffA; 465 | uint32_t leftPixels = length - (length&0xFFFFFFC0); 466 | uint32_t count = length>>6; 467 | uint8_t currentPixel=0; 468 | uint16_t color; 469 | uint8_t cmd = RAMWR; 470 | gpio_put(CS_PIN, 0); 471 | gpio_put(DC_PIN, 0); // command mode 472 | 473 | spi_write_blocking(SPI_DISP,&cmd, 1); 474 | gpio_put(DC_PIN, 1); // data mode 475 | while(count--){ 476 | if (count&0x00000001){ 477 | currentLineBuff = lineBuffA; 478 | updateLineBuff = lineBuffA; 479 | }else{ 480 | currentLineBuff = lineBuffB; 481 | updateLineBuff = lineBuffB; 482 | } 483 | for (int i=2;i>0;i--){ 484 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 485 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 486 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 487 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 488 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 489 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 490 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 491 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 492 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 493 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 494 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 495 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 496 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 497 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 498 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 499 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 500 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 501 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 502 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 503 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 504 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 505 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 506 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 507 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 508 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 509 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 510 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 511 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 512 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 513 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 514 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 515 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 516 | } 517 | while (dma_channel_is_busy(st_dma)); 518 | Write_dma((const uint8_t *)updateLineBuff,64*2); 519 | } 520 | if (leftPixels != 0){ 521 | if (updateLineBuff == lineBuffB){ 522 | currentLineBuff = lineBuffA; 523 | updateLineBuff = lineBuffA; 524 | }else{ 525 | currentLineBuff = lineBuffB; 526 | updateLineBuff = lineBuffB; 527 | } 528 | while(leftPixels--){ 529 | currentPixel = *frameBuff++;color = LUT[currentPixel];*currentLineBuff++ = color; 530 | } 531 | while (dma_channel_is_busy(st_dma)); 532 | Write_dma((const uint8_t *)lineBuffB,leftPixels*2); 533 | } 534 | while (dma_channel_is_busy(st_dma)); 535 | while (spi_get_hw(SPI_DISP)->sr & SPI_SSPSR_BSY_BITS) { 536 | tight_loop_contents(); 537 | } 538 | gpio_put(CS_PIN, 1); 539 | } 540 | 541 | 542 | void LUT4Update(uint8_t *frameBuff, uint32_t length, const uint16_t *LUT){ 543 | while (dma_channel_is_busy(st_dma)); 544 | //uint16_t lineBuffA[64]; 545 | //uint16_t lineBuffB[64]; 546 | uint16_t *currentLineBuff =lineBuffA; 547 | uint16_t *updateLineBuff =lineBuffA; 548 | uint32_t leftPixels = (length - (length&0xFFFFFFC0))>>1; 549 | uint32_t count = length>>6; 550 | uint8_t currentPixel=0; 551 | uint16_t color; 552 | uint8_t cmd = RAMWR; 553 | gpio_put(CS_PIN, 0); 554 | gpio_put(DC_PIN, 0); // command mode 555 | 556 | spi_write_blocking(SPI_DISP,&cmd, 1); 557 | gpio_put(DC_PIN, 1); // data mode 558 | while(count--){ 559 | if (count&0x00000001){ 560 | currentLineBuff = lineBuffA; 561 | updateLineBuff = lineBuffA; 562 | }else{ 563 | currentLineBuff = lineBuffB; 564 | updateLineBuff = lineBuffB; 565 | } 566 | for (int i=2;i>0;i--){ 567 | currentPixel = *frameBuff++;color = LUT[currentPixel>>4];*currentLineBuff++ = color; 568 | color = LUT[currentPixel&0x0F];*currentLineBuff++ = color; 569 | currentPixel = *frameBuff++;color = LUT[currentPixel>>4];*currentLineBuff++ = color; 570 | color = LUT[currentPixel&0x0F];*currentLineBuff++ = color; 571 | currentPixel = *frameBuff++;color = LUT[currentPixel>>4];*currentLineBuff++ = color; 572 | color = LUT[currentPixel&0x0F];*currentLineBuff++ = color; 573 | currentPixel = *frameBuff++;color = LUT[currentPixel>>4];*currentLineBuff++ = color; 574 | color = LUT[currentPixel&0x0F];*currentLineBuff++ = color; 575 | currentPixel = *frameBuff++;color = LUT[currentPixel>>4];*currentLineBuff++ = color; 576 | color = LUT[currentPixel&0x0F];*currentLineBuff++ = color; 577 | currentPixel = *frameBuff++;color = LUT[currentPixel>>4];*currentLineBuff++ = color; 578 | color = LUT[currentPixel&0x0F];*currentLineBuff++ = color; 579 | currentPixel = *frameBuff++;color = LUT[currentPixel>>4];*currentLineBuff++ = color; 580 | color = LUT[currentPixel&0x0F];*currentLineBuff++ = color; 581 | currentPixel = *frameBuff++;color = LUT[currentPixel>>4];*currentLineBuff++ = color; 582 | color = LUT[currentPixel&0x0F];*currentLineBuff++ = color; 583 | currentPixel = *frameBuff++;color = LUT[currentPixel>>4];*currentLineBuff++ = color; 584 | color = LUT[currentPixel&0x0F];*currentLineBuff++ = color; 585 | currentPixel = *frameBuff++;color = LUT[currentPixel>>4];*currentLineBuff++ = color; 586 | color = LUT[currentPixel&0x0F];*currentLineBuff++ = color; 587 | currentPixel = *frameBuff++;color = LUT[currentPixel>>4];*currentLineBuff++ = color; 588 | color = LUT[currentPixel&0x0F];*currentLineBuff++ = color; 589 | currentPixel = *frameBuff++;color = LUT[currentPixel>>4];*currentLineBuff++ = color; 590 | color = LUT[currentPixel&0x0F];*currentLineBuff++ = color; 591 | currentPixel = *frameBuff++;color = LUT[currentPixel>>4];*currentLineBuff++ = color; 592 | color = LUT[currentPixel&0x0F];*currentLineBuff++ = color; 593 | currentPixel = *frameBuff++;color = LUT[currentPixel>>4];*currentLineBuff++ = color; 594 | color = LUT[currentPixel&0x0F];*currentLineBuff++ = color; 595 | currentPixel = *frameBuff++;color = LUT[currentPixel>>4];*currentLineBuff++ = color; 596 | color = LUT[currentPixel&0x0F];*currentLineBuff++ = color; 597 | currentPixel = *frameBuff++;color = LUT[currentPixel>>4];*currentLineBuff++ = color; 598 | color = LUT[currentPixel&0x0F];*currentLineBuff++ = color; 599 | } 600 | while (dma_channel_is_busy(st_dma)); 601 | Write_dma((const uint8_t *)updateLineBuff,64*2); 602 | } 603 | if (leftPixels != 0){ 604 | if (updateLineBuff == lineBuffB){ 605 | currentLineBuff = lineBuffA; 606 | updateLineBuff = lineBuffA; 607 | }else{ 608 | currentLineBuff = lineBuffB; 609 | updateLineBuff = lineBuffB; 610 | } 611 | 612 | while(leftPixels--){ 613 | currentPixel = *frameBuff++;color = LUT[currentPixel>>4];*currentLineBuff++ = color; 614 | color = LUT[currentPixel&0x0F];*currentLineBuff++ = color; 615 | } 616 | while (dma_channel_is_busy(st_dma)); 617 | Write_dma((const uint8_t *)lineBuffB,leftPixels*4); 618 | } 619 | while (dma_channel_is_busy(st_dma)); 620 | while (spi_get_hw(SPI_DISP)->sr & SPI_SSPSR_BSY_BITS) { 621 | tight_loop_contents(); 622 | } 623 | gpio_put(CS_PIN, 1); 624 | } 625 | 626 | void LUT2Update(uint8_t *frameBuff, uint32_t length, const uint16_t *LUT){ 627 | while (dma_channel_is_busy(st_dma)); 628 | //uint16_t lineBuffA[64]; 629 | //uint16_t lineBuffB[64]; 630 | uint16_t *currentLineBuff=lineBuffA; 631 | uint16_t *updateLineBuff=lineBuffA; 632 | uint32_t leftPixels = (length - (length&0xFFFFFFC0))>>2; 633 | uint32_t count = length>>6; 634 | uint8_t currentPixel=0; 635 | uint16_t color; 636 | uint8_t cmd = RAMWR; 637 | gpio_put(CS_PIN, 0); 638 | gpio_put(DC_PIN, 0); // command mode 639 | 640 | spi_write_blocking(SPI_DISP,&cmd, 1); 641 | gpio_put(DC_PIN, 1); // data mode 642 | while(count--){ 643 | if (count&0x00000001){ 644 | currentLineBuff = lineBuffA; 645 | updateLineBuff = lineBuffA; 646 | }else{ 647 | currentLineBuff = lineBuffB; 648 | updateLineBuff = lineBuffB; 649 | } 650 | for (int i=2;i>0;i--){ 651 | currentPixel = *frameBuff++;color = LUT[currentPixel&0x03];*currentLineBuff++ = color; 652 | color = LUT[(currentPixel>>2)&0x03];*currentLineBuff++ = color; 653 | color = LUT[(currentPixel>>4)&0x03];*currentLineBuff++ = color; 654 | color = LUT[(currentPixel>>6)];*currentLineBuff++ = color; 655 | currentPixel = *frameBuff++;color = LUT[currentPixel&0x03];*currentLineBuff++ = color; 656 | color = LUT[(currentPixel>>2)&0x03];*currentLineBuff++ = color; 657 | color = LUT[(currentPixel>>4)&0x03];*currentLineBuff++ = color; 658 | color = LUT[(currentPixel>>6)];*currentLineBuff++ = color; 659 | currentPixel = *frameBuff++;color = LUT[currentPixel&0x03];*currentLineBuff++ = color; 660 | color = LUT[(currentPixel>>2)&0x03];*currentLineBuff++ = color; 661 | color = LUT[(currentPixel>>4)&0x03];*currentLineBuff++ = color; 662 | color = LUT[(currentPixel>>6)];*currentLineBuff++ = color; 663 | currentPixel = *frameBuff++;color = LUT[currentPixel&0x03];*currentLineBuff++ = color; 664 | color = LUT[(currentPixel>>2)&0x03];*currentLineBuff++ = color; 665 | color = LUT[(currentPixel>>4)&0x03];*currentLineBuff++ = color; 666 | color = LUT[(currentPixel>>6)];*currentLineBuff++ = color; 667 | currentPixel = *frameBuff++;color = LUT[currentPixel&0x03];*currentLineBuff++ = color; 668 | color = LUT[(currentPixel>>2)&0x03];*currentLineBuff++ = color; 669 | color = LUT[(currentPixel>>4)&0x03];*currentLineBuff++ = color; 670 | color = LUT[(currentPixel>>6)];*currentLineBuff++ = color; 671 | currentPixel = *frameBuff++;color = LUT[currentPixel&0x03];*currentLineBuff++ = color; 672 | color = LUT[(currentPixel>>2)&0x03];*currentLineBuff++ = color; 673 | color = LUT[(currentPixel>>4)&0x03];*currentLineBuff++ = color; 674 | color = LUT[(currentPixel>>6)];*currentLineBuff++ = color; 675 | currentPixel = *frameBuff++;color = LUT[currentPixel&0x03];*currentLineBuff++ = color; 676 | color = LUT[(currentPixel>>2)&0x03];*currentLineBuff++ = color; 677 | color = LUT[(currentPixel>>4)&0x03];*currentLineBuff++ = color; 678 | color = LUT[(currentPixel>>6)];*currentLineBuff++ = color; 679 | currentPixel = *frameBuff++;color = LUT[currentPixel&0x03];*currentLineBuff++ = color; 680 | color = LUT[(currentPixel>>2)&0x03];*currentLineBuff++ = color; 681 | color = LUT[(currentPixel>>4)&0x03];*currentLineBuff++ = color; 682 | color = LUT[(currentPixel>>6)];*currentLineBuff++ = color; 683 | } 684 | while (dma_channel_is_busy(st_dma)); 685 | Write_dma((const uint8_t *)updateLineBuff,64*2); 686 | } 687 | if (leftPixels != 0){ 688 | if (updateLineBuff == lineBuffB){ 689 | currentLineBuff = lineBuffA; 690 | updateLineBuff = lineBuffA; 691 | }else{ 692 | currentLineBuff = lineBuffB; 693 | updateLineBuff = lineBuffB; 694 | } 695 | 696 | while(leftPixels--){ 697 | currentPixel = *frameBuff++;color = LUT[currentPixel&0x03];*currentLineBuff++ = color; 698 | color = LUT[(currentPixel>>2)&0x03];*currentLineBuff++ = color; 699 | color = LUT[(currentPixel>>4)&0x03];*currentLineBuff++ = color; 700 | color = LUT[(currentPixel>>6)];*currentLineBuff++ = color; 701 | } 702 | while (dma_channel_is_busy(st_dma)); 703 | Write_dma((const uint8_t *)lineBuffB,leftPixels*8); 704 | } 705 | while (dma_channel_is_busy(st_dma)); 706 | while (spi_get_hw(SPI_DISP)->sr & SPI_SSPSR_BSY_BITS) { 707 | tight_loop_contents(); 708 | } 709 | gpio_put(CS_PIN, 1); 710 | } 711 | 712 | void LUT1Update(uint8_t *frameBuff, uint32_t length, const uint16_t *LUT){ 713 | while (dma_channel_is_busy(st_dma)); 714 | //uint16_t lineBuffA[64]; 715 | //uint16_t lineBuffB[64]; 716 | uint16_t *currentLineBuff=lineBuffA; 717 | uint16_t *updateLineBuff=lineBuffA; 718 | uint32_t leftPixels = (length - (length&0xFFFFFFC0))>>3; 719 | uint32_t count = length>>6; 720 | uint8_t currentPixel=0; 721 | uint16_t color; 722 | uint8_t cmd = RAMWR; 723 | gpio_put(CS_PIN, 0); 724 | gpio_put(DC_PIN, 0); // command mode 725 | 726 | spi_write_blocking(SPI_DISP,&cmd, 1); 727 | gpio_put(DC_PIN, 1); // data mode 728 | while(count--){ 729 | if (count&0x00000001){ 730 | currentLineBuff = lineBuffA; 731 | updateLineBuff = lineBuffA; 732 | }else{ 733 | currentLineBuff = lineBuffB; 734 | updateLineBuff = lineBuffB; 735 | } 736 | for (int i=2;i>0;i--){ 737 | currentPixel = *frameBuff++;color = LUT[currentPixel&0x01];*currentLineBuff++ = color; 738 | color = LUT[(currentPixel>>0x01)&0x01];*currentLineBuff++ = color; 739 | color = LUT[(currentPixel>>0x02)&0x01];*currentLineBuff++ = color; 740 | color = LUT[(currentPixel>>0x03)&0x01];*currentLineBuff++ = color; 741 | color = LUT[(currentPixel>>0x04)&0x01];*currentLineBuff++ = color; 742 | color = LUT[(currentPixel>>0x05)&0x01];*currentLineBuff++ = color; 743 | color = LUT[(currentPixel>>0x06)&0x01];*currentLineBuff++ = color; 744 | color = LUT[(currentPixel>>0x07)&0x01];*currentLineBuff++ = color; 745 | currentPixel = *frameBuff++;color = LUT[currentPixel&0x01];*currentLineBuff++ = color; 746 | color = LUT[(currentPixel>>0x01)&0x01];*currentLineBuff++ = color; 747 | color = LUT[(currentPixel>>0x02)&0x01];*currentLineBuff++ = color; 748 | color = LUT[(currentPixel>>0x03)&0x01];*currentLineBuff++ = color; 749 | color = LUT[(currentPixel>>0x04)&0x01];*currentLineBuff++ = color; 750 | color = LUT[(currentPixel>>0x05)&0x01];*currentLineBuff++ = color; 751 | color = LUT[(currentPixel>>0x06)&0x01];*currentLineBuff++ = color; 752 | color = LUT[(currentPixel>>0x07)&0x01];*currentLineBuff++ = color; 753 | currentPixel = *frameBuff++;color = LUT[currentPixel&0x01];*currentLineBuff++ = color; 754 | color = LUT[(currentPixel>>0x01)&0x01];*currentLineBuff++ = color; 755 | color = LUT[(currentPixel>>0x02)&0x01];*currentLineBuff++ = color; 756 | color = LUT[(currentPixel>>0x03)&0x01];*currentLineBuff++ = color; 757 | color = LUT[(currentPixel>>0x04)&0x01];*currentLineBuff++ = color; 758 | color = LUT[(currentPixel>>0x05)&0x01];*currentLineBuff++ = color; 759 | color = LUT[(currentPixel>>0x06)&0x01];*currentLineBuff++ = color; 760 | color = LUT[(currentPixel>>0x07)&0x01];*currentLineBuff++ = color; 761 | currentPixel = *frameBuff++;color = LUT[currentPixel&0x01];*currentLineBuff++ = color; 762 | color = LUT[(currentPixel>>0x01)&0x01];*currentLineBuff++ = color; 763 | color = LUT[(currentPixel>>0x02)&0x01];*currentLineBuff++ = color; 764 | color = LUT[(currentPixel>>0x03)&0x01];*currentLineBuff++ = color; 765 | color = LUT[(currentPixel>>0x04)&0x01];*currentLineBuff++ = color; 766 | color = LUT[(currentPixel>>0x05)&0x01];*currentLineBuff++ = color; 767 | color = LUT[(currentPixel>>0x06)&0x01];*currentLineBuff++ = color; 768 | color = LUT[(currentPixel>>0x07)&0x01];*currentLineBuff++ = color; 769 | } 770 | while (dma_channel_is_busy(st_dma)); 771 | Write_dma((const uint8_t *)updateLineBuff,64*2); 772 | } 773 | if (leftPixels != 0){ 774 | if (updateLineBuff == lineBuffB){ 775 | currentLineBuff = lineBuffA; 776 | updateLineBuff = lineBuffA; 777 | }else{ 778 | currentLineBuff = lineBuffB; 779 | updateLineBuff = lineBuffB; 780 | } 781 | 782 | while(leftPixels--){ 783 | currentPixel = *frameBuff++;color = LUT[currentPixel&0x01];*currentLineBuff++ = color; 784 | color = LUT[(currentPixel>>0x01)&0x01];*currentLineBuff++ = color; 785 | color = LUT[(currentPixel>>0x02)&0x01];*currentLineBuff++ = color; 786 | color = LUT[(currentPixel>>0x03)&0x01];*currentLineBuff++ = color; 787 | color = LUT[(currentPixel>>0x04)&0x01];*currentLineBuff++ = color; 788 | color = LUT[(currentPixel>>0x05)&0x01];*currentLineBuff++ = color; 789 | color = LUT[(currentPixel>>0x06)&0x01];*currentLineBuff++ = color; 790 | color = LUT[(currentPixel>>0x07)&0x01];*currentLineBuff++ = color; 791 | } 792 | while (dma_channel_is_busy(st_dma)); 793 | Write_dma((const uint8_t *)lineBuffB,leftPixels*16); 794 | } 795 | while (dma_channel_is_busy(st_dma)); 796 | while (spi_get_hw(SPI_DISP)->sr & SPI_SSPSR_BSY_BITS) { 797 | tight_loop_contents(); 798 | } 799 | gpio_put(CS_PIN, 1); 800 | } 801 | 802 | 803 | 804 | 805 | 806 | 807 | // Define all attributes of the module. 808 | // Table entries are key/value pairs of the attribute name (a string) 809 | // and the MicroPython object reference. 810 | // All identifiers and strings are written as MP_QSTR_xxx and will be 811 | // optimized to word-sized integers by the build system (interned strings). 812 | static const mp_rom_map_elem_t picocalcdisplay_globals_table[] = { 813 | { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_picocalcdisplay) }, 814 | { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pd_init_obj) }, 815 | { MP_ROM_QSTR(MP_QSTR_setLUT), MP_ROM_PTR(&setLUT_obj) }, 816 | { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&pd_update_obj) }, 817 | { MP_ROM_QSTR(MP_QSTR_startAutoUpdate), MP_ROM_PTR(&startAutoUpdate_obj) }, 818 | { MP_ROM_QSTR(MP_QSTR_stopAutoUpdate), MP_ROM_PTR(&stopAutoUpdate_obj) }, 819 | { MP_ROM_QSTR(MP_QSTR_drawTxt6x8), MP_ROM_PTR(&drawTxt6x8_obj) }, 820 | { MP_ROM_QSTR(MP_QSTR_resetLUT), MP_ROM_PTR(&pd_resetLUT_obj) }, 821 | { MP_ROM_QSTR(MP_QSTR_getLUTview), MP_ROM_PTR(&pd_getLUTview_obj) }, 822 | { MP_ROM_QSTR(MP_QSTR_isScreenUpdateDone), MP_ROM_PTR(&pd_isScreenUpdateDone_obj) }, 823 | 824 | }; 825 | static MP_DEFINE_CONST_DICT(picocalcdisplay_globals, picocalcdisplay_globals_table); 826 | 827 | // Define module object. 828 | const mp_obj_module_t picocalcdisplay_module = { 829 | .base = { &mp_type_module }, 830 | .globals = (mp_obj_dict_t *)&picocalcdisplay_globals, 831 | }; 832 | 833 | // Register the module to make it available in Python. 834 | MP_REGISTER_MODULE(MP_QSTR_picocalcdisplay, picocalcdisplay_module); 835 | -------------------------------------------------------------------------------- /picocalcdisplay/font6x8e500.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef FONT6X8TT_H 4 | #define FONT6X8TT_H 5 | 6 | 7 | //CP437 - IBM/MS-DOS Codepage 8 | //https://en.wikipedia.org/wiki/Code_page_437 9 | const uint8_t CP437_display[] = { 10 | // 0x10 ( ) 11 | 0b00000000, 12 | 0b11000000, 13 | 0b11110000, 14 | 0b11111100, 15 | 0b11111100, 16 | 0b11110000, 17 | 0b11000000, 18 | 0b00000000, 19 | // 0x11 ( ) 20 | 0b00000000, 21 | 0b00001100, 22 | 0b00111100, 23 | 0b11111100, 24 | 0b11111100, 25 | 0b00111100, 26 | 0b00001100, 27 | 0b00000000, 28 | // 0x12 ( ) 29 | 0b00100000, 30 | 0b01110000, 31 | 0b10101000, 32 | 0b00100000, 33 | 0b10101000, 34 | 0b01110000, 35 | 0b00100000, 36 | 0b00000000, 37 | // 0x13 ( ) 38 | 0b01010000, 39 | 0b01010000, 40 | 0b01010000, 41 | 0b01010000, 42 | 0b01010000, 43 | 0b00000000, 44 | 0b01010000, 45 | 0b00000000, 46 | // 0x14 ( ) 47 | 0b01111000, 48 | 0b11101000, 49 | 0b11101000, 50 | 0b01101000, 51 | 0b00101000, 52 | 0b00101000, 53 | 0b00101000, 54 | 0b00000000, 55 | // 0x15 ( ) 56 | 0b01110000, 57 | 0b10001000, 58 | 0b01100000, 59 | 0b01010000, 60 | 0b00111000, 61 | 0b10001000, 62 | 0b01110000, 63 | 0b00000000, 64 | // 0x16 ( ) 65 | 0b00000000, 66 | 0b00000000, 67 | 0b00000000, 68 | 0b00000000, 69 | 0b00000000, 70 | 0b00000000, 71 | 0b11111100, 72 | 0b11111100, 73 | // 0x17 ( ) 74 | 0b00100000, 75 | 0b01110000, 76 | 0b10101000, 77 | 0b00100000, 78 | 0b10101000, 79 | 0b01110000, 80 | 0b00100000, 81 | 0b11111000, 82 | // 0x18 ( ) 83 | 0b00100000, 84 | 0b01110000, 85 | 0b10101000, 86 | 0b00100000, 87 | 0b00100000, 88 | 0b00100000, 89 | 0b00100000, 90 | 0b00000000, 91 | // 0x19 ( ) 92 | 0b00100000, 93 | 0b00100000, 94 | 0b00100000, 95 | 0b00100000, 96 | 0b10101000, 97 | 0b01110000, 98 | 0b00100000, 99 | 0b00000000, 100 | // 0x1A ( ) 101 | 0b00000000, 102 | 0b00100000, 103 | 0b00010000, 104 | 0b11111000, 105 | 0b00010000, 106 | 0b00100000, 107 | 0b00000000, 108 | 0b00000000, 109 | // 0x1B ( ) 110 | 0b00000000, 111 | 0b00100000, 112 | 0b01000000, 113 | 0b11111000, 114 | 0b01000000, 115 | 0b00100000, 116 | 0b00000000, 117 | 0b00000000, 118 | // 0x1C ( ) 119 | 0b00000000, 120 | 0b00000000, 121 | 0b10000000, 122 | 0b10000000, 123 | 0b10000000, 124 | 0b10000000, 125 | 0b11111000, 126 | 0b00000000, 127 | // 0x1D ( ) 128 | 0b00000000, 129 | 0b00000000, 130 | 0b01010000, 131 | 0b11111000, 132 | 0b01010000, 133 | 0b00000000, 134 | 0b00000000, 135 | 0b00000000, 136 | // 0x1E ( ) 137 | 0b00000000, 138 | 0b00000000, 139 | 0b00100000, 140 | 0b01110000, 141 | 0b11111000, 142 | 0b00000000, 143 | 0b00000000, 144 | 0b00000000, 145 | // 0x1F ( ) 146 | 0b00000000, 147 | 0b00000000, 148 | 0b11111000, 149 | 0b01110000, 150 | 0b00100000, 151 | 0b00000000, 152 | 0b00000000, 153 | 0b00000000, 154 | // 0x20 ( ) 155 | 0b00000000, 156 | 0b00000000, 157 | 0b00000000, 158 | 0b00000000, 159 | 0b00000000, 160 | 0b00000000, 161 | 0b00000000, 162 | 0b00000000, 163 | // 0x21 ( ! ) 164 | 0b00100000, 165 | 0b00100000, 166 | 0b00100000, 167 | 0b00100000, 168 | 0b00100000, 169 | 0b00000000, 170 | 0b00100000, 171 | 0b00000000, 172 | // 0x22 ( " ) 173 | 0b01001000, 174 | 0b01001000, 175 | 0b10010000, 176 | 0b00000000, 177 | 0b00000000, 178 | 0b00000000, 179 | 0b00000000, 180 | 0b00000000, 181 | // 0x23 ( # ) 182 | 0b01010000, 183 | 0b11111000, 184 | 0b01010000, 185 | 0b01010000, 186 | 0b01010000, 187 | 0b11111000, 188 | 0b01010000, 189 | 0b00000000, 190 | // 0x24 ( $ ) 191 | 0b00100000, 192 | 0b01111000, 193 | 0b10100000, 194 | 0b01110000, 195 | 0b00101000, 196 | 0b11110000, 197 | 0b00100000, 198 | 0b00000000, 199 | // 0x25 ( % ) 200 | 0b11000000, 201 | 0b11001000, 202 | 0b00010000, 203 | 0b00100000, 204 | 0b01000000, 205 | 0b10011000, 206 | 0b00011000, 207 | 0b00000000, 208 | // 0x26 ( & ) 209 | 0b01100000, 210 | 0b10010000, 211 | 0b10100000, 212 | 0b01000000, 213 | 0b10101000, 214 | 0b10010000, 215 | 0b01101000, 216 | 0b00000000, 217 | // 0x27 ( ' ) 218 | 0b01100000, 219 | 0b01100000, 220 | 0b00100000, 221 | 0b01000000, 222 | 0b00000000, 223 | 0b00000000, 224 | 0b00000000, 225 | 0b00000000, 226 | // 0x28 ( ( ) 227 | 0b00010000, 228 | 0b00100000, 229 | 0b01000000, 230 | 0b01000000, 231 | 0b01000000, 232 | 0b00100000, 233 | 0b00010000, 234 | 0b00000000, 235 | // 0x29 ( ) ) 236 | 0b01000000, 237 | 0b00100000, 238 | 0b00010000, 239 | 0b00010000, 240 | 0b00010000, 241 | 0b00100000, 242 | 0b01000000, 243 | 0b00000000, 244 | // 0x2A ( * ) 245 | 0b00000000, 246 | 0b00100000, 247 | 0b10101000, 248 | 0b01110000, 249 | 0b10101000, 250 | 0b00100000, 251 | 0b00000000, 252 | 0b00000000, 253 | // 0x2B ( + ) 254 | 0b00000000, 255 | 0b00100000, 256 | 0b00100000, 257 | 0b11111000, 258 | 0b00100000, 259 | 0b00100000, 260 | 0b00000000, 261 | 0b00000000, 262 | // 0x2C ( , ) 263 | 0b00000000, 264 | 0b00000000, 265 | 0b00000000, 266 | 0b01100000, 267 | 0b01100000, 268 | 0b00100000, 269 | 0b01000000, 270 | 0b00000000, 271 | // 0x2D ( - ) 272 | 0b00000000, 273 | 0b00000000, 274 | 0b00000000, 275 | 0b11111000, 276 | 0b00000000, 277 | 0b00000000, 278 | 0b00000000, 279 | 0b00000000, 280 | // 0x2E ( . ) 281 | 0b00000000, 282 | 0b00000000, 283 | 0b00000000, 284 | 0b00000000, 285 | 0b00000000, 286 | 0b01100000, 287 | 0b01100000, 288 | 0b00000000, 289 | // 0x2F ( / ) 290 | 0b00001000, 291 | 0b00001000, 292 | 0b00010000, 293 | 0b00100000, 294 | 0b01000000, 295 | 0b10000000, 296 | 0b10000000, 297 | 0b00000000, 298 | // 0x30 ( 0 ) 299 | 0b01110000, 300 | 0b10001000, 301 | 0b10011000, 302 | 0b10101000, 303 | 0b11001000, 304 | 0b10001000, 305 | 0b01110000, 306 | 0b00000000, 307 | // 0x31 ( 1 ) 308 | 0b00100000, 309 | 0b01100000, 310 | 0b00100000, 311 | 0b00100000, 312 | 0b00100000, 313 | 0b00100000, 314 | 0b01110000, 315 | 0b00000000, 316 | // 0x32 ( 2 ) 317 | 0b01110000, 318 | 0b10001000, 319 | 0b00001000, 320 | 0b00010000, 321 | 0b00100000, 322 | 0b01000000, 323 | 0b11111000, 324 | 0b00000000, 325 | // 0x33 ( 3 ) 326 | 0b11111000, 327 | 0b00010000, 328 | 0b00100000, 329 | 0b01110000, 330 | 0b00001000, 331 | 0b00001000, 332 | 0b11110000, 333 | 0b00000000, 334 | // 0x34 ( 4 ) 335 | 0b00010000, 336 | 0b00110000, 337 | 0b01010000, 338 | 0b10010000, 339 | 0b11111000, 340 | 0b00010000, 341 | 0b00010000, 342 | 0b00000000, 343 | // 0x35 ( 5 ) 344 | 0b11111000, 345 | 0b10000000, 346 | 0b10000000, 347 | 0b11110000, 348 | 0b00001000, 349 | 0b10001000, 350 | 0b01110000, 351 | 0b00000000, 352 | // 0x36 ( 6 ) 353 | 0b00110000, 354 | 0b01000000, 355 | 0b10000000, 356 | 0b11110000, 357 | 0b10001000, 358 | 0b10001000, 359 | 0b01110000, 360 | 0b00000000, 361 | // 0x37 ( 7 ) 362 | 0b11111000, 363 | 0b00001000, 364 | 0b00010000, 365 | 0b00100000, 366 | 0b00100000, 367 | 0b00100000, 368 | 0b00100000, 369 | 0b00000000, 370 | // 0x38 ( 8 ) 371 | 0b01110000, 372 | 0b10001000, 373 | 0b10001000, 374 | 0b01110000, 375 | 0b10001000, 376 | 0b10001000, 377 | 0b01110000, 378 | 0b00000000, 379 | // 0x39 ( 9 ) 380 | 0b01110000, 381 | 0b10001000, 382 | 0b10001000, 383 | 0b01111000, 384 | 0b00001000, 385 | 0b00010000, 386 | 0b01100000, 387 | 0b00000000, 388 | // 0x3A ( : ) 389 | 0b00000000, 390 | 0b01100000, 391 | 0b01100000, 392 | 0b00000000, 393 | 0b01100000, 394 | 0b01100000, 395 | 0b00000000, 396 | 0b00000000, 397 | // 0x3B ( ; ) 398 | 0b01100000, 399 | 0b01100000, 400 | 0b00000000, 401 | 0b01100000, 402 | 0b01100000, 403 | 0b00100000, 404 | 0b01000000, 405 | 0b00000000, 406 | // 0x3C ( < ) 407 | 0b00010000, 408 | 0b00100000, 409 | 0b01000000, 410 | 0b10000000, 411 | 0b01000000, 412 | 0b00100000, 413 | 0b00010000, 414 | 0b00000000, 415 | // 0x3D ( = ) 416 | 0b00000000, 417 | 0b00000000, 418 | 0b11111000, 419 | 0b00000000, 420 | 0b11111000, 421 | 0b00000000, 422 | 0b00000000, 423 | 0b00000000, 424 | // 0x3E ( > ) 425 | 0b01000000, 426 | 0b00100000, 427 | 0b00010000, 428 | 0b00001000, 429 | 0b00010000, 430 | 0b00100000, 431 | 0b01000000, 432 | 0b00000000, 433 | // 0x3F ( ? ) 434 | 0b01110000, 435 | 0b10001000, 436 | 0b00001000, 437 | 0b00010000, 438 | 0b00100000, 439 | 0b00000000, 440 | 0b00100000, 441 | 0b00000000, 442 | // 0x40 ( @ ) 443 | 0b01110000, 444 | 0b10001000, 445 | 0b00001000, 446 | 0b01101000, 447 | 0b10101000, 448 | 0b10101000, 449 | 0b01110000, 450 | 0b00000000, 451 | // 0x41 ( A ) 452 | 0b00100000, 453 | 0b01010000, 454 | 0b10001000, 455 | 0b10001000, 456 | 0b11111000, 457 | 0b10001000, 458 | 0b10001000, 459 | 0b00000000, 460 | // 0x42 ( B ) 461 | 0b11110000, 462 | 0b01001000, 463 | 0b01001000, 464 | 0b01110000, 465 | 0b01001000, 466 | 0b01001000, 467 | 0b11110000, 468 | 0b00000000, 469 | // 0x43 ( C ) 470 | 0b01110000, 471 | 0b10001000, 472 | 0b10000000, 473 | 0b10000000, 474 | 0b10000000, 475 | 0b10001000, 476 | 0b01110000, 477 | 0b00000000, 478 | // 0x44 ( D ) 479 | 0b11110000, 480 | 0b01001000, 481 | 0b01001000, 482 | 0b01001000, 483 | 0b01001000, 484 | 0b01001000, 485 | 0b11110000, 486 | 0b00000000, 487 | // 0x45 ( E ) 488 | 0b11111000, 489 | 0b10000000, 490 | 0b10000000, 491 | 0b11110000, 492 | 0b10000000, 493 | 0b10000000, 494 | 0b11111000, 495 | 0b00000000, 496 | // 0x46 ( F ) 497 | 0b11111000, 498 | 0b10000000, 499 | 0b10000000, 500 | 0b11110000, 501 | 0b10000000, 502 | 0b10000000, 503 | 0b10000000, 504 | 0b00000000, 505 | // 0x47 ( G ) 506 | 0b01111000, 507 | 0b10000000, 508 | 0b10000000, 509 | 0b10011000, 510 | 0b10001000, 511 | 0b10001000, 512 | 0b01110000, 513 | 0b00000000, 514 | // 0x48 ( H ) 515 | 0b10001000, 516 | 0b10001000, 517 | 0b10001000, 518 | 0b11111000, 519 | 0b10001000, 520 | 0b10001000, 521 | 0b10001000, 522 | 0b00000000, 523 | // 0x49 ( I ) 524 | 0b01110000, 525 | 0b00100000, 526 | 0b00100000, 527 | 0b00100000, 528 | 0b00100000, 529 | 0b00100000, 530 | 0b01110000, 531 | 0b00000000, 532 | // 0x4A ( J ) 533 | 0b00111000, 534 | 0b00010000, 535 | 0b00010000, 536 | 0b00010000, 537 | 0b00010000, 538 | 0b10010000, 539 | 0b01100000, 540 | 0b00000000, 541 | // 0x4B ( K ) 542 | 0b10001000, 543 | 0b10010000, 544 | 0b10100000, 545 | 0b11000000, 546 | 0b10100000, 547 | 0b10010000, 548 | 0b10001000, 549 | 0b00000000, 550 | // 0x4C ( L ) 551 | 0b10000000, 552 | 0b10000000, 553 | 0b10000000, 554 | 0b10000000, 555 | 0b10000000, 556 | 0b10000000, 557 | 0b11111000, 558 | 0b00000000, 559 | // 0x4D ( M ) 560 | 0b10001000, 561 | 0b11011000, 562 | 0b10101000, 563 | 0b10001000, 564 | 0b10001000, 565 | 0b10001000, 566 | 0b10001000, 567 | 0b00000000, 568 | // 0x4E ( N ) 569 | 0b10001000, 570 | 0b10001000, 571 | 0b11001000, 572 | 0b10101000, 573 | 0b10011000, 574 | 0b10001000, 575 | 0b10001000, 576 | 0b00000000, 577 | // 0x4F ( O ) 578 | 0b01110000, 579 | 0b10001000, 580 | 0b10001000, 581 | 0b10001000, 582 | 0b10001000, 583 | 0b10001000, 584 | 0b01110000, 585 | 0b00000000, 586 | // 0x50 ( P ) 587 | 0b11110000, 588 | 0b10001000, 589 | 0b10001000, 590 | 0b11110000, 591 | 0b10000000, 592 | 0b10000000, 593 | 0b10000000, 594 | 0b00000000, 595 | // 0x51 ( Q ) 596 | 0b01110000, 597 | 0b10001000, 598 | 0b10001000, 599 | 0b10001000, 600 | 0b10101000, 601 | 0b10010000, 602 | 0b01101000, 603 | 0b00000000, 604 | // 0x52 ( R ) 605 | 0b11110000, 606 | 0b10001000, 607 | 0b10001000, 608 | 0b11110000, 609 | 0b10001000, 610 | 0b10001000, 611 | 0b10001000, 612 | 0b00000000, 613 | // 0x53 ( S ) 614 | 0b01111000, 615 | 0b10000000, 616 | 0b10000000, 617 | 0b01110000, 618 | 0b00001000, 619 | 0b10001000, 620 | 0b01110000, 621 | 0b00000000, 622 | // 0x54 ( T ) 623 | 0b11111000, 624 | 0b00100000, 625 | 0b00100000, 626 | 0b00100000, 627 | 0b00100000, 628 | 0b00100000, 629 | 0b00100000, 630 | 0b00000000, 631 | // 0x55 ( U ) 632 | 0b10001000, 633 | 0b10001000, 634 | 0b10001000, 635 | 0b10001000, 636 | 0b10001000, 637 | 0b10001000, 638 | 0b01110000, 639 | 0b00000000, 640 | // 0x56 ( V ) 641 | 0b10001000, 642 | 0b10001000, 643 | 0b10001000, 644 | 0b10001000, 645 | 0b01010000, 646 | 0b01010000, 647 | 0b00100000, 648 | 0b00000000, 649 | // 0x57 ( W ) 650 | 0b10001000, 651 | 0b10001000, 652 | 0b10001000, 653 | 0b10101000, 654 | 0b10101000, 655 | 0b11011000, 656 | 0b10001000, 657 | 0b00000000, 658 | // 0x58 ( X ) 659 | 0b10001000, 660 | 0b10001000, 661 | 0b01010000, 662 | 0b00100000, 663 | 0b01010000, 664 | 0b10001000, 665 | 0b10001000, 666 | 0b00000000, 667 | // 0x59 ( Y ) 668 | 0b10001000, 669 | 0b10001000, 670 | 0b01010000, 671 | 0b00100000, 672 | 0b00100000, 673 | 0b00100000, 674 | 0b00100000, 675 | 0b00000000, 676 | // 0x5A ( Z ) 677 | 0b11111000, 678 | 0b00001000, 679 | 0b00010000, 680 | 0b00100000, 681 | 0b01000000, 682 | 0b10000000, 683 | 0b11111000, 684 | 0b00000000, 685 | // 0x5B ( [ ) 686 | 0b01110000, 687 | 0b01000000, 688 | 0b01000000, 689 | 0b01000000, 690 | 0b01000000, 691 | 0b01000000, 692 | 0b01110000, 693 | 0b00000000, 694 | // 0x5C ( \ ) 695 | 0b10000000, 696 | 0b10000000, 697 | 0b01000000, 698 | 0b00100000, 699 | 0b00010000, 700 | 0b00001000, 701 | 0b00001000, 702 | 0b00000000, 703 | // 0x5D ( ] ) 704 | 0b01110000, 705 | 0b00010000, 706 | 0b00010000, 707 | 0b00010000, 708 | 0b00010000, 709 | 0b00010000, 710 | 0b01110000, 711 | 0b00000000, 712 | // 0x5E ( ^ ) 713 | 0b00000000, 714 | 0b00100000, 715 | 0b01010000, 716 | 0b10001000, 717 | 0b10001000, 718 | 0b00000000, 719 | 0b00000000, 720 | 0b00000000, 721 | // 0x5F ( _ ) 722 | 0b00000000, 723 | 0b00000000, 724 | 0b00000000, 725 | 0b00000000, 726 | 0b00000000, 727 | 0b00000000, 728 | 0b11111000, 729 | 0b00000000, 730 | // 0x60 ( ` ) 731 | 0b00110000, 732 | 0b00110000, 733 | 0b00100000, 734 | 0b00010000, 735 | 0b00000000, 736 | 0b00000000, 737 | 0b00000000, 738 | 0b00000000, 739 | // 0x61 ( a ) 740 | 0b00000000, 741 | 0b00000000, 742 | 0b01110000, 743 | 0b00001000, 744 | 0b01111000, 745 | 0b10001000, 746 | 0b01111000, 747 | 0b00000000, 748 | // 0x62 ( b ) 749 | 0b10000000, 750 | 0b10000000, 751 | 0b11110000, 752 | 0b10001000, 753 | 0b10001000, 754 | 0b10001000, 755 | 0b11110000, 756 | 0b00000000, 757 | // 0x63 ( c ) 758 | 0b00000000, 759 | 0b00000000, 760 | 0b01111000, 761 | 0b10000000, 762 | 0b10000000, 763 | 0b10000000, 764 | 0b01111000, 765 | 0b00000000, 766 | // 0x64 ( d ) 767 | 0b00001000, 768 | 0b00001000, 769 | 0b01111000, 770 | 0b10001000, 771 | 0b10001000, 772 | 0b10001000, 773 | 0b01111000, 774 | 0b00000000, 775 | // 0x65 ( e ) 776 | 0b00000000, 777 | 0b00000000, 778 | 0b01110000, 779 | 0b10001000, 780 | 0b11111000, 781 | 0b10000000, 782 | 0b01111000, 783 | 0b00000000, 784 | // 0x66 ( f ) 785 | 0b00110000, 786 | 0b01000000, 787 | 0b11110000, 788 | 0b01000000, 789 | 0b01000000, 790 | 0b01000000, 791 | 0b01000000, 792 | 0b00000000, 793 | // 0x67 ( g ) 794 | 0b00000000, 795 | 0b00000000, 796 | 0b01111000, 797 | 0b10001000, 798 | 0b10001000, 799 | 0b01111000, 800 | 0b00001000, 801 | 0b11110000, 802 | // 0x68 ( h ) 803 | 0b10000000, 804 | 0b10000000, 805 | 0b11110000, 806 | 0b10001000, 807 | 0b10001000, 808 | 0b10001000, 809 | 0b10001000, 810 | 0b00000000, 811 | // 0x69 ( i ) 812 | 0b00000000, 813 | 0b00100000, 814 | 0b00000000, 815 | 0b01100000, 816 | 0b00100000, 817 | 0b00100000, 818 | 0b00100000, 819 | 0b00000000, 820 | // 0x6A ( j ) 821 | 0b00000000, 822 | 0b00010000, 823 | 0b00000000, 824 | 0b00110000, 825 | 0b00010000, 826 | 0b00010000, 827 | 0b00010000, 828 | 0b11100000, 829 | // 0x6B ( k ) 830 | 0b10000000, 831 | 0b10000000, 832 | 0b10010000, 833 | 0b10100000, 834 | 0b11000000, 835 | 0b10100000, 836 | 0b10010000, 837 | 0b00000000, 838 | // 0x6C ( l ) 839 | 0b00100000, 840 | 0b00100000, 841 | 0b00100000, 842 | 0b00100000, 843 | 0b00100000, 844 | 0b00100000, 845 | 0b00010000, 846 | 0b00000000, 847 | // 0x6D ( m ) 848 | 0b00000000, 849 | 0b00000000, 850 | 0b01010000, 851 | 0b10101000, 852 | 0b10101000, 853 | 0b10001000, 854 | 0b10001000, 855 | 0b00000000, 856 | // 0x6E ( n ) 857 | 0b00000000, 858 | 0b00000000, 859 | 0b11110000, 860 | 0b10001000, 861 | 0b10001000, 862 | 0b10001000, 863 | 0b10001000, 864 | 0b00000000, 865 | // 0x6F ( o ) 866 | 0b00000000, 867 | 0b00000000, 868 | 0b01110000, 869 | 0b10001000, 870 | 0b10001000, 871 | 0b10001000, 872 | 0b01110000, 873 | 0b00000000, 874 | // 0x70 ( p ) 875 | 0b00000000, 876 | 0b00000000, 877 | 0b11110000, 878 | 0b10001000, 879 | 0b10001000, 880 | 0b11110000, 881 | 0b10000000, 882 | 0b10000000, 883 | // 0x71 ( q ) 884 | 0b00000000, 885 | 0b00000000, 886 | 0b01111000, 887 | 0b10001000, 888 | 0b10001000, 889 | 0b01111000, 890 | 0b00001000, 891 | 0b00001000, 892 | // 0x72 ( r ) 893 | 0b00000000, 894 | 0b00000000, 895 | 0b10110000, 896 | 0b11000000, 897 | 0b10000000, 898 | 0b10000000, 899 | 0b10000000, 900 | 0b00000000, 901 | // 0x73 ( s ) 902 | 0b00000000, 903 | 0b00000000, 904 | 0b01111000, 905 | 0b10000000, 906 | 0b01110000, 907 | 0b00001000, 908 | 0b11110000, 909 | 0b00000000, 910 | // 0x74 ( t ) 911 | 0b00000000, 912 | 0b00100000, 913 | 0b01111000, 914 | 0b00100000, 915 | 0b00100000, 916 | 0b00100000, 917 | 0b00011000, 918 | 0b00000000, 919 | // 0x75 ( u ) 920 | 0b00000000, 921 | 0b00000000, 922 | 0b10001000, 923 | 0b10001000, 924 | 0b10001000, 925 | 0b10001000, 926 | 0b01111000, 927 | 0b00000000, 928 | // 0x76 ( v ) 929 | 0b00000000, 930 | 0b00000000, 931 | 0b10001000, 932 | 0b10001000, 933 | 0b10001000, 934 | 0b01010000, 935 | 0b00100000, 936 | 0b00000000, 937 | // 0x77 ( w ) 938 | 0b00000000, 939 | 0b00000000, 940 | 0b10001000, 941 | 0b10001000, 942 | 0b10101000, 943 | 0b10101000, 944 | 0b01010000, 945 | 0b00000000, 946 | // 0x78 ( x ) 947 | 0b00000000, 948 | 0b00000000, 949 | 0b10001000, 950 | 0b01010000, 951 | 0b00100000, 952 | 0b01010000, 953 | 0b10001000, 954 | 0b00000000, 955 | // 0x79 ( y ) 956 | 0b00000000, 957 | 0b00000000, 958 | 0b10001000, 959 | 0b10001000, 960 | 0b10001000, 961 | 0b01111000, 962 | 0b00001000, 963 | 0b11110000, 964 | // 0x7A ( z ) 965 | 0b00000000, 966 | 0b00000000, 967 | 0b11111000, 968 | 0b00010000, 969 | 0b00100000, 970 | 0b01000000, 971 | 0b11111000, 972 | 0b00000000, 973 | // 0x7B ( { ) 974 | 0b00011000, 975 | 0b00100000, 976 | 0b00100000, 977 | 0b11000000, 978 | 0b00100000, 979 | 0b00100000, 980 | 0b00011000, 981 | 0b00000000, 982 | // 0x7C ( | ) 983 | 0b00100000, 984 | 0b00100000, 985 | 0b00100000, 986 | 0b00100000, 987 | 0b00100000, 988 | 0b00100000, 989 | 0b00100000, 990 | 0b00000000, 991 | // 0x7D ( } ) 992 | 0b11000000, 993 | 0b00100000, 994 | 0b00100000, 995 | 0b00011000, 996 | 0b00100000, 997 | 0b00100000, 998 | 0b11000000, 999 | 0b00000000, 1000 | // 0x7E ( ~ ) 1001 | 0b00000000, 1002 | 0b00000000, 1003 | 0b01000000, 1004 | 0b10101000, 1005 | 0b00010000, 1006 | 0b00000000, 1007 | 0b00000000, 1008 | 0b00000000, 1009 | // 0x7F (delta) 1010 | 0b00000000, 1011 | 0b00100000, 1012 | 0b00100000, 1013 | 0b01010000, 1014 | 0b01010000, 1015 | 0b10001000, 1016 | 0b11111000, 1017 | 0b00000000, 1018 | // 0x80 (C dot) 1019 | 0b01111000, 1020 | 0b10000000, 1021 | 0b10000000, 1022 | 0b10000000, 1023 | 0b10000000, 1024 | 0b01111000, 1025 | 0b00100000, 1026 | 0b01000000, 1027 | // 0x81 (u..) 1028 | 0b01010000, 1029 | 0b00000000, 1030 | 0b10001000, 1031 | 0b10001000, 1032 | 0b10001000, 1033 | 0b10001000, 1034 | 0b01111000, 1035 | 0b00000000, 1036 | // 0x82 (e~) 1037 | 0b00100000, 1038 | 0b01000000, 1039 | 0b01110000, 1040 | 0b10001000, 1041 | 0b11111000, 1042 | 0b10000000, 1043 | 0b01111000, 1044 | 0b00000000, 1045 | // 0x83 (a^) 1046 | 0b00100000, 1047 | 0b01010000, 1048 | 0b01110000, 1049 | 0b00001000, 1050 | 0b01111000, 1051 | 0b10001000, 1052 | 0b01111000, 1053 | 0b00000000, 1054 | // 0x84 (a..) 1055 | 0b01010000, 1056 | 0b00000000, 1057 | 0b01110000, 1058 | 0b00001000, 1059 | 0b01111000, 1060 | 0b10001000, 1061 | 0b01111000, 1062 | 0b00000000, 1063 | // 0x85 (a~) 1064 | 0b00100000, 1065 | 0b00010000, 1066 | 0b01110000, 1067 | 0b00001000, 1068 | 0b01111000, 1069 | 0b10001000, 1070 | 0b01111000, 1071 | 0b00000000, 1072 | // 0x86 (ao) 1073 | 0b00100000, 1074 | 0b00000000, 1075 | 0b01110000, 1076 | 0b00001000, 1077 | 0b01111000, 1078 | 0b10001000, 1079 | 0b01111000, 1080 | 0b00000000, 1081 | // 0x87 (c,) 1082 | 0b00000000, 1083 | 0b00000000, 1084 | 0b01111000, 1085 | 0b10000000, 1086 | 0b10000000, 1087 | 0b10000000, 1088 | 0b01111000, 1089 | 0b00100000, 1090 | // 0x88 (e^) 1091 | 0b00100000, 1092 | 0b01010000, 1093 | 0b01110000, 1094 | 0b10001000, 1095 | 0b11111000, 1096 | 0b10000000, 1097 | 0b01111000, 1098 | 0b00000000, 1099 | // 0x89 (e..) 1100 | 0b01010000, 1101 | 0b00000000, 1102 | 0b01110000, 1103 | 0b10001000, 1104 | 0b11111000, 1105 | 0b10000000, 1106 | 0b01111000, 1107 | 0b00000000, 1108 | // 0x8A (e~) 1109 | 0b00100000, 1110 | 0b00010000, 1111 | 0b01110000, 1112 | 0b10001000, 1113 | 0b11111000, 1114 | 0b10000000, 1115 | 0b01111000, 1116 | 0b00000000, 1117 | // 0x8B (i..) 1118 | 0b00000000, 1119 | 0b01010000, 1120 | 0b00000000, 1121 | 0b01100000, 1122 | 0b00100000, 1123 | 0b00100000, 1124 | 0b00100000, 1125 | 0b00000000, 1126 | // 0x8C (i^) 1127 | 0b00100000, 1128 | 0b01010000, 1129 | 0b00000000, 1130 | 0b01100000, 1131 | 0b00100000, 1132 | 0b00100000, 1133 | 0b00100000, 1134 | 0b00000000, 1135 | // 0x8D (i~) 1136 | 0b01000000, 1137 | 0b00100000, 1138 | 0b00000000, 1139 | 0b01100000, 1140 | 0b00100000, 1141 | 0b00100000, 1142 | 0b00100000, 1143 | 0b00000000, 1144 | // 0x8E (A..) 1145 | 0b01010000, 1146 | 0b00000000, 1147 | 0b0111000, 1148 | 0b10001000, 1149 | 0b11111000, 1150 | 0b10001000, 1151 | 0b10001000, 1152 | 0b00000000, 1153 | // 0x8F (A.) 1154 | 0b00100000, 1155 | 0b00000000, 1156 | 0b0111000, 1157 | 0b10001000, 1158 | 0b11111000, 1159 | 0b10001000, 1160 | 0b10001000, 1161 | 0b00000000, 1162 | // 0x90 (E~) 1163 | 0b00010000, 1164 | 0b00100000, 1165 | 0b11111000, 1166 | 0b10000000, 1167 | 0b11111000, 1168 | 0b10000000, 1169 | 0b11111000, 1170 | 0b00000000, 1171 | // 0x91 (ee) 1172 | 0b00000000, 1173 | 0b00000000, 1174 | 0b11010000, 1175 | 0b00101000, 1176 | 0b11111000, 1177 | 0b10100000, 1178 | 0b01011000, 1179 | 0b00000000, 1180 | // 0x92 (AE) 1181 | 0b00111000, 1182 | 0b01100000, 1183 | 0b10100000, 1184 | 0b10111000, 1185 | 0b11100000, 1186 | 0b10100000, 1187 | 0b10111000, 1188 | 0b00000000, 1189 | // 0x93 (o^) 1190 | 0b00100000, 1191 | 0b01010000, 1192 | 0b01110000, 1193 | 0b10001000, 1194 | 0b10001000, 1195 | 0b10001000, 1196 | 0b01110000, 1197 | 0b00000000, 1198 | // 0x94 (o.) 1199 | 0b00100000, 1200 | 0b00000000, 1201 | 0b01110000, 1202 | 0b10001000, 1203 | 0b10001000, 1204 | 0b10001000, 1205 | 0b01110000, 1206 | 0b00000000, 1207 | // 0x95 (o~) 1208 | 0b00100000, 1209 | 0b00010000, 1210 | 0b01110000, 1211 | 0b10001000, 1212 | 0b10001000, 1213 | 0b10001000, 1214 | 0b01110000, 1215 | 0b00000000, 1216 | // 0x96 (u^) 1217 | 0b00100000, 1218 | 0b01010000, 1219 | 0b10001000, 1220 | 0b10001000, 1221 | 0b10001000, 1222 | 0b10001000, 1223 | 0b01111000, 1224 | 0b00000000, 1225 | // 0x97 (u~) 1226 | 0b01000000, 1227 | 0b00100000, 1228 | 0b10001000, 1229 | 0b10001000, 1230 | 0b10001000, 1231 | 0b10001000, 1232 | 0b01111000, 1233 | 0b00000000, 1234 | // 0x98 (y..) 1235 | 0b01010000, 1236 | 0b00000000, 1237 | 0b10001000, 1238 | 0b10001000, 1239 | 0b10001000, 1240 | 0b01111000, 1241 | 0b00001000, 1242 | 0b11110000, 1243 | // 0x99 (O..) 1244 | 0b01010000, 1245 | 0b01110000, 1246 | 0b10001000, 1247 | 0b10001000, 1248 | 0b10001000, 1249 | 0b10001000, 1250 | 0b01110000, 1251 | 0b00000000, 1252 | // 0x9A (U..) 1253 | 0b01010000, 1254 | 0b10001000, 1255 | 0b10001000, 1256 | 0b10001000, 1257 | 0b10001000, 1258 | 0b10001000, 1259 | 0b01110000, 1260 | 0b00000000, 1261 | // 0x9B(c/) 1262 | 0b00000000, 1263 | 0b00100000, 1264 | 0b01110000, 1265 | 0b10100000, 1266 | 0b10100000, 1267 | 0b01110000, 1268 | 0b00100000, 1269 | 0b00000000, 1270 | // 0x9C (pound) 1271 | 0b00011000, 1272 | 0b00100000, 1273 | 0b00100000, 1274 | 0b11111000, 1275 | 0b00100000, 1276 | 0b01000000, 1277 | 0b11111000, 1278 | 0b00000000, 1279 | // 0x9D (yuan) 1280 | 0b10001000, 1281 | 0b01010000, 1282 | 0b11111000, 1283 | 0b00100000, 1284 | 0b11111000, 1285 | 0b00100000, 1286 | 0b00100000, 1287 | 0b00000000, 1288 | // 0x9E (pts) 1289 | 0b11000000, 1290 | 0b10100000, 1291 | 0b11000000, 1292 | 0b10100000, 1293 | 0b01110000, 1294 | 0b00100000, 1295 | 0b00111000, 1296 | 0b00000000, 1297 | // 0x9F (special f) 1298 | 0b00011000, 1299 | 0b00100000, 1300 | 0b11111000, 1301 | 0b00100000, 1302 | 0b00100000, 1303 | 0b00100000, 1304 | 0b00100000, 1305 | 0b11000000, 1306 | // 0xA0 (a~) 1307 | 0b00100000, 1308 | 0b01000000, 1309 | 0b01110000, 1310 | 0b00001000, 1311 | 0b01111000, 1312 | 0b10001000, 1313 | 0b01111000, 1314 | 0b00000000, 1315 | // 0xA1(i~) 1316 | 0b00010000, 1317 | 0b00100000, 1318 | 0b00000000, 1319 | 0b01100000, 1320 | 0b00100000, 1321 | 0b00100000, 1322 | 0b00100000, 1323 | 0b00000000, 1324 | // 0xA2(o~) 1325 | 0b00100000, 1326 | 0b01000000, 1327 | 0b01110000, 1328 | 0b10001000, 1329 | 0b10001000, 1330 | 0b10001000, 1331 | 0b01110000, 1332 | 0b00000000, 1333 | // 0xA3 (u~) 1334 | 0b00010000, 1335 | 0b00100000, 1336 | 0b10001000, 1337 | 0b10001000, 1338 | 0b10001000, 1339 | 0b10001000, 1340 | 0b01111000, 1341 | 0b00000000, 1342 | // 0xA4 (n~) 1343 | 0b10100000, 1344 | 0b01010000, 1345 | 0b11110000, 1346 | 0b10001000, 1347 | 0b10001000, 1348 | 0b10001000, 1349 | 0b10001000, 1350 | 0b00000000, 1351 | // 0xA5 (N~) 1352 | 0b10100000, 1353 | 0b01010000, 1354 | 0b10001000, 1355 | 0b11001000, 1356 | 0b10101000, 1357 | 0b10011000, 1358 | 0b10001000, 1359 | 0b00000000, 1360 | // 0xA6 (^a) 1361 | 0b01100000, 1362 | 0b10010000, 1363 | 0b01111000, 1364 | 0b00000000, 1365 | 0b00000000, 1366 | 0b00000000, 1367 | 0b00000000, 1368 | 0b00000000, 1369 | // 0xA7 (^o) 1370 | 0b00110000, 1371 | 0b01001000, 1372 | 0b01001000, 1373 | 0b00110000, 1374 | 0b00000000, 1375 | 0b00000000, 1376 | 0b00000000, 1377 | 0b00000000, 1378 | // 0xA8 (inv ?) 1379 | 0b00100000, 1380 | 0b00000000, 1381 | 0b00100000, 1382 | 0b01000000, 1383 | 0b10000000, 1384 | 0b10001000, 1385 | 0b01110000, 1386 | 0b00000000, 1387 | // 0xA9 (not) 1388 | 0b00000000, 1389 | 0b00000000, 1390 | 0b00000000, 1391 | 0b11111000, 1392 | 0b10000000, 1393 | 0b00000000, 1394 | 0b00000000, 1395 | 0b00000000, 1396 | // 0xAA (not) 1397 | 0b00000000, 1398 | 0b00000000, 1399 | 0b00000000, 1400 | 0b11111000, 1401 | 0b00001000, 1402 | 0b00000000, 1403 | 0b00000000, 1404 | 0b00000000, 1405 | // 0xAB (1/2) 1406 | 0b01000000, 1407 | 0b01001000, 1408 | 0b01010000, 1409 | 0b00111000, 1410 | 0b01001000, 1411 | 0b10010000, 1412 | 0b00111000, 1413 | 0b00000000, 1414 | // 0xAC (1/4) 1415 | 0b01000000, 1416 | 0b01001000, 1417 | 0b01010000, 1418 | 0b00101000, 1419 | 0b01011000, 1420 | 0b10111000, 1421 | 0b00001000, 1422 | 0b00000000, 1423 | // 0xAD (invert !) 1424 | 0b00100000, 1425 | 0b00000000, 1426 | 0b00100000, 1427 | 0b00100000, 1428 | 0b00100000, 1429 | 0b00100000, 1430 | 0b00100000, 1431 | 0b00000000, 1432 | // 0xAE (arrow left) 1433 | 0b00000000, 1434 | 0b00101000, 1435 | 0b01010000, 1436 | 0b10100000, 1437 | 0b01010000, 1438 | 0b00101000, 1439 | 0b00000000, 1440 | 0b00000000, 1441 | // 0xAF (arrow right) 1442 | 0b00000000, 1443 | 0b10100000, 1444 | 0b01010000, 1445 | 0b00101000, 1446 | 0b01010000, 1447 | 0b10100000, 1448 | 0b00000000, 1449 | 0b00000000, 1450 | // 0xB0 (shadow 0) 1451 | 0b10010010, 1452 | 0b00000000, 1453 | 0b01001001, 1454 | 0b00000000, 1455 | 0b00100100, 1456 | 0b00000000, 1457 | 0b10010010, 1458 | 0b00000000, 1459 | // 0xB1(shadow 1) 1460 | 0b10101010, 1461 | 0b01010101, 1462 | 0b10101010, 1463 | 0b01010101, 1464 | 0b10101010, 1465 | 0b01010101, 1466 | 0b10101010, 1467 | 0b01010101, 1468 | // 0xB2(shadow 2) 1469 | 0b01101101, 1470 | 0b11111111, 1471 | 0b10110110, 1472 | 0b11111111, 1473 | 0b11011011, 1474 | 0b11111111, 1475 | 0b01101101, 1476 | 0b11111111, 1477 | // 0xB3 (left vertical line) 1478 | 0b00010000, 1479 | 0b00010000, 1480 | 0b00010000, 1481 | 0b00010000, 1482 | 0b00010000, 1483 | 0b00010000, 1484 | 0b00010000, 1485 | 0b00010000, 1486 | // 0xB4( box right tee ) 1487 | 0b00010000, 1488 | 0b00010000, 1489 | 0b00010000, 1490 | 0b11110000, 1491 | 0b00010000, 1492 | 0b00010000, 1493 | 0b00010000, 1494 | 0b00010000, 1495 | // 0xB5( box right tee double line) 1496 | 0b00010000, 1497 | 0b00010000, 1498 | 0b00010000, 1499 | 0b11110000, 1500 | 0b11110000, 1501 | 0b00010000, 1502 | 0b00010000, 1503 | 0b00010000, 1504 | // 0xB6( box right tee vertical double line) 1505 | 0b00011000, 1506 | 0b00011000, 1507 | 0b00011000, 1508 | 0b11111000, 1509 | 0b00011000, 1510 | 0b00011000, 1511 | 0b00011000, 1512 | 0b00011000, 1513 | // 0xB7( box upper right corner vertical double line ) 1514 | 0b00000000, 1515 | 0b00000000, 1516 | 0b00000000, 1517 | 0b11111000, 1518 | 0b00011000, 1519 | 0b00011000, 1520 | 0b00011000, 1521 | 0b00011000, 1522 | // 0xB8( box upper right corner double line ) 1523 | 0b00000000, 1524 | 0b00000000, 1525 | 0b00000000, 1526 | 0b11110000, 1527 | 0b11110000, 1528 | 0b00010000, 1529 | 0b00010000, 1530 | 0b00010000, 1531 | // 0xB9( box right tee all double line) 1532 | 0b00011000, 1533 | 0b00011000, 1534 | 0b00011000, 1535 | 0b11111000, 1536 | 0b11111000, 1537 | 0b00011000, 1538 | 0b00011000, 1539 | 0b00011000, 1540 | // 0xBA (verticla double line) 1541 | 0b00011000, 1542 | 0b00011000, 1543 | 0b00011000, 1544 | 0b00011000, 1545 | 0b00011000, 1546 | 0b00011000, 1547 | 0b00011000, 1548 | 0b00011000, 1549 | // 0xBB( box upper right corner all double line ) 1550 | 0b00000000, 1551 | 0b00000000, 1552 | 0b00000000, 1553 | 0b11111000, 1554 | 0b11111000, 1555 | 0b00011000, 1556 | 0b00011000, 1557 | 0b00011000, 1558 | // 0xBC( box lower right corner all double line ) 1559 | 0b00011000, 1560 | 0b00011000, 1561 | 0b00011000, 1562 | 0b11111000, 1563 | 0b11111000, 1564 | 0b00000000, 1565 | 0b00000000, 1566 | 0b00000000, 1567 | // 0xBD( box lower right corner vertical double line ) 1568 | 0b00011000, 1569 | 0b00011000, 1570 | 0b00011000, 1571 | 0b11111000, 1572 | 0b00000000, 1573 | 0b00000000, 1574 | 0b00000000, 1575 | 0b00000000, 1576 | // 0xBE( box lower right corner double line ) 1577 | 0b00010000, 1578 | 0b00010000, 1579 | 0b00010000, 1580 | 0b11110000, 1581 | 0b11110000, 1582 | 0b00000000, 1583 | 0b00000000, 1584 | 0b00000000, 1585 | // 0xBF( box upper right corner ) 1586 | 0b00000000, 1587 | 0b00000000, 1588 | 0b00000000, 1589 | 0b11110000, 1590 | 0b00010000, 1591 | 0b00010000, 1592 | 0b00010000, 1593 | 0b00010000, 1594 | // 0xC0( box lower left corner ) 1595 | 0b00010000, 1596 | 0b00010000, 1597 | 0b00010000, 1598 | 0b00011111, 1599 | 0b00000000, 1600 | 0b00000000, 1601 | 0b00000000, 1602 | 0b00000000, 1603 | // 0xC1( box bottom tee ) 1604 | 0b00010000, 1605 | 0b00010000, 1606 | 0b00010000, 1607 | 0b11111111, 1608 | 0b00000000, 1609 | 0b00000000, 1610 | 0b00000000, 1611 | 0b00000000, 1612 | // 0xC2( box top tee ) 1613 | 0b00000000, 1614 | 0b00000000, 1615 | 0b00000000, 1616 | 0b11111111, 1617 | 0b00010000, 1618 | 0b00010000, 1619 | 0b00010000, 1620 | 0b00010000, 1621 | // 0xC3( box left tee ) 1622 | 0b00010000, 1623 | 0b00010000, 1624 | 0b00010000, 1625 | 0b00011111, 1626 | 0b00010000, 1627 | 0b00010000, 1628 | 0b00010000, 1629 | 0b00010000, 1630 | // 0xC4 horizontal line 1631 | 0b00000000, 1632 | 0b00000000, 1633 | 0b00000000, 1634 | 0b11111111, 1635 | 0b00000000, 1636 | 0b00000000, 1637 | 0b00000000, 1638 | 0b00000000, 1639 | // 0xC5( box crossing lines ) 1640 | 0b00010000, 1641 | 0b00010000, 1642 | 0b00010000, 1643 | 0b11111111, 1644 | 0b00010000, 1645 | 0b00010000, 1646 | 0b00010000, 1647 | 0b00010000, 1648 | // 0xC6 ( box left tee double line ) 1649 | 0b00010000, 1650 | 0b00010000, 1651 | 0b00010000, 1652 | 0b00011111, 1653 | 0b00011111, 1654 | 0b00010000, 1655 | 0b00010000, 1656 | 0b00010000, 1657 | // 0xC7( box left tee vertical double line ) 1658 | 0b00011000, 1659 | 0b00011000, 1660 | 0b00011000, 1661 | 0b00011111, 1662 | 0b00011000, 1663 | 0b00011000, 1664 | 0b00011000, 1665 | 0b00011000, 1666 | // 0xC8( box lower left corner all double line ) 1667 | 0b00011000, 1668 | 0b00011000, 1669 | 0b00011000, 1670 | 0b00011111, 1671 | 0b00011111, 1672 | 0b00000000, 1673 | 0b00000000, 1674 | 0b00000000, 1675 | // 0xC9( box upper left corner all double line ) 1676 | 0b00000000, 1677 | 0b00000000, 1678 | 0b00000000, 1679 | 0b00011111, 1680 | 0b00011111, 1681 | 0b00011000, 1682 | 0b00011000, 1683 | 0b00011000, 1684 | // 0xCA( box bottom tee all double line ) 1685 | 0b00011000, 1686 | 0b00011000, 1687 | 0b00011000, 1688 | 0b11111111, 1689 | 0b11111111, 1690 | 0b00000000, 1691 | 0b00000000, 1692 | 0b00000000, 1693 | // 0xCB( box top tee all double line ) 1694 | 0b00000000, 1695 | 0b00000000, 1696 | 0b00000000, 1697 | 0b11111111, 1698 | 0b11111111, 1699 | 0b00011000, 1700 | 0b00011000, 1701 | 0b00011000, 1702 | // 0xCC( box left tee ) 1703 | 0b00011000, 1704 | 0b00011000, 1705 | 0b00011000, 1706 | 0b00011111, 1707 | 0b00011111, 1708 | 0b00011000, 1709 | 0b00011000, 1710 | 0b00011000, 1711 | // 0xCD horizontal line double line 1712 | 0b00000000, 1713 | 0b00000000, 1714 | 0b00000000, 1715 | 0b11111111, 1716 | 0b11111111, 1717 | 0b00000000, 1718 | 0b00000000, 1719 | 0b00000000, 1720 | // 0xCE( box crossing lines all double line ) 1721 | 0b00011000, 1722 | 0b00011000, 1723 | 0b00011000, 1724 | 0b11111111, 1725 | 0b11111111, 1726 | 0b00011000, 1727 | 0b00011000, 1728 | 0b00011000, 1729 | // 0xCF( box bottom tee double line ) 1730 | 0b00010000, 1731 | 0b00010000, 1732 | 0b00010000, 1733 | 0b11111111, 1734 | 0b11111111, 1735 | 0b00000000, 1736 | 0b00000000, 1737 | 0b00000000, 1738 | // 0xD0( box bottom tee vertical double line ) 1739 | 0b00011000, 1740 | 0b00011000, 1741 | 0b00011000, 1742 | 0b11111111, 1743 | 0b00000000, 1744 | 0b00000000, 1745 | 0b00000000, 1746 | 0b00000000, 1747 | // 0xD1( box top tee double line ) 1748 | 0b00000000, 1749 | 0b00000000, 1750 | 0b00000000, 1751 | 0b11111111, 1752 | 0b11111111, 1753 | 0b00010000, 1754 | 0b00010000, 1755 | 0b00010000, 1756 | // 0xD2( box top tee vertical double line ) 1757 | 0b00000000, 1758 | 0b00000000, 1759 | 0b00000000, 1760 | 0b11111111, 1761 | 0b00011000, 1762 | 0b00011000, 1763 | 0b00011000, 1764 | 0b00011000, 1765 | // 0xD3( box lower left corner vertical double line ) 1766 | 0b00011000, 1767 | 0b00011000, 1768 | 0b00011000, 1769 | 0b00011111, 1770 | 0b00000000, 1771 | 0b00000000, 1772 | 0b00000000, 1773 | 0b00000000, 1774 | // 0xD4( box lower left corner double line ) 1775 | 0b00010000, 1776 | 0b00010000, 1777 | 0b00010000, 1778 | 0b00011111, 1779 | 0b00011111, 1780 | 0b00000000, 1781 | 0b00000000, 1782 | 0b00000000, 1783 | // 0xD5( box upper left corner double line ) 1784 | 0b00000000, 1785 | 0b00000000, 1786 | 0b00000000, 1787 | 0b00011111, 1788 | 0b00011111, 1789 | 0b00010000, 1790 | 0b00010000, 1791 | 0b00010000, 1792 | // 0xD6( box upper left corner vertical double line ) 1793 | 0b00000000, 1794 | 0b00000000, 1795 | 0b00000000, 1796 | 0b00011111, 1797 | 0b00011000, 1798 | 0b00011000, 1799 | 0b00011000, 1800 | 0b00011000, 1801 | // 0xD7( box crossing lines double line ) 1802 | 0b00011000, 1803 | 0b00011000, 1804 | 0b00011000, 1805 | 0b11111111, 1806 | 0b00011000, 1807 | 0b00011000, 1808 | 0b00011000, 1809 | 0b00011000, 1810 | // 0xD8( box crossing lines double line ) 1811 | 0b00010000, 1812 | 0b00010000, 1813 | 0b00010000, 1814 | 0b11111111, 1815 | 0b11111111, 1816 | 0b00010000, 1817 | 0b00010000, 1818 | 0b00010000, 1819 | // 0xD9( box lower right corner ) 1820 | 0b00010000, 1821 | 0b00010000, 1822 | 0b00010000, 1823 | 0b11110000, 1824 | 0b00000000, 1825 | 0b00000000, 1826 | 0b00000000, 1827 | 0b00000000, 1828 | // 0xDA( box upper left corner ) 1829 | 0b00000000, 1830 | 0b00000000, 1831 | 0b00000000, 1832 | 0b00011111, 1833 | 0b00010000, 1834 | 0b00010000, 1835 | 0b00010000, 1836 | 0b00010000, 1837 | // 0xDB (full) 1838 | 0b11111111, 1839 | 0b11111111, 1840 | 0b11111111, 1841 | 0b11111111, 1842 | 0b11111111, 1843 | 0b11111111, 1844 | 0b11111111, 1845 | 0b11111111, 1846 | // 0xDC (half) 1847 | 0b00000000, 1848 | 0b00000000, 1849 | 0b00000000, 1850 | 0b00000000, 1851 | 0b11111111, 1852 | 0b11111111, 1853 | 0b11111111, 1854 | 0b11111111, 1855 | // 0xDD (left) 1856 | 0b11100000, 1857 | 0b11100000, 1858 | 0b11100000, 1859 | 0b11100000, 1860 | 0b11100000, 1861 | 0b11100000, 1862 | 0b11100000, 1863 | 0b11100000, 1864 | // 0xDE (right) 1865 | 0b00011100, 1866 | 0b00011100, 1867 | 0b00011100, 1868 | 0b00011100, 1869 | 0b00011100, 1870 | 0b00011100, 1871 | 0b00011100, 1872 | 0b00011100, 1873 | // 0xDF (up) 1874 | 0b11111100, 1875 | 0b11111100, 1876 | 0b11111100, 1877 | 0b11111100, 1878 | 0b00000000, 1879 | 0b00000000, 1880 | 0b00000000, 1881 | 0b00000000, 1882 | // 0xE0 (alpha) 1883 | 0b00000000, 1884 | 0b00000000, 1885 | 0b01101000, 1886 | 0b10011000, 1887 | 0b10010000, 1888 | 0b10010000, 1889 | 0b01101000, 1890 | 0b00000000, 1891 | // 0xE1 (beta) 1892 | 0b01110000, 1893 | 0b10001000, 1894 | 0b10001000, 1895 | 0b11110000, 1896 | 0b10001000, 1897 | 0b10001000, 1898 | 0b11110000, 1899 | 0b10000000, 1900 | // 0xE2 (Gamma) 1901 | 0b11111000, 1902 | 0b10000000, 1903 | 0b10000000, 1904 | 0b10000000, 1905 | 0b10000000, 1906 | 0b10000000, 1907 | 0b10000000, 1908 | 0b00000000, 1909 | // 0xE3 (Pi) 1910 | 0b11111000, 1911 | 0b01010000, 1912 | 0b01010000, 1913 | 0b01010000, 1914 | 0b01010000, 1915 | 0b01010000, 1916 | 0b01010000, 1917 | 0b00000000, 1918 | // 0xE4 (Sigma) 1919 | 0b11111000, 1920 | 0b01000000, 1921 | 0b00100000, 1922 | 0b00010000, 1923 | 0b00100000, 1924 | 0b01000000, 1925 | 0b11111000, 1926 | 0b00000000, 1927 | // 0xE5 (sigma) 1928 | 0b00000000, 1929 | 0b00011000, 1930 | 0b01100000, 1931 | 0b10011000, 1932 | 0b10001000, 1933 | 0b10001000, 1934 | 0b01110000, 1935 | 0b00000000, 1936 | // 0xE6 (mu) 1937 | 0b00000000, 1938 | 0b00000000, 1939 | 0b10001000, 1940 | 0b10001000, 1941 | 0b10001000, 1942 | 0b10011000, 1943 | 0b11101000, 1944 | 0b10000000, 1945 | // 0xE7 (tau) 1946 | 0b00000000, 1947 | 0b00000000, 1948 | 0b00000000, 1949 | 0b11111000, 1950 | 0b00100000, 1951 | 0b00100000, 1952 | 0b00100000, 1953 | 0b00000000, 1954 | // 0xE8(Phi) 1955 | 0b00100000, 1956 | 0b01110000, 1957 | 0b10101000, 1958 | 0b10101000, 1959 | 0b10101000, 1960 | 0b01110000, 1961 | 0b00100000, 1962 | 0b00000000, 1963 | // 0xE9 (Theta) 1964 | 0b01110000, 1965 | 0b10001000, 1966 | 0b11011000, 1967 | 0b11111000, 1968 | 0b11011000, 1969 | 0b10001000, 1970 | 0b01110000, 1971 | 0b00000000, 1972 | // 0xEA (Omega) 1973 | 0b01110000, 1974 | 0b10001000, 1975 | 0b10001000, 1976 | 0b10001000, 1977 | 0b10001000, 1978 | 0b01010000, 1979 | 0b11011000, 1980 | 0b00000000, 1981 | // 0xEB (delta) 1982 | 0b01111000, 1983 | 0b10000000, 1984 | 0b01110000, 1985 | 0b10001000, 1986 | 0b10001000, 1987 | 0b10001000, 1988 | 0b01110000, 1989 | 0b00000000, 1990 | // 0xEC (infinity) 1991 | 0b00000000, 1992 | 0b00000000, 1993 | 0b01010000, 1994 | 0b10101000, 1995 | 0b10101000, 1996 | 0b01010000, 1997 | 0b00000000, 1998 | 0b00000000, 1999 | // 0xED (phi) 2000 | 0b00000000, 2001 | 0b01011000, 2002 | 0b10101000, 2003 | 0b10101000, 2004 | 0b01110000, 2005 | 0b00100000, 2006 | 0b00100000, 2007 | 0b00000000, 2008 | // 0xEE (epsilon) 2009 | 0b00000000, 2010 | 0b00000000, 2011 | 0b01110000, 2012 | 0b10000000, 2013 | 0b01110000, 2014 | 0b10000000, 2015 | 0b01110000, 2016 | 0b00000000, 2017 | // 0xEF (and) 2018 | 0b00100000, 2019 | 0b01010000, 2020 | 0b10001000, 2021 | 0b10001000, 2022 | 0b10001000, 2023 | 0b10001000, 2024 | 0b10001000, 2025 | 0b00000000, 2026 | // 0xF0 (three line) 2027 | 0b00000000, 2028 | 0b11111000, 2029 | 0b00000000, 2030 | 0b11111000, 2031 | 0b00000000, 2032 | 0b11111000, 2033 | 0b00000000, 2034 | 0b00000000, 2035 | // 0xF1( plus-minus ) 2036 | 0b00100000, 2037 | 0b00100000, 2038 | 0b11111000, 2039 | 0b00100000, 2040 | 0b00100000, 2041 | 0b00000000, 2042 | 0b11111000, 2043 | 0b00000000, 2044 | // 0xF2( greater than or equal ) 2045 | 0b00000000, 2046 | 0b01000000, 2047 | 0b00110000, 2048 | 0b00001000, 2049 | 0b00110000, 2050 | 0b01000000, 2051 | 0b11111000, 2052 | 0b00000000, 2053 | // 0xF3( less than or equal ) 2054 | 0b00000000, 2055 | 0b00010000, 2056 | 0b01100000, 2057 | 0b10000000, 2058 | 0b01100000, 2059 | 0b00010000, 2060 | 0b11111000, 2061 | 0b00000000, 2062 | // 0xF4 2063 | 0b00011000, 2064 | 0b00100000, 2065 | 0b00100000, 2066 | 0b00100000, 2067 | 0b00100000, 2068 | 0b00100000, 2069 | 0b0010000, 2070 | 0b00100000, 2071 | // 0xF5 2072 | 0b00100000, 2073 | 0b00100000, 2074 | 0b00100000, 2075 | 0b00100000, 2076 | 0b00100000, 2077 | 0b00100000, 2078 | 0b00100000, 2079 | 0b11000000, 2080 | // 0xF6 2081 | 0b00000000, 2082 | 0b00110000, 2083 | 0b00000000, 2084 | 0b11111000, 2085 | 0b00000000, 2086 | 0b01100000, 2087 | 0b00000000, 2088 | 0b00000000, 2089 | // 0xF7 2090 | 0b00000000, 2091 | 0b00110000, 2092 | 0b11001000, 2093 | 0b00000000, 2094 | 0b00110000, 2095 | 0b11001000, 2096 | 0b00000000, 2097 | 0b00000000, 2098 | // 0xF8 (degree) 2099 | 0b00110000, 2100 | 0b01001000, 2101 | 0b01001000, 2102 | 0b00110000, 2103 | 0b00000000, 2104 | 0b00000000, 2105 | 0b00000000, 2106 | 0b00000000, 2107 | // 0xF9 (dot) 2108 | 0b00000000, 2109 | 0b00000000, 2110 | 0b00000000, 2111 | 0b00010000, 2112 | 0b00000000, 2113 | 0b00000000, 2114 | 0b00000000, 2115 | 0b00000000, 2116 | // 0xFA (dot) 2117 | 0b00000000, 2118 | 0b00000000, 2119 | 0b00000000, 2120 | 0b00010000, 2121 | 0b00000000, 2122 | 0b00000000, 2123 | 0b00000000, 2124 | 0b00000000, 2125 | // 0xFB (r) 2126 | 0b00001000, 2127 | 0b00001000, 2128 | 0b00010000, 2129 | 0b00010000, 2130 | 0b00100000, 2131 | 0b10100000, 2132 | 0b01000000, 2133 | 0b00000000, 2134 | // 0xFC (^n) 2135 | 0b11100000, 2136 | 0b10010000, 2137 | 0b10010000, 2138 | 0b10010000, 2139 | 0b00000000, 2140 | 0b00000000, 2141 | 0b00000000, 2142 | 0b00000000, 2143 | // 0xFD (^2) 2144 | 0b01100000, 2145 | 0b00010000, 2146 | 0b01000000, 2147 | 0b11110000, 2148 | 0b00000000, 2149 | 0b00000000, 2150 | 0b00000000, 2151 | 0b00000000, 2152 | // 0xFE (small squre) 2153 | 0b00000000, 2154 | 0b00000000, 2155 | 0b01110000, 2156 | 0b01110000, 2157 | 0b01110000, 2158 | 0b00000000, 2159 | 0b00000000, 2160 | 0b00000000, 2161 | // 0xFF 2162 | 0b00000000, 2163 | 0b00000000, 2164 | 0b00000000, 2165 | 0b00000000, 2166 | 0b00000000, 2167 | 0b00000000, 2168 | 0b00000000, 2169 | 0b00000000, 2170 | }; 2171 | 2172 | #endif 2173 | -------------------------------------------------------------------------------- /vtterminal/vtterminal.c: -------------------------------------------------------------------------------- 1 | //A modified version of vt100 emulator from https://github.com/ht-deko/vt100_stm32 2 | #include "font6x8.h" 3 | #include "vtterminal.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "py/runtime.h" 10 | 11 | #include "py/mphal.h" 12 | #include "py/gc.h" 13 | #include "py/misc.h" 14 | 15 | 16 | #include "pico/stdlib.h" 17 | #include "hardware/timer.h" 18 | 19 | 20 | uint8_t* fontTop; 21 | 22 | uint16_t M_TOP = 0; 23 | uint16_t M_BOTTOM = SC_H - 1; 24 | 25 | #define SCSIZE (SC_W * SC_H) 26 | #define SP_W (SC_W * CH_W) 27 | #define SP_H (SC_H * CH_H) 28 | #define MAX_CH_X (CH_W - 1) 29 | #define MAX_CH_Y (CH_H - 1) 30 | #define MAX_SC_X (SC_W - 1) 31 | #define MAX_SC_Y (SC_H - 1) 32 | #define MAX_SP_X (SP_W - 1) 33 | #define MAX_SP_Y (SP_H - 1) 34 | 35 | typedef struct { 36 | uint8_t Bold : 1; // 1 37 | uint8_t Faint : 1; // 2 38 | uint8_t Italic : 1; // 3 39 | uint8_t Underline : 1; // 4 40 | uint8_t Blink : 1; // 5 (Slow Blink) 41 | uint8_t RapidBlink : 1; // 6 42 | uint8_t Reverse : 1; // 7 43 | uint8_t Conceal : 1; // 8 44 | }TATTR ; 45 | 46 | typedef union { 47 | uint8_t value; 48 | TATTR Bits; 49 | }ATTR ; 50 | 51 | 52 | 53 | 54 | 55 | typedef struct { 56 | uint8_t Foreground : 4; 57 | uint8_t Background : 4; 58 | }TCOLOR ; 59 | typedef union { 60 | uint8_t value; 61 | TCOLOR Color; 62 | }COLOR ; 63 | 64 | 65 | typedef struct { 66 | unsigned int g0g1 : 1; 67 | unsigned int Reserved4 : 1; 68 | unsigned int Reserved12 : 1; 69 | unsigned int CrLf : 1; 70 | unsigned int Reserved33 : 1; 71 | unsigned int Reserved34 : 1; 72 | unsigned int Reverse : 2; 73 | } TMODE; 74 | 75 | 76 | typedef union { 77 | uint8_t value; 78 | TMODE Flgs; 79 | } MODE ; 80 | 81 | typedef struct { 82 | unsigned int Reserved1 : 1; // 1 DECCKM (Cursor Keys Mode) 83 | unsigned int Reserved2 : 1; // 2 DECANM (ANSI/VT52 Mode) 84 | unsigned int Reserved3 : 1; // 3 DECCOLM (Column Mode) 85 | unsigned int Reserved4 : 1; // 4 DECSCLM (Scrolling Mode) 86 | unsigned int ScreenReverse : 1; // 5 DECSCNM (Screen Mode) 87 | unsigned int Reserved6 : 1; // 6 DECOM (Origin Mode) 88 | unsigned int WrapLine : 1; // 7 DECAWM (Autowrap Mode) 89 | unsigned int Reserved8 : 1; // 8 DECARM (Auto Repeat Mode) 90 | unsigned int Reserved9 : 1; // 9 DECINLM (Interlace Mode) 91 | unsigned int InsertMode:1; // 10 DECIM (Insert Mode) 92 | unsigned int Reverse : 6; 93 | }TMODE_EX ; 94 | 95 | typedef union { 96 | uint16_t value; 97 | TMODE_EX Flgs; 98 | }MODE_EX ; 99 | 100 | char outputBuf[30]={0}; 101 | int outputLen = 0; 102 | uint8_t screen[SCSIZE]; 103 | uint8_t attrib[SCSIZE]; 104 | uint8_t colors[SCSIZE]; 105 | uint8_t tabs[SC_W]; 106 | uint8_t *fb; 107 | const uint8_t *currentTextTable; 108 | #define NONE 0 109 | #define ES 1 110 | #define CSI 2 111 | #define CSI2 3 112 | #define LSC 4 113 | #define G0S 5 114 | #define G1S 6 115 | 116 | static const uint8_t defaultMode = 0b00001000; 117 | static const uint16_t defaultModeEx = 0b0000000001000000; 118 | static const ATTR defaultAttr = {0b00000000}; 119 | static const COLOR defaultColor = {(clBlack << 4) | clWhite}; // back, fore 120 | uint8_t escMode = NONE; // esc mode indicator 121 | bool isShowCursor = false; // is the cursor shown in last call? 122 | bool canShowCursor = true; // can the cursor be shown? 123 | bool hasParam = false; // [ has parameters 124 | bool isDECPrivateMode = false; // DEC Private Mode ( [ ?) 125 | MODE mode; 126 | //mode.value = defaultMode; 127 | MODE_EX mode_ex; 128 | //mode_ex.value = defaultModeEx; 129 | 130 | int16_t p_XP = 0; 131 | int16_t p_YP = 0; 132 | 133 | int16_t XP = 0; 134 | int16_t YP = 0; 135 | ATTR cAttr ; 136 | COLOR cColor ; 137 | 138 | int16_t b_XP = 0; 139 | int16_t b_YP = 0; 140 | ATTR bAttr ; 141 | COLOR bColor ; 142 | 143 | int16_t nVals = 0; 144 | int16_t vals[10] = {0}; 145 | static repeating_timer_t cursor_timer; 146 | 147 | 148 | bool dispCursor(repeating_timer_t *rt) ; 149 | 150 | 151 | 152 | //static void scroll_framebuffer(uint8_t *fb, int scroll_y1, int scroll_y2, int n, uint8_t bg_color); 153 | static void fill_rect_4bpp(uint8_t *fb, int x, int y, int w, int h, uint8_t color); 154 | static void drawTxt6x8(uint8_t *fb,uint8_t c,int x0,int y0, uint8_t color); 155 | static void setpixel(uint8_t *fb,int32_t x, int32_t y,uint8_t color); 156 | static void sc_updateChar(uint16_t x, uint16_t y); 157 | static void drawCursor(uint16_t x, uint16_t y); 158 | static void sc_updateLine(uint16_t ln); 159 | static void setCursorToHome(void); 160 | static void initCursorAndAttribute(void); 161 | static void scroll(void); 162 | static void clearParams(uint8_t m); 163 | static void saveCursor(void); 164 | static void restoreCursor(void); 165 | static void keypadApplicationMode(void); 166 | static void keypadNumericMode(void); 167 | static void vindex(int16_t v); 168 | static void nextLine(void) ; 169 | static void horizontalTabulationSet(void); 170 | static void reverseIndex(int16_t v); 171 | static void identify(void); 172 | static void resetToInitialState(void); 173 | //static void cursorUp(int16_t v); 174 | static void cursorDown(int16_t v); 175 | static void cursorPosition(uint8_t y, uint8_t x); 176 | static void refreshScreen(void); 177 | static void eraseInDisplay(uint8_t m); 178 | static void eraseInLine(uint8_t m); 179 | static void insertLine(uint8_t v); 180 | static void deleteLine(uint8_t v) ; 181 | static void cursorPositionReport(uint16_t y, uint16_t x); 182 | static void deviceAttributes(uint8_t m); 183 | static void tabulationClear(uint8_t m); 184 | static void lineMode(bool m); 185 | static void screenMode(bool m); 186 | static void autoWrapMode(bool m); 187 | static void setMode(int16_t *vals, int16_t nVals); 188 | static void decSetMode(int16_t *vals, int16_t nVals); 189 | static void resetMode(int16_t *vals, int16_t nVals); 190 | static void decResetMode(int16_t *vals, int16_t nVals); 191 | static void selectGraphicRendition(int16_t *vals, int16_t nVals); 192 | static void deviceStatusReport(uint8_t m); 193 | static void loadLEDs(uint8_t m); 194 | static void setTopAndBottomMargins(int16_t s, int16_t e); 195 | static void invokeConfidenceTests(uint8_t m); 196 | static void doubleHeightLine_TopHalf(void); 197 | static void doubleHeightLine_BotomHalf(void); 198 | static void singleWidthLine(void); 199 | static void doubleWidthLine(void); 200 | static void screenAlignmentDisplay(void); 201 | static void setG0charset(char c); 202 | static void setG1charset(char c); 203 | static void unknownSequence(uint8_t m, char c) ; 204 | static void cursorForward(int16_t v); 205 | static void cursorBackward(int16_t v); 206 | 207 | static void setpixel(uint8_t *fb,int32_t x, int32_t y,uint8_t color){ 208 | uint8_t *pixel = &((uint8_t *)fb)[(x + (SC_PIXEL_WIDTH*y))>>1]; 209 | 210 | if (x&0x01) { 211 | *pixel = ((uint8_t)color & 0x0f) | (*pixel & 0xf0); 212 | } else { 213 | *pixel = ((uint8_t)color << 4) | (*pixel & 0x0f); 214 | } 215 | } 216 | static void sc_updateChar(uint16_t x, uint16_t y) { 217 | uint16_t idx = SC_W * y + x; 218 | uint8_t c = screen[idx]; 219 | ATTR a; 220 | COLOR l; 221 | a.value = attrib[idx]; 222 | l.value = colors[idx]; 223 | uint8_t fore = l.Color.Foreground | (a.Bits.Blink << 3); 224 | uint8_t back = l.Color.Background | (a.Bits.Blink << 3); 225 | if (a.Bits.Reverse){ 226 | uint8_t temp = fore; fore = back; back = temp; 227 | } 228 | if (mode_ex.Flgs.ScreenReverse){ 229 | uint8_t temp = fore; fore = back; back = temp; 230 | } 231 | uint16_t xx = x * CH_W; 232 | uint16_t yy = y * CH_H; 233 | fill_rect_4bpp(fb, xx, yy, CH_W, CH_H, back); 234 | drawTxt6x8(fb,c,xx,yy, fore); 235 | if (a.Bits.Bold){ 236 | drawTxt6x8(fb,c,xx+1,yy, fore); 237 | } 238 | 239 | } 240 | 241 | 242 | 243 | 244 | static void drawCursor(uint16_t x, uint16_t y) { 245 | uint16_t xx = x * CH_W; 246 | uint16_t yy = y * CH_H; 247 | fill_rect_4bpp(fb, xx, yy, CH_W, CH_H, clWhite); 248 | } 249 | 250 | bool dispCursor(repeating_timer_t *rt) { 251 | if (escMode != NONE) 252 | return true; 253 | //sc_updateChar(p_XP, p_YP); 254 | if (canShowCursor){ 255 | 256 | isShowCursor = !isShowCursor; 257 | if (isShowCursor){ 258 | drawCursor(XP, YP); 259 | }else{ 260 | sc_updateChar(p_XP, p_YP); 261 | } 262 | p_XP = XP; 263 | p_YP = YP; 264 | } 265 | return true; 266 | } 267 | 268 | static void sc_updateLine(uint16_t ln) { 269 | for (uint32_t i=0;i M_BOTTOM); 294 | 295 | if (need_scroll) { 296 | YP = M_BOTTOM; 297 | int lines_to_scroll = M_BOTTOM - M_TOP; 298 | if (lines_to_scroll > 0) { 299 | size_t copy_bytes = lines_to_scroll * SC_W; 300 | int dst = M_TOP * SC_W; 301 | int src = (M_TOP + 1) * SC_W; 302 | memmove(&screen[dst], &screen[src], copy_bytes); 303 | memmove(&attrib[dst], &attrib[src], copy_bytes); 304 | memmove(&colors[dst], &colors[src], copy_bytes); 305 | } 306 | int bottom_idx = M_BOTTOM * SC_W; 307 | 308 | memset(&screen[bottom_idx], 0, SC_W); 309 | memset(&attrib[bottom_idx], defaultAttr.value, SC_W); 310 | memset(&colors[bottom_idx], defaultColor.value, SC_W); 311 | 312 | for (int y = M_TOP; y <= M_BOTTOM; y++) { 313 | if (y >= 0 && y < SC_H) { 314 | sc_updateLine(y); 315 | } 316 | } 317 | } else { 318 | YP = nextYP; 319 | } 320 | } 321 | 322 | static void scroll(void) { 323 | if (mode.Flgs.CrLf) XP = 0; 324 | YP++; 325 | 326 | if (YP > M_BOTTOM) { 327 | int lines_to_scroll = M_BOTTOM - M_TOP; 328 | 329 | if (lines_to_scroll > 0) { 330 | size_t copy_bytes = lines_to_scroll * SC_W; 331 | int dst = M_TOP * SC_W; 332 | int src = (M_TOP + 1) * SC_W; 333 | 334 | memmove(&screen[dst], &screen[src], copy_bytes); 335 | memmove(&attrib[dst], &attrib[src], copy_bytes); 336 | memmove(&colors[dst], &colors[src], copy_bytes); 337 | } 338 | 339 | 340 | int bottom_idx = M_BOTTOM * SC_W; 341 | memset(&screen[bottom_idx], 0, SC_W); 342 | memset(&attrib[bottom_idx], defaultAttr.value, SC_W); 343 | memset(&colors[bottom_idx], defaultColor.value, SC_W); 344 | 345 | YP = M_BOTTOM; 346 | 347 | for (uint8_t y = M_TOP; y <= M_BOTTOM; y++) 348 | sc_updateLine(y); 349 | } 350 | }*/ 351 | /* 352 | static void scroll(void) { 353 | if (mode.Flgs.CrLf) XP = 0; 354 | YP++; 355 | if (YP > M_BOTTOM) { 356 | uint16_t n = SCSIZE - SC_W - ((M_TOP + MAX_SC_Y - M_BOTTOM) * SC_W); 357 | uint16_t idx = SC_W * M_BOTTOM; 358 | uint16_t idx2; 359 | uint16_t idx3 = M_TOP * SC_W; 360 | memmove(&screen[idx3], &screen[idx3 + SC_W], n); 361 | memmove(&attrib[idx3], &attrib[idx3 + SC_W], n); 362 | memmove(&colors[idx3], &colors[idx3 + SC_W], n); 363 | for (uint8_t x = 0; x < SC_W; x++) { 364 | idx2 = idx + x; 365 | screen[idx2] = 0; 366 | attrib[idx2] = defaultAttr.value; 367 | colors[idx2] = defaultColor.value; 368 | } 369 | 370 | YP = M_BOTTOM; 371 | } 372 | for (uint8_t y = 0; y M_BOTTOM) { 381 | uint16_t n = SCSIZE - SC_W - ((M_TOP + MAX_SC_Y - M_BOTTOM) * SC_W); 382 | uint16_t idx = SC_W * M_BOTTOM; 383 | uint16_t idx2; 384 | uint16_t idx3 = M_TOP * SC_W; 385 | memmove(&screen[idx3], &screen[idx3 + SC_W], n); 386 | memmove(&attrib[idx3], &attrib[idx3 + SC_W], n); 387 | memmove(&colors[idx3], &colors[idx3 + SC_W], n); 388 | for (uint8_t x = 0; x < SC_W; x++) { 389 | idx2 = idx + x; 390 | screen[idx2] = 0; 391 | attrib[idx2] = defaultAttr.value; 392 | colors[idx2] = defaultColor.value; 393 | } 394 | for (uint8_t y = M_TOP; y <= M_BOTTOM; y++) 395 | sc_updateLine(y); 396 | YP = M_BOTTOM; 397 | } 398 | } 399 | 400 | 401 | static void clearParams(uint8_t m) { 402 | escMode = m; 403 | isDECPrivateMode = false; 404 | nVals = 0; 405 | vals[0] = vals[1] = vals[2] = vals[3] = 0; 406 | hasParam = false; 407 | } 408 | 409 | 410 | static mp_obj_t vt_printChar(mp_obj_t value_obj) { 411 | int c = mp_obj_get_int(value_obj); 412 | // [ESC] キー 413 | if (c == 0x1b) { 414 | escMode = ES; // esc mode start 415 | return mp_const_none; 416 | } 417 | // エスケープシーケンス 418 | if (escMode == ES) { 419 | switch (c) { 420 | case '[': 421 | // Control Sequence Introducer (CSI) 422 | clearParams(CSI); 423 | break; 424 | case '#': 425 | // Line Size Command 426 | clearParams(LSC); 427 | break; 428 | case '(': 429 | // G0 430 | clearParams(G0S); 431 | break; 432 | case ')': 433 | // G1 434 | clearParams(G1S); 435 | break; 436 | default: 437 | // xxx: 438 | switch (c) { 439 | case '7': 440 | // DECSC (Save Cursor): save cursor position 441 | saveCursor(); 442 | break; 443 | case '8': 444 | // DECRC (Restore Cursor): 445 | restoreCursor(); 446 | break; 447 | case '=': 448 | // DECKPAM (Keypad Application Mode): 449 | keypadApplicationMode(); 450 | break; 451 | case '>': 452 | // DECKPNM (Keypad Numeric Mode): 453 | keypadNumericMode(); 454 | break; 455 | case 'D': 456 | // IND (Index): one line down 457 | vindex(1); 458 | break; 459 | case 'E': 460 | // NEL (Next Line): 461 | nextLine(); 462 | break; 463 | case 'H': 464 | // HTS (Horizontal Tabulation Set): 465 | horizontalTabulationSet(); 466 | break; 467 | case 'M': 468 | // RI (Reverse Index): 469 | reverseIndex(1); 470 | break; 471 | case 'Z': 472 | // DECID (Identify): 473 | identify(); 474 | break; 475 | case 'c': 476 | // RIS (Reset To Initial State): 477 | resetToInitialState(); 478 | break; 479 | default: 480 | // not decodeable 481 | unknownSequence(escMode, c); 482 | break; 483 | } 484 | clearParams(NONE); 485 | break; 486 | } 487 | return mp_const_none; 488 | } 489 | 490 | // "[" Control Sequence Introducer (CSI) 491 | int16_t v1 = 0; 492 | int16_t v2 = 0; 493 | 494 | if (escMode == CSI) { 495 | escMode = CSI2; 496 | isDECPrivateMode = (c == '?'); 497 | if (isDECPrivateMode) return mp_const_none; 498 | } 499 | 500 | if (escMode == CSI2) { 501 | if (isdigit(c)) { 502 | // [パラメータ] 503 | vals[nVals] = vals[nVals] * 10 + (c - '0'); 504 | hasParam = true; 505 | } else if (c == ';') { 506 | // [セパレータ] 507 | nVals++; 508 | hasParam = false; 509 | } else { 510 | if (hasParam) nVals++; 511 | switch (c) { 512 | case 'A': 513 | // CUU (Cursor Up): 514 | v1 = (nVals == 0) ? 1 : vals[0]; 515 | reverseIndex(v1); 516 | break; 517 | case 'B': 518 | // CUD (Cursor Down): 519 | v1 = (nVals == 0) ? 1 : vals[0]; 520 | cursorDown(v1); 521 | break; 522 | case 'C': 523 | // CUF (Cursor Forward): 524 | v1 = (nVals == 0) ? 1 : vals[0]; 525 | cursorForward(v1); 526 | break; 527 | case 'D': 528 | // CUB (Cursor Backward): 529 | v1 = (nVals == 0) ? 1 : vals[0]; 530 | cursorBackward(v1); 531 | break; 532 | case 'H': 533 | // CUP (Cursor Position): 534 | case 'f': 535 | // HVP (Horizontal and Vertical Position): 536 | v1 = (nVals == 0) ? 1 : vals[0]; 537 | v2 = (nVals <= 1) ? 1 : vals[1]; 538 | cursorPosition(v1, v2); 539 | break; 540 | case 'J': 541 | // ED (Erase In Display): 542 | v1 = (nVals == 0) ? 0 : vals[0]; 543 | eraseInDisplay(v1); 544 | break; 545 | case 'K': 546 | // EL (Erase In Line) 547 | v1 = (nVals == 0) ? 0 : vals[0]; 548 | eraseInLine(v1); 549 | break; 550 | case 'L': 551 | // IL (Insert Line): 552 | v1 = (nVals == 0) ? 1 : vals[0]; 553 | insertLine(v1); 554 | break; 555 | case 'M': 556 | // DL (Delete Line): 557 | v1 = (nVals == 0) ? 1 : vals[0]; 558 | deleteLine(v1); 559 | break; 560 | case 'c': 561 | // DA (Device Attributes): 562 | v1 = (nVals == 0) ? 0 : vals[0]; 563 | deviceAttributes(v1); 564 | break; 565 | case 'g': 566 | // TBC (Tabulation Clear): 567 | v1 = (nVals == 0) ? 0 : vals[0]; 568 | tabulationClear(v1); 569 | break; 570 | case 'h': 571 | if (isDECPrivateMode) { 572 | // DECSET (DEC Set Mode): 573 | decSetMode(vals, nVals); 574 | } else { 575 | // SM (Set Mode): 576 | setMode(vals, nVals); 577 | } 578 | break; 579 | case 'l': 580 | if (isDECPrivateMode) { 581 | // DECRST (DEC Reset Mode): 582 | decResetMode(vals, nVals); 583 | } else { 584 | // RM (Reset Mode): 585 | resetMode(vals, nVals); 586 | } 587 | break; 588 | case 'm': 589 | // SGR (Select Graphic Rendition): 590 | if (nVals == 0) 591 | nVals = 1; // vals[0] = 0 592 | selectGraphicRendition(vals, nVals); 593 | break; 594 | case 'n': 595 | // DSR (Device Status Report): 596 | v1 = (nVals == 0) ? 0 : vals[0]; 597 | deviceStatusReport(v1); 598 | break; 599 | case 'q': 600 | // DECLL (Load LEDS): 601 | v1 = (nVals == 0) ? 0 : vals[0]; 602 | loadLEDs(v1); 603 | break; 604 | case 'r': 605 | // DECSTBM (Set Top and Bottom Margins): 606 | v1 = (nVals == 0) ? 1 : vals[0]; 607 | v2 = (nVals <= 1) ? SC_H : vals[1]; 608 | setTopAndBottomMargins(v1, v2); 609 | break; 610 | case 'y': 611 | // DECTST (Invoke Confidence Test): 612 | if ((nVals > 1) && (vals[0] = 2)) 613 | invokeConfidenceTests(vals[1]); 614 | break; 615 | default: 616 | // unknown command 617 | unknownSequence(escMode, c); 618 | break; 619 | } 620 | clearParams(NONE); 621 | } 622 | return mp_const_none; 623 | }else if (escMode == LSC) { 624 | switch (c) { 625 | case '3': 626 | // DECDHL (Double Height Line): 627 | doubleHeightLine_TopHalf(); 628 | break; 629 | case '4': 630 | // DECDHL (Double Height Line): 631 | doubleHeightLine_BotomHalf(); 632 | break; 633 | case '5': 634 | // DECSWL (Single-width Line): 635 | singleWidthLine(); 636 | break; 637 | case '6': 638 | // DECDWL (Double-Width Line): 639 | doubleWidthLine(); 640 | break; 641 | case '8': 642 | // DECALN (Screen Alignment Display): 643 | screenAlignmentDisplay(); 644 | break; 645 | default: 646 | // 未確認のシーケンス 647 | unknownSequence(escMode, c); 648 | break; 649 | } 650 | clearParams(NONE); 651 | return mp_const_none; 652 | }else if (escMode == G0S) { 653 | // SCS (Select Character Set): G0 654 | setG0charset(c); 655 | clearParams(NONE); 656 | return mp_const_none; 657 | }else if(escMode == G1S) { 658 | // SCS (Select Character Set): G1 659 | setG1charset(c); 660 | clearParams(NONE); 661 | return mp_const_none; 662 | } 663 | 664 | 665 | if ((c == 0x0a) || (c == 0x0b) || (c == 0x0c)) { 666 | scroll(); 667 | return mp_const_none; 668 | } 669 | 670 | // (CR) 671 | if (c == 0x0d) { 672 | XP = 0; 673 | return mp_const_none; 674 | } 675 | if (c== 0x0e){//using g1 676 | mode.Flgs.g0g1 = 1; 677 | currentTextTable=G1TABLE; 678 | return mp_const_none; 679 | } 680 | if (c==0x0f){//using g0 681 | mode.Flgs.g0g1 = 0; 682 | currentTextTable=G0TABLE; 683 | return mp_const_none; 684 | } 685 | // (BS) 686 | if (c == 0x7f) { 687 | cursorBackward(1); 688 | uint16_t idx = YP * SC_W + XP; 689 | screen[idx] = 0; 690 | attrib[idx] = 0; 691 | colors[idx] = cColor.value; 692 | sc_updateChar(XP, YP); 693 | return mp_const_none; 694 | } 695 | 696 | if (c == 0x08) { 697 | cursorBackward(1); 698 | return mp_const_none; 699 | } 700 | // tab 701 | if (c == 0x09) { 702 | int16_t idx = -1; 703 | for (int16_t i = XP + 1; i < SC_W; i++) { 704 | if (tabs[i]) { 705 | idx = i; 706 | break; 707 | } 708 | } 709 | XP = (idx == -1) ? MAX_SC_X : idx; 710 | return mp_const_none; 711 | } 712 | 713 | // normal char 714 | if (XP < SC_W) { 715 | uint16_t idx = YP * SC_W + XP; 716 | if (mode_ex.Flgs.InsertMode){ 717 | // insert 718 | for (int16_t i = (YP+1) * SC_W - 1; i > idx; i--) { 719 | screen[i] = screen[i - 1]; 720 | attrib[i] = attrib[i - 1]; 721 | colors[i] = colors[i - 1]; 722 | } 723 | screen[idx] = c; 724 | attrib[idx] = cAttr.value; 725 | colors[idx] = cColor.value; 726 | for (int16_t i = XP; i < SC_W; i++) { 727 | sc_updateChar(i, YP); 728 | } 729 | }else{ 730 | screen[idx] = c; 731 | attrib[idx] = cAttr.value; 732 | colors[idx] = cColor.value; 733 | sc_updateChar(XP, YP); 734 | } 735 | 736 | } 737 | 738 | 739 | // return 740 | if (XP+1>=SC_W){ 741 | if (mode_ex.Flgs.WrapLine){ 742 | XP=0; 743 | scroll(); 744 | } 745 | 746 | else{ 747 | XP = MAX_SC_X; 748 | } 749 | 750 | }else{ 751 | XP++; 752 | } 753 | 754 | 755 | return mp_const_none; 756 | } 757 | 758 | static MP_DEFINE_CONST_FUN_OBJ_1(vt_printChar_obj, vt_printChar); 759 | 760 | 761 | 762 | 763 | 764 | static void saveCursor(void) { 765 | b_XP = XP; 766 | b_YP = YP; 767 | bAttr.value = cAttr.value; 768 | bColor.value = cColor.value; 769 | } 770 | 771 | // DECRC (Restore Cursor): 772 | static void restoreCursor(void){ 773 | XP = b_XP; 774 | YP = b_YP; 775 | cAttr.value = bAttr.value; 776 | cColor.value = bColor.value; 777 | } 778 | 779 | // DECKPAM (Keypad Application Mode): 780 | static void keypadApplicationMode(void) { 781 | return; 782 | } 783 | 784 | // DECKPNM (Keypad Numeric Mode): 785 | static void keypadNumericMode(void) { 786 | return; 787 | } 788 | 789 | 790 | 791 | 792 | // IND (Index): 793 | 794 | static void vindex(int16_t v) { 795 | cursorDown(v); 796 | } 797 | 798 | // NEL (Next Line): 799 | 800 | static void nextLine(void) { 801 | scroll(); 802 | } 803 | 804 | // HTS (Horizontal Tabulation Set): 805 | static void horizontalTabulationSet(void) { 806 | tabs[XP] = 1; 807 | } 808 | 809 | static void reverseIndex(int16_t v) { 810 | if (v <= 0) return; 811 | 812 | int targetYP = YP - v; 813 | 814 | if (targetYP < M_TOP) { 815 | int lines_to_scroll = v; 816 | 817 | int scroll_region_height = M_BOTTOM - M_TOP + 1; 818 | if (lines_to_scroll > scroll_region_height) 819 | lines_to_scroll = scroll_region_height; 820 | 821 | int lines_to_move = scroll_region_height - lines_to_scroll; 822 | 823 | if (lines_to_move > 0) { 824 | int n = SC_W * lines_to_move; 825 | int dst = SC_W * (M_TOP + lines_to_scroll); 826 | int src = SC_W * M_TOP; 827 | 828 | if (src >= 0 && dst >= 0 && 829 | src + n <= SC_W * SC_H && 830 | dst + n <= SC_W * SC_H) { 831 | memmove(&screen[dst], &screen[src], n); 832 | memmove(&attrib[dst], &attrib[src], n); 833 | memmove(&colors[dst], &colors[src], n); 834 | } 835 | } 836 | int top_idx = SC_W * M_TOP; 837 | int fill_len = SC_W * lines_to_scroll; 838 | 839 | if (top_idx >= 0 && top_idx + fill_len <= SC_W * SC_H) { 840 | memset(&screen[top_idx], 0x00, fill_len); 841 | memset(&attrib[top_idx], defaultAttr.value, fill_len); 842 | memset(&colors[top_idx], defaultColor.value, fill_len); 843 | } 844 | 845 | YP = M_TOP; 846 | 847 | for (int y = M_TOP; y <= M_BOTTOM; y++) { 848 | if (y >= 0 && y < SC_H) { 849 | sc_updateLine(y); 850 | } 851 | } 852 | } else { 853 | YP = targetYP; 854 | } 855 | } 856 | // RI (Reverse Index): 857 | 858 | // DECID (Identify): 859 | static void identify(void) { 860 | deviceAttributes(0); // same as DA (Device Attributes) 861 | } 862 | 863 | // RIS (Reset To Initial State) リセット 864 | static void resetToInitialState(void) { 865 | fill_rect_4bpp(fb, 0, 0, SC_PIXEL_WIDTH, SC_PIXEL_HEIGHT, defaultColor.Color.Background); 866 | initCursorAndAttribute(); 867 | eraseInDisplay(2); 868 | } 869 | 870 | 871 | // "[" Control Sequence Introducer (CSI) 872 | // ----------------------------------------------------------------------------- 873 | 874 | // CUU (Cursor Up): 875 | 876 | /* 877 | static void cursorUp(int16_t v) { 878 | if ((YP - v) <= M_TOP){ 879 | YP = M_TOP; 880 | }else{ 881 | YP -= v; 882 | } 883 | } 884 | */ 885 | // CUD (Cursor Down): 886 | 887 | static void cursorDown(int16_t v) { 888 | 889 | if ((YP+v)>M_BOTTOM){ 890 | YP = M_BOTTOM; 891 | }else{ 892 | YP += v; 893 | } 894 | } 895 | 896 | // CUF (Cursor Forward): 897 | static void cursorForward(int16_t v) { 898 | if ((XP+v)>=SC_W){ 899 | XP = MAX_SC_X; 900 | }else{ 901 | XP += v; 902 | } 903 | } 904 | 905 | // CUB (Cursor Backward): 906 | void cursorBackward(int16_t v) { 907 | if ((XP-v)<0){ 908 | XP=0; 909 | }else{ 910 | XP -=v; 911 | } 912 | } 913 | 914 | // CUP (Cursor Position): 915 | // HVP (Horizontal and Vertical Position): 916 | static void cursorPosition(uint8_t y, uint8_t x) { 917 | 918 | if ((y-1)>=SC_H){ 919 | YP = MAX_SC_Y; 920 | }else{ 921 | YP= y-1; 922 | } 923 | 924 | if ((x-1)>=SC_W){ 925 | XP = MAX_SC_X; 926 | }else{ 927 | XP = x -1; 928 | } 929 | 930 | } 931 | 932 | 933 | static void refreshScreen(void) { 934 | 935 | for (uint8_t i = 0; i < SC_H; i++){ 936 | sc_updateLine(i); 937 | } 938 | } 939 | 940 | 941 | static void eraseInDisplay(uint8_t m) { 942 | uint8_t sl = 0, el = 0; 943 | uint16_t idx = 0, n = 0; 944 | 945 | switch (m) { 946 | case 0: 947 | 948 | sl = YP; 949 | el = MAX_SC_Y; 950 | idx = YP * SC_W + XP; 951 | n = SCSIZE - (YP * SC_W + XP); 952 | break; 953 | case 1: 954 | 955 | sl = 0; 956 | el = YP; 957 | idx = 0; 958 | n = YP * SC_W + XP + 1; 959 | break; 960 | case 2: 961 | 962 | sl = 0; 963 | el = MAX_SC_Y; 964 | idx = 0; 965 | n = SCSIZE; 966 | break; 967 | } 968 | 969 | if (m <= 2) { 970 | memset(&screen[idx], 0x00, n); 971 | memset(&attrib[idx], defaultAttr.value, n); 972 | memset(&colors[idx], defaultColor.value, n); 973 | for (uint8_t i = sl; i <= el; i++) 974 | sc_updateLine(i); 975 | } 976 | } 977 | 978 | // EL (Erase In Line): 979 | static void eraseInLine(uint8_t m) { 980 | uint16_t slp = 0, elp = 0; 981 | 982 | switch (m) { 983 | case 0: 984 | // current to end 985 | slp = YP * SC_W + XP; 986 | elp = YP * SC_W + MAX_SC_X; 987 | break; 988 | case 1: 989 | // start to current 990 | slp = YP * SC_W; 991 | elp = YP * SC_W + XP; 992 | break; 993 | case 2: 994 | // whole line 995 | slp = YP * SC_W; 996 | elp = YP * SC_W + MAX_SC_X; 997 | break; 998 | } 999 | 1000 | if (m <= 2) { 1001 | uint16_t n = elp - slp + 1; 1002 | memset(&screen[slp], 0x00, n); 1003 | memset(&attrib[slp], defaultAttr.value, n); 1004 | memset(&colors[slp], cColor.value, n); 1005 | //memset(&colors[slp], defaultColor.value, n); 1006 | sc_updateLine(YP); 1007 | } 1008 | } 1009 | 1010 | // IL (Insert Line): 1011 | 1012 | static void insertLine(uint8_t v) { 1013 | int16_t rows = v; 1014 | if (rows == 0) return; 1015 | if (rows > ((M_BOTTOM + 1) - YP)) rows = (M_BOTTOM + 1) - YP; 1016 | int16_t idx = SC_W * YP; 1017 | int16_t n = SC_W * rows; 1018 | int16_t idx2 = idx + n; 1019 | int16_t move_rows = (M_BOTTOM + 1) - YP - rows; 1020 | int16_t n2 = SC_W * move_rows; 1021 | 1022 | if (move_rows > 0) { 1023 | memmove(&screen[idx2], &screen[idx], n2); 1024 | memmove(&attrib[idx2], &attrib[idx], n2); 1025 | memmove(&colors[idx2], &colors[idx], n2); 1026 | } 1027 | memset(&screen[idx], 0x00, n); 1028 | memset(&attrib[idx], defaultAttr.value, n); 1029 | memset(&colors[idx], defaultColor.value, n); 1030 | for (uint8_t y = YP; y <= M_BOTTOM; y++) 1031 | sc_updateLine(y); 1032 | } 1033 | 1034 | // DL (Delete Line): 1035 | 1036 | static void deleteLine(uint8_t v) { 1037 | int16_t rows = v; 1038 | if (rows == 0) return; 1039 | if (rows > ((M_BOTTOM + 1) - YP)) rows = (M_BOTTOM + 1) - YP; 1040 | int16_t idx = SC_W * YP; 1041 | int16_t n = SC_W * rows; 1042 | int16_t idx2 = idx + n; 1043 | int16_t move_rows = (M_BOTTOM + 1) - YP - rows; 1044 | int16_t n2 = SC_W * move_rows; 1045 | int16_t idx3 = (M_BOTTOM + 1) * SC_W - n; 1046 | 1047 | if (move_rows > 0) { 1048 | memmove(&screen[idx], &screen[idx2], n2); 1049 | memmove(&attrib[idx], &attrib[idx2], n2); 1050 | memmove(&colors[idx], &colors[idx2], n2); 1051 | } 1052 | memset(&screen[idx3], 0x00, n); 1053 | memset(&attrib[idx3], defaultAttr.value, n); 1054 | memset(&colors[idx3], defaultColor.value, n); 1055 | for (uint8_t y = YP; y <= M_BOTTOM; y++) 1056 | sc_updateLine(y); 1057 | } 1058 | 1059 | // CPR (Cursor Position Report): 1060 | static void cursorPositionReport(uint16_t y, uint16_t x) { 1061 | char temp[30]; 1062 | int32_t len = sprintf(temp, "\x1b[%d;%dR", SC_H, SC_W); 1063 | 1064 | if (outputLen + len <= sizeof(outputBuf)) { 1065 | memcpy(&(outputBuf[outputLen]), temp, len); 1066 | outputLen += len; 1067 | } 1068 | } 1069 | 1070 | // DA (Device Attributes): 1071 | 1072 | static void deviceAttributes(uint8_t m) { 1073 | 1074 | if (outputLen + 7 <= sizeof(outputBuf)) { 1075 | memcpy(&(outputBuf[outputLen]), "\e[?1;0c", 7); 1076 | outputLen += 7; 1077 | } 1078 | } 1079 | 1080 | // TBC (Tabulation Clear): 1081 | static void tabulationClear(uint8_t m) { 1082 | switch (m) { 1083 | case 0: 1084 | // current position 1085 | tabs[XP] = 0; 1086 | break; 1087 | case 3: 1088 | // all tabs 1089 | memset(tabs, 0x00, SC_W); 1090 | break; 1091 | } 1092 | } 1093 | 1094 | // LNM (Line Feed / New Line Mode): 1095 | static void lineMode(bool m) { 1096 | mode.Flgs.CrLf = m; 1097 | } 1098 | 1099 | // DECSCNM (Screen Mode): 1100 | static void screenMode(bool m) { 1101 | mode_ex.Flgs.ScreenReverse = m; 1102 | refreshScreen(); 1103 | } 1104 | 1105 | // DECAWM (Auto Wrap Mode): 1106 | static void autoWrapMode(bool m) { 1107 | mode_ex.Flgs.WrapLine = m; 1108 | } 1109 | 1110 | // SM (Set Mode): 1111 | static void setMode(int16_t *vals, int16_t nVals) { 1112 | for (int16_t i = 0; i < nVals; i++) { 1113 | switch (vals[i]) { 1114 | case 20: 1115 | // LNM (Line Feed / New Line Mode) 1116 | lineMode(true); 1117 | break; 1118 | case 4: 1119 | // IRM (Insert Mode): 1120 | mode_ex.Flgs.InsertMode = 1; 1121 | break; 1122 | default: 1123 | break; 1124 | } 1125 | } 1126 | } 1127 | 1128 | // DECSET (DEC Set Mode): 1129 | static void decSetMode(int16_t *vals, int16_t nVals) { 1130 | for (int16_t i = 0; i < nVals; i++) { 1131 | switch (vals[i]) { 1132 | case 5: 1133 | // DECSCNM (Screen Mode): 1134 | screenMode(true); 1135 | break; 1136 | case 7: 1137 | // DECAWM (Auto Wrap Mode): 1138 | autoWrapMode(true); 1139 | break; 1140 | 1141 | case 25: 1142 | // DECTCEM (Cursor Mode): 1143 | canShowCursor = true; 1144 | break; 1145 | default: 1146 | break; 1147 | } 1148 | } 1149 | } 1150 | 1151 | // RM (Reset Mode): 1152 | static void resetMode(int16_t *vals, int16_t nVals) { 1153 | for (int16_t i = 0; i < nVals; i++) { 1154 | switch (vals[i]) { 1155 | case 20: 1156 | // LNM (Line Feed / New Line Mode) 1157 | lineMode(false); 1158 | break; 1159 | 1160 | case 4: 1161 | // IRM (Insert Mode): 1162 | mode_ex.Flgs.InsertMode = 0; 1163 | break; 1164 | default: 1165 | break; 1166 | } 1167 | } 1168 | } 1169 | 1170 | // DECRST (DEC Reset Mode): 1171 | static void decResetMode(int16_t *vals, int16_t nVals) { 1172 | for (int16_t i = 0; i < nVals; i++) { 1173 | switch (vals[i]) { 1174 | case 5: 1175 | // DECSCNM (Screen Mode): 1176 | screenMode(false); 1177 | break; 1178 | case 7: 1179 | // DECAWM (Auto Wrap Mode): 1180 | autoWrapMode(false); 1181 | break; 1182 | case 25: 1183 | // DECTCEM (Cursor Mode): 1184 | canShowCursor = false; 1185 | sc_updateChar(p_XP, p_YP);//cover the hided character at cursor position 1186 | break; 1187 | default: 1188 | break; 1189 | } 1190 | } 1191 | } 1192 | 1193 | // SGR (Select Graphic Rendition): 1194 | static void selectGraphicRendition(int16_t *vals, int16_t nVals) { 1195 | uint8_t seq = 0; 1196 | uint16_t r, g, b, cIdx; 1197 | bool isFore = true; 1198 | for (int16_t i = 0; i < nVals; i++) { 1199 | int16_t v = vals[i]; 1200 | switch (seq) { 1201 | case 0: 1202 | switch (v) { 1203 | case 0: 1204 | // Reset all attributes 1205 | cAttr.value = 0; 1206 | cColor.value = defaultColor.value; 1207 | break; 1208 | case 1: 1209 | // Bold 1210 | cAttr.Bits.Bold = 1; 1211 | break; 1212 | case 4: 1213 | // char with underline 1214 | cAttr.Bits.Underline = 1; 1215 | break; 1216 | case 5: 1217 | // blink 1218 | cAttr.Bits.Blink = 1; 1219 | break; 1220 | case 7: 1221 | // reverse 1222 | cAttr.Bits.Reverse = 1; 1223 | break; 1224 | case 21: 1225 | // bold 1226 | cAttr.Bits.Bold = 0; 1227 | break; 1228 | case 22: 1229 | // bold remove 1230 | cAttr.Bits.Bold = 0; 1231 | break; 1232 | case 24: 1233 | // char with underline remove 1234 | cAttr.Bits.Underline = 0; 1235 | break; 1236 | case 25: 1237 | // blink remove 1238 | cAttr.Bits.Blink = 0; 1239 | break; 1240 | case 27: 1241 | // inverse remove 1242 | cAttr.Bits.Reverse = 0; 1243 | break; 1244 | case 38: 1245 | seq = 1; 1246 | isFore = true; 1247 | break; 1248 | case 39: 1249 | // front color recover 1250 | cColor.Color.Foreground = defaultColor.Color.Foreground; 1251 | break; 1252 | case 48: 1253 | seq = 1; 1254 | isFore = false; 1255 | break; 1256 | case 49: 1257 | // background recover 1258 | cColor.Color.Background = defaultColor.Color.Background; 1259 | break; 1260 | default: 1261 | if (v >= 30 && v <= 37) { 1262 | //front color 1263 | cColor.Color.Foreground = v - 30; 1264 | } else if (v >= 40 && v <= 47) { 1265 | // background color 1266 | cColor.Color.Background = v - 40; 1267 | } 1268 | break; 1269 | } 1270 | break; 1271 | case 1: 1272 | switch (v) { 1273 | case 2: 1274 | // RGB 1275 | seq = 3; 1276 | break; 1277 | case 5: 1278 | // Color Index 1279 | seq = 2; 1280 | break; 1281 | default: 1282 | seq = 0; 1283 | break; 1284 | } 1285 | break; 1286 | case 2: 1287 | // Index Color 1288 | if (v < 256) { 1289 | if (v < 16) { 1290 | // 16 color 1291 | cIdx = v; 1292 | } else if (v < 232) { 1293 | // 6x6x6 RGB 1294 | b = ( (v - 16) % 6) / 3; 1295 | g = (((v - 16) / 6) % 6) / 3; 1296 | r = (((v - 16) / 36) % 6) / 3; 1297 | cIdx = (b << 2) | (g << 1) | r; 1298 | } else { 1299 | // 244 color 1300 | if (v < 244) 1301 | cIdx = clBlack; 1302 | else 1303 | cIdx = clWhite; 1304 | } 1305 | if (isFore) 1306 | cColor.Color.Foreground = cIdx; 1307 | else 1308 | cColor.Color.Background = cIdx; 1309 | } 1310 | seq = 0; 1311 | break; 1312 | case 3: 1313 | // RGB - R 1314 | seq = 4; 1315 | break; 1316 | case 4: 1317 | // RGB - G 1318 | seq = 5; 1319 | break; 1320 | case 5: 1321 | // RGB - B 1322 | if (vals[i-2]>128){ 1323 | r = 1; 1324 | }else{ 1325 | r=0; 1326 | } 1327 | if (vals[i-1]>128){ 1328 | g = 1; 1329 | }else{ 1330 | g=0; 1331 | } 1332 | if (vals[i-0]>128){ 1333 | b = 1; 1334 | }else{ 1335 | b=0; 1336 | } 1337 | cIdx = (b << 2) | (g << 1) | r; 1338 | if (isFore) 1339 | cColor.Color.Foreground = cIdx; 1340 | else 1341 | cColor.Color.Background = cIdx; 1342 | seq = 0; 1343 | break; 1344 | default: 1345 | seq = 0; 1346 | break; 1347 | } 1348 | } 1349 | } 1350 | 1351 | // DSR (Device Status Report): 1352 | static void deviceStatusReport(uint8_t m) { 1353 | switch (m) { 1354 | case 5: 1355 | if (outputLen + 4 <= sizeof(outputBuf)) { 1356 | memcpy(&(outputBuf[outputLen]), "\e[0n", 4); 1357 | outputLen += 4; 1358 | } 1359 | 1360 | break; 1361 | case 6: 1362 | cursorPositionReport(XP, YP); // CPR (Cursor Position Report) 1363 | break; 1364 | } 1365 | } 1366 | 1367 | // DECLL (Load LEDS): 1368 | static void loadLEDs(uint8_t m) { 1369 | return; 1370 | 1371 | } 1372 | 1373 | // DECSTBM (Set Top and Bottom Margins): 1374 | static void setTopAndBottomMargins(int16_t s, int16_t e) { 1375 | if (e <= s) return; 1376 | M_TOP = s - 1; 1377 | if (M_TOP > MAX_SC_Y) M_TOP = MAX_SC_Y; 1378 | M_BOTTOM = e - 1; 1379 | if (M_BOTTOM > MAX_SC_Y) M_BOTTOM = MAX_SC_Y; 1380 | setCursorToHome(); 1381 | } 1382 | 1383 | // DECTST (Invoke Confidence Test): 1384 | static void invokeConfidenceTests(uint8_t m) { 1385 | return; 1386 | } 1387 | 1388 | // "]" Operating System Command (OSC) 1389 | // ----------------------------------------------------------------------------- 1390 | 1391 | // "#" Line Size Command 1392 | // ----------------------------------------------------------------------------- 1393 | 1394 | // DECDHL (Double Height Line): 1395 | static void doubleHeightLine_TopHalf(void) { 1396 | return; 1397 | } 1398 | 1399 | // DECDHL (Double Height Line): 1400 | static void doubleHeightLine_BotomHalf(void) { 1401 | return; 1402 | } 1403 | 1404 | // DECSWL (Single-width Line): 1405 | static void singleWidthLine(void) { 1406 | return; 1407 | } 1408 | 1409 | // DECDWL (Double-Width Line): 1410 | static void doubleWidthLine(void) { 1411 | return; 1412 | } 1413 | 1414 | // DECALN (Screen Alignment Display): 1415 | static void screenAlignmentDisplay(void) { 1416 | 1417 | memset(screen, 0x45, SCSIZE); 1418 | memset(attrib, defaultAttr.value, SCSIZE); 1419 | memset(colors, defaultColor.value, SCSIZE); 1420 | for (uint8_t y = 0; y < SC_H; y++) 1421 | sc_updateLine(y); 1422 | } 1423 | 1424 | // "(" G0 Sets Sequence 1425 | // ----------------------------------------------------------------------------- 1426 | 1427 | // G0 1428 | static void setG0charset(char c) { 1429 | return; 1430 | } 1431 | 1432 | // "(" G1 Sets Sequence 1433 | // ----------------------------------------------------------------------------- 1434 | 1435 | // G1 1436 | static void setG1charset(char c) { 1437 | return; 1438 | } 1439 | 1440 | // Unknown Sequence 1441 | // ----------------------------------------------------------------------------- 1442 | 1443 | 1444 | static void unknownSequence(uint8_t m, char c) { 1445 | return; 1446 | } 1447 | 1448 | 1449 | 1450 | 1451 | 1452 | 1453 | 1454 | 1455 | static void drawTxt6x8(uint8_t *fb,uint8_t c,int x0,int y0, uint8_t color){ 1456 | // extract arguments 1457 | int x; 1458 | int y; 1459 | if (c < 16 ) { 1460 | c = 32; 1461 | } 1462 | // get char data 1463 | const uint8_t *chr_data = ¤tTextTable[(c - 16) * CH_H]; 1464 | // loop over char data 1465 | y = y0; 1466 | for (; y < y0+CH_H; y++) { 1467 | if (0 <= y && y < SC_PIXEL_WIDTH) { 1468 | x = x0; 1469 | uint8_t line_data = *chr_data++; 1470 | for (;x> 1; 1485 | if (scroll_y1 < 0 || scroll_y2 >= SC_PIXEL_HEIGHT || n <= 0 || (scroll_y2 - scroll_y1 + 1) <= n) 1486 | return; 1487 | 1488 | for (int y = scroll_y1; y <= scroll_y2 - n; y++) { 1489 | uint8_t *dst_ptr = fb + y * row_bytes; 1490 | uint8_t *src_ptr = fb + (y + n) * row_bytes; 1491 | 1492 | for (int x = 0; x < row_bytes; x += 8) { 1493 | *dst_ptr++ = *src_ptr++; 1494 | *dst_ptr++ = *src_ptr++; 1495 | *dst_ptr++ = *src_ptr++; 1496 | *dst_ptr++ = *src_ptr++; 1497 | *dst_ptr++ = *src_ptr++; 1498 | *dst_ptr++ = *src_ptr++; 1499 | *dst_ptr++ = *src_ptr++; 1500 | *dst_ptr++ = *src_ptr++; 1501 | } 1502 | } 1503 | bg_color = (bg_color & 0x0F)|(bg_color<<4); //double the bg color as 2 pixels 1504 | for (int y = scroll_y2 - n + 1; y <= scroll_y2; y++) { 1505 | uint8_t *dst_ptr = fb + y * row_bytes; 1506 | for (int x = 0; x < row_bytes; x += 8) { 1507 | *dst_ptr++ = bg_color; 1508 | *dst_ptr++ = bg_color; 1509 | *dst_ptr++ = bg_color; 1510 | *dst_ptr++ = bg_color; 1511 | *dst_ptr++ = bg_color; 1512 | *dst_ptr++ = bg_color; 1513 | *dst_ptr++ = bg_color; 1514 | *dst_ptr++ = bg_color; 1515 | } 1516 | } 1517 | } 1518 | */ 1519 | static void fill_rect_4bpp(uint8_t *fb, int x, int y, int w, int h, uint8_t color){ 1520 | 1521 | int row_bytes = SC_PIXEL_WIDTH >> 1; 1522 | uint8_t fill_byte = (color << 4) | (color & 0x0F); 1523 | for (int row = y; row < y + h; row++) { 1524 | uint8_t *row_ptr = fb + row * row_bytes; 1525 | int pos = x; 1526 | int pixels_to_fill = w; 1527 | uint8_t *ptr = row_ptr + (pos >> 1); 1528 | if (pos & 1) { 1529 | *ptr = (*ptr & 0xF0) | (color & 0x0F); 1530 | pos++; 1531 | pixels_to_fill--; 1532 | ptr = row_ptr + (pos >> 1); 1533 | } 1534 | int full_bytes = pixels_to_fill >> 1; 1535 | int remaining_pixels = pixels_to_fill & 1; 1536 | while (full_bytes >= 3) { 1537 | *ptr++ = fill_byte; 1538 | *ptr++ = fill_byte; 1539 | *ptr++ = fill_byte; 1540 | full_bytes -= 3; 1541 | } 1542 | while (full_bytes--) { 1543 | *ptr++ = fill_byte; 1544 | } 1545 | 1546 | if (remaining_pixels) { 1547 | *ptr = (*ptr & 0x0F) | (color << 4); 1548 | } 1549 | } 1550 | } 1551 | 1552 | 1553 | static mp_obj_t vtterminal_init(mp_obj_t fb_obj){ 1554 | 1555 | mp_buffer_info_t buf_info; 1556 | mp_get_buffer_raise(fb_obj, &buf_info, MP_BUFFER_READ); 1557 | fb=(uint8_t *)buf_info.buf; 1558 | 1559 | currentTextTable=G0TABLE; 1560 | resetToInitialState(); 1561 | setCursorToHome(); 1562 | 1563 | //init the timer and callback 1564 | add_repeating_timer_ms(250, dispCursor, NULL, &cursor_timer); 1565 | return mp_const_true; 1566 | } 1567 | 1568 | static MP_DEFINE_CONST_FUN_OBJ_1(vt_init_obj, vtterminal_init); 1569 | 1570 | 1571 | 1572 | static mp_obj_t vt_read(void){ 1573 | 1574 | mp_obj_t result = mp_obj_new_str(outputBuf, outputLen); 1575 | outputLen = 0; 1576 | return result; 1577 | } 1578 | static MP_DEFINE_CONST_FUN_OBJ_0(vt_read_obj, vt_read); 1579 | 1580 | 1581 | 1582 | 1583 | static const mp_rom_map_elem_t vtterminal_globals_table[] = { 1584 | { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_vtterminal) }, 1585 | { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&vt_init_obj) }, 1586 | { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&vt_read_obj) }, 1587 | { MP_ROM_QSTR(MP_QSTR_printChar), MP_ROM_PTR(&vt_printChar_obj)} 1588 | }; 1589 | static MP_DEFINE_CONST_DICT(vtterminal_globals, vtterminal_globals_table); 1590 | 1591 | 1592 | const mp_obj_module_t vtterminal_cmodule = { 1593 | .base = { &mp_type_module }, 1594 | .globals = (mp_obj_dict_t*)&vtterminal_globals, 1595 | }; 1596 | 1597 | 1598 | MP_REGISTER_MODULE(MP_QSTR_vtterminal, vtterminal_cmodule); --------------------------------------------------------------------------------