├── .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
--------------------------------------------------------------------------------