├── .gitignore ├── .vscode ├── launch.json └── settings.json ├── CMakeLists.txt ├── Icon ├── ICONDATA.VMS ├── Icon.c ├── IconMono.c ├── VMU.bin ├── make_icon └── make_icon.cpp ├── LICENSE ├── README.md ├── hardware ├── EAGLE │ ├── maplepad_pro.brd │ └── maplepad_pro.sch ├── HW_LICENSE.txt ├── README.MD ├── maplepad_assembly.pdf ├── maplepad_bom.txt ├── maplepad_pcb.jpg ├── maplepad_pro.png ├── maplepad_pro_2022-07-15.zip └── maplepad_wiring.png ├── images ├── 20221206_124644.jpg ├── IMG_20221216_191824_862.jpg ├── IMG_20221216_191824_896.jpg ├── jamma_adapter.jpg ├── jamma_adapter_basic.jpg ├── jamma_adapter_lcd.jpg ├── jamma_demo.mp4 ├── jojo1.png ├── jojo2.png ├── jojo3.png ├── maplepad_logo.png ├── maplepad_logo_cream.png ├── maplepad_logo_shadow.png ├── mem1.jpg ├── mem2.jpg ├── mem3.jpg ├── purupuru.png ├── striker1.jpg ├── striker2.jpg ├── striker3.jpg ├── vmu.png └── yakara.png ├── pico_sdk_import.cmake └── src ├── display.c ├── display.h ├── font.c ├── font.h ├── format.c ├── format.h ├── maple.c ├── maple.h ├── maple.pio ├── menu.c ├── menu.h ├── sh8601.c ├── sh8601.h ├── ssd1306.c ├── ssd1306.h ├── ssd1331.c ├── ssd1331.h ├── st7789.c ├── st7789.h ├── state_machine.c └── state_machine.h /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .vscode/* 3 | build/* -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Pico Debug", 6 | "type":"cortex-debug", 7 | "cwd": "${workspaceRoot}", 8 | "executable": "${command:cmake.launchTargetPath}", 9 | "request": "launch", 10 | "servertype": "external", 11 | // This may need to be arm-none-eabi-gdb depending on your system 12 | "gdbpath" : "arm-none-eabi-gdb", 13 | // Connect to an already running OpenOCD instance 14 | "gdbTarget": "localhost:3333", 15 | "svdFile": "${env:PICO_SDK_PATH}/src/rp2040/hardware_regs/rp2040.svd", 16 | "runToMain": true, 17 | // Work around for stopping at main on restart 18 | "postRestartCommands": [ 19 | "break main", 20 | "continue" 21 | ] 22 | // Try not to stop at all 23 | //"postLaunchCommands": [ 24 | // "continue" 25 | //] 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cmake.configureOnOpen": true, 3 | "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", 4 | 5 | // These settings tweaks to the cmake plugin will ensure 6 | // that you debug using cortex-debug instead of trying to launch 7 | // a Pico binary on the host 8 | "cmake.statusbar.advanced": { 9 | "debug": { 10 | "visibility": "hidden" 11 | }, 12 | "launch": { 13 | "visibility": "hidden" 14 | }, 15 | //"build": { 16 | // "visibility": "hidden" 17 | //}, 18 | "buildTarget": { 19 | "visibility": "hidden" 20 | } 21 | }, 22 | "cmake.buildBeforeRun": true, 23 | "files.associations": { 24 | "flash.h": "c", 25 | "pio.h": "c", 26 | "pwm.h": "c", 27 | "cmath": "c", 28 | "*.tcc": "c", 29 | "cinttypes": "c", 30 | "cstdlib": "c", 31 | "math.h": "c", 32 | "string.h": "c", 33 | "i2c.h": "c", 34 | "stdio.h": "c", 35 | "ssd1306.h": "c", 36 | "ssd1331.h": "c", 37 | "spi.h": "c", 38 | "maple.h": "c", 39 | "adc.h": "c", 40 | "maple.pio.h": "c", 41 | "state_machine.h": "c", 42 | "irq.h": "c", 43 | "multicore.h": "c", 44 | "stdlib.h": "c", 45 | "time.h": "c", 46 | "timer.h": "c", 47 | "stdint.h": "c", 48 | "menu.h": "c", 49 | "binary_info.h": "c", 50 | "display.h": "c", 51 | "st7789.h": "c", 52 | "dma.h": "c" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | include(pico_sdk_import.cmake) 4 | 5 | project(maplepad C CXX ASM) 6 | 7 | set(CMAKE_C_STANDARD 11) 8 | set(CMAKE_CXX_STANDARD 17) 9 | 10 | pico_sdk_init() 11 | 12 | add_executable(maplepad) 13 | 14 | target_compile_definitions(maplepad PRIVATE PICO_HW) 15 | 16 | pico_add_extra_outputs(maplepad) 17 | 18 | pico_generate_pio_header(maplepad ${CMAKE_CURRENT_LIST_DIR}/src/maple.pio) 19 | 20 | target_sources(maplepad PRIVATE src/maple.c src/state_machine.c src/format.c src/display.c src/sh8601.c src/ssd1331.c src/ssd1306.c src/st7789.c src/font.c src/menu.c) 21 | 22 | 23 | target_link_libraries(maplepad PRIVATE 24 | pico_stdlib 25 | pico_multicore 26 | pico_time 27 | hardware_adc 28 | hardware_pio 29 | hardware_dma 30 | hardware_pwm 31 | hardware_timer 32 | hardware_i2c 33 | hardware_spi 34 | hardware_flash 35 | ) 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Icon/ICONDATA.VMS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/Icon/ICONDATA.VMS -------------------------------------------------------------------------------- /Icon/Icon.c: -------------------------------------------------------------------------------- 1 | /* GIMP RGBA C-Source image dump (vmu_icon.c) */ 2 | 3 | static const struct { 4 | unsigned int width; 5 | unsigned int height; 6 | unsigned int bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */ 7 | unsigned char pixel_data[32 * 32 * 4 + 1]; 8 | } Icon = { 9 | 32, 32, 4, 10 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 11 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 12 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 13 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 14 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 15 | "\000\000\000\000\333\331\332\377\333\331\332\377\333\331\332\377\333\331\332\377" 16 | "\333\331\332\377\333\331\332\377\333\331\332\377\333\331\332\377\000\000\000\000" 17 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 18 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 19 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\333\331\332\377\333\331\332\377\333\331" 20 | "\332\377\333\331\332\377\333\331\332\377\333\331\332\377\333\331\332\377" 21 | "\333\331\332\377\333\331\332\377\333\331\332\377\333\331\332\377\333\331" 22 | "\332\377\333\331\332\377\333\331\332\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 23 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 24 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\333\331\332\377\333\331\332\377\314\311" 25 | "\312\377\314\311\312\377\314\311\312\377\314\311\312\377\314\311\312\377" 26 | "\314\311\312\377\314\311\312\377\333\331\332\377\333\331\332\377\333\331" 27 | "\332\377\333\331\332\377\333\331\332\377\333\331\332\377\314\311\312\377" 28 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 29 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\314\311\312\377\314\311" 30 | "\312\377\314\311\312\377\333\331\332\377\333\331\332\377\333\331\332\377" 31 | "\333\331\332\377\333\331\332\377\333\331\332\377\333\331\332\377\314\311" 32 | "\312\377\314\311\312\377\314\311\312\377\333\331\332\377\333\331\332\377" 33 | "\333\331\332\377\333\331\332\377\314\311\312\377\000\000\000\000\000\000\000\000\000\000\000\000" 34 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 35 | "\000\000\000\000\000\000\000\000\333\331\332\377\333\331\332\377\333\331\332\377\333\331" 36 | "\332\377\333\331\332\377\333\331\332\377\333\331\332\377\333\331\332\377" 37 | "\333\331\332\377\333\331\332\377\333\331\332\377\333\331\332\377\333\331" 38 | "\332\377\314\311\312\377\314\311\312\377\333\331\332\377\333\331\332\377" 39 | "\314\311\312\377\314\311\312\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 40 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\333\331\332\377" 41 | "\333\331\332\377\333\331\332\377\333\331\332\377\333\331\332\377\333\331" 42 | "\332\377\333\331\332\377\333\331\332\377\333\331\332\377\333\331\332\377" 43 | "\333\331\332\377\333\331\332\377\333\331\332\377\333\331\332\377\333\331" 44 | "\332\377\333\331\332\377\314\311\312\377\314\311\312\377\314\311\312\377" 45 | "\314\311\312\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 46 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\333\331\332\377\333\331\332\377" 47 | "\333\331\332\377l\211\211\377l\211\211\377l\211\211\377\271\300\301\377\271" 48 | "\300\301\377\312\314\315\377\316\320\321\377\316\320\321\377\333\331\332" 49 | "\377\333\331\332\377\333\331\332\377\333\331\332\377\333\331\332\377\333" 50 | "\331\332\377\314\311\312\377\314\311\312\377\314\311\312\377\000\000\000\000\000\000" 51 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 52 | "\000\000\333\331\332\377\333\331\332\377\333\331\332\377l\211\211\377l\211\211" 53 | "\377l\211\211\377l\211\211\377l\211\211\377l\211\211\377l\211\211\377l\211" 54 | "\211\377l\211\211\377\271\300\301\377\312\314\315\377\316\320\321\377\333" 55 | "\331\332\377\333\331\332\377\333\331\332\377\314\311\312\377\314\311\312" 56 | "\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 57 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\333\331\332\377\333\331\332\377\316\320\321" 58 | "\377l\211\211\377\000\000\000\377l\211\211\377l\211\211\377l\211\211\377l\211\211" 59 | "\377l\211\211\377l\211\211\377l\211\211\377l\211\211\377l\211\211\377Zrr" 60 | "\377\333\331\332\377\333\331\332\377\333\331\332\377\314\311\312\377\314" 61 | "\311\312\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 62 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\333\331\332\377\333\331\332\377\333\331\332" 63 | "\377l\211\211\377l\211\211\377l\211\211\377\000\000\000\377l\211\211\377l\211\211" 64 | "\377l\211\211\377l\211\211\377\000\000\000\377\000\000\000\377l\211\211\377l\211\211" 65 | "\377Zrr\377\333\331\332\377\333\331\332\377\333\331\332\377\314\311\312\377" 66 | "\314\311\312\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 67 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\333\331\332\377\333\331\332\377\316\320" 68 | "\321\377l\211\211\377\000\000\000\377\000\000\000\377l\211\211\377l\211\211\377l\211" 69 | "\211\377l\211\211\377\000\000\000\377l\211\211\377l\211\211\377l\211\211\377Zr" 70 | "r\377\316\320\321\377\333\331\332\377\333\331\332\377\314\311\312\377\314" 71 | "\311\312\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 72 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\333\331\332\377\333\331\332\377\333\331\332" 73 | "\377l\211\211\377l\211\211\377l\211\211\377l\211\211\377l\211\211\377l\211" 74 | "\211\377l\211\211\377l\211\211\377l\211\211\377\000\000\000\377l\211\211\377l\211" 75 | "\211\377Zrr\377\333\331\332\377\333\331\332\377\333\331\332\377\314\311\312" 76 | "\377\314\311\312\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 77 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\333\331\332\377\333\331\332\377\316" 78 | "\320\321\377l\211\211\377l\211\211\377l\211\211\377\000\000\000\377l\211\211\377" 79 | "l\211\211\377l\211\211\377\000\000\000\377l\211\211\377l\211\211\377l\211\211\377" 80 | "Zrr\377\316\320\321\377\333\331\332\377\333\331\332\377\314\311\312\377\314" 81 | "\311\312\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 82 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\333\331\332\377\333\331\332\377\333\331\332" 83 | "\377l\211\211\377l\211\211\377l\211\211\377l\211\211\377l\211\211\377\000\000" 84 | "\000\377\000\000\000\377\000\000\000\377l\211\211\377l\211\211\377l\211\211\377l\211\211" 85 | "\377Zrr\377\333\331\332\377\333\331\332\377\333\331\332\377\314\311\312\377" 86 | "\314\311\312\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 87 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\333\331\332\377\333\331\332\377\333\331" 88 | "\332\377Zrr\377Zrr\377Zrr\377l\211\211\377l\211\211\377l\211\211\377l\211" 89 | "\211\377\377\000\000\377l\211\211\377l\211\211\377l\211\211\377Zrr\377\316\320" 90 | "\321\377\333\331\332\377\333\331\332\377\314\311\312\377\314\311\312\377" 91 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 92 | "\000\000\000\000\000\000\000\000\333\331\332\377\333\331\332\377\333\331\332\377\333\331" 93 | "\332\377\333\331\332\377\333\331\332\377\316\320\321\377Zrr\377Zrr\377Zr" 94 | "r\377Zrr\377l\211\211\377l\211\211\377l\211\211\377l\211\211\377Zrr\377\333" 95 | "\331\332\377\333\331\332\377\333\331\332\377\314\311\312\377\314\311\312" 96 | "\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 97 | "\000\000\000\000\000\000\000\000\000\000\333\331\332\377\333\331\332\377\224\234\314\377\224" 98 | "\234\314\377\224\234\314\377\333\331\332\377\333\331\332\377\333\331\332" 99 | "\377\333\331\332\377\316\320\321\377\316\320\321\377Zrr\377Zrr\377Zrr\377" 100 | "Zrr\377\316\320\321\377\333\331\332\377\333\331\332\377\314\311\312\377\314" 101 | "\311\312\377\314\311\312\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 102 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\333\331\332\377\333\331\332\377\224" 103 | "\234\314\377\224\234\314\377\224\234\314\377\224\234\314\377\206\216\267" 104 | "\377\333\331\332\377\333\331\332\377\333\331\332\377\333\331\332\377\333" 105 | "\331\332\377\333\331\332\377\316\320\321\377\316\320\321\377\316\320\321" 106 | "\377\333\331\332\377\333\331\332\377\333\331\332\377\314\311\312\377\314" 107 | "\311\312\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 108 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\333\331\332\377\333\331\332\377\224\234\314" 109 | "\377\224\234\314\377\224\234\314\377\224\234\314\377\206\216\267\377\314" 110 | "\311\312\377\333\331\332\377\224\234\314\377\333\331\332\377\333\331\332" 111 | "\377\224\234\314\377\333\331\332\377\333\331\332\377\333\331\332\377\333" 112 | "\331\332\377\333\331\332\377\314\311\312\377\314\311\312\377\314\311\312" 113 | "\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 114 | "\000\000\000\000\000\000\333\331\332\377\333\331\332\377\333\331\332\377\206\216\267" 115 | "\377\224\234\314\377\224\234\314\377\206\216\267\377\206\216\267\377\314" 116 | "\311\312\377\333\331\332\377\333\331\332\377\333\331\332\377\333\331\332" 117 | "\377\333\331\332\377\333\331\332\377\333\331\332\377\333\331\332\377\333" 118 | "\331\332\377\333\331\332\377\314\311\312\377\314\311\312\377\000\000\000\000\000\000" 119 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 120 | "\000\000\333\331\332\377\333\331\332\377\333\331\332\377\314\311\312\377\206" 121 | "\216\267\377\206\216\267\377\206\216\267\377\314\311\312\377\333\331\332" 122 | "\377\271\274\323\377\224\234\314\377\271\274\323\377\333\331\332\377\271" 123 | "\274\323\377\224\234\314\377\271\274\323\377\333\331\332\377\333\331\332" 124 | "\377\314\311\312\377\314\311\312\377\314\311\312\377\000\000\000\000\000\000\000\000\000\000" 125 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\333" 126 | "\331\332\377\333\331\332\377\333\331\332\377\333\331\332\377\314\311\312" 127 | "\377\314\311\312\377\314\311\312\377\333\331\332\377\333\331\332\377\224" 128 | "\234\314\377\224\234\314\377\206\216\267\377\333\331\332\377\224\234\314" 129 | "\377\224\234\314\377\206\216\267\377\314\311\312\377\333\331\332\377\314" 130 | "\311\312\377\314\311\312\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 131 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\333\331\332\377\333" 132 | "\331\332\377\333\331\332\377\333\331\332\377\333\331\332\377\333\331\332" 133 | "\377\333\331\332\377\333\331\332\377\333\331\332\377\271\274\323\377\206" 134 | "\216\267\377\253\256\306\377\314\311\312\377\271\274\323\377\206\216\267" 135 | "\377\253\256\306\377\314\311\312\377\314\311\312\377\314\311\312\377\314" 136 | "\311\312\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 137 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\314\311\312\377\333\331\332\377\333" 138 | "\331\332\377\333\331\332\377\333\331\332\377\333\331\332\377\333\331\332" 139 | "\377\333\331\332\377\333\331\332\377\333\331\332\377\314\311\312\377\314" 140 | "\311\312\377\333\331\332\377\333\331\332\377\314\311\312\377\314\311\312" 141 | "\377\314\311\312\377\314\311\312\377\314\311\312\377\314\311\312\377\000\000" 142 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 143 | "\000\000\000\000\000\000\000\000\000\000\304\302\303\377\314\311\312\377\314\311\312\377\333" 144 | "\331\332\377\333\331\332\377\333\331\332\377\333\331\332\377\333\331\332" 145 | "\377\333\331\332\377\333\331\332\377\333\331\332\377\333\331\332\377\333" 146 | "\331\332\377\333\331\332\377\333\331\332\377\333\331\332\377\314\311\312" 147 | "\377\314\311\312\377\314\311\312\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 148 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 149 | "\000\000\304\302\303\377\314\311\312\377\314\311\312\377\314\311\312\377\314" 150 | "\311\312\377\333\331\332\377\333\331\332\377\333\331\332\377\333\331\332" 151 | "\377\333\331\332\377\333\331\332\377\333\331\332\377\333\331\332\377\333" 152 | "\331\332\377\333\331\332\377\314\311\312\377\314\311\312\377\314\311\312" 153 | "\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 154 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\304\302\303\377\304" 155 | "\302\303\377\250\246\247\377\250\246\247\377\314\311\312\377\314\311\312" 156 | "\377\314\311\312\377\333\331\332\377\333\331\332\377\333\331\332\377\333" 157 | "\331\332\377\333\331\332\377\314\311\312\377\314\311\312\377\314\311\312" 158 | "\377\304\302\303\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 159 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 160 | "\000\000\000\000\000\000\000\000\000\000\304\302\303\377\304\302\303\377\250\246\247\377\250" 161 | "\246\247\377\250\246\247\377\314\311\312\377\314\311\312\377\314\311\312" 162 | "\377\314\311\312\377\314\311\312\377\314\311\312\377\314\311\312\377\304" 163 | "\302\303\377\304\302\303\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 164 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 165 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\304\302\303\377\304\302\303" 166 | "\377\304\302\303\377\304\302\303\377\304\302\303\377\314\311\312\377\314" 167 | "\311\312\377\314\311\312\377\304\302\303\377\304\302\303\377\304\302\303" 168 | "\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 169 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 170 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\304\302\303\377\304" 171 | "\302\303\377\304\302\303\377\304\302\303\377\304\302\303\377\304\302\303" 172 | "\377\304\302\303\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 173 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 174 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 175 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 176 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 177 | "\000\000\000\000\000\000\000\000\000\000", 178 | }; 179 | 180 | -------------------------------------------------------------------------------- /Icon/IconMono.c: -------------------------------------------------------------------------------- 1 | /* GIMP RGBA C-Source image dump (vmu_icon_mono.c) */ 2 | 3 | static const struct { 4 | unsigned int width; 5 | unsigned int height; 6 | unsigned int bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */ 7 | unsigned char pixel_data[32 * 32 * 4 + 1]; 8 | } IconMono = { 9 | 32, 32, 4, 10 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 11 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 12 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 13 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 14 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 15 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 16 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 17 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 18 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 19 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 20 | "\377\377\377\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000" 21 | "\377\000\000\000\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377" 22 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 23 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 24 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 25 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 26 | "\377\377\377\377\377\377\377\377\000\000\000\377\377\377\377\377\377\377\377\377" 27 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 28 | "\377\377\377\377\377\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" 29 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 30 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 31 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 32 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377" 33 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 34 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 35 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 36 | "\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 37 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 38 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 39 | "\377\377\377\377\377\377\377\377\000\000\000\377\377\377\377\377\377\377\377\377" 40 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 41 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 42 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 43 | "\377\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 44 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 45 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 46 | "\377\377\377\377\377\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377" 47 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 48 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 49 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 50 | "\377\377\377\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377" 51 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 52 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 53 | "\000\000\000\377\377\377\377\377\377\377\377\377\000\000\000\377\000\000\000\377\000\000\000\377" 54 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 55 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 56 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377" 57 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 58 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 59 | "\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377\377\377" 60 | "\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\000\000" 61 | "\000\377\000\000\000\377\000\000\000\377\000\000\000\377\377\377\377\377\377\377\377\377\377" 62 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 63 | "\377\000\000\000\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377" 64 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 65 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377" 66 | "\377\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 67 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 68 | "\377\377\377\377\000\000\000\377\000\000\000\377\000\000\000\377\377\377\377\377\377\377\377" 69 | "\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377\377\377\377\377\377" 70 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 71 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 72 | "\377\377\377\377\377\000\000\000\377\377\377\377\377\000\000\000\377\377\377\377\377" 73 | "\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 74 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 75 | "\377\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000" 76 | "\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 77 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 78 | "\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377\377\377\000" 79 | "\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377" 80 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\000\000\000" 81 | "\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377\377\377\377\377\377" 82 | "\377\377\377\377\377\000\000\000\377\000\000\000\377\377\377\377\377\377\377\377\377" 83 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 84 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 85 | "\000\000\000\377\377\377\377\377\000\000\000\377\377\377\377\377\000\000\000\377\000\000\000\377" 86 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377" 87 | "\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377\377\377" 88 | "\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377\377\377" 89 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 90 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 91 | "\377\377\377\377\000\000\000\377\377\377\377\377\000\000\000\377\377\377\377\377\377" 92 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 93 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377\377" 94 | "\377\377\377\377\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377" 95 | "\377\000\000\000\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377" 96 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 97 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377" 98 | "\377\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000" 99 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377\377" 100 | "\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377\377\377\377\377\377" 101 | "\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377\377\377\377\377\377" 102 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 103 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 104 | "\377\000\000\000\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377\377\377" 105 | "\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\000\000\000\377\000\000" 106 | "\000\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\000" 107 | "\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\000\000\000" 108 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 109 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 110 | "\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377\377\377\377\377\377" 111 | "\377\000\000\000\377\000\000\000\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377" 112 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 113 | "\377\377\377\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377" 114 | "\377\377\377\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377" 115 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 116 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377" 117 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 118 | "\377\377\377\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\377\377\377\377" 119 | "\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377\377\377" 120 | "\377\377\377\377\377\377\377\377\000\000\000\377\000\000\000\377\377\377\377\377\377" 121 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 122 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 123 | "\377\377\377\000\000\000\377\377\377\377\377\000\000\000\377\000\000\000\377\000\000\000\377\377" 124 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 125 | "\377\377\377\377\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\377\377\377" 126 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\000\000\000\377" 127 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 128 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 129 | "\377\377\377\377\000\000\000\377\377\377\377\377\000\000\000\377\000\000\000\377\000\000\000\377" 130 | "\000\000\000\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 131 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 132 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 133 | "\377\377\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 134 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 135 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377\377" 136 | "\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\377\377\377\377\377" 137 | "\377\377\377\000\000\000\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377" 138 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 139 | "\377\377\377\377\000\000\000\377\000\000\000\377\377\377\377\377\377\377\377\377\377" 140 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 141 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377\377" 142 | "\377\377\377\377\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\377" 143 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 144 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 145 | "\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377\377\377\377" 146 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 147 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 148 | "\377\377\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377\000" 149 | "\000\000\377\000\000\000\377\000\000\000\377\377\377\377\377\377\377\377\377\000\000\000\377\000" 150 | "\000\000\377\000\000\000\377\377\377\377\377\000\000\000\377\000\000\000\377\000\000\000\377\377\377" 151 | "\377\377\377\377\377\377\377\377\377\377\000\000\000\377\000\000\000\377\377\377\377" 152 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 153 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 154 | "\377\377\377\377\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377" 155 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 156 | "\377\377\377\000\000\000\377\000\000\000\377\000\000\000\377\377\377\377\377\000\000\000\377\000\000" 157 | "\000\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377" 158 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 159 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 160 | "\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377\377\377" 161 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 162 | "\377\377\377\377\377\377\377\377\377\377\000\000\000\377\000\000\000\377\000\000\000\377\377" 163 | "\377\377\377\000\000\000\377\000\000\000\377\000\000\000\377\377\377\377\377\377\377\377\377" 164 | "\000\000\000\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 165 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 166 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000" 167 | "\000\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 168 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 169 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 170 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\000" 171 | "\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 172 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 173 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\000\000\000" 174 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 175 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 176 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 177 | "\377\377\377\377\377\377\377\000\000\000\377\000\000\000\377\377\377\377\377\377\377" 178 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 179 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 180 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\000\000\000" 181 | "\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 182 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 183 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 184 | "\377\000\000\000\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377" 185 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 186 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 187 | "\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\000\000\000\377\000\000" 188 | "\000\377\000\000\000\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377" 189 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 190 | "\377\377\377\377\377\377\000\000\000\377\000\000\000\377\377\377\377\377\377\377\377" 191 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 192 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 193 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 194 | "\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\000\000\000\377\000\000\000\377" 195 | "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\377\377\377\377\377\377\377\377" 196 | "\377\377\377\377\377\377\377\377\000\000\000\377\000\000\000\377\000\000\000\377\377\377\377" 197 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 198 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 199 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 200 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 201 | "\377\377\377\377\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000" 202 | "\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\377\377\377\377" 203 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 204 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 205 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 206 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 207 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 208 | "\377\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000" 209 | "\000\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 210 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 211 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 212 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 213 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 214 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 215 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 216 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 217 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 218 | "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" 219 | "\377", 220 | }; 221 | 222 | -------------------------------------------------------------------------------- /Icon/make_icon: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/Icon/make_icon -------------------------------------------------------------------------------- /Icon/make_icon.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "Icon.c" 7 | #include "IconMono.c" 8 | #include "../src/format.h" 9 | 10 | struct IconData 11 | { 12 | char Comment[16]; 13 | uint32_t MonochromeOffset; 14 | uint32_t ColourOffset; 15 | uint32_t Padding[2]; 16 | uint8_t Monochrome[32 * 32 * 1 / 8]; 17 | uint16_t Palette[16]; 18 | uint8_t Colour[32 * 32 * 4 / 8]; 19 | }; 20 | 21 | IconData VMU; 22 | uint8_t Padding[1024]; 23 | 24 | int main() 25 | { 26 | memset(Padding, 0xFF, sizeof(Padding)); 27 | 28 | strncpy(VMU.Comment, "Visual Memory ", sizeof(VMU.Comment)); 29 | VMU.MonochromeOffset = offsetof(IconData, Monochrome); 30 | VMU.ColourOffset = offsetof(IconData, Palette); 31 | for (int y = 0; y < 32; y++) 32 | { 33 | for (int x = 0; x < 32; x++) 34 | { 35 | if (IconMono.pixel_data[4 * (y * 32 + x)] == 0) 36 | { 37 | VMU.Monochrome[(y * 32 + x) / 8] |= 1 << (7 - (x & 7)); 38 | } 39 | } 40 | } 41 | 42 | uint32_t Palette32[16]; 43 | int NumEntries = 0; 44 | for (int y = 0; y < 32; y++) 45 | { 46 | for (int x = 0; x < 32; x++) 47 | { 48 | uint32_t Pixel = *(uint32_t *)&Icon.pixel_data[4 * (y * 32 + x)]; 49 | int Index; 50 | for (Index = 0; Index < NumEntries; Index++) 51 | { 52 | if (Pixel == Palette32[Index]) 53 | { 54 | break; 55 | } 56 | } 57 | if (Index == NumEntries) 58 | { 59 | if (NumEntries >= 16) 60 | { 61 | printf("Too many unique colours\n"); 62 | return 1; 63 | } 64 | VMU.Palette[NumEntries] = (((Pixel >> 28) & 0xF) << 12); 65 | VMU.Palette[NumEntries] |= (((Pixel >> 4) & 0xF) << 8); 66 | VMU.Palette[NumEntries] |= (((Pixel >> 12) & 0xF) << 4); 67 | VMU.Palette[NumEntries] |= (((Pixel >> 20) & 0xF) << 0); 68 | Palette32[NumEntries++] = Pixel; 69 | } 70 | VMU.Colour[(y * 32 + x) * 4 / 8] |= (x & 1) ? Index : (Index << 4); 71 | } 72 | } 73 | 74 | FILE* f=fopen("ICONDATA.VMS", "wb"); 75 | if (f) 76 | { 77 | fwrite(&VMU, sizeof(VMU), 1, f); 78 | fwrite(&Padding, sizeof(Padding) - sizeof(VMU), 1, f); 79 | fclose(f); 80 | } 81 | else 82 | { 83 | printf("Couldn't open ICONDATA.VMS\n"); 84 | return 1; 85 | } 86 | 87 | uint8_t MemoryCard[128 * 1024]; 88 | memset(MemoryCard, 0, sizeof(MemoryCard)); 89 | //CheckFormatted(MemoryCard); 90 | f = fopen("VMU.bin", "wb"); 91 | if (f) 92 | { 93 | fwrite(&MemoryCard, sizeof(MemoryCard), 1, f); 94 | fclose(f); 95 | } 96 | else 97 | { 98 | printf("Couldn't open VMU.bin\n"); 99 | } 100 | 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Attribution 4.0 International 2 | 3 | ======================================================================= 4 | 5 | Creative Commons Corporation ("Creative Commons") is not a law firm and 6 | does not provide legal services or legal advice. Distribution of 7 | Creative Commons public licenses does not create a lawyer-client or 8 | other relationship. Creative Commons makes its licenses and related 9 | information available on an "as-is" basis. Creative Commons gives no 10 | warranties regarding its licenses, any material licensed under their 11 | terms and conditions, or any related information. Creative Commons 12 | disclaims all liability for damages resulting from their use to the 13 | fullest extent possible. 14 | 15 | Using Creative Commons Public Licenses 16 | 17 | Creative Commons public licenses provide a standard set of terms and 18 | conditions that creators and other rights holders may use to share 19 | original works of authorship and other material subject to copyright 20 | and certain other rights specified in the public license below. The 21 | following considerations are for informational purposes only, are not 22 | exhaustive, and do not form part of our licenses. 23 | 24 | Considerations for licensors: Our public licenses are 25 | intended for use by those authorized to give the public 26 | permission to use material in ways otherwise restricted by 27 | copyright and certain other rights. Our licenses are 28 | irrevocable. Licensors should read and understand the terms 29 | and conditions of the license they choose before applying it. 30 | Licensors should also secure all rights necessary before 31 | applying our licenses so that the public can reuse the 32 | material as expected. Licensors should clearly mark any 33 | material not subject to the license. This includes other CC- 34 | licensed material, or material used under an exception or 35 | limitation to copyright. More considerations for licensors: 36 | wiki.creativecommons.org/Considerations_for_licensors 37 | 38 | Considerations for the public: By using one of our public 39 | licenses, a licensor grants the public permission to use the 40 | licensed material under specified terms and conditions. If 41 | the licensor's permission is not necessary for any reason--for 42 | example, because of any applicable exception or limitation to 43 | copyright--then that use is not regulated by the license. Our 44 | licenses grant only permissions under copyright and certain 45 | other rights that a licensor has authority to grant. Use of 46 | the licensed material may still be restricted for other 47 | reasons, including because others have copyright or other 48 | rights in the material. A licensor may make special requests, 49 | such as asking that all changes be marked or described. 50 | Although not required by our licenses, you are encouraged to 51 | respect those requests where reasonable. More considerations 52 | for the public: 53 | wiki.creativecommons.org/Considerations_for_licensees 54 | 55 | ======================================================================= 56 | 57 | Creative Commons Attribution 4.0 International Public License 58 | 59 | By exercising the Licensed Rights (defined below), You accept and agree 60 | to be bound by the terms and conditions of this Creative Commons 61 | Attribution 4.0 International Public License ("Public License"). To the 62 | extent this Public License may be interpreted as a contract, You are 63 | granted the Licensed Rights in consideration of Your acceptance of 64 | these terms and conditions, and the Licensor grants You such rights in 65 | consideration of benefits the Licensor receives from making the 66 | Licensed Material available under these terms and conditions. 67 | 68 | 69 | Section 1 -- Definitions. 70 | 71 | a. Adapted Material means material subject to Copyright and Similar 72 | Rights that is derived from or based upon the Licensed Material 73 | and in which the Licensed Material is translated, altered, 74 | arranged, transformed, or otherwise modified in a manner requiring 75 | permission under the Copyright and Similar Rights held by the 76 | Licensor. For purposes of this Public License, where the Licensed 77 | Material is a musical work, performance, or sound recording, 78 | Adapted Material is always produced where the Licensed Material is 79 | synched in timed relation with a moving image. 80 | 81 | b. Adapter's License means the license You apply to Your Copyright 82 | and Similar Rights in Your contributions to Adapted Material in 83 | accordance with the terms and conditions of this Public License. 84 | 85 | c. Copyright and Similar Rights means copyright and/or similar rights 86 | closely related to copyright including, without limitation, 87 | performance, broadcast, sound recording, and Sui Generis Database 88 | Rights, without regard to how the rights are labeled or 89 | categorized. For purposes of this Public License, the rights 90 | specified in Section 2(b)(1)-(2) are not Copyright and Similar 91 | Rights. 92 | 93 | d. Effective Technological Measures means those measures that, in the 94 | absence of proper authority, may not be circumvented under laws 95 | fulfilling obligations under Article 11 of the WIPO Copyright 96 | Treaty adopted on December 20, 1996, and/or similar international 97 | agreements. 98 | 99 | e. Exceptions and Limitations means fair use, fair dealing, and/or 100 | any other exception or limitation to Copyright and Similar Rights 101 | that applies to Your use of the Licensed Material. 102 | 103 | f. Licensed Material means the artistic or literary work, database, 104 | or other material to which the Licensor applied this Public 105 | License. 106 | 107 | g. Licensed Rights means the rights granted to You subject to the 108 | terms and conditions of this Public License, which are limited to 109 | all Copyright and Similar Rights that apply to Your use of the 110 | Licensed Material and that the Licensor has authority to license. 111 | 112 | h. Licensor means the individual(s) or entity(ies) granting rights 113 | under this Public License. 114 | 115 | i. Share means to provide material to the public by any means or 116 | process that requires permission under the Licensed Rights, such 117 | as reproduction, public display, public performance, distribution, 118 | dissemination, communication, or importation, and to make material 119 | available to the public including in ways that members of the 120 | public may access the material from a place and at a time 121 | individually chosen by them. 122 | 123 | j. Sui Generis Database Rights means rights other than copyright 124 | resulting from Directive 96/9/EC of the European Parliament and of 125 | the Council of 11 March 1996 on the legal protection of databases, 126 | as amended and/or succeeded, as well as other essentially 127 | equivalent rights anywhere in the world. 128 | 129 | k. You means the individual or entity exercising the Licensed Rights 130 | under this Public License. Your has a corresponding meaning. 131 | 132 | 133 | Section 2 -- Scope. 134 | 135 | a. License grant. 136 | 137 | 1. Subject to the terms and conditions of this Public License, 138 | the Licensor hereby grants You a worldwide, royalty-free, 139 | non-sublicensable, non-exclusive, irrevocable license to 140 | exercise the Licensed Rights in the Licensed Material to: 141 | 142 | a. reproduce and Share the Licensed Material, in whole or 143 | in part; and 144 | 145 | b. produce, reproduce, and Share Adapted Material. 146 | 147 | 2. Exceptions and Limitations. For the avoidance of doubt, where 148 | Exceptions and Limitations apply to Your use, this Public 149 | License does not apply, and You do not need to comply with 150 | its terms and conditions. 151 | 152 | 3. Term. The term of this Public License is specified in Section 153 | 6(a). 154 | 155 | 4. Media and formats; technical modifications allowed. The 156 | Licensor authorizes You to exercise the Licensed Rights in 157 | all media and formats whether now known or hereafter created, 158 | and to make technical modifications necessary to do so. The 159 | Licensor waives and/or agrees not to assert any right or 160 | authority to forbid You from making technical modifications 161 | necessary to exercise the Licensed Rights, including 162 | technical modifications necessary to circumvent Effective 163 | Technological Measures. For purposes of this Public License, 164 | simply making modifications authorized by this Section 2(a) 165 | (4) never produces Adapted Material. 166 | 167 | 5. Downstream recipients. 168 | 169 | a. Offer from the Licensor -- Licensed Material. Every 170 | recipient of the Licensed Material automatically 171 | receives an offer from the Licensor to exercise the 172 | Licensed Rights under the terms and conditions of this 173 | Public License. 174 | 175 | b. No downstream restrictions. You may not offer or impose 176 | any additional or different terms or conditions on, or 177 | apply any Effective Technological Measures to, the 178 | Licensed Material if doing so restricts exercise of the 179 | Licensed Rights by any recipient of the Licensed 180 | Material. 181 | 182 | 6. No endorsement. Nothing in this Public License constitutes or 183 | may be construed as permission to assert or imply that You 184 | are, or that Your use of the Licensed Material is, connected 185 | with, or sponsored, endorsed, or granted official status by, 186 | the Licensor or others designated to receive attribution as 187 | provided in Section 3(a)(1)(A)(i). 188 | 189 | b. Other rights. 190 | 191 | 1. Moral rights, such as the right of integrity, are not 192 | licensed under this Public License, nor are publicity, 193 | privacy, and/or other similar personality rights; however, to 194 | the extent possible, the Licensor waives and/or agrees not to 195 | assert any such rights held by the Licensor to the limited 196 | extent necessary to allow You to exercise the Licensed 197 | Rights, but not otherwise. 198 | 199 | 2. Patent and trademark rights are not licensed under this 200 | Public License. 201 | 202 | 3. To the extent possible, the Licensor waives any right to 203 | collect royalties from You for the exercise of the Licensed 204 | Rights, whether directly or through a collecting society 205 | under any voluntary or waivable statutory or compulsory 206 | licensing scheme. In all other cases the Licensor expressly 207 | reserves any right to collect such royalties. 208 | 209 | 210 | Section 3 -- License Conditions. 211 | 212 | Your exercise of the Licensed Rights is expressly made subject to the 213 | following conditions. 214 | 215 | a. Attribution. 216 | 217 | 1. If You Share the Licensed Material (including in modified 218 | form), You must: 219 | 220 | a. retain the following if it is supplied by the Licensor 221 | with the Licensed Material: 222 | 223 | i. identification of the creator(s) of the Licensed 224 | Material and any others designated to receive 225 | attribution, in any reasonable manner requested by 226 | the Licensor (including by pseudonym if 227 | designated); 228 | 229 | ii. a copyright notice; 230 | 231 | iii. a notice that refers to this Public License; 232 | 233 | iv. a notice that refers to the disclaimer of 234 | warranties; 235 | 236 | v. a URI or hyperlink to the Licensed Material to the 237 | extent reasonably practicable; 238 | 239 | b. indicate if You modified the Licensed Material and 240 | retain an indication of any previous modifications; and 241 | 242 | c. indicate the Licensed Material is licensed under this 243 | Public License, and include the text of, or the URI or 244 | hyperlink to, this Public License. 245 | 246 | 2. You may satisfy the conditions in Section 3(a)(1) in any 247 | reasonable manner based on the medium, means, and context in 248 | which You Share the Licensed Material. For example, it may be 249 | reasonable to satisfy the conditions by providing a URI or 250 | hyperlink to a resource that includes the required 251 | information. 252 | 253 | 3. If requested by the Licensor, You must remove any of the 254 | information required by Section 3(a)(1)(A) to the extent 255 | reasonably practicable. 256 | 257 | 4. If You Share Adapted Material You produce, the Adapter's 258 | License You apply must not prevent recipients of the Adapted 259 | Material from complying with this Public License. 260 | 261 | 262 | Section 4 -- Sui Generis Database Rights. 263 | 264 | Where the Licensed Rights include Sui Generis Database Rights that 265 | apply to Your use of the Licensed Material: 266 | 267 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right 268 | to extract, reuse, reproduce, and Share all or a substantial 269 | portion of the contents of the database; 270 | 271 | b. if You include all or a substantial portion of the database 272 | contents in a database in which You have Sui Generis Database 273 | Rights, then the database in which You have Sui Generis Database 274 | Rights (but not its individual contents) is Adapted Material; and 275 | 276 | c. You must comply with the conditions in Section 3(a) if You Share 277 | all or a substantial portion of the contents of the database. 278 | 279 | For the avoidance of doubt, this Section 4 supplements and does not 280 | replace Your obligations under this Public License where the Licensed 281 | Rights include other Copyright and Similar Rights. 282 | 283 | 284 | Section 5 -- Disclaimer of Warranties and Limitation of Liability. 285 | 286 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE 287 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS 288 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF 289 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, 290 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, 291 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR 292 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, 293 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT 294 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT 295 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. 296 | 297 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE 298 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, 299 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, 300 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, 301 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR 302 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN 303 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR 304 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR 305 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. 306 | 307 | c. The disclaimer of warranties and limitation of liability provided 308 | above shall be interpreted in a manner that, to the extent 309 | possible, most closely approximates an absolute disclaimer and 310 | waiver of all liability. 311 | 312 | 313 | Section 6 -- Term and Termination. 314 | 315 | a. This Public License applies for the term of the Copyright and 316 | Similar Rights licensed here. However, if You fail to comply with 317 | this Public License, then Your rights under this Public License 318 | terminate automatically. 319 | 320 | b. Where Your right to use the Licensed Material has terminated under 321 | Section 6(a), it reinstates: 322 | 323 | 1. automatically as of the date the violation is cured, provided 324 | it is cured within 30 days of Your discovery of the 325 | violation; or 326 | 327 | 2. upon express reinstatement by the Licensor. 328 | 329 | For the avoidance of doubt, this Section 6(b) does not affect any 330 | right the Licensor may have to seek remedies for Your violations 331 | of this Public License. 332 | 333 | c. For the avoidance of doubt, the Licensor may also offer the 334 | Licensed Material under separate terms or conditions or stop 335 | distributing the Licensed Material at any time; however, doing so 336 | will not terminate this Public License. 337 | 338 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public 339 | License. 340 | 341 | 342 | Section 7 -- Other Terms and Conditions. 343 | 344 | a. The Licensor shall not be bound by any additional or different 345 | terms or conditions communicated by You unless expressly agreed. 346 | 347 | b. Any arrangements, understandings, or agreements regarding the 348 | Licensed Material not stated herein are separate from and 349 | independent of the terms and conditions of this Public License. 350 | 351 | 352 | Section 8 -- Interpretation. 353 | 354 | a. For the avoidance of doubt, this Public License does not, and 355 | shall not be interpreted to, reduce, limit, restrict, or impose 356 | conditions on any use of the Licensed Material that could lawfully 357 | be made without permission under this Public License. 358 | 359 | b. To the extent possible, if any provision of this Public License is 360 | deemed unenforceable, it shall be automatically reformed to the 361 | minimum extent necessary to make it enforceable. If the provision 362 | cannot be reformed, it shall be severed from this Public License 363 | without affecting the enforceability of the remaining terms and 364 | conditions. 365 | 366 | c. No term or condition of this Public License will be waived and no 367 | failure to comply consented to unless expressly agreed to by the 368 | Licensor. 369 | 370 | d. Nothing in this Public License constitutes or may be interpreted 371 | as a limitation upon, or waiver of, any privileges and immunities 372 | that apply to the Licensor or You, including from the legal 373 | processes of any jurisdiction or authority. 374 | 375 | 376 | ======================================================================= 377 | 378 | Creative Commons is not a party to its public 379 | licenses. Notwithstanding, Creative Commons may elect to apply one of 380 | its public licenses to material it publishes and in those instances 381 | will be considered the “Licensor.” The text of the Creative Commons 382 | public licenses is dedicated to the public domain under the CC0 Public 383 | Domain Dedication. Except for the limited purpose of indicating that 384 | material is shared under a Creative Commons public license or as 385 | otherwise permitted by the Creative Commons policies published at 386 | creativecommons.org/policies, Creative Commons does not authorize the 387 | use of the trademark "Creative Commons" or any other trademark or logo 388 | of Creative Commons without its prior written consent including, 389 | without limitation, in connection with any unauthorized modifications 390 | to any of its public licenses or any other arrangements, 391 | understandings, or agreements concerning use of licensed material. For 392 | the avoidance of doubt, this paragraph does not form part of the 393 | public licenses. 394 | 395 | Creative Commons may be contacted at creativecommons.org. 396 | 397 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MaplePad🍁
2 | 3 | 4 | 5 | MaplePad is an all-in-one Dreamcast controller, VMU, and Purupuru (rumble pack) emulator for Dreamcast portables and custom Dreamcast controllers. It runs on RP2040 and is usable with the Raspberry Pi Pico as well as custom MaplePad PCBs. See the [hardware folder](https://github.com/mackieks/MaplePad/tree/main/hardware) for a wiring diagram. 6 | 7 | **Note:** MaplePad is still a WIP. You may experience issues with [Windows CE games](https://segaretro.org/Windows_CE). In almost all problematic titles, disabling VMU and rumble through the MaplePad menu will make the game playable. Check out the [Compatibility List](https://docs.google.com/spreadsheets/d/1JzTGN29Ci8SeuSGkQHLN1p6ayQNWUcsNw77SMujkjbs/edit?usp=sharing) for details! 8 | 9 | ## Features 10 | With MaplePad you can cycle through 8 200-block internal VMUs with custom icons and colors, use an I2C or SPI OLED display to see the VMU screen in color and at 2x integer scale, and enjoy rumble that is 1:1 with the Performance TremorPak in most retail software (still some minor bugs!) 11 | 12 | 13 | 14 | ### Feature List: 15 | - [x] Full FT0 (controller) support including analog joystick and triggers 16 | - [x] Full FT1 (storage) support for savegames with 1600 blocks of space 17 | - [x] Multipaging for memory card (8 separate 200-block memory cards) 18 | - [x] Full FT2 (LCD) support with SSD1331 96\*64 color SPI OLED for VMU display (monochrome SSD1306 128\*64 I2C OLED also supported) 19 | - [x] Customizable color palettes for all 8 internal memory cards 20 | - [x] Robust FT8 (vibration) functionality (WIP) 21 | - [x] Robust FT3 (timer/RTC) reporting for compatibility purposes (no RTC) 22 | - [x] Basic menu on SSD1306 and SSD1331 OLED for configuring MaplePad behavior (WIP) 23 | 24 | ### To-do: 25 | Release v1.6 is gated by the following TODOs 26 | - [ ] Finish menu (button test, VMU palette editor, misc. bugs) 27 | - [ ] Address issues with non-CE games (Crazy Taxi, Blue Stinger, Powerstone 2) 28 | - [ ] Finish FT8 (vibration) continuous vibration and AST 29 | 30 | Future TODOs 31 | - [ ] Fix compatibility with Windows CE games 32 | - [ ] Implement 'fancy' VMU color palettes (gradients, animated backgrounds, etc.) 33 | - [ ] Implement option for DC boot animation on OLED 34 | - [ ] Add external RTC for true FT3 (timer/RTC) support 35 | - [ ] Implement FT4 (microphone) support 36 | 37 | ## Project Showcase 38 | *StrikerDC MaplePad mod by Wesk* 39 | 40 | 41 | 42 | *MaplePad Arcade Controller with VMU de GamesCare. [link](https://gamescare.com.br/produto/controle-arcade-dreamcast-tela-de-vmu-e-8-vmus-virtuais-na-placa-maple-board/), [video](https://www.youtube.com/watch?v=b0IbSASR3B4/)* 43 | 44 | 45 | 46 | *Mini Arcade Stick de Mundo Yakara Colombia. Excellent video that showcases MaplePad v1.5 features! [video](https://www.youtube.com/watch?v=jbHO3rEyzZU)* 47 | 48 | 49 | 50 | *Mini plug'n'play virtual memory card by jounge. [link](https://tieba.baidu.com/p/8465994390)* 51 | 52 | 53 | 54 | *Various JAMMA Dreamcast adapters available on AliExpress. [link 1](https://www.aliexpress.us/item/3256805216279752.html), [link 2](https://www.aliexpress.us/item/3256804674679708.html), [video](https://www.youtube.com/shorts/UciW3vM-KWo) (flashing lights warning!)* 55 | 56 | 57 | 58 | *Giant Dreamcast VMU + Arcade Stick by CrazyJojo (code modified). [video](https://www.youtube.com/watch?v=bEA_On7P_g8)* 59 | 60 | 61 | 62 | ## Dumping VMUs to PC 63 | You can use [picotool](https://github.com/raspberrypi/picotool) to dump VMUs manually. Here's the process: 64 | 65 | - Put RP2040 into programming mode with BOOTSEL button and connect it to your PC 66 | - Use picotool to dump whichever VMU page you want: `picotool save -r 10020000 10040000 dump1.bin` 67 | ![image](https://user-images.githubusercontent.com/49252894/211163335-2463ae14-043e-40be-aa93-1a09b1a620f9.png) 68 | - VMUs start at 0x10020000 and each one is 0x20000 long. So to save page 7, for example, you'd use 69 | `picotool save -r 100E0000 10100000 dump7.bin` 70 | - Open dump in [VMU Explorer](https://segaretro.org/VMU_Explorer) 71 | ![image](https://user-images.githubusercontent.com/49252894/211163284-d4100301-11ad-459c-8d29-5afbde9b49f5.png) 72 | 73 | ## License 74 | Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License. 75 | 76 | Share — copy and redistribute the material in any medium or format
77 | Adapt — remix, transform, and build upon the material for any purpose, even commercially.
78 | Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made.
79 | 80 | MaplePad is forked from [Charlie Cole's Pop'n Music Controller.](https://github.com/charcole/Dreamcast-PopnMusic) 81 | 82 | Special thanks: [Charlie Cole](https://github.com/charcole), [Colton Pawielski](https://github.com/cepawiel) and [Wesk](https://www.youtube.com/channel/UCYAwbbBxi5_LK8WVrD10SUw). 83 | -------------------------------------------------------------------------------- /hardware/HW_LICENSE.txt: -------------------------------------------------------------------------------- 1 | Solderpad Hardware License v2.1 2 | 3 | This license operates as a wraparound license to the Apache License 4 | Version 2.0 (the “Apache License”) and incorporates the terms and 5 | conditions of the Apache License(which can be found here: 6 | http://apache.org/licenses/LICENSE-2.0), with the following additions 7 | and modifications. It must be read in conjunction with the Apache 8 | License. Section 1 below modifies definitions and terminology in the 9 | Apache License and Section 2 below replaces Section 2 of the Apache 10 | License. The Appendix replaces the Appendix in the Apache License. You 11 | may, at your option, choose to treat any Work released under this 12 | license as released under the Apache License (thus ignoring all 13 | sections written below entirely). 14 | 15 | 1. Terminology in the Apache License is supplemented or modified as 16 | follows: 17 | 18 | “Authorship”: any reference to ‘authorship’ shall be taken to 19 | read “authorship or design”. 20 | 21 | “Copyright owner”: any reference to ‘copyright owner’ shall be taken 22 | to read “Rights owner”. 23 | 24 | “Copyright statement”: the reference to ‘copyright statement’ shall be 25 | taken to read ‘copyright or other statement pertaining to Rights’. 26 | 27 | The following new definition shall be added to the Definitions section 28 | of the Apache License: 29 | 30 | “Rights” means copyright and any similar right including design right 31 | (whether registered or unregistered), rights in semiconductor 32 | topographies (mask works) and database rights (but excluding Patents 33 | and Trademarks). 34 | 35 | The following definitions shall replace the corresponding definitions 36 | in the Apache License: 37 | 38 | “License” shall mean this Solderpad Hardware License version 2.1, 39 | being the terms and conditions for use, manufacture, instantiation, 40 | adaptation, reproduction, and distribution as defined by Sections 1 41 | through 9 of this document. 42 | 43 | “Licensor” shall mean the owner of the Rights or entity authorized by 44 | the owner of the Rights that is granting the License. 45 | 46 | “Derivative Works” shall mean any work, whether in Source or Object 47 | form, that is based on (or derived from) the Work and for which the 48 | editorial revisions, annotations, elaborations, or other 49 | modifications represent, as a whole, an original work of authorship 50 | or design. For the purposes of this License, Derivative Works shall 51 | not include works that remain reversibly separable from, or merely 52 | link (or bind by name) or physically connect to or interoperate with 53 | the Work and Derivative Works thereof. 54 | 55 | “Object” form shall mean any form resulting from mechanical 56 | transformation or translation of a Source form or the application of 57 | a Source form to physical material, including but not limited to 58 | compiled object code, generated documentation, the instantiation of 59 | a hardware design or physical object or material and conversions to 60 | other media types, including intermediate forms such as bytecodes, 61 | FPGA bitstreams, moulds, artwork and semiconductor topographies 62 | (mask works). 63 | 64 | “Source” form shall mean the preferred form for making modifications, 65 | including but not limited to source code, net lists, board layouts, 66 | CAD files, documentation source, and configuration files. 67 | 68 | “Work” shall mean the work of authorship or design, whether in Source 69 | or Object form, made available under the License, as indicated by a 70 | notice relating to Rights that is included in or attached to the 71 | work (an example is provided in the Appendix below). 72 | 73 | 2. Grant of License. Subject to the terms and conditions of this 74 | License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | license under the Rights to reproduce, prepare Derivative Works of, 77 | make, adapt, repair, publicly display, publicly perform, sublicense, 78 | and distribute the Work and such Derivative Works in Source or Object 79 | form and do anything in relation to the Work as if the Rights did not 80 | exist. 81 | 82 | APPENDIX 83 | 84 | Copyright 2024 Mackie Kannard-Smith SPDX-License-Identifier: Apache-2.0 85 | WITH SHL-2.1 86 | 87 | Licensed under the Solderpad Hardware License v 2.1 88 | (the “License”); you may not use this file except in compliance with 89 | the License, or, at your option, the Apache License version 2.0. You 90 | may obtain a copy of the License at 91 | 92 | https://solderpad.org/licenses/SHL-2.1/ 93 | 94 | Unless required by applicable law or agreed to in writing, any work 95 | distributed under the License is distributed on an “AS IS” BASIS, 96 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 97 | implied. See the License for the specific language governing 98 | permissions and limitations under the License. 99 | -------------------------------------------------------------------------------- /hardware/README.MD: -------------------------------------------------------------------------------- 1 | # Raspberry Pi Pico 2 | 3 | Wiring diagram for Raspberry Pi Pico: 4 | 5 | 6 | 7 | Notes: 8 | - Do not connect a USB cable to the Pico when it is connected to the Dreamcast. (5V will backfeed to console!) 9 | - The official Raspberry Pi Pico must be modded to access the right trigger pin (ADC3). See the wiring diagram for details. 10 | - For rumble, use an N-channel FET with VGS(th) < 3V and Id ≥ 1A. Both large Xbox-style ERMs and coin-type vibration motors work well. 11 | - You can add a freewheel diode between 5V and the NFET's drain if you'd like, but it's not necessary for prototyping. 12 | - Connect OLED_SEL to GND to select the SSD1306 OLED. Leave floating to select the SSD1331 OLED. 13 | - When wiring the SSD1306 I2C OLED, SDA and SCL need to be swapped and will not match the silkscreen on the OLED PCB. See the wiring diagram for details. 14 | - The SSD1331 SPI OLED runs at a high clock speed. Use at least 34AWG wire and keep the wires short and direct. 15 | 16 | # MaplePad 17 | 18 | Replacement Dreamcast controller PCB for portablizing, using RP2040. EAGLE source, Gerbers, BOM and assembly drawing are available in this directory. (Photo below is of the previous revision which lacked the BOOTSEL button.) 19 | 20 | 21 | 22 | Recommended board fabrication specs: 23 | - 0.8mm 2-layer PCB 24 | - ENIG (for chipscale BGAs) 25 | - Red soldermask - optional, but in keeping with the Japanese maple theme :) 26 | 27 | JLCPCB may grow the drills under the flash to meet their spec-- this is OK. Also please note that the extremely small castellations often result in many 'crushed barrels' that require manual cleanup. 28 | 29 | 30 | 31 | Features: 32 | - [x] 18.5 x 22.4mm 2-layer PCB 33 | - [x] USB-C and BOOTSEL button for programming 34 | - [x] Full Dreamcast controller compatibility 35 | - [x] Analog joystick and triggers 36 | - [x] VMU emulation (8-page VMU, 1600 blocks total) 37 | - [x] SPI/I2C OLED for VMU screen 38 | - [x] Rumble (Purupuru) support (WIP) 39 | - [x] Power from 1.8V - 5.5V 40 | 41 | What it doesn't support: 42 | - [ ] Dual analog sticks 43 | - [ ] Dreamcast Microphone 44 | - [ ] Dreamcast Keyboard, Mouse, or Fishing Controller 45 | 46 | A future version may support these features. 47 | -------------------------------------------------------------------------------- /hardware/maplepad_assembly.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/hardware/maplepad_assembly.pdf -------------------------------------------------------------------------------- /hardware/maplepad_bom.txt: -------------------------------------------------------------------------------- 1 | Part Value Device Package 2 | C1 10uF C-USC0402 C0402 3 | C2 15pF C-USC0201 C0201 4 | C3 15pF C-USC0201 C0201 5 | C4 10uF C-USC0402 C0402 6 | C5 0.1uF C-USC0201 C0201 7 | C6 0.1uF C-USC0201 C0201 8 | C7 0.1uF C-USC0201 C0201 9 | C8 0.1uF C-USC0201 C0201 10 | C9 0.1uF C-USC0201 C0201 11 | C10 0.1uF C-USC0201 C0201 12 | C11 0.1uF C-USC0201 C0201 13 | C12 1uF C-USC0402 C0402 14 | C13 0.1uF C-USC0201 C0201 15 | C14 0.1uF C-USC0201 C0201 16 | C15 1uF C-USC0402 C0402 17 | C16 2.2uF C-USC0402 C0402 18 | IC1 RP2040_QFN56 RP2040_QFN56 QFN56_7MM_REDUCEDEPAD 19 | J2 2171790001 2171790001 2171790001_MOL 20 | L1 MCEE1005T1R0MHN L0402 R0402 21 | R1 10k R-US_R0201 R0201 22 | R2 5.1k R-US_R0201 R0201 23 | R3 1k R-US_R0201 R0201 24 | R4 10k R-US_R0201 R0201 25 | R6 200 R-US_R0201 R0201 26 | R7 22 R-US_R0201 R0201 27 | R8 22 R-US_R0201 R0201 28 | R9 4.7k R-US_R0201 R0201 29 | R10 4.7k R-US_R0201 R0201 30 | R11 5.1k R-US_R0201 R0201 31 | R12 0-ohm for I2C OLED R-US_R0201 R0201 32 | R13 10k R-US_R0201 R0201 33 | R14 1k R-US_R0201 R0201 34 | S1 GSNAN0T000101 GSNAN0T000101 GSNAN0T000101 35 | U$1 ISL9122A ISL9122A ISL9122A 36 | U$25 W25Q128JVYIQ-TR W25Q128JVYIQ-TR WLCSP24 37 | U1 CSD17585F5T CSD17585F5T YJK3_TEX 38 | Y1 12MHZ FA-20H 12.0000MD30Z-K3 CRYSTAL_2.5X2 -------------------------------------------------------------------------------- /hardware/maplepad_pcb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/hardware/maplepad_pcb.jpg -------------------------------------------------------------------------------- /hardware/maplepad_pro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/hardware/maplepad_pro.png -------------------------------------------------------------------------------- /hardware/maplepad_pro_2022-07-15.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/hardware/maplepad_pro_2022-07-15.zip -------------------------------------------------------------------------------- /hardware/maplepad_wiring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/hardware/maplepad_wiring.png -------------------------------------------------------------------------------- /images/20221206_124644.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/20221206_124644.jpg -------------------------------------------------------------------------------- /images/IMG_20221216_191824_862.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/IMG_20221216_191824_862.jpg -------------------------------------------------------------------------------- /images/IMG_20221216_191824_896.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/IMG_20221216_191824_896.jpg -------------------------------------------------------------------------------- /images/jamma_adapter.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/jamma_adapter.jpg -------------------------------------------------------------------------------- /images/jamma_adapter_basic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/jamma_adapter_basic.jpg -------------------------------------------------------------------------------- /images/jamma_adapter_lcd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/jamma_adapter_lcd.jpg -------------------------------------------------------------------------------- /images/jamma_demo.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/jamma_demo.mp4 -------------------------------------------------------------------------------- /images/jojo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/jojo1.png -------------------------------------------------------------------------------- /images/jojo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/jojo2.png -------------------------------------------------------------------------------- /images/jojo3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/jojo3.png -------------------------------------------------------------------------------- /images/maplepad_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/maplepad_logo.png -------------------------------------------------------------------------------- /images/maplepad_logo_cream.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/maplepad_logo_cream.png -------------------------------------------------------------------------------- /images/maplepad_logo_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/maplepad_logo_shadow.png -------------------------------------------------------------------------------- /images/mem1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/mem1.jpg -------------------------------------------------------------------------------- /images/mem2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/mem2.jpg -------------------------------------------------------------------------------- /images/mem3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/mem3.jpg -------------------------------------------------------------------------------- /images/purupuru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/purupuru.png -------------------------------------------------------------------------------- /images/striker1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/striker1.jpg -------------------------------------------------------------------------------- /images/striker2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/striker2.jpg -------------------------------------------------------------------------------- /images/striker3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/striker3.jpg -------------------------------------------------------------------------------- /images/vmu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/vmu.png -------------------------------------------------------------------------------- /images/yakara.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mackieks/MaplePad/89016439d79ddd38a000acd8309e6143d7d0ec8c/images/yakara.png -------------------------------------------------------------------------------- /pico_sdk_import.cmake: -------------------------------------------------------------------------------- 1 | # This is a copy of /external/pico_sdk_import.cmake 2 | 3 | # This can be dropped into an external project to help locate this SDK 4 | # It should be include()ed prior to project() 5 | 6 | # todo document 7 | 8 | if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) 9 | set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) 10 | message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") 11 | endif () 12 | 13 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) 14 | set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) 15 | message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") 16 | endif () 17 | 18 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) 19 | set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) 20 | message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") 21 | endif () 22 | 23 | set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the PICO SDK") 24 | set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of PICO SDK from git if not otherwise locatable") 25 | set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") 26 | 27 | if (NOT PICO_SDK_PATH) 28 | if (PICO_SDK_FETCH_FROM_GIT) 29 | include(FetchContent) 30 | set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) 31 | if (PICO_SDK_FETCH_FROM_GIT_PATH) 32 | get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") 33 | endif () 34 | FetchContent_Declare( 35 | pico_sdk 36 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk 37 | GIT_TAG master 38 | ) 39 | if (NOT pico_sdk) 40 | message("Downloading PICO SDK") 41 | FetchContent_Populate(pico_sdk) 42 | set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) 43 | endif () 44 | set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) 45 | else () 46 | message(FATAL_ERROR 47 | "PICO SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." 48 | ) 49 | endif () 50 | endif () 51 | 52 | get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") 53 | if (NOT EXISTS ${PICO_SDK_PATH}) 54 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") 55 | endif () 56 | 57 | set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) 58 | if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) 59 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the PICO SDK") 60 | endif () 61 | 62 | set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the PICO SDK" FORCE) 63 | 64 | include(${PICO_SDK_INIT_CMAKE_FILE}) 65 | -------------------------------------------------------------------------------- /src/display.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "pico/stdlib.h" 10 | #include "pico/binary_info.h" 11 | #include "hardware/spi.h" 12 | #include "hardware/dma.h" 13 | 14 | #include "maple.h" 15 | #include "menu.h" 16 | #include "font.h" 17 | 18 | extern tFont Font; 19 | 20 | float cos_32s(float x); 21 | 22 | float cos32(float x); 23 | 24 | float sin32(float x); 25 | 26 | double atan_66s(double x); 27 | 28 | double atan66(double x); 29 | 30 | void fast_hsv2rgb_32bit(uint16_t h, uint8_t s, uint8_t v, uint8_t *r, uint8_t *g, uint8_t *b); 31 | 32 | void setPixel(uint8_t x, uint8_t y, uint16_t color); 33 | 34 | void drawEllipse(uint8_t xc, uint8_t yc, uint8_t xr, uint8_t yr, int angle, uint16_t color, bool fill); 35 | 36 | void drawLine(int x0, int y0, int w, uint16_t color); 37 | 38 | void hagl_draw_line(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color); 39 | 40 | void fillRect(int x0, int x1, int y0, int y1, uint16_t color); 41 | 42 | void fillCircle(int x0, int y0, int r, uint16_t color); 43 | 44 | void drawCursor(int iy, uint16_t color); 45 | 46 | void drawToggle(int iy, uint16_t color, bool on); 47 | 48 | void putLetter(int ix, int iy, int index, uint16_t color); 49 | 50 | void putString(char *text, int ix, int iy, uint16_t color); 51 | 52 | void updateDisplay(void); 53 | 54 | void clearDisplay(void); 55 | 56 | void displayInit(void); -------------------------------------------------------------------------------- /src/font.c: -------------------------------------------------------------------------------- 1 | /* font.c 2 | * PureProg 12 5x8 Pixel Font 3 | * The FontStruction “PureProg 12 5x8 Pixel mono Normal” (https://fontstruct.com/fontstructions/show/157866) 4 | * by Timo Acker (alias Handfratze) is licensed under a Creative Commons Attribution Non-commercial Share Alike license 5 | */ 6 | 7 | #include "font.h" 8 | 9 | #if (0x0 == 0x0) 10 | static uint8_t image_data_Font_0x20[10] = { 11 | // ██████ 12 | // ██████ 13 | // ██████ 14 | // ██████ 15 | // ██████ 16 | // ██████ 17 | // ██████ 18 | // ██████ 19 | // ██████ 20 | // ██████ 21 | 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc}; 22 | static tImage Font_0x20 = {image_data_Font_0x20, 6, 10, 8}; 23 | #endif 24 | 25 | #if (0x0 == 0x0) 26 | static uint8_t image_data_Font_0x2d[10] = { 27 | // ██████ 28 | // ██████ 29 | // ██████ 30 | // ██████ 31 | // █∙∙∙∙∙ 32 | // ██████ 33 | // ██████ 34 | // ██████ 35 | // ██████ 36 | // ██████ 37 | 0xfc, 0xfc, 0xfc, 0xfc, 0x80, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc}; 38 | static tImage Font_0x2d = {image_data_Font_0x2d, 6, 10, 8}; 39 | #endif 40 | 41 | #if (0x0 == 0x0) 42 | static uint8_t image_data_Font_0x2e[10] = { 43 | // ██████ 44 | // ██████ 45 | // ██████ 46 | // ██████ 47 | // ██████ 48 | // ██████ 49 | // ███∙∙█ 50 | // ███∙∙█ 51 | // ██████ 52 | // ██████ 53 | 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xe4, 0xe4, 0xfc, 0xfc}; 54 | static tImage Font_0x2e = {image_data_Font_0x2e, 6, 10, 8}; 55 | #endif 56 | 57 | #if (0x0 == 0x0) 58 | static uint8_t image_data_Font_0x41[10] = { 59 | // ██∙∙∙█ 60 | // █∙███∙ 61 | // █∙███∙ 62 | // █∙███∙ 63 | // █∙∙∙∙∙ 64 | // █∙███∙ 65 | // █∙███∙ 66 | // █∙███∙ 67 | // ██████ 68 | // ██████ 69 | 0xc4, 0xb8, 0xb8, 0xb8, 0x80, 0xb8, 0xb8, 0xb8, 0xfc, 0xfc}; 70 | static tImage Font_0x41 = {image_data_Font_0x41, 6, 10, 8}; 71 | #endif 72 | 73 | #if (0x0 == 0x0) 74 | static uint8_t image_data_Font_0x42[10] = { 75 | // ██∙∙∙∙ 76 | // █∙███∙ 77 | // █∙███∙ 78 | // ██∙∙∙∙ 79 | // █∙███∙ 80 | // █∙███∙ 81 | // █∙███∙ 82 | // ██∙∙∙∙ 83 | // ██████ 84 | // ██████ 85 | 0xc0, 0xb8, 0xb8, 0xc0, 0xb8, 0xb8, 0xb8, 0xc0, 0xfc, 0xfc}; 86 | static tImage Font_0x42 = {image_data_Font_0x42, 6, 10, 8}; 87 | #endif 88 | 89 | #if (0x0 == 0x0) 90 | static uint8_t image_data_Font_0x43[10] = { 91 | // ██∙∙∙█ 92 | // █∙███∙ 93 | // █████∙ 94 | // █████∙ 95 | // █████∙ 96 | // █████∙ 97 | // █∙███∙ 98 | // ██∙∙∙█ 99 | // ██████ 100 | // ██████ 101 | 0xc4, 0xb8, 0xf8, 0xf8, 0xf8, 0xf8, 0xb8, 0xc4, 0xfc, 0xfc}; 102 | static tImage Font_0x43 = {image_data_Font_0x43, 6, 10, 8}; 103 | #endif 104 | 105 | #if (0x0 == 0x0) 106 | static uint8_t image_data_Font_0x44[10] = { 107 | // ██∙∙∙∙ 108 | // █∙███∙ 109 | // █∙███∙ 110 | // █∙███∙ 111 | // █∙███∙ 112 | // █∙███∙ 113 | // █∙███∙ 114 | // ██∙∙∙∙ 115 | // ██████ 116 | // ██████ 117 | 0xc0, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xc0, 0xfc, 0xfc}; 118 | static tImage Font_0x44 = {image_data_Font_0x44, 6, 10, 8}; 119 | #endif 120 | 121 | #if (0x0 == 0x0) 122 | static uint8_t image_data_Font_0x45[10] = { 123 | // █∙∙∙∙∙ 124 | // █████∙ 125 | // █████∙ 126 | // ██∙∙∙∙ 127 | // █████∙ 128 | // █████∙ 129 | // █████∙ 130 | // █∙∙∙∙∙ 131 | // ██████ 132 | // ██████ 133 | 0x80, 0xf8, 0xf8, 0xc0, 0xf8, 0xf8, 0xf8, 0x80, 0xfc, 0xfc}; 134 | static tImage Font_0x45 = {image_data_Font_0x45, 6, 10, 8}; 135 | #endif 136 | 137 | #if (0x0 == 0x0) 138 | static uint8_t image_data_Font_0x46[10] = { 139 | // █∙∙∙∙∙ 140 | // █████∙ 141 | // █████∙ 142 | // ██∙∙∙∙ 143 | // █████∙ 144 | // █████∙ 145 | // █████∙ 146 | // █████∙ 147 | // ██████ 148 | // ██████ 149 | 0x80, 0xf8, 0xf8, 0xc0, 0xf8, 0xf8, 0xf8, 0xf8, 0xfc, 0xfc}; 150 | static tImage Font_0x46 = {image_data_Font_0x46, 6, 10, 8}; 151 | #endif 152 | 153 | #if (0x0 == 0x0) 154 | static uint8_t image_data_Font_0x47[10] = { 155 | // ██∙∙∙█ 156 | // █∙███∙ 157 | // █████∙ 158 | // █████∙ 159 | // █∙∙██∙ 160 | // █∙███∙ 161 | // █∙███∙ 162 | // █∙∙∙∙█ 163 | // ██████ 164 | // ██████ 165 | 0xc4, 0xb8, 0xf8, 0xf8, 0x98, 0xb8, 0xb8, 0x84, 0xfc, 0xfc}; 166 | static tImage Font_0x47 = {image_data_Font_0x47, 6, 10, 8}; 167 | #endif 168 | 169 | #if (0x0 == 0x0) 170 | static uint8_t image_data_Font_0x48[10] = { 171 | // █∙███∙ 172 | // █∙███∙ 173 | // █∙███∙ 174 | // █∙∙∙∙∙ 175 | // █∙███∙ 176 | // █∙███∙ 177 | // █∙███∙ 178 | // █∙███∙ 179 | // ██████ 180 | // ██████ 181 | 0xb8, 0xb8, 0xb8, 0x80, 0xb8, 0xb8, 0xb8, 0xb8, 0xfc, 0xfc}; 182 | static tImage Font_0x48 = {image_data_Font_0x48, 6, 10, 8}; 183 | #endif 184 | 185 | #if (0x0 == 0x0) 186 | static uint8_t image_data_Font_0x49[10] = { 187 | // ██∙∙∙█ 188 | // ███∙██ 189 | // ███∙██ 190 | // ███∙██ 191 | // ███∙██ 192 | // ███∙██ 193 | // ███∙██ 194 | // ██∙∙∙█ 195 | // ██████ 196 | // ██████ 197 | 0xc4, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xc4, 0xfc, 0xfc}; 198 | static tImage Font_0x49 = {image_data_Font_0x49, 6, 10, 8}; 199 | #endif 200 | 201 | #if (0x0 == 0x0) 202 | static uint8_t image_data_Font_0x4a[10] = { 203 | // █∙∙∙∙█ 204 | // ██∙███ 205 | // ██∙███ 206 | // ██∙███ 207 | // ██∙███ 208 | // ██∙███ 209 | // ██∙███ 210 | // ███∙∙∙ 211 | // ██████ 212 | // ██████ 213 | 0x84, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, 0xe0, 0xfc, 0xfc}; 214 | static tImage Font_0x4a = {image_data_Font_0x4a, 6, 10, 8}; 215 | #endif 216 | 217 | #if (0x0 == 0x0) 218 | static uint8_t image_data_Font_0x4b[10] = { 219 | // █∙███∙ 220 | // ██∙██∙ 221 | // ███∙█∙ 222 | // ████∙∙ 223 | // ███∙█∙ 224 | // ██∙██∙ 225 | // █∙███∙ 226 | // █∙███∙ 227 | // ██████ 228 | // ██████ 229 | 0xb8, 0xd8, 0xe8, 0xf0, 0xe8, 0xd8, 0xb8, 0xb8, 0xfc, 0xfc}; 230 | static tImage Font_0x4b = {image_data_Font_0x4b, 6, 10, 8}; 231 | #endif 232 | 233 | #if (0x0 == 0x0) 234 | static uint8_t image_data_Font_0x4c[10] = { 235 | // █████∙ 236 | // █████∙ 237 | // █████∙ 238 | // █████∙ 239 | // █████∙ 240 | // █████∙ 241 | // █████∙ 242 | // █∙∙∙∙∙ 243 | // ██████ 244 | // ██████ 245 | 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x80, 0xfc, 0xfc}; 246 | static tImage Font_0x4c = {image_data_Font_0x4c, 6, 10, 8}; 247 | #endif 248 | 249 | #if (0x0 == 0x0) 250 | static uint8_t image_data_Font_0x4d[10] = { 251 | // █∙███∙ 252 | // █∙███∙ 253 | // █∙∙█∙∙ 254 | // █∙∙█∙∙ 255 | // █∙█∙█∙ 256 | // █∙█∙█∙ 257 | // █∙███∙ 258 | // █∙███∙ 259 | // ██████ 260 | // ██████ 261 | 0xb8, 0xb8, 0x90, 0x90, 0xa8, 0xa8, 0xb8, 0xb8, 0xfc, 0xfc}; 262 | static tImage Font_0x4d = {image_data_Font_0x4d, 6, 10, 8}; 263 | #endif 264 | 265 | #if (0x0 == 0x0) 266 | static uint8_t image_data_Font_0x4e[10] = { 267 | // █∙███∙ 268 | // █∙██∙∙ 269 | // █∙██∙∙ 270 | // █∙█∙█∙ 271 | // █∙█∙█∙ 272 | // █∙∙██∙ 273 | // █∙∙██∙ 274 | // █∙███∙ 275 | // ██████ 276 | // ██████ 277 | 0xb8, 0xb0, 0xb0, 0xa8, 0xa8, 0x98, 0x98, 0xb8, 0xfc, 0xfc}; 278 | static tImage Font_0x4e = {image_data_Font_0x4e, 6, 10, 8}; 279 | #endif 280 | 281 | #if (0x0 == 0x0) 282 | static uint8_t image_data_Font_0x4f[10] = { 283 | // ██∙∙∙█ 284 | // █∙███∙ 285 | // █∙███∙ 286 | // █∙███∙ 287 | // █∙███∙ 288 | // █∙███∙ 289 | // █∙███∙ 290 | // ██∙∙∙█ 291 | // ██████ 292 | // ██████ 293 | 0xc4, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xc4, 0xfc, 0xfc}; 294 | static tImage Font_0x4f = {image_data_Font_0x4f, 6, 10, 8}; 295 | #endif 296 | 297 | #if (0x0 == 0x0) 298 | static uint8_t image_data_Font_0x50[10] = { 299 | // ██∙∙∙∙ 300 | // █∙███∙ 301 | // █∙███∙ 302 | // █∙███∙ 303 | // ██∙∙∙∙ 304 | // █████∙ 305 | // █████∙ 306 | // █████∙ 307 | // ██████ 308 | // ██████ 309 | 0xc0, 0xb8, 0xb8, 0xb8, 0xc0, 0xf8, 0xf8, 0xf8, 0xfc, 0xfc}; 310 | static tImage Font_0x50 = {image_data_Font_0x50, 6, 10, 8}; 311 | #endif 312 | 313 | #if (0x0 == 0x0) 314 | static uint8_t image_data_Font_0x51[10] = { 315 | // ██∙∙∙█ 316 | // █∙███∙ 317 | // █∙███∙ 318 | // █∙███∙ 319 | // █∙███∙ 320 | // █∙█∙█∙ 321 | // ██∙██∙ 322 | // █∙█∙∙█ 323 | // █∙████ 324 | // ██████ 325 | 0xc4, 0xb8, 0xb8, 0xb8, 0xb8, 0xa8, 0xd8, 0xa4, 0xbc, 0xfc}; 326 | static tImage Font_0x51 = {image_data_Font_0x51, 6, 10, 8}; 327 | #endif 328 | 329 | #if (0x0 == 0x0) 330 | static uint8_t image_data_Font_0x52[10] = { 331 | // ██∙∙∙∙ 332 | // █∙███∙ 333 | // █∙███∙ 334 | // █∙███∙ 335 | // ██∙∙∙∙ 336 | // ███∙█∙ 337 | // ██∙██∙ 338 | // █∙███∙ 339 | // ██████ 340 | // ██████ 341 | 0xc0, 0xb8, 0xb8, 0xb8, 0xc0, 0xe8, 0xd8, 0xb8, 0xfc, 0xfc}; 342 | static tImage Font_0x52 = {image_data_Font_0x52, 6, 10, 8}; 343 | #endif 344 | 345 | #if (0x0 == 0x0) 346 | static uint8_t image_data_Font_0x53[10] = { 347 | // █∙∙∙∙█ 348 | // █████∙ 349 | // █████∙ 350 | // ██∙∙∙█ 351 | // █∙████ 352 | // █∙████ 353 | // █∙████ 354 | // ██∙∙∙∙ 355 | // ██████ 356 | // ██████ 357 | 0x84, 0xf8, 0xf8, 0xc4, 0xbc, 0xbc, 0xbc, 0xc0, 0xfc, 0xfc}; 358 | static tImage Font_0x53 = {image_data_Font_0x53, 6, 10, 8}; 359 | #endif 360 | 361 | #if (0x0 == 0x0) 362 | static uint8_t image_data_Font_0x54[10] = { 363 | // █∙∙∙∙∙ 364 | // ███∙██ 365 | // ███∙██ 366 | // ███∙██ 367 | // ███∙██ 368 | // ███∙██ 369 | // ███∙██ 370 | // ███∙██ 371 | // ██████ 372 | // ██████ 373 | 0x80, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xfc, 0xfc}; 374 | static tImage Font_0x54 = {image_data_Font_0x54, 6, 10, 8}; 375 | #endif 376 | 377 | #if (0x0 == 0x0) 378 | static uint8_t image_data_Font_0x55[10] = { 379 | // █∙███∙ 380 | // █∙███∙ 381 | // █∙███∙ 382 | // █∙███∙ 383 | // █∙███∙ 384 | // █∙███∙ 385 | // █∙███∙ 386 | // ██∙∙∙█ 387 | // ██████ 388 | // ██████ 389 | 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xc4, 0xfc, 0xfc}; 390 | static tImage Font_0x55 = {image_data_Font_0x55, 6, 10, 8}; 391 | #endif 392 | 393 | #if (0x0 == 0x0) 394 | static uint8_t image_data_Font_0x56[10] = { 395 | // █∙███∙ 396 | // █∙███∙ 397 | // █∙███∙ 398 | // ██∙█∙█ 399 | // ██∙█∙█ 400 | // ██∙█∙█ 401 | // ███∙██ 402 | // ███∙██ 403 | // ██████ 404 | // ██████ 405 | 0xb8, 0xb8, 0xb8, 0xd4, 0xd4, 0xd4, 0xec, 0xec, 0xfc, 0xfc}; 406 | static tImage Font_0x56 = {image_data_Font_0x56, 6, 10, 8}; 407 | #endif 408 | 409 | #if (0x0 == 0x0) 410 | static uint8_t image_data_Font_0x57[10] = { 411 | // █∙███∙ 412 | // █∙███∙ 413 | // █∙███∙ 414 | // █∙█∙█∙ 415 | // █∙█∙█∙ 416 | // █∙∙█∙∙ 417 | // █∙∙█∙∙ 418 | // █∙███∙ 419 | // ██████ 420 | // ██████ 421 | 0xb8, 0xb8, 0xb8, 0xa8, 0xa8, 0x90, 0x90, 0xb8, 0xfc, 0xfc}; 422 | static tImage Font_0x57 = {image_data_Font_0x57, 6, 10, 8}; 423 | #endif 424 | 425 | #if (0x0 == 0x0) 426 | static uint8_t image_data_Font_0x58[10] = { 427 | // █∙███∙ 428 | // ██∙█∙█ 429 | // ██∙█∙█ 430 | // ███∙██ 431 | // ███∙██ 432 | // ██∙█∙█ 433 | // ██∙█∙█ 434 | // █∙███∙ 435 | // ██████ 436 | // ██████ 437 | 0xb8, 0xd4, 0xd4, 0xec, 0xec, 0xd4, 0xd4, 0xb8, 0xfc, 0xfc}; 438 | static tImage Font_0x58 = {image_data_Font_0x58, 6, 10, 8}; 439 | #endif 440 | 441 | #if (0x0 == 0x0) 442 | static uint8_t image_data_Font_0x59[10] = { 443 | // █∙███∙ 444 | // █∙███∙ 445 | // ██∙█∙█ 446 | // ██∙█∙█ 447 | // ███∙██ 448 | // ███∙██ 449 | // ███∙██ 450 | // ███∙██ 451 | // ██████ 452 | // ██████ 453 | 0xb8, 0xb8, 0xd4, 0xd4, 0xec, 0xec, 0xec, 0xec, 0xfc, 0xfc}; 454 | static tImage Font_0x59 = {image_data_Font_0x59, 6, 10, 8}; 455 | #endif 456 | 457 | #if (0x0 == 0x0) 458 | static uint8_t image_data_Font_0x5a[10] = { 459 | // █∙∙∙∙∙ 460 | // ██∙███ 461 | // ██∙███ 462 | // ███∙██ 463 | // ███∙██ 464 | // ████∙█ 465 | // ████∙█ 466 | // █∙∙∙∙∙ 467 | // ██████ 468 | // ██████ 469 | 0x80, 0xdc, 0xdc, 0xec, 0xec, 0xf4, 0xf4, 0x80, 0xfc, 0xfc}; 470 | static tImage Font_0x5a = {image_data_Font_0x5a, 6, 10, 8}; 471 | #endif 472 | 473 | #if (0x0 == 0x0) 474 | static uint8_t image_data_Font_0x61[10] = { 475 | // ██████ 476 | // ██████ 477 | // ██∙∙∙█ 478 | // █∙████ 479 | // █∙∙∙∙█ 480 | // █∙███∙ 481 | // █∙███∙ 482 | // █∙∙∙∙█ 483 | // ██████ 484 | // ██████ 485 | 0xfc, 0xfc, 0xc4, 0xbc, 0x84, 0xb8, 0xb8, 0x84, 0xfc, 0xfc}; 486 | static tImage Font_0x61 = {image_data_Font_0x61, 6, 10, 8}; 487 | #endif 488 | 489 | #if (0x0 == 0x0) 490 | static uint8_t image_data_Font_0x62[10] = { 491 | // █████∙ 492 | // █████∙ 493 | // ██∙∙█∙ 494 | // █∙██∙∙ 495 | // █∙███∙ 496 | // █∙███∙ 497 | // █∙██∙∙ 498 | // ██∙∙█∙ 499 | // ██████ 500 | // ██████ 501 | 0xf8, 0xf8, 0xc8, 0xb0, 0xb8, 0xb8, 0xb0, 0xc8, 0xfc, 0xfc}; 502 | static tImage Font_0x62 = {image_data_Font_0x62, 6, 10, 8}; 503 | #endif 504 | 505 | #if (0x0 == 0x0) 506 | static uint8_t image_data_Font_0x63[10] = { 507 | // ██████ 508 | // ██████ 509 | // ██∙∙∙█ 510 | // █∙███∙ 511 | // █████∙ 512 | // █████∙ 513 | // █∙███∙ 514 | // ██∙∙∙█ 515 | // ██████ 516 | // ██████ 517 | 0xfc, 0xfc, 0xc4, 0xb8, 0xf8, 0xf8, 0xb8, 0xc4, 0xfc, 0xfc}; 518 | static tImage Font_0x63 = {image_data_Font_0x63, 6, 10, 8}; 519 | #endif 520 | 521 | #if (0x0 == 0x0) 522 | static uint8_t image_data_Font_0x64[10] = { 523 | // █∙████ 524 | // █∙████ 525 | // █∙█∙∙█ 526 | // █∙∙██∙ 527 | // █∙███∙ 528 | // █∙███∙ 529 | // █∙∙██∙ 530 | // █∙█∙∙█ 531 | // ██████ 532 | // ██████ 533 | 0xbc, 0xbc, 0xa4, 0x98, 0xb8, 0xb8, 0x98, 0xa4, 0xfc, 0xfc}; 534 | static tImage Font_0x64 = {image_data_Font_0x64, 6, 10, 8}; 535 | #endif 536 | 537 | #if (0x0 == 0x0) 538 | static uint8_t image_data_Font_0x65[10] = { 539 | // ██████ 540 | // ██████ 541 | // ██∙∙∙█ 542 | // █∙███∙ 543 | // █∙███∙ 544 | // █∙∙∙∙∙ 545 | // █████∙ 546 | // █∙∙∙∙█ 547 | // ██████ 548 | // ██████ 549 | 0xfc, 0xfc, 0xc4, 0xb8, 0xb8, 0x80, 0xf8, 0x84, 0xfc, 0xfc}; 550 | static tImage Font_0x65 = {image_data_Font_0x65, 6, 10, 8}; 551 | #endif 552 | 553 | #if (0x0 == 0x0) 554 | static uint8_t image_data_Font_0x66[10] = { 555 | // ██∙███ 556 | // ███∙██ 557 | // ███∙██ 558 | // ██∙∙∙█ 559 | // ███∙██ 560 | // ███∙██ 561 | // ███∙██ 562 | // ███∙██ 563 | // ██████ 564 | // ██████ 565 | 0xdc, 0xec, 0xec, 0xc4, 0xec, 0xec, 0xec, 0xec, 0xfc, 0xfc}; 566 | static tImage Font_0x66 = {image_data_Font_0x66, 6, 10, 8}; 567 | #endif 568 | 569 | #if (0x0 == 0x0) 570 | static uint8_t image_data_Font_0x67[10] = { 571 | // ██████ 572 | // ██████ 573 | // █∙█∙∙█ 574 | // █∙∙██∙ 575 | // █∙███∙ 576 | // █∙███∙ 577 | // █∙∙██∙ 578 | // █∙█∙∙█ 579 | // █∙████ 580 | // ██∙∙∙∙ 581 | 0xfc, 0xfc, 0xa4, 0x98, 0xb8, 0xb8, 0x98, 0xa4, 0xbc, 0xc0}; 582 | static tImage Font_0x67 = {image_data_Font_0x67, 6, 10, 8}; 583 | #endif 584 | 585 | #if (0x0 == 0x0) 586 | static uint8_t image_data_Font_0x68[10] = { 587 | // █████∙ 588 | // █████∙ 589 | // ██∙∙█∙ 590 | // █∙██∙∙ 591 | // █∙███∙ 592 | // █∙███∙ 593 | // █∙███∙ 594 | // █∙███∙ 595 | // ██████ 596 | // ██████ 597 | 0xf8, 0xf8, 0xc8, 0xb0, 0xb8, 0xb8, 0xb8, 0xb8, 0xfc, 0xfc}; 598 | static tImage Font_0x68 = {image_data_Font_0x68, 6, 10, 8}; 599 | #endif 600 | 601 | #if (0x0 == 0x0) 602 | static uint8_t image_data_Font_0x69[10] = { 603 | // ███∙██ 604 | // ██████ 605 | // ███∙∙█ 606 | // ███∙██ 607 | // ███∙██ 608 | // ███∙██ 609 | // ███∙██ 610 | // ██∙∙∙█ 611 | // ██████ 612 | // ██████ 613 | 0xec, 0xfc, 0xe4, 0xec, 0xec, 0xec, 0xec, 0xc4, 0xfc, 0xfc}; 614 | static tImage Font_0x69 = {image_data_Font_0x69, 6, 10, 8}; 615 | #endif 616 | 617 | #if (0x0 == 0x0) 618 | static uint8_t image_data_Font_0x6a[10] = { 619 | // ██∙███ 620 | // ██████ 621 | // ██∙∙∙█ 622 | // ██∙███ 623 | // ██∙███ 624 | // ██∙███ 625 | // ██∙███ 626 | // ██∙███ 627 | // ██∙███ 628 | // ███∙∙█ 629 | 0xdc, 0xfc, 0xc4, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, 0xe4}; 630 | static tImage Font_0x6a = {image_data_Font_0x6a, 6, 10, 8}; 631 | #endif 632 | 633 | #if (0x0 == 0x0) 634 | static uint8_t image_data_Font_0x6b[10] = { 635 | // █████∙ 636 | // █████∙ 637 | // █∙███∙ 638 | // ██∙██∙ 639 | // ███∙█∙ 640 | // ███∙∙∙ 641 | // ██∙██∙ 642 | // █∙███∙ 643 | // ██████ 644 | // ██████ 645 | 0xf8, 0xf8, 0xb8, 0xd8, 0xe8, 0xe0, 0xd8, 0xb8, 0xfc, 0xfc}; 646 | static tImage Font_0x6b = {image_data_Font_0x6b, 6, 10, 8}; 647 | #endif 648 | 649 | #if (0x0 == 0x0) 650 | static uint8_t image_data_Font_0x6c[10] = { 651 | // ███∙██ 652 | // ███∙██ 653 | // ███∙██ 654 | // ███∙██ 655 | // ███∙██ 656 | // ███∙██ 657 | // ███∙██ 658 | // ██∙███ 659 | // ██████ 660 | // ██████ 661 | 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xdc, 0xfc, 0xfc}; 662 | static tImage Font_0x6c = {image_data_Font_0x6c, 6, 10, 8}; 663 | #endif 664 | 665 | #if (0x0 == 0x0) 666 | static uint8_t image_data_Font_0x6d[10] = { 667 | // ██████ 668 | // ██████ 669 | // ██∙∙∙∙ 670 | // █∙█∙█∙ 671 | // █∙█∙█∙ 672 | // █∙█∙█∙ 673 | // █∙█∙█∙ 674 | // █∙█∙█∙ 675 | // ██████ 676 | // ██████ 677 | 0xfc, 0xfc, 0xc0, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xfc, 0xfc}; 678 | static tImage Font_0x6d = {image_data_Font_0x6d, 6, 10, 8}; 679 | #endif 680 | 681 | #if (0x0 == 0x0) 682 | static uint8_t image_data_Font_0x6e[10] = { 683 | // ██████ 684 | // ██████ 685 | // ██∙∙█∙ 686 | // █∙██∙∙ 687 | // █∙███∙ 688 | // █∙███∙ 689 | // █∙███∙ 690 | // █∙███∙ 691 | // ██████ 692 | // ██████ 693 | 0xfc, 0xfc, 0xc8, 0xb0, 0xb8, 0xb8, 0xb8, 0xb8, 0xfc, 0xfc}; 694 | static tImage Font_0x6e = {image_data_Font_0x6e, 6, 10, 8}; 695 | #endif 696 | 697 | #if (0x0 == 0x0) 698 | static uint8_t image_data_Font_0x6f[10] = { 699 | // ██████ 700 | // ██████ 701 | // ██∙∙∙█ 702 | // █∙███∙ 703 | // █∙███∙ 704 | // █∙███∙ 705 | // █∙███∙ 706 | // ██∙∙∙█ 707 | // ██████ 708 | // ██████ 709 | 0xfc, 0xfc, 0xc4, 0xb8, 0xb8, 0xb8, 0xb8, 0xc4, 0xfc, 0xfc}; 710 | static tImage Font_0x6f = {image_data_Font_0x6f, 6, 10, 8}; 711 | #endif 712 | 713 | #if (0x0 == 0x0) 714 | static uint8_t image_data_Font_0x70[10] = { 715 | // ██████ 716 | // ██████ 717 | // ██∙∙█∙ 718 | // █∙██∙∙ 719 | // █∙███∙ 720 | // █∙███∙ 721 | // █∙██∙∙ 722 | // ██∙∙█∙ 723 | // █████∙ 724 | // █████∙ 725 | 0xfc, 0xfc, 0xc8, 0xb0, 0xb8, 0xb8, 0xb0, 0xc8, 0xf8, 0xf8}; 726 | static tImage Font_0x70 = {image_data_Font_0x70, 6, 10, 8}; 727 | #endif 728 | 729 | #if (0x0 == 0x0) 730 | static uint8_t image_data_Font_0x71[10] = { 731 | // ██████ 732 | // ██████ 733 | // █∙█∙∙█ 734 | // █∙∙██∙ 735 | // █∙███∙ 736 | // █∙███∙ 737 | // █∙∙██∙ 738 | // █∙█∙∙█ 739 | // █∙████ 740 | // █∙████ 741 | 0xfc, 0xfc, 0xa4, 0x98, 0xb8, 0xb8, 0x98, 0xa4, 0xbc, 0xbc}; 742 | static tImage Font_0x71 = {image_data_Font_0x71, 6, 10, 8}; 743 | #endif 744 | 745 | #if (0x0 == 0x0) 746 | static uint8_t image_data_Font_0x72[10] = { 747 | // ██████ 748 | // ██████ 749 | // ██∙∙█∙ 750 | // █∙██∙∙ 751 | // █████∙ 752 | // █████∙ 753 | // █████∙ 754 | // █████∙ 755 | // ██████ 756 | // ██████ 757 | 0xfc, 0xfc, 0xc8, 0xb0, 0xf8, 0xf8, 0xf8, 0xf8, 0xfc, 0xfc}; 758 | static tImage Font_0x72 = {image_data_Font_0x72, 6, 10, 8}; 759 | #endif 760 | 761 | #if (0x0 == 0x0) 762 | static uint8_t image_data_Font_0x73[10] = { 763 | // ██████ 764 | // ██████ 765 | // █∙∙∙∙█ 766 | // █████∙ 767 | // ██∙∙∙█ 768 | // █∙████ 769 | // █∙████ 770 | // ██∙∙∙∙ 771 | // ██████ 772 | // ██████ 773 | 0xfc, 0xfc, 0x84, 0xf8, 0xc4, 0xbc, 0xbc, 0xc0, 0xfc, 0xfc}; 774 | static tImage Font_0x73 = {image_data_Font_0x73, 6, 10, 8}; 775 | #endif 776 | 777 | #if (0x0 == 0x0) 778 | static uint8_t image_data_Font_0x74[10] = { 779 | // ███∙██ 780 | // ███∙██ 781 | // ██∙∙∙█ 782 | // ███∙██ 783 | // ███∙██ 784 | // ███∙██ 785 | // ███∙██ 786 | // ██∙███ 787 | // ██████ 788 | // ██████ 789 | 0xec, 0xec, 0xc4, 0xec, 0xec, 0xec, 0xec, 0xdc, 0xfc, 0xfc}; 790 | static tImage Font_0x74 = {image_data_Font_0x74, 6, 10, 8}; 791 | #endif 792 | 793 | #if (0x0 == 0x0) 794 | static uint8_t image_data_Font_0x75[10] = { 795 | // ██████ 796 | // ██████ 797 | // █∙███∙ 798 | // █∙███∙ 799 | // █∙███∙ 800 | // █∙███∙ 801 | // █∙∙██∙ 802 | // █∙█∙∙█ 803 | // ██████ 804 | // ██████ 805 | 0xfc, 0xfc, 0xb8, 0xb8, 0xb8, 0xb8, 0x98, 0xa4, 0xfc, 0xfc}; 806 | static tImage Font_0x75 = {image_data_Font_0x75, 6, 10, 8}; 807 | #endif 808 | 809 | #if (0x0 == 0x0) 810 | static uint8_t image_data_Font_0x76[10] = { 811 | // ██████ 812 | // ██████ 813 | // █∙███∙ 814 | // █∙███∙ 815 | // ██∙█∙█ 816 | // ██∙█∙█ 817 | // ███∙██ 818 | // ███∙██ 819 | // ██████ 820 | // ██████ 821 | 0xfc, 0xfc, 0xb8, 0xb8, 0xd4, 0xd4, 0xec, 0xec, 0xfc, 0xfc}; 822 | static tImage Font_0x76 = {image_data_Font_0x76, 6, 10, 8}; 823 | #endif 824 | 825 | #if (0x0 == 0x0) 826 | static uint8_t image_data_Font_0x77[10] = { 827 | // ██████ 828 | // ██████ 829 | // █∙███∙ 830 | // █∙███∙ 831 | // █∙█∙█∙ 832 | // █∙█∙█∙ 833 | // █∙∙█∙∙ 834 | // █∙███∙ 835 | // ██████ 836 | // ██████ 837 | 0xfc, 0xfc, 0xb8, 0xb8, 0xa8, 0xa8, 0x90, 0xb8, 0xfc, 0xfc}; 838 | static tImage Font_0x77 = {image_data_Font_0x77, 6, 10, 8}; 839 | #endif 840 | 841 | #if (0x0 == 0x0) 842 | static uint8_t image_data_Font_0x78[10] = { 843 | // ██████ 844 | // ██████ 845 | // █∙███∙ 846 | // ██∙█∙█ 847 | // ███∙██ 848 | // ███∙██ 849 | // ██∙█∙█ 850 | // █∙███∙ 851 | // ██████ 852 | // ██████ 853 | 0xfc, 0xfc, 0xb8, 0xd4, 0xec, 0xec, 0xd4, 0xb8, 0xfc, 0xfc}; 854 | static tImage Font_0x78 = {image_data_Font_0x78, 6, 10, 8}; 855 | #endif 856 | 857 | #if (0x0 == 0x0) 858 | static uint8_t image_data_Font_0x79[10] = { 859 | // ██████ 860 | // ██████ 861 | // █∙███∙ 862 | // █∙███∙ 863 | // █∙███∙ 864 | // █∙███∙ 865 | // █∙∙██∙ 866 | // █∙█∙∙█ 867 | // █∙████ 868 | // ██∙∙∙∙ 869 | 0xfc, 0xfc, 0xb8, 0xb8, 0xb8, 0xb8, 0x98, 0xa4, 0xbc, 0xc0}; 870 | static tImage Font_0x79 = {image_data_Font_0x79, 6, 10, 8}; 871 | #endif 872 | 873 | #if (0x0 == 0x0) 874 | static uint8_t image_data_Font_0x7a[10] = { 875 | // ██████ 876 | // ██████ 877 | // █∙∙∙∙∙ 878 | // ██∙███ 879 | // ███∙██ 880 | // ███∙██ 881 | // ████∙█ 882 | // █∙∙∙∙∙ 883 | // ██████ 884 | // ██████ 885 | 0xfc, 0xfc, 0x80, 0xdc, 0xec, 0xec, 0xf4, 0x80, 0xfc, 0xfc}; 886 | static tImage Font_0x7a = {image_data_Font_0x7a, 6, 10, 8}; 887 | #endif 888 | 889 | #if (0x0 == 0x0) 890 | static uint8_t image_data_Font_0x21[10] = { 891 | // ███∙██ 892 | // ███∙██ 893 | // ███∙██ 894 | // ███∙██ 895 | // ███∙██ 896 | // ███∙██ 897 | // ██████ 898 | // ███∙██ 899 | // ██████ 900 | // ██████ 901 | 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xfc, 0xec, 0xfc, 0xfc}; 902 | static tImage Font_0x21 = {image_data_Font_0x21, 6, 10, 8}; 903 | #endif 904 | 905 | #if (0x0 == 0x0) 906 | static uint8_t image_data_Font_0x23[10] = { 907 | // ██∙█∙█ 908 | // ██∙█∙█ 909 | // █∙∙∙∙∙ 910 | // ██∙█∙█ 911 | // ██∙█∙█ 912 | // █∙∙∙∙∙ 913 | // ██∙█∙█ 914 | // ██∙█∙█ 915 | // ██████ 916 | // ██████ 917 | 0xd4, 0xd4, 0x80, 0xd4, 0xd4, 0x80, 0xd4, 0xd4, 0xfc, 0xfc}; 918 | static tImage Font_0x23 = {image_data_Font_0x23, 6, 10, 8}; 919 | #endif 920 | 921 | #if (0x0 == 0x0) 922 | static uint8_t image_data_Font_0x25[10] = { 923 | // █∙████ 924 | // ██∙█∙∙ 925 | // ██∙█∙∙ 926 | // ███∙██ 927 | // ███∙██ 928 | // █∙∙█∙█ 929 | // █∙∙█∙█ 930 | // █████∙ 931 | // ██████ 932 | // ██████ 933 | 0xbc, 0xd0, 0xd0, 0xec, 0xec, 0x94, 0x94, 0xf8, 0xfc, 0xfc}; 934 | static tImage Font_0x25 = {image_data_Font_0x25, 6, 10, 8}; 935 | #endif 936 | 937 | #if (0x0 == 0x0) 938 | static uint8_t image_data_Font_0x26[10] = { 939 | // ██████ 940 | // ██████ 941 | // ███∙∙█ 942 | // ██∙██∙ 943 | // ███∙∙█ 944 | // █∙█∙█∙ 945 | // ██∙██∙ 946 | // █∙█∙∙█ 947 | // ██████ 948 | // ██████ 949 | 0xfc, 0xfc, 0xe4, 0xd8, 0xe4, 0xa8, 0xd8, 0xa4, 0xfc, 0xfc}; 950 | static tImage Font_0x26 = {image_data_Font_0x26, 6, 10, 8}; 951 | #endif 952 | 953 | #if (0x0 == 0x0) 954 | static uint8_t image_data_Font_0x27[10] = { 955 | // ███∙██ 956 | // ███∙██ 957 | // ███∙██ 958 | // ██████ 959 | // ██████ 960 | // ██████ 961 | // ██████ 962 | // ██████ 963 | // ██████ 964 | // ██████ 965 | 0xec, 0xec, 0xec, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc}; 966 | static tImage Font_0x27 = {image_data_Font_0x27, 6, 10, 8}; 967 | #endif 968 | 969 | #if (0x0 == 0x0) 970 | static uint8_t image_data_Font_0x28[10] = { 971 | // ██∙███ 972 | // ███∙██ 973 | // ████∙█ 974 | // ████∙█ 975 | // ████∙█ 976 | // ████∙█ 977 | // ███∙██ 978 | // ██∙███ 979 | // ██████ 980 | // ██████ 981 | 0xdc, 0xec, 0xf4, 0xf4, 0xf4, 0xf4, 0xec, 0xdc, 0xfc, 0xfc}; 982 | static tImage Font_0x28 = {image_data_Font_0x28, 6, 10, 8}; 983 | #endif 984 | 985 | #if (0x0 == 0x0) 986 | static uint8_t image_data_Font_0x29[10] = { 987 | // ████∙█ 988 | // ███∙██ 989 | // ██∙███ 990 | // ██∙███ 991 | // ██∙███ 992 | // ██∙███ 993 | // ███∙██ 994 | // ████∙█ 995 | // ██████ 996 | // ██████ 997 | 0xf4, 0xec, 0xdc, 0xdc, 0xdc, 0xdc, 0xec, 0xf4, 0xfc, 0xfc}; 998 | static tImage Font_0x29 = {image_data_Font_0x29, 6, 10, 8}; 999 | #endif 1000 | 1001 | #if (0x0 == 0x0) 1002 | static uint8_t image_data_Font_0x2a[10] = { 1003 | // ██████ 1004 | // ██████ 1005 | // ███∙██ 1006 | // ███∙██ 1007 | // █∙∙∙∙∙ 1008 | // ███∙██ 1009 | // ██∙█∙█ 1010 | // ██████ 1011 | // ██████ 1012 | // ██████ 1013 | 0xfc, 0xfc, 0xec, 0xec, 0x80, 0xec, 0xd4, 0xfc, 0xfc, 0xfc}; 1014 | static tImage Font_0x2a = {image_data_Font_0x2a, 6, 10, 8}; 1015 | #endif 1016 | 1017 | #if (0x0 == 0x0) 1018 | static uint8_t image_data_Font_0x2b[10] = { 1019 | // ██████ 1020 | // ██████ 1021 | // ███∙██ 1022 | // ███∙██ 1023 | // █∙∙∙∙∙ 1024 | // ███∙██ 1025 | // ███∙██ 1026 | // ██████ 1027 | // ██████ 1028 | // ██████ 1029 | 0xfc, 0xfc, 0xec, 0xec, 0x80, 0xec, 0xec, 0xfc, 0xfc, 0xfc}; 1030 | static tImage Font_0x2b = {image_data_Font_0x2b, 6, 10, 8}; 1031 | #endif 1032 | 1033 | #if (0x0 == 0x0) 1034 | static uint8_t image_data_Font_0x2c[10] = { 1035 | // ██████ 1036 | // ██████ 1037 | // ██████ 1038 | // ██████ 1039 | // ██████ 1040 | // ██████ 1041 | // ███∙∙█ 1042 | // ███∙██ 1043 | // ███∙██ 1044 | // ████∙█ 1045 | 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xe4, 0xec, 0xec, 0xf4}; 1046 | static tImage Font_0x2c = {image_data_Font_0x2c, 6, 10, 8}; 1047 | #endif 1048 | 1049 | #if (0x0 == 0x0) 1050 | static uint8_t image_data_Font_0x30[10] = { 1051 | // ██∙∙∙█ 1052 | // █∙███∙ 1053 | // █∙███∙ 1054 | // █∙█∙█∙ 1055 | // █∙█∙█∙ 1056 | // █∙███∙ 1057 | // █∙███∙ 1058 | // ██∙∙∙█ 1059 | // ██████ 1060 | // ██████ 1061 | 0xc4, 0xb8, 0xb8, 0xa8, 0xa8, 0xb8, 0xb8, 0xc4, 0xfc, 0xfc}; 1062 | static tImage Font_0x30 = {image_data_Font_0x30, 6, 10, 8}; 1063 | #endif 1064 | 1065 | #if (0x0 == 0x0) 1066 | static uint8_t image_data_Font_0x31[10] = { 1067 | // ███∙██ 1068 | // ███∙∙█ 1069 | // ███∙█∙ 1070 | // ███∙██ 1071 | // ███∙██ 1072 | // ███∙██ 1073 | // ███∙██ 1074 | // █∙∙∙∙∙ 1075 | // ██████ 1076 | // ██████ 1077 | 0xec, 0xe4, 0xe8, 0xec, 0xec, 0xec, 0xec, 0x80, 0xfc, 0xfc}; 1078 | static tImage Font_0x31 = {image_data_Font_0x31, 6, 10, 8}; 1079 | #endif 1080 | 1081 | #if (0x0 == 0x0) 1082 | static uint8_t image_data_Font_0x32[10] = { 1083 | // ██∙∙∙█ 1084 | // █∙███∙ 1085 | // █∙████ 1086 | // ██∙███ 1087 | // ███∙██ 1088 | // ████∙█ 1089 | // █████∙ 1090 | // █∙∙∙∙∙ 1091 | // ██████ 1092 | // ██████ 1093 | 0xc4, 0xb8, 0xbc, 0xdc, 0xec, 0xf4, 0xf8, 0x80, 0xfc, 0xfc}; 1094 | static tImage Font_0x32 = {image_data_Font_0x32, 6, 10, 8}; 1095 | #endif 1096 | 1097 | #if (0x0 == 0x0) 1098 | static uint8_t image_data_Font_0x33[10] = { 1099 | // ██∙∙∙█ 1100 | // █∙███∙ 1101 | // █∙████ 1102 | // ██∙∙∙█ 1103 | // █∙████ 1104 | // █∙████ 1105 | // █∙███∙ 1106 | // ██∙∙∙█ 1107 | // ██████ 1108 | // ██████ 1109 | 0xc4, 0xb8, 0xbc, 0xc4, 0xbc, 0xbc, 0xb8, 0xc4, 0xfc, 0xfc}; 1110 | static tImage Font_0x33 = {image_data_Font_0x33, 6, 10, 8}; 1111 | #endif 1112 | 1113 | #if (0x0 == 0x0) 1114 | static uint8_t image_data_Font_0x34[10] = { 1115 | // █∙████ 1116 | // █∙∙███ 1117 | // █∙█∙██ 1118 | // █∙██∙█ 1119 | // █∙███∙ 1120 | // █∙∙∙∙∙ 1121 | // █∙████ 1122 | // █∙████ 1123 | // ██████ 1124 | // ██████ 1125 | 0xbc, 0x9c, 0xac, 0xb4, 0xb8, 0x80, 0xbc, 0xbc, 0xfc, 0xfc}; 1126 | static tImage Font_0x34 = {image_data_Font_0x34, 6, 10, 8}; 1127 | #endif 1128 | 1129 | #if (0x0 == 0x0) 1130 | static uint8_t image_data_Font_0x35[10] = { 1131 | // █∙∙∙∙∙ 1132 | // █████∙ 1133 | // █████∙ 1134 | // ██∙∙∙∙ 1135 | // █∙████ 1136 | // █∙████ 1137 | // █∙████ 1138 | // ██∙∙∙∙ 1139 | // ██████ 1140 | // ██████ 1141 | 0x80, 0xf8, 0xf8, 0xc0, 0xbc, 0xbc, 0xbc, 0xc0, 0xfc, 0xfc}; 1142 | static tImage Font_0x35 = {image_data_Font_0x35, 6, 10, 8}; 1143 | #endif 1144 | 1145 | #if (0x0 == 0x0) 1146 | static uint8_t image_data_Font_0x36[10] = { 1147 | // ██∙∙∙█ 1148 | // █∙███∙ 1149 | // █████∙ 1150 | // ██∙∙∙∙ 1151 | // █∙███∙ 1152 | // █∙███∙ 1153 | // █∙███∙ 1154 | // ██∙∙∙█ 1155 | // ██████ 1156 | // ██████ 1157 | 0xc4, 0xb8, 0xf8, 0xc0, 0xb8, 0xb8, 0xb8, 0xc4, 0xfc, 0xfc}; 1158 | static tImage Font_0x36 = {image_data_Font_0x36, 6, 10, 8}; 1159 | #endif 1160 | 1161 | #if (0x0 == 0x0) 1162 | static uint8_t image_data_Font_0x37[10] = { 1163 | // █∙∙∙∙∙ 1164 | // █∙███∙ 1165 | // ██∙███ 1166 | // ███∙██ 1167 | // ███∙██ 1168 | // ████∙█ 1169 | // ████∙█ 1170 | // ████∙█ 1171 | // ██████ 1172 | // ██████ 1173 | 0x80, 0xb8, 0xdc, 0xec, 0xec, 0xf4, 0xf4, 0xf4, 0xfc, 0xfc}; 1174 | static tImage Font_0x37 = {image_data_Font_0x37, 6, 10, 8}; 1175 | #endif 1176 | 1177 | #if (0x0 == 0x0) 1178 | static uint8_t image_data_Font_0x38[10] = { 1179 | // ██∙∙∙█ 1180 | // █∙███∙ 1181 | // █∙███∙ 1182 | // ██∙∙∙█ 1183 | // █∙███∙ 1184 | // █∙███∙ 1185 | // █∙███∙ 1186 | // ██∙∙∙█ 1187 | // ██████ 1188 | // ██████ 1189 | 0xc4, 0xb8, 0xb8, 0xc4, 0xb8, 0xb8, 0xb8, 0xc4, 0xfc, 0xfc}; 1190 | static tImage Font_0x38 = {image_data_Font_0x38, 6, 10, 8}; 1191 | #endif 1192 | 1193 | #if (0x0 == 0x0) 1194 | static uint8_t image_data_Font_0x39[10] = { 1195 | // ██∙∙∙█ 1196 | // █∙███∙ 1197 | // █∙███∙ 1198 | // █∙∙∙∙█ 1199 | // █∙████ 1200 | // █∙████ 1201 | // █∙███∙ 1202 | // ██∙∙∙█ 1203 | // ██████ 1204 | // ██████ 1205 | 0xc4, 0xb8, 0xb8, 0x84, 0xbc, 0xbc, 0xb8, 0xc4, 0xfc, 0xfc}; 1206 | static tImage Font_0x39 = {image_data_Font_0x39, 6, 10, 8}; 1207 | #endif 1208 | 1209 | #if (0x0 == 0x0) 1210 | static uint8_t image_data_Font_0x3a[10] = { 1211 | // ██████ 1212 | // ██████ 1213 | // ███∙∙█ 1214 | // ███∙∙█ 1215 | // ██████ 1216 | // ███∙∙█ 1217 | // ███∙∙█ 1218 | // ██████ 1219 | // ██████ 1220 | // ██████ 1221 | 0xfc, 0xfc, 0xe4, 0xe4, 0xfc, 0xe4, 0xe4, 0xfc, 0xfc, 0xfc}; 1222 | static tImage Font_0x3a = {image_data_Font_0x3a, 6, 10, 8}; 1223 | #endif 1224 | 1225 | #if (0x0 == 0x0) 1226 | static uint8_t image_data_Font_0x3b[10] = { 1227 | // ██████ 1228 | // ██████ 1229 | // ███∙∙█ 1230 | // ███∙∙█ 1231 | // ██████ 1232 | // ███∙∙█ 1233 | // ███∙∙█ 1234 | // ███∙██ 1235 | // ███∙██ 1236 | // ████∙█ 1237 | 0xfc, 0xfc, 0xe4, 0xe4, 0xfc, 0xe4, 0xe4, 0xec, 0xec, 0xf4}; 1238 | static tImage Font_0x3b = {image_data_Font_0x3b, 6, 10, 8}; 1239 | #endif 1240 | 1241 | #if (0x0 == 0x0) 1242 | static uint8_t image_data_Font_0x3d[10] = { 1243 | // ██████ 1244 | // ██████ 1245 | // ██████ 1246 | // █∙∙∙∙∙ 1247 | // ██████ 1248 | // █∙∙∙∙∙ 1249 | // ██████ 1250 | // ██████ 1251 | // ██████ 1252 | // ██████ 1253 | 0xfc, 0xfc, 0xfc, 0x80, 0xfc, 0x80, 0xfc, 0xfc, 0xfc, 0xfc}; 1254 | static tImage Font_0x3d = {image_data_Font_0x3d, 6, 10, 8}; 1255 | #endif 1256 | 1257 | static tChar Font_array[] = { 1258 | 1259 | #if (0x0 == 0x0) 1260 | // character: ' ' 1261 | {0x20, &Font_0x20}, 1262 | #else 1263 | // character: ' ' == '' 1264 | {0x20, &Font_0x}, 1265 | #endif 1266 | 1267 | #if (0x0 == 0x0) 1268 | // character: '-' 1269 | {0x2d, &Font_0x2d}, 1270 | #else 1271 | // character: '-' == '' 1272 | {0x2d, &Font_0x}, 1273 | #endif 1274 | 1275 | #if (0x0 == 0x0) 1276 | // character: '.' 1277 | {0x2e, &Font_0x2e}, 1278 | #else 1279 | // character: '.' == '' 1280 | {0x2e, &Font_0x}, 1281 | #endif 1282 | 1283 | #if (0x0 == 0x0) 1284 | // character: 'A' 1285 | {0x41, &Font_0x41}, 1286 | #else 1287 | // character: 'A' == '' 1288 | {0x41, &Font_0x}, 1289 | #endif 1290 | 1291 | #if (0x0 == 0x0) 1292 | // character: 'B' 1293 | {0x42, &Font_0x42}, 1294 | #else 1295 | // character: 'B' == '' 1296 | {0x42, &Font_0x}, 1297 | #endif 1298 | 1299 | #if (0x0 == 0x0) 1300 | // character: 'C' 1301 | {0x43, &Font_0x43}, 1302 | #else 1303 | // character: 'C' == '' 1304 | {0x43, &Font_0x}, 1305 | #endif 1306 | 1307 | #if (0x0 == 0x0) 1308 | // character: 'D' 1309 | {0x44, &Font_0x44}, 1310 | #else 1311 | // character: 'D' == '' 1312 | {0x44, &Font_0x}, 1313 | #endif 1314 | 1315 | #if (0x0 == 0x0) 1316 | // character: 'E' 1317 | {0x45, &Font_0x45}, 1318 | #else 1319 | // character: 'E' == '' 1320 | {0x45, &Font_0x}, 1321 | #endif 1322 | 1323 | #if (0x0 == 0x0) 1324 | // character: 'F' 1325 | {0x46, &Font_0x46}, 1326 | #else 1327 | // character: 'F' == '' 1328 | {0x46, &Font_0x}, 1329 | #endif 1330 | 1331 | #if (0x0 == 0x0) 1332 | // character: 'G' 1333 | {0x47, &Font_0x47}, 1334 | #else 1335 | // character: 'G' == '' 1336 | {0x47, &Font_0x}, 1337 | #endif 1338 | 1339 | #if (0x0 == 0x0) 1340 | // character: 'H' 1341 | {0x48, &Font_0x48}, 1342 | #else 1343 | // character: 'H' == '' 1344 | {0x48, &Font_0x}, 1345 | #endif 1346 | 1347 | #if (0x0 == 0x0) 1348 | // character: 'I' 1349 | {0x49, &Font_0x49}, 1350 | #else 1351 | // character: 'I' == '' 1352 | {0x49, &Font_0x}, 1353 | #endif 1354 | 1355 | #if (0x0 == 0x0) 1356 | // character: 'J' 1357 | {0x4a, &Font_0x4a}, 1358 | #else 1359 | // character: 'J' == '' 1360 | {0x4a, &Font_0x}, 1361 | #endif 1362 | 1363 | #if (0x0 == 0x0) 1364 | // character: 'K' 1365 | {0x4b, &Font_0x4b}, 1366 | #else 1367 | // character: 'K' == '' 1368 | {0x4b, &Font_0x}, 1369 | #endif 1370 | 1371 | #if (0x0 == 0x0) 1372 | // character: 'L' 1373 | {0x4c, &Font_0x4c}, 1374 | #else 1375 | // character: 'L' == '' 1376 | {0x4c, &Font_0x}, 1377 | #endif 1378 | 1379 | #if (0x0 == 0x0) 1380 | // character: 'M' 1381 | {0x4d, &Font_0x4d}, 1382 | #else 1383 | // character: 'M' == '' 1384 | {0x4d, &Font_0x}, 1385 | #endif 1386 | 1387 | #if (0x0 == 0x0) 1388 | // character: 'N' 1389 | {0x4e, &Font_0x4e}, 1390 | #else 1391 | // character: 'N' == '' 1392 | {0x4e, &Font_0x}, 1393 | #endif 1394 | 1395 | #if (0x0 == 0x0) 1396 | // character: 'O' 1397 | {0x4f, &Font_0x4f}, 1398 | #else 1399 | // character: 'O' == '' 1400 | {0x4f, &Font_0x}, 1401 | #endif 1402 | 1403 | #if (0x0 == 0x0) 1404 | // character: 'P' 1405 | {0x50, &Font_0x50}, 1406 | #else 1407 | // character: 'P' == '' 1408 | {0x50, &Font_0x}, 1409 | #endif 1410 | 1411 | #if (0x0 == 0x0) 1412 | // character: 'Q' 1413 | {0x51, &Font_0x51}, 1414 | #else 1415 | // character: 'Q' == '' 1416 | {0x51, &Font_0x}, 1417 | #endif 1418 | 1419 | #if (0x0 == 0x0) 1420 | // character: 'R' 1421 | {0x52, &Font_0x52}, 1422 | #else 1423 | // character: 'R' == '' 1424 | {0x52, &Font_0x}, 1425 | #endif 1426 | 1427 | #if (0x0 == 0x0) 1428 | // character: 'S' 1429 | {0x53, &Font_0x53}, 1430 | #else 1431 | // character: 'S' == '' 1432 | {0x53, &Font_0x}, 1433 | #endif 1434 | 1435 | #if (0x0 == 0x0) 1436 | // character: 'T' 1437 | {0x54, &Font_0x54}, 1438 | #else 1439 | // character: 'T' == '' 1440 | {0x54, &Font_0x}, 1441 | #endif 1442 | 1443 | #if (0x0 == 0x0) 1444 | // character: 'U' 1445 | {0x55, &Font_0x55}, 1446 | #else 1447 | // character: 'U' == '' 1448 | {0x55, &Font_0x}, 1449 | #endif 1450 | 1451 | #if (0x0 == 0x0) 1452 | // character: 'V' 1453 | {0x56, &Font_0x56}, 1454 | #else 1455 | // character: 'V' == '' 1456 | {0x56, &Font_0x}, 1457 | #endif 1458 | 1459 | #if (0x0 == 0x0) 1460 | // character: 'W' 1461 | {0x57, &Font_0x57}, 1462 | #else 1463 | // character: 'W' == '' 1464 | {0x57, &Font_0x}, 1465 | #endif 1466 | 1467 | #if (0x0 == 0x0) 1468 | // character: 'X' 1469 | {0x58, &Font_0x58}, 1470 | #else 1471 | // character: 'X' == '' 1472 | {0x58, &Font_0x}, 1473 | #endif 1474 | 1475 | #if (0x0 == 0x0) 1476 | // character: 'Y' 1477 | {0x59, &Font_0x59}, 1478 | #else 1479 | // character: 'Y' == '' 1480 | {0x59, &Font_0x}, 1481 | #endif 1482 | 1483 | #if (0x0 == 0x0) 1484 | // character: 'Z' 1485 | {0x5a, &Font_0x5a}, 1486 | #else 1487 | // character: 'Z' == '' 1488 | {0x5a, &Font_0x}, 1489 | #endif 1490 | 1491 | #if (0x0 == 0x0) 1492 | // character: 'a' 1493 | {0x61, &Font_0x61}, 1494 | #else 1495 | // character: 'a' == '' 1496 | {0x61, &Font_0x}, 1497 | #endif 1498 | 1499 | #if (0x0 == 0x0) 1500 | // character: 'b' 1501 | {0x62, &Font_0x62}, 1502 | #else 1503 | // character: 'b' == '' 1504 | {0x62, &Font_0x}, 1505 | #endif 1506 | 1507 | #if (0x0 == 0x0) 1508 | // character: 'c' 1509 | {0x63, &Font_0x63}, 1510 | #else 1511 | // character: 'c' == '' 1512 | {0x63, &Font_0x}, 1513 | #endif 1514 | 1515 | #if (0x0 == 0x0) 1516 | // character: 'd' 1517 | {0x64, &Font_0x64}, 1518 | #else 1519 | // character: 'd' == '' 1520 | {0x64, &Font_0x}, 1521 | #endif 1522 | 1523 | #if (0x0 == 0x0) 1524 | // character: 'e' 1525 | {0x65, &Font_0x65}, 1526 | #else 1527 | // character: 'e' == '' 1528 | {0x65, &Font_0x}, 1529 | #endif 1530 | 1531 | #if (0x0 == 0x0) 1532 | // character: 'f' 1533 | {0x66, &Font_0x66}, 1534 | #else 1535 | // character: 'f' == '' 1536 | {0x66, &Font_0x}, 1537 | #endif 1538 | 1539 | #if (0x0 == 0x0) 1540 | // character: 'g' 1541 | {0x67, &Font_0x67}, 1542 | #else 1543 | // character: 'g' == '' 1544 | {0x67, &Font_0x}, 1545 | #endif 1546 | 1547 | #if (0x0 == 0x0) 1548 | // character: 'h' 1549 | {0x68, &Font_0x68}, 1550 | #else 1551 | // character: 'h' == '' 1552 | {0x68, &Font_0x}, 1553 | #endif 1554 | 1555 | #if (0x0 == 0x0) 1556 | // character: 'i' 1557 | {0x69, &Font_0x69}, 1558 | #else 1559 | // character: 'i' == '' 1560 | {0x69, &Font_0x}, 1561 | #endif 1562 | 1563 | #if (0x0 == 0x0) 1564 | // character: 'j' 1565 | {0x6a, &Font_0x6a}, 1566 | #else 1567 | // character: 'j' == '' 1568 | {0x6a, &Font_0x}, 1569 | #endif 1570 | 1571 | #if (0x0 == 0x0) 1572 | // character: 'k' 1573 | {0x6b, &Font_0x6b}, 1574 | #else 1575 | // character: 'k' == '' 1576 | {0x6b, &Font_0x}, 1577 | #endif 1578 | 1579 | #if (0x0 == 0x0) 1580 | // character: 'l' 1581 | {0x6c, &Font_0x6c}, 1582 | #else 1583 | // character: 'l' == '' 1584 | {0x6c, &Font_0x}, 1585 | #endif 1586 | 1587 | #if (0x0 == 0x0) 1588 | // character: 'm' 1589 | {0x6d, &Font_0x6d}, 1590 | #else 1591 | // character: 'm' == '' 1592 | {0x6d, &Font_0x}, 1593 | #endif 1594 | 1595 | #if (0x0 == 0x0) 1596 | // character: 'n' 1597 | {0x6e, &Font_0x6e}, 1598 | #else 1599 | // character: 'n' == '' 1600 | {0x6e, &Font_0x}, 1601 | #endif 1602 | 1603 | #if (0x0 == 0x0) 1604 | // character: 'o' 1605 | {0x6f, &Font_0x6f}, 1606 | #else 1607 | // character: 'o' == '' 1608 | {0x6f, &Font_0x}, 1609 | #endif 1610 | 1611 | #if (0x0 == 0x0) 1612 | // character: 'p' 1613 | {0x70, &Font_0x70}, 1614 | #else 1615 | // character: 'p' == '' 1616 | {0x70, &Font_0x}, 1617 | #endif 1618 | 1619 | #if (0x0 == 0x0) 1620 | // character: 'q' 1621 | {0x71, &Font_0x71}, 1622 | #else 1623 | // character: 'q' == '' 1624 | {0x71, &Font_0x}, 1625 | #endif 1626 | 1627 | #if (0x0 == 0x0) 1628 | // character: 'r' 1629 | {0x72, &Font_0x72}, 1630 | #else 1631 | // character: 'r' == '' 1632 | {0x72, &Font_0x}, 1633 | #endif 1634 | 1635 | #if (0x0 == 0x0) 1636 | // character: 's' 1637 | {0x73, &Font_0x73}, 1638 | #else 1639 | // character: 's' == '' 1640 | {0x73, &Font_0x}, 1641 | #endif 1642 | 1643 | #if (0x0 == 0x0) 1644 | // character: 't' 1645 | {0x74, &Font_0x74}, 1646 | #else 1647 | // character: 't' == '' 1648 | {0x74, &Font_0x}, 1649 | #endif 1650 | 1651 | #if (0x0 == 0x0) 1652 | // character: 'u' 1653 | {0x75, &Font_0x75}, 1654 | #else 1655 | // character: 'u' == '' 1656 | {0x75, &Font_0x}, 1657 | #endif 1658 | 1659 | #if (0x0 == 0x0) 1660 | // character: 'v' 1661 | {0x76, &Font_0x76}, 1662 | #else 1663 | // character: 'v' == '' 1664 | {0x76, &Font_0x}, 1665 | #endif 1666 | 1667 | #if (0x0 == 0x0) 1668 | // character: 'w' 1669 | {0x77, &Font_0x77}, 1670 | #else 1671 | // character: 'w' == '' 1672 | {0x77, &Font_0x}, 1673 | #endif 1674 | 1675 | #if (0x0 == 0x0) 1676 | // character: 'x' 1677 | {0x78, &Font_0x78}, 1678 | #else 1679 | // character: 'x' == '' 1680 | {0x78, &Font_0x}, 1681 | #endif 1682 | 1683 | #if (0x0 == 0x0) 1684 | // character: 'y' 1685 | {0x79, &Font_0x79}, 1686 | #else 1687 | // character: 'y' == '' 1688 | {0x79, &Font_0x}, 1689 | #endif 1690 | 1691 | #if (0x0 == 0x0) 1692 | // character: 'z' 1693 | {0x7a, &Font_0x7a}, 1694 | #else 1695 | // character: 'z' == '' 1696 | {0x7a, &Font_0x} 1697 | #endif 1698 | {0x21, &Font_0x21}, 1699 | {0x23, &Font_0x23}, 1700 | {0x25, &Font_0x25}, 1701 | {0x26, &Font_0x26}, 1702 | {0x27, &Font_0x27}, 1703 | {0x28, &Font_0x28}, 1704 | {0x29, &Font_0x29}, 1705 | {0x2a, &Font_0x2a}, 1706 | {0x2b, &Font_0x2b}, 1707 | {0x2c, &Font_0x2c}, 1708 | {0x30, &Font_0x30}, 1709 | {0x31, &Font_0x31}, 1710 | {0x32, &Font_0x32}, 1711 | {0x33, &Font_0x33}, 1712 | {0x34, &Font_0x34}, 1713 | {0x35, &Font_0x35}, 1714 | {0x36, &Font_0x36}, 1715 | {0x37, &Font_0x37}, 1716 | {0x38, &Font_0x38}, 1717 | {0x39, &Font_0x39}, 1718 | {0x3a, &Font_0x3a}, 1719 | {0x3b, &Font_0x3b}, 1720 | {0x3d, &Font_0x3d}}; 1721 | 1722 | tFont Font = {78, Font_array}; -------------------------------------------------------------------------------- /src/font.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | typedef struct { 6 | uint8_t *data; 7 | uint16_t width; 8 | uint16_t height; 9 | uint8_t dataSize; 10 | } tImage; 11 | typedef struct { 12 | long int code; 13 | tImage *image; 14 | } tChar; 15 | typedef struct { 16 | int length; 17 | tChar *chars; 18 | } tFont; 19 | -------------------------------------------------------------------------------- /src/format.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "format.h" 5 | #ifdef PICO_HW 6 | #include "hardware/flash.h" 7 | #endif 8 | 9 | enum EFileType 10 | { 11 | FileType_NoFile = 0x00, 12 | FileType_Data = 0x33, 13 | FileType_Game = 0xCC 14 | }; 15 | 16 | enum EFATType 17 | { 18 | FATType_Free = 0xFFFC, 19 | FATType_EOF = 0xFFFA 20 | }; 21 | 22 | typedef struct Date_s 23 | { 24 | uint8_t Century; 25 | uint8_t Year; 26 | uint8_t Month; 27 | uint8_t Day; 28 | uint8_t Hour; 29 | uint8_t Minute; 30 | uint8_t Second; 31 | uint8_t DayOfWeek; 32 | } Date; 33 | 34 | typedef struct DirectoryEntry_s 35 | { 36 | uint8_t FileType; 37 | uint8_t CopyProtect; 38 | uint16_t FirstBlock; 39 | char Name[12]; 40 | Date Creation; 41 | uint16_t SizeInBlocks; 42 | uint16_t HeaderOffset; 43 | uint8_t Padding[4]; 44 | } DirectoryEntry; 45 | 46 | typedef struct RootBlock_s 47 | { 48 | uint8_t Magic[16]; 49 | uint8_t CustomColor; 50 | uint8_t CustomColorBlue; 51 | uint8_t CustomColorGreen; 52 | uint8_t CustomColorRed; 53 | uint8_t CustomColorAlpha; 54 | uint8_t Padding[27]; 55 | Date Format; 56 | uint8_t Padding2[8]; 57 | uint16_t TotalSize; // Seems to be the same as memory info but with a set bit in last uint 58 | uint16_t ParitionNumber; 59 | uint16_t SystemArea; 60 | uint16_t FATBlock; 61 | uint16_t FATSizeInBlocks; 62 | uint16_t DirectoryBlock; 63 | uint16_t DirectorySizeInBlocks; 64 | uint16_t IconShape; 65 | uint16_t NumberOfUserBlocks; 66 | uint16_t NumSaveBlocks; 67 | uint32_t Unknown; 68 | } RootBlock; 69 | 70 | // // ICONDATA_VMS generated by make_icon.cpp 71 | // static const uint8_t IconData[0x2C0] = 72 | // /* G:\ICONDATA (1).VMS (8/21/2021 11:28:53 AM) 73 | // StartOffset(h): 00000000, EndOffset(h): 000002CF, Length(h): 000002D0 */ 74 | // { 75 | // 0x2E, 0x2F, 0x75, 0x70, 0x6C, 0x6F, 0x61, 0x64, 0x2F, 0x65, 0x62, 0x37, 76 | // 0x61, 0x61, 0x30, 0x36, 0x20, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, 77 | // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 78 | // 0x00, 0x7E, 0x7F, 0x00, 0x00, 0x7E, 0x7F, 0x00, 0x01, 0xFF, 0xFF, 0xC0, 79 | // 0x02, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x20, 80 | // 0x02, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x20, 0x02, 0x7F, 0xFF, 0x20, 81 | // 0x02, 0x7F, 0xFF, 0x20, 0x02, 0x7F, 0xFF, 0x20, 0x02, 0x7F, 0xFF, 0x20, 82 | // 0x02, 0x7F, 0xFF, 0x20, 0x02, 0x7F, 0xFF, 0x20, 0x02, 0x7F, 0xFF, 0x20, 83 | // 0x02, 0x7F, 0xFF, 0x20, 0x02, 0x7F, 0xFF, 0x20, 0x02, 0x7F, 0xFF, 0x20, 84 | // 0x02, 0x7F, 0xFF, 0x20, 0x02, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x20, 85 | // 0x02, 0x00, 0xD8, 0x20, 0x02, 0x38, 0xDB, 0xA0, 0x02, 0x7C, 0x03, 0xA0, 86 | // 0x02, 0x7C, 0x73, 0xA0, 0x02, 0x7C, 0x70, 0x20, 0x02, 0x38, 0x70, 0x20, 87 | // 0x02, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x40, 0x00, 0xF0, 0x07, 0x80, 88 | // 0x00, 0x0F, 0xF8, 0x00, 0xFF, 0xFF, 0xBB, 0xFB, 0x00, 0xF0, 0x80, 0xF0, 89 | // 0x88, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 90 | // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 91 | // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 92 | // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x22, 0x22, 0x20, 93 | // 0x02, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 94 | // 0x02, 0x22, 0x22, 0x20, 0x02, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 95 | // 0x00, 0x00, 0x00, 0x02, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 96 | // 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x11, 0x11, 0x11, 0x11, 97 | // 0x11, 0x11, 0x11, 0x11, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 98 | // 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x20, 0x00, 0x00, 99 | // 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 100 | // 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 101 | // 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 102 | // 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0x10, 0x20, 0x00, 0x00, 103 | // 0x00, 0x00, 0x00, 0x20, 0x14, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 104 | // 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x12, 0x33, 0x33, 0x33, 105 | // 0x33, 0x33, 0x33, 0x32, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 106 | // 0x12, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x32, 0x10, 0x20, 0x00, 0x00, 107 | // 0x00, 0x00, 0x00, 0x20, 0x12, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x32, 108 | // 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x12, 0x33, 0x33, 0x33, 109 | // 0x33, 0x33, 0x33, 0x32, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 110 | // 0x12, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x32, 0x10, 0x20, 0x00, 0x00, 111 | // 0x00, 0x00, 0x00, 0x20, 0x12, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x32, 112 | // 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x12, 0x33, 0x33, 0x33, 113 | // 0x33, 0x33, 0x33, 0x32, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 114 | // 0x12, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x32, 0x10, 0x20, 0x00, 0x00, 115 | // 0x00, 0x00, 0x00, 0x20, 0x12, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x32, 116 | // 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x14, 0x22, 0x22, 0x22, 117 | // 0x22, 0x22, 0x22, 0x24, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 118 | // 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0x10, 0x20, 0x00, 0x00, 119 | // 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 120 | // 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x11, 0x10, 0x00, 121 | // 0x44, 0x04, 0x40, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 122 | // 0x11, 0x22, 0x21, 0x00, 0x44, 0x04, 0x41, 0x42, 0x40, 0x20, 0x00, 0x00, 123 | // 0x00, 0x00, 0x00, 0x20, 0x12, 0x22, 0x22, 0x10, 0x00, 0x00, 0x01, 0x22, 124 | // 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x12, 0x22, 0x22, 0x10, 125 | // 0x04, 0x24, 0x11, 0x42, 0x40, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 126 | // 0x12, 0x22, 0x22, 0x10, 0x02, 0x22, 0x10, 0x00, 0x10, 0x20, 0x00, 0x00, 127 | // 0x00, 0x00, 0x00, 0x20, 0x11, 0x22, 0x21, 0x00, 0x04, 0x24, 0x10, 0x00, 128 | // 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 129 | // 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 130 | // 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x12, 0x00, 0x00, 0x00, 131 | // 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x11, 0x11, 0x11, 0x11, 0x12, 0x22, 132 | // 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 133 | // 0x22, 0x22, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x1A, 0x1A, 0x1A, 134 | // 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A 135 | // }; 136 | 137 | // ICONDATA_VMS generated by make_icon.cpp 138 | static const uint8_t IconData[0x2C0] = 139 | /* G:\ICONDATA (1).VMS (8/21/2021 11:28:53 AM) 140 | StartOffset(h): 00000000, EndOffset(h): 000002CF, Length(h): 000002D0 */ 141 | { 0x56, 0x69, 0x73, 0x75, 0x61, 0x6c, 0x20, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 142 | 0x79, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 143 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 144 | 0x00, 0x03, 0xfc, 0x00, 0x00, 0x04, 0x03, 0xe0, 0x00, 0x08, 0x00, 0x10, 145 | 0x00, 0x10, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x27, 0x00, 0x04, 146 | 0x00, 0x28, 0xf8, 0x0c, 0x00, 0x50, 0x07, 0x08, 0x00, 0x54, 0x01, 0x18, 147 | 0x00, 0xa2, 0x19, 0x18, 0x00, 0xac, 0x22, 0x10, 0x01, 0x40, 0x12, 0x30, 148 | 0x01, 0x44, 0x44, 0x20, 0x02, 0x43, 0x84, 0x60, 0x02, 0x70, 0x08, 0x40, 149 | 0x04, 0x0f, 0x08, 0xc0, 0x05, 0xc0, 0xf0, 0xc0, 0x0b, 0xe0, 0x00, 0x80, 150 | 0x0b, 0xe4, 0x81, 0x80, 0x13, 0xe0, 0x01, 0x00, 0x11, 0xce, 0xe3, 0x00, 151 | 0x10, 0x0e, 0xe2, 0x00, 0x10, 0x0e, 0xe6, 0x00, 0x10, 0x00, 0x06, 0x00, 152 | 0x18, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x07, 0xc0, 0x18, 0x00, 153 | 0x01, 0xfc, 0x38, 0x00, 0x00, 0x7f, 0xf0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 154 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0xfd, 0xcc, 0xfc, 0x88, 0xf6, 155 | 0xcc, 0xfb, 0xcc, 0xfc, 0xdd, 0xfc, 0x00, 0xf0, 0x77, 0xf5, 0x00, 0xff, 156 | 0x9c, 0xf9, 0x8b, 0xf8, 0xbd, 0xfb, 0xac, 0xfa, 0xcc, 0xfc, 0xaa, 0xfa, 157 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 158 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 159 | 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 160 | 0x00, 0x00, 0x01, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0x00, 0x00, 161 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x22, 0x22, 0x21, 0x11, 162 | 0x11, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x22, 0x11, 163 | 0x11, 0x11, 0x12, 0x22, 0x11, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 164 | 0x00, 0x01, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x22, 0x11, 0x22, 0x00, 165 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 166 | 0x11, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x13, 0x33, 167 | 0x44, 0x56, 0x61, 0x11, 0x11, 0x12, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 168 | 0x01, 0x11, 0x33, 0x33, 0x33, 0x33, 0x34, 0x56, 0x11, 0x12, 0x20, 0x00, 169 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x16, 0x37, 0x33, 0x33, 0x33, 0x33, 0x38, 170 | 0x11, 0x12, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x13, 0x33, 0x73, 171 | 0x33, 0x37, 0x73, 0x38, 0x11, 0x12, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 172 | 0x11, 0x63, 0x77, 0x33, 0x33, 0x73, 0x33, 0x86, 0x11, 0x22, 0x00, 0x00, 173 | 0x00, 0x00, 0x00, 0x01, 0x11, 0x33, 0x33, 0x33, 0x33, 0x37, 0x33, 0x81, 174 | 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x16, 0x33, 0x37, 0x33, 175 | 0x37, 0x33, 0x38, 0x61, 0x12, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 176 | 0x13, 0x33, 0x33, 0x77, 0x73, 0x33, 0x38, 0x11, 0x12, 0x20, 0x00, 0x00, 177 | 0x00, 0x00, 0x00, 0x11, 0x18, 0x88, 0x33, 0x33, 0x93, 0x33, 0x86, 0x11, 178 | 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x11, 0x16, 0x88, 0x88, 179 | 0x33, 0x33, 0x81, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1a, 180 | 0xaa, 0x11, 0x11, 0x66, 0x88, 0x88, 0x61, 0x12, 0x22, 0x00, 0x00, 0x00, 181 | 0x00, 0x00, 0x11, 0xaa, 0xaa, 0xb1, 0x11, 0x11, 0x16, 0x66, 0x11, 0x12, 182 | 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xaa, 0xaa, 0xb2, 0x1a, 0x11, 183 | 0xa1, 0x11, 0x11, 0x22, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0xba, 184 | 0xab, 0xb2, 0x11, 0x11, 0x11, 0x11, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 185 | 0x00, 0x01, 0x11, 0x2b, 0xbb, 0x21, 0xca, 0xc1, 0xca, 0xc1, 0x12, 0x22, 186 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x12, 0x22, 0x11, 0xaa, 0xb1, 187 | 0xaa, 0xb2, 0x12, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x11, 188 | 0x11, 0x11, 0xcb, 0xd2, 0xcb, 0xd2, 0x22, 0x20, 0x00, 0x00, 0x00, 0x00, 189 | 0x00, 0x02, 0x11, 0x11, 0x11, 0x11, 0x12, 0x21, 0x12, 0x22, 0x22, 0x20, 190 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x22, 0x11, 0x11, 0x11, 0x11, 0x11, 191 | 0x11, 0x12, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x22, 192 | 0x21, 0x11, 0x11, 0x11, 0x11, 0x12, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 193 | 0x00, 0x00, 0x0e, 0xef, 0xf2, 0x22, 0x11, 0x11, 0x12, 0x22, 0xe0, 0x00, 194 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xef, 0xff, 0x22, 0x22, 195 | 0x22, 0x2e, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 196 | 0x0e, 0xee, 0xee, 0x22, 0x2e, 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 197 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0xee, 0xe0, 0x00, 0x00, 198 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 199 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 200 | }; 201 | 202 | static void AllocateFAT(uint16_t *FAT, uint16_t StartBlock, uint16_t NumBlocks) 203 | { 204 | uint32_t EndBlock = StartBlock + NumBlocks - 1; 205 | FAT[StartBlock] = FATType_EOF; 206 | while (StartBlock != EndBlock) 207 | { 208 | StartBlock++; 209 | FAT[StartBlock] = StartBlock - 1; 210 | } 211 | } 212 | 213 | // Soft pink color: 233, 209, 255, 175 214 | // 215 | 216 | uint32_t pagePalette[] = { 217 | 0xff474796, 218 | 0xed7d0a96, 219 | 0x19863e96, 220 | 0x8af4c396, 221 | 0x056bff96, 222 | 0x211c9e96, 223 | 0xbc5dd496, 224 | 0xf6abe596 225 | }; 226 | 227 | uint32_t CheckFormatted(uint8_t *MemoryCard, uint32_t CurrentPage) 228 | { 229 | uint32_t SectorDirty = 0; 230 | const RootBlock Root = 231 | { 232 | {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55}, 233 | 1, pagePalette[CurrentPage - 1] >> 8 & 0xFF, pagePalette[CurrentPage - 1] >> 16 & 0xFF, pagePalette[CurrentPage - 1] >> 24 & 0xFF, pagePalette[CurrentPage - 1] & 0xFF, {0}, {0x20, 0x21, 0x03, 0x02, 0x09, 0x00, 0x00, 0x01}, {0}, CARD_BLOCKS - 1, 234 | 0, ROOT_BLOCK, FAT_BLOCK, NUM_FAT_BLOCKS, DIRECTORY_BLOCK, NUM_DIRECTORY_BLOCKS, 0, SAVE_BLOCK, NUM_SAVE_BLOCKS, 0x800000}; 235 | 236 | if (memcmp(&MemoryCard[ROOT_BLOCK * BLOCK_SIZE], Root.Magic, sizeof(Root.Magic)) != 0) 237 | { 238 | // If not formatted then initialize ourselves. Saves user a step + means we can have a fancy icon 239 | uint32_t StartOfDirectoryBlock = Root.DirectoryBlock - Root.DirectorySizeInBlocks + 1; 240 | memset(&MemoryCard[StartOfDirectoryBlock * BLOCK_SIZE], 0, (256 - StartOfDirectoryBlock) * BLOCK_SIZE); 241 | memcpy(&MemoryCard[ROOT_BLOCK * BLOCK_SIZE], &Root, sizeof(Root)); 242 | 243 | const DirectoryEntry IconDataVMS = {FileType_Data, 0, SAVE_BLOCK - 2, "ICONDATA_VMS", {0x20, 0x21, 0x03, 0x02, 0x09, 0x00, 0x00, 0x01}, 2, 0}; 244 | memcpy(&MemoryCard[Root.DirectoryBlock * BLOCK_SIZE], &IconDataVMS, sizeof(IconDataVMS)); 245 | memcpy(&MemoryCard[IconDataVMS.FirstBlock * BLOCK_SIZE], &IconData, sizeof(IconData)); 246 | 247 | uint32_t StartOfFATBlock = Root.FATBlock - Root.FATSizeInBlocks + 1; 248 | uint16_t *FAT = (uint16_t *)&MemoryCard[StartOfFATBlock * BLOCK_SIZE]; 249 | for (uint32_t Block = 0; Block < Root.FATSizeInBlocks * (BLOCK_SIZE / sizeof(uint16_t)); Block++) 250 | { 251 | FAT[Block] = FATType_Free; 252 | } 253 | AllocateFAT(FAT, ROOT_BLOCK, 1); 254 | AllocateFAT(FAT, StartOfFATBlock, Root.FATSizeInBlocks); 255 | AllocateFAT(FAT, StartOfDirectoryBlock, Root.DirectorySizeInBlocks); 256 | FAT[IconDataVMS.FirstBlock] = IconDataVMS.FirstBlock + 1; 257 | FAT[IconDataVMS.FirstBlock + 1] = FATType_EOF; 258 | 259 | #if PICO_HW 260 | // Everything above StartOfDirectoryBlock now needs writing to flash + icon data 261 | SectorDirty |= ~((1u << ((StartOfDirectoryBlock * BLOCK_SIZE) / FLASH_SECTOR_SIZE)) - 1); 262 | SectorDirty |= 1u << ((IconDataVMS.FirstBlock * BLOCK_SIZE) / FLASH_SECTOR_SIZE); 263 | #endif 264 | } 265 | return SectorDirty; 266 | } -------------------------------------------------------------------------------- /src/format.h: -------------------------------------------------------------------------------- 1 | #ifdef __cplusplus 2 | extern "C" { 3 | #endif 4 | 5 | #define CARD_BLOCKS 256 6 | #define ROOT_BLOCK 255 7 | #define FAT_BLOCK 254 8 | #define NUM_FAT_BLOCKS 1 9 | #define DIRECTORY_BLOCK 253 10 | #define NUM_DIRECTORY_BLOCKS 13 11 | #define SAVE_BLOCK 200 12 | #define NUM_SAVE_BLOCKS 31 // Not sure what this means 13 | 14 | #define BLOCK_SIZE 512 15 | 16 | uint32_t CheckFormatted(uint8_t *MemoryCard, uint32_t CurrentPage); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif -------------------------------------------------------------------------------- /src/maple.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "format.h" 9 | #include "maple.pio.h" 10 | #include "pico/stdlib.h" 11 | 12 | #include "ssd1306.h" 13 | #include "ssd1331.h" 14 | 15 | #include "hardware/adc.h" 16 | #include "hardware/flash.h" 17 | #include "hardware/i2c.h" 18 | #include "hardware/irq.h" 19 | #include "hardware/pio.h" 20 | #include "hardware/pwm.h" 21 | #include "hardware/timer.h" 22 | #include "maple.pio.h" 23 | #include "pico/multicore.h" 24 | #include "pico/stdlib.h" 25 | #include "pico/time.h" 26 | #include "state_machine.h" 27 | 28 | #define HKT7700 0 // "Seed" (standard controller) 29 | #define HKT7300 1 // Arcade stick 30 | 31 | #if HKT7700 32 | #define NUM_BUTTONS 9 33 | #elif HKT7300 34 | #define NUM_BUTTONS 11 35 | #endif 36 | 37 | #define CURRENT_FW_VERSION VER_1_5 38 | 39 | #define VER_1_0 0x00 40 | #define VER_1_1 0x01 41 | #define VER_1_2 0x02 42 | #define VER_1_3 0x03 43 | #define VER_1_3b 0x04 44 | #define VER_1_4 0x05 45 | #define VER_1_4b 0x06 46 | #define VER_1_4c 0x07 47 | #define VER_1_4d 0x08 48 | #define VER_1_4e 0x09 49 | #define VER_1_5 0x0A 50 | #define VER_1_6 0x0B 51 | #define VER_1_7 0x0C 52 | 53 | extern uint8_t flashData[]; 54 | 55 | void updateFlashData(); 56 | 57 | typedef struct PacketHeader_s { 58 | int8_t Command; 59 | uint8_t Destination; 60 | uint8_t Origin; 61 | uint8_t NumWords; 62 | } PacketHeader; 63 | 64 | typedef struct PacketDeviceInfo_s { 65 | uint Func; // Nb. Big endian 66 | uint FuncData[3]; // Nb. Big endian 67 | int8_t AreaCode; 68 | uint8_t ConnectorDirection; 69 | char ProductName[30]; 70 | char ProductLicense[60]; 71 | uint16_t StandbyPower; 72 | uint16_t MaxPower; 73 | } PacketDeviceInfo; 74 | 75 | typedef struct PacketAllDeviceInfo_s { 76 | uint Func; // Nb. Big endian 77 | uint FuncData[3]; // Nb. Big endian 78 | int8_t AreaCode; 79 | uint8_t ConnectorDirection; 80 | char ProductName[30]; 81 | char ProductLicense[60]; 82 | uint16_t StandbyPower; 83 | uint16_t MaxPower; 84 | char FreeDeviceStatus[80]; 85 | } PacketAllDeviceInfo; 86 | 87 | typedef struct PacketMemoryInfo_s { 88 | uint Func; // Nb. Big endian 89 | uint16_t TotalSize; 90 | uint16_t ParitionNumber; 91 | uint16_t SystemArea; 92 | uint16_t FATArea; 93 | uint16_t NumFATBlocks; 94 | uint16_t FileInfoArea; 95 | uint16_t NumInfoBlocks; 96 | uint8_t VolumeIcon; 97 | uint8_t Reserved; 98 | uint16_t SaveArea; 99 | uint16_t NumSaveBlocks; 100 | uint Reserved32; 101 | uint16_t Reserved16; 102 | } PacketMemoryInfo; 103 | 104 | typedef struct PacketLCDInfo_s { 105 | uint Func; // Nb. Big endian 106 | uint8_t dX; // Number of X-axis dots 107 | uint8_t dY; // Number of Y-axis dots 108 | uint8_t GradContrast; // Upper nybble Gradation (bits/dot), lower nybble contrast (0 to 16 steps) 109 | uint8_t Reserved; 110 | 111 | } PacketLCDInfo; 112 | 113 | typedef struct PacketPuruPuruInfo_s { 114 | uint Func; // Nb. Big endian 115 | uint8_t VSet0; // Upper nybble is number of vibration sources, lower nybble is vibration source location and vibration source axis 116 | uint8_t Vset1; // b7: Variable vibration intensity flag, b6: Continuous vibration flag, b5: Vibration direction control flag, b4: Arbitrary waveform flag 117 | // Lower nybble is Vibration Attribute flag (fixed freq. or ranged freq.) 118 | uint8_t FMin; // Minimum vibration frequency when VA = 0000 (Ffix when VA = 0001, reserved when VA = 1111) 119 | uint8_t FMax; // Maximum vibration frequency when VA = 0000 (reserved when VA= 0001 or 1111) 120 | 121 | } PacketPuruPuruInfo; 122 | 123 | typedef struct PacketControllerCondition_s { 124 | uint Condition; // Nb. Big endian 125 | uint16_t Buttons; 126 | uint8_t RightTrigger; 127 | uint8_t LeftTrigger; 128 | uint8_t JoyX; 129 | uint8_t JoyY; 130 | uint8_t JoyX2; 131 | uint8_t JoyY2; 132 | } PacketControllerCondition; 133 | 134 | typedef struct PacketPuruPuruCondition_s { 135 | uint Func; // Nb. Big endian 136 | uint8_t Ctrl; // Vibration control 137 | uint8_t Power; // Vibration intensity 138 | uint8_t Freq; // Vibration frequency 139 | uint8_t Inc; // Vibration inclination 140 | } PacketPuruPuruCondition; 141 | 142 | typedef struct PacketTimerCondition_s { 143 | uint Func; // Nb. Big endian 144 | uint8_t BT; // Button data 145 | uint8_t Reserved[3]; // Reserved (0) 146 | } PacketTimerCondition; 147 | 148 | typedef struct PacketBlockRead_s { 149 | uint Func; // Nb. Big endian 150 | uint Address; 151 | uint8_t Data[BLOCK_SIZE]; 152 | } PacketBlockRead; 153 | 154 | typedef struct PuruPuruBlockReadPacket_s { 155 | uint Func; // Nb. Big endian 156 | uint Address; 157 | uint8_t Data[4]; 158 | } PuruPuruBlockReadPacket; 159 | 160 | typedef struct TimerBlockReadPacket_s { 161 | uint Func; // Nb. Big endian 162 | uint8_t Date[8]; 163 | } TimerBlockReadPacket; 164 | 165 | typedef struct FACKPacket_s { 166 | uint BitPairsMinus1; 167 | PacketHeader Header; 168 | uint CRC; 169 | } FACKPacket; 170 | 171 | typedef struct FInfoPacket_s { 172 | uint BitPairsMinus1; 173 | PacketHeader Header; 174 | PacketDeviceInfo Info; 175 | uint CRC; 176 | } FInfoPacket; 177 | 178 | typedef struct FAllInfoPacket_s { 179 | uint BitPairsMinus1; 180 | PacketHeader Header; 181 | PacketAllDeviceInfo Info; 182 | uint CRC; 183 | } FAllInfoPacket; 184 | 185 | typedef struct FMemoryInfoPacket_s { 186 | uint BitPairsMinus1; 187 | PacketHeader Header; 188 | PacketMemoryInfo Info; 189 | uint CRC; 190 | } FMemoryInfoPacket; 191 | 192 | typedef struct FLCDInfoPacket_s { 193 | uint BitPairsMinus1; 194 | PacketHeader Header; 195 | PacketLCDInfo Info; 196 | uint CRC; 197 | } FLCDInfoPacket; 198 | 199 | typedef struct FPuruPuruInfoPacket_s { 200 | uint BitPairsMinus1; 201 | PacketHeader Header; 202 | PacketPuruPuruInfo Info; 203 | uint CRC; 204 | } FPuruPuruInfoPacket; 205 | 206 | typedef struct FPuruPuruConditionPacket_s { 207 | uint BitPairsMinus1; 208 | PacketHeader Header; 209 | PacketPuruPuruCondition Condition; 210 | uint CRC; 211 | } FPuruPuruConditionPacket; 212 | 213 | typedef struct FTimerConditionPacket_s { 214 | uint BitPairsMinus1; 215 | PacketHeader Header; 216 | PacketTimerCondition Condition; 217 | uint CRC; 218 | } FTimerConditionPacket; 219 | 220 | typedef struct FControllerPacket_s { 221 | uint BitPairsMinus1; 222 | PacketHeader Header; 223 | PacketControllerCondition Controller; 224 | uint CRC; 225 | } FControllerPacket; 226 | 227 | typedef struct FPuruPuruBlockReadResponsePacket_s { 228 | uint BitPairsMinus1; 229 | PacketHeader Header; 230 | PuruPuruBlockReadPacket PuruPuruBlockRead; 231 | uint CRC; 232 | } FPuruPuruBlockReadResponsePacket; 233 | 234 | typedef struct FBlockReadResponsePacket_s { 235 | uint BitPairsMinus1; 236 | PacketHeader Header; 237 | PacketBlockRead BlockRead; 238 | uint CRC; 239 | } FBlockReadResponsePacket; 240 | 241 | typedef struct FTimerBlockReadResponsePacket_s { 242 | uint BitPairsMinus1; 243 | PacketHeader Header; 244 | TimerBlockReadPacket TimerBlockRead; 245 | uint CRC; 246 | } FTimerBlockReadResponsePacket; 247 | 248 | typedef struct ButtonInfo_s { 249 | int InputIO; 250 | int DCButtonMask; 251 | } ButtonInfo; 252 | 253 | static ButtonInfo ButtonInfos[NUM_BUTTONS] = { 254 | {0, 0x0004}, // A 255 | {1, 0x0002}, // B 256 | {4, 0x0400}, // X 257 | {5, 0x0200}, // Y 258 | {6, 0x0010}, // Up 259 | {7, 0x0020}, // Down 260 | {8, 0x0040}, // Left 261 | {9, 0x0080}, // Right 262 | {10, 0x0008} // Start 263 | #if HKT7300 264 | , 265 | {16, 0x0001}, // C 266 | {17, 0x0100} // Z 267 | #endif 268 | }; -------------------------------------------------------------------------------- /src/maple.pio: -------------------------------------------------------------------------------- 1 | ; 2 | ; Maple TX/RX PIO code by Charlie Cole 3 | ; 4 | 5 | .program maple_tx 6 | .side_set 1 7 | .define HOLD 12 ; Cycles to hold after clocking data 8 | .define SETTLE 6 ; Cycles to hold data before clocking 9 | .define MID 6 ; Cycles before starting transitions for next bit 10 | 11 | set pindirs, 0 side 1 ; Set to input 12 | 13 | ; set up loop 14 | pull side 1 [HOLD] ; Used to align back to 32 bits. Will block here until packet ready to send 15 | out x,32 side 1 ; size of packet in bit pairs - 1 16 | set pindirs, 3 side 1 ; Set pins to output (drive the bus) 17 | 18 | ; Send the sync pulses to start the packet 19 | set y,3 side 1 20 | set pins, 2 side 1 [HOLD] 21 | syncloop: 22 | nop side 0 [HOLD] 23 | jmp y-- syncloop side 1 [HOLD] 24 | set pins, 3 side 1 [MID] 25 | nop side 0 [HOLD] 26 | 27 | ; Send the actual data 28 | dataloop: 29 | out y, 1 side 0 30 | set pins, 1 side 0 [MID-1] 31 | jmp !y, send_zero side 0 32 | 33 | ; Send a one 34 | nop side 1 [SETTLE] 35 | set pins, 2 side 1 [HOLD] 36 | jmp outro side 1 [MID] 37 | 38 | send_zero: 39 | nop side 0 [SETTLE] 40 | set pins, 0 side 0 [HOLD] 41 | nop side 1 [MID] 42 | 43 | outro: 44 | out pins, 1 side 1 [SETTLE] 45 | jmp x-- dataloop side 0 [HOLD-1] 46 | 47 | ; Send the tail sequence to signify end of packet 48 | set pins, 1 side 0 [HOLD] 49 | nop side 1 [HOLD] 50 | nop side 0 [HOLD] 51 | set pins, 0 side 0 [HOLD] 52 | set pins, 1 side 0 [HOLD] 53 | set pins, 0 side 0 [HOLD] 54 | set pins, 1 side 0 [HOLD] 55 | set pins, 3 side 1 [HOLD] 56 | 57 | % c-sdk { 58 | static inline void maple_tx_program_init(PIO TXPio, uint SM, uint Offset, uint Pin1, uint Pin5, float ClockDivider) 59 | { 60 | pio_sm_config SMConfig = maple_tx_program_get_default_config(Offset); 61 | assert(Pin5 == Pin1 + 1); // Need to be consecutive for set to control both pins 62 | 63 | sm_config_set_out_pins(&SMConfig, Pin1, 1); // Only want to output on pin 1 (so we can shift directly) 64 | sm_config_set_set_pins(&SMConfig, Pin1, 2); // But we need to set direction of both pins to take control of bus 65 | sm_config_set_sideset_pins(&SMConfig, Pin5); // Possibly could do without on second thoughts but saves some instructions 66 | 67 | sm_config_set_out_shift(&SMConfig, false, true, 32); // Autopull every 32 bits (makes DMA more efficient to do it this way) 68 | sm_config_set_clkdiv(&SMConfig, ClockDivider); 69 | sm_config_set_fifo_join(&SMConfig, PIO_FIFO_JOIN_TX); // Not using RX FIFO so double TX FIFO length 70 | 71 | // Set the pin direction to input at the PIO but high when used as output 72 | pio_sm_set_pins_with_mask(TXPio, SM, (1u << Pin1) | (1u << Pin5), (1u << Pin1) | (1u << Pin5)); 73 | pio_sm_set_pindirs_with_mask(TXPio, SM, 0, (1u << Pin1) | (1u << Pin5)); 74 | 75 | // Set this pin's GPIO function (connect PIO to the pad) 76 | pio_gpio_init(TXPio, Pin1); 77 | pio_gpio_init(TXPio, Pin5); 78 | 79 | pio_sm_init(TXPio, SM, Offset, &SMConfig); // Load our configuration, and jump to the start of the program 80 | pio_sm_set_enabled(TXPio, SM, true); // Set the state machine running 81 | } 82 | %} 83 | 84 | ; Just shifts in pins whenever there's a change 85 | ; Done as three programs as hard to deal with multiple input pins due to lack of masking 86 | 87 | ; Waits for signal from other programs and then shifts current state of pins 88 | .program maple_rx_triple1 89 | wait 1 irq 7 90 | in pins, 2 91 | 92 | ; Waits for transition on the maple bus pin 1 (data) then signals maple_rx_triple1 93 | .program maple_rx_triple2 94 | wait 0 pin 0 95 | irq 7 96 | wait 1 pin 0 97 | irq 7 98 | 99 | ; Waits for transition on the maple bus pin 5 (data) then signals maple_rx_triple1 100 | .program maple_rx_triple3 101 | wait 0 pin 1 102 | irq 7 103 | wait 1 pin 1 104 | irq 7 105 | 106 | % c-sdk { 107 | static inline void maple_rx_triple_program_init(PIO RXPio, uint* Offset, uint Pin1, uint Pin5, float ClockDivider) 108 | { 109 | assert(Pin5 == Pin1 + 1); 110 | for (int SM = 0; SM < 3; SM++) 111 | { 112 | // Both pins inputs 113 | pio_sm_set_consecutive_pindirs(RXPio, SM, Pin1, 2, false); 114 | 115 | pio_sm_config c = 116 | (SM == 0)?maple_rx_triple1_program_get_default_config(Offset[0]): 117 | ((SM == 1)?maple_rx_triple2_program_get_default_config(Offset[1]): 118 | maple_rx_triple3_program_get_default_config(Offset[2])); 119 | 120 | sm_config_set_in_pins(&c, Pin1); 121 | 122 | // autopush every 8 bits (gives possibly 3 missed transitions which is enough to still detect end of packet) 123 | sm_config_set_in_shift(&c, false, true, 8); 124 | sm_config_set_clkdiv(&c, ClockDivider); 125 | sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX); // Not using transmit FIFO so use it for recieving 126 | 127 | // Load our configuration, and jump to the start of the program 128 | pio_sm_init(RXPio, SM, Offset[SM], &c); 129 | } 130 | } 131 | %} 132 | -------------------------------------------------------------------------------- /src/menu.c: -------------------------------------------------------------------------------- 1 | /* 2 | * MaplePad Menu 3 | * 4 | * Attempt at a flexible & extensible hierarchical menu system 5 | * 6 | * TO-DO: 7 | * ☐ VMU Palette submenu 8 | * ☐ UI Palette submenu 9 | * ☐ Deadzone adjust submenus for stick + trigger 10 | * ☐ Button test submenu (lineart + ellipse routine for now) 11 | * ☐ OLED Detect (ssd1331present, needs to make certain menu items invisible if ssd1306 is selected) 12 | * 13 | */ 14 | 15 | #include "maple.h" 16 | #include "menu.h" 17 | #include "display.h" 18 | 19 | uint32_t flipLockout; 20 | volatile bool redraw = 1; 21 | 22 | struct repeating_timer redrawTimer; 23 | 24 | static uint16_t color = 0x0000; 25 | 26 | int paletteVMU(menu *self) { 27 | // draw VMU palette selection 28 | return (1); 29 | } 30 | 31 | int paletteUI(menu *self) { 32 | // draw UI palette selection 33 | return (1); 34 | } 35 | 36 | int buttontest(menu *self) { 37 | // draw button test 38 | return (1); 39 | } 40 | 41 | int sCal(menu *self) { 42 | // draw stick calibration 43 | redraw = 0; // Disable redrawMenu 44 | 45 | while (!gpio_get(ButtonInfos[0].InputIO)); 46 | 47 | clearDisplay(); 48 | char *cal_string = "Center stick,"; 49 | putString(cal_string, 0, 0, color); 50 | cal_string = "then press A!"; 51 | putString(cal_string, 0, 1, color); 52 | updateDisplay(); 53 | 54 | sleep_ms(50); 55 | while (gpio_get(ButtonInfos[0].InputIO)); 56 | 57 | adc_select_input(0); // X 58 | xCenter = adc_read() >> 4; 59 | 60 | adc_select_input(1); // Y 61 | yCenter = adc_read() >> 4; 62 | 63 | clearDisplay(); 64 | cal_string = "Move stick"; 65 | putString(cal_string, 0, 0, color); 66 | cal_string = " around"; 67 | putString(cal_string, 0, 1, color); 68 | cal_string = " a lot!"; 69 | putString(cal_string, 0, 2, color); 70 | updateDisplay(); 71 | 72 | xMin = 0x80; 73 | xMax = 0x80; 74 | yMin = 0x80; 75 | yMax = 0x80; 76 | 77 | uint32_t start = to_ms_since_boot(get_absolute_time()); 78 | while ((to_ms_since_boot(get_absolute_time()) - start) < 4000 ? true : gpio_get(ButtonInfos[0].InputIO)) { 79 | static bool prompt = true; 80 | static uint8_t xData = 0; 81 | static uint8_t yData = 0; 82 | 83 | adc_select_input(0); // X 84 | xData = adc_read() >> 4; 85 | 86 | adc_select_input(1); // Y 87 | yData = adc_read() >> 4; 88 | 89 | if (xData < xMin) 90 | xMin = xData; 91 | else if (xData > xMax) 92 | xMax = xData; 93 | 94 | if (yData < yMin) 95 | yMin = yData; 96 | else if (yData > yMax) 97 | yMax = yData; 98 | 99 | // printf("\033[H\033[2J"); 100 | // printf("\033[36m"); 101 | // printf("xRaw: 0x%04x yRaw: 0x%02x\n", xRaw, yRaw); 102 | // printf("xData: 0x%02x yData: 0x%02x\n", xData, yData); 103 | // printf("xMin: 0x%02x xMax: 0x%02x yMin: 0x%02x yMax: 0x%02x\n", xMin, xMax, yMin, yMax); 104 | // sleep_ms(50); 105 | 106 | if ((to_ms_since_boot(get_absolute_time()) - start) >= 4000 && prompt) { 107 | prompt = false; 108 | cal_string = " Press A"; 109 | putString(cal_string, 0, 3, color); 110 | cal_string = " when done!"; 111 | putString(cal_string, 0, 4, color); 112 | updateDisplay(); 113 | } 114 | } 115 | 116 | // Write config values to flash 117 | updateFlashData(); 118 | 119 | redraw = 1; 120 | 121 | return (1); 122 | } 123 | 124 | int tCal(menu *self) { 125 | // draw trigger calibration 126 | redraw = 0; // Disable redrawMenu 127 | 128 | while (!gpio_get(ButtonInfos[0].InputIO)) 129 | ; 130 | 131 | clearDisplay(); 132 | char *cal_string = "leave"; 133 | putString(cal_string, 0, 0, color); 134 | cal_string = "triggers idle"; 135 | putString(cal_string, 0, 1, color); 136 | cal_string = "and press A"; 137 | putString(cal_string, 0, 2, color); 138 | updateDisplay(); 139 | 140 | sleep_ms(500); 141 | while (gpio_get(ButtonInfos[0].InputIO)) 142 | ; 143 | 144 | adc_select_input(2); // L 145 | lMin = adc_read() >> 4; 146 | 147 | adc_select_input(3); // R 148 | rMin = adc_read() >> 4; 149 | 150 | clearDisplay(); 151 | cal_string = "hold lMax"; 152 | putString(cal_string, 0, 0, color); 153 | cal_string = "and press A"; 154 | putString(cal_string, 0, 1, color); 155 | updateDisplay(); 156 | 157 | sleep_ms(500); 158 | while (gpio_get(ButtonInfos[0].InputIO)) 159 | ; 160 | 161 | adc_select_input(2); // lMax 162 | lMax = adc_read() >> 4; 163 | 164 | clearDisplay(); 165 | cal_string = "hold rMax"; 166 | putString(cal_string, 0, 0, color); 167 | cal_string = "and press A"; 168 | putString(cal_string, 0, 1, color); 169 | updateDisplay(); 170 | 171 | sleep_ms(500); 172 | while (gpio_get(ButtonInfos[0].InputIO)) 173 | ; 174 | 175 | adc_select_input(3); // rMax 176 | rMax = adc_read() >> 4; 177 | 178 | if (lMin > lMax) { 179 | uint temp = lMin; 180 | lMin = lMax; 181 | lMax = temp; 182 | } 183 | 184 | if (rMin > rMax) { 185 | uint temp = rMin; 186 | rMin = rMax; 187 | rMax = temp; 188 | } 189 | 190 | // Write config values to flash 191 | updateFlashData(); 192 | 193 | redraw = 1; 194 | 195 | return (1); 196 | } 197 | 198 | int sDeadzone(menu *self) { 199 | // draw deadzone configuration 200 | 201 | redraw = 0; 202 | 203 | char* cal_string = "X Deadzone"; 204 | char sdata[5] = {0}; 205 | 206 | while(!gpio_get(ButtonInfos[0].InputIO)); 207 | 208 | while (gpio_get(ButtonInfos[0].InputIO)) { 209 | clearDisplay(); 210 | putString(cal_string, 0, 0, color); 211 | sprintf(sdata, "0x%02x", xDeadzone); 212 | putString(sdata, 3, 2, color); 213 | updateDisplay(); 214 | 215 | if (!gpio_get(ButtonInfos[4].InputIO)){ 216 | if (xDeadzone < 128) 217 | xDeadzone++;} 218 | else if (!gpio_get(ButtonInfos[5].InputIO)){ 219 | if (xDeadzone > 0) 220 | xDeadzone--;} 221 | else if (!gpio_get(ButtonInfos[6].InputIO)){ 222 | if (xDeadzone > 7) 223 | xDeadzone = xDeadzone - 8;} 224 | else if (!gpio_get(ButtonInfos[7].InputIO)){ 225 | if (xDeadzone < 121) 226 | xDeadzone = xDeadzone + 8;} 227 | 228 | sleep_ms(60); 229 | } 230 | 231 | while(!gpio_get(ButtonInfos[0].InputIO)); 232 | 233 | while (gpio_get(ButtonInfos[0].InputIO)) { 234 | clearDisplay(); 235 | cal_string = "X"; 236 | putString(cal_string, 5, 0, color); 237 | cal_string = "AntiDeadzone"; 238 | putString(cal_string, 0, 1, color); 239 | sprintf(sdata, "0x%02x", xAntiDeadzone); 240 | putString(sdata, 3, 3, color); 241 | updateDisplay(); 242 | 243 | if (!gpio_get(ButtonInfos[4].InputIO)){ 244 | if (xAntiDeadzone < 128) 245 | xAntiDeadzone++;} 246 | else if (!gpio_get(ButtonInfos[5].InputIO)){ 247 | if (xAntiDeadzone > 0) 248 | xAntiDeadzone--;} 249 | else if (!gpio_get(ButtonInfos[6].InputIO)){ 250 | if (xAntiDeadzone > 7) 251 | xAntiDeadzone = xAntiDeadzone - 8;} 252 | else if (!gpio_get(ButtonInfos[7].InputIO)){ 253 | if (xAntiDeadzone < 121) 254 | xAntiDeadzone = xAntiDeadzone + 8;} 255 | 256 | sleep_ms(60); 257 | } 258 | 259 | while(!gpio_get(ButtonInfos[0].InputIO)); 260 | 261 | while (gpio_get(ButtonInfos[0].InputIO)) { 262 | clearDisplay(); 263 | cal_string = "Y Deadzone"; 264 | putString(cal_string, 0, 0, color); 265 | sprintf(sdata, "0x%02x", yDeadzone); 266 | putString(sdata, 3, 2, color); 267 | updateDisplay(); 268 | 269 | if (!gpio_get(ButtonInfos[4].InputIO)){ 270 | if (yDeadzone < 128) 271 | yDeadzone++;} 272 | else if (!gpio_get(ButtonInfos[5].InputIO)){ 273 | if (yDeadzone > 0) 274 | yDeadzone--;} 275 | else if (!gpio_get(ButtonInfos[6].InputIO)){ 276 | if (yDeadzone > 7) 277 | yDeadzone = yDeadzone - 8;} 278 | else if (!gpio_get(ButtonInfos[7].InputIO)){ 279 | if (yDeadzone < 121) 280 | yDeadzone = yDeadzone + 8;} 281 | 282 | sleep_ms(60); 283 | } 284 | 285 | while(!gpio_get(ButtonInfos[0].InputIO)); 286 | 287 | while (gpio_get(ButtonInfos[0].InputIO)) { 288 | clearDisplay(); 289 | cal_string = "Y"; 290 | putString(cal_string, 5, 0, color); 291 | cal_string = "AntiDeadzone"; 292 | putString(cal_string, 0, 1, color); 293 | sprintf(sdata, "0x%02x", yAntiDeadzone); 294 | putString(sdata, 3, 3, color); 295 | updateDisplay(); 296 | 297 | if (!gpio_get(ButtonInfos[4].InputIO)){ 298 | if (yAntiDeadzone < 128) 299 | yAntiDeadzone++;} 300 | else if (!gpio_get(ButtonInfos[5].InputIO)){ 301 | if (yAntiDeadzone > 0) 302 | yAntiDeadzone--;} 303 | else if (!gpio_get(ButtonInfos[6].InputIO)){ 304 | if (yAntiDeadzone > 7) 305 | yAntiDeadzone = yAntiDeadzone - 8;} 306 | else if (!gpio_get(ButtonInfos[7].InputIO)){ 307 | if (yAntiDeadzone < 121) 308 | yAntiDeadzone = yAntiDeadzone + 8;} 309 | 310 | sleep_ms(60); 311 | } 312 | 313 | updateFlashData(); 314 | 315 | clearDisplay(); 316 | 317 | redraw = 1; 318 | 319 | return (1); 320 | } 321 | 322 | int tDeadzone(menu *self) { 323 | // draw deadzone configuration 324 | 325 | redraw = 0; 326 | 327 | char* cal_string = "L Deadzone"; 328 | char tdata[5]; 329 | 330 | while(!gpio_get(ButtonInfos[0].InputIO)); 331 | 332 | while (gpio_get(ButtonInfos[0].InputIO)) { 333 | clearDisplay(); 334 | putString(cal_string, 0, 0, color); 335 | sprintf(tdata, "0x%02x", lDeadzone); 336 | putString(tdata, 3, 2, color); 337 | updateDisplay(); 338 | 339 | if (!gpio_get(ButtonInfos[4].InputIO)){ 340 | if (lDeadzone < 128) 341 | lDeadzone++;} 342 | else if (!gpio_get(ButtonInfos[5].InputIO)){ 343 | if (lDeadzone > 0) 344 | lDeadzone--;} 345 | else if (!gpio_get(ButtonInfos[6].InputIO)){ 346 | if (lDeadzone > 7) 347 | lDeadzone = lDeadzone - 8;} 348 | else if (!gpio_get(ButtonInfos[7].InputIO)){ 349 | if (lDeadzone < 121) 350 | lDeadzone = lDeadzone + 8;} 351 | 352 | sleep_ms(60); 353 | } 354 | 355 | while(!gpio_get(ButtonInfos[0].InputIO)); 356 | 357 | while (gpio_get(ButtonInfos[0].InputIO)) { 358 | clearDisplay(); 359 | cal_string = "L"; 360 | putString(cal_string, 5, 0, color); 361 | cal_string = "AntiDeadzone"; 362 | putString(cal_string, 0, 1, color); 363 | sprintf(tdata, "0x%02x", lAntiDeadzone); 364 | putString(tdata, 3, 3, color); 365 | updateDisplay(); 366 | 367 | if (!gpio_get(ButtonInfos[4].InputIO)){ 368 | if (lAntiDeadzone < 128) 369 | lAntiDeadzone++;} 370 | else if (!gpio_get(ButtonInfos[5].InputIO)){ 371 | if (lAntiDeadzone > 0) 372 | lAntiDeadzone--;} 373 | else if (!gpio_get(ButtonInfos[6].InputIO)){ 374 | if (lAntiDeadzone > 7) 375 | lAntiDeadzone = lAntiDeadzone - 8;} 376 | else if (!gpio_get(ButtonInfos[7].InputIO)){ 377 | if (lAntiDeadzone < 121) 378 | lAntiDeadzone = lAntiDeadzone + 8;} 379 | 380 | sleep_ms(60); 381 | } 382 | 383 | while(!gpio_get(ButtonInfos[0].InputIO)); 384 | 385 | while (gpio_get(ButtonInfos[0].InputIO)) { 386 | clearDisplay(); 387 | cal_string = "R Deadzone"; 388 | putString(cal_string, 0, 0, color); 389 | sprintf(tdata, "0x%02x", rDeadzone); 390 | putString(tdata, 3, 2, color); 391 | updateDisplay(); 392 | 393 | if (!gpio_get(ButtonInfos[4].InputIO)){ 394 | if (rDeadzone < 128) 395 | rDeadzone++;} 396 | else if (!gpio_get(ButtonInfos[5].InputIO)){ 397 | if (rDeadzone > 0) 398 | rDeadzone--;} 399 | else if (!gpio_get(ButtonInfos[6].InputIO)){ 400 | if (rDeadzone > 7) 401 | rDeadzone = rDeadzone - 8;} 402 | else if (!gpio_get(ButtonInfos[7].InputIO)){ 403 | if (rDeadzone < 121) 404 | rDeadzone = rDeadzone + 8;} 405 | 406 | sleep_ms(60); 407 | } 408 | 409 | while(!gpio_get(ButtonInfos[0].InputIO)); 410 | 411 | while (gpio_get(ButtonInfos[0].InputIO)) { 412 | clearDisplay(); 413 | cal_string = "R"; 414 | putString(cal_string, 5, 0, color); 415 | cal_string = "AntiDeadzone"; 416 | putString(cal_string, 0, 1, color); 417 | sprintf(tdata, "0x%02x", rAntiDeadzone); 418 | putString(tdata, 3, 3, color); 419 | updateDisplay(); 420 | 421 | if (!gpio_get(ButtonInfos[4].InputIO)){ 422 | if (rAntiDeadzone < 128) 423 | rAntiDeadzone++;} 424 | else if (!gpio_get(ButtonInfos[5].InputIO)){ 425 | if (rAntiDeadzone > 0) 426 | rAntiDeadzone--;} 427 | else if (!gpio_get(ButtonInfos[6].InputIO)){ 428 | if (rAntiDeadzone > 7) 429 | rAntiDeadzone = rAntiDeadzone - 8;} 430 | else if (!gpio_get(ButtonInfos[7].InputIO)){ 431 | if (rAntiDeadzone < 121) 432 | rAntiDeadzone = rAntiDeadzone + 8;} 433 | 434 | sleep_ms(60); 435 | } 436 | 437 | updateFlashData(); 438 | 439 | clearDisplay(); 440 | redraw = 1; 441 | 442 | return (1); 443 | } 444 | 445 | int timerAdjust(menu *self) { 446 | // draw deadzone configuration 447 | 448 | redraw = 0; 449 | 450 | char* cal_string = "Autoreset"; 451 | char tdata[5]; 452 | 453 | while(!gpio_get(ButtonInfos[0].InputIO)); 454 | 455 | while (gpio_get(ButtonInfos[0].InputIO)) { 456 | clearDisplay(); 457 | putString(cal_string, 0, 0, color); 458 | sprintf(tdata, "%03d seconds", autoResetTimer * 2); 459 | putString(tdata, 0, 2, color); 460 | updateDisplay(); 461 | 462 | if (!gpio_get(ButtonInfos[4].InputIO)){ 463 | if (autoResetTimer < 255) 464 | autoResetTimer++;} 465 | else if (!gpio_get(ButtonInfos[5].InputIO)){ 466 | if (autoResetTimer > 0) 467 | autoResetTimer--;} 468 | else if (!gpio_get(ButtonInfos[6].InputIO)){ 469 | if (autoResetTimer > 7) 470 | autoResetTimer = autoResetTimer - 8;} 471 | else if (!gpio_get(ButtonInfos[7].InputIO)){ 472 | if (autoResetTimer < 248) 473 | autoResetTimer = autoResetTimer + 8;} 474 | 475 | sleep_ms(60); 476 | } 477 | 478 | while(!gpio_get(ButtonInfos[0].InputIO)); 479 | 480 | updateFlashData(); 481 | 482 | clearDisplay(); 483 | redraw = 1; 484 | 485 | return (1); 486 | } 487 | 488 | int toggleOption(menu *self) { 489 | 490 | if (!strcmp(self->name, "OLED Flip ")) { 491 | if ((to_ms_since_boot(get_absolute_time()) - flipLockout) > 500) { 492 | 493 | if (self->type == 1) 494 | self->on = !(self->on); 495 | 496 | flipLockout = to_ms_since_boot(get_absolute_time()); 497 | 498 | cancel_repeating_timer(&redrawTimer); 499 | updateFlags(); 500 | updateFlashData(); 501 | 502 | if(oledType) 503 | ssd1331_init(); 504 | else ssd1306_init(); 505 | sleep_ms(100); 506 | 507 | add_repeating_timer_ms(-10, rainbowCycle, NULL, &redrawTimer); 508 | return (1); 509 | } else 510 | return (1); 511 | } else { 512 | if (self->type == 1) 513 | self->on = !(self->on); 514 | } 515 | 516 | return (1); 517 | } 518 | 519 | int exitToPad(menu *self) { 520 | // gather up flags and update them 521 | updateFlags(); 522 | return (0); 523 | } 524 | 525 | int dummy(menu *self) { return (1); } 526 | 527 | static menu mainMenu[6] = { 528 | {"Button Test ", 2, 1, 1, 1, 1, buttontest}, 529 | {"Stick Config ", 0, 1, 0, 1, 1, dummy}, 530 | {"Trigger Config", 0, 1, 0, 1, 1, dummy}, 531 | {"Edit VMU Color", 2, 1, 0, 1, 1, paletteVMU}, // ssd1331 present 532 | {"Settings ", 0, 1, 0, 1, 1, dummy}, 533 | {"Exit ", 2, 0, 0, 1, 1, exitToPad} 534 | }; 535 | 536 | menu *currentMenu = mainMenu; 537 | uint8_t currentNumEntries = sizeof(mainMenu) / sizeof(menu); 538 | uint8_t currentEntry = 0; 539 | uint8_t selectedEntry = 0; 540 | uint8_t firstVisibleEntry = 0; 541 | uint8_t lastVisibleEntry = 4; 542 | uint8_t prevEntryModifier = 0; 543 | uint8_t entryModifier = 0; 544 | 545 | int mainmen(menu *self) { 546 | currentMenu = mainMenu; 547 | currentNumEntries = sizeof(mainMenu) / sizeof(menu); 548 | entryModifier = prevEntryModifier; 549 | return (1); 550 | } 551 | 552 | static menu stickConfig[6] = { 553 | {"Back ", 2, 1, 0, 1, 1, mainmen}, // i.e. setCurrentMenu to mainMenu 554 | {"Calibration ", 2, 1, 1, 1, 1, sCal}, 555 | {"Deadzone Edit ", 2, 1, 0, 1, 1, sDeadzone}, 556 | {"Invert X ", 1, 1, 0, 0, 1, toggleOption}, 557 | {"Invert Y ", 1, 1, 0, 0, 1, toggleOption}, 558 | {"Swap X&Y ", 1, 0, 0, 0, 1, toggleOption} 559 | }; 560 | 561 | int sConfig(menu *self) { 562 | currentMenu = stickConfig; 563 | currentNumEntries = sizeof(stickConfig) / sizeof(menu); 564 | prevEntryModifier = entryModifier; 565 | entryModifier = 0; 566 | return (1); 567 | } 568 | 569 | static menu triggerConfig[6] = { 570 | {"Back ", 2, 1, 0, 1, 1, mainmen}, 571 | {"Calibration ", 2, 1, 1, 1, 1, tCal}, 572 | {"Deadzone Edit ", 2, 1, 0, 1, 1, tDeadzone}, 573 | {"Invert L ", 1, 1, 0, 0, 1, toggleOption}, 574 | {"Invert R ", 1, 1, 0, 0, 1, toggleOption}, 575 | {"Swap L&R ", 1, 0, 0, 0, 1, toggleOption} 576 | }; 577 | 578 | int tConfig(menu *self) { 579 | currentMenu = triggerConfig; 580 | currentNumEntries = sizeof(triggerConfig) / sizeof(menu); 581 | prevEntryModifier = entryModifier; 582 | entryModifier = 0; 583 | return (1); 584 | } 585 | 586 | static menu settings[11] = { 587 | {"Back ", 2, 1, 1, 1, 1, mainmen}, 588 | {"Boot Video ", 3, 1, 0, 1, 1, dummy}, 589 | {"Rumble ", 1, 1, 0, 1, 1, toggleOption}, 590 | {"VMU ", 1, 1, 0, 1, 1, toggleOption}, 591 | {"UI Color ", 2, 1, 0, 1, 1, paletteUI}, // ssd1331 present 592 | {"OLED: ", 3, 0, 0, 1, 1, dummy}, 593 | {"OLED Flip ", 1, 0, 0, 0, 1, toggleOption}, 594 | {"Autoreset ", 1, 0, 0, 0, 1, toggleOption}, 595 | {"Adjust Timeout", 2, 0, 0, 1, 1, timerAdjust}, 596 | 597 | #if HKT7700 598 | {"Dev: HKT-7700", 3, 0, 0, 1, 1, dummy}, 599 | #elif HKT7300 600 | {"Dev: HKT-7300", 3, 0, 0, 1, 1, dummy}, 601 | #endif 602 | 603 | {"FW: 1.5", 3, 0, 0, 1, 1, dummy} 604 | }; 605 | 606 | int setting(menu *self) { 607 | currentMenu = settings; 608 | currentNumEntries = sizeof(settings) / sizeof(menu); 609 | prevEntryModifier = entryModifier; 610 | entryModifier = 0; 611 | return (1); 612 | } 613 | 614 | void loadFlags() { 615 | stickConfig[3].on = invertX; 616 | stickConfig[4].on = invertY; 617 | stickConfig[5].on = swapXY; 618 | triggerConfig[3].on = invertL; 619 | triggerConfig[4].on = invertR; 620 | triggerConfig[5].on = swapLR; 621 | settings[2].on = rumbleEnable; 622 | settings[3].on = vmuEnable; 623 | settings[6].on = oledFlip; 624 | settings[7].on = autoResetEnable; 625 | } 626 | 627 | void updateFlags() { 628 | invertX = stickConfig[3].on; 629 | invertY = stickConfig[4].on; 630 | swapXY = stickConfig[5].on; 631 | invertL = triggerConfig[3].on; 632 | invertR = triggerConfig[4].on; 633 | swapLR = triggerConfig[5].on; 634 | rumbleEnable = settings[2].on; 635 | vmuEnable = settings[3].on; 636 | oledFlip = settings[6].on; 637 | autoResetEnable = settings[7].on; 638 | } 639 | 640 | void getSelectedEntry() { 641 | for (int i = 0; i < currentNumEntries; i++) { 642 | if (currentMenu[i].selected) { 643 | selectedEntry = i; 644 | break; 645 | } 646 | } 647 | } 648 | 649 | void getFirstVisibleEntry() { 650 | for (int i = 0; i < currentNumEntries; i++) { 651 | if (currentMenu[i].visible) { 652 | firstVisibleEntry = i; 653 | break; 654 | } 655 | } 656 | } 657 | 658 | void getLastVisibleEntry() { 659 | for (int i = currentNumEntries - 1; i >= 0; i--) { 660 | if (currentMenu[i].visible) { 661 | lastVisibleEntry = i; 662 | break; 663 | } 664 | } 665 | } 666 | 667 | void redrawMenu() { 668 | clearDisplay(); 669 | 670 | int i = 0; 671 | 672 | for (uint8_t n = 0; n < currentNumEntries; n++) { 673 | if (currentMenu[n].visible) { 674 | putString(currentMenu[n].name, 0, n + entryModifier, color); 675 | if (currentMenu[n].type == 1) // boolean type menu 676 | drawToggle(n + entryModifier, color, currentMenu[n].on); 677 | } 678 | drawCursor(selectedEntry + entryModifier, color); 679 | } 680 | updateDisplay(); 681 | } 682 | 683 | static uint16_t hue = 0; 684 | 685 | bool rainbowCycle(struct repeating_timer *t) { 686 | static uint8_t r = 0x00; 687 | static uint8_t g = 0x00; 688 | static uint8_t b = 0x00; 689 | 690 | fast_hsv2rgb_32bit(hue, 255, 255, &r, &g, &b); 691 | 692 | color = ((r & 0b11111000) << 8) | ((g & 0b11111100) << 3) | (b >> 3); 693 | 694 | if (hue == 1535) 695 | hue = 0; 696 | else 697 | hue++; 698 | 699 | if (redraw) 700 | redrawMenu(); 701 | 702 | return (true); 703 | } 704 | 705 | void runMenu() { 706 | 707 | // Check for menu button combo (Start + Down + B) 708 | 709 | /* Menu 710 | -Stick to 96x64 size even on monochrome OLED... Simpler! 711 | -Need method to handle number of current menu entries. Iterate through different arrays of menu structs to know which entries to draw...? 712 | -menu_item struct can have a "visible" flag that menuRedraw or menuScroll will toggle 713 | -Function call to redraw menu list (menuRedraw()?) 714 | -Draw cursor next to current menu item, move up and down when dpad (or optionally, analog stick) is moved 715 | -Cursor should default to second item on menus with 'Back' option 716 | -Scroll menu when cursor reaches bottom of screen 717 | 718 | -SSD1306 and SSD1331 drawing functions can accelerate menu development: 719 | -Drawing squares with top left and bottom right coordinates and specific color ✓ 720 | -Drawing hollow rectangles with inner and outer top left and bottom right coordinates and specific color ✓ 721 | -Drawing circles (AA?) at certain coordinates ✓ 722 | -Drawing cursor at generic menu item locations ✓ 723 | -Drawing menu items (text) at prescribed locations using specific font ✓ 724 | 725 | Menu Layout: 726 | -Button Test 727 | -Enters button test screen (Press and hold B to exit) 728 | -Sticks Config 729 | -Back 730 | -Calibration ✓ 731 | -Deadzone Adjust 732 | -Invert X ✓ 733 | -Invert Y ✓ 734 | -Swap X and Y ✓ 735 | -Triggers Config 736 | -Back 737 | -Analog/Digital ✓ 738 | -Calibration, greyed out if digital selected ✓ 739 | -Invert L, greyed out if digital selected ✓ 740 | -Invert R, greyed out if digital selected ✓ 741 | -Swap L and R ✓ 742 | -Edit VMU Colors (greyed out if SSD1306 detected) 743 | -Enters VMU Palette screen. Cycle left and right through all 8 VMU pages, and select from 8 preset colors or enter a custom RGB565 value (Press and hold B to exit) 744 | -Settings 745 | -Back 746 | -Splashscreen (on/off), gets greyed out when Boot Video is turned on 747 | -Boot Video (on/off), gets greyed out when Splashscreen is turned on or if SSD1306 detected 748 | -Rumble (on/off) 749 | -UI Color (same interface as VMU Colors, greyed out if SSD1306 detected) 750 | -Control UI with analog stick (on/off) 751 | -OLED Model (shows 'SSD1306' or 'SSD1331' next to text) 752 | -Firmware Version (shows firmware version next to text) 753 | -Exit 754 | 755 | */ 756 | 757 | mainMenu[1].run = sConfig; 758 | mainMenu[2].run = tConfig; 759 | mainMenu[4].run = setting; 760 | 761 | loadFlags(); 762 | 763 | if (oledType) { // SSD1331 764 | strcpy(settings[5].name, "OLED: SSD1331"); 765 | } else { // SSD1306 766 | strcpy(settings[5].name, "OLED: SSD1306"); 767 | 768 | // disable color-only menu entries 769 | //mainMenu[3].enabled = false; 770 | //settings[4].enabled = false; 771 | 772 | } 773 | 774 | // negative interval means the callback func is called every 10ms regardless of how long callback takes to execute 775 | add_repeating_timer_ms(-10, rainbowCycle, NULL, &redrawTimer); 776 | 777 | while (1) { 778 | getSelectedEntry(); // where to draw cursor 779 | // redrawMenu(); // called by redrawTimer 780 | 781 | // Wait for A button release (submenu rate-limit) 782 | while (!gpio_get(ButtonInfos[0].InputIO)); 783 | 784 | uint8_t pressed = 0; 785 | do { 786 | for (int i = 0; i < 9; i++) { 787 | pressed |= (!gpio_get(ButtonInfos[i].InputIO)); 788 | } 789 | } while (!pressed); 790 | 791 | sleep_ms(75); // Wait out switch bounce + rate-limiting 792 | 793 | if (!gpio_get(ButtonInfos[4].InputIO)) { // Up 794 | /* check currently selected entry 795 | if element is not the top one, deselect current entry 796 | and select the first enabled entry above it */ 797 | if (selectedEntry) { // i.e. not 0 798 | currentMenu[selectedEntry].selected = false; 799 | currentMenu[selectedEntry - 1].selected = true; 800 | 801 | getFirstVisibleEntry(); 802 | if ((selectedEntry == firstVisibleEntry) && (firstVisibleEntry)) { 803 | currentMenu[firstVisibleEntry + 4].visible = false; 804 | currentMenu[firstVisibleEntry - 1].visible = true; 805 | entryModifier++; 806 | } 807 | } 808 | 809 | } 810 | 811 | else if (!gpio_get(ButtonInfos[5].InputIO)) { // Down 812 | /* check currently selected entry 813 | if entry is not the bottom one, deselect current entry 814 | and select first enabled entry below it */ 815 | if (selectedEntry < currentNumEntries - 1) { 816 | currentMenu[selectedEntry].selected = false; 817 | currentMenu[selectedEntry + 1].selected = true; 818 | 819 | getLastVisibleEntry(); 820 | if ((selectedEntry == lastVisibleEntry) && (lastVisibleEntry < currentNumEntries)) { 821 | currentMenu[lastVisibleEntry - 4].visible = false; 822 | currentMenu[lastVisibleEntry + 1].visible = true; 823 | entryModifier--; 824 | } 825 | } 826 | } 827 | 828 | else if (!gpio_get(ButtonInfos[0].InputIO)) { // A 829 | /* check currently selected entry 830 | if entry is enabled, run entry's function 831 | entry functions should set currentMenu if they enter a submenu. */ 832 | if (currentMenu[selectedEntry].enabled) 833 | if (!currentMenu[selectedEntry].run(¤tMenu[selectedEntry])) 834 | break; 835 | } 836 | /* Entrys' functions should all return 1 except for mainMenu.exitToPad, 837 | which should return 0 and result in a break from this while loop. */ 838 | } 839 | cancel_repeating_timer(&redrawTimer); 840 | } 841 | -------------------------------------------------------------------------------- /src/menu.h: -------------------------------------------------------------------------------- 1 | /* 2 | Menu 3 | */ 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "sh8601.h" 14 | #include "ssd1331.h" 15 | #include "ssd1306.h" 16 | 17 | #include "pico/stdlib.h" 18 | 19 | #define xCenter flashData[0] 20 | #define xMin flashData[1] 21 | #define xMax flashData[2] 22 | #define yCenter flashData[3] 23 | #define yMin flashData[4] 24 | #define yMax flashData[5] 25 | #define lMin flashData[6] 26 | #define lMax flashData[7] 27 | #define rMin flashData[8] 28 | #define rMax flashData[9] 29 | #define invertX flashData[10] 30 | #define invertY flashData[11] 31 | #define invertL flashData[12] 32 | #define invertR flashData[13] 33 | #define firstBoot flashData[14] 34 | #define currentPage flashData[15] 35 | #define rumbleEnable flashData[16] 36 | #define vmuEnable flashData[17] 37 | #define oledFlip flashData[18] 38 | #define swapXY flashData[19] 39 | #define swapLR flashData[20] 40 | #define oledType flashData[21] 41 | #define triggerMode flashData[22] // 1 = analog, 0 = digital 42 | #define xDeadzone flashData[23] 43 | #define xAntiDeadzone flashData[24] 44 | #define yDeadzone flashData[25] 45 | #define yAntiDeadzone flashData[26] 46 | #define lDeadzone flashData[27] 47 | #define lAntiDeadzone flashData[28] 48 | #define rDeadzone flashData[29] 49 | #define rAntiDeadzone flashData[30] 50 | #define autoResetEnable flashData[31] 51 | #define autoResetTimer flashData[32] // units are 2s, max value 8.5 minutes 52 | #define version flashData[33] 53 | 54 | extern ButtonInfo ButtonInfos[]; 55 | 56 | typedef struct menu_s menu; 57 | 58 | struct menu_s { 59 | char name[14]; 60 | int type; // 0: submenu, 1: boolean toggle, 2: function, 3: inert 61 | bool visible; 62 | bool selected; 63 | bool on; 64 | bool enabled; // control for hidden menu items (ssd1306) 65 | int (*run)(menu *self); 66 | }; 67 | 68 | int paletteVMU(menu *); 69 | 70 | int paletteUI(menu *); 71 | 72 | int buttontest(menu *); 73 | 74 | int stickcal(menu *); 75 | 76 | int trigcal(menu *); 77 | 78 | int deadzone(menu *); 79 | 80 | int toggleOption(menu *); 81 | 82 | int exitToPad(menu *); 83 | 84 | int dummy(menu *); 85 | 86 | int mainmen(menu *); 87 | 88 | int sconfig(menu *); 89 | 90 | int tconfig(menu *); 91 | 92 | int setting(menu *); 93 | 94 | void getSelectedElement(void); 95 | 96 | void loadFlags(void); 97 | 98 | void updateFlags(void); 99 | 100 | void redrawMenu(void); 101 | 102 | bool rainbowCycle(struct repeating_timer *); 103 | 104 | void runMenu(void); -------------------------------------------------------------------------------- /src/sh8601.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "pico/stdlib.h" 8 | #include "pico/binary_info.h" 9 | #include "hardware/spi.h" 10 | #include "hardware/dma.h" 11 | 12 | #define SH8601_SPI spi0 13 | #define SH8601_SPEED 20000000 // 62.5MHz 14 | #define SH8601_DC 0 15 | #define SH8601_CS 1 16 | #define SH8601_SCK 2 17 | #define SH8601_MOSI 3 18 | #define SH8601_RST 5 19 | #define SH8601_PWR_EN 6 20 | 21 | #define SH8601_OLED_W 368 22 | #define SH8601_OLED_H 448 23 | 24 | #define OLED_FLIP flashData[18] 25 | 26 | // SH8601 Commands 27 | #define SH8601_CMD_NOP 0x00 28 | #define SH8601_CMD_SWRESET 0x01 29 | #define SH8601_READ_ID 0x04 30 | #define SH8601_READ_DSI_ERR 0x05 31 | #define SH8601_READ_PWRMODE 0x0A 32 | #define SH8601_READ_MADCTL 0x0B 33 | #define SH8601_READ_PXLMODE 0x0C 34 | #define SH8601_READ_IMGMODE 0x0D 35 | #define SH8601_READ_SGNLMODE 0x0E 36 | #define SH8601_READ_SELFDIAG 0x0F 37 | #define SH8601_SLEEPIN 0x10 38 | #define SH8601_SLEEPOUT 0x11 39 | #define SH8601_PARTIAL_DISP_MODE_ON 0x12 40 | #define SH8601_NORMAL_DISP_MODE_ON 0x13 41 | #define SH8601_INVERT_OFF 0x20 42 | #define SH8601_INVERT_ON 0x21 43 | #define SH8601_ALL_PXL_OFF 0x22 44 | #define SH8601_ALL_PXL_ON 0x23 45 | #define SH8601_DISP_OFF 0x28 46 | #define SH8601_DISP_ON 0x29 47 | #define SH8601_COLSET 0x2A 48 | #define SH8601_PGADDRSET 0x2B 49 | #define SH8601_MEMWRITE 0x2C 50 | #define SH8601_PARTIAL_ROWSET 0x30 51 | #define SH8601_PARTIAL_COLSET 0x31 52 | #define SH8601_TE_OFF 0x34 53 | #define SH8601_TE_ON 0x35 54 | #define SH8601_MADCTL 0x36 55 | #define SH8601_IDLE_OFF 0x38 56 | #define SH8601_IDLE_ON 0x39 57 | #define SH8601_WRITE_PXL_FMT 0x3A 58 | #define SH8601_MEMWRITE_CONT 0x3C 59 | #define SH8601_WRITE_TE 0x44 60 | #define SH8601_READ_SCANLINE_NO 0x45 61 | #define SH8601_SPI_RD_OFF 0x46 62 | #define SH8601_SPI_RD_ON 0x47 63 | #define SH8601_AOD_OFF 0x48 64 | #define SH8601_AOD_ON 0x49 65 | #define SH8601_WRITE_AODBRT 0x4A 66 | #define SH8601_READ_AODBRT 0x4B 67 | #define SH8601_DEEP_STDBY 0x4F 68 | #define SH8601_WRITE_BRT 0x51 69 | #define SH8601_READ_BRT 0x52 70 | #define SH8601_WRITE_CTRL1 0x53 71 | #define SH8601_READ_CTRL1 0x54 72 | #define SH8601_WRITE_CTRL2 0x55 73 | #define SH8601_READ_CTRL2 0x56 74 | #define SH8601_WRITE_CE 0x58 75 | #define SH8601_READ_CE 0x59 76 | #define SH8601_WRITE_HBMBRT 0x63 77 | #define SH8601_READ_HBMBRT 0x64 78 | #define SH8601_WRITE_HBMCTRL 0x66 79 | #define SH8601_READ_DDB_ST 0xA1 80 | #define SH8601_READ_DDB_CT 0xA8 81 | #define SH8601_READ_CRC_ST 0xAA 82 | #define SH8601_READ_CRC_CT 0xAF 83 | #define SH8601_SPI_MODE 0xC4 84 | #define SH8601_READ_ID1 0xDA 85 | #define SH8601_READ_ID2 0xDB 86 | #define SH8601_READ_ID3 0xDC 87 | 88 | void sh8601WriteCommand(const uint8_t data); 89 | 90 | void sh8601WriteData(const uint8_t data); 91 | 92 | void sh8601SetPixel(const uint8_t x, const uint8_t y, const uint16_t color); 93 | 94 | void sh8601_clear(void); 95 | 96 | void sh8601_update(void); 97 | 98 | void sh8601_splash(void); 99 | 100 | void sh8601_init(); -------------------------------------------------------------------------------- /src/ssd1306.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "pico/stdlib.h" 6 | #include "hardware/i2c.h" 7 | 8 | // SSD1306 defines 9 | #define SSD1306_ADDRESS 0x3C 10 | #define SSD1306_I2C i2c1 11 | #define I2C_SDA 2 12 | #define I2C_SCL 3 13 | 14 | // value in KHz 15 | #define I2C_CLOCK 3000 16 | 17 | #define SSD1306_LCDWIDTH 128 18 | #define SSD1306_LCDHEIGHT 64 19 | #define SSD1306_FRAMEBUFFER_SIZE (SSD1306_LCDWIDTH * SSD1306_LCDHEIGHT / 8) 20 | 21 | #define SSD1306_SETLOWCOLUMN 0x00 22 | #define SSD1306_SETHIGHCOLUMN 0x10 23 | 24 | #define SSD1306_MEMORYMODE 0x20 25 | #define SSD1306_COLUMNADDR 0x21 26 | #define SSD1306_PAGEADDR 0x22 27 | #define SSD1306_DEACTIVATE_SCROLL 0x2E 28 | #define SSD1306_ACTIVATE_SCROLL 0x2F 29 | 30 | #define SSD1306_SETSTARTLINE 0x40 31 | 32 | #define SSD1306_SETCONTRAST 0x81 33 | #define SSD1306_CHARGEPUMP 0x8D 34 | 35 | #define SSD1306_SEGREMAP0 0xA0 36 | #define SSD1306_SEGREMAP127 0xA1 37 | #define SSD1306_DISPLAYALLON_RESUME 0xA4 38 | #define SSD1306_DISPLAYALLON 0xA5 39 | #define SSD1306_NORMALDISPLAY 0xA6 40 | #define SSD1306_INVERTDISPLAY 0xA7 41 | #define SSD1306_SETMULTIPLEX 0xA8 42 | #define SSD1306_DISPLAYOFF 0xAE 43 | #define SSD1306_DISPLAYON 0xAF 44 | 45 | #define SSD1306_COMSCANINC 0xC0 46 | #define SSD1306_COMSCANDEC 0xC8 47 | 48 | #define SSD1306_SETDISPLAYOFFSET 0xD3 49 | #define SSD1306_SETDISPLAYCLOCKDIV 0xD5 50 | #define SSD1306_SETPRECHARGE 0xD9 51 | #define SSD1306_SETCOMPINS 0xDA 52 | #define SSD1306_SETVCOMDETECT 0xDB 53 | 54 | void ssd1306SendCommand(uint8_t cmd); 55 | 56 | void ssd1306SendCommandBuffer(uint8_t *inbuf, int len); 57 | 58 | void ssd1306_init(); 59 | 60 | void updateSSD1306(); 61 | 62 | void clearSSD1306(); 63 | 64 | void splashSSD1306(); 65 | 66 | void setPixelSSD1306(int x, int y, bool on); -------------------------------------------------------------------------------- /src/ssd1331.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "pico/stdlib.h" 8 | #include "pico/binary_info.h" 9 | #include "hardware/spi.h" 10 | #include "hardware/dma.h" 11 | 12 | #define SSD1331_SPI spi0 13 | #define SSD1331_SPEED 50000000 // 62.5MHz 14 | #define SCK 2 15 | #define MOSI 3 16 | #define DC 14 17 | #define RST 13 18 | 19 | #define OLED_W 96 20 | #define OLED_H 64 21 | 22 | #define OLED_FLIP flashData[18] 23 | 24 | // SSD1331 Commands 25 | #define SSD1331_CMD_DRAWLINE 0x21 //!< Draw line 26 | #define SSD1331_CMD_DRAWRECT 0x22 //!< Draw rectangle 27 | #define SSD1331_CMD_FILL 0x26 //!< Fill enable/disable 28 | #define SSD1331_CMD_SETCOLUMN 0x15 //!< Set column address 29 | #define SSD1331_CMD_SETROW 0x75 //!< Set row adress 30 | #define SSD1331_CMD_CONTRASTA 0x81 //!< Set contrast for color A 31 | #define SSD1331_CMD_CONTRASTB 0x82 //!< Set contrast for color B 32 | #define SSD1331_CMD_CONTRASTC 0x83 //!< Set contrast for color C 33 | #define SSD1331_CMD_MASTERCURRENT 0x87 //!< Master current control 34 | #define SSD1331_CMD_SETREMAP 0xA0 //!< Set re-map & data format 35 | #define SSD1331_CMD_STARTLINE 0xA1 //!< Set display start line 36 | #define SSD1331_CMD_DISPLAYOFFSET 0xA2 //!< Set display offset 37 | #define SSD1331_CMD_NORMALDISPLAY 0xA4 //!< Set display to normal mode 38 | #define SSD1331_CMD_DISPLAYALLON 0xA5 //!< Set entire display ON 39 | #define SSD1331_CMD_DISPLAYALLOFF 0xA6 //!< Set entire display OFF 40 | #define SSD1331_CMD_INVERTDISPLAY 0xA7 //!< Invert display 41 | #define SSD1331_CMD_SETMULTIPLEX 0xA8 //!< Set multiplex ratio 42 | #define SSD1331_CMD_SETMASTER 0xAD //!< Set master configuration 43 | #define SSD1331_CMD_DISPLAYOFF 0xAE //!< Display OFF (sleep mode) 44 | #define SSD1331_CMD_DISPLAYON 0xAF //!< Normal Brightness Display ON 45 | #define SSD1331_CMD_POWERMODE 0xB0 //!< Power save mode 46 | #define SSD1331_CMD_PRECHARGE 0xB1 //!< Phase 1 and 2 period adjustment 47 | #define SSD1331_CMD_CLOCKDIV 0xB3 //!< Set display clock divide ratio/oscillator frequency 48 | #define SSD1331_CMD_PRECHARGEA 0x8A //!< Set second pre-charge speed for color A 49 | #define SSD1331_CMD_PRECHARGEB 0x8B //!< Set second pre-charge speed for color B 50 | #define SSD1331_CMD_PRECHARGEC 0x8C //!< Set second pre-charge speed for color C 51 | #define SSD1331_CMD_PRECHARGELEVEL 0xBB //!< Set pre-charge voltage 52 | #define SSD1331_CMD_VCOMH 0xBE //!< Set Vcomh voltge 53 | 54 | float cos_32s(float x); 55 | float cos32(float x); 56 | float sin32(float x); 57 | double atan66(double x); 58 | double atan_66s(double x); 59 | 60 | void fast_hsv2rgb_32bit(uint16_t, uint8_t, uint8_t, uint8_t *, uint8_t *, uint8_t *); 61 | 62 | void ssd1331WriteCommand(const uint8_t data); 63 | 64 | void ssd1331WriteCommands(const uint8_t *data, uint num); 65 | 66 | void ssd1331WriteData(const uint8_t *data, uint numbytes); 67 | 68 | void setPixelSSD1331(const uint8_t x, const uint8_t y, const uint16_t color); 69 | 70 | void clearSSD1331(void); 71 | 72 | void updateSSD1331(void); 73 | 74 | void splashSSD1331(void); 75 | 76 | void ssd1331_init(); -------------------------------------------------------------------------------- /src/st7789.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "pico/stdlib.h" 8 | #include "pico/binary_info.h" 9 | #include "hardware/spi.h" 10 | #include "hardware/dma.h" 11 | 12 | #define ST7789_SPI spi0 13 | #define ST7789_SPEED 60000000 // 40MHz 14 | #define ST7789_DC 5 15 | #define ST7789_CS 1 16 | #define ST7789_SCK 2 17 | #define ST7789_MOSI 3 18 | #define ST7789_RST 6 19 | #define ST7789_BL_EN 7 20 | 21 | #define ST7789_CMD_NOP 0x00 /**< no operation command */ 22 | #define ST7789_CMD_SWRESET 0x01 /**< software reset command */ 23 | #define ST7789_CMD_SLPIN 0x10 /**< sleep in command */ 24 | #define ST7789_CMD_SLPOUT 0x11 /**< sleep out command */ 25 | #define ST7789_CMD_PTLON 0x12 /**< partial mode on command */ 26 | #define ST7789_CMD_NORON 0x13 /**< normal display mode on command */ 27 | #define ST7789_CMD_INVOFF 0x20 /**< display inversion off command */ 28 | #define ST7789_CMD_INVON 0x21 /**< display inversion on command */ 29 | #define ST7789_CMD_GAMSET 0x26 /**< display inversion set command */ 30 | #define ST7789_CMD_DISPOFF 0x28 /**< display off command */ 31 | #define ST7789_CMD_DISPON 0x29 /**< display on command */ 32 | #define ST7789_CMD_CASET 0x2A /**< column address set command */ 33 | #define ST7789_CMD_RASET 0x2B /**< row address set command */ 34 | #define ST7789_CMD_RAMWR 0x2C /**< memory write command */ 35 | #define ST7789_CMD_PTLAR 0x30 /**< partial start/end address set command */ 36 | #define ST7789_CMD_VSCRDEF 0x33 /**< vertical scrolling definition command */ 37 | #define ST7789_CMD_TEOFF 0x34 /**< tearing effect line off command */ 38 | #define ST7789_CMD_TEON 0x35 /**< tearing effect line on command */ 39 | #define ST7789_CMD_MADCTL 0x36 /**< memory data access control command */ 40 | #define ST7789_CMD_VSCRSADD 0x37 /**< vertical scrolling start address command */ 41 | #define ST7789_CMD_IDMOFF 0x38 /**< idle mode off command */ 42 | #define ST7789_CMD_IDMON 0x39 /**< idle mode on command */ 43 | #define ST7789_CMD_COLMOD 0x3A /**< interface pixel format command */ 44 | #define ST7789_CMD_RAMWRC 0x3C /**< memory write continue command */ 45 | #define ST7789_CMD_TESCAN 0x44 /**< set tear scanline command */ 46 | #define ST7789_CMD_WRDISBV 0x51 /**< write display brightness command */ 47 | #define ST7789_CMD_WRCTRLD 0x53 /**< write CTRL display command */ 48 | #define ST7789_CMD_WRCACE 0x55 /**< write content adaptive brightness control and color enhancement command */ 49 | #define ST7789_CMD_WRCABCMB 0x5E /**< write CABC minimum brightness command */ 50 | #define ST7789_CMD_RAMCTRL 0xB0 /**< ram control command */ 51 | #define ST7789_CMD_RGBCTRL 0xB1 /**< rgb control command */ 52 | #define ST7789_CMD_PORCTRL 0xB2 /**< porch control command */ 53 | #define ST7789_CMD_FRCTRL1 0xB3 /**< frame rate control 1 command */ 54 | #define ST7789_CMD_PARCTRL 0xB5 /**< partial mode control command */ 55 | #define ST7789_CMD_GCTRL 0xB7 /**< gate control command */ 56 | #define ST7789_CMD_GTADJ 0xB8 /**< gate on timing adjustment command */ 57 | #define ST7789_CMD_DGMEN 0xBA /**< digital gamma enable command */ 58 | #define ST7789_CMD_VCOMS 0xBB /**< vcoms setting command */ 59 | #define ST7789_CMD_LCMCTRL 0xC0 /**< lcm control command */ 60 | #define ST7789_CMD_IDSET 0xC1 /**< id setting command */ 61 | #define ST7789_CMD_VDVVRHEN 0xC2 /**< vdv and vrh command enable command */ 62 | #define ST7789_CMD_VRHS 0xC3 /**< vrh set command */ 63 | #define ST7789_CMD_VDVSET 0xC4 /**< vdv setting command */ 64 | #define ST7789_CMD_VCMOFSET 0xC5 /**< vcoms offset set command */ 65 | #define ST7789_CMD_FRCTR2 0xC6 /**< fr control 2 command */ 66 | #define ST7789_CMD_CABCCTRL 0xC7 /**< cabc control command */ 67 | #define ST7789_CMD_REGSEL1 0xC8 /**< register value selection1 command */ 68 | #define ST7789_CMD_REGSEL2 0xCA /**< register value selection2 command */ 69 | #define ST7789_CMD_PWMFRSEL 0xCC /**< pwm frequency selection command */ 70 | #define ST7789_CMD_PWCTRL1 0xD0 /**< power control 1 command */ 71 | #define ST7789_CMD_VAPVANEN 0xD2 /**< enable vap/van signal output command */ 72 | #define ST7789_CMD_CMD2EN 0xDF /**< command 2 enable command */ 73 | #define ST7789_CMD_PVGAMCTRL 0xE0 /**< positive voltage gamma control command */ 74 | #define ST7789_CMD_NVGAMCTRL 0xE1 /**< negative voltage gamma control command */ 75 | #define ST7789_CMD_DGMLUTR 0xE2 /**< digital gamma look-up table for red command */ 76 | #define ST7789_CMD_DGMLUTB 0xE3 /**< digital gamma look-up table for blue command */ 77 | #define ST7789_CMD_GATECTRL 0xE4 /**< gate control command */ 78 | #define ST7789_CMD_SPI2EN 0xE7 /**< spi2 command */ 79 | #define ST7789_CMD_PWCTRL2 0xE8 /**< power control 2 command */ 80 | #define ST7789_CMD_EQCTRL 0xE9 /**< equalize time control command */ 81 | #define ST7789_CMD_PROMCTRL 0xEC /**< program control command */ 82 | #define ST7789_CMD_PROMEN 0xFA /**< program mode enable command */ 83 | #define ST7789_CMD_NVMSET 0xFC /**< nvm setting command */ 84 | #define ST7789_CMD_PROMACT 0xFE /**< program action command */ 85 | 86 | void st7789WriteCommand(const uint8_t data); 87 | 88 | void st7789WriteData(const uint8_t data); 89 | 90 | void st7789SetPixel(const uint8_t x, const uint8_t y, const uint16_t color); 91 | 92 | void st7789_clear(void); 93 | 94 | void st7789_update(void); 95 | 96 | void st7789_splash(void); 97 | 98 | void st7789_init(); -------------------------------------------------------------------------------- /src/state_machine.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "pico/stdlib.h" 3 | #include "state_machine.h" 4 | 5 | // Simple state machine 6 | // This part of the code encodes the basic state machine states for recieving Maple packets 7 | // We will later use this to precalculate the lookup table for dealing with multiple transitions at once 8 | // The tables we create here could be thrown away once the combined state machine table is built 9 | 10 | enum { 11 | STATUS_NONE = -1, 12 | STATUS_START, 13 | STATUS_END, 14 | STATUS_PUSHBIT0, 15 | STATUS_PUSHBIT1, 16 | STATUS_PUSHBIT2, 17 | STATUS_PUSHBIT3, 18 | STATUS_PUSHBIT4, 19 | STATUS_PUSHBIT5, 20 | STATUS_PUSHBIT6, 21 | STATUS_PUSHBIT7, 22 | STATUS_BITSET = 0x80, 23 | }; 24 | 25 | typedef struct SimpleState_s { 26 | int Next[4]; 27 | int Status; 28 | } SimpleState; 29 | 30 | static SimpleState States[NUM_STATES]; 31 | static int NumStates = 0; 32 | 33 | static int NewState(int Expected) { 34 | int New = NumStates++; 35 | SimpleState *s = &States[New]; 36 | memset(s, 0xFF, sizeof(*s)); 37 | s->Next[Expected] = New; 38 | return New; 39 | } 40 | 41 | static int ExpectState(int ParentState, int Expected) { 42 | int New = NewState(Expected); 43 | States[ParentState].Next[Expected] = New; 44 | return New; 45 | } 46 | 47 | static int ExpectStateWithStatus(int ParentState, int Expected, uint Status) { 48 | int New = NewState(Expected); 49 | States[New].Status = Status; 50 | States[ParentState].Next[Expected] = New; 51 | return New; 52 | } 53 | 54 | static int ExpectStateTwoParents(int ParentState, int OtherParentState, int Expected) { 55 | int New = NewState(Expected); 56 | States[ParentState].Next[Expected] = New; 57 | States[OtherParentState].Next[Expected] = New; 58 | return New; 59 | } 60 | 61 | static void BuildBasicStates() { 62 | // The transitions we expect to happen for a valid stream 63 | // 0b10 is Maple bus pin 5 high 64 | // 0b01 is Maple bus pin 1 high 65 | // Using info from http://mc.pp.se/dc/maplewire.html 66 | 67 | // Start (11 states) 68 | int Prev = NewState(0b11); 69 | Prev = ExpectState(Prev, 0b10); 70 | Prev = ExpectState(Prev, 0b00); 71 | Prev = ExpectState(Prev, 0b10); 72 | Prev = ExpectState(Prev, 0b00); 73 | Prev = ExpectState(Prev, 0b10); 74 | Prev = ExpectState(Prev, 0b00); 75 | Prev = ExpectState(Prev, 0b10); 76 | Prev = ExpectState(Prev, 0b00); 77 | Prev = ExpectState(Prev, 0b10); 78 | Prev = ExpectStateWithStatus(Prev, 0b11, STATUS_START); 79 | 80 | // Byte (6*4 = 24 states) 81 | // We encode each bit seperately so we don't need to do any shifting when recieving 82 | int PossibleEnd; 83 | int Option = Prev; 84 | int StartByte = NumStates; 85 | for (int i = 0; i < 4; i++) { 86 | Prev = ExpectStateTwoParents(Option, Prev, 0b01); 87 | Option = ExpectStateWithStatus(Prev, 0b11, (STATUS_PUSHBIT0 + i * 2) | STATUS_BITSET); 88 | Prev = ExpectStateWithStatus(Prev, 0b00, (STATUS_PUSHBIT0 + i * 2)); 89 | if (i == 0) { 90 | PossibleEnd = Option; 91 | } 92 | 93 | Prev = ExpectStateTwoParents(Option, Prev, 0b10); 94 | Option = ExpectStateWithStatus(Prev, 0b11, (STATUS_PUSHBIT1 + i * 2) | STATUS_BITSET); 95 | Prev = ExpectStateWithStatus(Prev, 0b00, (STATUS_PUSHBIT1 + i * 2)); 96 | 97 | if (i == 3) { 98 | // Loop back around 99 | States[Option].Next[0b01] = StartByte; 100 | States[Prev].Next[0b01] = StartByte; 101 | } 102 | } 103 | 104 | // End (5 states) 105 | Prev = ExpectState(PossibleEnd, 0b01); 106 | Prev = ExpectState(Prev, 0b00); 107 | // Signal end now. We need to be at least 4 transitions back from real end as PIO only pushes byte (4 transitions) at a time 108 | // If we were closer to the end then we could be sitting in idle waiting for a transitions and we wouldn't be replying 109 | // However if end was very long (for some reason) could mean we reply while end is still happening 110 | Prev = ExpectStateWithStatus(Prev, 0b01, STATUS_END); 111 | Prev = ExpectState(Prev, 0b00); 112 | Prev = ExpectState(Prev, 0b01); 113 | States[Prev].Next[0b11] = 0; 114 | assert(NumStates == NUM_STATES); 115 | } 116 | 117 | // Combined state machine 118 | // Produces the table we will use for recieving 119 | // Uses the simple state machine to precalculate a response for every possible byte we could get from Maple RX PIO 120 | 121 | StateMachine Machine[NUM_STATES][256]; // 20Kb 122 | uint8_t SetBits[NUM_SETBITS][2]; // 128 bytes 123 | static int SetBitsEntries = 0; 124 | 125 | static int FindOrAddSetBits(uint8_t CurrentByte, uint8_t NextByte) { 126 | for (int i = 0; i < SetBitsEntries; i++) { 127 | if (SetBits[i][0] == CurrentByte && SetBits[i][1] == NextByte) { 128 | return i; 129 | } 130 | } 131 | int NewEntry = SetBitsEntries++; 132 | assert(NewEntry < NUM_SETBITS); 133 | SetBits[NewEntry][0] = CurrentByte; 134 | SetBits[NewEntry][1] = NextByte; 135 | return NewEntry; 136 | } 137 | 138 | void BuildStateMachineTables() { 139 | BuildBasicStates(); 140 | 141 | // For any byte we can recieve (from Maple RX PIO) in any starting state pre-calculate a response 142 | for (int StartingState = 0; StartingState < NUM_STATES; StartingState++) { 143 | for (int ByteFromMapleRXPIO = 0; ByteFromMapleRXPIO < 256; ByteFromMapleRXPIO++) { 144 | StateMachine M = {0}; 145 | int State = StartingState; 146 | int Transitions = ByteFromMapleRXPIO; 147 | int LastState = State; 148 | uint8_t DataBytes[2] = {0, 0}; 149 | uint CurrentDataByte = 0; 150 | for (int i = 0; i < 4; i++) { 151 | State = States[State].Next[(Transitions >> 6) & 3]; 152 | if (State < 0) { 153 | M.Error = 1; 154 | State = 0; 155 | } 156 | // Ideally we should always have a transition as that's what Maple RX PIO is doing but they seem to happen 157 | if (State != LastState) { 158 | uint Status = States[State].Status; 159 | if (Status & STATUS_BITSET) { 160 | // Data recieved most significant bit first 161 | DataBytes[CurrentDataByte] |= (1 << (7 - ((Status & ~STATUS_BITSET) - STATUS_PUSHBIT0))); 162 | } 163 | switch (States[State].Status & ~STATUS_BITSET) { 164 | case STATUS_START: 165 | M.Reset = 1; 166 | break; 167 | case STATUS_END: 168 | M.End = 1; 169 | break; 170 | case STATUS_PUSHBIT7: // Last bit of current byte 171 | M.Push = 1; 172 | CurrentDataByte = 1; 173 | break; 174 | } 175 | LastState = State; 176 | } 177 | Transitions <<= 2; 178 | } 179 | M.NewState = State; 180 | M.SetBitsIndex = FindOrAddSetBits(DataBytes[0], DataBytes[1]); 181 | Machine[StartingState][ByteFromMapleRXPIO] = M; 182 | } 183 | } 184 | } -------------------------------------------------------------------------------- /src/state_machine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define NUM_STATES 40 4 | #define NUM_SETBITS 64 5 | 6 | typedef struct StateMachine_s { 7 | uint16_t NewState : 6; 8 | uint16_t Push : 1; 9 | uint16_t Error : 1; 10 | uint16_t Reset : 1; 11 | uint16_t End : 1; 12 | uint16_t SetBitsIndex : 6; 13 | } StateMachine; 14 | 15 | // The state machine table 16 | // Pre-calculated responses for any byte we can recieve from Maple RX PIO 17 | extern StateMachine Machine[NUM_STATES][256]; // 20Kb 18 | 19 | // Bits to set indexed from StateMachine::SetBitsIndex 20 | extern uint8_t SetBits[NUM_SETBITS][2]; // 128 bytes 21 | 22 | // Function which builds above tables 23 | void BuildStateMachineTables(void); 24 | --------------------------------------------------------------------------------