├── .github └── workflows │ └── nopr.yaml ├── .gitignore ├── .gitmodules ├── README.md ├── bits ├── bootlogos │ ├── miniui │ │ ├── image1.jpg │ │ └── image1.txt │ └── pak │ │ ├── image1.jpg │ │ ├── image1.txt │ │ ├── image2.jpg │ │ ├── image3.jpg │ │ └── launch.sh └── commits.sh ├── commits.txt ├── extras ├── Bios │ ├── GG │ │ └── .keep │ ├── MGBA │ │ └── .keep │ ├── PCE │ │ └── .keep │ ├── PKM │ │ └── .keep │ ├── SGB │ │ └── .keep │ └── SMS │ │ └── .keep ├── Emus │ ├── GG.pak │ │ └── launch.sh │ ├── MGBA.pak │ │ └── launch.sh │ ├── P8.pak │ │ └── launch.sh │ ├── PCE.pak │ │ └── launch.sh │ ├── PKM.pak │ │ └── launch.sh │ ├── SGB.pak │ │ └── launch.sh │ ├── SH.pak │ │ └── launch.sh │ ├── SMS.pak │ │ └── launch.sh │ └── SUPA.pak │ │ └── launch.sh ├── README.txt ├── Roms │ ├── Game Boy Advance (MGBA) │ │ └── .keep │ ├── Native Games (SH) │ │ ├── Cave Story │ │ │ ├── Cave Story.m3u │ │ │ ├── launch.sh │ │ │ └── readme.txt │ │ └── VVVVVV │ │ │ ├── VVVVVV.m3u │ │ │ ├── launch.sh │ │ │ └── readme.txt │ ├── Pokémon mini (PKM) │ │ └── .keep │ ├── Sega Game Gear (GG) │ │ └── .keep │ ├── Sega Master System (SMS) │ │ └── .keep │ ├── Super Game Boy (SGB) │ │ └── .keep │ └── TurboGrafx-16 (PCE) │ │ └── .keep ├── Saves │ ├── GG │ │ └── .keep │ ├── MGBA │ │ └── .keep │ ├── PCE │ │ └── .keep │ ├── PKM │ │ └── .keep │ ├── SGB │ │ └── .keep │ ├── SMS │ │ └── .keep │ └── SUPA │ │ └── .keep └── Tools │ ├── Clock.pak │ └── launch.sh │ ├── Enable Simple Mode.pak │ ├── README.txt │ └── launch.sh │ ├── Example.pak │ ├── fam.png │ └── launch.sh │ ├── Files.pak │ └── launch.sh │ ├── Random Game.pak │ └── launch.sh │ └── Screenshots.pak │ └── launch.sh ├── github ├── main.png └── menu.png ├── makefile ├── nopes.txt ├── patches ├── SDL-1.2 │ └── 0001-vol-keys.patch └── picoarch │ └── 0001-pokemini-make.patch ├── skeleton ├── .system │ ├── bin │ │ ├── needs-swap │ │ ├── shutdown │ │ └── warn │ ├── cores │ │ └── .keep │ ├── lib │ │ └── .keep │ ├── paks │ │ ├── Emus │ │ │ ├── FC.pak │ │ │ │ └── launch.sh │ │ │ ├── GB.pak │ │ │ │ └── launch.sh │ │ │ ├── GBA.pak │ │ │ │ └── launch.sh │ │ │ ├── GBC.pak │ │ │ │ └── launch.sh │ │ │ ├── MD.pak │ │ │ │ └── launch.sh │ │ │ ├── PS.pak │ │ │ │ └── launch.sh │ │ │ └── SFC.pak │ │ │ │ └── launch.sh │ │ └── MiniUI.pak │ │ │ └── launch.sh │ └── res │ │ ├── BPreplayBold-unhinted.otf │ │ ├── arrow-highlighted.png │ │ ├── arrow.png │ │ ├── bad-battery-fill.png │ │ ├── bad-battery-line.png │ │ ├── battery-charging.png │ │ ├── battery-fill.png │ │ ├── battery-line.png │ │ ├── battery-sdl.png │ │ ├── bg-black.png │ │ ├── bg-white.png │ │ ├── btn.png │ │ ├── charging-union.png │ │ ├── charging.png │ │ ├── confirm.png │ │ ├── digits.png │ │ ├── logo-union.png │ │ ├── logo.png │ │ ├── okay.png │ │ ├── progress-bar-empty.png │ │ ├── progress-bar-full.png │ │ ├── rule.png │ │ ├── settings-bar-empty.png │ │ ├── settings-bar-full.png │ │ ├── settings-brightness.png │ │ ├── settings-mute.png │ │ ├── settings-volume.png │ │ ├── slot-dot-selected.png │ │ ├── slot-dots.png │ │ └── slot-overlay.png ├── .tmp_update │ └── updater ├── Bios │ ├── .keep │ ├── FC │ │ └── .keep │ ├── GB │ │ └── .keep │ ├── GBA │ │ └── .keep │ ├── GBC │ │ └── .keep │ ├── MD │ │ └── .keep │ ├── PS │ │ └── .keep │ └── SFC │ │ └── .keep ├── README.txt ├── Roms │ ├── Game Boy (GB) │ │ └── .keep │ ├── Game Boy Advance (GBA) │ │ └── .keep │ ├── Game Boy Color (GBC) │ │ └── .keep │ ├── Nintendo Entertainment System (FC) │ │ └── .keep │ ├── Sega Genesis (MD) │ │ └── .keep │ ├── Sony PlayStation (PS) │ │ └── .keep │ └── Super Nintendo Entertainment System (SFC) │ │ └── .keep ├── Saves │ ├── .keep │ ├── FC │ │ └── .keep │ ├── GB │ │ └── .keep │ ├── GBA │ │ └── .keep │ ├── GBC │ │ └── .keep │ ├── MD │ │ └── .keep │ ├── PS │ │ └── .keep │ └── SFC │ │ └── .keep └── miyoo354 │ └── app │ ├── MainUI │ └── keymon.sh ├── src ├── batmon │ ├── batmon.c │ └── makefile ├── blank │ ├── main.c │ └── makefile ├── clock │ ├── main.c │ └── makefile ├── common │ ├── common.c │ └── common.h ├── confirm │ ├── main.c │ └── makefile ├── keymon │ ├── credits.txt │ ├── keymon.c │ └── makefile ├── libmmenu │ ├── makefile │ ├── mmenu.c │ └── mmenu.h ├── libmsettings │ ├── makefile │ ├── msettings.c │ └── msettings.h ├── lumon │ ├── lumon.c │ └── makefile ├── miniui │ ├── main.c │ └── makefile ├── progressui │ ├── main.c │ ├── makefile │ └── progress.sh ├── say │ ├── main.c │ └── makefile └── show │ ├── main.c │ └── makefile ├── third-party ├── latency_reduction │ ├── Makefile │ ├── audioserver.mod │ ├── credits.txt │ └── main.c ├── logotweak │ ├── credits.txt │ ├── logomake │ │ ├── Makefile │ │ └── main.c │ ├── logoread │ │ ├── Makefile │ │ └── main.c │ └── logowrite │ │ ├── Makefile │ │ └── main.c └── screenshot │ ├── Makefile │ ├── credits.txt │ └── main.c └── todo.txt /.github/workflows/nopr.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | workflow_dispatch: 4 | 5 | 6 | jobs: 7 | close: 8 | name: Close Pull Request 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Close Pull Request 12 | env: 13 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 14 | run: | 15 | # Find all open PRs, and close them. 16 | gh pr list --repo=${{ github.repository }} --state=open --json=number | jq '.[].number' | xargs gh pr close --repo=${{ github.repository }} -d 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | nopes/ 3 | releases/ 4 | 5 | .DS_Store 6 | *.o 7 | *.so 8 | 9 | # thanks I hate it 10 | batmon 11 | !batmon/ 12 | keymon 13 | !keymon/ 14 | lumon 15 | !lumon/ 16 | MiniUI 17 | !MiniUI/ 18 | progressui 19 | !progressui/ 20 | show 21 | !show/ 22 | confirm 23 | !confirm/ 24 | say 25 | !say/ 26 | blank 27 | !blank/ 28 | clock 29 | !clock/ 30 | 31 | screenshot 32 | !screenshot/ 33 | logoread 34 | !logoread/ 35 | logomake 36 | !logomake/ 37 | logowrite 38 | !logowrite/ 39 | 40 | # NOTE: this eats miyoo/app/keymon, had to add extension then remove it in makefile 41 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "third-party/DinguxCommander"] 2 | path = third-party/DinguxCommander 3 | url = https://github.com/shauninman/DinguxCommander.git 4 | branch = miniui-miyoomini 5 | [submodule "third-party/SDL-1.2"] 6 | path = third-party/SDL-1.2 7 | url = https://github.com/shauninman/SDL-1.2.git 8 | branch = miniui-miyoomini 9 | [submodule "third-party/picoarch"] 10 | path = third-party/picoarch 11 | url = https://github.com/shauninman/picoarch.git 12 | branch = miniui-miyoomini 13 | [submodule "third-party/vvvvvv"] 14 | path = third-party/vvvvvv 15 | url = https://github.com/shauninman/VVVVVV.git 16 | branch = miniui-miyoomini 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DotUI 2 | 3 | _DotUI is a port of the popular [MiniUI](https://github.com/shauninman/MiniUI) custom launcher and integrated in-game menu, compatible with the [Miyoo Mini Plus](https://www.aliexpress.com/item/1005005215387485.html) handheld emulator_ 4 | 5 | 6 | 7 | # Important Notice 8 | 9 | All support for this port on the Mini Plus will be provided on this project by Xpndable. Please raise issues here, or discuss them on the [Retro Gaming Handhelds discord server](https://discord.gg/retro-game-handhelds-529983248114122762). 10 | 11 | # Project Information 12 | 13 | This project now has a release candidate, and barring any major bugs or issues found, will be graduated to v1.0 some time after publishing. The download files can be found [here](https://github.com/Xpndable/DotUI/releases) 14 | 15 | The following are the list of features that will be worked on to take advantage of the WiFi chip in the Miyoo Mini Plus (in no particular order): 16 | * WiFi configuration tool and OTA updates 17 | * File Transfer tool 18 | * Cloud Saves 19 | * Retroachievements 20 | * RTC Sync 21 | * NetPlay 22 | 23 | ## Contributing 24 | 25 | If you'd like to contribute to the project: 26 | * For bugs, simply raise a pull request and it will be assessed on it's own merits. 27 | * For features, first build and release a .pak as either a Tool or Emu add-on in your own project on GitHub. If you'd then like to have this included in the project as an official extra, raise a pull request that links your code into the `third-party` folder, and include a modified `make` script. This will ensure an ever-green approach to including your work in the DotUI repository. 28 | * If your feature requires modification to the core components such as `keymon`, `batmon`, `main`, `common`, `mmenu` or `msettings`, feel free to discuss with me your ideas in the [Retro Gaming Handhelds discord server](https://discord.gg/retro-game-handhelds-529983248114122762), and we can co-ordinate our combined efforts. -------------------------------------------------------------------------------- /bits/bootlogos/miniui/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/bits/bootlogos/miniui/image1.jpg -------------------------------------------------------------------------------- /bits/bootlogos/miniui/image1.txt: -------------------------------------------------------------------------------- 1 | 32bfc3839b8fa8a0816030554506487f -------------------------------------------------------------------------------- /bits/bootlogos/pak/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/bits/bootlogos/pak/image1.jpg -------------------------------------------------------------------------------- /bits/bootlogos/pak/image1.txt: -------------------------------------------------------------------------------- 1 | 61bfac86f630ddbdf70e14c5b0be7af9 -------------------------------------------------------------------------------- /bits/bootlogos/pak/image2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/bits/bootlogos/pak/image2.jpg -------------------------------------------------------------------------------- /bits/bootlogos/pak/image3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/bits/bootlogos/pak/image3.jpg -------------------------------------------------------------------------------- /bits/bootlogos/pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # used to generate the following paks 4 | 5 | # /Tools/Single-use/02) Add MiniUI Boot Logo.pak 6 | # /Tools/Single-use/02) Remove MiniUI Boot Logo.pak 7 | 8 | DIR=$(dirname "$0") 9 | cd "$DIR" 10 | 11 | { 12 | 13 | SUPPORTED_VERSION="202205010000" # there is no 202205010000 firmware, it's when I created this pak 14 | EXPECT1_MD5=`cat ./image1.txt` 15 | EXPECT2_MD5=64c9ec14d4c4995cb9681bba1eefaa34 16 | EXPECT3_MD5=6c0f4834b754a19ad578b39b3da03c95 17 | MAX_SUM=129732 # 12KB minus 1340b header 18 | 19 | bail() 20 | { 21 | show okay.png 22 | say "$1"$'\n' 23 | sleep 0.1 24 | confirm only 25 | exit 1 26 | } 27 | 28 | if [ $MIYOO_VERSION -gt $SUPPORTED_VERSION ]; then 29 | bail "Unknown firmware version"$'\n\n'"Please update this pak"$'\n'"and try again."$'\n' 30 | fi 31 | 32 | show confirm.png 33 | say "WARNING! Modifying the boot"$'\n'"logo has the potential to brick"$'\n'"your Miyoo Mini. No takebacks!"$'\n' 34 | 35 | if confirm; then 36 | blank 37 | 38 | say "Verifying logo" 39 | sleep 1 40 | 41 | IMAGE1_MD5=$(md5sum ./image1.jpg | awk '{print $1}') 42 | IMAGE2_MD5=$(md5sum ./image2.jpg | awk '{print $1}') 43 | IMAGE3_MD5=$(md5sum ./image3.jpg | awk '{print $1}') 44 | 45 | if [[ "$IMAGE1_MD5" != "$EXPECT1_MD5" ]]; then 46 | bail "Image 1 failed verification"$'\n\n'"Aborted"$'\n' 47 | elif [[ "$IMAGE2_MD5" != "$EXPECT2_MD5" ]]; then 48 | bail "Image 2 failed verification"$'\n\n'"Aborted"$'\n' 49 | elif [[ "$IMAGE3_MD5" != "$EXPECT3_MD5" ]]; then 50 | bail "Image 3 failed verification"$'\n\n'"Aborted"$'\n' 51 | fi 52 | 53 | IMAGE1_SIZE=$(stat -c%s ./image1.jpg) 54 | IMAGE2_SIZE=$(stat -c%s ./image2.jpg) 55 | IMAGE3_SIZE=$(stat -c%s ./image3.jpg) 56 | 57 | SUM=$(expr $IMAGE1_SIZE + $IMAGE2_SIZE + $IMAGE3_SIZE) 58 | 59 | if [ $SUM -gt $MAX_SUM ]; then 60 | bail "Sum of image file sizes"$'\n'"is greater than 128KB"$'\n\n'"Aborted"$'\n' 61 | fi 62 | 63 | blank 64 | say "Preparing logo" 65 | sleep 1 66 | if ! ./logomake; then 67 | bail "Preparing logo failed"$'\n\n'"Aborted"$'\n' 68 | fi 69 | 70 | blank 71 | say "Flashing logo" 72 | sleep 1 73 | if ! ./logowrite; then 74 | bail "Flashing logo failed"$'\n\n'"Aborted"$'\n' 75 | fi 76 | 77 | blank 78 | say "Done" 79 | sleep 1 80 | else 81 | blank 82 | say "Aborted" 83 | sleep 1 84 | fi 85 | 86 | } &> "$LOGS_PATH/BootLogo.txt" 87 | -------------------------------------------------------------------------------- /bits/commits.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # echo "$(git rev-parse --short=8 HEAD) $(basename $PWD) ($(date "+%Y-%m-%d %H:%M:%S"))" # $(git config --get remote.origin.url) 4 | # echo "-------- ------" 5 | # 6 | shopt -s dotglob 7 | update() { 8 | for d in "$@"; do 9 | test -d "$d" -a \! -L "$d" || continue 10 | cd "$d" 11 | if [ -d ".git" ] || [ -f ".git" ]; then 12 | echo "$(git rev-parse --short=8 HEAD) $(basename $PWD)" # $(git config --get remote.origin.url) 13 | update * 14 | fi 15 | cd .. 16 | done 17 | } 18 | 19 | cd ./third-party 20 | update * 21 | 22 | cd ./picoarch/cores 23 | update * 24 | 25 | echo "--------" 26 | echo "generated by $0" -------------------------------------------------------------------------------- /commits.txt: -------------------------------------------------------------------------------- 1 | 5e600602 DinguxCommander 2 | 608ebfc1 SDL-1.2 3 | ab7f0294 picoarch 4 | 76e45c34 libpicofe 5 | 88252880 libretro-common 6 | 15e0485e vvvvvv 7 | e8801687 beetle-pce-fast 8 | 0b9ea388 beetle-vb 9 | 74fc9369 fake-08 10 | b3c35b65 fceumm 11 | 15536214 gambatte 12 | 73e64647 genesis-plus-gx 13 | 03fc2b7d gpsp 14 | 85b55272 mednafen_supafaust 15 | 3990558e mgba 16 | fc102fa3 nxengine 17 | 131a1b41 pcsx_rearmed 18 | 2ec448a8 picodrive 19 | 684e7ea0 pokemini 20 | 9de9847d smsplus-gx 21 | 23f759bc snes9x2005 22 | 23f759bc snes9x2005_plus 23 | -------- 24 | generated by ./bits/commits.sh 25 | -------------------------------------------------------------------------------- /extras/Bios/GG/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/extras/Bios/GG/.keep -------------------------------------------------------------------------------- /extras/Bios/MGBA/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/extras/Bios/MGBA/.keep -------------------------------------------------------------------------------- /extras/Bios/PCE/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/extras/Bios/PCE/.keep -------------------------------------------------------------------------------- /extras/Bios/PKM/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/extras/Bios/PKM/.keep -------------------------------------------------------------------------------- /extras/Bios/SGB/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/extras/Bios/SGB/.keep -------------------------------------------------------------------------------- /extras/Bios/SMS/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/extras/Bios/SMS/.keep -------------------------------------------------------------------------------- /extras/Emus/GG.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EMU_EXE=picodrive 4 | 5 | ############################### 6 | 7 | EMU_TAG=$(basename "$(dirname "$0")" .pak) 8 | ROM="$1" 9 | mkdir -p "$BIOS_PATH/$EMU_TAG" 10 | mkdir -p "$SAVES_PATH/$EMU_TAG" 11 | HOME="$USERDATA_PATH" 12 | cd "$HOME" 13 | picoarch "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" LCD &> "$LOGS_PATH/$EMU_TAG.txt" 14 | -------------------------------------------------------------------------------- /extras/Emus/MGBA.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EMU_EXE=mgba 4 | CORES_PATH=$(dirname "$0") 5 | 6 | ############################### 7 | 8 | EMU_TAG=$(basename "$(dirname "$0")" .pak) 9 | ROM="$1" 10 | mkdir -p "$BIOS_PATH/$EMU_TAG" 11 | mkdir -p "$SAVES_PATH/$EMU_TAG" 12 | HOME="$USERDATA_PATH" 13 | cd "$HOME" 14 | picoarch "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" LCD &> "$LOGS_PATH/$EMU_TAG.txt" 15 | -------------------------------------------------------------------------------- /extras/Emus/P8.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EMU_EXE=fake-08 4 | CORES_PATH=$(dirname "$0") 5 | 6 | ############################### 7 | 8 | EMU_TAG=$(basename "$(dirname "$0")" .pak) 9 | ROM="$1" 10 | mkdir -p "$BIOS_PATH/$EMU_TAG" 11 | mkdir -p "$SAVES_PATH/$EMU_TAG" 12 | HOME="$USERDATA_PATH" 13 | cd "$HOME" 14 | picoarch "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" &> "$LOGS_PATH/$EMU_TAG.txt" 15 | -------------------------------------------------------------------------------- /extras/Emus/PCE.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EMU_EXE=mednafen_pce_fast 4 | CORES_PATH=$(dirname "$0") 5 | 6 | ############################### 7 | 8 | EMU_TAG=$(basename "$(dirname "$0")" .pak) 9 | ROM="$1" 10 | mkdir -p "$BIOS_PATH/$EMU_TAG" 11 | mkdir -p "$SAVES_PATH/$EMU_TAG" 12 | HOME="$USERDATA_PATH" 13 | cd "$HOME" 14 | picoarch "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" &> "$LOGS_PATH/$EMU_TAG.txt" 15 | -------------------------------------------------------------------------------- /extras/Emus/PKM.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EMU_EXE=pokemini 4 | CORES_PATH=$(dirname "$0") 5 | 6 | ############################### 7 | 8 | EMU_TAG=$(basename "$(dirname "$0")" .pak) 9 | ROM="$1" 10 | mkdir -p "$BIOS_PATH/$EMU_TAG" 11 | mkdir -p "$SAVES_PATH/$EMU_TAG" 12 | HOME="$USERDATA_PATH" 13 | cd "$HOME" 14 | picoarch "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" DMG &> "$LOGS_PATH/$EMU_TAG.txt" 15 | -------------------------------------------------------------------------------- /extras/Emus/SGB.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EMU_EXE=mgba 4 | CORES_PATH=$(dirname "$0") 5 | 6 | ############################### 7 | 8 | EMU_TAG=$(basename "$(dirname "$0")" .pak) 9 | ROM="$1" 10 | mkdir -p "$BIOS_PATH/$EMU_TAG" 11 | mkdir -p "$SAVES_PATH/$EMU_TAG" 12 | HOME="$USERDATA_PATH" 13 | cd "$HOME" 14 | picoarch "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" &> "$LOGS_PATH/$EMU_TAG.txt" 15 | -------------------------------------------------------------------------------- /extras/Emus/SH.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # for Native Games or Ports 4 | 5 | EMU_TAG=$(basename "$(dirname "$0")" .pak) 6 | mkdir -p "$SAVES_PATH/$EMU_TAG" 7 | "$1" &> "$LOGS_PATH/$EMU_TAG.txt" -------------------------------------------------------------------------------- /extras/Emus/SMS.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EMU_EXE=picodrive 4 | 5 | ############################### 6 | 7 | EMU_TAG=$(basename "$(dirname "$0")" .pak) 8 | ROM="$1" 9 | mkdir -p "$BIOS_PATH/$EMU_TAG" 10 | mkdir -p "$SAVES_PATH/$EMU_TAG" 11 | HOME="$USERDATA_PATH" 12 | cd "$HOME" 13 | picoarch "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" &> "$LOGS_PATH/$EMU_TAG.txt" 14 | -------------------------------------------------------------------------------- /extras/Emus/SUPA.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EMU_EXE=mednafen_supafaust 4 | CORES_PATH=$(dirname "$0") 5 | 6 | ############################### 7 | 8 | EMU_TAG=$(basename "$(dirname "$0")" .pak) 9 | ROM="$1" 10 | mkdir -p "$BIOS_PATH/$EMU_TAG" 11 | mkdir -p "$SAVES_PATH/$EMU_TAG" 12 | HOME="$USERDATA_PATH" 13 | cd "$HOME" 14 | picoarch "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" &> "$LOGS_PATH/$EMU_TAG.txt" 15 | -------------------------------------------------------------------------------- /extras/README.txt: -------------------------------------------------------------------------------- 1 | DotUI is a minimal launcher for the Miyoo Mini Plus, adapted from Shaun Inman's MiniUI 2 | 3 | DotUI Source: https://github.com/Xpndable/DotUI 4 | 5 | MiniUI Source: https://github.com/shauninman/MiniUI 6 | 7 | ---------------------------------------- 8 | Adding Paks 9 | 10 | A pak is a folder with a pak extension that contains a shell script named launch.sh. 11 | 12 | There are two kinds of paks, emulators and tools. Emulator paks live in the Emus folder. Tool paks live in the Tools folder. Both of those folders live at the root of your SD card. If you're adding paks created by someone else (sharing is caring) just copy each pak into the corresponding folder. That's usually it but they may have additional steps (eg. additions to the Roms or Bios folders). Check for a readme or ask the original author if you're unsure. 13 | 14 | ---------------------------------------- 15 | Creating an emulator pak 16 | 17 | There are two kinds of emulator paks, both similar, both super simple. The first re-uses an existing DotUI libretro core. The second uses a custom libretro core. To illustrate the different approaches, let's create a Sega Game Gear pak (already part of this zip file). 18 | 19 | First create an "Emus" folder at the root of your SD card if one doesn't already exist. Then make sure your file browser is showing invisible files for this next step. Copy "/.system/paks/Emus/MD.pak/" into the Emus folder and rename it to GG.pak. GG is your emulator tag. The tag is used to map its roms folder to the pak. That's it. You're done. You just created your first DotUI emulator pak! Now create the corresponding roms folder "/Roms/Game Gear (GG)/" (see, there's that tag again!) and load it up with a few roms. Boot up DotUI and give it a shot. Easy, right? Let's do the next one. 20 | 21 | First download the smsplus-gx_libretro.so core and put it in your GG.pak. Then open launch.sh in a plain text editor (make sure this editor uses just `\n` for newlines, Linux is picky Windows friends). We need to change two things this time. Replace `EMU_EXE=picodrive` with `EMU_EXE=smsplus-gx` then right below that line add `CORES_PATH=$(dirname "$0")`. Save and you're done. Still pretty damn easy. 22 | 23 | There are two things to consider when creating your own emulator pak. If a core doesn't support save states, autoresume will not work. That means if a player manually powers off in game or it falls alseep while on the menu and automatically powers off, they will lose any unsaved progress. Please don't do this to people. It doesn't matter if you mention it in a readme (!), people won't read it and they will be angry at you (or more likely, me). Just don't. The other thing worth noting is that DotUI doesn't enable swap by default (it can degrade performance of emulators that don't need it). For emulators that require more memory than is physically available on the Miyoo Mini, just call `needs-swap` before launching `picoarch` to enabled a 128MB swap image. 24 | 25 | ---------------------------------------- 26 | Bios files 27 | 28 | You'll need to BYOB for these emulator paks included in this zip file. 29 | 30 | MGBA: gba_bios.bin 31 | PCE: syscard3.pce 32 | PKM: bios.min 33 | SGB: sgb_bios.bin 34 | 35 | ---------------------------------------- 36 | Creating a tool pak 37 | 38 | Tool paks can run a GUI program, setup a daemon, or just script a quick action before exiting. See the Files and Screenshots paks for examples but usually a tool pak will change to the current directory, set any necessary environmental variables, and then launch a binary relative to the folder. 39 | 40 | DotUI comes with a couple of binaries to simplify providing feedback to users: show, blank, say, and confirm. (If you need to perform a longer action with discrete steps there is also the more advanced progressui.) Check out the Example pak for...um, an example of how those work. 41 | -------------------------------------------------------------------------------- /extras/Roms/Game Boy Advance (MGBA)/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/extras/Roms/Game Boy Advance (MGBA)/.keep -------------------------------------------------------------------------------- /extras/Roms/Native Games (SH)/Cave Story/Cave Story.m3u: -------------------------------------------------------------------------------- 1 | launch.sh -------------------------------------------------------------------------------- /extras/Roms/Native Games (SH)/Cave Story/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | DIR="$(dirname "$0")" 4 | HOME="$USERDATA_PATH" 5 | 6 | cd "$DIR" 7 | if [ -f Doukutsu.exe ] && [ -d data ]; then 8 | cd "$HOME" 9 | picoarch "$DIR/nxengine_libretro.so" "$DIR/Doukutsu.exe" 10 | else 11 | show "okay.png" 12 | say "Missing exe and data folder!"$'\n\n'"Please see readme.txt"$'\n'"in the Cave Story folder"$'\n'"on your SD card."$'\n' 13 | confirm only 14 | fi 15 | -------------------------------------------------------------------------------- /extras/Roms/Native Games (SH)/Cave Story/readme.txt: -------------------------------------------------------------------------------- 1 | Download the English translation (pre-patched) from: 2 | 3 | https://www.cavestory.org/downloads/cavestoryen.zip 4 | 5 | Unzip and copy the resulting data folder and 6 | Doukutsu.exe into this Cave Story folder. -------------------------------------------------------------------------------- /extras/Roms/Native Games (SH)/VVVVVV/VVVVVV.m3u: -------------------------------------------------------------------------------- 1 | launch.sh -------------------------------------------------------------------------------- /extras/Roms/Native Games (SH)/VVVVVV/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd "$(dirname "$0")" 4 | HOME="$USERDATA_PATH" 5 | 6 | if [ -f data.zip ]; then 7 | warn 8 | ./vvvvvv 9 | else 10 | show "okay.png" 11 | say "Missing data.zip!"$'\n\n'"Please see readme.txt"$'\n'"in the VVVVVV folder"$'\n'"on your SD card."$'\n' 12 | confirm only 13 | fi 14 | 15 | -------------------------------------------------------------------------------- /extras/Roms/Native Games (SH)/VVVVVV/readme.txt: -------------------------------------------------------------------------------- 1 | Download the Desktop data file from: 2 | 3 | https://thelettervsixtim.es/makeandplay/data.zip 4 | 5 | and place it inside this VVVVVV folder. 6 | 7 | Do not unzip data.zip. 8 | -------------------------------------------------------------------------------- /extras/Roms/Pokémon mini (PKM)/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/extras/Roms/Pokémon mini (PKM)/.keep -------------------------------------------------------------------------------- /extras/Roms/Sega Game Gear (GG)/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/extras/Roms/Sega Game Gear (GG)/.keep -------------------------------------------------------------------------------- /extras/Roms/Sega Master System (SMS)/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/extras/Roms/Sega Master System (SMS)/.keep -------------------------------------------------------------------------------- /extras/Roms/Super Game Boy (SGB)/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/extras/Roms/Super Game Boy (SGB)/.keep -------------------------------------------------------------------------------- /extras/Roms/TurboGrafx-16 (PCE)/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/extras/Roms/TurboGrafx-16 (PCE)/.keep -------------------------------------------------------------------------------- /extras/Saves/GG/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/extras/Saves/GG/.keep -------------------------------------------------------------------------------- /extras/Saves/MGBA/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/extras/Saves/MGBA/.keep -------------------------------------------------------------------------------- /extras/Saves/PCE/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/extras/Saves/PCE/.keep -------------------------------------------------------------------------------- /extras/Saves/PKM/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/extras/Saves/PKM/.keep -------------------------------------------------------------------------------- /extras/Saves/SGB/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/extras/Saves/SGB/.keep -------------------------------------------------------------------------------- /extras/Saves/SMS/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/extras/Saves/SMS/.keep -------------------------------------------------------------------------------- /extras/Saves/SUPA/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/extras/Saves/SUPA/.keep -------------------------------------------------------------------------------- /extras/Tools/Clock.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd "$(dirname "$0")" 3 | ./clock 4 | -------------------------------------------------------------------------------- /extras/Tools/Enable Simple Mode.pak/README.txt: -------------------------------------------------------------------------------- 1 | Simple Mode 2 | 3 | ---------------------------------------- 4 | You know, for kids! 5 | 6 | Simple Mode does two things: 7 | 8 | 1. disables the Tools menu (if present) 9 | 2. changes the Advanced option to Reset 10 | 11 | That's it! 12 | 13 | ---------------------------------------- 14 | Disabling Simple Mode 15 | 16 | Delete the following file from your SD card: 17 | 18 | /.userdata/enable-simple-mode 19 | 20 | Truth in advertising. 21 | -------------------------------------------------------------------------------- /extras/Tools/Enable Simple Mode.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | show confirm.png && say "Once enabled Simple Mode can only"$'\n'"be disabled by using another device"$'\n'"to delete a file from this SD card."$'\n\n'"Please see the README included"$'\n'"in this pak for details."$'\n\n' 4 | 5 | if confirm; then 6 | touch /mnt/SDCARD/.userdata/enable-simple-mode 7 | fi -------------------------------------------------------------------------------- /extras/Tools/Example.pak/fam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/extras/Tools/Example.pak/fam.png -------------------------------------------------------------------------------- /extras/Tools/Example.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | DIR=$(dirname "$0") 4 | cd "$DIR" 5 | 6 | progressui & 7 | 8 | progress 0 "Sorry to make you wait" 9 | sleep 0.5 10 | 11 | progress 33 "Practice makes progress" 12 | sleep 0.5 13 | 14 | progress 66 "Not much longer now" 15 | sleep 0.5 16 | 17 | progress 100 "That wasn't so bad" 18 | sleep 1 19 | 20 | progress quit 21 | 22 | show confirm.png 23 | say "So, do you want to do the thing?"$'\n' 24 | 25 | if confirm; then 26 | blank 27 | say "Yeah man, I want to do it" 28 | sleep 2 29 | show "$DIR/fam.png" 30 | confirm any 31 | else 32 | show okay.png 33 | say "Nah, I'm good"$'\n' 34 | sleep 0.1 35 | confirm only 36 | fi -------------------------------------------------------------------------------- /extras/Tools/Files.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd "$(dirname "$0")" 4 | 5 | HOME="$SDCARD_PATH" 6 | ./DinguxCommander &> "$LOGS_PATH/Commander.txt" 7 | -------------------------------------------------------------------------------- /extras/Tools/Random Game.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # TODO: write a daemon that binds this to Y? 4 | 5 | say "Finding a random game..." 6 | sleep 1 7 | 8 | cd $SDCARD_PATH 9 | ROMS="$SDCARD_PATH/Roms" 10 | FILE="$ROMS" 11 | LOOPS=0 12 | while :; do 13 | if [[ ! -d "$FILE" ]]; then 14 | break 15 | fi 16 | 17 | LINES=`find "$FILE" -maxdepth 1 -not -path '*/.*'` 18 | TOTAL=`echo -n "$LINES" | grep -c '^'` 19 | if [[ "$TOTAL" -le "1" ]]; then # the current directory seems to be listed first 20 | FILE="$ROMS" # take it again from the top? 21 | LOOPS=`expr ${LOOPS} + 1` 22 | if [[ "$LOOPS" -ge "16" ]]; then 23 | FILE="" 24 | break 25 | fi 26 | fi 27 | 28 | R=`expr ${RANDOM} % ${TOTAL} + 1` 29 | FILE=`echo "$LINES" | head -n $R | tail -1` 30 | 31 | if [[ -f "$FILE" ]]; then 32 | break 33 | fi 34 | 35 | BASE=$(basename "$FILE") 36 | if [[ -f "$FILE/$BASE.m3u" ]]; then 37 | break 38 | fi 39 | 40 | if [[ -f "$FILE/$BASE.cue" ]]; then 41 | break 42 | fi 43 | done 44 | 45 | if [[ -z "$FILE" ]]; then 46 | show okay.png 47 | say "Could not find any games."$'\n'"(Too many empty folders?)"$'\n' 48 | sleep 0.1 49 | confirm only 50 | exit 51 | fi 52 | 53 | # the shell isn't liking parameter expansion 54 | # when the var contains spaces so we have to 55 | # pop the directories manually 56 | TMP="$FILE" 57 | EMU_TAG="$TMP" 58 | while :; do 59 | TMP=$(dirname "$EMU_TAG") 60 | if [ "$TMP" = "$ROMS" ]; then 61 | EMU_TAG=$(basename "$EMU_TAG") 62 | break 63 | fi 64 | EMU_TAG="$TMP" 65 | done 66 | 67 | # see above 68 | # EMU_TAG="$FILE" 69 | # EMU_TAG="${EMU_TAG//\/mnt\/SDCARD\/Roms\//}" 70 | # EMU_TAG="${EMU_TAG//\/*/}" 71 | EMU_TAG="${EMU_TAG//*(/}" 72 | EMU_TAG="${EMU_TAG//)*/}" 73 | 74 | echo -n "$FILE" > "/tmp/last.txt" 75 | # echo -n "${EMU_TAG}.pak $FILE" > "$SDCARD_PATH/random.txt" 76 | 77 | if [[ -f "$SDCARD_PATH/Emus/${EMU_TAG}.pak/launch.sh" ]]; then 78 | "$SDCARD_PATH/Emus/${EMU_TAG}.pak/launch.sh" "$FILE" 79 | elif [[ -f "$SDCARD_PATH/.system/paks/Emus/${EMU_TAG}.pak/launch.sh" ]]; then 80 | "$SDCARD_PATH/.system/paks/Emus/${EMU_TAG}.pak/launch.sh" "$FILE" 81 | fi -------------------------------------------------------------------------------- /extras/Tools/Screenshots.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd "$(dirname "$0")" 4 | a=`ps | grep screenshot | grep -v grep` 5 | if [ "$a" == "" ] ; then 6 | ./screenshot & 7 | say "Enabled screenshots"$'\n'"Press L2 + R2 to take" 8 | sleep 2 9 | else 10 | killall screenshot 11 | say "Disabled screenshots" 12 | sleep 1 13 | fi 14 | 15 | -------------------------------------------------------------------------------- /github/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/github/main.png -------------------------------------------------------------------------------- /github/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/github/menu.png -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean 2 | 3 | ########################################################### 4 | 5 | ifeq (,$(PLATFORM)) 6 | PLATFORM=$(UNION_PLATFORM) 7 | endif 8 | 9 | ifeq (,$(PLATFORM)) 10 | $(error please specify PLATFORM, eg. PLATFORM=trimui make) 11 | endif 12 | 13 | ########################################################### 14 | 15 | BUILD_ARCH!=uname -m 16 | BUILD_HASH!=git rev-parse --short HEAD 17 | BUILD_TIME!=date "+%Y-%m-%d %H:%M:%S" 18 | BUILD_REPO=https://github.com/shauninman/MiniUI 19 | BUILD_GCC:=$(shell $(CROSS_COMPILE)gcc -dumpfullversion -dumpversion) 20 | 21 | RELEASE_TIME!=date +%Y%m%d 22 | RELEASE_BASE=DotUI-$(RELEASE_TIME) 23 | RELEASE_DOT!=find ./releases/. -regex ".*/$(RELEASE_BASE)-[0-9]+-base\.zip" -printf '.' | wc -m 24 | RELEASE_NAME=$(RELEASE_BASE)-$(RELEASE_DOT) 25 | 26 | PATCH = git apply 27 | 28 | LIBC_LIB=/opt/miyoomini-toolchain/arm-none-linux-gnueabihf/libc/lib 29 | BUNDLE_LIBS= 30 | 31 | GCC_VER_GTE9_0 := $(shell echo `gcc -dumpversion | cut -f1-2 -d.` \>= 9.0 | bc ) 32 | ifeq "$(GCC_VER_GTE9_0)" "1" 33 | BUNDLE_LIBS=bundle 34 | endif 35 | 36 | all: third-party/SDL-1.2/.patched third-party/picoarch/.patched lib sdl core emu tools payload readmes $(BUNDLE_LIBS) zip 37 | 38 | extras: emu 39 | 40 | # To fix/move into private repos 41 | third-party/SDL-1.2/.patched: 42 | cd third-party/SDL-1.2 && $(PATCH) -p1 < ../../patches/SDL-1.2/0001-vol-keys.patch && touch .patched 43 | 44 | third-party/picoarch/.patched: 45 | cd third-party/picoarch && $(PATCH) -p1 < ../../patches/picoarch/0001-pokemini-make.patch && touch .patched 46 | 47 | lib: 48 | cd ./src/libmsettings && make 49 | cd ./src/libmmenu && make 50 | cd ./third-party/latency_reduction && make 51 | sdl: 52 | cd ./third-party/SDL-1.2 && ./make.sh 53 | 54 | core: 55 | cd ./src/batmon && make 56 | cd ./src/keymon && make 57 | cd ./src/lumon && make 58 | cd ./src/progressui && make 59 | cd ./src/miniui && make 60 | cd ./src/show && make 61 | cd ./src/confirm && make 62 | cd ./src/say && make 63 | cd ./src/blank && make 64 | 65 | emu: 66 | cd ./third-party/picoarch && make platform=miyoomini -j 67 | cd ./third-party/vvvvvv && make -j 68 | ./bits/commits.sh > ./commits.txt 69 | 70 | tools: 71 | cd ./third-party/DinguxCommander && make -j 72 | cd ./third-party/screenshot && make 73 | cd ./third-party/logotweak/logomake && make 74 | cd ./third-party/logotweak/logowrite && make 75 | cd ./src/clock && make 76 | 77 | readmes: 78 | fmt -w 40 -s ./skeleton//README.txt > ./build/PAYLOAD/README.txt 79 | fmt -w 40 -s ./extras//README.txt > ./build/EXTRAS/README.txt 80 | 81 | payload: 82 | rm -rf ./build 83 | mkdir -p ./releases 84 | mkdir -p ./build 85 | cp -R ./skeleton/. ./build/PAYLOAD 86 | cp -R ./extras/. ./build/EXTRAS 87 | mv ./build/PAYLOAD/miyoo354/app/keymon.sh ./build/PAYLOAD/miyoo354/app/keymon 88 | cd ./build && find . -type f -name '.keep' -delete 89 | cd ./build && find . -type f -name '.DS_Store' -delete 90 | cp ./src/libmsettings/libmsettings.so ./build/PAYLOAD/.system/lib/ 91 | cp ./src/libmmenu/libmmenu.so ./build/PAYLOAD/.system/lib/ 92 | cp ./third-party/latency_reduction/as_preload.so ./build/PAYLOAD/.system/lib/ 93 | cp ./third-party/latency_reduction/audioserver.mod ./build/PAYLOAD/.system/bin/ 94 | cp ./third-party/SDL-1.2/build/.libs/libSDL-1.2.so.0.11.5 ./build/PAYLOAD/.system/lib/libSDL-1.2.so.0 95 | cp ./src/batmon/batmon ./build/PAYLOAD/.system/bin/ 96 | cp ./src/keymon/keymon ./build/PAYLOAD/.system/bin/ 97 | cp ./src/lumon/lumon ./build/PAYLOAD/.system/bin/ 98 | cp ./src/progressui/progressui ./build/PAYLOAD/.system/bin/ 99 | cp ./src/progressui/progress.sh ./build/PAYLOAD/.system/bin/progress 100 | cp ./src/miniui/MiniUI ./build/PAYLOAD/.system/paks/MiniUI.pak/ 101 | cp ./src/show/show ./build/PAYLOAD/.system/bin/ 102 | cp ./src/confirm/confirm ./build/PAYLOAD/.system/bin/ 103 | cp ./src/say/say ./build/PAYLOAD/.system/bin/ 104 | cp ./src/blank/blank ./build/PAYLOAD/.system/bin/ 105 | cp ./src/say/say ./build/PAYLOAD/miyoo354/app/ 106 | cp ./src/blank/blank ./build/PAYLOAD/miyoo354/app/ 107 | cp ./third-party/picoarch/output/picoarch ./build/PAYLOAD/.system/bin/ 108 | cp ./third-party/picoarch/output/fceumm_libretro.so ./build/PAYLOAD/.system/cores/ 109 | cp ./third-party/picoarch/output/gambatte_libretro.so ./build/PAYLOAD/.system/cores/ 110 | cp ./third-party/picoarch/output/gpsp_libretro.so ./build/PAYLOAD/.system/cores/ 111 | cp ./third-party/picoarch/output/pcsx_rearmed_libretro.so ./build/PAYLOAD/.system/cores/ 112 | cp ./third-party/picoarch/output/picodrive_libretro.so ./build/PAYLOAD/.system/cores/ 113 | cp ./third-party/picoarch/output/snes9x2005_plus_libretro.so ./build/PAYLOAD/.system/cores/ 114 | cp ./third-party/DinguxCommander/output/DinguxCommander ./build/EXTRAS/Tools/Files.pak/ 115 | cp ./src/clock/clock ./build/EXTRAS/Tools/Clock.pak/ 116 | cp -r ./third-party/DinguxCommander/res ./build/EXTRAS/Tools/Files.pak/ 117 | cp ./third-party/screenshot/screenshot ./build/EXTRAS/Tools/Screenshots.pak/ 118 | cp ./third-party/picoarch/output/beetle-pce-fast_libretro.so ./build/EXTRAS/Emus/PCE.pak/mednafen_pce_fast_libretro.so 119 | cp ./third-party/picoarch/output/pokemini_libretro.so ./build/EXTRAS/Emus/PKM.pak/ 120 | cp ./third-party/picoarch/output/mednafen_supafaust_libretro.so ./build/EXTRAS/Emus/SUPA.pak/ 121 | cp ./third-party/picoarch/output/mgba_libretro.so ./build/EXTRAS/Emus/MGBA.pak/ 122 | cp ./third-party/picoarch/output/mgba_libretro.so ./build/EXTRAS/Emus/SGB.pak/ 123 | cp ./third-party/picoarch/output/fake-08_libretro.so ./build/EXTRAS/Emus/P8.pak/ 124 | cp ./third-party/picoarch/output/nxengine_libretro.so "./build/EXTRAS/Roms/Native Games (SH)/Cave Story/" 125 | cp ./third-party/vvvvvv/vvvvvv "./build/EXTRAS/Roms/Native Games (SH)/VVVVVV/" 126 | # cp -R ./bits/bootlogos/pak/. ./build/EXTRAS/Tools/Single-use/bootlogo.tmp 127 | # cp ./third-party/logotweak/logomake/logomake ./build/EXTRAS/Tools/Single-use/bootlogo.tmp/ 128 | # cp ./third-party/logotweak/logowrite/logowrite ./build/EXTRAS/Tools/Single-use/bootlogo.tmp/ 129 | # cd ./build/EXTRAS/Tools/Single-use/ && cp -R ./bootlogo.tmp/. "02) Remove MiniUI Boot Logo.pak" 130 | # cp -R ./bits/bootlogos/miniui/. ./build/EXTRAS/Tools/Single-use/bootlogo.tmp/ 131 | # cd ./build/EXTRAS/Tools/Single-use/ && cp -R ./bootlogo.tmp/. "02) Add MiniUI Boot Logo.pak" 132 | # rm -rf ./build/EXTRAS/Tools/Single-use/bootlogo.tmp 133 | 134 | bundle: 135 | cp -L /opt/miyoomini-toolchain/arm-none-linux-gnueabihf/libc/lib/ld-linux-armhf.so.3 ./build/PAYLOAD/.system/lib/ 136 | cp -L /opt/miyoomini-toolchain/arm-none-linux-gnueabihf/libc/lib/libc.so.6 ./build/PAYLOAD/.system/lib/ 137 | cp -L /opt/miyoomini-toolchain/arm-none-linux-gnueabihf/libc/lib/libcrypt.so.1 ./build/PAYLOAD/.system/lib/ 138 | cp -L /opt/miyoomini-toolchain/arm-none-linux-gnueabihf/libc/lib/libdl.so.2 ./build/PAYLOAD/.system/lib/ 139 | cp -L /opt/miyoomini-toolchain/arm-none-linux-gnueabihf/libc/lib/libgcc_s.so.1 ./build/PAYLOAD/.system/lib/ 140 | cp -L /opt/miyoomini-toolchain/arm-none-linux-gnueabihf/libc/lib/libm.so.6 ./build/PAYLOAD/.system/lib/ 141 | cp -L /opt/miyoomini-toolchain/arm-none-linux-gnueabihf/libc/lib/libpcprofile.so ./build/PAYLOAD/.system/lib/ 142 | cp -L /opt/miyoomini-toolchain/arm-none-linux-gnueabihf/libc/lib/libpthread.so.0 ./build/PAYLOAD/.system/lib/ 143 | cp -L /opt/miyoomini-toolchain/arm-none-linux-gnueabihf/libc/lib/libresolv.so.2 ./build/PAYLOAD/.system/lib/ 144 | cp -L /opt/miyoomini-toolchain/arm-none-linux-gnueabihf/libc/lib/librt.so.1 ./build/PAYLOAD/.system/lib/ 145 | cp -L /opt/miyoomini-toolchain/arm-none-linux-gnueabihf/libc/lib/libstdc++.so.6 ./build/PAYLOAD/.system/lib/ 146 | 147 | zip: 148 | cd ./build/PAYLOAD/.system/paks/MiniUI.pak && echo "$(RELEASE_NAME)-base.zip\n$(BUILD_HASH)" > version.txt 149 | cp ./commits.txt ./build/PAYLOAD/.system/paks/MiniUI.pak 150 | cd ./build/PAYLOAD && zip -r MiniUI.zip .system .tmp_update 151 | mv ./build/PAYLOAD/MiniUI.zip ./build/PAYLOAD/miyoo354/app/ 152 | cd ./build/PAYLOAD && zip -r ../../releases/$(RELEASE_NAME)-base.zip Bios Roms Saves miyoo354 README.txt 153 | cd ./build/EXTRAS && zip -r ../../releases/$(RELEASE_NAME)-extras.zip Bios Emus Roms Saves Tools README.txt 154 | echo "$(RELEASE_NAME)" > ./build/latest.txt 155 | 156 | rezip: payload $(BUNDLE_LIBS) zip 157 | 158 | clean: 159 | rm -rf ./build 160 | cd ./src/libmsettings && make clean 161 | cd ./src/libmmenu && make clean 162 | cd ./third-party/SDL-1.2 && make distclean 163 | cd ./src/batmon && make clean 164 | cd ./src/keymon && make clean 165 | cd ./src/lumon && make clean 166 | cd ./src/progressui && make clean 167 | cd ./src/miniui && make clean 168 | cd ./src/show && make clean 169 | cd ./src/confirm && make clean 170 | cd ./src/say && make clean 171 | cd ./src/blank && make clean 172 | cd ./third-party/picoarch && make platform=miyoomini clean 173 | cd ./third-party/DinguxCommander && make clean 174 | -------------------------------------------------------------------------------- /nopes.txt: -------------------------------------------------------------------------------- 1 | keyrepeat doesn't work in in-game menu 2 | this is intentional so you can't accidentally choose 3 | Load instead of Save by holding the button too long 4 | 5 | alt core UI 6 | I figured out what I don't like about this: 7 | it forces a user to think about emulator meta in the launcher 8 | and creates an opportunity for indecision instead of helping 9 | them get out of their own way and just enjoy playing games 10 | 11 | Pak Management 12 | installs/uninstalls paks? 13 | nah, you have to do the SD card shuffle anyways to add roms and bios, just do it manually 14 | 15 | see if we can get access to the dmg grid color somehow 16 | not seeing a clean way 17 | what if I set a flag when we change an emu config 18 | then on the next frame use a special version of the dmg scaler that tries to find the 4 colors and sets the grid color 19 | yiiiikes 20 | limit dmg to just gambatte and pokemini? 21 | would still available on GBC games 22 | 23 | when resuming a quicksave set previous path to Recently Played 24 | it was disorienting in practice (because there's no current directory label) 25 | 26 | add Time Limit.pak 27 | set duration 28 | auto-save and power off 29 | snooze option? 30 | would require deep integration, not worth it 31 | 32 | support paks in arbitrary folders? 33 | eh, why? 34 | 35 | Tools 36 | Scaling 37 | Pixel Perfect 38 | Always Aspect 39 | no. overrides, especially in a completely different location from where they're normaly set is bad 40 | 41 | apply boot fix on install/update 42 | I have reservations about this since it's a one time thing 43 | we don't need to be touching nand every install/update 44 | 45 | Settings 46 | NO SETTINGS! 47 | 48 | Version (2022-02-22 12:34:56) 49 | Automatic Update (when present on SD card) 50 | Disabled 51 | Enabled 52 | Automatic Sleep (only while in menus) 53 | Disabled 54 | 30 seconds 55 | 60 seconds 56 | Automatic Power Off (while sleeping) 57 | Disabled 58 | 1 minute 59 | 5 minutes 60 | Automatic Save (before sleep and poweroff) 61 | Disabled 62 | Enabled 63 | Scaling (may affect emulator performance) 64 | Pixel Purist 65 | Aspect Aficionado 66 | Fullscreen Fiend -------------------------------------------------------------------------------- /patches/SDL-1.2/0001-vol-keys.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/video/fbcon/SDL_fbevents.c b/src/video/fbcon/SDL_fbevents.c 2 | index 71b25791..dcfac313 100644 3 | --- a/src/video/fbcon/SDL_fbevents.c 4 | +++ b/src/video/fbcon/SDL_fbevents.c 5 | @@ -1107,12 +1107,12 @@ void FB_InitOSKeymap(_THIS) 6 | case SCANCODE_RIGHTCONTROL: 7 | keymap[i] = SDLK_RCTRL; 8 | break; 9 | - case SCANCODE_RIGHTWIN: 10 | - keymap[i] = SDLK_RSUPER; 11 | - break; 12 | - case SCANCODE_LEFTWIN: 13 | + case SCANCODE_VOLUMEDOWN: 14 | keymap[i] = SDLK_LSUPER; 15 | break; 16 | + case SCANCODE_VOLUMEUP: 17 | + keymap[i] = SDLK_RSUPER; 18 | + break; 19 | case SCANCODE_LEFTALT: 20 | keymap[i] = SDLK_LALT; 21 | break; 22 | diff --git a/src/video/fbcon/SDL_fbkeys.h b/src/video/fbcon/SDL_fbkeys.h 23 | index 3c4dec2f..84524be5 100644 24 | --- a/src/video/fbcon/SDL_fbkeys.h 25 | +++ b/src/video/fbcon/SDL_fbkeys.h 26 | @@ -133,6 +133,8 @@ 27 | #define SCANCODE_PAGEDOWN 109 28 | #define SCANCODE_INSERT 110 29 | #define SCANCODE_REMOVE 111 30 | +#define SCANCODE_VOLUMEDOWN 114 31 | +#define SCANCODE_VOLUMEUP 115 32 | #define SCANCODE_POWER 116 33 | 34 | #define SCANCODE_RIGHTWIN 126 35 | -------------------------------------------------------------------------------- /patches/picoarch/0001-pokemini-make.patch: -------------------------------------------------------------------------------- 1 | diff --git a/Makefile b/Makefile 2 | index 18cccfe..84be842 100644 3 | --- a/Makefile 4 | +++ b/Makefile 5 | @@ -75,6 +75,7 @@ picodrive_MAKEFILE = Makefile.libretro 6 | 7 | pokemini_REPO = https://github.com/libretro/PokeMini 8 | pokemini_MAKEFILE = Makefile.libretro 9 | +pokemini_REVISION = 684e7ea0950f4df48cd1fbf1160e6af3c262c9f0 10 | 11 | quicknes_REPO = https://github.com/libretro/QuickNES_Core 12 | 13 | -------------------------------------------------------------------------------- /skeleton/.system/bin/needs-swap: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | SWAP_PATH=$USERDATA_PATH/swapfile 4 | if [ ! -f "$SWAP_PATH" ]; then 5 | say "Creating swap file" 6 | dd if="/dev/zero" of="$SWAP_PATH" bs=1M count=128 7 | chmod 600 "$SWAP_PATH" 8 | mkswap "$SWAP_PATH" 9 | fi 10 | swapon "$SWAP_PATH" 11 | 12 | touch "/tmp/using-swap" -------------------------------------------------------------------------------- /skeleton/.system/bin/shutdown: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -n "$DATETIME_PATH" ]; then 4 | echo `date +'%F %T'` > "$DATETIME_PATH" 5 | fi 6 | sync && poweroff && sleep 10 -------------------------------------------------------------------------------- /skeleton/.system/bin/warn: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | show "okay.png" 4 | say "This pak does not support"$'\n'"save states, auto-power off"$'\n'"or quicksave and resume."$'\n' 5 | confirm only -------------------------------------------------------------------------------- /skeleton/.system/cores/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/cores/.keep -------------------------------------------------------------------------------- /skeleton/.system/lib/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/lib/.keep -------------------------------------------------------------------------------- /skeleton/.system/paks/Emus/FC.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EMU_EXE=fceumm 4 | 5 | ############################### 6 | 7 | EMU_TAG=$(basename "$(dirname "$0")" .pak) 8 | ROM="$1" 9 | mkdir -p "$BIOS_PATH/$EMU_TAG" 10 | mkdir -p "$SAVES_PATH/$EMU_TAG" 11 | HOME="$USERDATA_PATH" 12 | cd "$HOME" 13 | picoarch "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" &> "$LOGS_PATH/$EMU_TAG.txt" 14 | -------------------------------------------------------------------------------- /skeleton/.system/paks/Emus/GB.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EMU_EXE=gambatte 4 | 5 | ############################### 6 | 7 | EMU_TAG=$(basename "$(dirname "$0")" .pak) 8 | ROM="$1" 9 | mkdir -p "$BIOS_PATH/$EMU_TAG" 10 | mkdir -p "$SAVES_PATH/$EMU_TAG" 11 | HOME="$USERDATA_PATH" 12 | cd "$HOME" 13 | picoarch "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" DMG &> "$LOGS_PATH/$EMU_TAG.txt" 14 | -------------------------------------------------------------------------------- /skeleton/.system/paks/Emus/GBA.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EMU_EXE=gpsp 4 | 5 | ############################### 6 | 7 | EMU_TAG=$(basename "$(dirname "$0")" .pak) 8 | ROM="$1" 9 | mkdir -p "$BIOS_PATH/$EMU_TAG" 10 | mkdir -p "$SAVES_PATH/$EMU_TAG" 11 | HOME="$USERDATA_PATH" 12 | cd "$HOME" 13 | picoarch "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" LCD &> "$LOGS_PATH/$EMU_TAG.txt" 14 | -------------------------------------------------------------------------------- /skeleton/.system/paks/Emus/GBC.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EMU_EXE=gambatte 4 | 5 | ############################### 6 | 7 | EMU_TAG=$(basename "$(dirname "$0")" .pak) 8 | ROM="$1" 9 | mkdir -p "$BIOS_PATH/$EMU_TAG" 10 | mkdir -p "$SAVES_PATH/$EMU_TAG" 11 | HOME="$USERDATA_PATH" 12 | cd "$HOME" 13 | picoarch "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" LCD &> "$LOGS_PATH/$EMU_TAG.txt" 14 | -------------------------------------------------------------------------------- /skeleton/.system/paks/Emus/MD.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EMU_EXE=picodrive 4 | 5 | #////////////////////////////// 6 | 7 | EMU_TAG=$(basename "$(dirname "$0")" .pak) 8 | ROM="$1" 9 | mkdir -p "$BIOS_PATH/$EMU_TAG" 10 | mkdir -p "$SAVES_PATH/$EMU_TAG" 11 | HOME="$USERDATA_PATH" 12 | cd "$HOME" 13 | picoarch "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" &> "$LOGS_PATH/$EMU_TAG.txt" 14 | -------------------------------------------------------------------------------- /skeleton/.system/paks/Emus/PS.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EMU_EXE=pcsx_rearmed 4 | 5 | ############################### 6 | 7 | EMU_TAG=$(basename "$(dirname "$0")" .pak) 8 | ROM="$1" 9 | mkdir -p "$BIOS_PATH/$EMU_TAG" 10 | mkdir -p "$SAVES_PATH/$EMU_TAG" 11 | HOME="$USERDATA_PATH" 12 | cd "$HOME" 13 | picoarch "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" &> "$LOGS_PATH/$EMU_TAG.txt" 14 | -------------------------------------------------------------------------------- /skeleton/.system/paks/Emus/SFC.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EMU_EXE=snes9x2005_plus 4 | 5 | ############################### 6 | 7 | EMU_TAG=$(basename "$(dirname "$0")" .pak) 8 | ROM="$1" 9 | mkdir -p "$BIOS_PATH/$EMU_TAG" 10 | mkdir -p "$SAVES_PATH/$EMU_TAG" 11 | HOME="$USERDATA_PATH" 12 | cd "$HOME" 13 | picoarch "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" &> "$LOGS_PATH/$EMU_TAG.txt" 14 | -------------------------------------------------------------------------------- /skeleton/.system/paks/MiniUI.pak/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # MiniUI.pak 3 | 4 | /mnt/SDCARD/.system/bin/blank 5 | 6 | # init backlight 7 | echo 0 > /sys/class/pwm/pwmchip0/export 8 | echo 800 > /sys/class/pwm/pwmchip0/pwm0/period 9 | echo 6 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle 10 | echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable 11 | 12 | # init lcd 13 | cat /proc/ls 14 | sleep 0.5 15 | 16 | # init charger detection 17 | if [ ! -f /sys/devices/gpiochip0/gpio/gpio59/direction ]; then 18 | echo 59 > /sys/class/gpio/export 19 | echo in > /sys/devices/gpiochip0/gpio/gpio59/direction 20 | fi 21 | 22 | export SDCARD_PATH=/mnt/SDCARD 23 | export BIOS_PATH=/mnt/SDCARD/Bios 24 | export ROMS_PATH=/mnt/SDCARD/Roms 25 | export SAVES_PATH=/mnt/SDCARD/Saves 26 | export USERDATA_PATH=/mnt/SDCARD/.userdata 27 | export LOGS_PATH=/mnt/SDCARD/.userdata/logs 28 | export CORES_PATH=/mnt/SDCARD/.system/cores 29 | export RES_PATH=/mnt/SDCARD/.system/res 30 | export DATETIME_PATH=$USERDATA_PATH/.miniui/datetime.txt # used by bin/shutdown 31 | 32 | # killall tee # NOTE: killing tee is somehow responsible for audioserver crashes 33 | rm -f "$SDCARD_PATH/update.log" 34 | 35 | export LD_LIBRARY_PATH="/mnt/SDCARD/.system/lib:$LD_LIBRARY_PATH" 36 | export PATH="/mnt/SDCARD/.system/bin:$PATH" 37 | 38 | # NOTE: could cause performance issues on more demanding cores...maybe? 39 | if [ -f /customer/lib/libpadsp.so ]; then 40 | LD_PRELOAD=as_preload.so audioserver.mod & 41 | export LD_PRELOAD=libpadsp.so 42 | fi 43 | 44 | lumon & # adjust lcd luma and saturation 45 | 46 | CHARGING=`/customer/app/axp_test | awk -F'[,: {}]+' '{print $7}'` 47 | if [ "$CHARGING" == "3" ]; then 48 | batmon 49 | fi 50 | 51 | keymon & 52 | 53 | mkdir -p "$LOGS_PATH" 54 | mkdir -p "$USERDATA_PATH/.mmenu" 55 | mkdir -p "$USERDATA_PATH/.miniui" 56 | 57 | # init datetime 58 | if [ -f "$DATETIME_PATH" ]; then 59 | DATETIME=`cat "$DATETIME_PATH"` 60 | date +'%F %T' -s "$DATETIME" 61 | DATETIME=`date +'%s'` 62 | DATETIME=$((DATETIME + 6 * 60 * 60)) 63 | date -s "@$DATETIME" 64 | fi 65 | 66 | AUTO_PATH=$USERDATA_PATH/auto.sh 67 | if [ -f "$AUTO_PATH" ]; then 68 | "$AUTO_PATH" 69 | fi 70 | 71 | cd $(dirname "$0") 72 | 73 | EXEC_PATH=/tmp/miniui_exec 74 | touch "$EXEC_PATH" && sync 75 | 76 | MIYOO_VERSION=`/etc/fw_printenv miyoo_version` 77 | export MIYOO_VERSION=${MIYOO_VERSION#miyoo_version=} 78 | 79 | # Battery level debug info 80 | ls /customer/app > "$USERDATA_PATH/.miniui/app_contents.txt" 81 | /customer/app/axp_test > "$USERDATA_PATH/.miniui/axp_result.txt" 82 | 83 | CPU_PATH=/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor 84 | while [ -f "$EXEC_PATH" ]; do 85 | echo ondemand > "$CPU_PATH" 86 | 87 | ./MiniUI &> "$LOGS_PATH/MiniUI.txt" 88 | 89 | echo `date +'%F %T'` > "$DATETIME_PATH" 90 | echo performance > "$CPU_PATH" 91 | sync 92 | 93 | NEXT="/tmp/next" 94 | if [ -f $NEXT ]; then 95 | CMD=`cat $NEXT` 96 | eval $CMD 97 | rm -f $NEXT 98 | if [ -f "/tmp/using-swap" ]; then 99 | swapoff $USERDATA_PATH/swapfile 100 | rm -f "/tmp/using-swap" 101 | fi 102 | 103 | echo `date +'%F %T'` > "$DATETIME_PATH" 104 | sync 105 | fi 106 | done 107 | 108 | shutdown # just in case 109 | -------------------------------------------------------------------------------- /skeleton/.system/res/BPreplayBold-unhinted.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/BPreplayBold-unhinted.otf -------------------------------------------------------------------------------- /skeleton/.system/res/arrow-highlighted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/arrow-highlighted.png -------------------------------------------------------------------------------- /skeleton/.system/res/arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/arrow.png -------------------------------------------------------------------------------- /skeleton/.system/res/bad-battery-fill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/bad-battery-fill.png -------------------------------------------------------------------------------- /skeleton/.system/res/bad-battery-line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/bad-battery-line.png -------------------------------------------------------------------------------- /skeleton/.system/res/battery-charging.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/battery-charging.png -------------------------------------------------------------------------------- /skeleton/.system/res/battery-fill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/battery-fill.png -------------------------------------------------------------------------------- /skeleton/.system/res/battery-line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/battery-line.png -------------------------------------------------------------------------------- /skeleton/.system/res/battery-sdl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/battery-sdl.png -------------------------------------------------------------------------------- /skeleton/.system/res/bg-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/bg-black.png -------------------------------------------------------------------------------- /skeleton/.system/res/bg-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/bg-white.png -------------------------------------------------------------------------------- /skeleton/.system/res/btn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/btn.png -------------------------------------------------------------------------------- /skeleton/.system/res/charging-union.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/charging-union.png -------------------------------------------------------------------------------- /skeleton/.system/res/charging.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/charging.png -------------------------------------------------------------------------------- /skeleton/.system/res/confirm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/confirm.png -------------------------------------------------------------------------------- /skeleton/.system/res/digits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/digits.png -------------------------------------------------------------------------------- /skeleton/.system/res/logo-union.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/logo-union.png -------------------------------------------------------------------------------- /skeleton/.system/res/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/logo.png -------------------------------------------------------------------------------- /skeleton/.system/res/okay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/okay.png -------------------------------------------------------------------------------- /skeleton/.system/res/progress-bar-empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/progress-bar-empty.png -------------------------------------------------------------------------------- /skeleton/.system/res/progress-bar-full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/progress-bar-full.png -------------------------------------------------------------------------------- /skeleton/.system/res/rule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/rule.png -------------------------------------------------------------------------------- /skeleton/.system/res/settings-bar-empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/settings-bar-empty.png -------------------------------------------------------------------------------- /skeleton/.system/res/settings-bar-full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/settings-bar-full.png -------------------------------------------------------------------------------- /skeleton/.system/res/settings-brightness.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/settings-brightness.png -------------------------------------------------------------------------------- /skeleton/.system/res/settings-mute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/settings-mute.png -------------------------------------------------------------------------------- /skeleton/.system/res/settings-volume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/settings-volume.png -------------------------------------------------------------------------------- /skeleton/.system/res/slot-dot-selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/slot-dot-selected.png -------------------------------------------------------------------------------- /skeleton/.system/res/slot-dots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/slot-dots.png -------------------------------------------------------------------------------- /skeleton/.system/res/slot-overlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/.system/res/slot-overlay.png -------------------------------------------------------------------------------- /skeleton/.tmp_update/updater: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # install 4 | if [ -d "/mnt/SDCARD/miyoo354" ] ; then 5 | exit 0 6 | fi 7 | 8 | # or launch (and keep launched) 9 | LAUNCH_PATH="/mnt/SDCARD/.system/paks/MiniUI.pak/launch.sh" 10 | while [ -f "$LAUNCH_PATH" ] ; do 11 | "$LAUNCH_PATH" 12 | done 13 | 14 | reboot # under no circumstances should stock be allowed to touch this card 15 | -------------------------------------------------------------------------------- /skeleton/Bios/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Bios/.keep -------------------------------------------------------------------------------- /skeleton/Bios/FC/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Bios/FC/.keep -------------------------------------------------------------------------------- /skeleton/Bios/GB/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Bios/GB/.keep -------------------------------------------------------------------------------- /skeleton/Bios/GBA/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Bios/GBA/.keep -------------------------------------------------------------------------------- /skeleton/Bios/GBC/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Bios/GBC/.keep -------------------------------------------------------------------------------- /skeleton/Bios/MD/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Bios/MD/.keep -------------------------------------------------------------------------------- /skeleton/Bios/PS/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Bios/PS/.keep -------------------------------------------------------------------------------- /skeleton/Bios/SFC/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Bios/SFC/.keep -------------------------------------------------------------------------------- /skeleton/README.txt: -------------------------------------------------------------------------------- 1 | DotUI is a minimal launcher for the Miyoo Mini Plus, adapted from Shaun Inman's MiniUI 2 | 3 | DotUI Source: https://github.com/Xpndable/DotUI 4 | 5 | MiniUI Source: https://github.com/shauninman/MiniUI 6 | 7 | ---------------------------------------- 8 | Features 9 | 10 | - No settings or configuration 11 | - Simple launcher, simple SD card 12 | - Automatically hides extension 13 | and region/version cruft in 14 | display names 15 | - Consistent in-emulator menu with 16 | quick access to save states, disc 17 | changing, and emulator options 18 | - Automatically sleeps after 30 seconds 19 | or press POWER to sleep (and wake) 20 | - Automatically powers off while asleep 21 | after two minutes or hold POWER for 22 | one second 23 | - Automatically resumes right where 24 | you left off if powered off while 25 | in-game, manually or while asleep 26 | - Resume from manually created, last 27 | used save state by pressing X in 28 | the launcher instead of A 29 | - Streamlined emulator frontend 30 | (picoarch + libretro cores) 31 | 32 | ---------------------------------------- 33 | Install 34 | 35 | DotUI works on all known versions of the official firmware, no need to upgrade. Save yourself a headache. 36 | 37 | Copy the contents of this archive to the root of a fresh FAT32 formatted SD card. Don't forget the "miyoo354" folder. Insert your SD card into the device and power it on. DotUI will install automatically and be ready to go in about 10 seconds. 38 | 39 | ---------------------------------------- 40 | Update 41 | 42 | To install an update copy just the "miyoo354" folder to the root of your SD card. Insert your SD card into the device and power it on. DotUI will update automatically and be ready to go in about 10 seconds. 43 | 44 | ---------------------------------------- 45 | Shortcuts 46 | 47 | Reduce/increase brightness: 48 | START + L or R 49 | 50 | Reduce/increase volume: 51 | Volume Buttons 52 | (To show volume level, hold SELECT in menus) 53 | 54 | Force power off (in case of hangs): 55 | MENU + POWER 56 | 57 | ---------------------------------------- 58 | Roms 59 | 60 | Included in this zip is a Roms folder containing folders for each console DotUI currently supports. You can rename these folders but you must keep the uppercase tag name in parentheses in order to retain the mapping to the correct emulator (eg. "Nintendo Entertainment System (FC)" could be renamed to "Nintendo (FC)", "NES (FC)", or "Famicom (FC)"). 61 | 62 | You should probably preload these folders with roms and copy each one to the Roms folder on your SD card before installing. Or not, I'm not the boss of you. 63 | 64 | When one or more folder share the same display name (eg. "Game Boy Advance (GBA)" and "Game Boy Advance (MGBA)") they will be combined into a single menu item containing the roms from both folders (continuing the previous example, "Game Boy Advance"). This allows opening specific roms with an alternate pak. 65 | 66 | ---------------------------------------- 67 | Bios 68 | 69 | Some emulators require or perform much better with official bios. DotUI is strictly BYOB. Place the bios for each system in a folder that matches the tag in the corresponding Roms folder name (eg. bios for "Sony PlayStation (PS)" roms goes in "/Bios/PS/"), 70 | 71 | Bios file names are case-sensitive: 72 | 73 | FC: disksys.rom 74 | GB: gb_bios.bin 75 | GBA: gba_bios.bin 76 | GBC: gbc_bios.bin 77 | PS: psxonpsp660.bin 78 | 79 | ---------------------------------------- 80 | Disc-based games 81 | 82 | To streamline launching multi-file disc-based games with DotUI place your bin/cue (and/or iso/wav files) in a folder with the same name as the cue file. DotUI will automatically launch the cue file instead of navigating into the folder when selected, eg. 83 | 84 | Harmful Park (English v1.0)/ 85 | Harmful Park (English v1.0).bin 86 | Harmful Park (English v1.0).cue 87 | 88 | For multi-disc games, put all the files for all the discs in a single folder and create an m3u file (just a text file containing the relative path to each disc's cue file on a separate line) with the same name as the folder. Instead of showing the entire messy contents of the folder, DotUI will launch the appropriate cue file, eg. For a Policenauts folder structured like this: 89 | 90 | Policenauts (English v1.0)/ 91 | Policenauts (English v1.0).m3u 92 | Policenauts (Japan) (Disc 1).bin 93 | Policenauts (Japan) (Disc 1).cue 94 | Policenauts (Japan) (Disc 2).bin 95 | Policenauts (Japan) (Disc 2).cue 96 | 97 | the m3u file would contain just: 98 | 99 | Policenauts (Japan) (Disc 1).cue 100 | Policenauts (Japan) (Disc 2).cue 101 | 102 | DotUI also reportedly supports chd files and official pbp files (multi-disc pbp files larger than 2GB are not supported). 103 | 104 | ---------------------------------------- 105 | Collections 106 | 107 | A collection is just a text file containing an ordered list of full paths to rom, cue, or m3u files. These text files live in the Collections folder at the root of your SD card, eg. "/Collections/Metroid series.txt" might look like this: 108 | 109 | /Roms/GBA/Metroid Zero Mission.gba 110 | /Roms/GB/Metroid II.gb 111 | /Roms/SNES (SFC)/Super Metroid.sfc 112 | /Roms/GBA/Metroid Fusion.gba 113 | 114 | ---------------------------------------- 115 | Advanced 116 | 117 | DotUI can automatically run a user-authored shell script on boot (eg. for starting daemons like screenshots). Just place a file named "auto.sh" to "/.userdata/". 118 | 119 | Just keep in mind, syntax errors in auto.sh may prevent DotUI from launching which will allow the stock system to modify your SD card, polluting the root of the card and your Roms folder with unnecessary subfolders, and removing the hook that allows DotUI to boot. If this happens you will need to reinstall DotUI (well, really just its "./tmp_update/" folder). No userdata is lost when this happens, it's just kinda annoying. 120 | 121 | ---------------------------------------- 122 | DotUI Thanks 123 | 124 | Huge thanks to Shaun Inman from whom this code base is ported for the Miyoo Mini Plus and will be adapted to suit over time. His efforts on MinUI and MiniUI are monumental for the entire community, and we would be poorer without his efforts. 125 | 126 | Check out Shaun's repos: https://github.com/shauninman 127 | 128 | ---------------------------------------- 129 | MiniUI Thanks (from Shaun) 130 | 131 | To eggs for his example middleware code, countless bug fixes, neon scalers, and patience in the face of my endless questions. 132 | 133 | Check out eggs' releases: https://www.dropbox.com/sh/hqcsr1h1d7f8nr3/AABtSOygIX_e4mio3rkLetWTa 134 | 135 | To neonloop for putting together the Trimui toolchain from which I learned everything I know about docker and buildroot and is the basis for the Miyoo Mini toolchain I put together, and for picoarch, without which I might have given up entirely. 136 | 137 | Check out neonloop's repos: https://git.crowdedwood.com 138 | 139 | To Jim Gray, Totofaki, and the entire Onion crew for taking a joke, running with it, and turning a stop-gap into a beloved launcher and community, it's been amazing to watch. 140 | 141 | Check out Onion for a more full-bodied Miyoo Mini experience: https://github.com/OnionUI/Onion/ 142 | 143 | To Evil_Rob for gently and regularly nudging me towards a better understanding of how all the Linux-y bits (are supposed to) work under the hood. 144 | 145 | To the creators of the Trimui Model S and Miyoo Mini for making some nice (now hard to find) hardware and simple interfaces in a market crowded with bloated, ugly front ends that require entirely too much work to setup as intended. 146 | 147 | And to the entire Retro Game Handhelds Miyoo Mini and dev Discord community for their enthusiasm and encouragement. 148 | 149 | Checkout the channel on the Retro Game Handhelds Discord: https://discord.com/channels/529983248114122762/891336865540620338 150 | -------------------------------------------------------------------------------- /skeleton/Roms/Game Boy (GB)/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Roms/Game Boy (GB)/.keep -------------------------------------------------------------------------------- /skeleton/Roms/Game Boy Advance (GBA)/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Roms/Game Boy Advance (GBA)/.keep -------------------------------------------------------------------------------- /skeleton/Roms/Game Boy Color (GBC)/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Roms/Game Boy Color (GBC)/.keep -------------------------------------------------------------------------------- /skeleton/Roms/Nintendo Entertainment System (FC)/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Roms/Nintendo Entertainment System (FC)/.keep -------------------------------------------------------------------------------- /skeleton/Roms/Sega Genesis (MD)/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Roms/Sega Genesis (MD)/.keep -------------------------------------------------------------------------------- /skeleton/Roms/Sony PlayStation (PS)/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Roms/Sony PlayStation (PS)/.keep -------------------------------------------------------------------------------- /skeleton/Roms/Super Nintendo Entertainment System (SFC)/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Roms/Super Nintendo Entertainment System (SFC)/.keep -------------------------------------------------------------------------------- /skeleton/Saves/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Saves/.keep -------------------------------------------------------------------------------- /skeleton/Saves/FC/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Saves/FC/.keep -------------------------------------------------------------------------------- /skeleton/Saves/GB/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Saves/GB/.keep -------------------------------------------------------------------------------- /skeleton/Saves/GBA/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Saves/GBA/.keep -------------------------------------------------------------------------------- /skeleton/Saves/GBC/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Saves/GBC/.keep -------------------------------------------------------------------------------- /skeleton/Saves/MD/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Saves/MD/.keep -------------------------------------------------------------------------------- /skeleton/Saves/PS/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Saves/PS/.keep -------------------------------------------------------------------------------- /skeleton/Saves/SFC/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/skeleton/Saves/SFC/.keep -------------------------------------------------------------------------------- /skeleton/miyoo354/app/MainUI: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # { 4 | 5 | DIR=/mnt/SDCARD/miyoo354/app 6 | cd "$DIR" 7 | 8 | export LD_LIBRARY_PATH=/lib:/config/lib:/customer/lib 9 | 10 | # update bootcmd if necessary 11 | contains() { [ -z "${2##*$1*}" ]; } 12 | MIYOO_VERSION=`/etc/fw_printenv miyoo_version` 13 | MIYOO_VERSION=${MIYOO_VERSION#miyoo_version=} 14 | SUPPORTED_VERSION="202205010000" # date after latest known version 15 | if [ $MIYOO_VERSION -lt $SUPPORTED_VERSION ]; then 16 | OLD_CMD=`/etc/fw_printenv bootcmd` 17 | NEW_CMD="gpio output 85 1; bootlogo 0 0 0 0 0; mw 1f001cc0 11; gpio out 8 0; sf probe 0;sf read 0x22000000 \${sf_kernel_start} \${sf_kernel_size}; gpio out 8 1; gpio output 4 1; bootm 0x22000000" 18 | if contains "sleepms" "$OLD_CMD"; then 19 | ./say "Updating bootcmd" 20 | /etc/fw_setenv bootcmd $NEW_CMD 21 | sleep 1 22 | fi 23 | fi 24 | 25 | SYSTEM_PATH=/mnt/SDCARD/.system 26 | OLD_SYSTEM_PATH=/mnt/SDCARD/.system_old 27 | 28 | # figure out what we're doing here 29 | if [ -d "$SYSTEM_PATH" ]; then 30 | rm -rf "/mnt/SDCARD/.tmp_update" 31 | mv "$SYSTEM_PATH" "$OLD_SYSTEM_PATH" 32 | VERB=Updating 33 | NOUN=Update 34 | JUST_UPDATED=1 35 | else 36 | VERB=Installing 37 | NOUN=Installation 38 | JUST_INSTALLED=1 39 | fi 40 | 41 | # then do it 42 | ./blank 43 | ./say "$VERB DotUI" 44 | unzip -o "/mnt/SDCARD/miyoo354/app/MiniUI.zip" -d "/mnt/SDCARD" 45 | 46 | # post-install 47 | POST_INSTALL=/mnt/SDCARD/.system/post-install.sh 48 | if [ -f "$POST_INSTALL" ]; then 49 | if [ -n "$JUST_INSTALLED" ]; then 50 | "$POST_INSTALL" 51 | fi 52 | rm -f "$POST_INSTALL" 53 | fi 54 | 55 | # post-update 56 | POST_UPDATE=/mnt/SDCARD/.system/post-update.sh 57 | if [ -f "$POST_UPDATE" ]; then 58 | if [ -n "$JUST_UPDATED" ]; then 59 | "$POST_UPDATE" 60 | fi 61 | rm -f "$POST_UPDATE" 62 | fi 63 | 64 | # we're done here 65 | ./blank 66 | ./say "$NOUN complete" 67 | 68 | rm -rf "$OLD_SYSTEM_PATH" 69 | rm -rf /mnt/SDCARD/miyoo354 70 | 71 | # } > /mnt/SDCARD/miyoo.txt 2>&1 72 | 73 | # let's do this 74 | /mnt/SDCARD/.tmp_update/updater 75 | -------------------------------------------------------------------------------- /skeleton/miyoo354/app/keymon.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | exit 0 -------------------------------------------------------------------------------- /src/batmon/batmon.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | static int is_charging = 1; 13 | static int screen_on = 0; 14 | static unsigned long screen_start; 15 | void screenOn(void) { 16 | screen_start = SDL_GetTicks(); 17 | if (!screen_on) system("echo 100 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle"); 18 | screen_on = 1; 19 | } 20 | void screenOff(void) { 21 | system("echo 0 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle"); 22 | screen_on = 0; 23 | } 24 | void checkCharging(void) { 25 | // Code adapted from OnionOS 26 | char *cmd = "cd /customer/app/ ; ./axp_test"; 27 | int batJsonSize = 100; 28 | char buf[batJsonSize]; 29 | int charge_number; 30 | 31 | FILE *fp; 32 | fp = popen(cmd, "r"); 33 | if (fgets(buf, batJsonSize, fp) != NULL) { 34 | sscanf(buf, "{\"battery\":%*d, \"voltage\":%*d, \"charging\":%d}", &charge_number); 35 | is_charging = (charge_number==3); 36 | } 37 | pclose(fp); 38 | } 39 | static pthread_t charging_pt; 40 | void* chargingThread(void* arg) { 41 | while (1) { 42 | sleep(1); 43 | checkCharging(); 44 | } 45 | } 46 | 47 | static int launch = 0; 48 | static int input_fd; 49 | static pthread_t input_pt; 50 | void* inputThread(void* arg) { 51 | struct input_event event; 52 | while (read(input_fd, &event, sizeof(event))==sizeof(event)) { 53 | if (event.type!=EV_KEY || event.value>1) continue; 54 | if (event.type==EV_KEY) screenOn(); 55 | if (event.code==KEY_POWER) launch = 1; 56 | } 57 | } 58 | 59 | int main(void) { 60 | int fb0_fd = open("/dev/fb0", O_RDWR); 61 | struct fb_var_screeninfo vinfo; 62 | ioctl(fb0_fd, FBIOGET_VSCREENINFO, &vinfo); 63 | int map_size = vinfo.xres * vinfo.yres * (vinfo.bits_per_pixel / 8); // 640x480x4 64 | char* fb0_map = (char*)mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb0_fd, 0); 65 | 66 | memset(fb0_map, 0, map_size); // clear screen 67 | 68 | char charging_path[128]; 69 | sprintf(charging_path, "%s/charging.png", getenv("RES_PATH")); 70 | SDL_Surface* img = IMG_Load(charging_path); // 24-bit opaque png 71 | 72 | uint8_t* dst = (uint8_t*)fb0_map; // rgba 73 | uint8_t* src = (uint8_t*)img->pixels; // bgr 74 | src += ((img->h * img->w) - 1) * 3; 75 | for (int y=0; yh; y++) { 76 | for (int x=0; xw; x++) { 77 | *(dst+0) = *(src+2); // r 78 | *(dst+1) = *(src+1); // g 79 | *(dst+2) = *(src+0); // b 80 | *(dst+3) = 0xf; // alpha 81 | dst += 4; 82 | src -= 3; 83 | } 84 | } 85 | SDL_FreeSurface(img); 86 | 87 | screenOn(); 88 | 89 | input_fd = open("/dev/input/event0", O_RDONLY); 90 | pthread_create(&input_pt, NULL, &inputThread, NULL); 91 | 92 | pthread_create(&charging_pt, NULL, &chargingThread, NULL); 93 | 94 | while (!launch && is_charging) { 95 | if (screen_on && SDL_GetTicks()-screen_start>=3000) screenOff(); 96 | } 97 | 98 | close(input_fd); 99 | 100 | pthread_cancel(input_pt); 101 | pthread_join(input_pt, NULL); 102 | 103 | pthread_cancel(charging_pt); 104 | pthread_join(charging_pt, NULL); 105 | 106 | munmap(fb0_map, map_size); 107 | close(fb0_fd); 108 | 109 | if (!launch) { 110 | system("shutdown"); 111 | while (1) pause(); 112 | } 113 | 114 | return EXIT_SUCCESS; 115 | } 116 | -------------------------------------------------------------------------------- /src/batmon/makefile: -------------------------------------------------------------------------------- 1 | ifeq (,$(CROSS_COMPILE)) 2 | $(error missing CROSS_COMPILE for this toolchain) 3 | endif 4 | 5 | TARGET = batmon 6 | 7 | CC = $(CROSS_COMPILE)gcc 8 | CFLAGS = -marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7ve 9 | LDFLAGS = -lSDL -lSDL_image -lpthread 10 | 11 | all: 12 | $(CC) $(TARGET).c -o $(TARGET) $(CFLAGS) $(LDFLAGS) 13 | clean: 14 | rm -f $(TARGET) -------------------------------------------------------------------------------- /src/blank/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main(int argc , char* argv[]) { 11 | // clear screen 12 | int fb0_fd = open("/dev/fb0", O_RDWR); 13 | struct fb_var_screeninfo vinfo; 14 | ioctl(fb0_fd, FBIOGET_VSCREENINFO, &vinfo); 15 | int map_size = vinfo.xres * vinfo.yres * (vinfo.bits_per_pixel / 8); // 640x480x4 16 | char* fb0_map = (char*)mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb0_fd, 0); 17 | memset(fb0_map, 0, map_size); 18 | munmap(fb0_map, map_size); 19 | close(fb0_fd); 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /src/blank/makefile: -------------------------------------------------------------------------------- 1 | ifeq (,$(CROSS_COMPILE)) 2 | $(error missing CROSS_COMPILE for this toolchain) 3 | endif 4 | 5 | TARGET = blank 6 | 7 | CC = $(CROSS_COMPILE)gcc 8 | CFLAGS = -marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7ve 9 | LDFLAGS = 10 | 11 | all: 12 | $(CC) main.c -o $(TARGET) $(CFLAGS) $(LDFLAGS) 13 | clean: 14 | rm -f $(TARGET) -------------------------------------------------------------------------------- /src/clock/main.c: -------------------------------------------------------------------------------- 1 | // loosely based on https://github.com/gameblabla/clock_sdl_app 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int argc , char* argv[]) { 10 | SDL_Init(SDL_INIT_VIDEO); 11 | SDL_ShowCursor(0); 12 | 13 | SDL_Surface* screen = SDL_SetVideoMode(640, 480, 16, SDL_HWSURFACE | SDL_DOUBLEBUF); 14 | 15 | #define RES_PATH "/mnt/SDCARD/.system/res/" 16 | SDL_Surface* confirm = IMG_Load(RES_PATH "confirm.png"); 17 | SDL_Surface* digits = IMG_Load(RES_PATH "digits.png"); // 20x32 18 | 19 | SDL_Event event; 20 | int quit = 0; 21 | int save_changes = 0; 22 | int select_cursor = 0; 23 | 24 | time_t t = time(NULL); 25 | struct tm tm = *localtime(&t); 26 | 27 | uint32_t day_selected = tm.tm_mday; 28 | uint32_t month_selected = tm.tm_mon + 1; 29 | uint32_t year_selected = tm.tm_year + 1900; 30 | uint32_t hour_selected = tm.tm_hour; 31 | uint32_t minute_selected = tm.tm_min; 32 | uint32_t seconds_selected = tm.tm_sec; 33 | 34 | uint32_t white = SDL_MapRGB(screen->format, 255,255,255); 35 | 36 | #define kSlash 10 37 | #define kColon 11 38 | #define kBar 12 39 | int blit(int i, int x, int y) { 40 | SDL_BlitSurface(digits, &(SDL_Rect){i*20,0,20,32}, screen, &(SDL_Rect){x,y}); 41 | return x + 20; 42 | } 43 | void blitBar(int x, int y, int len) { 44 | int w = len * 20; 45 | SDL_FillRect(screen, &(SDL_Rect){x,y,w,5}, white); 46 | SDL_BlitSurface(digits, &(SDL_Rect){kBar*20,0,3,5}, screen, &(SDL_Rect){x,y}); 47 | SDL_BlitSurface(digits, &(SDL_Rect){(kBar*20)+2,0,3,5}, screen, &(SDL_Rect){x+w-3,y}); 48 | } 49 | int blitNumber(int num, int x, int y) { 50 | int n; 51 | if (num > 999) { 52 | n = num / 1000; 53 | num -= n * 1000; 54 | x = blit(n, x,y); 55 | 56 | n = num / 100; 57 | num -= n * 100; 58 | x = blit(n, x,y); 59 | } 60 | n = num / 10; 61 | num -= n * 10; 62 | x = blit(n, x,y); 63 | 64 | n = num; 65 | x = blit(n, x,y); 66 | 67 | return x; 68 | } 69 | void validate(void) { 70 | // leap year 71 | uint32_t february_days = 28; 72 | if ( ((year_selected % 4 == 0) && (year_selected % 100 != 0)) || (year_selected % 400 == 0)) february_days = 29; 73 | 74 | // day 75 | if (day_selected < 1) day_selected = 1; 76 | if (month_selected > 12) month_selected = 12; 77 | else if (month_selected < 1) month_selected = 1; 78 | 79 | if (year_selected > 2100) year_selected = 2100; 80 | else if (year_selected < 1970) year_selected = 1970; 81 | 82 | switch(month_selected) 83 | { 84 | case 2: 85 | if (day_selected > february_days) day_selected = february_days; 86 | break; 87 | case 4: 88 | case 6: 89 | case 9: 90 | case 11: 91 | if (day_selected > 30) day_selected = 30; 92 | break; 93 | default: 94 | if (day_selected > 31) day_selected = 31; 95 | break; 96 | } 97 | 98 | // time 99 | if (hour_selected > 23) hour_selected = 0; 100 | if (minute_selected > 59) minute_selected = 0; 101 | if (seconds_selected > 59) seconds_selected = 0; 102 | } 103 | 104 | SDL_EnableKeyRepeat(300,100); 105 | 106 | while(!quit) { 107 | unsigned long frame_start = SDL_GetTicks(); 108 | 109 | while (SDL_PollEvent(&event)) { 110 | switch(event.type) { 111 | case SDL_KEYDOWN: 112 | switch(event.key.keysym.sym) { 113 | case SDLK_UP: 114 | switch(select_cursor) { 115 | case 0: 116 | year_selected++; 117 | break; 118 | case 1: 119 | month_selected++; 120 | break; 121 | case 2: 122 | day_selected++; 123 | break; 124 | case 3: 125 | hour_selected++; 126 | break; 127 | case 4: 128 | minute_selected++; 129 | break; 130 | case 5: 131 | seconds_selected++; 132 | break; 133 | } 134 | break; 135 | case SDLK_DOWN: 136 | switch(select_cursor) { 137 | case 0: 138 | year_selected--; 139 | break; 140 | case 1: 141 | month_selected--; 142 | break; 143 | case 2: 144 | day_selected--; 145 | break; 146 | case 3: 147 | hour_selected--; 148 | break; 149 | case 4: 150 | minute_selected--; 151 | break; 152 | case 5: 153 | seconds_selected--; 154 | break; 155 | } 156 | break; 157 | case SDLK_LEFT: 158 | select_cursor--; 159 | if (select_cursor < 0) select_cursor += 6; 160 | break; 161 | case SDLK_RIGHT: 162 | select_cursor++; 163 | if (select_cursor > 5) select_cursor -= 6; 164 | break; 165 | case SDLK_SPACE: // A 166 | save_changes = 1; 167 | quit = 1; 168 | break; 169 | case SDLK_LCTRL: // B 170 | quit = 1; 171 | break; 172 | default: 173 | break; 174 | } 175 | break; 176 | case SDL_QUIT: 177 | quit = 1; 178 | break; 179 | } 180 | } 181 | 182 | validate(); 183 | 184 | // render 185 | SDL_BlitSurface(confirm, NULL, screen, NULL); 186 | 187 | // datetime 188 | int x = 130; 189 | int y = 185; 190 | 191 | x = blitNumber(year_selected, x,y); 192 | x = blit(kSlash, x,y); 193 | x = blitNumber(month_selected, x,y); 194 | x = blit(kSlash, x,y); 195 | x = blitNumber(day_selected, x,y); 196 | x += 20; // space 197 | x = blitNumber(hour_selected, x,y); 198 | x = blit(kColon, x,y); 199 | x = blitNumber(minute_selected, x,y); 200 | x = blit(kColon, x,y); 201 | x = blitNumber(seconds_selected, x,y); 202 | 203 | // cursor 204 | x = 130; 205 | y = 222; 206 | if (select_cursor>0) { 207 | x += 100; // YYYY/ 208 | x += (select_cursor - 1) * 60; 209 | } 210 | blitBar(x,y, (select_cursor>0 ? 2 : 4)); 211 | 212 | SDL_Flip(screen); 213 | 214 | // slow down to 60fps 215 | unsigned long frame_duration = SDL_GetTicks() - frame_start; 216 | #define kTargetFrameDuration 17 217 | if (frame_duration 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "common.h" 12 | #include 13 | 14 | // TODO: move any functions not also used by libmmenu out of here 15 | // TODO: one wrinkle, functions that require static variables defined in here... 16 | 17 | // TODO: standardize function casing, eg. Object_methodName vs function_name vs functionName 18 | // NOTE: currently thinking it should be Object_methodName() and functionName() but instance->property_name and variable_name 19 | // NOTE: constants can be CONSTANT_NAME or kConstantName, not sure what distinguishes the two types... 20 | // NOTE: CONSTANT_NAME matches C and feels lower level, kConstantName is recognized by my IDE's C syntax coloring :sweat_smile: 21 | 22 | UnionScreen Screen = { 23 | .width = 640, 24 | .height = 480, 25 | 26 | .font = { 27 | .small_size = 24, 28 | .medium_size = 28, 29 | .large_size = 32, 30 | .small_oy = 8, 31 | .medium_oy = 10, 32 | .large_oy = 10, 33 | 34 | .shadow = { 35 | .ox = 2, 36 | .oy = 3, 37 | }, 38 | }, 39 | 40 | .button = { 41 | .size = 22*2, 42 | .text = { 43 | .oy = -2, 44 | .ox_A = 1, 45 | .ox_B = 2, 46 | .ox_X = 1, 47 | .ox_Y = 2, 48 | }, 49 | }, 50 | 51 | .pill = { 52 | .pad_width = 12, 53 | .text_oy = 4, 54 | }, 55 | 56 | .hint = { 57 | .ox = 6, 58 | .text_oy = 2, 59 | }, 60 | 61 | .settings = { 62 | .width = 292, 63 | .height = 52, 64 | .icon = { 65 | .ox = 12, 66 | .oy = 8, 67 | }, 68 | .bar = { 69 | .ox = 60, 70 | .oy = 22, 71 | }, 72 | }, 73 | 74 | .buttons = { 75 | .top = 422, 76 | .left = 16, 77 | .right = 20, 78 | .gutter = 16, 79 | }, 80 | 81 | .main = { 82 | .settings = { 83 | .x = 342, 84 | .y = 8, 85 | }, 86 | .battery = { 87 | .x = 600, 88 | .y = 18, 89 | }, 90 | .rule = { 91 | .top_y = 70, 92 | .bottom_y = 406, 93 | }, 94 | 95 | .logo = { 96 | .x = 20, 97 | .y = 20, 98 | }, 99 | .list = { 100 | .row_count = 5, 101 | .y = 76, 102 | .ox = 32, 103 | .oy = 8, 104 | .row_height = 64, 105 | .alt_ox = 64, // from right 106 | .alt_oy = 20, 107 | }, 108 | }, 109 | 110 | .menu = { 111 | .settings = { 112 | .x = 174, 113 | .y = 74, 114 | }, 115 | .battery = { 116 | .x = 606, 117 | .y = 10, 118 | }, 119 | .rule = { 120 | .top_y = 54, 121 | .bottom_y = 422, 122 | }, 123 | 124 | .buttons = { 125 | .top = 434, 126 | }, 127 | .slots = { 128 | .x = 400, 129 | .y = 394, 130 | .ox = 16, 131 | }, 132 | .disc = { 133 | .ox = 130, 134 | .oy = 8, 135 | }, 136 | .preview = { 137 | .x = 296, 138 | .y = 142, 139 | .width = 332, 140 | .height = 270, 141 | .inset = 6, 142 | }, 143 | 144 | .title = { 145 | .x = 48, 146 | .y = 6, 147 | .width = 544, 148 | }, 149 | .window = { 150 | .x = 12, 151 | .y = 142, 152 | .width = 280, 153 | .height = 270, 154 | }, 155 | .list = { 156 | .x = 28, 157 | .y = 152, 158 | .oy = 0, 159 | .line_height = 50, 160 | .row_height = 54, 161 | }, 162 | .arrow = { 163 | .ox = 12, // from right 164 | .oy = 14, 165 | }, 166 | 167 | .bar_height = 60, 168 | }, 169 | 170 | .body = { 171 | .line_height = 48, // paired with Screen.font.large_size 172 | }, 173 | }; 174 | 175 | UnionPaths Paths = { 176 | .rootDir = "/mnt/SDCARD", 177 | .resDir = "/mnt/SDCARD/.system/res", 178 | .paksDir = "/mnt/SDCARD/.system/paks", 179 | .userdataDir = "/mnt/SDCARD/.userdata", 180 | .romsDir = "/mnt/SDCARD/Roms", 181 | .recentPath = "/mnt/SDCARD/.userdata/.miniui/recent.txt", 182 | .fauxRecentDir = "/mnt/SDCARD/Recently Played", 183 | .collectionsDir = "/mnt/SDCARD/Collections", 184 | }; 185 | 186 | /////////////////////////////////////// 187 | 188 | struct ButtonState { 189 | int is_pressed; 190 | int just_pressed; 191 | int just_repeated; 192 | int just_released; 193 | }; 194 | static struct ButtonState buttons[kButtonCount]; 195 | 196 | void Input_reset(void) { 197 | // reset all 198 | for (int i=0; i=0 && strncasecmp(suf, str+offset, len)==0); 275 | } 276 | int exactMatch(char* str1, char* str2) { 277 | int len1 = strlen(str1); 278 | if (len1!=strlen(str2)) return 0; 279 | return (strncmp(str1,str2,len1)==0); 280 | } 281 | int hide(char* file_name) { 282 | return file_name[0]=='.'; 283 | } 284 | 285 | void getDisplayName(const char* in_name, char* out_name) { 286 | char* tmp; 287 | strcpy(out_name, in_name); 288 | 289 | // extract just the filename if necessary 290 | tmp = strrchr(in_name, '/'); 291 | if (tmp) strcpy(out_name, tmp+1); 292 | 293 | // remove extension 294 | tmp = strrchr(out_name, '.'); 295 | if (tmp && strlen(tmp)<=4) tmp[0] = '\0'; // 3 letter extension plus dot 296 | 297 | // remove trailing parens (round and square) 298 | char safe_name[256]; 299 | strcpy(safe_name,out_name); 300 | while ((tmp=strrchr(out_name, '('))!=NULL || (tmp=strrchr(out_name, '['))!=NULL) { 301 | if (tmp==out_name) break; 302 | tmp[0] = '\0'; 303 | tmp = out_name; 304 | } 305 | 306 | // make sure we haven't nuked the entire name 307 | if (out_name[0]=='\0') strcpy(out_name, safe_name); 308 | 309 | // remove trailing whitespace 310 | tmp = out_name + strlen(out_name) - 1; 311 | while(tmp>out_name && isspace((unsigned char)*tmp)) tmp--; 312 | tmp[1] = '\0'; 313 | } 314 | void getEmuName(const char* in_name, char* out_name) { 315 | char* tmp; 316 | strcpy(out_name, in_name); 317 | tmp = out_name; 318 | 319 | // extract just the Roms folder name if necessary 320 | if (prefixMatch(Paths.romsDir, tmp)) { 321 | tmp += strlen(Paths.romsDir) + 1; 322 | char* tmp2 = strchr(tmp, '/'); 323 | if (tmp2) tmp2[0] = '\0'; 324 | } 325 | 326 | // finally extract pak name from parenths if present 327 | tmp = strrchr(tmp, '('); 328 | if (tmp) { 329 | tmp += 1; 330 | strcpy(out_name, tmp); 331 | tmp = strchr(out_name,')'); 332 | tmp[0] = '\0'; 333 | } 334 | } 335 | 336 | void normalizeNewline(char* line) { 337 | int len = strlen(line); 338 | if (len>1 && line[len-1]=='\n' && line[len-2]=='\r') { // windows! 339 | line[len-2] = '\n'; 340 | line[len-1] = '\0'; 341 | } 342 | } 343 | void trimTrailingNewlines(char* line) { 344 | int len = strlen(line); 345 | while (len>0 && line[len-1]=='\n') { 346 | line[len-1] = '\0'; // trim newline 347 | len -= 1; 348 | } 349 | } 350 | 351 | /////////////////////////////////////// 352 | 353 | int exists(char* path) { 354 | return access(path, F_OK)==0; 355 | } 356 | void touch(char* path) { 357 | close(open(path, O_RDWR|O_CREAT, 0777)); 358 | } 359 | void putFile(char* path, char* contents) { 360 | FILE* file = fopen(path, "w"); 361 | if (file) { 362 | fputs(contents, file); 363 | fclose(file); 364 | } 365 | } 366 | void getFile(char* path, char* buffer, size_t buffer_size) { 367 | FILE *file = fopen(path, "r"); 368 | if (file) { 369 | fseek(file, 0L, SEEK_END); 370 | size_t size = ftell(file); 371 | if (size>buffer_size-1) size = buffer_size - 1; 372 | rewind(file); 373 | fread(buffer, sizeof(char), size, file); 374 | fclose(file); 375 | buffer[size] = '\0'; 376 | } 377 | } 378 | int getInt(char* path) { 379 | int i = 0; 380 | FILE *file = fopen(path, "r"); 381 | if (file!=NULL) { 382 | fscanf(file, "%i", &i); 383 | fclose(file); 384 | } 385 | return i; 386 | } 387 | void putInt(char* path, int value) { 388 | char buffer[8]; 389 | sprintf(buffer, "%d", value); 390 | putFile(path, buffer); 391 | } 392 | 393 | /////////////////////////////////////// 394 | 395 | static TTF_Font* font_s; 396 | static TTF_Font* font_m; 397 | static TTF_Font* font_l; 398 | static SDL_Surface* screen; // video surface 399 | static SDL_Surface* rule; 400 | static SDL_Surface* button; 401 | static SDL_Surface* slot_overlay; 402 | static SDL_Surface* bg_white; 403 | static SDL_Surface* bg_black; 404 | static SDL_Surface* settings_bar_full; 405 | static SDL_Surface* settings_bar_empty; 406 | static SDL_Surface* settings_brightness; 407 | static SDL_Surface* settings_volume; 408 | static SDL_Surface* settings_mute; 409 | 410 | static SDL_Color pink = {PINK_TRIAD}; 411 | static SDL_Color bronze = {BRONZE_TRIAD}; 412 | static SDL_Color white = {WHITE_TRIAD}; 413 | static SDL_Color gray = {GRAY_TRIAD}; 414 | static SDL_Color shadow25 = {SHADOW25_TRIAD}; 415 | static SDL_Color shadow50 = {SHADOW50_TRIAD}; 416 | static SDL_Color disabled = {DISABLED_TRIAD}; 417 | static SDL_Color disabled_shadow = {DISABLED_SHADOW_TRIAD}; 418 | 419 | static SDL_Surface* battery_charging; 420 | static SDL_Surface* battery_fill; 421 | static SDL_Surface* battery_line; 422 | static SDL_Surface* battery_fill_bad; 423 | static SDL_Surface* battery_line_bad; 424 | void GFX_init(void) { 425 | char font_path[256]; 426 | sprintf(font_path, "%s/%s", Paths.resDir, "BPreplayBold-unhinted.otf"); 427 | 428 | TTF_Init(); 429 | font_s = TTF_OpenFont(font_path, Screen.font.small_size); 430 | font_m = TTF_OpenFont(font_path, Screen.font.medium_size); 431 | font_l = TTF_OpenFont(font_path, Screen.font.large_size); 432 | 433 | if (!font_s || !font_m || !font_l) printf("TTF_OpenFont: %s\n", TTF_GetError()); 434 | 435 | rule = GFX_loadImage("rule.png"); 436 | button = GFX_loadImage("btn.png"); 437 | bg_white = GFX_loadImage("bg-white.png"); 438 | bg_black = GFX_loadImage("bg-black.png"); 439 | 440 | settings_bar_full = GFX_loadImage("settings-bar-full.png"); 441 | settings_bar_empty = GFX_loadImage("settings-bar-empty.png"); 442 | settings_brightness = GFX_loadImage("settings-brightness.png"); 443 | settings_volume = GFX_loadImage("settings-volume.png"); 444 | settings_mute = GFX_loadImage("settings-mute.png"); 445 | 446 | battery_charging = GFX_loadImage("battery-charging.png"); 447 | battery_fill = GFX_loadImage("battery-fill.png"); 448 | battery_line = GFX_loadImage("battery-line.png"); 449 | battery_fill_bad = GFX_loadImage("bad-battery-fill.png"); 450 | battery_line_bad = GFX_loadImage("bad-battery-line.png"); 451 | 452 | puts("GFX_init"); fflush(stdout); 453 | } 454 | void GFX_ready(void) { 455 | screen = SDL_GetVideoSurface(); // :cold_sweat: 456 | } 457 | SDL_Surface* GFX_loadImage(char* path) { 458 | static char full_path[256]; 459 | sprintf(full_path, "%s/%s", Paths.resDir, path); 460 | 461 | SDL_Surface* image = IMG_Load(full_path); 462 | if (!image) printf("IMG_Load: %s\n", IMG_GetError()); 463 | return image; 464 | } 465 | 466 | void GFX_quit(void) { 467 | puts("GFX_quit"); fflush(stdout); 468 | 469 | SDL_FreeSurface(rule); 470 | SDL_FreeSurface(button); 471 | SDL_FreeSurface(bg_white); 472 | SDL_FreeSurface(bg_black); 473 | SDL_FreeSurface(settings_bar_full); 474 | SDL_FreeSurface(settings_bar_empty); 475 | SDL_FreeSurface(settings_brightness); 476 | SDL_FreeSurface(settings_volume); 477 | SDL_FreeSurface(settings_mute); 478 | 479 | SDL_FreeSurface(battery_charging); 480 | SDL_FreeSurface(battery_fill); 481 | SDL_FreeSurface(battery_line); 482 | SDL_FreeSurface(battery_fill_bad); 483 | SDL_FreeSurface(battery_line_bad); 484 | 485 | TTF_CloseFont(font_s); 486 | TTF_CloseFont(font_m); 487 | TTF_CloseFont(font_l); 488 | 489 | if (screen) SDL_FreeSurface(screen); 490 | 491 | TTF_Quit(); 492 | } 493 | 494 | void GFX_clear(void) { 495 | SDL_FillRect(screen, NULL, 0); 496 | SDL_Flip(screen); 497 | } 498 | void GFX_blitRule(SDL_Surface* surface, int y) { 499 | SDL_BlitSurface(rule, NULL, surface, &(SDL_Rect){0,y}); 500 | } 501 | int GFX_blitHint(SDL_Surface* surface, char* htxt, int x, int y) { 502 | SDL_Surface* hint_text = TTF_RenderUTF8_Blended(font_m, htxt, white); 503 | SDL_BlitSurface(hint_text, NULL, surface, &(SDL_Rect){x,y}); 504 | SDL_FreeSurface(hint_text); 505 | } 506 | int GFX_blitPill(SDL_Surface* surface, char* btxt, char* htxt, int x, int y) { 507 | SDL_Surface* button_text = TTF_RenderUTF8_Blended(font_s, btxt, bronze); 508 | SDL_Surface* hint_text = TTF_RenderUTF8_Blended(font_m, htxt, white); 509 | 510 | int pill_width = Screen.pill.pad_width + button_text->w + Screen.pill.pad_width; 511 | int total_width = pill_width + Screen.hint.ox + hint_text->w; 512 | if (x<0) x += Screen.width - total_width; 513 | 514 | int hw = Screen.button.size/2; 515 | int fill_width = pill_width - hw - hw; 516 | SDL_BlitSurface(button, &(SDL_Rect){0,0,hw,Screen.button.size}, surface, &(SDL_Rect){x,y}); 517 | SDL_FillRect(surface, &(SDL_Rect){x+hw,y,fill_width,Screen.button.size}, SDL_MapRGB(button->format, WHITE_TRIAD)); 518 | SDL_BlitSurface(button, &(SDL_Rect){hw,0,hw,Screen.button.size}, surface, &(SDL_Rect){x+hw+fill_width,y}); 519 | SDL_BlitSurface(button_text, NULL, surface, &(SDL_Rect){x+Screen.pill.pad_width,y+Screen.pill.text_oy}); 520 | SDL_BlitSurface(hint_text, NULL, surface, &(SDL_Rect){x+pill_width+Screen.hint.ox,y+Screen.hint.text_oy}); 521 | SDL_FreeSurface(button_text); 522 | SDL_FreeSurface(hint_text); 523 | return total_width; 524 | } 525 | int GFX_blitButton(SDL_Surface* surface, char* btxt, char* htxt, int x, int y, int bx) { 526 | SDL_Surface* button_text = TTF_RenderUTF8_Blended(font_l, btxt, bronze); 527 | SDL_Surface* hint_text = TTF_RenderUTF8_Blended(font_m, htxt, white); 528 | 529 | int total_width = Screen.button.size + Screen.hint.ox + hint_text->w; 530 | if (x<0) x += Screen.width - total_width; 531 | 532 | int button_text_ox = (Screen.button.size - button_text->w) / 2 + bx; 533 | SDL_BlitSurface(button, NULL, surface, &(SDL_Rect){x,y}); 534 | SDL_BlitSurface(button_text, NULL, surface, &(SDL_Rect){x+button_text_ox,y+Screen.button.text.oy}); 535 | SDL_BlitSurface(hint_text, NULL, surface, &(SDL_Rect){x+Screen.button.size+Screen.hint.ox,y+Screen.hint.text_oy}); 536 | SDL_FreeSurface(button_text); 537 | SDL_FreeSurface(hint_text); 538 | return total_width; 539 | } 540 | 541 | static void trimSortingMeta(char** str) { // eg. `001) ` 542 | char* safe = *str; 543 | while(isdigit(**str)) *str += 1; // ignore leading numbers 544 | 545 | if (*str[0]==')') { // then match a closing parenthesis 546 | *str += 1; 547 | } 548 | else { // or bail, restoring the string to its original value 549 | *str = safe; 550 | return; 551 | } 552 | 553 | while(isblank(**str)) *str += 1; // ignore leading space 554 | } 555 | void GFX_blitMenu(SDL_Surface* surface, char* name, char* path, char* unique, int row, int selected_row) { 556 | int max_width = Screen.width - (2 * Screen.main.list.ox); 557 | SDL_Surface* text; 558 | if (row==selected_row) { 559 | char* display_name = unique ? unique : name; 560 | trimSortingMeta(&display_name); 561 | 562 | // bar 563 | SDL_FillRect(surface, &(SDL_Rect){0,Screen.main.list.y+(row*Screen.main.list.row_height),Screen.width,Screen.main.list.row_height}, SDL_MapRGB(surface->format, PINK_TRIAD)); 564 | 565 | // shadow 566 | text = TTF_RenderUTF8_Blended(font_l, display_name, shadow50); 567 | 568 | // if (text->w>max_width) needs_scrolling = 1; // TODO: restore 569 | SDL_BlitSurface(text, &(SDL_Rect){0,0,max_width,text->h}, surface, &(SDL_Rect){Screen.main.list.ox+Screen.font.shadow.ox,Screen.main.list.y+(row*Screen.main.list.row_height)+Screen.main.list.oy+Screen.font.shadow.oy}); 570 | SDL_FreeSurface(text); 571 | 572 | text = TTF_RenderUTF8_Blended(font_l, display_name, white); 573 | SDL_BlitSurface(text, &(SDL_Rect){0,0,max_width,text->h}, surface, &(SDL_Rect){Screen.main.list.ox,Screen.main.list.y+(row*Screen.main.list.row_height)+Screen.main.list.oy}); 574 | SDL_FreeSurface(text); 575 | } 576 | else { 577 | if (unique) { 578 | trimSortingMeta(&unique); 579 | text = TTF_RenderUTF8_Blended(font_l, unique, gray); 580 | SDL_BlitSurface(text, &(SDL_Rect){0,0,max_width,text->h}, surface, &(SDL_Rect){Screen.main.list.ox,Screen.main.list.y+(row*Screen.main.list.row_height)+Screen.main.list.oy}); 581 | SDL_FreeSurface(text); 582 | } 583 | 584 | trimSortingMeta(&name); 585 | text = TTF_RenderUTF8_Blended(font_l, name, white); 586 | SDL_BlitSurface(text, &(SDL_Rect){0,0,max_width,text->h}, surface, &(SDL_Rect){Screen.main.list.ox,Screen.main.list.y+(row*Screen.main.list.row_height)+Screen.main.list.oy}); 587 | SDL_FreeSurface(text); 588 | } 589 | } 590 | // copy/paste/mod 591 | static int scroll_selected = -1; 592 | static int scroll_ticks = 0; 593 | static int scroll_delay = 30; 594 | static int scroll_ox = 0; 595 | int GFX_scrollMenu(SDL_Surface* surface, char* name, char* path, char* unique, int row, int selected, int reset, int force) { 596 | // reset is used when changing directories (otherwise returning from the first row to the first row above wouldn't reset the scroll) 597 | if (reset || selected!=scroll_selected) { 598 | scroll_ticks = 0; 599 | scroll_ox = 0; 600 | scroll_selected = selected; 601 | } 602 | 603 | scroll_ticks += 1; 604 | if (scroll_ticksw<=max_width) { 615 | SDL_FreeSurface(text); 616 | return 0; 617 | } 618 | 619 | // prevent overscroll 620 | if (scroll_ox>text->w-max_width) { 621 | scroll_ox = text->w-max_width; 622 | if (!force) { // nothing to draw unless something outside of this function dirtied the screen 623 | SDL_FreeSurface(text); 624 | return 0; 625 | } 626 | } 627 | 628 | // bar 629 | SDL_FillRect(surface, &(SDL_Rect){0,Screen.main.list.y+(row*Screen.main.list.row_height),Screen.width,Screen.main.list.row_height}, SDL_MapRGB(surface->format, PINK_TRIAD)); 630 | 631 | // shadow 632 | SDL_BlitSurface(text, &(SDL_Rect){scroll_ox,0,max_width,text->h}, surface, &(SDL_Rect){Screen.main.list.ox+Screen.font.shadow.ox,Screen.main.list.y+(row*Screen.main.list.row_height)+Screen.main.list.oy+Screen.font.shadow.oy}); 633 | SDL_FreeSurface(text); 634 | 635 | // actual text 636 | text = TTF_RenderUTF8_Blended(font_l, display_name, white); 637 | SDL_BlitSurface(text, &(SDL_Rect){scroll_ox,0,max_width,text->h}, surface, &(SDL_Rect){Screen.main.list.ox,Screen.main.list.y+(row*Screen.main.list.row_height)+Screen.main.list.oy}); 638 | SDL_FreeSurface(text); 639 | return 1; 640 | } 641 | void GFX_blitWindow(SDL_Surface* surface, int x, int y, int width, int height, int color) { 642 | SDL_Surface* bg = color ? bg_white : bg_black; 643 | int color_rgb = color ? SDL_MapRGB(bg->format, WHITE_TRIAD) : 0; 644 | int hw = (bg->w / 2); 645 | int hh = (bg->h / 2); 646 | 647 | // corners 648 | SDL_BlitSurface(bg, &(SDL_Rect){0,0,hw,hh}, surface, &(SDL_Rect){x,y}); 649 | SDL_BlitSurface(bg, &(SDL_Rect){hw,0,hw,hh}, surface, &(SDL_Rect){x+width-hw,y}); 650 | SDL_BlitSurface(bg, &(SDL_Rect){0,hh,hw,hh}, surface, &(SDL_Rect){x,y+height-hh}); 651 | SDL_BlitSurface(bg, &(SDL_Rect){hw,hh,hw,hh}, surface, &(SDL_Rect){x+width-hw,y+height-hh}); 652 | 653 | // fill 654 | SDL_FillRect(surface, &(SDL_Rect){x+hw,y,width-bg->w,hh}, color_rgb); 655 | SDL_FillRect(surface, &(SDL_Rect){x,y+hh,width,height-bg->h}, color_rgb); 656 | SDL_FillRect(surface, &(SDL_Rect){x+hw,y+height-hh,width-bg->w,hh}, color_rgb); 657 | } 658 | 659 | void GFX_blitBodyCopy(SDL_Surface* surface, char* str, int ox, int oy, int width, int height) { 660 | SDL_Surface* text; 661 | #define kTextBoxMaxRows 16 662 | char* rows[kTextBoxMaxRows]; 663 | int row_count = 0; 664 | 665 | char* tmp; 666 | rows[row_count++] = str; 667 | while ((tmp=strchr(rows[row_count-1], '\n'))!=NULL) { 668 | if (row_count+1>=kTextBoxMaxRows) return; // TODO: bail 669 | rows[row_count++] = tmp+1; 670 | } 671 | 672 | int rendered_height = Screen.body.line_height * row_count; 673 | int y = oy; 674 | y += (height - rendered_height) / 2; 675 | 676 | char line[256]; 677 | for (int i=0; iw) / 2; 694 | SDL_BlitSurface(text, NULL, surface, &(SDL_Rect){x,y}); 695 | SDL_FreeSurface(text); 696 | } 697 | y += Screen.body.line_height; 698 | } 699 | } 700 | // this function is completely asinine, wtf was I thinking 701 | // TODO: this needs serious refactoring...I mean, yikes! 702 | int GFX_blitText(SDL_Surface* surface, char* str, int size, int x, int y, int width, int color, int has_shadow) { 703 | // size=0:small,1:medium,2:large width=0:left,>0:center,<0:right, color=-1:gray,0:white,1:gold, no multiline 704 | SDL_Surface* text; 705 | 706 | SDL_Color shadow_color = (x==Screen.menu.list.x?(color==-1?disabled_shadow:shadow25):shadow50); 707 | if (has_shadow && color==-1) color = 0; 708 | 709 | TTF_Font* font = size==0?font_s:(size==1?font_m:font_l); 710 | int oy = size=0?Screen.font.small_oy:(size==1?Screen.font.medium_oy:Screen.font.large_oy); 711 | text = TTF_RenderUTF8_Blended(font, str, has_shadow?shadow_color:(color==-1?disabled:(color?pink:white))); 712 | int w = text->w; 713 | 714 | if (width>0) x += (width - w) / 2; 715 | else if (width<0) x += width - w; 716 | 717 | if (has_shadow) { 718 | SDL_BlitSurface(text, NULL, surface, &(SDL_Rect){x+Screen.font.shadow.ox,y+Screen.font.shadow.oy}); 719 | SDL_FreeSurface(text); 720 | text = TTF_RenderUTF8_Blended(font, str, color==-1?gray:(color?pink:white)); 721 | } 722 | 723 | // SDL_FillRect(surface, &(SDL_Rect){x,y,text->w,text->h}, white_rgb); // TODO: tmp 724 | 725 | SDL_BlitSurface(text, NULL, surface, &(SDL_Rect){x,y}); 726 | SDL_FreeSurface(text); 727 | return w; 728 | } 729 | 730 | SDL_Surface* GFX_getText(char* text, int size, int color) { 731 | TTF_Font* font = size==0?font_s:(size==1?font_m:font_l); 732 | return TTF_RenderUTF8_Blended(font, text, color?pink:white); 733 | } 734 | 735 | void GFX_blitBattery(SDL_Surface* surface, int x, int y) { 736 | if (isCharging()) SDL_BlitSurface(battery_charging, NULL, surface, &(SDL_Rect){x,y}); 737 | else { 738 | int charge = getInt("/tmp/battery"); 739 | SDL_Surface* fill = charge<=17 ? battery_fill_bad : battery_fill; 740 | SDL_Surface* line = charge<=10 ? battery_line_bad : battery_line; 741 | SDL_BlitSurface(line, NULL, surface, &(SDL_Rect){x,y}); 742 | 743 | x += 4; 744 | y += 6; 745 | 746 | int h = fill->h * (float)charge / 100; 747 | int oy = fill->h - h; 748 | SDL_BlitSurface(fill, &(SDL_Rect){0,oy,fill->w,h}, surface, &(SDL_Rect){x,y+oy}); 749 | } 750 | } 751 | void GFX_blitSettings(SDL_Surface* surface, int x, int y, int icon, int value, int min_value, int max_value) { 752 | if (x==Screen.menu.settings.x) GFX_blitWindow(surface, x,y,Screen.settings.width,Screen.settings.height, 0); 753 | SDL_BlitSurface(icon==0?settings_brightness:(icon==1?settings_volume:settings_mute), NULL, surface, &(SDL_Rect){x+Screen.settings.icon.ox,y+Screen.settings.icon.oy}); 754 | SDL_BlitSurface(settings_bar_empty, NULL, surface, &(SDL_Rect){x+Screen.settings.bar.ox,y+Screen.settings.bar.oy}); 755 | int w = settings_bar_full->w * ((float)(value-min_value) / (max_value-min_value)); 756 | int h = settings_bar_full->h; 757 | SDL_BlitSurface(settings_bar_full, &(SDL_Rect){0,0,w,h}, surface, &(SDL_Rect){x+Screen.settings.bar.ox,y+Screen.settings.bar.oy,w,h}); 758 | } 759 | 760 | /////////////////////////////////////// 761 | 762 | static int can_poweroff = 1; 763 | void disablePoweroff(void) { 764 | can_poweroff = 0; 765 | } 766 | 767 | void waitForWake(void) { 768 | SDL_Event event; 769 | int wake = 0; 770 | unsigned long sleep_ticks = SDL_GetTicks(); 771 | while (!wake) { 772 | while (SDL_PollEvent(&event)) { 773 | if (event.type==SDL_KEYUP) { 774 | SDLKey key = event.key.keysym.sym; 775 | if (key==MINUI_POWER) { 776 | wake = 1; 777 | break; 778 | } 779 | } 780 | } 781 | SDL_Delay(200); 782 | if (can_poweroff && SDL_GetTicks()-sleep_ticks>=120000) { // increased to two minutes 783 | if (isCharging()) sleep_ticks += 60000; // check again in a minute 784 | else powerOff(); 785 | } 786 | } 787 | return; 788 | } 789 | 790 | void fauxSleep(void) { 791 | GFX_clear(); 792 | Input_reset(); 793 | 794 | enterSleep(); 795 | system("killall -s STOP keymon"); 796 | waitForWake(); 797 | system("killall -s CONT keymon"); 798 | exitSleep(); 799 | } 800 | 801 | int isCharging(void) { 802 | // Code adapted from OnionOS 803 | char *cmd = "cd /customer/app/ ; ./axp_test"; 804 | int batJsonSize = 100; 805 | char buf[batJsonSize]; 806 | int charge_number; 807 | int result; 808 | 809 | FILE *fp; 810 | fp = popen(cmd, "r"); 811 | if (fgets(buf, batJsonSize, fp) != NULL) { 812 | sscanf(buf, "{\"battery\":%*d, \"voltage\":%*d, \"charging\":%d}", &charge_number); 813 | result = (charge_number==3); 814 | } 815 | pclose(fp); 816 | 817 | return result; 818 | } 819 | 820 | #define GOVERNOR_PATH "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor" 821 | static char governor[128]; 822 | 823 | void enterSleep(void) { 824 | //SetRawVolume(-60); 825 | SetMute(1); 826 | // SetRawBrightness(0); 827 | putInt("/sys/class/gpio/export", 4); 828 | putFile("/sys/class/gpio/gpio4/direction", "out"); 829 | putInt("/sys/class/gpio/gpio4/value", 0); 830 | 831 | // save current governor (either ondemand or performance) 832 | getFile(GOVERNOR_PATH, governor, 128); 833 | trimTrailingNewlines(governor); 834 | 835 | putFile(GOVERNOR_PATH, "powersave"); 836 | sync(); 837 | } 838 | void exitSleep(void) { 839 | putInt("/sys/class/gpio/gpio4/value", 1); 840 | putInt("/sys/class/gpio/unexport", 4); 841 | putInt("/sys/class/pwm/pwmchip0/export", 0); 842 | putInt("/sys/class/pwm/pwmchip0/pwm0/enable",0); 843 | putInt("/sys/class/pwm/pwmchip0/pwm0/enable",1); 844 | // SetBrightness(GetBrightness()); 845 | SetMute(0); 846 | SetVolume(GetVolume()); 847 | 848 | // restore previous governor 849 | putFile(GOVERNOR_PATH, governor); 850 | } 851 | 852 | int preventAutosleep(void) { 853 | return isCharging(); 854 | } 855 | 856 | void powerOff(void) { 857 | if (can_poweroff) { 858 | char* msg = exists(kAutoResumePath) ? "Quicksave created,\npowering off" : "Powering off"; 859 | SDL_FillRect(screen, NULL, 0); 860 | GFX_blitBodyCopy(screen, msg, 0,0,Screen.width,Screen.height); 861 | SDL_Flip(screen); 862 | sleep(1); 863 | system("shutdown"); 864 | while (1) pause(); 865 | } 866 | } -------------------------------------------------------------------------------- /src/common/common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H 2 | #define COMMON_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // platform independent 9 | #define MIN_VOLUME 0 10 | #define MAX_VOLUME 20 11 | #define MIN_BRIGHTNESS 0 12 | #define MAX_BRIGHTNESS 10 13 | 14 | #define HINT_SLEEP "POWER" 15 | #define HINT_RESUME "X" 16 | 17 | #define SDLK_UNDEFINED -1 18 | 19 | // must be unique except for absent buttons 20 | #define MINUI_UP SDLK_UP 21 | #define MINUI_DOWN SDLK_DOWN 22 | #define MINUI_LEFT SDLK_LEFT 23 | #define MINUI_RIGHT SDLK_RIGHT 24 | #define MINUI_A SDLK_SPACE 25 | #define MINUI_B SDLK_LCTRL 26 | #define MINUI_X SDLK_LSHIFT 27 | #define MINUI_Y SDLK_LALT 28 | #define MINUI_START SDLK_RETURN 29 | #define MINUI_SELECT SDLK_RCTRL 30 | #define MINUI_L SDLK_e 31 | #define MINUI_R SDLK_t 32 | #define MINUI_MENU SDLK_ESCAPE 33 | #define MINUI_L2 SDLK_TAB 34 | #define MINUI_R2 SDLK_BACKSPACE 35 | #define MINUI_L3 SDLK_UNDEFINED 36 | #define MINUI_R3 SDLK_UNDEFINED 37 | #define MINUI_POWER SDLK_POWER 38 | #define MINUI_VOLDN SDLK_LSUPER 39 | #define MINUI_VOLUP SDLK_RSUPER 40 | 41 | #define PINK_TRIAD 0xd4,0x98,0xab 42 | #define BRONZE_TRIAD 0xa1,0x74,0x82 43 | #define WHITE_TRIAD 0xff,0xff,0xff 44 | #define GRAY_TRIAD 0x66,0x66,0x66 45 | #define SHADOW25_TRIAD 0xa1,0x87,0x47 46 | #define SHADOW50_TRIAD 0x68,0x5a,0x35 47 | #define DISABLED_TRIAD 0xda,0xda,0xda 48 | #define DISABLED_SHADOW_TRIAD 0xc4,0xc4,0xc4 49 | 50 | typedef enum ButtonIndex { 51 | kButtonUp = 0, 52 | kButtonDown, 53 | kButtonLeft, 54 | kButtonRight, 55 | kButtonA, 56 | kButtonB, 57 | kButtonX, 58 | kButtonY, 59 | kButtonStart, 60 | kButtonSelect, 61 | kButtonL, 62 | kButtonR, 63 | kButtonMenu, 64 | kButtonL2, 65 | kButtonR2, 66 | kButtonL3, 67 | kButtonR3, 68 | kButtonPower, 69 | kButtonVolDn, 70 | kButtonVolUp, 71 | kButtonCount, 72 | } ButtonIndex; 73 | 74 | // map actions to platform specific buttons here 75 | // TODO: considering moving resume to START on all platforms? 76 | // but then we need to extend the can_start and can_select behavior too... 77 | #define kButtonSleep kButtonPower 78 | #define kButtonResume kButtonX 79 | #define kButtonAltEmu kButtonY 80 | 81 | typedef struct UnionPaths { 82 | char rootDir[256]; 83 | char userdataDir[256]; 84 | char resDir[256]; 85 | char romsDir[256]; 86 | char paksDir[256]; 87 | char recentPath[256]; 88 | char fauxRecentDir[256]; 89 | char collectionsDir[256]; 90 | } UnionPaths; 91 | 92 | // TODO: pull paths out of Paths struct, remove unnecessary sprintf calls 93 | #define kLastPath "/tmp/last.txt" // transient 94 | #define kChangeDiscPath "/tmp/change_disc.txt" 95 | #define kResumeSlotPath "/tmp/mmenu_slot.txt" 96 | #define kAutoResumePath "/mnt/SDCARD/.userdata/.miniui/auto_resume.txt" 97 | #define kAutoResumeSlot "9" 98 | #define kEnableSimpleModePath "/mnt/SDCARD/.userdata/enable-simple-mode" 99 | 100 | // NOTE: this was a huge, dumb refactor 101 | typedef struct UnionScreen { 102 | int width; 103 | int height; 104 | 105 | struct { 106 | 107 | // TODO: break up into {size,oy} structs by size 108 | int small_size; 109 | int medium_size; 110 | int large_size; 111 | int small_oy; 112 | int medium_oy; 113 | int large_oy; 114 | 115 | struct { 116 | int ox; 117 | int oy; 118 | } shadow; 119 | } font; 120 | 121 | struct { 122 | int size; 123 | struct { 124 | int oy; 125 | int ox_A; 126 | int ox_B; 127 | int ox_X; 128 | int ox_Y; 129 | } text; 130 | } button; 131 | 132 | struct { 133 | int pad_width; 134 | int text_oy; 135 | } pill; 136 | 137 | struct { 138 | int ox; 139 | int text_oy; 140 | } hint; 141 | 142 | struct { 143 | int width; 144 | int height; 145 | struct { 146 | int ox; 147 | int oy; 148 | } icon; 149 | struct { 150 | int ox; 151 | int oy; 152 | } bar; 153 | } settings; 154 | 155 | struct { 156 | int top; // TODO: why is this top and not y? 157 | int left; 158 | int right; 159 | int gutter; 160 | } buttons; 161 | 162 | struct { // main 163 | struct { 164 | int x; 165 | int y; 166 | } settings; 167 | 168 | struct { 169 | int x; 170 | int y; 171 | } battery; 172 | 173 | struct { 174 | int top_y; 175 | int bottom_y; 176 | } rule; 177 | 178 | struct { 179 | int x; 180 | int y; 181 | } logo; 182 | 183 | struct { 184 | int row_count; 185 | int y; 186 | int ox; 187 | int oy; 188 | int row_height; 189 | int alt_ox; 190 | int alt_oy; 191 | } list; 192 | } main; 193 | 194 | struct { // menu 195 | struct { 196 | int x; 197 | int y; 198 | } settings; 199 | 200 | struct { 201 | int x; 202 | int y; 203 | } battery; 204 | 205 | struct { 206 | int top_y; 207 | int bottom_y; 208 | } rule; 209 | 210 | struct { 211 | int top; // TODO: why is this top and not y? 212 | } buttons; 213 | 214 | struct { 215 | int ox; 216 | int oy; 217 | } disc; 218 | 219 | struct { 220 | int x; 221 | int y; 222 | int width; 223 | int height; 224 | int inset; 225 | } preview; 226 | 227 | struct { 228 | int x; 229 | int y; 230 | int ox; 231 | } slots; 232 | 233 | struct { 234 | int x; 235 | int y; 236 | int width; 237 | } title; 238 | 239 | struct { 240 | int x; 241 | int y; 242 | int width; 243 | int height; 244 | } window; 245 | 246 | struct { 247 | int x; 248 | int y; 249 | int oy; 250 | int line_height; 251 | int row_height; 252 | } list; 253 | 254 | struct { 255 | int ox; // NOTE: from right edge 256 | int oy; 257 | } arrow; 258 | 259 | int bar_height; 260 | } menu; 261 | 262 | struct { 263 | int line_height; 264 | } body; 265 | 266 | } UnionScreen; 267 | 268 | extern UnionPaths Paths; 269 | extern UnionScreen Screen; 270 | 271 | void Input_reset(void); 272 | void Input_poll(void); 273 | int Input_anyPressed(void); 274 | int Input_justPressed(ButtonIndex btn); 275 | int Input_justRepeated(ButtonIndex btn); 276 | int Input_isPressed(ButtonIndex btn); 277 | int Input_justReleased(ButtonIndex btn); 278 | 279 | int prefixMatch(char* pre, char* str); 280 | int suffixMatch(char* suf, char* str); 281 | int exactMatch(char* str1, char* str2); 282 | int hide(char* file_name); 283 | 284 | void getDisplayName(const char* in_name, char* out_name); 285 | void getEmuName(const char* in_name, char* out_name); 286 | 287 | void normalizeNewline(char* line); 288 | void trimTrailingNewlines(char* line); 289 | 290 | int exists(char* path); 291 | void touch(char* path); 292 | void putFile(char* path, char* contents); 293 | void getFile(char* path, char* buffer, size_t buffer_size); 294 | void putInt(char* path, int value); 295 | int getInt(char* path); 296 | 297 | void GFX_init(void); 298 | void GFX_ready(void); 299 | void GFX_quit(void); 300 | void GFX_clear(void); 301 | SDL_Surface* GFX_loadImage(char* path); // only meant for system images, not arbitrary images like save state previews! 302 | void GFX_blitRule(SDL_Surface* surface, int y); 303 | int GFX_blitHint(SDL_Surface* surface, char* htxt, int x, int y); 304 | int GFX_blitPill(SDL_Surface* surface, char* btxt, char* htxt, int x, int y); 305 | int GFX_blitButton(SDL_Surface* surface, char* btxt, char* htxt, int x, int y, int bx); 306 | void GFX_blitMenu(SDL_Surface* surface, char* name, char* path, char* unique, int row, int selected_row); 307 | int GFX_scrollMenu(SDL_Surface* surface, char* name, char* path, char* unique, int row, int selected, int reset, int force); 308 | void GFX_blitWindow(SDL_Surface* surface, int x, int y, int width, int height, int color); // color=0:black,1:white 309 | void GFX_blitBodyCopy(SDL_Surface* surface, char* text, int x, int y, int width, int height); // gold, centered in rect, multiline okay! 310 | int GFX_blitText(SDL_Surface* surface, char* text, int size, int x, int y, int width, int color, int has_shadow); // size=0:small,1:medium,2:large width=0:left,>0:center,<0:right, color=0:white,1:gold, no multiline 311 | 312 | SDL_Surface* GFX_getText(char* text, int size, int color); 313 | void GFX_blitBattery(SDL_Surface* surface, int x, int y); 314 | void GFX_blitSettings(SDL_Surface* surface, int x, int y, int icon, int value, int min_value, int max_value); // icon=0:brightness,1:volume,2:mute 315 | 316 | void waitForWake(void); 317 | void fauxSleep(void); 318 | 319 | int isCharging(void); 320 | 321 | void powerOff(void); 322 | 323 | void enterSleep(void); 324 | void exitSleep(void); 325 | 326 | 327 | void disablePoweroff(void); 328 | int preventAutosleep(void); 329 | 330 | #endif -------------------------------------------------------------------------------- /src/confirm/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define BUTTON_A KEY_SPACE 12 | #define BUTTON_B KEY_LEFTCTRL 13 | 14 | int main(int argc , char* argv[]) { 15 | int any = 0; 16 | int only = 0; 17 | 18 | if (argc<1) { 19 | puts("Usage: confirm [any|only]"); 20 | puts(" default: only A button confirms, only B button cancels"); 21 | puts(" any: any button confirms, none cancel"); 22 | puts(" only: only the A button confirms, none cancel"); 23 | return 0; 24 | } 25 | 26 | if (argc>1) { 27 | char mode[4]; 28 | strncpy(mode,argv[1],4); 29 | any = strncmp(mode, "any", 4)==0; 30 | only = strncmp(mode, "only", 4)==0; 31 | } 32 | 33 | int confirmed = 0; // true in shell 34 | 35 | int input_fd = open("/dev/input/event0", O_RDONLY); 36 | struct input_event event; 37 | while (read(input_fd, &event, sizeof(event))==sizeof(event)) { 38 | if (event.type!=EV_KEY || event.value>1) continue; 39 | if (event.type==EV_KEY) { 40 | if (any || event.code==BUTTON_A) break; 41 | else if (!only && event.code==BUTTON_B) { 42 | confirmed = 1; // false in shell terms 43 | break; 44 | } 45 | } 46 | } 47 | 48 | // clear screen 49 | int fb0_fd = open("/dev/fb0", O_RDWR); 50 | struct fb_var_screeninfo vinfo; 51 | ioctl(fb0_fd, FBIOGET_VSCREENINFO, &vinfo); 52 | int map_size = vinfo.xres * vinfo.yres * (vinfo.bits_per_pixel / 8); // 640x480x4 53 | char* fb0_map = (char*)mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb0_fd, 0); 54 | memset(fb0_map, 0, map_size); 55 | munmap(fb0_map, map_size); 56 | close(fb0_fd); 57 | 58 | close(input_fd); 59 | 60 | return confirmed; 61 | } 62 | -------------------------------------------------------------------------------- /src/confirm/makefile: -------------------------------------------------------------------------------- 1 | ifeq (,$(CROSS_COMPILE)) 2 | $(error missing CROSS_COMPILE for this toolchain) 3 | endif 4 | 5 | TARGET = confirm 6 | 7 | CC = $(CROSS_COMPILE)gcc 8 | CFLAGS = -marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7ve 9 | LDFLAGS = 10 | 11 | all: 12 | $(CC) main.c -o $(TARGET) $(CFLAGS) $(LDFLAGS) 13 | clean: 14 | rm -f $(TARGET) -------------------------------------------------------------------------------- /src/keymon/credits.txt: -------------------------------------------------------------------------------- 1 | based on eggs custom keymon for Trimui: 2 | https://www.dropbox.com/sh/5e9xwvp672vt8cr/AABUIdw1vLYp9h0waoCUqHPOa/source?dl=0&subfolder_nav_tracking=1 3 | modified to use libmsettings -------------------------------------------------------------------------------- /src/keymon/keymon.c: -------------------------------------------------------------------------------- 1 | // miyoomini/keymon.c 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | // Button Defines 20 | #define BUTTON_MENU KEY_ESC 21 | #define BUTTON_POWER KEY_POWER 22 | #define BUTTON_SELECT KEY_RIGHTCTRL 23 | #define BUTTON_START KEY_ENTER 24 | #define BUTTON_L1 KEY_E 25 | #define BUTTON_R1 KEY_T 26 | #define BUTTON_L2 KEY_TAB 27 | #define BUTTON_R2 KEY_BACKSPACE 28 | #define BUTTON_VOLUP KEY_VOLUMEUP 29 | #define BUTTON_VOLDOWN KEY_VOLUMEDOWN 30 | 31 | // for keyshm 32 | #define VOLUME 0 33 | #define BRIGHTNESS 1 34 | #define VOLMAX 20 35 | #define BRIMAX 10 36 | 37 | // for ev.value 38 | #define RELEASED 0 39 | #define PRESSED 1 40 | #define REPEAT 2 41 | 42 | // for button_flag 43 | #define SELECT_BIT 0 44 | #define START_BIT 1 45 | #define SELECT (1< 0) close(input_fd); 80 | if (sar_fd > 0) close(sar_fd); 81 | exit(exitcode); 82 | } 83 | 84 | static int isCharging(void) { 85 | // Code adapted from OnionOS 86 | char *cmd = "cd /customer/app/ ; ./axp_test"; 87 | int batJsonSize = 100; 88 | char buf[batJsonSize]; 89 | int charge_number; 90 | int result; 91 | 92 | FILE *fp; 93 | fp = popen(cmd, "r"); 94 | if (fgets(buf, batJsonSize, fp) != NULL) { 95 | sscanf(buf, "{\"battery\":%*d, \"voltage\":%*d, \"charging\":%d}", &charge_number); 96 | result = (charge_number==3); 97 | } 98 | pclose(fp); 99 | 100 | return result; 101 | } 102 | 103 | void checkAXP() { 104 | // Code adapted from OnionOS 105 | char *cmd = "cd /customer/app/ ; ./axp_test"; 106 | int batJsonSize = 100; 107 | char buf[batJsonSize]; 108 | int battery_number; 109 | 110 | FILE *fp; 111 | fp = popen(cmd, "r"); 112 | if (fgets(buf, batJsonSize, fp) != NULL) { 113 | sscanf(buf, "{\"battery\":%d, \"voltage\":%*d, \"charging\":%*d}", &battery_number); 114 | } 115 | pclose(fp); 116 | 117 | int bat_fd = open("/tmp/battery", O_CREAT | O_WRONLY | O_TRUNC); 118 | if (bat_fd>0) { 119 | char value[3]; 120 | sprintf(value, "%d", battery_number); 121 | write(bat_fd, value, strlen(value)); 122 | close(bat_fd); 123 | } 124 | } 125 | 126 | static void* runAXP(void *arg) { 127 | while(1) { 128 | sleep(5); 129 | checkAXP(); 130 | } 131 | return 0; 132 | } 133 | 134 | int main (int argc, char *argv[]) { 135 | checkAXP(); 136 | pthread_create(&adc_pt, NULL, &runAXP, NULL); 137 | 138 | // Set Initial Volume / Brightness 139 | InitSettings(); 140 | 141 | input_fd = open("/dev/input/event0", O_RDONLY); 142 | 143 | // Main Loop 144 | register uint32_t val; 145 | register uint32_t button_flag = 0; 146 | register uint32_t menu_pressed = 0; 147 | register uint32_t power_pressed = 0; 148 | uint32_t repeat_vol = 0; 149 | while( read(input_fd, &ev, sizeof(ev)) == sizeof(ev) ) { 150 | val = ev.value; 151 | if (( ev.type != EV_KEY ) || ( val > REPEAT )) continue; 152 | switch (ev.code) { 153 | case BUTTON_MENU: 154 | if ( val != REPEAT ) menu_pressed = val; 155 | break; 156 | case BUTTON_POWER: 157 | if ( val != REPEAT ) power_pressed = val; 158 | break; 159 | case BUTTON_START: 160 | if ( val != REPEAT ) { 161 | button_flag = button_flag & (~START) | (val< 0) { 174 | val = GetBrightness(); 175 | if (val0) SetMute(0); 180 | } 181 | } 182 | break; 183 | case BUTTON_VOLDOWN: 184 | if ( val == REPEAT ) { 185 | // Adjust repeat speed to 1/2 186 | val = repeat_vol; 187 | repeat_vol ^= PRESSED; 188 | } else { 189 | repeat_vol = 0; 190 | } 191 | if ( val == PRESSED ) { 192 | if (menu_pressed > 0) { 193 | val = GetBrightness(); 194 | if (val>0) SetBrightness(--val); 195 | } else { 196 | val = GetVolume(); 197 | if (val>0) SetVolume(--val); 198 | if (val==0) SetMute(1); 199 | } 200 | } 201 | break; 202 | default: 203 | break; 204 | } 205 | 206 | if (menu_pressed && power_pressed) { 207 | menu_pressed = power_pressed = 0; 208 | system("shutdown"); 209 | while (1) pause(); 210 | } 211 | } 212 | ERROR("Failed to read input event"); 213 | } 214 | -------------------------------------------------------------------------------- /src/keymon/makefile: -------------------------------------------------------------------------------- 1 | ifeq (,$(CROSS_COMPILE)) 2 | $(error missing CROSS_COMPILE for this toolchain) 3 | endif 4 | 5 | CC = $(CROSS_COMPILE)gcc 6 | FLAGS = -Os -lmsettings -lpthread -lrt -ldl -Wl,--gc-sections -s 7 | 8 | all: 9 | $(CC) keymon.c -o keymon $(FLAGS) 10 | clean: 11 | rm -rf keymon -------------------------------------------------------------------------------- /src/libmmenu/makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build 2 | .PHONY: clean 3 | 4 | TARGET=mmenu 5 | 6 | ########################################################### 7 | 8 | ifeq (,$(PLATFORM)) 9 | PLATFORM=$(UNION_PLATFORM) 10 | endif 11 | ifeq (,$(PLATFORM)) 12 | $(error please specify PLATFORM, eg. make PLATFORM=trimui) 13 | endif 14 | ifeq (,$(CROSS_COMPILE)) 15 | $(error missing CROSS_COMPILE for this toolchain) 16 | endif 17 | ifeq (,$(PREFIX)) 18 | $(error missing PREFIX for installation in toolchain) 19 | endif 20 | 21 | ########################################################### 22 | 23 | CC = $(CROSS_COMPILE)gcc 24 | 25 | SYSROOT := $(shell $(CC) --print-sysroot) 26 | 27 | INCLUDEDIR = $(SYSROOT)/usr/include 28 | CFLAGS = -I$(INCLUDEDIR) -I. -I../common -DPLATFORM_$(shell echo $(PLATFORM) | tr a-z A-Z) -std=gnu99 29 | LDFLAGS = -s -lSDL -lSDL_image -lSDL_ttf -lz -lm -Wl,--no-as-needed -ldl -lrt 30 | 31 | CFLAGS += -ggdb3 -Og 32 | 33 | ifeq (trimui,$(PLATFORM)) 34 | LDFLAGS += -ltinyalsa 35 | endif 36 | ifeq (rs90,$(PLATFORM)) 37 | LDFLAGS += -lasound 38 | endif 39 | 40 | OPTM=-Ofast 41 | 42 | build: 43 | $(CC) -c -Werror -fpic $(TARGET).c ../common/common.c $(CFLAGS) $(LDFLAGS) $(OPTM) 44 | $(CC) -shared -o lib$(TARGET).so $(TARGET).o common.o 45 | cp $(TARGET).h $(PREFIX)/include 46 | cp lib$(TARGET).so $(PREFIX)/lib 47 | clean: 48 | rm -f *.o 49 | rm -f lib$(TARGET).so 50 | rm -f $(PREFIX)/include/$(TARGET).h 51 | rm -f $(PREFIX)/lib/lib$(TARGET).so -------------------------------------------------------------------------------- /src/libmmenu/mmenu.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "../common/common.h" 12 | 13 | #include "mmenu.h" 14 | 15 | static SDL_Surface* overlay; 16 | static SDL_Surface* screen; 17 | static SDL_Surface* slot_overlay; 18 | static SDL_Surface* slot_dots; 19 | static SDL_Surface* slot_dot_selected; 20 | static SDL_Surface* arrow; 21 | static SDL_Surface* arrow_highlighted; 22 | static SDL_Surface* no_preview; 23 | static SDL_Surface* empty_slot; 24 | 25 | enum { 26 | kItemContinue, 27 | kItemSave, 28 | kItemLoad, 29 | kItemAdvanced, 30 | kItemExitGame, 31 | }; 32 | #define kItemCount 5 33 | static char* items[kItemCount]; 34 | 35 | #define kSlotCount 8 36 | static int slot = 0; 37 | static int is_simple = 0; 38 | 39 | __attribute__((constructor)) static void init(void) { 40 | void* librt = dlopen("librt.so.1", RTLD_LAZY | RTLD_GLOBAL); // shm 41 | void* libmsettings = dlopen("libmsettings.so", RTLD_LAZY | RTLD_GLOBAL); 42 | InitSettings(); 43 | 44 | is_simple = exists(kEnableSimpleModePath); 45 | 46 | items[kItemContinue] = "Continue"; 47 | items[kItemSave] = "Save"; 48 | items[kItemLoad] = "Load"; 49 | items[kItemAdvanced] = is_simple ? "Reset" : "Advanced"; 50 | items[kItemExitGame] = "Quit"; 51 | 52 | GFX_init(); 53 | 54 | overlay = SDL_CreateRGBSurface(SDL_SWSURFACE, Screen.width, Screen.height, 16, 0, 0, 0, 0); 55 | SDL_SetAlpha(overlay, SDL_SRCALPHA, 0x80); 56 | SDL_FillRect(overlay, NULL, 0); 57 | 58 | slot_overlay = GFX_loadImage("slot-overlay.png"); 59 | slot_dots = GFX_loadImage("slot-dots.png"); 60 | slot_dot_selected = GFX_loadImage("slot-dot-selected.png"); 61 | arrow = GFX_loadImage("arrow.png"); 62 | arrow_highlighted = GFX_loadImage("arrow-highlighted.png"); 63 | no_preview = GFX_getText("No Preview", 0, 1); 64 | empty_slot = GFX_getText("Empty Slot", 0, 1); 65 | } 66 | __attribute__((destructor)) static void quit(void) { 67 | SDL_FreeSurface(overlay); 68 | SDL_FreeSurface(slot_overlay); 69 | SDL_FreeSurface(slot_dots); 70 | SDL_FreeSurface(slot_dot_selected); 71 | SDL_FreeSurface(arrow); 72 | SDL_FreeSurface(arrow_highlighted); 73 | SDL_FreeSurface(no_preview); 74 | SDL_FreeSurface(empty_slot); 75 | } 76 | 77 | typedef struct __attribute__((__packed__)) uint24_t { 78 | uint8_t a,b,c; 79 | } uint24_t; 80 | static SDL_Surface* createThumbnail(SDL_Surface* src_img) { 81 | SDL_Surface* dst_img = SDL_CreateRGBSurface(0,Screen.width/2, Screen.height/2,src_img->format->BitsPerPixel,src_img->format->Rmask,src_img->format->Gmask,src_img->format->Bmask,src_img->format->Amask); 82 | 83 | uint8_t* src_px = src_img->pixels; 84 | uint8_t* dst_px = dst_img->pixels; 85 | int step = dst_img->format->BytesPerPixel; 86 | int step2 = step * 2; 87 | int stride = src_img->pitch; 88 | for (int y=0; yh; y++) { 89 | for (int x=0; xw; x++) { 90 | switch(step) { 91 | case 1: 92 | *dst_px = *src_px; 93 | break; 94 | case 2: 95 | *(uint16_t*)dst_px = *(uint16_t*)src_px; 96 | break; 97 | case 3: 98 | *(uint24_t*)dst_px = *(uint24_t*)src_px; 99 | break; 100 | case 4: 101 | *(uint32_t*)dst_px = *(uint32_t*)src_px; 102 | break; 103 | } 104 | dst_px += step; 105 | src_px += step2; 106 | } 107 | src_px += stride; 108 | } 109 | 110 | return dst_img; 111 | } 112 | 113 | static int state_support = 1; 114 | static int disable_poweroff = 0; 115 | void ShowWarning(void) { 116 | state_support = 0; 117 | disable_poweroff = 1; 118 | disablePoweroff(); 119 | 120 | screen = SDL_GetVideoSurface(); 121 | GFX_ready(); 122 | 123 | SDL_Surface* okay = GFX_loadImage("okay.png"); 124 | SDL_BlitSurface(okay, NULL, screen, NULL); 125 | GFX_blitBodyCopy(screen, "This pak does not support\nsave states, auto-power off\nor quicksave and resume.", 0,0,screen->w,406); 126 | SDL_Flip(screen); 127 | 128 | SDL_Event event; 129 | int warned = 0; 130 | while (!warned) { 131 | while (SDL_PollEvent(&event)) { 132 | if (event.type==SDL_KEYDOWN) { 133 | SDLKey key = event.key.keysym.sym; 134 | if (key==MINUI_A) { 135 | warned = 1; 136 | break; 137 | } 138 | } 139 | } 140 | SDL_Delay(200); 141 | } 142 | SDL_FreeSurface(okay); 143 | } 144 | 145 | // TODO: look at common data between SaveLoad and ShowMenu and determine which can be determined once and cached 146 | 147 | static MenuReturnStatus SaveLoad(char* rom_path, char* save_path_template, SDL_Surface* optional_snapshot, MenuRequestState requested_state, AutoSave_t autosave) { 148 | int status = kStatusContinue; 149 | if (!state_support) return status; 150 | 151 | char *tmp; 152 | char rom_file[256]; // with extension 153 | char slot_path[256]; 154 | char emu_name[256]; 155 | char mmenu_dir[256]; 156 | char txt_path[256]; 157 | 158 | tmp = strrchr(rom_path,'/'); 159 | if (tmp==NULL) tmp = rom_path; 160 | else tmp += 1; 161 | strcpy(rom_file, tmp); 162 | 163 | getEmuName(rom_path, emu_name); 164 | sprintf(mmenu_dir, "%s/.mmenu/%s", getenv("USERDATA_PATH"), emu_name); 165 | mkdir(mmenu_dir, 0755); 166 | 167 | sprintf(txt_path, "%s/%s.%d.txt", mmenu_dir, rom_file, slot); 168 | 169 | // does this game have an m3u? 170 | int rom_disc = -1; 171 | int disc = rom_disc; 172 | int total_discs = 0; 173 | char disc_name[16]; 174 | char* disc_paths[9]; // up to 9 paths, Arc the Lad Collection is 7 discs 175 | 176 | // construct m3u path based on parent directory 177 | // essentially hasM3u() from MiniUI but we use the building blocks as well 178 | char m3u_path[256]; 179 | strcpy(m3u_path, rom_path); 180 | tmp = strrchr(m3u_path, '/') + 1; 181 | tmp[0] = '\0'; 182 | 183 | // path to parent directory 184 | char base_path[256]; // used below too when status==kItemSave 185 | strcpy(base_path, m3u_path); 186 | 187 | tmp = strrchr(m3u_path, '/'); 188 | tmp[0] = '\0'; 189 | 190 | // get parent directory name 191 | char dir_name[256]; 192 | tmp = strrchr(m3u_path, '/'); 193 | strcpy(dir_name, tmp); 194 | 195 | // dir_name is also our m3u file name 196 | tmp = m3u_path + strlen(m3u_path); 197 | strcpy(tmp, dir_name); 198 | 199 | // add extension 200 | tmp = m3u_path + strlen(m3u_path); 201 | strcpy(tmp, ".m3u"); 202 | 203 | if (exists(m3u_path)) { 204 | // share saves across multi-disc games 205 | strcpy(rom_file, dir_name); 206 | tmp = rom_file + strlen(rom_file); 207 | strcpy(tmp, ".m3u"); 208 | 209 | //read m3u file 210 | FILE* file = fopen(m3u_path, "r"); 211 | if (file) { 212 | char line[256]; 213 | while (fgets(line,256,file)!=NULL) { 214 | int len = strlen(line); 215 | if (len>0 && line[len-1]=='\n') { 216 | line[len-1] = 0; // trim newline 217 | len -= 1; 218 | if (len>0 && line[len-1]=='\r') { 219 | line[len-1] = 0; // trim Windows newline 220 | len -= 1; 221 | } 222 | } 223 | if (len==0) continue; // skip empty lines 224 | 225 | char disc_path[256]; 226 | strcpy(disc_path, base_path); 227 | tmp = disc_path + strlen(disc_path); 228 | strcpy(tmp, line); 229 | 230 | // found a valid disc path 231 | if (exists(disc_path)) { 232 | disc_paths[total_discs] = strdup(disc_path); 233 | // matched our current disc 234 | if (exactMatch(disc_path, rom_path)) { 235 | rom_disc = total_discs; 236 | disc = rom_disc; 237 | sprintf(disc_name, "Disc %i", disc+1); 238 | } 239 | total_discs += 1; 240 | } 241 | } 242 | fclose(file); 243 | } 244 | } 245 | 246 | // m3u path may change rom_file 247 | sprintf(slot_path, "%s/%s.txt", mmenu_dir, rom_file); 248 | if (exists(slot_path)) slot = getInt(slot_path); 249 | if (slot==8) slot = 0; 250 | 251 | if (requested_state==kRequestSave) { 252 | if (!optional_snapshot) optional_snapshot = SDL_GetVideoSurface(); 253 | 254 | char bmp_path[256]; 255 | sprintf(bmp_path, "%s/%s.%d.bmp", mmenu_dir, rom_file, slot); 256 | 257 | status = kStatusSaveSlot + slot; 258 | SDL_Surface* preview = createThumbnail(optional_snapshot); 259 | SDL_RWops* out = SDL_RWFromFile(bmp_path, "wb"); 260 | if (total_discs) { 261 | char* disc_path = disc_paths[disc]; 262 | putFile(txt_path, disc_path + strlen(base_path)); 263 | sprintf(bmp_path, "%s/%s.%d.bmp", mmenu_dir, rom_file, slot); 264 | } 265 | SDL_SaveBMP_RW(preview, out, 1); 266 | SDL_FreeSurface(preview); 267 | putInt(slot_path, slot); 268 | } 269 | else if (requested_state==kRequestLoad) { 270 | char save_path[256]; 271 | sprintf(save_path, save_path_template, slot); 272 | 273 | if (exists(save_path) && total_discs) { 274 | char slot_disc_name[256]; 275 | getFile(txt_path, slot_disc_name, 256); 276 | char slot_disc_path[256]; 277 | if (slot_disc_name[0]=='/') strcpy(slot_disc_path, slot_disc_name); 278 | else sprintf(slot_disc_path, "%s%s", base_path, slot_disc_name); 279 | char* disc_path = disc_paths[disc]; 280 | if (!exactMatch(slot_disc_path, disc_path)) { 281 | putFile(kChangeDiscPath, slot_disc_path); 282 | } 283 | } 284 | status = kStatusLoadSlot + slot; 285 | putInt(slot_path, slot); 286 | } 287 | 288 | for (int i=0; i0 && line[len-1]=='\n') { 369 | line[len-1] = 0; // trim newline 370 | len -= 1; 371 | if (len>0 && line[len-1]=='\r') { 372 | line[len-1] = 0; // trim Windows newline 373 | len -= 1; 374 | } 375 | } 376 | if (len==0) continue; // skip empty lines 377 | 378 | char disc_path[256]; 379 | strcpy(disc_path, base_path); 380 | tmp = disc_path + strlen(disc_path); 381 | strcpy(tmp, line); 382 | 383 | // found a valid disc path 384 | if (exists(disc_path)) { 385 | disc_paths[total_discs] = strdup(disc_path); 386 | // matched our current disc 387 | if (exactMatch(disc_path, rom_path)) { 388 | rom_disc = total_discs; 389 | disc = rom_disc; 390 | sprintf(disc_name, "Disc %i", disc+1); 391 | } 392 | total_discs += 1; 393 | } 394 | } 395 | fclose(file); 396 | } 397 | } 398 | 399 | // m3u path may change rom_file 400 | sprintf(slot_path, "%s/%s.txt", mmenu_dir, rom_file); 401 | getDisplayName(rom_file, rom_name); 402 | 403 | // cache static elements 404 | 405 | // NOTE: original screen copying logic 406 | // SDL_Surface* copy = SDL_CreateRGBSurface(SDL_SWSURFACE, Screen.width, Screen.height, 16, 0, 0, 0, 0); 407 | // SDL_BlitSurface(screen, NULL, copy, NULL); 408 | 409 | // NOTE: copying the screen to a new surface caused a 15fps drop in PocketSNES 410 | // on the 280M running stock OpenDingux after opening the menu, 411 | // tried ConvertSurface and DisplaySurface too 412 | // only this direct copy worked without tanking the framerate 413 | int copy_bytes = screen->h * screen->pitch; 414 | void* copy_pixels = malloc(copy_bytes); 415 | memcpy(copy_pixels, screen->pixels, copy_bytes); 416 | SDL_Surface* copy = SDL_CreateRGBSurfaceFrom(copy_pixels, screen->w,screen->h, screen->format->BitsPerPixel, screen->pitch, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask); 417 | 418 | SDL_Surface* cache = SDL_CreateRGBSurface(SDL_SWSURFACE, Screen.width, Screen.height, 16, 0, 0, 0, 0); 419 | SDL_BlitSurface(copy, NULL, cache, NULL); 420 | SDL_BlitSurface(overlay, NULL, cache, NULL); 421 | 422 | SDL_FillRect(cache, &(SDL_Rect){0,0,Screen.width,Screen.menu.bar_height}, 0); 423 | GFX_blitRule(cache, Screen.menu.rule.top_y); 424 | 425 | GFX_blitText(cache, rom_name, 1, Screen.menu.title.x, Screen.menu.title.y, Screen.menu.title.width, 1, 0); 426 | 427 | GFX_blitWindow(cache, Screen.menu.window.x, Screen.menu.window.y, Screen.menu.window.width, Screen.menu.window.height, 1); 428 | 429 | SDL_FillRect(cache, &(SDL_Rect){0,Screen.height-Screen.menu.bar_height,Screen.width,Screen.menu.bar_height}, 0); 430 | GFX_blitRule(cache, Screen.menu.rule.bottom_y); 431 | 432 | Input_reset(); 433 | 434 | int pink_rgb = SDL_MapRGB(screen->format, PINK_TRIAD); 435 | int gray_rgb = SDL_MapRGB(screen->format, DISABLED_TRIAD); 436 | SDL_Color pink = (SDL_Color){PINK_TRIAD}; 437 | SDL_Color white = (SDL_Color){WHITE_TRIAD}; 438 | 439 | int status = kStatusContinue; 440 | int selected = 0; // resets every launch 441 | if (exists(slot_path)) slot = getInt(slot_path); 442 | if (slot==8) slot = 0; 443 | 444 | // inline functions? okay. 445 | void SystemRequest(MenuRequestState request) { 446 | autosave(); 447 | putFile(kAutoResumePath, rom_path + strlen(Paths.rootDir)); 448 | if (request==kRequestSleep) { 449 | fauxSleep(); 450 | unlink(kAutoResumePath); 451 | } 452 | else powerOff(); 453 | } 454 | 455 | if (requested_state!=kRequestMenu) { // sleep or poweroff 456 | if (disable_poweroff && requested_state==kRequestPowerOff) return kStatusContinue; 457 | SystemRequest(requested_state); 458 | if (requested_state==kRequestPowerOff) return kStatusPowerOff; 459 | } 460 | 461 | char save_path[256]; 462 | char bmp_path[256]; 463 | char txt_path[256]; 464 | int save_exists = 0; 465 | int preview_exists = 0; 466 | 467 | int quit = 0; 468 | int dirty = 1; 469 | int show_setting = 0; // 1=brightness,2=volume 470 | int setting_value = 0; 471 | int setting_min = 0; 472 | int setting_max = 0; 473 | unsigned long setting_start = 0; 474 | unsigned long cancel_start = SDL_GetTicks(); 475 | int was_charging = isCharging(); 476 | unsigned long charge_start = SDL_GetTicks(); 477 | unsigned long power_start = 0; 478 | while (!quit) { 479 | unsigned long frame_start = SDL_GetTicks(); 480 | int select_was_pressed = Input_isPressed(kButtonSelect); // rs90-only 481 | 482 | Input_poll(); 483 | 484 | if (Input_justPressed(kButtonUp)) { 485 | selected -= 1; 486 | if (selected<0) selected += kItemCount; 487 | dirty = 1; 488 | } 489 | else if (Input_justPressed(kButtonDown)) { 490 | selected += 1; 491 | if (selected>=kItemCount) selected -= kItemCount; 492 | dirty = 1; 493 | } 494 | else if (Input_justPressed(kButtonLeft)) { 495 | if (total_discs>1 && selected==kItemContinue) { 496 | disc -= 1; 497 | if (disc<0) disc += total_discs; 498 | dirty = 1; 499 | sprintf(disc_name, "Disc %i", disc+1); 500 | } 501 | else if (selected==kItemSave || selected==kItemLoad) { 502 | slot -= 1; 503 | if (slot<0) slot += kSlotCount; 504 | dirty = 1; 505 | } 506 | } 507 | else if (Input_justPressed(kButtonRight)) { 508 | if (total_discs>1 && selected==kItemContinue) { 509 | disc += 1; 510 | if (disc==total_discs) disc -= total_discs; 511 | dirty = 1; 512 | sprintf(disc_name, "Disc %i", disc+1); 513 | } 514 | else if (selected==kItemSave || selected==kItemLoad) { 515 | slot += 1; 516 | if (slot>=kSlotCount) slot -= kSlotCount; 517 | dirty = 1; 518 | } 519 | } 520 | 521 | if (dirty && state_support && (selected==kItemSave || selected==kItemLoad)) { 522 | sprintf(save_path, save_path_template, slot); 523 | sprintf(bmp_path, "%s/%s.%d.bmp", mmenu_dir, rom_file, slot); 524 | sprintf(txt_path, "%s/%s.%d.txt", mmenu_dir, rom_file, slot); 525 | 526 | save_exists = exists(save_path); 527 | preview_exists = save_exists && exists(bmp_path); 528 | // printf("save_path: %s (%i)\n", save_path, save_exists); 529 | // printf("bmp_path: %s (%i)\n", bmp_path, preview_exists); 530 | } 531 | 532 | if ((Input_justPressed(kButtonB) || Input_justReleased(kButtonMenu)) && !dirty && show_setting == 0) { 533 | status = kStatusContinue; 534 | quit = 1; 535 | } 536 | else if (Input_justPressed(kButtonA)) { 537 | switch(selected) { 538 | case kItemContinue: 539 | if (total_discs && rom_disc!=disc) { 540 | status = kStatusChangeDisc; 541 | char* disc_path = disc_paths[disc]; 542 | putFile(kChangeDiscPath, disc_path); 543 | } 544 | else { 545 | status = kStatusContinue; 546 | } 547 | quit = 1; 548 | break; 549 | 550 | // TODO: this code is duplicated in SaveLoad() 551 | case kItemSave: 552 | if (state_support) { 553 | status = kStatusSaveSlot + slot; 554 | SDL_Surface* preview = createThumbnail(optional_snapshot ? optional_snapshot : copy); 555 | SDL_RWops* out = SDL_RWFromFile(bmp_path, "wb"); 556 | if (total_discs) { 557 | char* disc_path = disc_paths[disc]; 558 | putFile(txt_path, disc_path + strlen(base_path)); 559 | sprintf(bmp_path, "%s/%s.%d.bmp", mmenu_dir, rom_file, slot); 560 | } 561 | SDL_SaveBMP_RW(preview, out, 1); 562 | SDL_FreeSurface(preview); 563 | putInt(slot_path, slot); 564 | quit = 1; 565 | } 566 | break; 567 | case kItemLoad: 568 | if (state_support) { 569 | if (save_exists && total_discs) { 570 | char slot_disc_name[256]; 571 | getFile(txt_path, slot_disc_name, 256); 572 | char slot_disc_path[256]; 573 | if (slot_disc_name[0]=='/') strcpy(slot_disc_path, slot_disc_name); 574 | else sprintf(slot_disc_path, "%s%s", base_path, slot_disc_name); 575 | char* disc_path = disc_paths[disc]; 576 | if (!exactMatch(slot_disc_path, disc_path)) { 577 | putFile(kChangeDiscPath, slot_disc_path); 578 | } 579 | } 580 | status = kStatusLoadSlot + slot; 581 | putInt(slot_path, slot); 582 | quit = 1; 583 | } 584 | break; 585 | case kItemAdvanced: 586 | status = is_simple ? kStatusResetGame : kStatusOpenMenu; 587 | quit = 1; 588 | break; 589 | case kItemExitGame: 590 | status = kStatusExitGame; 591 | quit = 1; 592 | break; 593 | } 594 | if (quit) break; 595 | } 596 | 597 | unsigned long now = SDL_GetTicks(); 598 | if (Input_anyPressed()) cancel_start = now; 599 | 600 | #define kChargeDelay 1000 601 | if (dirty || now-charge_start>=kChargeDelay) { 602 | int is_charging = isCharging(); 603 | if (was_charging!=is_charging) { 604 | was_charging = is_charging; 605 | dirty = 1; 606 | } 607 | charge_start = now; 608 | } 609 | 610 | if (!disable_poweroff && power_start && now-power_start>=1000) { 611 | SystemRequest(kRequestPowerOff); 612 | status = kStatusPowerOff; 613 | quit = 1; 614 | } 615 | if (Input_justPressed(kButtonSleep)) { 616 | power_start = now; 617 | } 618 | 619 | #define kSleepDelay 30000 620 | if (now-cancel_start>=kSleepDelay && preventAutosleep()) cancel_start = now; 621 | 622 | if (now-cancel_start>=kSleepDelay || Input_justReleased(kButtonSleep)) // || Input_justPressed(kButtonMenu)) 623 | { 624 | SystemRequest(kRequestSleep); 625 | cancel_start = SDL_GetTicks(); 626 | power_start = 0; 627 | dirty = 1; 628 | } 629 | 630 | int old_setting = show_setting; 631 | int old_value = setting_value; 632 | show_setting = 0; 633 | if (Input_isPressed(kButtonStart) && Input_isPressed(kButtonSelect)) { 634 | // buh 635 | } 636 | else if (Input_isPressed(kButtonMenu) && (Input_isPressed(kButtonVolDn) || Input_isPressed(kButtonVolUp))) { 637 | show_setting = 1; 638 | setting_value = GetBrightness(); 639 | setting_min = MIN_BRIGHTNESS; 640 | setting_max = MAX_BRIGHTNESS; 641 | } 642 | else if (Input_isPressed(kButtonMenu) && old_setting == 1) { 643 | show_setting = 1; 644 | setting_value = GetBrightness(); 645 | setting_min = MIN_BRIGHTNESS; 646 | setting_max = MAX_BRIGHTNESS; 647 | } 648 | else if (Input_isPressed(kButtonVolDn) || Input_isPressed(kButtonVolUp)) { 649 | show_setting = 2; 650 | setting_value = GetVolume(); 651 | setting_min = MIN_VOLUME; 652 | setting_max = MAX_VOLUME; 653 | } 654 | 655 | if (old_setting && !show_setting) setting_start = SDL_GetTicks(); 656 | 657 | if (old_value != setting_value) dirty = 1; 658 | else if (!old_setting && show_setting) dirty = 1; 659 | else if (setting_start > 0 && SDL_GetTicks() - setting_start > 500) { 660 | dirty = 1; 661 | setting_start = 0; 662 | } 663 | 664 | if (dirty) { 665 | dirty = 0; 666 | SDL_BlitSurface(cache, NULL, screen, NULL); 667 | GFX_blitBattery(screen, Screen.menu.battery.x, Screen.menu.battery.y); 668 | 669 | if (show_setting) { 670 | GFX_blitSettings(screen, Screen.menu.settings.x, Screen.menu.settings.y, show_setting==1?0:(setting_value>0?1:2), setting_value,setting_min,setting_max); 671 | } 672 | 673 | // list 674 | SDL_Surface* text; 675 | for (int i=0; i1 && i==kItemContinue)) { 688 | SDL_BlitSurface(i==selected?arrow_highlighted:arrow, NULL, screen, &(SDL_Rect){Screen.menu.window.x+Screen.menu.window.width-(arrow->w+Screen.menu.arrow.ox),Screen.menu.list.y+(i*Screen.menu.list.line_height)+Screen.menu.arrow.oy}); 689 | } 690 | } 691 | 692 | // disc change 693 | if (total_discs>1 && selected==kItemContinue) { 694 | GFX_blitWindow(screen, Screen.menu.preview.x, Screen.menu.preview.y, Screen.menu.preview.width, Screen.menu.list.row_height+(Screen.menu.disc.oy*2), 1); 695 | GFX_blitText(screen, disc_name, 2, Screen.menu.preview.x+Screen.menu.disc.ox, Screen.menu.list.y+Screen.menu.list.oy, 0, 1, 0); 696 | } 697 | // slot preview 698 | else if (state_support && (selected==kItemSave || selected==kItemLoad)) { 699 | // preview window 700 | SDL_Rect preview_rect = {Screen.menu.preview.x+Screen.menu.preview.inset,Screen.menu.preview.y+Screen.menu.preview.inset}; 701 | GFX_blitWindow(screen, Screen.menu.preview.x, Screen.menu.preview.y, Screen.menu.preview.width, Screen.menu.preview.height, 1); 702 | 703 | if (preview_exists) { // has save, has preview 704 | SDL_Surface* preview = IMG_Load(bmp_path); 705 | if (!preview) printf("IMG_Load: %s\n", IMG_GetError()); 706 | SDL_BlitSurface(preview, NULL, screen, &preview_rect); 707 | SDL_FreeSurface(preview); 708 | } 709 | else { 710 | int hw = Screen.width / 2; 711 | int hh = Screen.height / 2; 712 | SDL_FillRect(screen, &(SDL_Rect){Screen.menu.preview.x+Screen.menu.preview.inset,Screen.menu.preview.y+Screen.menu.preview.inset,hw,hh}, 0); 713 | if (save_exists) { // has save but no preview 714 | SDL_BlitSurface(no_preview, NULL, screen, &(SDL_Rect){ 715 | Screen.menu.preview.x+Screen.menu.preview.inset+(hw-no_preview->w)/2, 716 | Screen.menu.preview.y+Screen.menu.preview.inset+(hh-no_preview->h)/2 717 | }); 718 | } 719 | else { // no save 720 | SDL_BlitSurface(empty_slot, NULL, screen, &(SDL_Rect){ 721 | Screen.menu.preview.x+Screen.menu.preview.inset+(hw-empty_slot->w)/2, 722 | Screen.menu.preview.y+Screen.menu.preview.inset+(hh-empty_slot->h)/2 723 | }); 724 | } 725 | } 726 | 727 | SDL_BlitSurface(slot_overlay, NULL, screen, &preview_rect); 728 | SDL_BlitSurface(slot_dots, NULL, screen, &(SDL_Rect){Screen.menu.slots.x,Screen.menu.slots.y}); 729 | SDL_BlitSurface(slot_dot_selected, NULL, screen, &(SDL_Rect){Screen.menu.slots.x+(Screen.menu.slots.ox*slot),Screen.menu.slots.y}); 730 | } 731 | 732 | GFX_blitPill(screen, HINT_SLEEP, "SLEEP", Screen.buttons.left, Screen.menu.buttons.top); 733 | // TODO: change ACT to OKAY? 734 | int button_width = GFX_blitButton(screen, "A", "ACT", -Screen.buttons.right, Screen.menu.buttons.top, Screen.button.text.ox_A); 735 | GFX_blitButton(screen, "B", "BACK", -(Screen.buttons.right+button_width+Screen.buttons.gutter),Screen.menu.buttons.top, Screen.button.text.ox_B); 736 | // TODO: /can this be cached? 737 | 738 | SDL_Flip(screen); 739 | } 740 | 741 | // slow down to 60fps 742 | unsigned long frame_duration = SDL_GetTicks() - frame_start; 743 | #define kTargetFrameDuration 17 744 | if (frame_durationpixels was manually malloc'd so it must be manually freed too 756 | SDL_FreeSurface(copy); 757 | free(copy_pixels); 758 | 759 | SDL_EnableKeyRepeat(0,0); 760 | 761 | // if (SDL_MUSTLOCK(screen)) SDL_LockSurface(screen); // fix for regba? 762 | for (int i=0; i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #include "msettings.h" 18 | 19 | /////////////////////////////////////// 20 | 21 | typedef struct Settings { 22 | int version; // future proofing 23 | int brightness; 24 | int unused1; 25 | int speaker; 26 | int unused[4]; // for future use 27 | } Settings; 28 | static Settings DefaultSettings = { 29 | .version = 1, 30 | .brightness = 2, 31 | .speaker = 20, 32 | }; 33 | static Settings* settings; 34 | 35 | #define SHM_KEY "/SharedSettings" 36 | #define MI_AO_SETMUTE 0x4008690d 37 | static char SettingsPath[256]; 38 | static int shm_fd = -1; 39 | static int is_host = 0; 40 | static int shm_size = sizeof(Settings); 41 | 42 | void InitSettings(void) { 43 | sprintf(SettingsPath, "%s/msettings.bin", getenv("USERDATA_PATH")); 44 | 45 | shm_fd = shm_open(SHM_KEY, O_RDWR | O_CREAT | O_EXCL, 0644); // see if it exists 46 | if (shm_fd==-1 && errno==EEXIST) { // already exists 47 | puts("Settings client"); 48 | shm_fd = shm_open(SHM_KEY, O_RDWR, 0644); 49 | settings = mmap(NULL, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); 50 | } 51 | else { // host 52 | puts("Settings host"); 53 | is_host = 1; 54 | // we created it so set initial size and populate 55 | ftruncate(shm_fd, shm_size); 56 | settings = mmap(NULL, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); 57 | 58 | int fd = open(SettingsPath, O_RDONLY); 59 | if (fd>=0) { 60 | read(fd, settings, shm_size); 61 | // TODO: use settings->version for future proofing 62 | close(fd); 63 | } 64 | else { 65 | // load defaults 66 | memcpy(settings, &DefaultSettings, shm_size); 67 | } 68 | } 69 | printf("brightness: %i\nspeaker: %i\n", settings->brightness, settings->speaker); 70 | 71 | MI_AO_Enable(0); 72 | MI_AO_EnableChn(0,0); 73 | SetVolume(GetVolume()); 74 | if (GetVolume()==0) SetMute(1); 75 | else SetMute(0); 76 | SetBrightness(GetBrightness()); 77 | } 78 | void QuitSettings(void) { 79 | munmap(settings, shm_size); 80 | if (is_host) shm_unlink(SHM_KEY); 81 | } 82 | static inline void SaveSettings(void) { 83 | int fd = open(SettingsPath, O_CREAT|O_WRONLY, 0644); 84 | if (fd>=0) { 85 | write(fd, settings, shm_size); 86 | close(fd); 87 | sync(); 88 | } 89 | } 90 | 91 | int GetBrightness(void) { // 0-10 92 | return settings->brightness; 93 | } 94 | void SetBrightness(int value) { 95 | if (value > 2) { 96 | SetRawBrightness(pow(value,2)); 97 | } else { 98 | SetRawBrightness(3+(value*2)); 99 | } 100 | settings->brightness = value; 101 | SaveSettings(); 102 | } 103 | 104 | int GetVolume(void) { // 0-20 105 | return settings->speaker; 106 | } 107 | void SetVolume(int value) { 108 | int raw = -60 + value * 3; 109 | SetRawVolume(raw); 110 | settings->speaker = value; 111 | SaveSettings(); 112 | } 113 | 114 | void SetRawBrightness(int val) { 115 | int fd = open("/sys/class/pwm/pwmchip0/pwm0/duty_cycle", O_WRONLY); 116 | if (fd>=0) { 117 | dprintf(fd,"%d",val); 118 | close(fd); 119 | } 120 | } 121 | void SetRawVolume(int val) { 122 | MI_AO_SetVolume(0,val); 123 | } 124 | 125 | void SetMute(int mute) { 126 | int fd = open("/dev/mi_ao", O_RDWR); 127 | if (fd >= 0) { 128 | int buf2[] = {0, mute}; 129 | uint64_t buf1[] = {sizeof(buf2), (uintptr_t)buf2}; 130 | 131 | ioctl(fd, MI_AO_SETMUTE, buf1); 132 | close(fd); 133 | } 134 | } 135 | 136 | int GetJack(void) { 137 | return 0; 138 | } 139 | void SetJack(int value) { 140 | // buh 141 | } -------------------------------------------------------------------------------- /src/libmsettings/msettings.h: -------------------------------------------------------------------------------- 1 | #ifndef msettings_h__ 2 | #define msettings_h__ 3 | 4 | void InitSettings(void); 5 | void QuitSettings(void); 6 | 7 | int GetBrightness(void); 8 | int GetVolume(void); 9 | 10 | void SetRawBrightness(int value); // 0-100 11 | void SetRawVolume(int value); // -60-0 12 | void SetMute(int mute); // 0-1 13 | 14 | void SetBrightness(int value); // 0-10 15 | void SetVolume(int value); // 0-20 16 | 17 | int GetJack(void); 18 | void SetJack(int value); // 0-1 19 | 20 | #endif // msettings_h__ 21 | -------------------------------------------------------------------------------- /src/lumon/lumon.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main(void) { 11 | MI_DISP_DEV dev = 0; 12 | 13 | MI_DISP_PubAttr_t attrs; 14 | memset(&attrs,0,sizeof(MI_DISP_PubAttr_t)); 15 | MI_DISP_GetPubAttr(dev,&attrs); 16 | 17 | attrs.eIntfType = E_MI_DISP_INTF_LCD; 18 | attrs.eIntfSync = E_MI_DISP_OUTPUT_USER; 19 | MI_DISP_SetPubAttr(dev,&attrs); 20 | 21 | MI_DISP_Enable(dev); 22 | 23 | MI_DISP_LcdParam_t params; 24 | memset(¶ms,0,sizeof(MI_DISP_LcdParam_t)); 25 | MI_DISP_GetLcdParam(dev, ¶ms); 26 | 27 | params.stCsc.u32Luma = 45; 28 | params.stCsc.u32Contrast = 50; 29 | params.stCsc.u32Hue = 50; 30 | params.stCsc.u32Saturation = 45; 31 | params.u32Sharpness = 0; 32 | 33 | MI_DISP_SetLcdParam(dev,¶ms); 34 | 35 | while (1) pause(); 36 | 37 | // MI_DISP_Disable(dev); 38 | } 39 | -------------------------------------------------------------------------------- /src/lumon/makefile: -------------------------------------------------------------------------------- 1 | ifeq (,$(CROSS_COMPILE)) 2 | $(error missing CROSS_COMPILE for this toolchain) 3 | endif 4 | 5 | TARGET = lumon 6 | 7 | CC = $(CROSS_COMPILE)gcc 8 | CFLAGS = -marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7ve 9 | LDFLAGS = -Os -lmi_sys -lmi_disp 10 | 11 | all: 12 | $(CC) $(TARGET).c -o $(TARGET) $(CFLAGS) $(LDFLAGS) 13 | clean: 14 | rm -f $(TARGET) -------------------------------------------------------------------------------- /src/miniui/makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build 2 | .PHONY: clean 3 | 4 | ########################################################### 5 | 6 | ifeq (,$(PLATFORM)) 7 | PLATFORM=$(UNION_PLATFORM) 8 | endif 9 | 10 | ifeq (,$(PLATFORM)) 11 | $(error please specify PLATFORM, eg. make PLATFORM=trimui) 12 | endif 13 | ifeq (,$(CROSS_COMPILE)) 14 | $(error missing CROSS_COMPILE for this toolchain) 15 | endif 16 | 17 | ########################################################### 18 | 19 | CC = $(CROSS_COMPILE)gcc 20 | SYSROOT := $(shell $(CC) --print-sysroot) 21 | INCLUDEDIR = $(SYSROOT)/usr/include 22 | CFLAGS = -I$(INCLUDEDIR) -I. -I../common -DPLATFORM_$(shell echo $(PLATFORM) | tr a-z A-Z) -std=gnu99 23 | LDFLAGS = -s -lSDL -lSDL_image -lSDL_ttf -lmsettings -lrt -lz -lm 24 | OPTM=-O3 25 | 26 | build: 27 | $(CC) -o MiniUI main.c ../common/common.c $(CFLAGS) $(LDFLAGS) $(OPTM) -ldl -rdynamic 28 | clean: 29 | rm -f MiniUI -------------------------------------------------------------------------------- /src/progressui/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "../common/common.h" 12 | 13 | #define UPDATE_DIR "/tmp/" 14 | #define UPDATE_TXT "update_progress.txt" 15 | 16 | #define EVENT_SIZE ( sizeof (struct inotify_event) ) 17 | #define BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) ) 18 | 19 | int main (int argc, char *argv[]) { 20 | int fd = inotify_init(); 21 | int wd = inotify_add_watch( fd, UPDATE_DIR, IN_MODIFY | IN_CREATE ); 22 | 23 | SDL_Init(SDL_INIT_VIDEO); 24 | SDL_ShowCursor(0); 25 | InitSettings(); 26 | 27 | SDL_Surface* screen = SDL_SetVideoMode(Screen.width, Screen.height, 16, SDL_HWSURFACE | SDL_DOUBLEBUF); 28 | 29 | SDL_Surface* progress_bar_empty = GFX_loadImage("progress-bar-empty.png"); 30 | SDL_Surface* progress_bar_full = GFX_loadImage("progress-bar-full.png"); 31 | 32 | GFX_init(); 33 | GFX_ready(); 34 | 35 | int done = 0; 36 | int progress = -1; 37 | char msg[256]; 38 | void updateProgress(void) { 39 | char new_msg[256]; 40 | getFile(UPDATE_DIR UPDATE_TXT, new_msg, 256); 41 | 42 | trimTrailingNewlines(new_msg); 43 | // printf("\t[%s]\n", new_msg); fflush(stdout); 44 | 45 | if (strlen(new_msg)==0) return; 46 | 47 | if (exactMatch(new_msg, "quit")) { 48 | done = 1; 49 | return; 50 | } 51 | 52 | if (exactMatch(new_msg, msg)) return; 53 | char* tmp = strchr(new_msg, ' '); 54 | // TODO: this doesn't do what I think it will (update message without updating progress bar) 55 | if (tmp) { 56 | tmp[0] = '\0'; 57 | progress = atoi(new_msg); 58 | if (progress>100) progress = 100; 59 | strcpy(msg, tmp+1); 60 | } 61 | else { 62 | strcpy(msg, new_msg); 63 | } 64 | 65 | // printf("%f: %s\n", progress/100.0, msg); fflush(stdout); 66 | 67 | SDL_FillRect(screen, NULL, 0); 68 | if (progress>-1) { 69 | SDL_BlitSurface(progress_bar_empty, NULL, screen, &(SDL_Rect){120,236}); 70 | SDL_BlitSurface(progress_bar_full, &(SDL_Rect){0,0,progress*4,8}, screen, &(SDL_Rect){120,236}); 71 | } 72 | GFX_blitBodyCopy(screen, msg, 0,80, Screen.width,Screen.height-80); 73 | SDL_Flip(screen); 74 | } 75 | 76 | if (exists(UPDATE_DIR UPDATE_TXT)) updateProgress(); // don't miss the first message 77 | 78 | while (!done) { 79 | 80 | struct inotify_event *event; 81 | char buffer[BUF_LEN]; 82 | int length = read( fd, buffer, BUF_LEN ); // blocks 83 | 84 | for(int i=0; ilen) { 85 | event = (struct inotify_event *)&buffer[i]; 86 | 87 | if (!event->len) continue; 88 | if (!(event->mask & IN_CREATE) && !(event->mask & IN_MODIFY)) continue; 89 | if (!exactMatch(event->name, UPDATE_TXT)) continue; 90 | 91 | updateProgress(); 92 | } 93 | } 94 | 95 | inotify_rm_watch(fd, wd); 96 | close(fd); 97 | 98 | unlink(UPDATE_DIR UPDATE_TXT); 99 | 100 | SDL_FillRect(screen, NULL, 0); 101 | SDL_Flip(screen); 102 | 103 | SDL_FreeSurface(progress_bar_empty); 104 | SDL_FreeSurface(progress_bar_full); 105 | 106 | GFX_quit(); 107 | SDL_Quit(); 108 | QuitSettings(); 109 | 110 | return 0; 111 | } -------------------------------------------------------------------------------- /src/progressui/makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build 2 | .PHONY: clean 3 | 4 | ########################################################### 5 | 6 | ifeq (,$(PLATFORM)) 7 | PLATFORM=$(UNION_PLATFORM) 8 | endif 9 | 10 | ifeq (,$(PLATFORM)) 11 | $(error please specify PLATFORM, eg. make PLATFORM=trimui) 12 | endif 13 | ifeq (,$(CROSS_COMPILE)) 14 | $(error missing CROSS_COMPILE for this toolchain) 15 | endif 16 | 17 | ########################################################### 18 | 19 | CC = $(CROSS_COMPILE)gcc 20 | SYSROOT := $(shell $(CC) --print-sysroot) 21 | INCLUDEDIR = $(SYSROOT)/usr/include 22 | CFLAGS = -I$(INCLUDEDIR) -I. -I../common -DPLATFORM_$(shell echo $(PLATFORM) | tr a-z A-Z) -std=gnu99 23 | LDFLAGS = -s -lSDL -lSDL_image -lSDL_ttf -lmsettings -lpthread -lrt -lz -lm 24 | OPTM=-O3 25 | 26 | build: 27 | $(CC) -o progressui main.c ../common/common.c $(CFLAGS) $(LDFLAGS) $(OPTM) -ldl -rdynamic 28 | clean: 29 | rm -f progressui -------------------------------------------------------------------------------- /src/progressui/progress.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo $@ > /tmp/update_progress.txt -------------------------------------------------------------------------------- /src/say/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define PINK_TRIAD 0xd4,0x98,0xab 12 | #define kTextBoxMaxRows 8 13 | #define kTextLineLength 256 14 | #define kLineHeight 48 15 | 16 | #define kMiniUIFont "/mnt/SDCARD/.system/res/BPreplayBold-unhinted.otf" 17 | #define kStockFont "/customer/app/BPreplayBold.otf" 18 | 19 | static void blit(void* _dst, int dst_w, int dst_h, void* _src, int src_w, int src_h, int ox, int oy) { 20 | uint8_t* dst = (uint8_t*)_dst; 21 | uint8_t* src = (uint8_t*)_src; 22 | 23 | oy += kLineHeight - src_h; 24 | 25 | for (int y=0; y0.1) { 31 | *(dst_row+0) = *(src_row+0) * a; 32 | *(dst_row+1) = *(src_row+1) * a; 33 | *(dst_row+2) = *(src_row+2) * a; 34 | *(dst_row+3) = 0xff; 35 | } 36 | dst_row -= 4; 37 | src_row += 4; 38 | } 39 | } 40 | } 41 | 42 | int main(int argc , char* argv[]) { 43 | if (argc<2) { 44 | puts("Usage: say \"message\""); 45 | return EXIT_SUCCESS; 46 | } 47 | 48 | char* path = NULL; 49 | if (access(kMiniUIFont, F_OK)==0) path = kMiniUIFont; 50 | else if (access(kStockFont, F_OK)==0) path = kStockFont; 51 | if (!path) return 0; 52 | 53 | char str[kTextBoxMaxRows*kTextLineLength]; 54 | strncpy(str,argv[1],kTextBoxMaxRows*kTextLineLength); 55 | 56 | int fb0_fd = open("/dev/fb0", O_RDWR); 57 | struct fb_var_screeninfo vinfo; 58 | ioctl(fb0_fd, FBIOGET_VSCREENINFO, &vinfo); 59 | int map_size = vinfo.xres * vinfo.yres * (vinfo.bits_per_pixel / 8); // 640x480x4 60 | char* fb0_map = (char*)mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb0_fd, 0); 61 | 62 | TTF_Init(); 63 | TTF_Font* font = TTF_OpenFont(path, 32); 64 | 65 | int width = 640; 66 | int height = 480; 67 | SDL_Color pink = {PINK_TRIAD}; 68 | SDL_Surface* text; 69 | char* rows[kTextBoxMaxRows]; 70 | int row_count = 0; 71 | 72 | char* tmp; 73 | rows[row_count++] = str; 74 | while ((tmp=strchr(rows[row_count-1], '\n'))!=NULL) { 75 | if (row_count+1>=kTextBoxMaxRows) break; 76 | rows[row_count++] = tmp+1; 77 | } 78 | 79 | int rendered_height = kLineHeight * row_count; 80 | int y = (height - rendered_height) / 2; 81 | 82 | char line[kTextLineLength]; 83 | 84 | for (int i=0; iw) / 2; 99 | blit(fb0_map,width,height,text->pixels,text->w,text->h,x,y); 100 | SDL_FreeSurface(text); 101 | } 102 | y += kLineHeight; 103 | } 104 | 105 | TTF_CloseFont(font); 106 | TTF_Quit(); 107 | munmap(fb0_map, map_size); 108 | close(fb0_fd); 109 | 110 | return EXIT_SUCCESS; 111 | } 112 | -------------------------------------------------------------------------------- /src/say/makefile: -------------------------------------------------------------------------------- 1 | ifeq (,$(CROSS_COMPILE)) 2 | $(error missing CROSS_COMPILE for this toolchain) 3 | endif 4 | 5 | TARGET = say 6 | 7 | CC = $(CROSS_COMPILE)gcc 8 | CFLAGS = -marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7ve 9 | LDFLAGS = -lSDL -lSDL_image -lSDL_ttf 10 | 11 | all: 12 | $(CC) main.c -o $(TARGET) $(CFLAGS) $(LDFLAGS) 13 | clean: 14 | rm -f $(TARGET) -------------------------------------------------------------------------------- /src/show/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main(int argc , char* argv[]) { 11 | if (argc<2) { 12 | puts("Usage: show image.png"); 13 | return 0; 14 | } 15 | 16 | char path[256]; 17 | if (strchr(argv[1], '/')==NULL) sprintf(path, "/mnt/SDCARD/.system/res/%s", argv[1]); 18 | else strncpy(path,argv[1],256); 19 | 20 | if (access(path, F_OK)!=0) return 0; // nothing to show :( 21 | 22 | int fb0_fd = open("/dev/fb0", O_RDWR); 23 | struct fb_var_screeninfo vinfo; 24 | ioctl(fb0_fd, FBIOGET_VSCREENINFO, &vinfo); 25 | int map_size = vinfo.xres * vinfo.yres * (vinfo.bits_per_pixel / 8); // 640x480x4 26 | char* fb0_map = (char*)mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb0_fd, 0); 27 | memset(fb0_map, 0, map_size); // clear screen 28 | 29 | SDL_Surface* img = IMG_Load(path); // 24-bit opaque png 30 | 31 | uint8_t* dst = (uint8_t*)fb0_map; // rgba 32 | uint8_t* src = (uint8_t*)img->pixels; // bgr 33 | src += ((img->h * img->w) - 1) * 3; 34 | for (int y=0; yh; y++) { 35 | for (int x=0; xw; x++) { 36 | *(dst+0) = *(src+2); // r 37 | *(dst+1) = *(src+1); // g 38 | *(dst+2) = *(src+0); // b 39 | *(dst+3) = 0xf; // alpha 40 | dst += 4; 41 | src -= 3; 42 | } 43 | } 44 | SDL_FreeSurface(img); 45 | 46 | munmap(fb0_map, map_size); 47 | close(fb0_fd); 48 | 49 | return EXIT_SUCCESS; 50 | } 51 | -------------------------------------------------------------------------------- /src/show/makefile: -------------------------------------------------------------------------------- 1 | ifeq (,$(CROSS_COMPILE)) 2 | $(error missing CROSS_COMPILE for this toolchain) 3 | endif 4 | 5 | TARGET = show 6 | 7 | CC = $(CROSS_COMPILE)gcc 8 | CFLAGS = -marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7ve 9 | LDFLAGS = -lSDL -lSDL_image 10 | 11 | all: 12 | $(CC) main.c -o $(TARGET) $(CFLAGS) $(LDFLAGS) 13 | clean: 14 | rm -f $(TARGET) -------------------------------------------------------------------------------- /third-party/latency_reduction/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = as_preload.so 2 | 3 | CC = $(CROSS_COMPILE)gcc 4 | 5 | SOURCES = . 6 | CFILES = $(foreach dir, $(SOURCES), $(wildcard $(dir)/*.c)) 7 | 8 | CFLAGS = -Os -marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7ve+simd 9 | CFLAGS += -fPIC -Wall 10 | LDFLAGS = -shared -ldl -s 11 | 12 | $(TARGET): $(CFILES) 13 | $(CC) $(CFLAGS) $(LDFLAGS) $(CFILES) -o $@ 14 | 15 | clean: 16 | rm -f $(TARGET) 17 | -------------------------------------------------------------------------------- /third-party/latency_reduction/audioserver.mod: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpndable/DotUI/35346971efbb0c261c5042ee2cfbc283fc53bfbb/third-party/latency_reduction/audioserver.mod -------------------------------------------------------------------------------- /third-party/latency_reduction/credits.txt: -------------------------------------------------------------------------------- 1 | created by eggs for the Miyoo Mini: 2 | https://www.dropbox.com/sh/hqcsr1h1d7f8nr3/AABtSOygIX_e4mio3rkLetWTa?preview=latency_reduction.zip -------------------------------------------------------------------------------- /third-party/latency_reduction/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #define FREQ 48000 9 | #define BUSY_THRESHOLD ((FREQ<<2)/(1000/20)) // 20ms 10 | 11 | MI_S32 MI_AO_SendFrame(MI_AUDIO_DEV AoDevId, MI_AO_CHN AoChn, MI_AUDIO_Frame_t *pstData, MI_S32 s32MilliSec) { 12 | static void* mi_ao_handle = NULL; 13 | static MI_S32 (*_MI_AO_SendFrame)(MI_AUDIO_DEV AoDevId, MI_AO_CHN AoChn, MI_AUDIO_Frame_t *pstData, MI_S32 s32MilliSec); 14 | static MI_S32 (*_MI_AO_QueryChnStat)(MI_AUDIO_DEV AoDevId , MI_AO_CHN AoChn, MI_AO_ChnState_t *pstStatus); 15 | 16 | if (!mi_ao_handle) { 17 | mi_ao_handle = dlopen("/config/lib/libmi_ao.so", RTLD_LAZY); 18 | _MI_AO_SendFrame = dlsym(mi_ao_handle, "MI_AO_SendFrame"); 19 | _MI_AO_QueryChnStat = dlsym(mi_ao_handle, "MI_AO_QueryChnStat"); 20 | } 21 | 22 | MI_S32 ret = _MI_AO_SendFrame(AoDevId, AoChn, pstData, 0); 23 | 24 | if (s32MilliSec) { 25 | MI_AO_ChnState_t status; 26 | _MI_AO_QueryChnStat(AoDevId, AoChn, &status); 27 | if (status.u32ChnBusyNum > BUSY_THRESHOLD) { 28 | useconds_t usleepclock = (uint64_t)(status.u32ChnBusyNum - BUSY_THRESHOLD) * 1000000 / (FREQ << 2); 29 | if (usleepclock) usleep(usleepclock); 30 | } 31 | } 32 | 33 | return ret; 34 | } 35 | -------------------------------------------------------------------------------- /third-party/logotweak/credits.txt: -------------------------------------------------------------------------------- 1 | created by eggs for the Miyoo Mini: 2 | https://www.dropbox.com/sh/hqcsr1h1d7f8nr3/AABtSOygIX_e4mio3rkLetWTa?preview=logotweak.zip -------------------------------------------------------------------------------- /third-party/logotweak/logomake/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = logomake 2 | 3 | CC = $(CROSS_COMPILE)gcc 4 | 5 | SOURCES = . 6 | CFILES = $(foreach dir, $(SOURCES), $(wildcard $(dir)/*.c)) 7 | OFILES = $(CFILES:.c=.o) 8 | 9 | CFLAGS = -O3 -marm -mtune=cortex-a7 -march=armv7ve+simd -mfpu=neon-vfpv4 -mfloat-abi=hard -Wall 10 | LDFLAGS = -s 11 | 12 | $(TARGET): $(OFILES) 13 | $(CC) $(OFILES) -o $@ $(LDFLAGS) 14 | 15 | %.o: %.c 16 | $(CC) $(CFLAGS) -c $< -o $@ 17 | 18 | clean: 19 | rm -f $(TARGET) $(OFILES) 20 | 21 | install: 22 | echo do nothing for install 23 | -------------------------------------------------------------------------------- /third-party/logotweak/logomake/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define IMGSIZE 0x20000 12 | 13 | int main() 14 | { 15 | mtd_info_t mtdinfo; 16 | uint32_t i, a, size, size32, imgcount, *read_ofs32; 17 | uint8_t *read_buf, *read_ofs; 18 | const char img_name[4][12] = { "image1.jpg", "image2.jpg", "image3.jpg", "logo.img" }; 19 | int mtdfd, imgfd; 20 | struct stat fst; 21 | 22 | read_buf = malloc(IMGSIZE); 23 | if (!read_buf) { puts("malloc failed"); return -1; } 24 | 25 | printf("Reading /dev/mtd3 ... "); 26 | mtdfd = open("/dev/mtd3", O_RDONLY); 27 | if (mtdfd < 0) { puts("failed to open"); return -1; } 28 | 29 | ioctl(mtdfd, MEMGETINFO, &mtdinfo); 30 | if (mtdinfo.type != 3) { puts("MTD type incorrect"); return -1; } 31 | if (mtdinfo.size != IMGSIZE) { puts("MTD size incorrect"); return -1; } 32 | if (mtdinfo.erasesize != 0x10000) { puts("MTD erasesize incorrect"); return -1; } 33 | 34 | lseek(mtdfd, 0, SEEK_SET); 35 | if (read(mtdfd, read_buf, IMGSIZE) != IMGSIZE) { puts("failed to read"); return -1; } 36 | close(mtdfd); 37 | puts("OK"); 38 | 39 | printf("Checking partition ... "); 40 | read_ofs = read_buf; // "SSTAR" offset 41 | read_ofs32 = (uint32_t*)read_ofs; 42 | if ((read_ofs32[0] != 0x41545353)||(read_ofs32[1] != 0x52)||(read_ofs32[2] != 4)) { puts("missing SSTAR"); return -1; } 43 | 44 | read_ofs = read_ofs + 12; // "DISP" offset 45 | read_ofs32 = (uint32_t*)read_ofs; 46 | if (read_ofs32[0] != 0x50534944) { puts("missing DISP"); return -1; } 47 | for (i=1,a=0; i<8; i++) a += read_ofs32[i]; 48 | read_ofs = read_ofs + read_ofs32[8] + read_ofs32[9]; // 1st "LOGO" offset 49 | if ((a)||(read_ofs - read_buf) > (IMGSIZE-0x2c)) { puts("invalid DISP format"); return -1; } 50 | 51 | read_ofs32 = (uint32_t*)read_ofs; 52 | if (read_ofs32[0] != 0x4F474F4C) { puts("missing LOGO"); return -1; } 53 | puts("OK"); 54 | 55 | // read 3 jpg images 56 | for (imgcount=0; imgcount<3; imgcount++) { 57 | printf("Reading %s ... ",img_name[imgcount]); 58 | 59 | read_ofs32[0] = 0x4F474F4C; 60 | for (i=1; i<8; i++) read_ofs32[i] = 0; 61 | read_ofs32[9] = 0x2c; read_ofs32[10] = 1; 62 | 63 | imgfd = open(img_name[imgcount], O_RDONLY); 64 | if (imgfd < 0) { puts("failed to open"); return -1; } 65 | 66 | fstat(imgfd, &fst); 67 | size = fst.st_size; 68 | size32 = (size+3)&~3; 69 | read_ofs32[8] = size32; 70 | 71 | read_ofs += 0x2c; 72 | if (read_ofs + size32 > read_buf + IMGSIZE) { puts("img size overflow"); return -1; } 73 | if (size) { 74 | memset(read_ofs, 0, size32); 75 | if (read(imgfd, read_ofs, size) != size) { puts("failed to read"); return -1; } 76 | } 77 | close(imgfd); 78 | if (size != size32) read_ofs[size] = 0xff; 79 | puts("OK"); 80 | 81 | read_ofs += size32; 82 | read_ofs32 = (uint32_t*)read_ofs; 83 | } 84 | 85 | // fill rest bytes to 0xFF 86 | if (IMGSIZE-(read_ofs-read_buf) > 0) memset(read_ofs, 0xFF, IMGSIZE-(read_ofs-read_buf)); 87 | 88 | // write logo.img 89 | printf("Writing %s ... ",img_name[3]); 90 | imgfd = creat(img_name[3], 777); 91 | if (imgfd < 0) { puts("failed to create"); return -1; } 92 | if (write(imgfd, read_buf, IMGSIZE) != IMGSIZE) { puts("failed to write"); return -1; } 93 | close(imgfd); 94 | puts("OK"); 95 | 96 | free(read_buf); 97 | 98 | return 0; 99 | } 100 | -------------------------------------------------------------------------------- /third-party/logotweak/logoread/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = logoread 2 | 3 | CC = $(CROSS_COMPILE)gcc 4 | 5 | SOURCES = . 6 | CFILES = $(foreach dir, $(SOURCES), $(wildcard $(dir)/*.c)) 7 | OFILES = $(CFILES:.c=.o) 8 | 9 | CFLAGS = -O3 -marm -mtune=cortex-a7 -march=armv7ve+simd -mfpu=neon-vfpv4 -mfloat-abi=hard -Wall 10 | LDFLAGS = -s 11 | 12 | $(TARGET): $(OFILES) 13 | $(CC) $(OFILES) -o $@ $(LDFLAGS) 14 | 15 | %.o: %.c 16 | $(CC) $(CFLAGS) -c $< -o $@ 17 | 18 | clean: 19 | rm -f $(TARGET) $(OFILES) 20 | 21 | install: 22 | echo do nothing for install 23 | -------------------------------------------------------------------------------- /third-party/logotweak/logoread/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define IMGSIZE 0x20000 10 | 11 | int main() 12 | { 13 | mtd_info_t mtdinfo; 14 | uint32_t i, a, size, imgcount, *read_ofs32; 15 | uint8_t *read_buf, *read_ofs; 16 | const char img_name[3][12] = { "image1.jpg", "image2.jpg", "image3.jpg" }; 17 | int mtdfd, imgfd; 18 | 19 | read_buf = malloc(IMGSIZE); 20 | if (!read_buf) { puts("malloc failed"); return -1; } 21 | 22 | printf("Reading /dev/mtd3 ... "); 23 | mtdfd = open("/dev/mtd3", O_RDONLY); 24 | if (mtdfd < 0) { puts("failed to open"); return -1; } 25 | 26 | ioctl(mtdfd, MEMGETINFO, &mtdinfo); 27 | if (mtdinfo.type != 3) { puts("MTD type incorrect"); return -1; } 28 | if (mtdinfo.size != IMGSIZE) { puts("MTD size incorrect"); return -1; } 29 | if (mtdinfo.erasesize != 0x10000) { puts("MTD erasesize incorrect"); return -1; } 30 | 31 | lseek(mtdfd, 0, SEEK_SET); 32 | if (read(mtdfd, read_buf, IMGSIZE) != IMGSIZE) { puts("failed to read"); return -1; } 33 | close(mtdfd); 34 | puts("OK"); 35 | 36 | printf("Checking partition ... "); 37 | read_ofs = read_buf; // "SSTAR" offset 38 | read_ofs32 = (uint32_t*)read_ofs; 39 | if ((read_ofs32[0] != 0x41545353)||(read_ofs32[1] != 0x52)||(read_ofs32[2] != 4)) { puts("missing SSTAR"); return -1; } 40 | 41 | read_ofs = read_ofs + 12; // "DISP" offset 42 | read_ofs32 = (uint32_t*)read_ofs; 43 | if (read_ofs32[0] != 0x50534944) { puts("missing DISP"); return -1; } 44 | for (i=1,a=0; i<8; i++) a += read_ofs32[i]; 45 | read_ofs = read_ofs + read_ofs32[8] + read_ofs32[9]; // 1st "LOGO" offset 46 | if ((a)||(read_ofs - read_buf) > (IMGSIZE-0x2c)) { puts("invalid DISP format"); return -1; } 47 | 48 | read_ofs32 = (uint32_t*)read_ofs; 49 | if (read_ofs32[0] != 0x4F474F4C) { puts("missing LOGO"); return -1; } 50 | puts("OK"); 51 | 52 | for (imgcount=0; imgcount<3; imgcount++) { 53 | printf("Writing %s ... ",img_name[imgcount]); 54 | 55 | if (read_ofs32[0] != 0x4F474F4C) { puts("missing LOGO"); return -1; } 56 | for (i=1,a=0; i<8; i++) a += read_ofs32[i]; 57 | if ((a)||(read_ofs32[9] != 0x2c)||(read_ofs32[10] != 0x1)) { puts("invalid LOGO format"); return -1; } 58 | size = read_ofs32[8]; 59 | read_ofs += 0x2c; 60 | 61 | imgfd = creat(img_name[imgcount], 777); 62 | if (imgfd < 0) { puts("failed to create"); return -1; } 63 | if (size) if (write(imgfd, read_ofs, size) != size) { puts("failed to read"); return -1; } 64 | close(imgfd); 65 | puts("OK"); 66 | 67 | read_ofs += size; 68 | read_ofs32 = (uint32_t*)read_ofs; 69 | } 70 | free(read_buf); 71 | 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /third-party/logotweak/logowrite/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = logowrite 2 | 3 | CC = $(CROSS_COMPILE)gcc 4 | 5 | SOURCES = . 6 | CFILES = $(foreach dir, $(SOURCES), $(wildcard $(dir)/*.c)) 7 | OFILES = $(CFILES:.c=.o) 8 | 9 | CFLAGS = -O3 -marm -mtune=cortex-a7 -march=armv7ve+simd -mfpu=neon-vfpv4 -mfloat-abi=hard -Wall 10 | LDFLAGS = -s 11 | 12 | $(TARGET): $(OFILES) 13 | $(CC) $(OFILES) -o $@ $(LDFLAGS) 14 | 15 | %.o: %.c 16 | $(CC) $(CFLAGS) -c $< -o $@ 17 | 18 | clean: 19 | rm -f $(TARGET) $(OFILES) 20 | 21 | install: 22 | echo do nothing for install 23 | -------------------------------------------------------------------------------- /third-party/logotweak/logowrite/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define IMGSIZE 0x20000 12 | 13 | int main() 14 | { 15 | mtd_info_t mtdinfo; 16 | erase_info_t ei; 17 | uint32_t i, a, *read_ofs32; 18 | uint8_t r, *read_buf, *read_ofs, *verify_buf; 19 | int imgfd, mtdfd; 20 | struct stat fst; 21 | const char img_name[] = "logo.img"; 22 | 23 | read_buf = malloc(IMGSIZE); 24 | if (!read_buf) { puts("malloc failed"); return -1; } 25 | 26 | printf("Opening logo.img ... "); 27 | imgfd = open(img_name, O_RDONLY); 28 | if (imgfd < 0) { puts("failed to open"); return -1; } 29 | fstat(imgfd, &fst); 30 | if (fst.st_size != IMGSIZE) { puts("invalid size"); return -1; } 31 | puts("OK"); 32 | 33 | printf("Checking logo.img ... "); 34 | lseek(imgfd, 0, SEEK_SET); 35 | if (read(imgfd, read_buf, IMGSIZE) != IMGSIZE) { puts("failed to read"); return -1; } 36 | read_ofs = read_buf; // "SSTAR" offset 37 | read_ofs32 = (uint32_t*)read_ofs; 38 | if ((read_ofs32[0] != 0x41545353)||(read_ofs32[1] != 0x52)||(read_ofs32[2] != 4)) { puts("missing SSTAR"); return -1; } 39 | 40 | read_ofs = read_ofs + 12; // "DISP" offset 41 | read_ofs32 = (uint32_t*)read_ofs; 42 | if (read_ofs32[0] != 0x50534944) { puts("missing DISP"); return -1; } 43 | for (i=1,a=0; i<8; i++) a += read_ofs32[i]; 44 | read_ofs += read_ofs32[8] + read_ofs32[9]; // 1st "LOGO" offset 45 | if ((a)||(read_ofs - read_buf) > (IMGSIZE-0x2c)) { puts("invalid DISP format"); return -1; } 46 | 47 | read_ofs32 = (uint32_t*)read_ofs; 48 | if (read_ofs32[0] != 0x4F474F4C) { puts("missing LOGO1"); return -1; } 49 | for (i=1,a=0; i<8; i++) a += read_ofs32[i]; 50 | read_ofs += read_ofs32[8] + read_ofs32[9]; 51 | if ((a)||(read_ofs - read_buf) > (IMGSIZE-0x2c)) { puts("invalid LOGO1 format"); return -1; } 52 | 53 | read_ofs32 = (uint32_t*)read_ofs; 54 | if (read_ofs32[0] != 0x4F474F4C) { puts("missing LOGO2"); return -1; } 55 | for (i=1,a=0; i<8; i++) a += read_ofs32[i]; 56 | read_ofs += read_ofs32[8] + read_ofs32[9]; 57 | if ((a)||(read_ofs - read_buf) > (IMGSIZE-0x2c)) { puts("invalid LOGO2 format"); return -1; } 58 | 59 | read_ofs32 = (uint32_t*)read_ofs; 60 | if (read_ofs32[0] != 0x4F474F4C) { puts("missing LOGO3"); return -1; } 61 | for (i=1,a=0; i<8; i++) a += read_ofs32[i]; 62 | read_ofs += read_ofs32[8] + read_ofs32[9]; 63 | if ((a)||(read_ofs - read_buf) > IMGSIZE) { puts("invalid LOGO3 format"); return -1; } 64 | puts("OK"); 65 | 66 | printf("Opening /dev/mtd3 ... "); 67 | mtdfd = open("/dev/mtd3", O_RDWR); 68 | if (mtdfd < 0) { puts("failed to open"); return -1; } 69 | 70 | ioctl(mtdfd, MEMGETINFO, &mtdinfo); 71 | if (mtdinfo.type != 3) { puts("MTD type incorrect"); return -1; } 72 | if (mtdinfo.size != IMGSIZE) { puts("MTD size incorrect"); return -1; } 73 | if (mtdinfo.erasesize != 0x10000) { puts("MTD erasesize incorrect"); return -1; } 74 | puts("OK"); 75 | 76 | printf("Erasing /dev/mtd3 ... "); 77 | ei.length = mtdinfo.erasesize; 78 | for (ei.start = 0; ei.start < mtdinfo.size; ei.start += ei.length) { 79 | ioctl(mtdfd, MEMUNLOCK, &ei); 80 | ioctl(mtdfd, MEMERASE, &ei); 81 | } 82 | puts("OK"); 83 | 84 | printf("Checking erased /dev/mtd3 ... "); 85 | lseek(mtdfd, 0, SEEK_SET); 86 | if (read(mtdfd, read_buf, IMGSIZE) != IMGSIZE) { puts("failed to read"); return -1; } 87 | for (i=0, r=0xff; i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | // 15 | // Rumble ON(1) / OFF(0) 16 | // 17 | void rumble(uint32_t val) { 18 | int fd; 19 | const char str_export[] = "48"; 20 | const char str_direction[] = "out"; 21 | char value[1]; 22 | value[0] = ((val&1)^1) + 0x30; 23 | 24 | fd = open("/sys/class/gpio/export", O_WRONLY); 25 | if (fd > 0) { 26 | write(fd, str_export, 2); 27 | close(fd); 28 | } 29 | fd = open("/sys/class/gpio/gpio48/direction", O_WRONLY); 30 | if (fd > 0) { 31 | write(fd, str_direction, 3); 32 | close(fd); 33 | } 34 | fd = open("/sys/class/gpio/gpio48/value", O_WRONLY); 35 | if (fd > 0) { 36 | write(fd, value, 1); 37 | close(fd); 38 | } 39 | } 40 | 41 | // 42 | // Search pid of running executable 43 | // 44 | pid_t searchpid(const char *commname) { 45 | DIR *procdp; 46 | struct dirent *dir; 47 | char fname[32]; 48 | char comm[128]; 49 | pid_t pid; 50 | pid_t ret = 0; 51 | 52 | procdp = opendir("/proc"); 53 | while ((dir = readdir(procdp))) { 54 | if (dir->d_type == DT_DIR) { 55 | pid = atoi(dir->d_name); 56 | if ( pid > 2 ) { 57 | sprintf(fname, "/proc/%d/comm", pid); 58 | FILE *fp = fopen(fname, "r"); 59 | if (fp) { 60 | fscanf(fp, "%127s", comm); 61 | fclose(fp); 62 | if (!strcmp(comm, commname)) { ret = pid; break; } 63 | } 64 | } 65 | } 66 | } 67 | closedir(procdp); 68 | return ret; 69 | } 70 | 71 | // 72 | // Get Most recent file name from Roms/recentlist.json 73 | // 74 | char* getrecent(char *filename) { 75 | FILE *fp; 76 | char *fnptr; 77 | uint32_t i; 78 | 79 | strcpy(filename, "/mnt/SDCARD/Screenshots/"); 80 | if (access(filename, F_OK)) mkdir(filename, 777); 81 | 82 | fnptr = filename + strlen(filename); 83 | 84 | if (!access("/tmp/cmd_to_run.sh", F_OK)) { 85 | // for stock 86 | if ((fp = fopen("/mnt/SDCARD/Roms/recentlist.json", "r"))) { 87 | fscanf(fp, "%*255[^:]%*[:]%*[\"]%255[^\"]", fnptr); 88 | fclose(fp); 89 | } 90 | } else if ((fp = fopen("/tmp/next", "r"))) { 91 | // for MiniUI 92 | char ename[256]; 93 | char fname[256]; 94 | char *strptr; 95 | ename[0] = 0; fname[0] = 0; 96 | fscanf(fp, "%*[\"]%255[^\"]%*[\" ]%255[^\"]", ename, fname); 97 | fclose(fp); 98 | if (fname[0]) { 99 | if ((strptr = strrchr(fname, '.'))) *strptr = 0; 100 | if ((strptr = strrchr(fname, '/'))) strptr++; else strptr = fname; 101 | strcpy(fnptr, strptr); 102 | } else if (ename[0]) { 103 | if ((strptr = strrchr(ename, '/'))) *strptr = 0; 104 | if ((strptr = strrchr(ename, '.'))) *strptr = 0; 105 | if ((strptr = strrchr(ename, '/'))) strptr++; else strptr = ename; 106 | strcpy(fnptr, strptr); 107 | } 108 | } 109 | 110 | if (!(*fnptr)) { 111 | if (searchpid("MiniUI")) strcat(filename, "MiniUI"); 112 | else strcat(filename, "MainUI"); 113 | } 114 | 115 | fnptr = filename + strlen(filename); 116 | for (i=0; i<1000; i++) { 117 | sprintf(fnptr, "_%03d.png", i); 118 | if ( access(filename, F_OK) != 0 ) break; 119 | } if (i > 999) return NULL; 120 | return filename; 121 | } 122 | 123 | // 124 | // Screenshot (640x480, rotate180, png) 125 | // 126 | void screenshot(void) { 127 | char screenshotname[512]; 128 | uint32_t *buffer, *src; 129 | uint32_t linebuffer[640], x, y, pix; 130 | FILE *fp; 131 | int fd_fb; 132 | struct fb_var_screeninfo vinfo; 133 | png_structp png_ptr; 134 | png_infop info_ptr; 135 | 136 | if (getrecent(screenshotname) == NULL) return; 137 | if ((buffer = (uint32_t*)malloc(640*480*4)) != NULL) { 138 | fd_fb = open("/dev/fb0", O_RDWR); 139 | ioctl(fd_fb, FBIOGET_VSCREENINFO, &vinfo); 140 | lseek(fd_fb, 640*vinfo.yoffset*4, SEEK_SET); 141 | read(fd_fb, buffer, 640*480*4); 142 | close(fd_fb); 143 | 144 | fp = fopen(screenshotname, "wb"); 145 | if (fp != NULL) { 146 | png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); 147 | info_ptr = png_create_info_struct(png_ptr); 148 | png_init_io(png_ptr, fp); 149 | png_set_IHDR(png_ptr, info_ptr, 640, 480, 8, PNG_COLOR_TYPE_RGBA, 150 | PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); 151 | png_write_info(png_ptr, info_ptr); 152 | src = buffer + 640*480; 153 | for (y=0; y<480; y++) { 154 | for (x=0; x<640; x++){ 155 | pix = *--src; 156 | linebuffer[x] = 0xFF000000 | (pix & 0x0000FF00) | (pix & 0x00FF0000)>>16 | (pix & 0x000000FF)<<16; 157 | } 158 | png_write_row(png_ptr, (png_bytep)linebuffer); 159 | } 160 | png_write_end(png_ptr, info_ptr); 161 | png_destroy_write_struct(&png_ptr, &info_ptr); 162 | fclose(fp); 163 | sync(); 164 | } 165 | free(buffer); 166 | } 167 | } 168 | 169 | // 170 | // Screenshot Sample Main 171 | // 172 | #define BUTTON_MENU KEY_ESC 173 | #define BUTTON_POWER KEY_POWER 174 | #define BUTTON_L2 KEY_TAB 175 | #define BUTTON_R2 KEY_BACKSPACE 176 | int main() { 177 | int input_fd; 178 | struct input_event ev; 179 | uint32_t val; 180 | uint32_t l2_pressed = 0; 181 | uint32_t r2_pressed = 0; 182 | 183 | // Prepare for Poll button input 184 | input_fd = open("/dev/input/event0", O_RDONLY); 185 | 186 | while( read(input_fd, &ev, sizeof(ev)) == sizeof(ev) ) { 187 | val = ev.value; 188 | if (( ev.type != EV_KEY ) || ( val > 1 )) continue; 189 | if (( ev.code == BUTTON_L2 )||( ev.code == BUTTON_R2 )) { 190 | if ( ev.code == BUTTON_L2 ) { 191 | l2_pressed = val; 192 | } else if ( ev.code == BUTTON_R2 ) { 193 | r2_pressed = val; 194 | } 195 | if (l2_pressed & r2_pressed) { 196 | rumble(1); 197 | screenshot(); 198 | usleep(100000); //0.1s 199 | rumble(0); 200 | l2_pressed = r2_pressed = 0; 201 | } 202 | } 203 | } 204 | 205 | // Quit 206 | close(input_fd); 207 | 208 | return 0; 209 | } 210 | -------------------------------------------------------------------------------- /todo.txt: -------------------------------------------------------------------------------- 1 | ------------------------------- 2 | 3 | Please see the README.txt in the zip file for installation and update instructions. 4 | 5 | - fixed issue selecting the previously launched game on exit when name contains a single quote 6 | - extras: fixed hang in Random Game.pak (it could get lost in empty folders, poor guy) 7 | - extras: added P8.pak (PICO-8 core, jtothebell's fake-08) 8 | 9 | ------------------------------- 10 | 11 | - can we auto-resume fastfoward after hotkey save/load? 12 | 13 | - gpsp has issues closing when a ~12MB zipped rom is loaded 14 | - add Add/Remove MiniUI Boot Logo to extras Tools 15 | 16 | - pcsx can't select analog or dualshock controller 17 | - see picoarch/source/core.c#714 18 | - might be able to special case a place for this in Emulator controls? 19 | 20 | - SDL 21 | - put libmsettings behind a build flag or dlopen/dlsym 22 | 23 | - can virtual boy be optimized at all? 24 | - add frameskip? 25 | - tada! 39fps and stuttery audio to 50fps with skip-free audio 26 | - seems tempermental, sometimes a restart fixes framerate 27 | 28 | - quicksave and power off when /tmp/battery hits 5? 29 | change message when performing emergency power off 30 | maybe handle in keymon? then signal picoarch to shutdown 31 | 32 | - revisit defaults and overrides for gambatte and mgba 33 | - mgba needs rumble strength setting 34 | 35 | - move all picoarch userdata folders into: 36 | .picoarch/EMU_TAG/CORE_NAME/ 37 | - still? 38 | 39 | - picoarch 40 | hold to ff? 41 | can't figure it out 42 | allow audio while ff? 43 | possible but after trying not actually desireable... 44 | 45 | - pcsx is going through some serious changes (besides the update to v2 options) 46 | wait for the dust to settle before considering updating 47 | 48 | - test supafaust 49 | - msu-1 50 | - marvelous 51 | 52 | - script checking core repos for newer commits? 53 | 54 | - look at the way eggs clockd works and see if we can do something similar to add libmmenu to standalones 55 | - launch binary and pass its pid to standalonemenu which listens for MENU and sends a sig STOP to the previous binary? 56 | 57 | - add an Extended Font.pak? 58 | 59 | - picoarch 60 | truncate the common parts of a group of options, not the (usually unique) ends 61 | integrate cheat support into MiniUI 62 | 63 | - look into CamOS and MI_ERRs in MiniUI and picoarch 64 | - probably tied to both settings and SDL trying to restore audio volume? 65 | - add logging to try to bookend the errors to identify their source then untangle the cause 66 | 67 | - look into removing trimui patches from picoarch cores, breaking on latest core commits, see pcsx_rearmed 68 | 69 | - BUG: repo doesn't checkout correct branch for submodules when cloned... 70 | tried but didn't work 71 | git submodule set-branch -b miniui-miyoomini third-party/picoarch 72 | maybe 73 | https://stackoverflow.com/questions/1777854/how-can-i-specify-a-branch-tag-when-adding-a-git-submodule/18799234#18799234 74 | this worked for everything but SDL I think 75 | 76 | - faqs 77 | - known issues 78 | 79 | - BUG: say doesn't seem to respect extra line returns at end of msg 80 | 81 | - use smsplus-gx for SMS/GG? 82 | 83 | - press L on a save state to lock/unlock it? to make it the default state to open instead of a cold launch? 84 | 85 | - auto-adjust brightness based on screen effect? 86 | 87 | change all logging from &> log to > log 2>&1 88 | 89 | - show, confirm, and say don't sleep (neither does Files.pak) 90 | :thinking_face: :shrug: 91 | 92 | - find . -name ".DS_Store" -type f -print -delete --------------------------------------------------------------------------------