diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b01fdbed7..dc9cbef9e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -42,6 +42,7 @@ jobs: toolchain: - tg5040 - tg5050 + - h700 steps: - name: Checkout @@ -64,6 +65,7 @@ jobs: toolchain: - tg5040 - tg5050 + - h700 core: ${{ fromJson(needs.core-matrix.outputs.cores) }} steps: - name: Checkout @@ -124,6 +126,39 @@ jobs: env: PLATFORM: tg5050 + - name: Download Cores (h700) + uses: actions/download-artifact@v4.3.0 + with: + path: workspace/h700/cores/output/ + pattern: core-h700-* + merge-multiple: true + + - name: Build (h700) + run: make h700 + env: + PLATFORM: h700 + + - name: Check H700 settings runtime links + run: | + docker run --rm --platform linux/arm64 -v "$PWD:/work" -w /work ubuntu:22.04 sh -ec ' + apt-get update + apt-get install -y --no-install-recommends \ + libegl1 \ + libfreetype6 \ + libgcc-s1 \ + libglib2.0-0 \ + libgles2 \ + libjpeg-turbo8 \ + liblzma5 \ + libpng16-16 \ + libstdc++6 \ + libtiff5 \ + libwebp7 \ + libzstd1 \ + zlib1g + sh ./workspace/h700/check-settings-ldd.sh + ' + - name: Special run: make special diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index bf1e220e4..aa4e0c7ea 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -61,6 +61,7 @@ jobs: toolchain: - tg5040 - tg5050 + - h700 steps: - name: Checkout @@ -83,6 +84,7 @@ jobs: toolchain: - tg5040 - tg5050 + - h700 core: ${{ fromJson(needs.core-matrix.outputs.cores) }} steps: - name: Checkout @@ -143,6 +145,39 @@ jobs: env: PLATFORM: tg5050 + - name: Download Cores (h700) + uses: actions/download-artifact@v4.3.0 + with: + path: workspace/h700/cores/output/ + pattern: core-h700-* + merge-multiple: true + + - name: Build (h700) + run: make h700 + env: + PLATFORM: h700 + + - name: Check H700 settings runtime links + run: | + docker run --rm --platform linux/arm64 -v "$PWD:/work" -w /work ubuntu:22.04 sh -ec ' + apt-get update + apt-get install -y --no-install-recommends \ + libegl1 \ + libfreetype6 \ + libgcc-s1 \ + libglib2.0-0 \ + libgles2 \ + libjpeg-turbo8 \ + liblzma5 \ + libpng16-16 \ + libstdc++6 \ + libtiff5 \ + libwebp7 \ + libzstd1 \ + zlib1g + sh ./workspace/h700/check-settings-ldd.sh + ' + - name: Special run: make special @@ -225,4 +260,3 @@ jobs: ## How to install/update For a fresh installation, follow the instructions here: https://nextui.loveretro.games/getting-started/installation/ When updating from a previous release: https://nextui.loveretro.games/getting-started/updating/ - diff --git a/PAKS.md b/PAKS.md index d9d629d1f..8f4adfbb0 100644 --- a/PAKS.md +++ b/PAKS.md @@ -6,7 +6,7 @@ There are two kinds of paks, emulators and tools. Emulator paks live in the Emus Paks are platform specific. Inside the Emus and Tools folders you will find (or need to create) platform folders. Some platform folders are named after the target device (eg. "rgb30" for the Powkiddy RGB30), others use the device's internal name (eg. "tg5040" for the Trimui Smart Pro), other use an arbitrary shortname (eg. "trimui" for the Trimui Model S), all are completely lowercase. See the extras bundle for up-to-date supported platform folder names. -Some platforms have multiple devices with unique qualities. NextUI differentiates these devices from the base platform with the `DEVICE` envar. eg. the "rg35xxplus" platform has two unique devices "cube" for the RG CubeXX, and "wide" for the RG34xx. It also supports "hdmi" for when outputting to HDMI. A pak can choose to use or ignore this envar. +Some platforms have multiple devices with unique qualities. NextUI differentiates these with the `DEVICE` envar. On tg5040 that is `brick`, `brickpro`, or `smartpro`. On h700 it is an exact SKU id such as `rg40xxv`, `rg34xxsp`, or `rgcubexx` (full list in the H700 Pak porting wiki page). A pak can choose to use or ignore this envar. # The types of emulator pak diff --git a/makefile b/makefile index fed3da9f6..f1f6d49c7 100644 --- a/makefile +++ b/makefile @@ -12,7 +12,7 @@ endif ifeq (,$(PLATFORMS)) #PLATFORMS = miyoomini trimuismart rg35xx rg35xxplus my355 tg5040 zero28 rgb30 m17 gkdpixel my282 magicmini -PLATFORMS = tg5050 tg5040 +PLATFORMS = tg5050 tg5040 h700 endif ########################################################### @@ -103,15 +103,22 @@ endif cp ./workspace/all/clock/build/$(PLATFORM)/clock.elf ./build/EXTRAS/Tools/$(PLATFORM)/Clock.pak/ cp ./workspace/all/minput/build/$(PLATFORM)/minput.elf ./build/EXTRAS/Tools/$(PLATFORM)/Input.pak/ cp ./workspace/all/settings/build/$(PLATFORM)/settings.elf ./build/EXTRAS/Tools/$(PLATFORM)/Settings.pak/ -ifneq (,$(filter $(PLATFORM),tg5040 tg5050)) +ifneq (,$(filter $(PLATFORM),tg5040 tg5050 h700)) cp ./workspace/all/ledcontrol/build/$(PLATFORM)/ledcontrol.elf ./build/EXTRAS/Tools/$(PLATFORM)/LedControl.pak/ - cp ./workspace/all/bootlogo/build/$(PLATFORM)/bootlogo.elf ./build/EXTRAS/Tools/$(PLATFORM)/Bootlogo.pak/ ifeq ($(PLATFORM), tg5040) # Limbo fix cp ./workspace/$(PLATFORM)/poweroff_next/build/$(PLATFORM)/poweroff_next.elf ./build/SYSTEM/$(PLATFORM)/bin/poweroff_next endif endif -ifneq (,$(filter $(PLATFORM),tg5040 tg5050 my355)) +ifeq ($(PLATFORM), h700) + # Limbo fix (AXP2202 needs an explicit software power-off) + cp ./workspace/$(PLATFORM)/poweroff_next/build/$(PLATFORM)/poweroff_next.elf ./build/SYSTEM/$(PLATFORM)/bin/poweroff_next + cp ./workspace/$(PLATFORM)/poweroff_next/build/$(PLATFORM)/reboot_next.elf ./build/SYSTEM/$(PLATFORM)/bin/reboot_next +endif +ifneq (,$(filter $(PLATFORM),tg5040 tg5050 h700)) + cp ./workspace/all/bootlogo/build/$(PLATFORM)/bootlogo.elf ./build/EXTRAS/Tools/$(PLATFORM)/Bootlogo.pak/ +endif +ifneq (,$(filter $(PLATFORM),tg5040 tg5050 h700 my355)) # Audio resampling cp ./workspace/all/minarch/build/$(PLATFORM)/libsamplerate.* ./build/SYSTEM/$(PLATFORM)/lib/ @@ -125,7 +132,7 @@ ifneq (,$(filter $(PLATFORM),tg5040 tg5050 my355)) cp ./workspace/all/minarch/build/$(PLATFORM)/libchdr.so.* ./build/SYSTEM/$(PLATFORM)/lib/ cp ./workspace/all/minarch/build/$(PLATFORM)/libcrypto.so.* ./build/SYSTEM/$(PLATFORM)/lib/ -ifeq ($(PLATFORM), tg5040) +ifneq (,$(filter $(PLATFORM),tg5040 h700)) # liblz4 for Rewind support cp -L ./workspace/all/minarch/build/$(PLATFORM)/liblz4.so.1 ./build/SYSTEM/$(PLATFORM)/lib/ endif @@ -265,7 +272,7 @@ package: tidy # TODO: can I just add everything in BASE to zip? # cd ./build/BASE && zip -r ../../releases/$(RELEASE_NAME)-base.zip Bios Roms Saves miyoo miyoo354 trimui rg35xx rg35xxplus gkdpixel miyoo355 magicx em_ui.sh MinUI.zip README.txt - cd ./build/BASE && zip -r ../../releases/$(RELEASE_NAME)-base.zip Bios Roms Saves Shaders Overlays trimui em_ui.sh MinUI.zip *.pakz README.txt + cd ./build/BASE && zip -r ../../releases/$(RELEASE_NAME)-base.zip Bios Roms Saves Shaders Overlays trimui h700 em_ui.sh MinUI.zip *.pakz README.txt cd ./build/EXTRAS && zip -r ../../releases/$(RELEASE_NAME)-extras.zip Bios Emus Roms Saves Shaders Overlays Tools README.txt echo "$(RELEASE_VERSION)" > ./build/latest.txt diff --git a/makefile.toolchain b/makefile.toolchain index fba8ecee0..c56b4015e 100644 --- a/makefile.toolchain +++ b/makefile.toolchain @@ -9,9 +9,11 @@ endif HOST_WORKSPACE=$(shell pwd)/workspace GUEST_WORKSPACE=/root/workspace -GIT_IF_NECESSARY=toolchains/$(PLATFORM)-toolchain -INIT_IF_NECESSARY=toolchains/$(PLATFORM)-toolchain/.build -IMAGE_NAME=ghcr.io/loveretro/$(PLATFORM)-toolchain:latest +TOOLCHAIN_NAME=$(PLATFORM) + +GIT_IF_NECESSARY=toolchains/$(TOOLCHAIN_NAME)-toolchain +INIT_IF_NECESSARY=toolchains/$(TOOLCHAIN_NAME)-toolchain/.build +IMAGE_NAME=ghcr.io/loveretro/$(TOOLCHAIN_NAME)-toolchain:latest CONTAINER_RUNTIME ?= $(shell command -v docker 2>/dev/null || command -v podman 2>/dev/null) ifeq (,$(CONTAINER_RUNTIME)) @@ -28,18 +30,18 @@ LAST_RUNTIME := $(shell cat $(RUNTIME_MARKER) 2>/dev/null) CURRENT_RUNTIME := $(notdir $(CONTAINER_RUNTIME)) all: $(INIT_IF_NECESSARY) - $(CONTAINER_RUNTIME) run -it --rm $(CONTAINER_MOUNT_OPTS) -v $(HOST_WORKSPACE):$(GUEST_WORKSPACE) $(IMAGE_NAME) /bin/bash + $(CONTAINER_RUNTIME) run -it --rm $(CONTAINER_MOUNT_OPTS) -v $(HOST_WORKSPACE):$(GUEST_WORKSPACE) -e PLATFORM=$(PLATFORM) -e UNION_PLATFORM=$(PLATFORM) $(IMAGE_NAME) /bin/bash -lc 'export PLATFORM=$(PLATFORM) UNION_PLATFORM=$(PLATFORM); cd $(GUEST_WORKSPACE); exec /bin/bash' $(INIT_IF_NECESSARY): $(GIT_IF_NECESSARY) - cd toolchains/$(PLATFORM)-toolchain && make .build + cd toolchains/$(TOOLCHAIN_NAME)-toolchain && make .build $(GIT_IF_NECESSARY): mkdir -p toolchains - git clone https://github.com/LoveRetro/$(PLATFORM)-toolchain/ toolchains/$(PLATFORM)-toolchain - $(CONTAINER_RUNTIME) pull $(IMAGE_NAME) && touch toolchains/$(PLATFORM)-toolchain/.build + git clone https://github.com/LoveRetro/$(TOOLCHAIN_NAME)-toolchain/ toolchains/$(TOOLCHAIN_NAME)-toolchain + $(CONTAINER_RUNTIME) pull $(IMAGE_NAME) && touch toolchains/$(TOOLCHAIN_NAME)-toolchain/.build clean: - cd toolchains/$(PLATFORM)-toolchain && make clean + cd toolchains/$(TOOLCHAIN_NAME)-toolchain && make clean _runtime_check: @if [ -n "$(LAST_RUNTIME)" ] && [ "$(LAST_RUNTIME)" != "$(CURRENT_RUNTIME)" ]; then \ @@ -55,17 +57,24 @@ _runtime_check: fi; \ fi +# The platform reaches the guest build through the environment only, never as a +# `make PLATFORM=...` argument. A command-line variable lands in MAKEOVERRIDES and +# overrides same-named assignments in *every* recursive make, including each core's +# own `PLATFORM = libretro` (picodrive, pcsx_rearmed) — those then build without +# their libretro frontend and link to an entry-point-less stub. Environment values +# lose to a makefile assignment, which is what workspace/makefile expects. + build: $(INIT_IF_NECESSARY) _runtime_check - $(CONTAINER_RUNTIME) run --rm $(CONTAINER_MOUNT_OPTS) -v $(HOST_WORKSPACE):$(GUEST_WORKSPACE) -e COMPILE_CORES=$(COMPILE_CORES) $(IMAGE_NAME) /bin/bash -c '. ~/.bashrc && cd /root/workspace && make' + $(CONTAINER_RUNTIME) run --rm $(CONTAINER_MOUNT_OPTS) -v $(HOST_WORKSPACE):$(GUEST_WORKSPACE) -e COMPILE_CORES=$(COMPILE_CORES) -e PLATFORM=$(PLATFORM) -e UNION_PLATFORM=$(PLATFORM) $(IMAGE_NAME) /bin/bash -c '. ~/.bashrc && export PLATFORM=$(PLATFORM) UNION_PLATFORM=$(PLATFORM) && cd /root/workspace && make' @echo "$(CURRENT_RUNTIME)" > $(RUNTIME_MARKER) build-cores: $(INIT_IF_NECESSARY) _runtime_check - $(CONTAINER_RUNTIME) run --rm $(CONTAINER_MOUNT_OPTS) -v $(HOST_WORKSPACE):$(GUEST_WORKSPACE) -e COMPILE_CORES=$(COMPILE_CORES) $(IMAGE_NAME) /bin/bash -c '. ~/.bashrc && cd /root/workspace && make cores' + $(CONTAINER_RUNTIME) run --rm $(CONTAINER_MOUNT_OPTS) -v $(HOST_WORKSPACE):$(GUEST_WORKSPACE) -e COMPILE_CORES=$(COMPILE_CORES) -e PLATFORM=$(PLATFORM) -e UNION_PLATFORM=$(PLATFORM) $(IMAGE_NAME) /bin/bash -c '. ~/.bashrc && export PLATFORM=$(PLATFORM) UNION_PLATFORM=$(PLATFORM) && cd /root/workspace && make cores' @echo "$(CURRENT_RUNTIME)" > $(RUNTIME_MARKER) build-core: $(INIT_IF_NECESSARY) _runtime_check ifndef CORE $(error CORE is not set) endif - $(CONTAINER_RUNTIME) run --rm $(CONTAINER_MOUNT_OPTS) -v $(HOST_WORKSPACE):$(GUEST_WORKSPACE) -e COMPILE_CORES=$(COMPILE_CORES) -e CORE=$(CORE) $(IMAGE_NAME) /bin/bash -c '. ~/.bashrc && cd /root/workspace && make core' + $(CONTAINER_RUNTIME) run --rm $(CONTAINER_MOUNT_OPTS) -v $(HOST_WORKSPACE):$(GUEST_WORKSPACE) -e COMPILE_CORES=$(COMPILE_CORES) -e CORE=$(CORE) -e PLATFORM=$(PLATFORM) -e UNION_PLATFORM=$(PLATFORM) $(IMAGE_NAME) /bin/bash -c '. ~/.bashrc && export PLATFORM=$(PLATFORM) UNION_PLATFORM=$(PLATFORM) && cd /root/workspace && make core' @echo "$(CURRENT_RUNTIME)" > $(RUNTIME_MARKER) diff --git a/skeleton/BASE/README.txt b/skeleton/BASE/README.txt index 5f6b965bd..2477498bb 100644 --- a/skeleton/BASE/README.txt +++ b/skeleton/BASE/README.txt @@ -36,6 +36,14 @@ TRIMUI SMART PRO / TRIMUI BRICK Copy the "trimui" folder and "MinUI.zip" (without unzipping) to the root of the SD card. +ANBERNIC RG XX (H700) DEVICES + +Copy "MinUI.zip" (without unzipping) to the root of the SD card. + +Copy the "dmenu.bin" file (found inside the "h700" folder) to the root of your stock OS card's ROMS partition. You can delete it later to uninstall and return to stock. + +IMPORTANT: In the stock OS, set the user interface theme to "old style" (default) — not "MU style 1" or "MU style 2", otherwise NextUI will not start. + MIYOO FLIP Copy the "miyoo355" folder and "MinUI.zip" (without unzipping) to the root of the SD card. Put the SD card into the right slot (beneath the power button). @@ -60,6 +68,11 @@ TRIMUI BRICK / BRICK PRO / SMART PRO S Buttons with no action of their own can be assigned a pak to launch: L3/R3 on the Brick, L4/R4 on the Brick Pro, and HOME on the Brick Pro and Smart Pro S. Assign them under Settings > Assignments. Assignments only apply in the main menu, not in-game. HOME no longer acts as a second menu button. +ANBERNIC RG XX + + Menu button: Quick menu + Select button: Game switcher + ---------------------------------------- Quicksave & auto-resume @@ -153,7 +166,7 @@ Not simple enough for you (or maybe your kids)? NextUI has a simple mode that hi ---------------------------------------- Advanced -NextUI can automatically run a user-authored shell script on boot. Just place a file named "auto.sh" in "/.userdata//". If you're on Windows, make sure your text editor uses Unix line-endings (eg. `\n`), these devices usually choke on Windows line-endings (eg. `\r\n`). +NextUI can automatically run a user-authored shell script on boot. Just place a file named "auto.sh" in "/.userdata//" (eg. `/.userdata/h700/` or `/.userdata/tg5040/`). If you're on Windows, make sure your text editor uses Unix line-endings (eg. `\n`), these devices usually choke on Windows line-endings (eg. `\r\n`). ---------------------------------------- Thanks diff --git a/skeleton/BOOT/common/updater b/skeleton/BOOT/common/updater index db8357a7d..e280ad509 100755 --- a/skeleton/BOOT/common/updater +++ b/skeleton/BOOT/common/updater @@ -3,6 +3,10 @@ # NOTE: becomes .tmp_update/updater INFO=`cat /proc/cpuinfo 2> /dev/null` +MODEL=`cat /proc/device-tree/model 2> /dev/null` +if echo "$MODEL" | grep -q "sun50iw9"; then + PLATFORM="h700" # Anbernic RG XX, Allwinner H700 +fi case $INFO in *"sun8i"*) if [ -d /usr/miyoo ]; then @@ -21,7 +25,9 @@ case $INFO in PLATFORM="tg5050" # Trimui Smart Pro S ;; *"0xd03"*) - PLATFORM="zero28" # MagicX Mini Zero 28 + if [ -z "$PLATFORM" ]; then + PLATFORM="zero28" # MagicX Mini Zero 28 + fi ;; *"0xd05"*) PLATFORM="my355" # Miyoo Flip diff --git a/skeleton/EXTRAS/Emus/h700/32X.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/32X.pak/default.cfg new file mode 100644 index 000000000..368a439ab --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/32X.pak/default.cfg @@ -0,0 +1,19 @@ +-picodrive_drc = enabled +-picodrive_sound_rate = 44100 +-picodrive_smstype = Auto +-picodrive_smsfm = off +-picodrive_smsmapper = Auto +-picodrive_ggghost = off + +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Mode = SELECT +bind Start = START +bind A Button = Y +bind B Button = X:B +bind C Button = A +bind X Button = B:L1 +bind Y Button = L1:X +bind Z Button = R1 diff --git a/skeleton/EXTRAS/Emus/h700/32X.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/32X.pak/launch.sh new file mode 100755 index 000000000..8ceb019a2 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/32X.pak/launch.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +EMU_EXE=picodrive + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/A2600.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/A2600.pak/default.cfg new file mode 100644 index 000000000..48c64810e --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/A2600.pak/default.cfg @@ -0,0 +1,14 @@ +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind X Button = X +bind Y Button = Y +bind B Button = B +bind A Button = A +bind L1 Button = L1 +bind L2 Button = L2 +bind R1 Button = R1 +bind R2 Button = R2 diff --git a/skeleton/EXTRAS/Emus/h700/A2600.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/A2600.pak/launch.sh new file mode 100644 index 000000000..4646f9b42 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/A2600.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=stella2014 +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/A5200.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/A5200.pak/default.cfg new file mode 100644 index 000000000..48c64810e --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/A5200.pak/default.cfg @@ -0,0 +1,14 @@ +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind X Button = X +bind Y Button = Y +bind B Button = B +bind A Button = A +bind L1 Button = L1 +bind L2 Button = L2 +bind R1 Button = R1 +bind R2 Button = R2 diff --git a/skeleton/EXTRAS/Emus/h700/A5200.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/A5200.pak/launch.sh new file mode 100644 index 000000000..b42bc170a --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/A5200.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=a5200 +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/A7800.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/A7800.pak/default.cfg new file mode 100644 index 000000000..48c64810e --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/A7800.pak/default.cfg @@ -0,0 +1,14 @@ +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind X Button = X +bind Y Button = Y +bind B Button = B +bind A Button = A +bind L1 Button = L1 +bind L2 Button = L2 +bind R1 Button = R1 +bind R2 Button = R2 diff --git a/skeleton/EXTRAS/Emus/h700/A7800.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/A7800.pak/launch.sh new file mode 100644 index 000000000..38fccc181 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/A7800.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=prosystem +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/C128.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/C128.pak/default.cfg new file mode 100644 index 000000000..48c64810e --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/C128.pak/default.cfg @@ -0,0 +1,14 @@ +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind X Button = X +bind Y Button = Y +bind B Button = B +bind A Button = A +bind L1 Button = L1 +bind L2 Button = L2 +bind R1 Button = R1 +bind R2 Button = R2 diff --git a/skeleton/EXTRAS/Emus/h700/C128.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/C128.pak/launch.sh new file mode 100644 index 000000000..50a003646 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/C128.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=vice_x128 +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/C64.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/C64.pak/default.cfg new file mode 100644 index 000000000..48c64810e --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/C64.pak/default.cfg @@ -0,0 +1,14 @@ +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind X Button = X +bind Y Button = Y +bind B Button = B +bind A Button = A +bind L1 Button = L1 +bind L2 Button = L2 +bind R1 Button = R1 +bind R2 Button = R2 diff --git a/skeleton/EXTRAS/Emus/h700/C64.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/C64.pak/launch.sh new file mode 100644 index 000000000..2e8dfeff3 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/C64.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=vice_x64 +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/COLECO.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/COLECO.pak/default.cfg new file mode 100644 index 000000000..acd0b6a74 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/COLECO.pak/default.cfg @@ -0,0 +1,14 @@ +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind X Button = X +bind Y Button = Y +bind B Button = B +bind A Button = A +bind L1 Button = L1 +bind L2 Button = L2 +bind R1 Button = R1 +bind R2 Button = R2 \ No newline at end of file diff --git a/skeleton/EXTRAS/Emus/h700/COLECO.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/COLECO.pak/launch.sh new file mode 100755 index 000000000..d18a787eb --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/COLECO.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=gearcoleco +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/CPC.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/CPC.pak/default.cfg new file mode 100644 index 000000000..48c64810e --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/CPC.pak/default.cfg @@ -0,0 +1,14 @@ +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind X Button = X +bind Y Button = Y +bind B Button = B +bind A Button = A +bind L1 Button = L1 +bind L2 Button = L2 +bind R1 Button = R1 +bind R2 Button = R2 diff --git a/skeleton/EXTRAS/Emus/h700/CPC.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/CPC.pak/launch.sh new file mode 100644 index 000000000..67edeb06a --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/CPC.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=cap32 +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/FBN.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/FBN.pak/default.cfg new file mode 100644 index 000000000..cff2093e2 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/FBN.pak/default.cfg @@ -0,0 +1,15 @@ +-fbneo-vertical-mode = disabled +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind X Button = X +bind Y Button = Y +bind B Button = B +bind A Button = A +bind L1 Button = L1 +bind L2 Button = L2 +bind R1 Button = R1 +bind R2 Button = R2 \ No newline at end of file diff --git a/skeleton/EXTRAS/Emus/h700/FBN.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/FBN.pak/launch.sh new file mode 100755 index 000000000..e739e99e3 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/FBN.pak/launch.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +EMU_EXE=fbneo +CORES_PATH=$(dirname "$0") +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/FDS.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/FDS.pak/default.cfg new file mode 100644 index 000000000..677c0359b --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/FDS.pak/default.cfg @@ -0,0 +1,20 @@ +fceumm_sndquality = High +fceumm_sndvolume = 10 +-fceumm_aspect = 8:7 PAR +-fceumm_turbo_enable = Player 1 +-fceumm_show_adv_system_options = disabled +-fceumm_show_adv_sound_options = disabled + +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind A Button = A +bind B Button = B +bind A Turbo = NONE:X +bind B Turbo = NONE:Y +bind Change Disk = L1 +bind Insert Disk = R1 +bind Insert Coin = NONE:R2 \ No newline at end of file diff --git a/skeleton/EXTRAS/Emus/h700/FDS.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/FDS.pak/launch.sh new file mode 100755 index 000000000..780ad5456 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/FDS.pak/launch.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +EMU_EXE=fceumm + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/GG.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/GG.pak/default.cfg new file mode 100644 index 000000000..44ce34743 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/GG.pak/default.cfg @@ -0,0 +1,18 @@ +-picodrive_smstype = Game Gear +-picodrive_smsmapper = Auto +-picodrive_sound_rate = 44100 +-picodrive_ramcart = disabled +-picodrive_dacnoise = disabled +-picodrive_input1 = 3 button pad +-picodrive_input2 = 3 button pad +-picodrive_fm_filter = off +-picodrive_audio_filter = disabled +-picodrive_overclk68k = disabled + +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Button 1 = B +bind Button 2 = A +bind Pause = START \ No newline at end of file diff --git a/skeleton/EXTRAS/Emus/h700/GG.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/GG.pak/launch.sh new file mode 100755 index 000000000..8ceb019a2 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/GG.pak/launch.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +EMU_EXE=picodrive + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/LYNX.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/LYNX.pak/default.cfg new file mode 100644 index 000000000..48c64810e --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/LYNX.pak/default.cfg @@ -0,0 +1,14 @@ +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind X Button = X +bind Y Button = Y +bind B Button = B +bind A Button = A +bind L1 Button = L1 +bind L2 Button = L2 +bind R1 Button = R1 +bind R2 Button = R2 diff --git a/skeleton/EXTRAS/Emus/h700/LYNX.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/LYNX.pak/launch.sh new file mode 100755 index 000000000..98b51743d --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/LYNX.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=handy +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/MGBA.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/MGBA.pak/default.cfg new file mode 100644 index 000000000..266d90c20 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/MGBA.pak/default.cfg @@ -0,0 +1,18 @@ +mgba_skip_bios = ON + +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind A Button = A +bind B Button = B +bind A Turbo = NONE:X +bind B Turbo = NONE:Y +bind L Button = L1 +bind R Button = R1 +bind L Turbo = NONE:L2 +bind R Turbo = NONE:R2 +bind More Sun = NONE:L3 +bind Less Sun = NONE:R3 \ No newline at end of file diff --git a/skeleton/EXTRAS/Emus/h700/MGBA.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/MGBA.pak/launch.sh new file mode 100755 index 000000000..598c1ca44 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/MGBA.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=mgba +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/MSX.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/MSX.pak/default.cfg new file mode 100644 index 000000000..acd0b6a74 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/MSX.pak/default.cfg @@ -0,0 +1,14 @@ +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind X Button = X +bind Y Button = Y +bind B Button = B +bind A Button = A +bind L1 Button = L1 +bind L2 Button = L2 +bind R1 Button = R1 +bind R2 Button = R2 \ No newline at end of file diff --git a/skeleton/EXTRAS/Emus/h700/MSX.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/MSX.pak/launch.sh new file mode 100755 index 000000000..706a81460 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/MSX.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=bluemsx +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/NGP.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/NGP.pak/default.cfg new file mode 100644 index 000000000..33f5a6b95 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/NGP.pak/default.cfg @@ -0,0 +1,9 @@ +race_dark_filter_level = 50 + +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind A Button = B +bind B Button = A +bind Option = START \ No newline at end of file diff --git a/skeleton/EXTRAS/Emus/h700/NGP.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/NGP.pak/launch.sh new file mode 100755 index 000000000..09ec144ee --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/NGP.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=race +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/NGPC.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/NGPC.pak/default.cfg new file mode 100644 index 000000000..7d05719ba --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/NGPC.pak/default.cfg @@ -0,0 +1,7 @@ +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind A Button = B +bind B Button = A +bind Option = START \ No newline at end of file diff --git a/skeleton/EXTRAS/Emus/h700/NGPC.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/NGPC.pak/launch.sh new file mode 100755 index 000000000..09ec144ee --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/NGPC.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=race +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/P8.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/P8.pak/default.cfg new file mode 100644 index 000000000..73611d3f3 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/P8.pak/default.cfg @@ -0,0 +1,7 @@ +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind A Button = A +bind B Button = B +bind Start = START \ No newline at end of file diff --git a/skeleton/EXTRAS/Emus/h700/P8.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/P8.pak/launch.sh new file mode 100755 index 000000000..2e6658a91 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/P8.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=fake08 +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/PCE.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/PCE.pak/default.cfg new file mode 100644 index 000000000..671219086 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/PCE.pak/default.cfg @@ -0,0 +1,15 @@ +-pce_fast_turbo_toggle_hotkey = disabled + +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Run = START +bind I = A +bind II = B +bind III = Y +bind IV = X +bind V = L1 +bind VI = R1 +bind Mode = L2 \ No newline at end of file diff --git a/skeleton/EXTRAS/Emus/h700/PCE.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/PCE.pak/launch.sh new file mode 100755 index 000000000..3d92d15cc --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/PCE.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=mednafen_pce_fast +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/PET.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/PET.pak/default.cfg new file mode 100644 index 000000000..48c64810e --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/PET.pak/default.cfg @@ -0,0 +1,14 @@ +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind X Button = X +bind Y Button = Y +bind B Button = B +bind A Button = A +bind L1 Button = L1 +bind L2 Button = L2 +bind R1 Button = R1 +bind R2 Button = R2 diff --git a/skeleton/EXTRAS/Emus/h700/PET.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/PET.pak/launch.sh new file mode 100644 index 000000000..e7b71659f --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/PET.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=vice_xpet +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/PKM.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/PKM.pak/default.cfg new file mode 100644 index 000000000..031fac732 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/PKM.pak/default.cfg @@ -0,0 +1,17 @@ +minarch_screen_scaling = Native + +pokemini_video_scale = 5x +-pokemini_60hz_mode = enabled +pokemini_palette = Old +pokemini_piezofilter = disabled +pokemini_lowpass_filter = enabled + +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind A Button = A +bind B Button = B +bind C Button = R1 +bind Shake = L1 +bind Power = SELECT diff --git a/skeleton/EXTRAS/Emus/h700/PKM.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/PKM.pak/launch.sh new file mode 100755 index 000000000..4f9cbbf4d --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/PKM.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=pokemini +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/PLUS4.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/PLUS4.pak/default.cfg new file mode 100644 index 000000000..48c64810e --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/PLUS4.pak/default.cfg @@ -0,0 +1,14 @@ +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind X Button = X +bind Y Button = Y +bind B Button = B +bind A Button = A +bind L1 Button = L1 +bind L2 Button = L2 +bind R1 Button = R1 +bind R2 Button = R2 diff --git a/skeleton/EXTRAS/Emus/h700/PLUS4.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/PLUS4.pak/launch.sh new file mode 100644 index 000000000..e9851f25e --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/PLUS4.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=vice_xplus4 +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/PRBOOM.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/PRBOOM.pak/default.cfg new file mode 100644 index 000000000..b10538a03 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/PRBOOM.pak/default.cfg @@ -0,0 +1,18 @@ +prboom-mouse_on = disabled +prboom-find_recursive_on = enabled +prboom-analog_deadzone = 15 +prboom-purge_limit = 16 +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind X Button = X +bind Y Button = Y +bind B Button = B +bind A Button = A +bind L1 Button = L1 +bind L2 Button = L2 +bind R1 Button = R1 +bind R2 Button = R2 diff --git a/skeleton/EXTRAS/Emus/h700/PRBOOM.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/PRBOOM.pak/launch.sh new file mode 100644 index 000000000..d7d8fb54e --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/PRBOOM.pak/launch.sh @@ -0,0 +1,74 @@ +#!/bin/sh +set -x +PAK_DIR="$(dirname "$0")" +PAK_NAME="$(basename "$PAK_DIR")" +PAK_NAME="${PAK_NAME%.*}" + +EMU_EXE=prboom +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) + +rm -f "$LOGS_PATH/$EMU_TAG.txt" +exec >>"$LOGS_PATH/$EMU_TAG.txt" +exec 2>&1 + +get_doom_version() { + DOOM_VERSION="" + if [ -f "$ROM" ]; then + # get the directory of the file + ROM_DIR=$(dirname "$ROM") + if [ -f "$ROM_DIR/doom.version" ]; then + DOOM_VERSION=$(cat "$ROM_DIR/doom.version") + fi + fi + echo "$DOOM_VERSION" +} + +prep_doom_folder() { + DOOM_VERSION="$1" + + if [ -z "$DOOM_VERSION" ]; then + return + fi + + if [ ! -d "$BIOS_PATH/PRBOOM/$DOOM_VERSION" ]; then + return + fi + + if [ ! -f "$BIOS_PATH/PRBOOM/$DOOM_VERSION/prboom.wad" ] && [ -f "$BIOS_PATH/PRBOOM/prboom.wad" ]; then + cp "$BIOS_PATH/PRBOOM/prboom.wad" "$BIOS_PATH/PRBOOM/$DOOM_VERSION/prboom.wad" + fi + + touch "$BIOS_PATH/PRBOOM/$DOOM_VERSION/prboom.cfg" + mkdir -p "$BIOS_PATH/PRBOOM/prboom" + mount -o bind "$BIOS_PATH/PRBOOM/$DOOM_VERSION" "$BIOS_PATH/PRBOOM/prboom" +} + +cleanup() { + umount "$BIOS_PATH/PRBOOM/prboom" || true +} + +main() { + trap "cleanup" EXIT INT TERM HUP QUIT + + ROM="$1" + mkdir -p "$BIOS_PATH/$EMU_TAG" + mkdir -p "$SAVES_PATH/$EMU_TAG" + HOME="$USERDATA_PATH" + cd "$HOME" || exit 1 + + DOOM_VERSION="$(get_doom_version "$ROM")" + prep_doom_folder "$DOOM_VERSION" + + if [ ! -f "$BIOS_PATH/PRBOOM/prboom/prboom.wad" ] && [ ! -f "$BIOS_PATH/PRBOOM/prboom.wad" ]; then + echo "No prboom.wad found in $BIOS_PATH/PRBOOM or $BIOS_PATH/PRBOOM/prboom" + exit 1 + fi + + minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" +} + +main "$@" diff --git a/skeleton/EXTRAS/Emus/h700/PUAE.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/PUAE.pak/default.cfg new file mode 100644 index 000000000..82f9adce0 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/PUAE.pak/default.cfg @@ -0,0 +1,17 @@ +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind A / 2nd fire / Blue = A +bind B / Fire / Red = B +bind X / Yellow = X +bind Y / Green = Y +bind Start / Play = START +bind Select = SELECT +bind L / Rewind = L1 +bind R / Forward = R1 +bind L2 = L2 +bind R2 = R2 +bind L3 = L3 +bind R3 = R3 + diff --git a/skeleton/EXTRAS/Emus/h700/PUAE.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/PUAE.pak/launch.sh new file mode 100644 index 000000000..e1aabd29e --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/PUAE.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=puae2021 +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/SEGACD.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/SEGACD.pak/default.cfg new file mode 100644 index 000000000..dac408932 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/SEGACD.pak/default.cfg @@ -0,0 +1,18 @@ +-picodrive_sound_rate = 44100 +-picodrive_smstype = Auto +-picodrive_smsfm = off +-picodrive_smsmapper = Auto +-picodrive_ggghost = off + +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Mode = SELECT +bind Start = START +bind A Button = Y +bind B Button = X:B +bind C Button = A +bind X Button = B:L1 +bind Y Button = L1:X +bind Z Button = R1 diff --git a/skeleton/EXTRAS/Emus/h700/SEGACD.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/SEGACD.pak/launch.sh new file mode 100755 index 000000000..8ceb019a2 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/SEGACD.pak/launch.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +EMU_EXE=picodrive + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/SG1000.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/SG1000.pak/default.cfg new file mode 100644 index 000000000..1daad20e5 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/SG1000.pak/default.cfg @@ -0,0 +1,19 @@ +-picodrive_smstype = Auto +picodrive_smsmapper = Auto +-picodrive_ggghost = off +-picodrive_sound_rate = 44100 +-picodrive_ramcart = disabled +-picodrive_dacnoise = disabled +-picodrive_input1 = 3 button pad +-picodrive_input2 = 3 button pad +-picodrive_fm_filter = off +-picodrive_audio_filter = disabled +-picodrive_overclk68k = disabled + +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Button 1 = B +bind Button 2 = A +bind Pause = START diff --git a/skeleton/EXTRAS/Emus/h700/SG1000.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/SG1000.pak/launch.sh new file mode 100755 index 000000000..8ceb019a2 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/SG1000.pak/launch.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +EMU_EXE=picodrive + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/SGB.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/SGB.pak/default.cfg new file mode 100644 index 000000000..78fdedb28 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/SGB.pak/default.cfg @@ -0,0 +1,24 @@ +-mgba_gb_model = Super Game Boy +mgba_skip_bios = ON +-mgba_gb_colors_preset = 2 +-mgba_force_gbp = OFF +-mgba_color_correction = OFF +-mgba_interframe_blending = OFF +mgba_sgb_borders = ON + +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind A Button = A +bind B Button = B +bind A Turbo = NONE:X +bind B Turbo = NONE:Y +bind L Button = L1 +bind R Button = R1 +bind L Turbo = NONE:L2 +bind R Turbo = NONE:R2 +bind More Sun = NONE:L3 +bind Less Sun = NONE:R3 \ No newline at end of file diff --git a/skeleton/EXTRAS/Emus/h700/SGB.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/SGB.pak/launch.sh new file mode 100755 index 000000000..598c1ca44 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/SGB.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=mgba +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/SMS.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/SMS.pak/default.cfg new file mode 100644 index 000000000..0d2df362d --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/SMS.pak/default.cfg @@ -0,0 +1,19 @@ +-picodrive_smstype = Master System +picodrive_smsmapper = Auto +-picodrive_ggghost = off +-picodrive_sound_rate = 44100 +-picodrive_ramcart = disabled +-picodrive_dacnoise = disabled +-picodrive_input1 = 3 button pad +-picodrive_input2 = 3 button pad +-picodrive_fm_filter = off +-picodrive_audio_filter = disabled +-picodrive_overclk68k = disabled + +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Button 1 = B +bind Button 2 = A +bind Pause = START diff --git a/skeleton/EXTRAS/Emus/h700/SMS.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/SMS.pak/launch.sh new file mode 100755 index 000000000..8ceb019a2 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/SMS.pak/launch.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +EMU_EXE=picodrive + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/SUPA.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/SUPA.pak/default.cfg new file mode 100644 index 000000000..4a77a7b31 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/SUPA.pak/default.cfg @@ -0,0 +1,16 @@ +-supafaust_pixel_format = rgb565 +-supafaust_thread_affinity_emu = 0x3 +-supafaust_thread_affinity_ppu = 0xc + +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind Y Button = Y +bind X Button = X +bind B Button = B +bind A Button = A +bind L Button = L1 +bind R Button = R1 diff --git a/skeleton/EXTRAS/Emus/h700/SUPA.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/SUPA.pak/launch.sh new file mode 100755 index 000000000..09cc58d7a --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/SUPA.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=mednafen_supafaust +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/VB.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/VB.pak/default.cfg new file mode 100644 index 000000000..a83095a2b --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/VB.pak/default.cfg @@ -0,0 +1,20 @@ +minarch_cpu_speed = Performance + +-vb_3dmode = anaglyph +-vb_right_analog_to_digital = disabled + +bind L. Up = UP +bind L. Down = DOWN +bind L. Left = LEFT +bind L. Right = RIGHT +bind Select = SELECT +bind Start = START +bind A = A +bind B = B +bind L Button = L1 +bind R Button = R1 +bind Low Battery = NONE:X +bind R. Up = NONE:L2 +bind R. Down = NONE:L3 +bind R. Left = NONE:R2 +bind R. Right = NONE:R3 diff --git a/skeleton/EXTRAS/Emus/h700/VB.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/VB.pak/launch.sh new file mode 100755 index 000000000..4094998e9 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/VB.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=mednafen_vb +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Emus/h700/VIC.pak/default.cfg b/skeleton/EXTRAS/Emus/h700/VIC.pak/default.cfg new file mode 100644 index 000000000..48c64810e --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/VIC.pak/default.cfg @@ -0,0 +1,14 @@ +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind X Button = X +bind Y Button = Y +bind B Button = B +bind A Button = A +bind L1 Button = L1 +bind L2 Button = L2 +bind R1 Button = R1 +bind R2 Button = R2 diff --git a/skeleton/EXTRAS/Emus/h700/VIC.pak/launch.sh b/skeleton/EXTRAS/Emus/h700/VIC.pak/launch.sh new file mode 100644 index 000000000..1ff5fe536 --- /dev/null +++ b/skeleton/EXTRAS/Emus/h700/VIC.pak/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +EMU_EXE=vice_xvic +CORES_PATH=$(dirname "$0") + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/EXTRAS/Tools/h700/Battery.pak/launch.sh b/skeleton/EXTRAS/Tools/h700/Battery.pak/launch.sh new file mode 100755 index 000000000..de648a67c --- /dev/null +++ b/skeleton/EXTRAS/Tools/h700/Battery.pak/launch.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +cd "$(dirname "$0")" +./battery.elf > ./log.txt 2>&1 diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/Atari Bootlogo 2.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/Atari Bootlogo 2.bmp new file mode 100644 index 000000000..a8d4f0b47 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/Atari Bootlogo 2.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/Atari Bootlogo 3.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/Atari Bootlogo 3.bmp new file mode 100644 index 000000000..685087e47 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/Atari Bootlogo 3.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/Atari Bootlogo 4.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/Atari Bootlogo 4.bmp new file mode 100644 index 000000000..7835dc48e Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/Atari Bootlogo 4.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/Atari Bootlogo.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/Atari Bootlogo.bmp new file mode 100644 index 000000000..16d425660 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/Atari Bootlogo.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/DS Beta BIOS.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/DS Beta BIOS.bmp new file mode 100644 index 000000000..6ea40e8ae Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/DS Beta BIOS.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/DSi Beta BIOS.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/DSi Beta BIOS.bmp new file mode 100644 index 000000000..5ecc0d85b Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/DSi Beta BIOS.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA BIOS BW.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA BIOS BW.bmp new file mode 100644 index 000000000..6654fa9a1 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA BIOS BW.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA BIOS.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA BIOS.bmp new file mode 100644 index 000000000..eaae4b71f Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA BIOS.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA DK 4x3 Black.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA DK 4x3 Black.bmp new file mode 100644 index 000000000..f9b7e69c6 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA DK 4x3 Black.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA DK 4x3.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA DK 4x3.bmp new file mode 100644 index 000000000..6eaef4836 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA DK 4x3.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA Health Safety.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA Health Safety.bmp new file mode 100644 index 000000000..75227ae77 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA Health Safety.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA Logo BW.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA Logo BW.bmp new file mode 100644 index 000000000..16728b1ed Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA Logo BW.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA Logo Pixel 2.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA Logo Pixel 2.bmp new file mode 100644 index 000000000..718ce2f5d Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA Logo Pixel 2.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA Logo Pixel.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA Logo Pixel.bmp new file mode 100644 index 000000000..8b98fcd93 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA Logo Pixel.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA Logo Saturated.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA Logo Saturated.bmp new file mode 100644 index 000000000..0a28d6212 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/GBA Logo Saturated.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/MinUI Next.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/MinUI Next.bmp new file mode 100644 index 000000000..2b75ac9d5 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/MinUI Next.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/MinUI.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/MinUI.bmp new file mode 100644 index 000000000..af863a0a7 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/MinUI.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/NeoGeo Pocket Color BIOS.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/NeoGeo Pocket Color BIOS.bmp new file mode 100644 index 000000000..acaf07d56 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/NeoGeo Pocket Color BIOS.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/NextUI Helaas.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/NextUI Helaas.bmp new file mode 100644 index 000000000..14f6e985e Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/NextUI Helaas.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/NextUI.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/NextUI.bmp new file mode 100644 index 000000000..a2695d486 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/NextUI.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/NintendoPixel.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/NintendoPixel.bmp new file mode 100644 index 000000000..9dbcf29c1 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/NintendoPixel.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/NintendoPixelTilted.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/NintendoPixelTilted.bmp new file mode 100644 index 000000000..71d218c9c Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/NintendoPixelTilted.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/Sony CE Pixel.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/Sony CE Pixel.bmp new file mode 100644 index 000000000..a2928d785 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/480x640/Sony CE Pixel.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/Atari Bootlogo 2.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/Atari Bootlogo 2.bmp new file mode 100644 index 000000000..108512777 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/Atari Bootlogo 2.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/Atari Bootlogo 3.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/Atari Bootlogo 3.bmp new file mode 100644 index 000000000..53835b80b Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/Atari Bootlogo 3.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/Atari Bootlogo 4.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/Atari Bootlogo 4.bmp new file mode 100644 index 000000000..c77df5396 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/Atari Bootlogo 4.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/Atari Bootlogo.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/Atari Bootlogo.bmp new file mode 100644 index 000000000..7c70a6263 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/Atari Bootlogo.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/DS Beta BIOS.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/DS Beta BIOS.bmp new file mode 100644 index 000000000..cc4d64857 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/DS Beta BIOS.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/DSi Beta BIOS.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/DSi Beta BIOS.bmp new file mode 100644 index 000000000..ee9bbecd8 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/DSi Beta BIOS.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA BIOS BW.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA BIOS BW.bmp new file mode 100644 index 000000000..b605fed69 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA BIOS BW.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA BIOS.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA BIOS.bmp new file mode 100644 index 000000000..82dcca540 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA BIOS.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA DK 4x3 Black.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA DK 4x3 Black.bmp new file mode 100644 index 000000000..a652e7d1e Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA DK 4x3 Black.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA DK 4x3.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA DK 4x3.bmp new file mode 100644 index 000000000..157f2f4ea Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA DK 4x3.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA Health Safety.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA Health Safety.bmp new file mode 100644 index 000000000..b17a3913a Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA Health Safety.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA Logo BW.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA Logo BW.bmp new file mode 100644 index 000000000..73832f6b1 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA Logo BW.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA Logo Pixel 2.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA Logo Pixel 2.bmp new file mode 100644 index 000000000..65e4b2f71 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA Logo Pixel 2.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA Logo Pixel.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA Logo Pixel.bmp new file mode 100644 index 000000000..a8483c3bb Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA Logo Pixel.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA Logo Saturated.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA Logo Saturated.bmp new file mode 100644 index 000000000..ed7c3bad7 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/GBA Logo Saturated.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/MinUI Next.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/MinUI Next.bmp new file mode 100644 index 000000000..e62f53d26 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/MinUI Next.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/MinUI.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/MinUI.bmp new file mode 100644 index 000000000..e675787da Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/MinUI.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/NeoGeo Pocket Color BIOS.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/NeoGeo Pocket Color BIOS.bmp new file mode 100644 index 000000000..553b00679 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/NeoGeo Pocket Color BIOS.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/NextUI Helaas.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/NextUI Helaas.bmp new file mode 100644 index 000000000..8ed47595a Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/NextUI Helaas.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/NextUI.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/NextUI.bmp new file mode 100644 index 000000000..293555c8e Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/NextUI.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/NintendoPixel.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/NintendoPixel.bmp new file mode 100644 index 000000000..a7143543e Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/NintendoPixel.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/NintendoPixelTilted.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/NintendoPixelTilted.bmp new file mode 100644 index 000000000..93572a534 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/NintendoPixelTilted.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/Sony CE Pixel.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/Sony CE Pixel.bmp new file mode 100644 index 000000000..ef9038c96 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/640x480/Sony CE Pixel.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/Atari Bootlogo 2.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/Atari Bootlogo 2.bmp new file mode 100644 index 000000000..a88a0a2fe Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/Atari Bootlogo 2.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/Atari Bootlogo 3.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/Atari Bootlogo 3.bmp new file mode 100644 index 000000000..958654fa0 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/Atari Bootlogo 3.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/Atari Bootlogo 4.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/Atari Bootlogo 4.bmp new file mode 100644 index 000000000..7a5fe414d Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/Atari Bootlogo 4.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/Atari Bootlogo.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/Atari Bootlogo.bmp new file mode 100644 index 000000000..678ea516e Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/Atari Bootlogo.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/DS Beta BIOS.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/DS Beta BIOS.bmp new file mode 100644 index 000000000..a6f32a1cf Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/DS Beta BIOS.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/DSi Beta BIOS.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/DSi Beta BIOS.bmp new file mode 100644 index 000000000..cd23d382e Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/DSi Beta BIOS.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA BIOS BW.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA BIOS BW.bmp new file mode 100644 index 000000000..4a0ee4d3b Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA BIOS BW.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA BIOS.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA BIOS.bmp new file mode 100644 index 000000000..d65a4b0dc Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA BIOS.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA DK 4x3 Black.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA DK 4x3 Black.bmp new file mode 100644 index 000000000..0376612f6 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA DK 4x3 Black.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA DK 4x3.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA DK 4x3.bmp new file mode 100644 index 000000000..37b7d5118 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA DK 4x3.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA Health Safety.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA Health Safety.bmp new file mode 100644 index 000000000..ce4f79a24 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA Health Safety.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA Logo BW.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA Logo BW.bmp new file mode 100644 index 000000000..aa0a56657 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA Logo BW.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA Logo Pixel 2.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA Logo Pixel 2.bmp new file mode 100644 index 000000000..fb1a6d44b Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA Logo Pixel 2.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA Logo Pixel.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA Logo Pixel.bmp new file mode 100644 index 000000000..9de803ec7 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA Logo Pixel.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA Logo Saturated.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA Logo Saturated.bmp new file mode 100644 index 000000000..28891aad2 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/GBA Logo Saturated.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/MinUI Next.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/MinUI Next.bmp new file mode 100644 index 000000000..db11a5de4 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/MinUI Next.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/MinUI.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/MinUI.bmp new file mode 100644 index 000000000..2e478d49b Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/MinUI.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/NeoGeo Pocket Color BIOS.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/NeoGeo Pocket Color BIOS.bmp new file mode 100644 index 000000000..616666681 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/NeoGeo Pocket Color BIOS.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/NextUI Helaas.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/NextUI Helaas.bmp new file mode 100644 index 000000000..19eacbbb0 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/NextUI Helaas.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/NextUI.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/NextUI.bmp new file mode 100644 index 000000000..b6f52eef6 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/NextUI.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/NintendoPixel.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/NintendoPixel.bmp new file mode 100644 index 000000000..c8075b283 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/NintendoPixel.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/NintendoPixelTilted.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/NintendoPixelTilted.bmp new file mode 100644 index 000000000..063b2da34 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/NintendoPixelTilted.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/Sony CE Pixel.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/Sony CE Pixel.bmp new file mode 100644 index 000000000..6d67d781b Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x480/Sony CE Pixel.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/Atari Bootlogo 2.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/Atari Bootlogo 2.bmp new file mode 100644 index 000000000..16ed9ee48 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/Atari Bootlogo 2.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/Atari Bootlogo 3.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/Atari Bootlogo 3.bmp new file mode 100644 index 000000000..a14f1b2ea Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/Atari Bootlogo 3.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/Atari Bootlogo 4.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/Atari Bootlogo 4.bmp new file mode 100644 index 000000000..38ed6d957 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/Atari Bootlogo 4.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/Atari Bootlogo.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/Atari Bootlogo.bmp new file mode 100644 index 000000000..ae8ac2733 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/Atari Bootlogo.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/DS Beta BIOS.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/DS Beta BIOS.bmp new file mode 100644 index 000000000..4a8c2a57b Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/DS Beta BIOS.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/DSi Beta BIOS.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/DSi Beta BIOS.bmp new file mode 100644 index 000000000..8f1188080 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/DSi Beta BIOS.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA BIOS BW.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA BIOS BW.bmp new file mode 100644 index 000000000..a2befd402 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA BIOS BW.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA BIOS.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA BIOS.bmp new file mode 100644 index 000000000..45fea350a Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA BIOS.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA DK 4x3 Black.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA DK 4x3 Black.bmp new file mode 100644 index 000000000..b998d2c51 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA DK 4x3 Black.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA DK 4x3.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA DK 4x3.bmp new file mode 100644 index 000000000..dc792d2c2 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA DK 4x3.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA Health Safety.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA Health Safety.bmp new file mode 100644 index 000000000..42f532466 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA Health Safety.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA Logo BW.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA Logo BW.bmp new file mode 100644 index 000000000..c938eca01 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA Logo BW.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA Logo Pixel 2.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA Logo Pixel 2.bmp new file mode 100644 index 000000000..f443d1223 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA Logo Pixel 2.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA Logo Pixel.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA Logo Pixel.bmp new file mode 100644 index 000000000..7d5ef6189 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA Logo Pixel.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA Logo Saturated.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA Logo Saturated.bmp new file mode 100644 index 000000000..8787f2c0c Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/GBA Logo Saturated.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/MinUI Next.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/MinUI Next.bmp new file mode 100644 index 000000000..6369dcb17 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/MinUI Next.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/MinUI.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/MinUI.bmp new file mode 100644 index 000000000..e4384d032 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/MinUI.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/NeoGeo Pocket Color BIOS.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/NeoGeo Pocket Color BIOS.bmp new file mode 100644 index 000000000..29ae63bf6 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/NeoGeo Pocket Color BIOS.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/NextUI Helaas.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/NextUI Helaas.bmp new file mode 100644 index 000000000..35b9d60a5 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/NextUI Helaas.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/NextUI.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/NextUI.bmp new file mode 100644 index 000000000..03dfa0377 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/NextUI.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/NintendoPixel.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/NintendoPixel.bmp new file mode 100644 index 000000000..da3f62afd Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/NintendoPixel.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/NintendoPixelTilted.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/NintendoPixelTilted.bmp new file mode 100644 index 000000000..d3a7dd6d9 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/NintendoPixelTilted.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/Sony CE Pixel.bmp b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/Sony CE Pixel.bmp new file mode 100644 index 000000000..3e520d3f3 Binary files /dev/null and b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/720x720/Sony CE Pixel.bmp differ diff --git a/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/launch.sh b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/launch.sh new file mode 100755 index 000000000..ffe531f4c --- /dev/null +++ b/skeleton/EXTRAS/Tools/h700/Bootlogo.pak/launch.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +cd "$(dirname "$0")" +./bootlogo.elf > ./log.txt 2>&1 diff --git a/skeleton/EXTRAS/Tools/h700/Clock.pak/launch.sh b/skeleton/EXTRAS/Tools/h700/Clock.pak/launch.sh new file mode 100755 index 000000000..ae71b3857 --- /dev/null +++ b/skeleton/EXTRAS/Tools/h700/Clock.pak/launch.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +cd "$(dirname "$0")" +./clock.elf > ./log.txt 2>&1 diff --git a/skeleton/EXTRAS/Tools/h700/Files.pak/h700.cfg b/skeleton/EXTRAS/Tools/h700/Files.pak/h700.cfg new file mode 100644 index 000000000..103e29ff5 --- /dev/null +++ b/skeleton/EXTRAS/Tools/h700/Files.pak/h700.cfg @@ -0,0 +1,6 @@ +disp_width=640 +disp_height=480 +disp_autoscale=1 +disp_autoscale_dpi=0 +disp_ppu_x=2 +disp_ppu_y=2 diff --git a/skeleton/EXTRAS/Tools/h700/Files.pak/launch.sh b/skeleton/EXTRAS/Tools/h700/Files.pak/launch.sh new file mode 100755 index 000000000..af119315d --- /dev/null +++ b/skeleton/EXTRAS/Tools/h700/Files.pak/launch.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +cd $(dirname "$0") + +HOME="$SDCARD_PATH" +CFG="h700.cfg" + +./NextCommander --config $CFG diff --git a/skeleton/EXTRAS/Tools/h700/Game Tracker.pak/launch.sh b/skeleton/EXTRAS/Tools/h700/Game Tracker.pak/launch.sh new file mode 100755 index 000000000..5a3bdac03 --- /dev/null +++ b/skeleton/EXTRAS/Tools/h700/Game Tracker.pak/launch.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +cd "$(dirname "$0")" +./gametime.elf > ./log.txt 2>&1 diff --git a/skeleton/EXTRAS/Tools/h700/Input.pak/launch.sh b/skeleton/EXTRAS/Tools/h700/Input.pak/launch.sh new file mode 100755 index 000000000..ca0aefe28 --- /dev/null +++ b/skeleton/EXTRAS/Tools/h700/Input.pak/launch.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +cd $(dirname "$0") +./minput.elf diff --git a/skeleton/EXTRAS/Tools/h700/LedControl.pak/launch.sh b/skeleton/EXTRAS/Tools/h700/LedControl.pak/launch.sh new file mode 100755 index 000000000..b73cd2c1b --- /dev/null +++ b/skeleton/EXTRAS/Tools/h700/LedControl.pak/launch.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +cd "$(dirname "$0")" + +# Seed the defaults once; after that the file belongs to the user. +TARGET="/mnt/SDCARD/.userdata/shared/ledsettings_h700.txt" +if [ ! -f "$TARGET" ]; then + cp ./ledsettings_h700.txt "$TARGET" +fi + +./ledcontrol.elf > ./log.txt 2>&1 diff --git a/skeleton/EXTRAS/Tools/h700/LedControl.pak/ledsettings_h700.txt b/skeleton/EXTRAS/Tools/h700/LedControl.pak/ledsettings_h700.txt new file mode 100644 index 000000000..3773477ac --- /dev/null +++ b/skeleton/EXTRAS/Tools/h700/LedControl.pak/ledsettings_h700.txt @@ -0,0 +1,19 @@ +[Left] +effect=4 +color1=0x440044 +color2=0x440044 +speed=1000 +brightness=100 +trigger=1 +filename=l +inbrightness=100 + +[Right] +effect=4 +color1=0x440044 +color2=0x440044 +speed=1000 +brightness=100 +trigger=1 +filename=r +inbrightness=100 diff --git a/skeleton/EXTRAS/Tools/h700/Settings.pak/launch.sh b/skeleton/EXTRAS/Tools/h700/Settings.pak/launch.sh new file mode 100644 index 000000000..006467eae --- /dev/null +++ b/skeleton/EXTRAS/Tools/h700/Settings.pak/launch.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +SDCARD_PATH="/mnt/SDCARD" +USERDATA_PATH="$SDCARD_PATH/.userdata" +SHARED_USERDATA_PATH="$USERDATA_PATH/shared" + +cd $(dirname "$0") +./settings.elf > settings.log 2>&1 diff --git a/skeleton/SYSTEM/h700/bin/governor.sh b/skeleton/SYSTEM/h700/bin/governor.sh new file mode 100755 index 000000000..6f9f812ef --- /dev/null +++ b/skeleton/SYSTEM/h700/bin/governor.sh @@ -0,0 +1,87 @@ +#!/bin/sh +# governor.sh - CPU/GPU governor controller for H700 +# Usage: governor.sh +# Modes: auto, performance, powersave + +MODE="$1" +[ -z "$MODE" ] && MODE="auto" + +set_policy() { + local policy_path="$1" + local governor="$2" + local max_type="$3" # "max" or "mid" + + [ -f "$policy_path/scaling_available_frequencies" ] || return 0 + FREQS=$(cat "$policy_path/scaling_available_frequencies" | tr ' ' '\n' | grep -v '^$' | sort -n) + MIN_FREQ=$(echo "$FREQS" | head -1) + + case "$max_type" in + max) + MAX_FREQ=$(echo "$FREQS" | tail -1) + ;; + mid) + COUNT=$(echo "$FREQS" | wc -l) + MID=$(( (COUNT + 1) / 2 )) + MAX_FREQ=$(echo "$FREQS" | sed -n "${MID}p") + ;; + *) + MAX_FREQ=$(echo "$FREQS" | tail -1) + ;; + esac + + echo "$governor" > "$policy_path/scaling_governor" 2>/dev/null || true + echo "$MIN_FREQ" > "$policy_path/scaling_min_freq" + echo "$MAX_FREQ" > "$policy_path/scaling_max_freq" +} + +# The simple_ondemand GPU governor doesn't perform well under vsync. +# Pin to max GPU speed. It costs about 0.5% more battery usage (when screen is at +# full power), but the performance gain is worth it in my opinion. The power gating +# will reduce GPU power when it's not busy anyway: so it's a race-to-idle. Or at +# least that's my logic. +set_gpu_floor() { + local floor_type="$1" # "max" or "min" + + for devfreq in /sys/class/devfreq/*gpu*; do + [ -f "$devfreq/available_frequencies" ] || continue + [ -w "$devfreq/min_freq" ] || continue + + GPU_FREQS=$(cat "$devfreq/available_frequencies" | tr ' ' '\n' | grep -v '^$' | sort -n) + case "$floor_type" in + max) + GPU_FREQ=$(echo "$GPU_FREQS" | tail -1) + ;; + *) + GPU_FREQ=$(echo "$GPU_FREQS" | head -1) + ;; + esac + + [ -n "$GPU_FREQ" ] || continue + echo "$GPU_FREQ" > "$devfreq/min_freq" 2>/dev/null || true + done +} + +case "$MODE" in + auto) + # H700's advertised 1.5 GHz ceiling is in-spec, not an overclock. Let + # schedutil use the full hardware frequency range when load requires it. + set_policy /sys/devices/system/cpu/cpufreq/policy0 "schedutil" "max" + set_policy /sys/devices/system/cpu/cpu0/cpufreq "schedutil" "max" + set_gpu_floor "max" + ;; + performance) + set_policy /sys/devices/system/cpu/cpufreq/policy0 "performance" "max" + set_policy /sys/devices/system/cpu/cpu0/cpufreq "performance" "max" + set_gpu_floor "max" + ;; + powersave) + set_policy /sys/devices/system/cpu/cpufreq/policy0 "conservative" "mid" + set_policy /sys/devices/system/cpu/cpu0/cpufreq "conservative" "mid" + set_gpu_floor "min" + ;; + *) + echo "governor.sh: unknown mode '$MODE'" >&2 + echo " Valid modes: auto, performance, powersave" >&2 + exit 1 + ;; +esac diff --git a/skeleton/SYSTEM/h700/bin/h700-device.sh b/skeleton/SYSTEM/h700/bin/h700-device.sh new file mode 100755 index 000000000..76a0f832d --- /dev/null +++ b/skeleton/SYSTEM/h700/bin/h700-device.sh @@ -0,0 +1,40 @@ +#!/bin/sh +# Map stock RGXX_MODEL (from dmenu.bin) to DEVICE. +# Behaviour keys on DEVICE; RGXX_MODEL is for display/logs only. +# +# RG28xx rg28xx +# RG34xx rg34xx +# RG34xxSP rg34xxsp +# RG35xx rg35xxplus (Plus and 2024 both report RG35xx) +# RG35xxH rg35xxh +# RG35xxPro rg35xxpro +# RG35xxSP rg35xxsp +# RG40xxH rg40xxh +# RG40xxV rg40xxv +# RGcubexx rgcubexx +# RGSP rgsp +# anything else / empty → rg35xxplus + +h700_export_device() { + if [ -z "$RGXX_MODEL" ]; then + RGXX_MODEL="$(strings /mnt/vendor/bin/dmenu.bin 2>/dev/null | grep -m1 '^RG')" + fi + export RGXX_MODEL + + # Longer suffixes before shorter / bare forms. Case-sensitive stock strings. + case "$RGXX_MODEL" in + RG28xx) DEVICE=rg28xx ;; + RG34xxSP) DEVICE=rg34xxsp ;; + RG34xx) DEVICE=rg34xx ;; + RGSP) DEVICE=rgsp ;; + RG35xxSP) DEVICE=rg35xxsp ;; + RG35xxPro) DEVICE=rg35xxpro ;; + RG35xxH) DEVICE=rg35xxh ;; + RG35xx) DEVICE=rg35xxplus ;; + RG40xxV) DEVICE=rg40xxv ;; + RG40xxH) DEVICE=rg40xxh ;; + RGcubexx) DEVICE=rgcubexx ;; + *) DEVICE=rg35xxplus ;; + esac + export DEVICE +} diff --git a/skeleton/SYSTEM/h700/bin/run_hooks.sh b/skeleton/SYSTEM/h700/bin/run_hooks.sh new file mode 100755 index 000000000..3decb9c11 --- /dev/null +++ b/skeleton/SYSTEM/h700/bin/run_hooks.sh @@ -0,0 +1,36 @@ +#!/bin/sh +# run_hooks.sh - shared hook runner for NextUI +# Usage: run_hooks.sh [--sync-only] +# +# dir-name: directory name under $USERDATA_PATH/.hooks/ (e.g. pre-launch.d, boot.d) +# --sync-only: force all scripts to run synchronously +# +# By default, scripts run in the background. Scripts ending in .sync.sh +# always run synchronously. All background scripts are waited on before exit. + +DIR_NAME="$1" +SYNC_ONLY="${2:-}" + +: "${SDCARD_PATH:=/mnt/SDCARD}" +: "${PLATFORM:=h700}" +: "${USERDATA_PATH:=$SDCARD_PATH/.userdata/$PLATFORM}" + +HOOK_DIR="$USERDATA_PATH/.hooks/$DIR_NAME" +[ -d "$HOOK_DIR" ] || exit 0 + +case "$DIR_NAME" in + pre-*) export HOOK_PHASE="pre" ;; + post-*) export HOOK_PHASE="post" ;; + boot*) export HOOK_PHASE="boot" ;; +esac +export HOOK_CATEGORY="$DIR_NAME" + +for script in "$HOOK_DIR"/*.sh; do + [ -f "$script" ] || continue + if [ "$SYNC_ONLY" = "--sync-only" ] || echo "$script" | grep -q '\.sync\.sh$'; then + ( "$script" ) > /dev/null 2>&1 || true + else + ( "$script" ) > /dev/null 2>&1 & + fi +done +wait diff --git a/skeleton/SYSTEM/h700/bin/setterm b/skeleton/SYSTEM/h700/bin/setterm new file mode 100755 index 000000000..97983f35f --- /dev/null +++ b/skeleton/SYSTEM/h700/bin/setterm @@ -0,0 +1,3 @@ +#!/bin/sh +# generates unnecessary errors when missing +exit 0 diff --git a/skeleton/SYSTEM/h700/bin/suspend b/skeleton/SYSTEM/h700/bin/suspend new file mode 100755 index 000000000..72fe500c9 --- /dev/null +++ b/skeleton/SYSTEM/h700/bin/suspend @@ -0,0 +1,150 @@ +#!/bin/sh +# NOTE: stock H700 /bin/sh does not support `set -o pipefail`; +# using it makes the script exit 2 immediately, which NextUI treats +# as a failed suspend and escalates to poweroff. +set -u +set +e +exec 0<&- + +#logfile="/mnt/SDCARD/.userdata/h700/logs/suspend_$(date +%Y%m%d_%H%M%S).log" +#exec >> "$logfile" 2>&1 + +wifid_running= +bluetoothd_running= + +sleep_retval= + +asound_state_dir=/tmp/asound-suspend + +before() { + >&2 echo "Preparing for suspend..." + echo 1 > /sys/class/power_supply/axp2202-battery/work_led 2>/dev/null || true + # RGB models: cut the LED MCU rail, otherwise the last frame stays lit for + # the whole sleep. NextUI repaints it on wake (PLAT_enableBacklight). + echo 0 > /sys/class/power_supply/axp2202-battery/mcu_pwr 2>/dev/null || true + + # Run pre-sleep hooks synchronously before services are stopped. + # Subshell ensures a crashing hook cannot block suspend. + ( "$SYSTEM_PATH/bin/run_hooks.sh" pre-sleep.d --sync-only ) >/dev/null 2>&1 || true + + >&2 echo "Saving mixer state..." + mkdir -p "$asound_state_dir" + alsactl --file "$asound_state_dir/asound.state.pre" store || true + + if pgrep bluetoothd; then + bluetoothd_running=1 + >&2 echo "Stopping bluetoothd..." + "$SYSTEM_PATH/etc/bluetooth/bt_init.sh" stop || true + fi + + if pgrep wpa_supplicant; then + wifid_running=1 + >&2 echo "Stopping wpa_supplicant..." + "$SYSTEM_PATH/etc/wifi/wifi_init.sh" stop || true + fi +} + +# Resume work that must finish BEFORE this script exits: the caller +# (nextui/minarch) reinitializes the ALSA device as soon as system() +# returns, and a concurrent alsactl restore makes that reinit block +# for ~10s (buttons appear dead after wake). +after_sync() { + >&2 echo "Resumed from suspend." + echo 0 > /sys/class/power_supply/axp2202-battery/work_led 2>/dev/null || true + echo 1 > /sys/class/power_supply/axp2202-battery/mcu_pwr 2>/dev/null || true + + if [ -f "$asound_state_dir/asound.state.pre" ]; then + >&2 echo "Restoring mixer state..." + alsactl --file "$asound_state_dir/asound.state.pre" restore || true + fi + + if [ -x "$SYSTEM_PATH/bin/syncsettings.elf" ]; then + >&2 echo "Restoring display settings..." + "$SYSTEM_PATH/bin/syncsettings.elf" || true + fi +} + +# Slow resume work (radios take ~5s) that must NOT delay the script's +# exit, or it freezes the caller's input handling for that long. +after_async() { + if [ -n "$wifid_running" ]; then + >&2 echo "Starting wpa_supplicant..." + "$SYSTEM_PATH/etc/wifi/wifi_init.sh" start || true + fi + + if [ -n "$bluetoothd_running" ]; then + >&2 echo "Starting bluetoothd..." + "$SYSTEM_PATH/etc/bluetooth/bt_init.sh" start || true + fi + + # Run post-resume hooks after core services and display state are restored. + ( "$SYSTEM_PATH/bin/run_hooks.sh" post-resume.d ) >/dev/null 2>&1 +} + +before + +hallkey=/sys/class/power_supply/axp2202-battery/hallkey +os_sleep=/sys/class/power_supply/axp2202-battery/os_sleep + +>&2 echo "Suspending..." +while :; do + sleep_max_tries=5 + for i in $(seq 1 $sleep_max_tries); do + >&2 echo "Deep sleep attempt $i of $sleep_max_tries" + + sleep_time=$(date +%s) + + # Enable Super Standby before sleeping. + # 16 is the value used by stock and stockmod OS, so we preserve + # it, but any non-zero value has the same effect. + # Non-SP kernels do not expose this attribute and already use the + # full USB-controller suspend path. + [ -w "$os_sleep" ] && printf '16' > "$os_sleep" + + # Now issue suspend-to-ram command. + echo mem >/sys/power/state + sleep_retval=$? + + >&2 echo "Deep sleep: kernel returned $sleep_retval" + if [ $sleep_retval -eq 0 ]; then + break + fi + + wake_time=$(date +%s) + time_asleep=$(($wake_time-$sleep_time)) + + # Workaround for a strange false negative case where + # the device sleeps properly but still returns non-zero. + # If unaddressed, the device would sleep again immediately + # after the user tried to wake it. + + # If device has been asleep for longer than a set period, + # ignore the retval and continue with waking the device. + if [ $time_asleep -gt 5 ]; then + >&2 echo "Deep sleep: averting false negative retval - (sleep for $time_asleep secs)" + sleep_retval=0 + break + fi + + + >&2 echo "Deep sleep failed: retrying in 3 seconds" + sleep 3 + done + + # Clamshells: a pocketed power press wakes the kernel even with the + # lid shut. Only hand control back to the caller (which turns the + # screen on) once the lid is actually open; otherwise re-suspend. + # Non-clamshell hallkey reads 1, and a suspend failure must still + # exit so the caller can escalate to poweroff. + if [ $sleep_retval -eq 0 ] && [ -r "$hallkey" ] && [ "$(cat "$hallkey")" = "0" ]; then + >&2 echo "Woke with lid closed; re-suspending" + sleep 1 + continue + fi + break +done + +after_sync +after_async & + +exit $sleep_retval diff --git a/skeleton/SYSTEM/h700/cores/.keep b/skeleton/SYSTEM/h700/cores/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/skeleton/SYSTEM/h700/etc/bluetooth/bt_init.sh b/skeleton/SYSTEM/h700/etc/bluetooth/bt_init.sh new file mode 100755 index 000000000..4ab4f0a26 --- /dev/null +++ b/skeleton/SYSTEM/h700/etc/bluetooth/bt_init.sh @@ -0,0 +1,347 @@ +#!/bin/sh + +# H700 stock firmware attaches the RTL8821CS Bluetooth UART from the stock +# frontend via setBluetooth.sh. NextUI replaces that frontend, so it must run +# the vendor attach path itself before starting BlueZ. + +if [ -z "$RGXX_MODEL" ]; then + RGXX_MODEL="$(strings /mnt/vendor/bin/dmenu.bin 2>/dev/null | grep -m1 '^RG')" +fi +DEVICE_NAME="Anbernic ${RGXX_MODEL:-RG XX} (NextUI)" +VENDOR_BT_SCRIPT="/mnt/vendor/ctrl/setBluetooth.sh" +BTCTL="/usr/bin/bluetoothctl" +BTCTL_TIMEOUT=5 +BLUEALSA="/usr/bin/bluealsa" +HCI_PATH="/sys/class/bluetooth/hci0" +VENDOR_LOCK="/tmp/.init_bt" +NEXTUI_LOCK="/tmp/nextui-bt-init.lock" +HCI_LOG="/tmp/nextui-rtk_hciattach.log" +BLUEALSA_LOG="/tmp/nextui-bluealsa.log" +LOG_DIR="${LOGS_PATH:-/mnt/SDCARD/.userdata/h700/logs}" +LOG_FILE="$LOG_DIR/bluetooth.txt" + +mkdir -p "$LOG_DIR" 2>/dev/null || true + +log() { + bt_message="$(date '+%Y-%m-%d %H:%M:%S') bt_init: $*" + printf '%s\n' "$bt_message" >> "$LOG_FILE" 2>/dev/null || true + printf '%s\n' "$bt_message" >&2 +} + +release_lock() { + rm -rf "$NEXTUI_LOCK" 2>/dev/null || true +} + +acquire_lock() { + bt_lock_tries=0 + while ! mkdir "$NEXTUI_LOCK" 2>/dev/null; do + if [ -r "$NEXTUI_LOCK/pid" ]; then + bt_lock_pid="$(cat "$NEXTUI_LOCK/pid" 2>/dev/null)" + if [ -n "$bt_lock_pid" ] && ! kill -0 "$bt_lock_pid" 2>/dev/null; then + log "Removing stale operation lock from pid $bt_lock_pid" + release_lock + continue + fi + fi + + bt_lock_tries=$((bt_lock_tries + 1)) + if [ "$bt_lock_tries" -ge 10 ]; then + log "Timed out waiting for another Bluetooth operation" + return 1 + fi + sleep 1 + done + + printf '%s\n' "$$" > "$NEXTUI_LOCK/pid" + trap release_lock 0 + trap 'release_lock; exit 1' 1 2 15 + return 0 +} + +unblock_bt() { + if command -v rfkill.elf >/dev/null 2>&1; then + rfkill.elf unblock bluetooth >> "$LOG_FILE" 2>&1 || true + else + rfkill unblock bluetooth >> "$LOG_FILE" 2>&1 || true + fi +} + +block_bt() { + if command -v rfkill.elf >/dev/null 2>&1; then + rfkill.elf block bluetooth >> "$LOG_FILE" 2>&1 || true + else + rfkill block bluetooth >> "$LOG_FILE" 2>&1 || true + fi +} + +run_btctl_bounded() { + if command -v timeout >/dev/null 2>&1; then + timeout "$BTCTL_TIMEOUT" "$BTCTL" "$@" + else + "$BTCTL" "$@" + fi +} + +wait_for_hci() { + bt_hci_tries=0 + while [ ! -d "$HCI_PATH" ] && [ "$bt_hci_tries" -lt 7 ]; do + bt_hci_tries=$((bt_hci_tries + 1)) + sleep 1 + done + [ -d "$HCI_PATH" ] +} + +attach_hci() { + [ -d "$HCI_PATH" ] && return 0 + + if [ ! -x "$VENDOR_BT_SCRIPT" ]; then + log "Vendor Bluetooth script is missing or not executable: $VENDOR_BT_SCRIPT" + return 1 + fi + + # Recover from an interrupted init: the vendor script refuses to attach when + # its tmpfs lock exists, even if rtk_hciattach is no longer running. + if pidof rtk_hciattach >/dev/null 2>&1; then + log "rtk_hciattach is running without hci0; restarting it" + killall rtk_hciattach >> "$LOG_FILE" 2>&1 || true + sleep 1 + fi + rm -f "$VENDOR_LOCK" + + log "Attaching stock Bluetooth UART via $VENDOR_BT_SCRIPT" + : > "$HCI_LOG" + if ! "$VENDOR_BT_SCRIPT" init >> "$HCI_LOG" 2>&1; then + log "Vendor Bluetooth init command failed" + tail -n 80 "$HCI_LOG" >> "$LOG_FILE" 2>&1 || true + return 1 + fi + + if ! wait_for_hci; then + log "Timed out waiting for $HCI_PATH" + tail -n 80 "$HCI_LOG" >> "$LOG_FILE" 2>&1 || true + ps | grep rtk_hciattach | grep -v grep >> "$LOG_FILE" 2>&1 || true + return 1 + fi + + log "Bluetooth adapter appeared as hci0" + return 0 +} + +start_bluez() { + if systemctl is-active --quiet bluetooth 2>/dev/null; then + # BlueZ may have started before hci0 existed. Restart it once after a new + # attach so its initial adapter state is deterministic. + if [ "$bt_attached_now" = "1" ]; then + log "Restarting stock bluetooth.service after HCI attach" + systemctl restart bluetooth >> "$LOG_FILE" 2>&1 || return 1 + fi + else + log "Starting stock bluetooth.service" + systemctl start bluetooth >> "$LOG_FILE" 2>&1 || return 1 + fi + return 0 +} + +wait_for_bluez_adapter() { + bt_bluez_tries=0 + while [ "$bt_bluez_tries" -lt 5 ]; do + if "$BTCTL" show >/dev/null 2>&1; then + return 0 + fi + bt_bluez_tries=$((bt_bluez_tries + 1)) + sleep 1 + done + return 1 +} + +power_on_adapter() { + bt_power_tries=0 + while [ "$bt_power_tries" -lt 5 ]; do + if "$BTCTL" show 2>/dev/null | grep -q 'Powered: yes'; then + return 0 + fi + if "$BTCTL" power on >> "$LOG_FILE" 2>&1; then + sleep 1 + if "$BTCTL" show 2>/dev/null | grep -q 'Powered: yes'; then + return 0 + fi + fi + bt_power_tries=$((bt_power_tries + 1)) + sleep 1 + done + return 1 +} + +bluealsa_dbus_ready() { + if command -v busctl >/dev/null 2>&1; then + busctl --system list 2>/dev/null | grep -q 'org\.bluealsa' + else + pidof bluealsa >/dev/null 2>&1 + fi +} + +start_bluealsa() { + if [ ! -x "$BLUEALSA" ]; then + log "Stock bluealsa is missing or not executable; Bluetooth audio will be disabled" + return 1 + fi + + if pidof bluealsa >/dev/null 2>&1; then + if bluealsa_dbus_ready; then + return 0 + fi + log "bluealsa is running without its D-Bus service; restarting it" + killall bluealsa >> "$LOG_FILE" 2>&1 || true + sleep 1 + fi + + bt_bluealsa_version="$($BLUEALSA --version 2>&1)" + if [ $? -ne 0 ]; then + log "Stock bluealsa cannot run: $bt_bluealsa_version" + return 1 + fi + log "Starting bluealsa $bt_bluealsa_version with A2DP source" + : > "$BLUEALSA_LOG" + # Keep BlueALSA's default volume mode. BaseOS BlueZ does not expose the + # transport Volume property early enough for --a2dp-volume, leaving some + # headsets (including AirPods 4) at absolute volume zero. The default mode + # publishes the mixer control that libmsettings updates after connection. + "$BLUEALSA" -p a2dp-source --initial-volume=100 < /dev/null >> "$BLUEALSA_LOG" 2>&1 & + bt_bluealsa_pid=$! + + bt_bluealsa_tries=0 + while [ "$bt_bluealsa_tries" -lt 5 ]; do + if ! kill -0 "$bt_bluealsa_pid" 2>/dev/null; then + log "bluealsa exited during startup" + tail -n 80 "$BLUEALSA_LOG" >> "$LOG_FILE" 2>&1 || true + return 1 + fi + if bluealsa_dbus_ready; then + log "Bluetooth A2DP source is ready" + return 0 + fi + bt_bluealsa_tries=$((bt_bluealsa_tries + 1)) + sleep 1 + done + + log "Timed out waiting for the bluealsa D-Bus service" + tail -n 80 "$BLUEALSA_LOG" >> "$LOG_FILE" 2>&1 || true + kill "$bt_bluealsa_pid" 2>/dev/null || true + return 1 +} + +start_bt() { + log "Starting Bluetooth for ${RGXX_MODEL:-unknown H700 model}" + + if [ ! -x "$VENDOR_BT_SCRIPT" ]; then + log "Vendor Bluetooth script is missing or not executable: $VENDOR_BT_SCRIPT" + return 1 + fi + if [ ! -x "$BTCTL" ]; then + log "Stock bluetoothctl is missing or not executable: $BTCTL" + return 1 + fi + btctl_version="$($BTCTL --version 2>&1)" + if [ $? -ne 0 ]; then + log "Stock bluetoothctl cannot run: $btctl_version" + return 1 + fi + log "Using stock $btctl_version" + + unblock_bt + + bt_attached_now=0 + if [ ! -d "$HCI_PATH" ]; then + attach_hci || return 1 + bt_attached_now=1 + fi + + if ! "$VENDOR_BT_SCRIPT" enable >> "$LOG_FILE" 2>&1; then + log "Vendor Bluetooth enable command failed" + return 1 + fi + + start_bluez || { + log "Failed to start stock bluetooth.service" + return 1 + } + + if ! wait_for_bluez_adapter; then + log "BlueZ did not expose hci0 through bluetoothctl" + return 1 + fi + + if ! power_on_adapter; then + log "Failed to power on the BlueZ adapter" + return 1 + fi + "$BTCTL" discoverable on >> "$LOG_FILE" 2>&1 || log "Failed to make the adapter discoverable" + "$BTCTL" pairable on >> "$LOG_FILE" 2>&1 || log "Failed to make the adapter pairable" + "$BTCTL" system-alias "$DEVICE_NAME" >> "$LOG_FILE" 2>&1 || log "Failed to set the adapter alias" + + if ! "$BTCTL" show 2>/dev/null | grep -q 'Powered: yes'; then + log "Bluetooth adapter exists but is not powered" + return 1 + fi + if ! "$BTCTL" show 2>/dev/null | grep -q 'Pairable: yes'; then + log "Adapter is powered; Settings will make it pairable while its persistent agent is open" + fi + start_bluealsa || log "Controller Bluetooth is ready, but Bluetooth audio is unavailable" + + log "Bluetooth is ready" + return 0 +} + +stop_bt() { + log "Stopping Bluetooth" + + # Settings may still have discovery clients running while the toggle is being + # changed. Clear them before teardown so they cannot hold open a stale D-Bus + # request after BlueZ exits. + killall bluetoothctl 2>/dev/null || true + + # BaseOS starts BlueZ on demand. When Bluetooth is already off, invoking + # bluetoothctl without bluetoothd can block forever and retain NEXTUI_LOCK, + # preventing the next start operation. Only ask a live daemon to stop scanning + # and power down, and bound both best-effort requests in case it is unhealthy. + if [ -x "$BTCTL" ] && pidof bluetoothd >/dev/null 2>&1; then + run_btctl_bounded scan off >> "$LOG_FILE" 2>&1 || true + run_btctl_bounded power off >> "$LOG_FILE" 2>&1 || true + fi + killall bluetoothctl 2>/dev/null || true + + # Stop the stock A2DP media endpoint before stopping BlueZ. + killall bluealsa 2>/dev/null || true + + systemctl stop bluetooth >> "$LOG_FILE" 2>&1 || killall bluetoothd 2>/dev/null || true + hciconfig hci0 down >> "$LOG_FILE" 2>&1 || true + if pidof rtk_hciattach >/dev/null 2>&1; then + killall rtk_hciattach >> "$LOG_FILE" 2>&1 || true + sleep 1 + fi + rm -f "$VENDOR_LOCK" + block_bt + + log "Bluetooth is stopped" + return 0 +} + +if ! acquire_lock; then + exit 1 +fi + +case "$1" in + start|"") + start_bt + ;; + stop) + stop_bt + ;; + restart) + stop_bt && start_bt + ;; + *) + echo "Usage: $0 {start|stop|restart}" + exit 1 + ;; +esac diff --git a/skeleton/SYSTEM/h700/etc/wifi/wifi_init.sh b/skeleton/SYSTEM/h700/etc/wifi/wifi_init.sh new file mode 100755 index 000000000..c679b287e --- /dev/null +++ b/skeleton/SYSTEM/h700/etc/wifi/wifi_init.sh @@ -0,0 +1,110 @@ +#!/bin/sh + +WIFI_INTERFACE="${WIFI_INTERFACE:-wlan0}" +SDCARD_PATH="${SDCARD_PATH:-/mnt/SDCARD}" +USERDATA_PATH="${USERDATA_PATH:-$SDCARD_PATH/.userdata/h700}" +WIFI_STATE_DIR="$USERDATA_PATH/wifi" +WIFI_RUNTIME_DIR="/tmp/wifi" +WIFI_SOCK_DIR="$WIFI_RUNTIME_DIR/sockets" +WPA_SUPPLICANT_CONF="$WIFI_STATE_DIR/wpa_supplicant.conf" +WPA_ACTION_SCRIPT="$WIFI_RUNTIME_DIR/wpa_action.sh" + +write_default_config() { + mkdir -p "$WIFI_STATE_DIR" "$WIFI_SOCK_DIR" + if [ ! -f "$WPA_SUPPLICANT_CONF" ]; then + cat > "$WPA_SUPPLICANT_CONF" << EOF +ctrl_interface=$WIFI_SOCK_DIR +disable_scan_offload=1 +update_config=1 +wowlan_triggers=any + +EOF + fi +} + +write_action_script() { + mkdir -p "$WIFI_RUNTIME_DIR" + cat > "$WPA_ACTION_SCRIPT" << 'EOF' +#!/bin/sh + +IFACE="$1" +EVENT="$2" + +case "$EVENT" in + CONNECTED) + if command -v dhclient >/dev/null 2>&1; then + dhclient -r "$IFACE" >/dev/null 2>&1 || true + dhclient -nw "$IFACE" >/dev/null 2>&1 || true + elif command -v udhcpc >/dev/null 2>&1; then + killall udhcpc 2>/dev/null || true + udhcpc -i "$IFACE" -b >/dev/null 2>&1 || true + fi + ;; + DISCONNECTED) + if command -v dhclient >/dev/null 2>&1; then + dhclient -r "$IFACE" >/dev/null 2>&1 || true + fi + killall udhcpc 2>/dev/null || true + ;; +esac +EOF + chmod +x "$WPA_ACTION_SCRIPT" +} + +start_dhcp() { + if command -v dhclient >/dev/null 2>&1; then + dhclient -nw "$WIFI_INTERFACE" >/dev/null 2>&1 || true + elif command -v udhcpc >/dev/null 2>&1; then + udhcpc -i "$WIFI_INTERFACE" -b >/dev/null 2>&1 || true + fi +} + +stop_dhcp() { + if command -v dhclient >/dev/null 2>&1; then + dhclient -r "$WIFI_INTERFACE" >/dev/null 2>&1 || true + fi + killall udhcpc 2>/dev/null || true +} + +start() { + systemctl stop NetworkManager 2>/dev/null || true + systemctl stop wpa_supplicant "wpa_supplicant@$WIFI_INTERFACE.service" 2>/dev/null || true + rfkill.elf unblock wifi 2>/dev/null || rfkill unblock wifi 2>/dev/null || true + ip link set "$WIFI_INTERFACE" up 2>/dev/null || true + write_default_config + write_action_script + + killall wpa_cli 2>/dev/null || true + killall wpa_supplicant 2>/dev/null || true + wpa_supplicant -B -i "$WIFI_INTERFACE" -c "$WPA_SUPPLICANT_CONF" -C "$WIFI_SOCK_DIR" >/dev/null 2>&1 + wpa_cli -B -p "$WIFI_SOCK_DIR" -i "$WIFI_INTERFACE" -a "$WPA_ACTION_SCRIPT" >/dev/null 2>&1 || true + start_dhcp +} + +stop() { + wpa_cli -p "$WIFI_SOCK_DIR" -i "$WIFI_INTERFACE" terminate >/dev/null 2>&1 || true + killall wpa_cli 2>/dev/null || true + systemctl stop wpa_supplicant "wpa_supplicant@$WIFI_INTERFACE.service" 2>/dev/null || true + killall wpa_supplicant 2>/dev/null || true + stop_dhcp + ip link set "$WIFI_INTERFACE" down 2>/dev/null || true + rfkill.elf block wifi 2>/dev/null || rfkill block wifi 2>/dev/null || true +} + +case "$1" in + start|"") + start + ;; + stop) + stop + ;; + restart) + stop + sleep 1 + start + ;; + *) + echo "Usage: $0 {start|stop|restart}" + exit 1 + ;; +esac diff --git a/skeleton/SYSTEM/h700/lib/.keep b/skeleton/SYSTEM/h700/lib/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/skeleton/SYSTEM/h700/paks/Emus/FC.pak/default.cfg b/skeleton/SYSTEM/h700/paks/Emus/FC.pak/default.cfg new file mode 100644 index 000000000..90365a9d1 --- /dev/null +++ b/skeleton/SYSTEM/h700/paks/Emus/FC.pak/default.cfg @@ -0,0 +1,20 @@ +fceumm_sndquality = High +fceumm_sndvolume = 10 +-fceumm_aspect = 8:7 PAR +-fceumm_turbo_enable = Player 1 +-fceumm_show_adv_system_options = disabled +-fceumm_show_adv_sound_options = disabled + +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind A Button = A +bind B Button = B +bind A Turbo = NONE:X +bind B Turbo = NONE:Y +bind Change Disk = NONE:L1 +bind Insert Disk = NONE:R1 +bind Insert Coin = NONE:R2 diff --git a/skeleton/SYSTEM/h700/paks/Emus/FC.pak/launch.sh b/skeleton/SYSTEM/h700/paks/Emus/FC.pak/launch.sh new file mode 100755 index 000000000..780ad5456 --- /dev/null +++ b/skeleton/SYSTEM/h700/paks/Emus/FC.pak/launch.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +EMU_EXE=fceumm + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/SYSTEM/h700/paks/Emus/GB.pak/default.cfg b/skeleton/SYSTEM/h700/paks/Emus/GB.pak/default.cfg new file mode 100644 index 000000000..d3e80e7b6 --- /dev/null +++ b/skeleton/SYSTEM/h700/paks/Emus/GB.pak/default.cfg @@ -0,0 +1,18 @@ +gambatte_gb_colorization = internal +gambatte_gb_internal_palette = TWB64 - Pack 1 +gambatte_gb_palette_twb64_1 = TWB64 038 - Pokemon mini Ver. +gambatte_gb_bootloader = disabled +-gambatte_audio_resampler = sinc + +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind A Button = A +bind B Button = B +bind A Turbo = NONE:X +bind B Turbo = NONE:Y +bind Prev. Palette = NONE:L1 +bind Next Palette = NONE:R1 diff --git a/skeleton/SYSTEM/h700/paks/Emus/GB.pak/launch.sh b/skeleton/SYSTEM/h700/paks/Emus/GB.pak/launch.sh new file mode 100755 index 000000000..9b93f4e5d --- /dev/null +++ b/skeleton/SYSTEM/h700/paks/Emus/GB.pak/launch.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +EMU_EXE=gambatte + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/SYSTEM/h700/paks/Emus/GBA.pak/default.cfg b/skeleton/SYSTEM/h700/paks/Emus/GBA.pak/default.cfg new file mode 100644 index 000000000..ea76e21f6 --- /dev/null +++ b/skeleton/SYSTEM/h700/paks/Emus/GBA.pak/default.cfg @@ -0,0 +1,14 @@ +-gpsp_save_method = libretro + +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind A Button = A +bind B Button = B +bind A Turbo = NONE:X +bind B Turbo = NONE:Y +bind L Button = L1 +bind R Button = R1 diff --git a/skeleton/SYSTEM/h700/paks/Emus/GBA.pak/launch.sh b/skeleton/SYSTEM/h700/paks/Emus/GBA.pak/launch.sh new file mode 100755 index 000000000..0ed0b8f3f --- /dev/null +++ b/skeleton/SYSTEM/h700/paks/Emus/GBA.pak/launch.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +EMU_EXE=gpsp + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/SYSTEM/h700/paks/Emus/GBC.pak/default.cfg b/skeleton/SYSTEM/h700/paks/Emus/GBC.pak/default.cfg new file mode 100644 index 000000000..606e7b74c --- /dev/null +++ b/skeleton/SYSTEM/h700/paks/Emus/GBC.pak/default.cfg @@ -0,0 +1,15 @@ +gambatte_gb_bootloader = disabled +-gambatte_audio_resampler = sinc + +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind A Button = A +bind B Button = B +bind A Turbo = NONE:X +bind B Turbo = NONE:Y +bind Prev. Palette = NONE:L1 +bind Next Palette = NONE:R1 diff --git a/skeleton/SYSTEM/h700/paks/Emus/GBC.pak/launch.sh b/skeleton/SYSTEM/h700/paks/Emus/GBC.pak/launch.sh new file mode 100755 index 000000000..9b93f4e5d --- /dev/null +++ b/skeleton/SYSTEM/h700/paks/Emus/GBC.pak/launch.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +EMU_EXE=gambatte + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/SYSTEM/h700/paks/Emus/MD.pak/default.cfg b/skeleton/SYSTEM/h700/paks/Emus/MD.pak/default.cfg new file mode 100644 index 000000000..dac408932 --- /dev/null +++ b/skeleton/SYSTEM/h700/paks/Emus/MD.pak/default.cfg @@ -0,0 +1,18 @@ +-picodrive_sound_rate = 44100 +-picodrive_smstype = Auto +-picodrive_smsfm = off +-picodrive_smsmapper = Auto +-picodrive_ggghost = off + +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Mode = SELECT +bind Start = START +bind A Button = Y +bind B Button = X:B +bind C Button = A +bind X Button = B:L1 +bind Y Button = L1:X +bind Z Button = R1 diff --git a/skeleton/SYSTEM/h700/paks/Emus/MD.pak/launch.sh b/skeleton/SYSTEM/h700/paks/Emus/MD.pak/launch.sh new file mode 100755 index 000000000..8ceb019a2 --- /dev/null +++ b/skeleton/SYSTEM/h700/paks/Emus/MD.pak/launch.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +EMU_EXE=picodrive + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/SYSTEM/h700/paks/Emus/PS.pak/default.cfg b/skeleton/SYSTEM/h700/paks/Emus/PS.pak/default.cfg new file mode 100644 index 000000000..1daef22c7 --- /dev/null +++ b/skeleton/SYSTEM/h700/paks/Emus/PS.pak/default.cfg @@ -0,0 +1,26 @@ +-pcsx_rearmed_display_internal_fps = disabled +-pcsx_rearmed_show_input_settings = disabled +minarch_rewind_buffer_mb = 128 +minarch_rewind_granularity = 33 +minarch_rewind_compression_speed = 12 +minarch_rewind_compression = On + +pcsx_rearmed_dithering = enabled + +minarch_gamepad_type = 1 +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind Circle = A +bind Cross = B +bind Triangle = X +bind Square = Y +bind L1 Button = L1 +bind R1 Button = R1 +bind L2 Button = L2 +bind R2 Button = R2 +bind L3 Button = L3 +bind R3 Button = R3 diff --git a/skeleton/SYSTEM/h700/paks/Emus/PS.pak/launch.sh b/skeleton/SYSTEM/h700/paks/Emus/PS.pak/launch.sh new file mode 100755 index 000000000..d15d0b984 --- /dev/null +++ b/skeleton/SYSTEM/h700/paks/Emus/PS.pak/launch.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +EMU_EXE=pcsx_rearmed + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/SYSTEM/h700/paks/Emus/SFC.pak/default.cfg b/skeleton/SYSTEM/h700/paks/Emus/SFC.pak/default.cfg new file mode 100644 index 000000000..8100f20a1 --- /dev/null +++ b/skeleton/SYSTEM/h700/paks/Emus/SFC.pak/default.cfg @@ -0,0 +1,12 @@ +bind Up = UP +bind Down = DOWN +bind Left = LEFT +bind Right = RIGHT +bind Select = SELECT +bind Start = START +bind Y Button = Y +bind X Button = X +bind B Button = B +bind A Button = A +bind L Button = L1 +bind R Button = R1 \ No newline at end of file diff --git a/skeleton/SYSTEM/h700/paks/Emus/SFC.pak/launch.sh b/skeleton/SYSTEM/h700/paks/Emus/SFC.pak/launch.sh new file mode 100755 index 000000000..efbb14e2c --- /dev/null +++ b/skeleton/SYSTEM/h700/paks/Emus/SFC.pak/launch.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +EMU_EXE=snes9x + +############################### + +EMU_TAG=$(basename "$(dirname "$0")" .pak) +ROM="$1" +mkdir -p "$BIOS_PATH/$EMU_TAG" +mkdir -p "$SAVES_PATH/$EMU_TAG" +mkdir -p "$CHEATS_PATH/$EMU_TAG" +HOME="$USERDATA_PATH" +cd "$HOME" +minarch.elf "$CORES_PATH/${EMU_EXE}_libretro.so" "$ROM" > "$LOGS_PATH/$EMU_TAG.txt" 2>&1 diff --git a/skeleton/SYSTEM/h700/paks/MinUI.pak/launch.sh b/skeleton/SYSTEM/h700/paks/MinUI.pak/launch.sh new file mode 100755 index 000000000..52696d5d2 --- /dev/null +++ b/skeleton/SYSTEM/h700/paks/MinUI.pak/launch.sh @@ -0,0 +1,219 @@ +#!/bin/sh +# MinUI.pak for Anbernic RG XX / Allwinner H700 + +export PLATFORM="h700" +REAL_SDCARD_PATH="/mnt/sdcard" +COMPAT_SDCARD_PATH="/mnt/SDCARD" + +mkdir -p "$REAL_SDCARD_PATH" +if ! mountpoint -q "$REAL_SDCARD_PATH"; then + mount -t vfat -o rw,utf8,noatime /dev/mmcblk1p1 "$REAL_SDCARD_PATH" 2>/dev/null || true +fi + +if ! mountpoint -q "$COMPAT_SDCARD_PATH" && [ ! -L "$COMPAT_SDCARD_PATH" ]; then + if [ -e "$COMPAT_SDCARD_PATH" ]; then + mount --bind "$REAL_SDCARD_PATH" "$COMPAT_SDCARD_PATH" 2>/dev/null || true + else + ln -s "$REAL_SDCARD_PATH" "$COMPAT_SDCARD_PATH" 2>/dev/null || true + fi +fi + +export SDCARD_PATH="$COMPAT_SDCARD_PATH" +export BIOS_PATH="$SDCARD_PATH/Bios" +export ROMS_PATH="$SDCARD_PATH/Roms" +export SAVES_PATH="$SDCARD_PATH/Saves" +export CHEATS_PATH="$SDCARD_PATH/Cheats" +export SYSTEM_PATH="$SDCARD_PATH/.system/$PLATFORM" +export CORES_PATH="$SYSTEM_PATH/cores" +export USERDATA_PATH="$SDCARD_PATH/.userdata/$PLATFORM" +export SHARED_USERDATA_PATH="$SDCARD_PATH/.userdata/shared" +export LOGS_PATH="$USERDATA_PATH/logs" +export HOOKS_PATH="$USERDATA_PATH/.hooks" +export DATETIME_PATH="$SHARED_USERDATA_PATH/datetime.txt" +export HOME="$USERDATA_PATH" +LAUNCH_LOG="$LOGS_PATH/launch.txt" + +export PATH="$SYSTEM_PATH/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH" +export LD_LIBRARY_PATH="$SYSTEM_PATH/lib:/usr/lib:/usr/lib/aarch64-linux-gnu:/lib/aarch64-linux-gnu:$LD_LIBRARY_PATH" +export CURL_CA_BUNDLE="$SYSTEM_PATH/etc/ssl/certs/ca-certificates.crt" +export SDL_VIDEODRIVER="mali" +export SDL_AUDIODRIVER="alsa" +export SDL_JOYSTICK_DISABLE_UDEV=1 +export SDL_HIDAPI_JOYSTICK_DISABLE_UDEV=1 + +for egl_path in /usr/lib/libEGL.so /usr/lib/libEGL.so.1 /usr/lib/libEGL.so.1.4.0 /usr/lib/aarch64-linux-gnu/libEGL.so /usr/lib/aarch64-linux-gnu/libEGL.so.1; do + if [ -e "$egl_path" ]; then + export SDL_VIDEO_EGL_DRIVER="$egl_path" + break + fi +done +for gles_path in /usr/lib/libGLESv2.so /usr/lib/libGLESv2.so.2 /usr/lib/libGLESv2.so.2.1.0 /usr/lib/aarch64-linux-gnu/libGLESv2.so /usr/lib/aarch64-linux-gnu/libGLESv2.so.2; do + if [ -e "$gles_path" ]; then + export SDL_VIDEO_GL_DRIVER="$gles_path" + break + fi +done + +log_runtime_state() { + echo "launch: runtime state $(date)" >> "$LAUNCH_LOG" + echo "launch: DEVICE=$DEVICE RGXX_MODEL=$RGXX_MODEL" >> "$LAUNCH_LOG" + echo "launch: LD_LIBRARY_PATH=$LD_LIBRARY_PATH" >> "$LAUNCH_LOG" + ldd "$SYSTEM_PATH/bin/nextui.elf" >> "$LAUNCH_LOG" 2>&1 || true + ldd "$SYSTEM_PATH/lib/libSDL2-2.0.so.0" >> "$LAUNCH_LOG" 2>&1 || true + ls -l /usr/lib/libEGL.so* /usr/lib/libGLESv2.so* /usr/lib/aarch64-linux-gnu/libEGL.so* /usr/lib/aarch64-linux-gnu/libGLESv2.so* >> "$LAUNCH_LOG" 2>&1 || true +} + +ensure_system_dbus() { + [ -S /run/dbus/system_bus_socket ] && return 0 + command -v dbus-daemon >/dev/null 2>&1 || return 1 + + mkdir -p /run/dbus + if [ ! -s /run/machine-id ] && command -v dbus-uuidgen >/dev/null 2>&1; then + dbus-uuidgen > /run/machine-id 2>/dev/null || true + fi + dbus-daemon --system >/dev/null 2>&1 || true + + dbus_tries=0 + while [ ! -S /run/dbus/system_bus_socket ] && [ "$dbus_tries" -lt 20 ]; do + sleep 0.1 2>/dev/null || sleep 1 + dbus_tries=$((dbus_tries + 1)) + done + [ -S /run/dbus/system_bus_socket ] +} + +if [ -f "/tmp/poweroff" ]; then + poweroff_next || poweroff + exit 0 +fi +if [ -f "/tmp/reboot" ]; then + reboot_next || reboot + exit 0 +fi + +mkdir -p "$BIOS_PATH" "$ROMS_PATH" "$SAVES_PATH" "$CHEATS_PATH" +mkdir -p "$USERDATA_PATH" "$LOGS_PATH" "$HOOKS_PATH" "$SHARED_USERDATA_PATH/.minui" +echo "launch: starting $(date)" > "$LAUNCH_LOG" + +. "$SYSTEM_PATH/bin/h700-device.sh" +h700_export_device +if [ "$DEVICE" = "rg28xx" ]; then + export SDL_ROTATION="${SDL_ROTATION:-1}" +fi +export IS_NEXT="yes" +log_runtime_state + +if [ -f /mnt/vendor/muos1.ini ] || [ -f /mnt/vendor/muos2.ini ]; then + echo "stockmod muOS override files are present; stock boot target must be selected for TF1 dmenu.bin autoboot." > "$LOGS_PATH/stockmod-warning.txt" +fi + +killall brightCtrl.bin cexpert 2>/dev/null || true +systemctl stop NetworkManager 2>/dev/null || true +if loginctl show-logind >/dev/null 2>&1; then + mkdir -p /run/systemd/logind.conf.d /run/systemd/system 2>/dev/null || true + cat > /run/systemd/logind.conf.d/nextui-h700.conf << EOF +[Login] +HandlePowerKey=ignore +HandlePowerKeyLongPress=ignore +EOF + systemctl restart systemd-logind 2>/dev/null || true +fi + +if [ -f "$SYSTEM_PATH/dat/dmenu.bin" ] && mountpoint -q /mnt/mmc; then + if ! cmp -s "$SYSTEM_PATH/dat/dmenu.bin" /mnt/mmc/dmenu.bin 2>/dev/null; then + cp "$SYSTEM_PATH/dat/dmenu.bin" /mnt/mmc/dmenu.bin 2>/dev/null || true + sync + fi +fi + +rm -rf "$SDCARD_PATH/.shadercache" +echo 0 > /sys/class/power_supply/axp2202-battery/work_led 2>/dev/null || true + +sh "$SYSTEM_PATH/bin/governor.sh" "auto" + +keymon.elf > "$LOGS_PATH/keymon.txt" 2>&1 & +batmon.elf > "$LOGS_PATH/batmon.txt" 2>&1 & + +rm -f "$USERDATA_PATH/.asoundrc" +ensure_system_dbus || echo "launch: system D-Bus unavailable; audio device monitoring may be disabled" >> "$LAUNCH_LOG" +audiomon.elf > "$LOGS_PATH/audiomon.txt" 2>&1 & + +bluetoothon=$(nextval.elf bluetooth | sed -n 's/.*"bluetooth": \([0-9]*\).*/\1/p') +if [ "$bluetoothon" = "0" ]; then + "$SYSTEM_PATH/etc/bluetooth/bt_init.sh" stop > /dev/null 2>&1 & +else + "$SYSTEM_PATH/etc/bluetooth/bt_init.sh" start > /dev/null 2>&1 & +fi + +wifion=$(nextval.elf wifi | sed -n 's/.*"wifi": \([0-9]*\).*/\1/p') +if [ "$wifion" = "0" ]; then + "$SYSTEM_PATH/etc/wifi/wifi_init.sh" stop > /dev/null 2>&1 & +else + "$SYSTEM_PATH/etc/wifi/wifi_init.sh" start > /dev/null 2>&1 & +fi + +AUTO_PATH="$USERDATA_PATH/auto.sh" +if [ -f "$AUTO_PATH" ]; then + "$AUTO_PATH" +fi +"$SYSTEM_PATH/bin/run_hooks.sh" boot.d + +cd "$(dirname "$0")" +killall -9 show2.elf > /dev/null 2>&1 || true + +parse_hook_cmd() { + HOOK_CMD="$1" + HOOK_EMU_PATH=$(echo "$HOOK_CMD" | sed "s/^'\\([^']*\\)'.*/\\1/") + _remainder=$(echo "$HOOK_CMD" | sed "s/^'[^']*'//") + if echo "$_remainder" | grep -q "'"; then + HOOK_TYPE="rom" + HOOK_ROM_PATH=$(echo "$_remainder" | sed "s/.*'\\([^']*\\)'.*/\\1/") + else + HOOK_TYPE="pak" + HOOK_ROM_PATH="" + fi + [ -f /tmp/last.txt ] && HOOK_LAST=$(cat /tmp/last.txt) || HOOK_LAST="" + export HOOK_CMD HOOK_EMU_PATH HOOK_TYPE HOOK_ROM_PATH HOOK_LAST +} + +EXEC_PATH="/tmp/nextui_exec" +NEXT_PATH="/tmp/next" +CRASH_COUNT=0 +touch "$EXEC_PATH" && sync +while [ -f "$EXEC_PATH" ]; do + echo "launch: starting nextui.elf $(date)" >> "$LAUNCH_LOG" + nextui.elf > "$LOGS_PATH/nextui.txt" 2>&1 + EXIT_CODE=$? + echo "launch: nextui.elf exited $EXIT_CODE $(date)" >> "$LAUNCH_LOG" + if [ "$EXIT_CODE" != "0" ]; then + CRASH_COUNT=$((CRASH_COUNT + 1)) + if [ "$CRASH_COUNT" -ge 5 ]; then + echo "launch: crash limit reached; powering off" >> "$LAUNCH_LOG" + rm -f "$EXEC_PATH" + continue + fi + else + CRASH_COUNT=0 + fi + sh "$SYSTEM_PATH/bin/governor.sh" "performance" + + if [ -f "$NEXT_PATH" ]; then + CMD="$(cat "$NEXT_PATH")" + parse_hook_cmd "$CMD" + "$SYSTEM_PATH/bin/run_hooks.sh" pre-launch.d + eval "$CMD" + "$SYSTEM_PATH/bin/run_hooks.sh" post-launch.d + rm -f "$NEXT_PATH" + sh "$SYSTEM_PATH/bin/governor.sh" "performance" + fi + + if [ -f "/tmp/poweroff" ]; then + poweroff_next || poweroff + exit 0 + fi + if [ -f "/tmp/reboot" ]; then + reboot_next || reboot + exit 0 + fi +done + +poweroff_next || poweroff diff --git a/skeleton/SYSTEM/h700/shaders/colorfix.glsl b/skeleton/SYSTEM/h700/shaders/colorfix.glsl new file mode 100644 index 000000000..20a129919 --- /dev/null +++ b/skeleton/SYSTEM/h700/shaders/colorfix.glsl @@ -0,0 +1,21 @@ +#if defined(VERTEX) +attribute vec2 VertexCoord; +attribute vec2 TexCoord; +varying vec2 vTexCoord; + +void main() { + vTexCoord = TexCoord; + gl_Position = vec4(VertexCoord, 0.0, 1.0); +} +#endif + +#if defined(FRAGMENT) +precision mediump float; +uniform sampler2D Texture; +varying vec2 vTexCoord; + +void main() { + vec4 pixel = texture2D(Texture, vec2(vTexCoord.x, 1.0 - vTexCoord.y)); + gl_FragColor = vec4(pixel.a, pixel.b, pixel.g, pixel.r); +} +#endif \ No newline at end of file diff --git a/skeleton/SYSTEM/h700/shaders/default.glsl b/skeleton/SYSTEM/h700/shaders/default.glsl new file mode 100644 index 000000000..539ab8478 --- /dev/null +++ b/skeleton/SYSTEM/h700/shaders/default.glsl @@ -0,0 +1,21 @@ +#if defined(VERTEX) +attribute vec2 VertexCoord; +attribute vec2 TexCoord; +varying vec2 vTexCoord; + +void main() { + // Flip Y-axis in the vertex shader + vTexCoord = vec2(TexCoord.x, 1.0 - TexCoord.y); // Flip Y + gl_Position = vec4(VertexCoord, 0.0, 1.0); +} +#endif + +#if defined(FRAGMENT) +precision mediump float; +uniform sampler2D Texture; +varying vec2 vTexCoord; + +void main() { + gl_FragColor = texture2D(Texture, vTexCoord); +} +#endif \ No newline at end of file diff --git a/skeleton/SYSTEM/h700/shaders/noshader.glsl b/skeleton/SYSTEM/h700/shaders/noshader.glsl new file mode 100644 index 000000000..c7f94f998 --- /dev/null +++ b/skeleton/SYSTEM/h700/shaders/noshader.glsl @@ -0,0 +1,21 @@ +#if defined(VERTEX) +attribute vec2 VertexCoord; +attribute vec2 TexCoord; +varying vec2 vTexCoord; + +void main() { + // Flip Y-axis in the vertex shader + vTexCoord = vec2(TexCoord.x, TexCoord.y); // Flip Y + gl_Position = vec4(VertexCoord, 0.0, 1.0); +} +#endif + +#if defined(FRAGMENT) +precision mediump float; +uniform sampler2D Texture; +varying vec2 vTexCoord; + +void main() { + gl_FragColor = texture2D(Texture, vTexCoord); +} +#endif \ No newline at end of file diff --git a/skeleton/SYSTEM/h700/shaders/overlay.glsl b/skeleton/SYSTEM/h700/shaders/overlay.glsl new file mode 100644 index 000000000..5672d1a90 --- /dev/null +++ b/skeleton/SYSTEM/h700/shaders/overlay.glsl @@ -0,0 +1,20 @@ +#if defined(VERTEX) +attribute vec2 VertexCoord; +attribute vec2 TexCoord; +varying vec2 vTexCoord; + +void main() { + vTexCoord = TexCoord; + gl_Position = vec4(VertexCoord, 0.0, 1.0); +} +#endif + +#if defined(FRAGMENT) +precision mediump float; +uniform sampler2D Texture; +varying vec2 vTexCoord; + +void main() { + gl_FragColor = texture2D(Texture, vec2(vTexCoord.x, 1.0 - vTexCoord.y)); +} +#endif \ No newline at end of file diff --git a/skeleton/SYSTEM/h700/shaders/pixellate.glsl b/skeleton/SYSTEM/h700/shaders/pixellate.glsl new file mode 100644 index 000000000..aa248462f --- /dev/null +++ b/skeleton/SYSTEM/h700/shaders/pixellate.glsl @@ -0,0 +1,143 @@ +// Pixellate Shader +// Copyright (c) 2011, 2012 Fes +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +// IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// (Fes gave their permission to have this shader distributed under this +// licence in this forum post: +// http://board.byuu.org/viewtopic.php?p=57295#p57295 + +// Parameter lines go here: +#pragma parameter INTERPOLATE_IN_LINEAR_GAMMA "Linear Gamma Weight" 1.0 0.0 1.0 1.0 + +#if defined(VERTEX) + +#if __VERSION__ >= 130 +#define COMPAT_VARYING out +#define COMPAT_ATTRIBUTE in +#define COMPAT_TEXTURE texture +#else +#define COMPAT_VARYING varying +#define COMPAT_ATTRIBUTE attribute +#define COMPAT_TEXTURE texture2D +#endif + +#ifdef GL_ES +#define COMPAT_PRECISION mediump +#else +#define COMPAT_PRECISION +#endif + +COMPAT_ATTRIBUTE vec4 VertexCoord; +COMPAT_ATTRIBUTE vec4 COLOR; +COMPAT_ATTRIBUTE vec4 TexCoord; +COMPAT_VARYING vec4 COL0; +COMPAT_VARYING vec4 TEX0; + +uniform mat4 MVPMatrix; +uniform COMPAT_PRECISION int FrameDirection; +uniform COMPAT_PRECISION int FrameCount; +uniform COMPAT_PRECISION vec2 OutputSize; +uniform COMPAT_PRECISION vec2 TextureSize; +uniform COMPAT_PRECISION vec2 InputSize; + +// vertex compatibility #defines +#define vTexCoord TEX0.xy +#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize +#define outsize vec4(OutputSize, 1.0 / OutputSize) + +void main() +{ + gl_Position = MVPMatrix * VertexCoord; + COL0 = COLOR; + TEX0.xy = TexCoord.xy; +} + +#elif defined(FRAGMENT) + +#if __VERSION__ >= 130 +#define COMPAT_VARYING in +#define COMPAT_TEXTURE texture +out vec4 FragColor; +#else +#define COMPAT_VARYING varying +#define FragColor gl_FragColor +#define COMPAT_TEXTURE texture2D +#endif + +#ifdef GL_ES +#ifdef GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; +#endif +#define COMPAT_PRECISION highp +#else +#define COMPAT_PRECISION +#endif + +uniform COMPAT_PRECISION int FrameDirection; +uniform COMPAT_PRECISION int FrameCount; +uniform COMPAT_PRECISION vec2 OutputSize; +uniform COMPAT_PRECISION vec2 TextureSize; +uniform COMPAT_PRECISION vec2 InputSize; +uniform sampler2D Texture; +COMPAT_VARYING vec4 TEX0; + +// fragment compatibility #defines +#define Source Texture +#define vTexCoord TEX0.xy + +#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize +#define outsize vec4(OutputSize, 1.0 / OutputSize) + +#ifdef PARAMETER_UNIFORM +uniform COMPAT_PRECISION float INTERPOLATE_IN_LINEAR_GAMMA; +#else +#define INTERPOLATE_IN_LINEAR_GAMMA 1.0 +#endif + +void main() +{ + vec2 texelSize = SourceSize.zw; + + vec2 range = vec2(abs(InputSize.x / (outsize.x * SourceSize.x)), abs(InputSize.y / (outsize.y * SourceSize.y))); + range = range / 2.0 * 0.999; + + float left = vTexCoord.x - range.x; + float top = vTexCoord.y + range.y; + float right = vTexCoord.x + range.x; + float bottom = vTexCoord.y - range.y; + + vec3 topLeftColor = COMPAT_TEXTURE(Source, (floor(vec2(left, top) / texelSize) + 0.5) * texelSize).rgb; + vec3 bottomRightColor = COMPAT_TEXTURE(Source, (floor(vec2(right, bottom) / texelSize) + 0.5) * texelSize).rgb; + vec3 bottomLeftColor = COMPAT_TEXTURE(Source, (floor(vec2(left, bottom) / texelSize) + 0.5) * texelSize).rgb; + vec3 topRightColor = COMPAT_TEXTURE(Source, (floor(vec2(right, top) / texelSize) + 0.5) * texelSize).rgb; + + if (INTERPOLATE_IN_LINEAR_GAMMA > 0.5){ + topLeftColor = pow(topLeftColor, vec3(2.2)); + bottomRightColor = pow(bottomRightColor, vec3(2.2)); + bottomLeftColor = pow(bottomLeftColor, vec3(2.2)); + topRightColor = pow(topRightColor, vec3(2.2)); + } + + vec2 border = clamp(floor((vTexCoord / texelSize) + vec2(0.5)) * texelSize, vec2(left, bottom), vec2(right, top)); + + float totalArea = 4.0 * range.x * range.y; + + vec3 averageColor; + averageColor = ((border.x - left) * (top - border.y) / totalArea) * topLeftColor; + averageColor += ((right - border.x) * (border.y - bottom) / totalArea) * bottomRightColor; + averageColor += ((border.x - left) * (border.y - bottom) / totalArea) * bottomLeftColor; + averageColor += ((right - border.x) * (top - border.y) / totalArea) * topRightColor; + + FragColor = (INTERPOLATE_IN_LINEAR_GAMMA > 0.5) ? vec4(pow(averageColor, vec3(1.0 / 2.2)), 1.0) : vec4(averageColor, 1.0); +} +#endif diff --git a/skeleton/SYSTEM/h700/system.cfg b/skeleton/SYSTEM/h700/system.cfg new file mode 100644 index 000000000..3a0888cc5 --- /dev/null +++ b/skeleton/SYSTEM/h700/system.cfg @@ -0,0 +1,19 @@ +minarch_screen_scaling = Aspect +minarch_nrofshaders = 0 +minarch_shader1 = stock.glsl +minarch_shader1_filter = NEAREST +minarch_shader1_srctype = source +minarch_shader1_scaletype = source +minarch_shader1_upscale = 2 +minarch_shader2 = stock.glsl +minarch_shader2_filter = LINEAR +minarch_shader2_srctype = relative +minarch_shader2_scaletype = relative +minarch_shader2_upscale = 1 +minarch_shader3 = stock.glsl +minarch_shader3_filter = NEAREST +minarch_shader3_srctype = source +minarch_shader3_scaletype = source +minarch_shader3_upscale = screen +minarch_scale_filter = NEAREST +-minarch_thread_video = Off diff --git a/workspace/all/audiomon/Makefile b/workspace/all/audiomon/Makefile index b22e9c7d9..aad2d5784 100644 --- a/workspace/all/audiomon/Makefile +++ b/workspace/all/audiomon/Makefile @@ -28,6 +28,9 @@ CCXX= $(CROSS_COMPILE)g++ CXXFLAGS += -Wall -O2 -I. -I../common/ -I../../$(PLATFORM)/platform/ -I$(PREFIX)/include/dbus-1.0 -I$(PREFIX)/lib/dbus-1.0/include LDFLAGS += $$(pkg-config --libs dbus-1 libudev) CXXFLAGS += -I$(PREFIX_LOCAL)/include -DPLATFORM=\"$(PLATFORM)\" $$(pkg-config --cflags dbus-1 libudev) +ifeq ($(PLATFORM),h700) +CXXFLAGS += -DH700_BLUEALSA_NO_DELAY +endif LDFLAGS += -L$(PREFIX_LOCAL)/lib -lmsettings SRCS = audiomon.cpp @@ -40,7 +43,7 @@ all: $(PREFIX_LOCAL)/include/msettings.h $(PRODUCT) build/$(PLATFORM): mkdir -p $@ -$(PRODUCT): build/$(PLATFORM) $(OBJS) +$(PRODUCT): build/$(PLATFORM) $(OBJS) Makefile ../../$(PLATFORM)/platform/makefile.env $(CXX) -o $@ $(OBJS) $(LDFLAGS) $(PREFIX_LOCAL)/include/msettings.h: @@ -49,7 +52,7 @@ $(PREFIX_LOCAL)/include/msettings.h: %.o: %.cpp $(CXX) $(CXXFLAGS) -c $< -o $@ -build/$(PLATFORM)/%.o: %.cpp +build/$(PLATFORM)/%.o: %.cpp Makefile ../../$(PLATFORM)/platform/makefile.env $(CXX) $(CXXFLAGS) -c $< -o $@ clean: diff --git a/workspace/all/audiomon/audiomon.cpp b/workspace/all/audiomon/audiomon.cpp index 6fafd66f7..0815982ea 100644 --- a/workspace/all/audiomon/audiomon.cpp +++ b/workspace/all/audiomon/audiomon.cpp @@ -39,6 +39,17 @@ void log(const std::string& msg) { else std::cout << msg << std::endl; } +bool commandExists(const char *command) { + std::string cmd = "command -v "; + cmd += command; + cmd += " >/dev/null 2>&1"; + return std::system(cmd.c_str()) == 0; +} + +bool bluetoothAudioAvailable() { + return commandExists("bluealsa"); +} + void ensureDirExists(const std::string& path) { mkdir(path.c_str(), 0755); } @@ -59,9 +70,11 @@ void writeAudioFile(const std::string& device_identifier, DeviceType type) { << " slave.pcm {\n" << " type bluealsa\n" << " device \"" << device_identifier << "\"\n" - << " profile \"a2dp\"\n" - << " delay 0\n" - << " }\n" + << " profile \"a2dp\"\n"; +#ifndef H700_BLUEALSA_NO_DELAY + f << " delay 0\n"; +#endif + f << " }\n" << "}\n" << "ctl.!default {\n" << " type bluealsa\n" @@ -202,6 +215,10 @@ bool hasUUID(DBusConnection* conn, const std::string& path, const std::string& u void handleDeviceConnected(DBusConnection* conn, const std::string& path) { std::string mac = pathToMac(path); if (hasUUID(conn, path, UUID_A2DP)) { + if (!bluetoothAudioAvailable()) { + log("Audio device connected but bluealsa is unavailable: " + mac); + return; + } log("Audio device connected: " + mac); writeAudioFile(mac, DEVICE_BLUETOOTH); SetAudioSink(AUDIO_SINK_BLUETOOTH); diff --git a/workspace/all/bootlogo/bootlogo.c b/workspace/all/bootlogo/bootlogo.c index c9c2913a3..2ae307fd2 100644 --- a/workspace/all/bootlogo/bootlogo.c +++ b/workspace/all/bootlogo/bootlogo.c @@ -1,8 +1,11 @@ #include #include #include +#include #include #include +#include +#include #include #include @@ -25,28 +28,74 @@ static void sigHandler(int sig) } } +// the stock OS reads bootlogo.bmp from this vfat partition at power-on +#ifndef BOOTLOGO_PARTITION +#define BOOTLOGO_PARTITION "/dev/mmcblk0p1" +#endif + +// platforms whose bootloader blits the logo panel-native onto a rotated panel +// set this so previews are rotated to match the boot-time appearance +#ifndef BOOTLOGO_PREVIEW_ROTATE_CW +#define BOOTLOGO_PREVIEW_ROTATE_CW 0 +#endif + static SDL_Surface *screen; SDL_Surface** images; char **image_paths; +static char basepath[MAX_PATH]; static int selected = 0; static int count = 0; +// returns a 90°-clockwise-rotated copy of the preset (or the original on +// failure) so the preview matches what the rotated panel shows at boot +static SDL_Surface* rotatePreviewCW(SDL_Surface* src) +{ + SDL_Surface* conv = SDL_ConvertSurfaceFormat(src, SDL_PIXELFORMAT_ARGB8888, 0); + if (!conv) + return src; + SDL_Surface* dst = SDL_CreateRGBSurfaceWithFormat(0, conv->h, conv->w, 32, SDL_PIXELFORMAT_ARGB8888); + if (!dst) { + SDL_FreeSurface(conv); + return src; + } + uint32_t* src_pixels = conv->pixels; + uint32_t* dst_pixels = dst->pixels; + int src_stride = conv->pitch / 4; + int dst_stride = dst->pitch / 4; + for (int y = 0; y < conv->h; y++) + for (int x = 0; x < conv->w; x++) + dst_pixels[x * dst_stride + (conv->h - 1 - y)] = src_pixels[y * src_stride + x]; + SDL_FreeSurface(conv); + SDL_FreeSurface(src); + return dst; +} + int loadImages() { char* device = getenv("DEVICE"); +#ifdef BOOTLOGO_RESOLUTION_DIRS + // presets are shared between devices with the same panel resolution + char* folder = "640x480"; + if (exactMatch("rg28xx", device)) folder = "480x640"; + else if (exactMatch("rg34xx", device) || exactMatch("rg34xxsp", device) + || exactMatch("rgsp", device)) folder = "720x480"; + else if (exactMatch("rgcubexx", device)) folder = "720x720"; + snprintf(basepath, sizeof(basepath), "%s/Bootlogo.pak/%s/", TOOLS_PATH, folder); +#else // This needs to get a bit more flexible down the line, but for now we either expect the files // in the pak root directory or in the "brick" subfolder. - char basepath[MAX_PATH]; if(exactMatch("brick", device) || exactMatch("brickpro", device)) { snprintf(basepath, sizeof(basepath), "%s/Bootlogo.pak/brick/", TOOLS_PATH); } else { snprintf(basepath, sizeof(basepath), "%s/Bootlogo.pak/smartpro/", TOOLS_PATH); } +#endif - // grab all bmp files in the directory and load them with IMG_Load, + // grab all bmp files in the directory and load them with IMG_Load, // keep them in an array of SDL_Surface pointers + LOG_info("loading presets from %s (DEVICE=%s)\n", basepath, device ? device : "(unset)"); DIR *dir; struct dirent *ent; if ((dir = opendir(basepath)) != NULL) { @@ -55,24 +104,28 @@ int loadImages() char path[MAX_PATH]; snprintf(path, sizeof(path), "%s%s", basepath, ent->d_name); SDL_Surface *bmp = IMG_Load(path); - if (bmp) { - count++; - images = realloc(images, sizeof(SDL_Surface*) * count); - images[count-1] = bmp; - image_paths = realloc(image_paths, sizeof(char*) * count); - image_paths[count-1] = strdup(path); + if (!bmp) { + LOG_error("failed to load %s: %s\n", path, IMG_GetError()); + continue; } + if (BOOTLOGO_PREVIEW_ROTATE_CW) + bmp = rotatePreviewCW(bmp); + count++; + images = realloc(images, sizeof(SDL_Surface*) * count); + images[count-1] = bmp; + image_paths = realloc(image_paths, sizeof(char*) * count); + image_paths[count-1] = strdup(path); } } closedir(dir); } else { - // could not open directory - LOG_error("could not open directory"); + LOG_error("could not open %s: %s\n", basepath, strerror(errno)); if (CFG_getHaptics()) { VIB_triplePulse(5, 150, 200); } return 0; } + LOG_info("loaded %i presets\n", count); return count; } @@ -116,21 +169,21 @@ int main(int argc, char *argv[]) } else { - if (PAD_justRepeated(BTN_LEFT)) + if (PAD_justRepeated(BTN_LEFT) && count > 0) { selected -= 1; if (selected<0) selected = count - 1; dirty = 1; } - else if (PAD_justRepeated(BTN_RIGHT)) + else if (PAD_justRepeated(BTN_RIGHT) && count > 0) { selected += 1; if (selected>=count) selected = 0; dirty = 1; } - else if (PAD_justPressed(BTN_A)) + else if (PAD_justPressed(BTN_A) && count > 0) { // apply with system calls // BOOT_PATH=/mnt/boot/ @@ -142,8 +195,13 @@ int main(int argc, char *argv[]) // reboot char* boot_path = "/mnt/boot/"; char* logo_path = image_paths[selected]; - char cmd[256]; - snprintf(cmd, sizeof(cmd), "mkdir -p %s && mount -t vfat /dev/mmcblk0p1 %s && cp \"%s\" %s/bootlogo.bmp && sync && umount %s && reboot", boot_path, boot_path, logo_path, boot_path, boot_path); + char cmd[1024]; +#ifdef BOOTLOGO_RESOLUTION_DIRS + // back up the stock logo as a restorable preset before the first overwrite + snprintf(cmd, sizeof(cmd), "mkdir -p %s && mount -t vfat " BOOTLOGO_PARTITION " %s && ([ -f \"%soriginal.bmp\" ] || cp %sbootlogo.bmp \"%soriginal.bmp\"; cp \"%s\" %sbootlogo.bmp && sync && umount %s && reboot)", boot_path, boot_path, basepath, boot_path, basepath, logo_path, boot_path, boot_path); +#else + snprintf(cmd, sizeof(cmd), "mkdir -p %s && mount -t vfat " BOOTLOGO_PARTITION " %s && cp \"%s\" %s/bootlogo.bmp && sync && umount %s && reboot", boot_path, boot_path, logo_path, boot_path, boot_path); +#endif system(cmd); } else if (PAD_justPressed(BTN_B)) @@ -171,12 +229,35 @@ int main(int argc, char *argv[]) if(count > 0) { // render the selected image, centered on screen SDL_Surface *image = images[selected]; - SDL_Rect image_rect = { - screen->w /2 - image->w /2, - screen->h /2 - image->h / 2, - image->w, - image->h}; - SDL_BlitSurface(image, NULL, screen, &image_rect); + if (image->w > screen->w || image->h > screen->h) { + // aspect-fit oversized presets (e.g. custom logos larger than the UI) + int fit_w = screen->w; + int fit_h = image->h * screen->w / image->w; + if (fit_h > screen->h) { + fit_h = screen->h; + fit_w = image->w * screen->h / image->h; + } + SDL_Rect image_rect = { + screen->w / 2 - fit_w / 2, + screen->h / 2 - fit_h / 2, + fit_w, + fit_h}; + SDL_BlitScaled(image, NULL, screen, &image_rect); + } + else { + SDL_Rect image_rect = { + screen->w /2 - image->w /2, + screen->h /2 - image->h / 2, + image->w, + image->h}; + SDL_BlitSurface(image, NULL, screen, &image_rect); + } + } + else { + // surface the reason on-screen so it can be diagnosed without pulling logs + char msg[MAX_PATH + 32]; + snprintf(msg, sizeof(msg), "No presets found in\n%s", basepath); + GFX_blitMessage(font.small, msg, screen, NULL); } GFX_blitButtonGroup((char *[]){"L/R", "SCROLL", NULL}, 0, screen, 0); @@ -197,4 +278,4 @@ int main(int argc, char *argv[]) GFX_quit(); return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/workspace/all/common/api.c b/workspace/all/common/api.c index 19f3f5439..ef44c3df7 100644 --- a/workspace/all/common/api.c +++ b/workspace/all/common/api.c @@ -658,19 +658,29 @@ void GFX_setAmbientColor(const void *data, unsigned width, unsigned height, size uint32_t dominant_color = GFX_extract_average_color(data, width, height, pitch); - if (mode == 1 || mode == 2 || mode == 5) + // the zone indices below are the Brick layout (0/1 = FN keys or sticks, + // 2 = top bar, 3 = L/R). Devices with fewer lights simply don't have the + // higher ones, so every index has to be checked -- these are writes into + // a MAX_LIGHTS array and slot 3 is out of bounds on a 2-light device. + int count = LEDS_getCount(); + + if ((mode == 1 || mode == 2 || mode == 5) && count > 2) { (lightsAmbient)[2].color1 = dominant_color; (lightsAmbient)[2].effect = 4; } if (mode == 1 || mode == 3) { - (lightsAmbient)[0].color1 = dominant_color; - (lightsAmbient)[0].effect = 4; - (lightsAmbient)[1].color1 = dominant_color; - (lightsAmbient)[1].effect = 4; + if (count > 0) { + (lightsAmbient)[0].color1 = dominant_color; + (lightsAmbient)[0].effect = 4; + } + if (count > 1) { + (lightsAmbient)[1].color1 = dominant_color; + (lightsAmbient)[1].effect = 4; + } } - if (mode == 1 || mode == 4 || mode == 5) + if ((mode == 1 || mode == 4 || mode == 5) && count > 3) { (lightsAmbient)[3].color1 = dominant_color; (lightsAmbient)[3].effect = 4; @@ -4179,6 +4189,11 @@ void PWR_update(int *_dirty, int *_show_setting, PWR_callback_t before_sleep, PW *_show_setting = show_setting; } +void PWR_requestSleep(void) +{ + pwr.requested_sleep = 1; +} + // TODO: this isn't whether it can sleep but more if it should sleep in response to the sleep button void PWR_disableSleep(void) { @@ -4245,7 +4260,10 @@ void PWR_powerOff(int reboot) static void PWR_enterSleep(void) { - SND_pauseAudio(true); + // Fully close the audio device before sleeping: a PCM that stays open + // across suspend-to-RAM ends up in a state SDL takes ~10s to close on + // wake, freezing the UI. PWR_exitSleep reopens it via SND_resetAudio. + SND_quit(); LEDS_pushProfileOverride(LIGHT_PROFILE_SLEEP); if (GetHDMI()) { @@ -4444,6 +4462,26 @@ FALLBACK_IMPLEMENTATION void PLAT_setLedInbrightness(LightSettings *led) {} FALLBACK_IMPLEMENTATION void PLAT_setLedEffectCycles(LightSettings *led) {} FALLBACK_IMPLEMENTATION void PLAT_setLedEffectSpeed(LightSettings *led) {} +FALLBACK_IMPLEMENTATION int PLAT_getNumLeds(void) { return MAX_LIGHTS; } +FALLBACK_IMPLEMENTATION const char *PLAT_getLedSettingsFile(void) { return "ledsettings.txt"; } +FALLBACK_IMPLEMENTATION const char *PLAT_getLedLabel(int index) { return NULL; } +FALLBACK_IMPLEMENTATION int PLAT_getLedEffectCount(void) { return 6; } // LedControl's historical range +FALLBACK_IMPLEMENTATION int PLAT_getLedEffectId(int index) { return index + 1; } +FALLBACK_IMPLEMENTATION const char *PLAT_getLedEffectName(int effect_id) { return NULL; } + +int LEDS_getCount(void) +{ + static int count = -1; + if (count < 0) { + count = PLAT_getNumLeds(); + // the arrays are MAX_LIGHTS long, so this is the hard backstop + // against a platform over-reporting and walking off the end + if (count < 0) count = 0; + if (count > MAX_LIGHTS) count = MAX_LIGHTS; + } + return count; +} + void LEDS_setProfile(int profile) { if(lights_initialized == 0) @@ -4540,10 +4578,7 @@ void LEDS_updateLeds(bool indicator_only) return; } - char *device = getenv("DEVICE"); - int lightsize = exactMatch("brick", device) ? 4 - : exactMatch("brickpro", device) ? 5 - : 3; // smartpro, smartpro s + int lightsize = LEDS_getCount(); if(!lights) { diff --git a/workspace/all/common/api.h b/workspace/all/common/api.h index 828af8271..61b15cfc8 100644 --- a/workspace/all/common/api.h +++ b/workspace/all/common/api.h @@ -573,6 +573,7 @@ int PWR_isPoweringOff(void); void PWR_sleep(void); int PWR_deepSleep(void); +void PWR_requestSleep(void); void PWR_disableSleep(void); void PWR_enableSleep(void); @@ -623,6 +624,9 @@ bool LEDS_popProfileOverride(int profile); // returns top of stack, or default if stack is empty int LEDS_getProfileOverride(); +// number of lights on this device, cached and clamped to [0, MAX_LIGHTS] +int LEDS_getCount(void); + // changes the active led profile, calls LEDS_updateLeds() implicitly if needed void LEDS_setProfile(int profile); // enum LightProfile // reapplies the current led config. This should only be necessary @@ -773,6 +777,27 @@ void PLAT_setLedInbrightness(LightSettings *led); void PLAT_setLedEffectSpeed(LightSettings *led); void PLAT_setLedEffectCycles(LightSettings *led); +// How many lights this device actually has. MAX_LIGHTS is only a compile-time +// ceiling: platforms that serve several models (tg5040, h700) populate fewer +// slots than that, and the unpopulated ones are zeroed globals. Walking them +// is not harmless -- on the trimui platforms a zeroed slot writes brightness 0 +// to the *global* led_anim/max_scale and extinguishes every LED -- so every +// platform whose model count differs from MAX_LIGHTS must implement this. +int PLAT_getNumLeds(void); +// basename of the LedControl ini inside SHARED_USERDATA_PATH +const char *PLAT_getLedSettingsFile(void); +// user-visible name for a light, or NULL to let LedControl use its own table +const char *PLAT_getLedLabel(int index); + +// The effect ids in LightSettings.effect are a shared (trimui-derived) space: +// LEDS_initLeds() hardcodes 2 (breathe) and 3 (blink) for the battery/charging +// profiles and GFX_setAmbientColor() hardcodes 4 (static). Platforms expose the +// subset they can actually render via these hooks and translate internally -- +// they never renumber. +int PLAT_getLedEffectCount(void); +int PLAT_getLedEffectId(int index); +const char *PLAT_getLedEffectName(int effect_id); + bool PLAT_canTurbo(void); int PLAT_toggleTurbo(int btn_id); void PLAT_clearTurbo(); diff --git a/workspace/all/common/displaycal.h b/workspace/all/common/displaycal.h index ec0c44ae0..e32071b04 100644 --- a/workspace/all/common/displaycal.h +++ b/workspace/all/common/displaycal.h @@ -59,19 +59,54 @@ static const struct DisplayCalDefaults DisplayCalDefaults_BrickPro = { DISPLAYCAL_BRICKPRO_DEFAULT_BLUE_GAIN }; +// Anbernic H700 family. Uncalibrated models remain disabled with neutral gains. +#define DISPLAYCAL_H700_UNCALIBRATED { 0, 100, 100, 100 } +static const struct DisplayCalDefaults DisplayCalDefaults_RG28XX = { 1, 100, 92, 65 }; +static const struct DisplayCalDefaults DisplayCalDefaults_RG34XX = DISPLAYCAL_H700_UNCALIBRATED; +static const struct DisplayCalDefaults DisplayCalDefaults_RG34XXSP = { 1, 100, 83, 86 }; +static const struct DisplayCalDefaults DisplayCalDefaults_RGSP = { 1, 100, 68, 61 }; +static const struct DisplayCalDefaults DisplayCalDefaults_RG35XXPlus = DISPLAYCAL_H700_UNCALIBRATED; +static const struct DisplayCalDefaults DisplayCalDefaults_RG35XXH = DISPLAYCAL_H700_UNCALIBRATED; +static const struct DisplayCalDefaults DisplayCalDefaults_RG35XXSP = DISPLAYCAL_H700_UNCALIBRATED; +static const struct DisplayCalDefaults DisplayCalDefaults_RG35XXPRO = DISPLAYCAL_H700_UNCALIBRATED; +static const struct DisplayCalDefaults DisplayCalDefaults_RG40XXH = DISPLAYCAL_H700_UNCALIBRATED; +static const struct DisplayCalDefaults DisplayCalDefaults_RG40XXV = { 1, 91, 100, 63 }; +static const struct DisplayCalDefaults DisplayCalDefaults_RGCubeXX = DISPLAYCAL_H700_UNCALIBRATED; + enum DisplayCalPreset { DISPLAYCAL_PRESET_DEFAULT = 0, DISPLAYCAL_PRESET_BRICK, DISPLAYCAL_PRESET_SMARTPRO, DISPLAYCAL_PRESET_BRICKPRO, + DISPLAYCAL_PRESET_RG28XX, + DISPLAYCAL_PRESET_RG34XX, + DISPLAYCAL_PRESET_RG34XXSP, + DISPLAYCAL_PRESET_RGSP, + DISPLAYCAL_PRESET_RG35XXPLUS, + DISPLAYCAL_PRESET_RG35XXH, + DISPLAYCAL_PRESET_RG35XXSP, + DISPLAYCAL_PRESET_RG35XXPRO, + DISPLAYCAL_PRESET_RG40XXH, + DISPLAYCAL_PRESET_RG40XXV, + DISPLAYCAL_PRESET_RGCUBEXX }; static inline DisplayCalDefaults DisplayCal_getDefaultSettings(enum DisplayCalPreset preset) { - if(preset == DISPLAYCAL_PRESET_SMARTPRO) { - return DisplayCalDefaults_SmartPro; - } - if(preset == DISPLAYCAL_PRESET_BRICK) { - return DisplayCalDefaults_Brick; + switch(preset) { + case DISPLAYCAL_PRESET_SMARTPRO: return DisplayCalDefaults_SmartPro; + case DISPLAYCAL_PRESET_BRICK: return DisplayCalDefaults_Brick; + case DISPLAYCAL_PRESET_RG28XX: return DisplayCalDefaults_RG28XX; + case DISPLAYCAL_PRESET_RG34XX: return DisplayCalDefaults_RG34XX; + case DISPLAYCAL_PRESET_RG34XXSP: return DisplayCalDefaults_RG34XXSP; + case DISPLAYCAL_PRESET_RGSP: return DisplayCalDefaults_RGSP; + case DISPLAYCAL_PRESET_RG35XXPLUS: return DisplayCalDefaults_RG35XXPlus; + case DISPLAYCAL_PRESET_RG35XXH: return DisplayCalDefaults_RG35XXH; + case DISPLAYCAL_PRESET_RG35XXSP: return DisplayCalDefaults_RG35XXSP; + case DISPLAYCAL_PRESET_RG35XXPRO: return DisplayCalDefaults_RG35XXPRO; + case DISPLAYCAL_PRESET_RG40XXH: return DisplayCalDefaults_RG40XXH; + case DISPLAYCAL_PRESET_RG40XXV: return DisplayCalDefaults_RG40XXV; + case DISPLAYCAL_PRESET_RGCUBEXX: return DisplayCalDefaults_RGCubeXX; + default: break; } if(preset == DISPLAYCAL_PRESET_BRICKPRO) { return DisplayCalDefaults_BrickPro; diff --git a/workspace/all/common/generic_video.c b/workspace/all/common/generic_video.c index 00cb0cbf8..56b4b5e24 100644 --- a/workspace/all/common/generic_video.c +++ b/workspace/all/common/generic_video.c @@ -615,7 +615,10 @@ SDL_Surface* PLAT_initVideo(void) { #endif SDL_LogSetOutputFunction(sdl_log_stdout, NULL); //SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE); - SDL_InitSubSystem(SDL_INIT_VIDEO); + if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { + LOG_error("SDL_InitSubSystem(SDL_INIT_VIDEO) failed: %s\n", SDL_GetError()); + exit(1); + } SDL_ShowCursor(0); // SDL_version compiled; @@ -654,7 +657,15 @@ SDL_Surface* PLAT_initVideo(void) { SDL_SetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION,"1"); vid.window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w,h, SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN); + if (!vid.window) { + LOG_error("SDL_CreateWindow failed: %s\n", SDL_GetError()); + exit(1); + } vid.renderer = SDL_CreateRenderer(vid.window,-1,SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC); + if (!vid.renderer) { + LOG_error("SDL_CreateRenderer failed: %s\n", SDL_GetError()); + exit(1); + } SDL_SetRenderDrawBlendMode(vid.renderer, SDL_BLENDMODE_BLEND); SDL_RendererInfo info; SDL_GetRendererInfo(vid.renderer, &info); @@ -677,6 +688,10 @@ SDL_Surface* PLAT_initVideo(void) { } vid.gl_context = SDL_GL_CreateContext(vid.window); + if (!vid.gl_context) { + LOG_error("SDL_GL_CreateContext failed: %s\n", SDL_GetError()); + exit(1); + } SDL_GL_MakeCurrent(vid.window, vid.gl_context); glViewport(0, 0, w, h); diff --git a/workspace/all/ledcontrol/ledcontrol.c b/workspace/all/ledcontrol/ledcontrol.c index c38167a3c..8441d77fc 100644 --- a/workspace/all/ledcontrol/ledcontrol.c +++ b/workspace/all/ledcontrol/ledcontrol.c @@ -29,23 +29,44 @@ const char *lr_effect_names[] = { "Blink 1", "Blink 2", "Blink 3", "Rainbow", "Twinkle", "Fire", "Glitter", "NeonGlow", "Firefly", "Aurora", "Reactive", "LR Rainbow", "LR Reactive"}; +// Resolves an effect id to the index the platform's effect list holds it at, +// so left/right walk the list the hardware actually supports. Falls back to the +// first entry for ids that aren't offered here (a settings file carried over +// from another device, or one of the profile-only ids). +static int effect_index_of(int effect_id) { + int count = PLAT_getLedEffectCount(); + for (int i = 0; i < count; ++i) { + if (PLAT_getLedEffectId(i) == effect_id) return i; + } + return 0; +} + +// Platforms that don't name their own effects keep the historical tables below. +static const char *effect_name_for(int light_index, int effect_id) { + const char *name = PLAT_getLedEffectName(effect_id); + if (name) return name; + + const char **table = effect_names; + int count = sizeof(effect_names) / sizeof(effect_names[0]); + if (light_index == 3) { + table = lr_effect_names; + count = sizeof(lr_effect_names) / sizeof(lr_effect_names[0]); + } + else if (light_index == 2) { + table = topbar_effect_names; + count = sizeof(topbar_effect_names) / sizeof(topbar_effect_names[0]); + } + // effect comes from a user-editable ini, so it can be anything + if (effect_id < 1 || effect_id > count) return "Unknown"; + return table[effect_id - 1]; +} + void save_settings() { LOG_debug("saving settings plat\n"); char diskfilename[256]; - char* device = getenv("DEVICE"); - int maxlights = 3; + int maxlights = LEDS_getCount(); // TODO: this shouldnt be in shared userdata - if(exactMatch("brick", device)) { - maxlights = 4; - snprintf(diskfilename, sizeof(diskfilename), SHARED_USERDATA_PATH "/ledsettings_brick.txt"); - } - else if (exactMatch("brickpro", device)) { - maxlights = 5; - snprintf(diskfilename, sizeof(diskfilename), SHARED_USERDATA_PATH "/ledsettings_brickpro.txt"); - } - else { - snprintf(diskfilename, sizeof(diskfilename), SHARED_USERDATA_PATH "/ledsettings.txt"); - } + snprintf(diskfilename, sizeof(diskfilename), SHARED_USERDATA_PATH "/%s", PLAT_getLedSettingsFile()); FILE *file = fopen(diskfilename, "w"); @@ -100,15 +121,20 @@ void handle_light_input(LightSettings *light, SDL_Event *event, int selected_set switch (selected_setting) { case 0: // Effect - if (PAD_justPressed(BTN_RIGHT)) + { + int effect_count = PLAT_getLedEffectCount(); + if (effect_count > 0 && PAD_justPressed(BTN_RIGHT)) { - light->effect = (light->effect % 6) + 1; // Increase effect (1 to 8) + int index = (effect_index_of(light->effect) + 1) % effect_count; + light->effect = PLAT_getLedEffectId(index); } - else if (PAD_justPressed(BTN_LEFT)) + else if (effect_count > 0 && PAD_justPressed(BTN_LEFT)) { - light->effect = (light->effect - 2 + 6) % 6 + 1; // Decrease effect (1 to 8) + int index = (effect_index_of(light->effect) - 1 + effect_count) % effect_count; + light->effect = PLAT_getLedEffectId(index); } break; + } case 1: // Color if (PAD_justPressed(BTN_RIGHT)) { @@ -217,35 +243,69 @@ void handle_light_input(LightSettings *light, SDL_Event *event, int selected_set int main(int argc, char *argv[]) { char* device = getenv("DEVICE"); - + InitSettings(); PWR_setCPUSpeed(CPU_SPEED_AUTO); - int numOfLights = 3; + SDL_Surface* screen = GFX_init(MODE_MAIN); + PAD_init(); + PWR_init(); + + GFX_clearAll(); + GFX_clearLayers(0); + GFX_flip(screen); + + // GFX_init() is what gets the platform far enough along to answer this + // (the trimui platforms only learn their model in PLAT_initPlatform) + int numOfLights = LEDS_getCount(); + + if (numOfLights == 0) { + // devices in this platform's family that simply have no RGB lights + int quit_msg = 0; + int msg_dirty = 1; + while (!quit_msg) { + GFX_startFrame(); + PAD_poll(); + if (PAD_justPressed(BTN_B)) quit_msg = 1; + + if (msg_dirty) { + GFX_clear(screen); + GFX_blitMessage(font.large, "This device has no RGB lights.", screen, + &(SDL_Rect){0, 0, screen->w, screen->h}); + GFX_blitButtonGroup((char*[]){ "B","BACK", NULL }, 1, screen, 1); + GFX_flip(screen); + msg_dirty = 0; + } + else GFX_sync(); + } + PWR_quit(); + PAD_quit(); + GFX_quit(); + QuitSettings(); + return 0; + } + + // brightness is a single global control unless the hardware exposes one + // per light (the Brick family does, via its per-zone max_scale nodes) int combinedBrightness = 1; if (exactMatch("brick", device)) { const char *brick_names[] = {"F1 key", "F2 key", "Top bar", "L&R triggers"}; memcpy(lightnames, brick_names, sizeof(brick_names)); // Copy values - numOfLights = 4; combinedBrightness = 0; } else if (exactMatch("brickpro", device)) { const char *brickpro_names[] = {"F1 key", "F2 key", "Top bar", "Joysticks", "Triggers"}; memcpy(lightnames, brickpro_names, sizeof(brickpro_names)); // Copy values - numOfLights = 5; combinedBrightness = 0; } else { const char *default_names[] = {"Joystick L","Joystick R", "Logo"}; memcpy(lightnames, default_names, sizeof(default_names)); // Copy values } - - SDL_Surface* screen = GFX_init(MODE_MAIN); - PAD_init(); - PWR_init(); - - GFX_clearAll(); - GFX_clearLayers(0); - GFX_flip(screen); + // platforms that name their own lights win over the tables above + for (int i = 0; i < numOfLights && i < 5; ++i) { + const char *name = PLAT_getLedLabel(i); + if (name) lightnames[i] = name; + } bool running = true; int selected_light = 0; @@ -354,7 +414,7 @@ int main(int argc, char *argv[]) int y = SCALE1(PADDING + PILL_SIZE * (j + 1)); if (j == 0) { // Display effect name instead of number - snprintf(setting_text, sizeof(setting_text), "%s: %s", settings_labels[j], selected_light == 3 ? lr_effect_names[settings_values[j] - 1] : selected_light == 2 ? topbar_effect_names[settings_values[j] - 1] : effect_names[settings_values[j] - 1]); + snprintf(setting_text, sizeof(setting_text), "%s: %s", settings_labels[j], effect_name_for(selected_light, settings_values[j])); SDL_Surface *text = TTF_RenderUTF8_Blended(font.medium, setting_text, current_color); int text_width = text->w + SCALE1(BUTTON_PADDING * 2); GFX_blitPill(selected ? ASSET_WHITE_PILL : ASSET_BLACK_PILL, screen, diff --git a/workspace/all/minarch/ma_config.c b/workspace/all/minarch/ma_config.c index 438a0a65b..ab89fa02c 100644 --- a/workspace/all/minarch/ma_config.c +++ b/workspace/all/minarch/ma_config.c @@ -509,6 +509,8 @@ static void Config_readControlsString(char* cfg) { mapping->mod = mod; } } +static void configureAmbientOption(void); // defined next to ambient_labels below + void Config_load(void) { LOG_info("Config_load\n"); @@ -522,7 +524,9 @@ void Config_load(void) { if (!GFX_supportsOverscan()) { scaling_labels[4] = NULL; } - + + configureAmbientOption(); + char* system_path = SYSTEM_PATH "/system.cfg"; char device_system_path[MAX_PATH] = {0}; @@ -1304,6 +1308,24 @@ char* getScreenScalingDesc(void) { int getScreenScalingCount(void) { return GFX_supportsOverscan() ? 5 : 4; } + +// The ambient zone list is the Brick layout: All, Top bar, FN keys, L/R. +// Devices with two lights only have the pair GFX_setAmbientColor() writes for +// mode 1, so offer that as a plain on/off rather than four options that mostly +// do nothing. No value remapping needed: index 1 is already mode 1. The menu +// walks labels until NULL, so truncating that is what limits the choices. +static void configureAmbientOption(void) { + Option* ambient_option = &config.frontend.options[FE_OPT_AMBIENT]; + int lights = LEDS_getCount(); + if (lights == 0) { + ambient_option->lock = 1; // nothing to light up, keep it out of the menu + } + else if (lights <= 2) { + ambient_labels[1] = "On"; + ambient_labels[2] = NULL; + ambient_option->count = 2; + } +} struct Config config = { diff --git a/workspace/all/minarch/ma_internal.h b/workspace/all/minarch/ma_internal.h index 49d4a8935..b2967769d 100644 --- a/workspace/all/minarch/ma_internal.h +++ b/workspace/all/minarch/ma_internal.h @@ -22,7 +22,7 @@ struct Core { const char version[128]; // eg. Gambatte (v0.5.0-netlink 7e02df6) const char extensions[128]; // eg. gb|gbc|dmg - const char config_dir[MAX_PATH]; // eg. /mnt/sdcard/.userdata/rg35xx/GB-gambatte + const char config_dir[MAX_PATH]; // eg. /mnt/sdcard/.userdata/h700/GB-gambatte const char states_dir[MAX_PATH]; // eg. /mnt/sdcard/.userdata/arm-480/GB-gambatte const char saves_dir[MAX_PATH]; // eg. /mnt/sdcard/Saves/GB const char bios_dir[MAX_PATH]; // eg. /mnt/sdcard/Bios/GB diff --git a/workspace/all/minarch/makefile b/workspace/all/minarch/makefile index ae10f2529..ea0abdd15 100644 --- a/workspace/all/minarch/makefile +++ b/workspace/all/minarch/makefile @@ -28,7 +28,7 @@ SOURCE = $(TARGET).c ma_cheats.c ma_rewind.c ma_audio.c ma_input.c \ ../common/notification.c ../../$(PLATFORM)/platform/platform.c # RA support -ifneq (,$(filter $(PLATFORM),tg5040 tg5050 my355 desktop)) +ifneq (,$(filter $(PLATFORM),tg5040 tg5050 h700 my355 desktop)) # RA source files SOURCE += ../common/http.c ../common/ra_badges.c ../common/ra_offline.c ../common/ra_sync.c ../common/ra_event_queue.c ra_integration.c chd_reader.c endif @@ -66,7 +66,7 @@ LDFLAGS += -lasound endif # RA support: rcheevos and libchdr linking -ifneq (,$(filter $(PLATFORM),tg5040 tg5050 my355 desktop)) +ifneq (,$(filter $(PLATFORM),tg5040 tg5050 h700 my355 desktop)) LDFLAGS += -lrcheevos -lchdr -lcrypto CFLAGS += -DRC_CLIENT_SUPPORTS_HASH -DHAS_CHEEVOS -DHAS_CHDR ifeq ($(PLATFORM), desktop) @@ -98,7 +98,7 @@ ifeq ($(PLATFORM), desktop) all: clean libretro-common rcheevos libchdr $(PREFIX_LOCAL)/include/msettings.h mkdir -p build/$(PLATFORM) $(CC) $(SOURCE) -o $(PRODUCT) $(CFLAGS) $(LDFLAGS) -else ifneq (,$(filter $(PLATFORM),tg5040 tg5050 my355)) +else ifneq (,$(filter $(PLATFORM),tg5040 tg5050 h700 my355)) # Platforms with RA support all: clean libretro-common libsrm.a rcheevos libchdr $(PREFIX_LOCAL)/include/msettings.h mkdir -p build/$(PLATFORM) @@ -157,4 +157,4 @@ libsrm.a: $(OBJECTS) clean: rm -f $(PRODUCT) - rm -f $(OBJECTS) $(LIBRARY) \ No newline at end of file + rm -f $(OBJECTS) $(LIBRARY) diff --git a/workspace/all/minarch/minarch.c b/workspace/all/minarch/minarch.c index b3e156eda..2870169ca 100644 --- a/workspace/all/minarch/minarch.c +++ b/workspace/all/minarch/minarch.c @@ -118,7 +118,7 @@ void hdmimon(void) { LOG_info("restarting after HDMI change...\n"); Menu_beforeSleep(); - sleep(4); + sleep(1); // cable-seating debounce; the output switch itself happens at next app start show_menu = 0; quit = 1; } diff --git a/workspace/all/nextui/nextui.c b/workspace/all/nextui/nextui.c index 5ed6d612e..af4101283 100644 --- a/workspace/all/nextui/nextui.c +++ b/workspace/all/nextui/nextui.c @@ -2255,11 +2255,15 @@ int main (int argc, char *argv[]) { simple_mode = exists(SIMPLE_MODE_PATH); LOG_info("NextUI\n"); + LOG_info("InitSettings\n"); InitSettings(); + LOG_info("GFX_init\n"); screen = GFX_init(MODE_MAIN); + LOG_info("GFX_init done\n"); // LOG_info("- graphics init: %lu\n", SDL_GetTicks() - main_begin); + LOG_info("PAD_init\n"); PAD_init(); // LOG_info("- input init: %lu\n", SDL_GetTicks() - main_begin); VIB_init(); @@ -3412,7 +3416,7 @@ int main (int argc, char *argv[]) { Entry* entry = top->entries->items[top->selected]; LOG_info("restarting after HDMI change... (%s)\n", entry->path); saveLast(entry->path); // NOTE: doesn't work in Recents (by design) - sleep(4); + sleep(1); // cable-seating debounce; the output switch itself happens at next app start quit = 1; } } diff --git a/workspace/all/settings/btmenu.cpp b/workspace/all/settings/btmenu.cpp index 261971230..2bd616c54 100644 --- a/workspace/all/settings/btmenu.cpp +++ b/workspace/all/settings/btmenu.cpp @@ -26,13 +26,15 @@ Menu::Menu(const int &globalQuit, int &globalDirty) : MenuList(MenuItemType::Fix std::bind(&Menu::getBtDiagnosticsState, this), std::bind(&Menu::setBtDiagnosticsState, this, std::placeholders::_1), std::bind(&Menu::resetBtDiagnosticsState, this)); + items.push_back(toggleItem); + items.push_back(diagItem); +#ifndef NO_BT_AUDIO rateItem = new MenuItem(ListItemType::Generic, "Maximum sampling rate", "44100 Hz: better compatibility\n48000 Hz: better quality", {44100, 48000}, {"44100 Hz", "48000 Hz"}, std::bind(&Menu::getSamplerateMaximum, this), std::bind(&Menu::setSamplerateMaximum, this, std::placeholders::_1), std::bind(&Menu::resetSamplerateMaximum, this)); - items.push_back(toggleItem); - items.push_back(diagItem); items.push_back(rateItem); +#endif // best effort layout based on the platform defines, user should really call performLayout manually MenuList::performLayout((SDL_Rect){0, 0, FIXED_WIDTH, FIXED_HEIGHT}); @@ -179,7 +181,7 @@ void Menu::updater() items.clear(); items.push_back(toggleItem); items.push_back(diagItem); - items.push_back(rateItem); + if (rateItem) items.push_back(rateItem); layout_called = false; for (auto &[s, r] : scanMap) @@ -228,7 +230,7 @@ void Menu::updater() items.clear(); items.push_back(toggleItem); items.push_back(diagItem); - items.push_back(rateItem); + if (rateItem) items.push_back(rateItem); layout_called = false; selectionDirty = true; pollSecs = 15; diff --git a/workspace/all/settings/btmenu.hpp b/workspace/all/settings/btmenu.hpp index f9374e643..d6f86eacd 100644 --- a/workspace/all/settings/btmenu.hpp +++ b/workspace/all/settings/btmenu.hpp @@ -16,7 +16,7 @@ namespace Bluetooth // diagnostics on/off MenuItem *diagItem; // max sample rate - MenuItem *rateItem; + MenuItem *rateItem = nullptr; std::thread worker; bool quit = false; @@ -94,4 +94,4 @@ namespace Bluetooth public: UnpairItem(BT_devicePaired n, bool& dirty); }; -} \ No newline at end of file +} diff --git a/workspace/all/settings/makefile b/workspace/all/settings/makefile index ea854f1c8..4924f7576 100644 --- a/workspace/all/settings/makefile +++ b/workspace/all/settings/makefile @@ -44,6 +44,12 @@ CXXFLAGS += -DHAS_BTAGENT CXXSOURCE += btagent.cpp CXXFLAGS += $$(pkg-config --cflags --libs gio-2.0 glib-2.0) endif +ifeq ($(PLATFORM), h700) +# drop as soon as we use btagent on all platforms +CXXFLAGS += -DHAS_BTAGENT +CXXSOURCE += btagent.cpp +CXXFLAGS += $$(pkg-config --cflags --libs gio-2.0 glib-2.0) +endif PRODUCT= build/$(PLATFORM)/$(TARGET).elf diff --git a/workspace/all/settings/settings.cpp b/workspace/all/settings/settings.cpp index 7a3eeda49..5a8dbc039 100644 --- a/workspace/all/settings/settings.cpp +++ b/workspace/all/settings/settings.cpp @@ -241,7 +241,8 @@ namespace { enum Vendor { Unknown, Trimui, - Miyoo + Miyoo, + Anbernic }; enum Model { @@ -250,14 +251,26 @@ namespace { BrickPro, SmartPro, SmartProS, - Flip + Flip, + RG40XXV, + RG40XXH, + RG34XX, + RG34XXSP, + RGSP, // RG34XXSP panel, no sticks + RG35XXPlus, // Plus and 2024 both report RG35xx + RG35XXH, + RG35XXSP, + RG35XXPRO, + RG28XX, + RGCubeXX }; enum Platform { UnknownPlatform, tg5040, tg5050, - my355 + my355, + h700 }; DeviceInfo() { @@ -283,6 +296,50 @@ namespace { m_vendor = Trimui; m_model = Flip; m_platform = my355; + } else if(exactMatch("rg40xxv", device)) { + m_vendor = Anbernic; + m_model = RG40XXV; + m_platform = h700; + } else if(exactMatch("rg40xxh", device)) { + m_vendor = Anbernic; + m_model = RG40XXH; + m_platform = h700; + } else if(exactMatch("rg35xxplus", device)) { + m_vendor = Anbernic; + m_model = RG35XXPlus; + m_platform = h700; + } else if(exactMatch("rg35xxh", device)) { + m_vendor = Anbernic; + m_model = RG35XXH; + m_platform = h700; + } else if(exactMatch("rg35xxsp", device)) { + m_vendor = Anbernic; + m_model = RG35XXSP; + m_platform = h700; + } else if(exactMatch("rg35xxpro", device)) { + m_vendor = Anbernic; + m_model = RG35XXPRO; + m_platform = h700; + } else if(exactMatch("rg34xx", device)) { + m_vendor = Anbernic; + m_model = RG34XX; + m_platform = h700; + } else if(exactMatch("rg34xxsp", device)) { + m_vendor = Anbernic; + m_model = RG34XXSP; + m_platform = h700; + } else if(exactMatch("rgsp", device)) { + m_vendor = Anbernic; + m_model = RGSP; + m_platform = h700; + } else if(exactMatch("rg28xx", device)) { + m_vendor = Anbernic; + m_model = RG28XX; + m_platform = h700; + } else if(exactMatch("rgcubexx", device)) { + m_vendor = Anbernic; + m_model = RGCubeXX; + m_platform = h700; } } } @@ -292,9 +349,11 @@ namespace { Platform getPlatform() const { return m_platform; } bool hasColorTemperature() const { - return m_platform == tg5040; + return m_platform == tg5040 || m_platform == h700; } + // the H700 disp driver doesn't support the enhance_* sysfs nodes, + // so contrast/saturation/exposure are hidden there bool hasContrastSaturation() const { return m_platform == my355 || m_platform == tg5040; } @@ -304,7 +363,7 @@ namespace { } bool hasDisplayCal() const { - return m_platform == tg5040; + return m_platform == tg5040 || m_platform == h700; } bool hasActiveCooling() const { @@ -316,15 +375,17 @@ namespace { } bool hasAnalogSticks() const { - return m_model == SmartPro || m_model == SmartProS || m_model == BrickPro; + return m_model == SmartPro || m_model == SmartProS || m_model == BrickPro + || m_model == RG40XXV || m_model == RG40XXH || m_model == RGCubeXX + || m_model == RG34XXSP || m_model == RG35XXH || m_model == RG35XXPRO; } bool hasWifi() const { - return m_platform == tg5050 || m_platform == tg5040 || m_platform == my355; + return m_platform == tg5050 || m_platform == tg5040 || m_platform == my355 || m_platform == h700; } bool hasBluetooth() const { - return m_platform == tg5050 || m_platform == tg5040 || m_platform == my355; + return m_platform == tg5050 || m_platform == tg5040 || m_platform == my355 || m_platform == h700; } private: @@ -536,9 +597,21 @@ int main(int argc, char *argv[]) if(deviceInfo.hasDisplayCal()) { const DisplayCalDefaults defaultDisplayCal = DisplayCal_getDefaultSettings( - deviceInfo.getModel() == DeviceInfo::Brick ? DISPLAYCAL_PRESET_BRICK : + deviceInfo.getModel() == DeviceInfo::Brick ? DISPLAYCAL_PRESET_BRICK : deviceInfo.getModel() == DeviceInfo::BrickPro ? DISPLAYCAL_PRESET_BRICKPRO : - deviceInfo.getModel() == DeviceInfo::SmartPro ? DISPLAYCAL_PRESET_SMARTPRO : DISPLAYCAL_PRESET_DEFAULT); + deviceInfo.getModel() == DeviceInfo::SmartPro ? DISPLAYCAL_PRESET_SMARTPRO : + deviceInfo.getModel() == DeviceInfo::RG28XX ? DISPLAYCAL_PRESET_RG28XX : + deviceInfo.getModel() == DeviceInfo::RG34XX ? DISPLAYCAL_PRESET_RG34XX : + deviceInfo.getModel() == DeviceInfo::RG34XXSP ? DISPLAYCAL_PRESET_RG34XXSP : + deviceInfo.getModel() == DeviceInfo::RGSP ? DISPLAYCAL_PRESET_RGSP : + deviceInfo.getModel() == DeviceInfo::RG35XXPlus ? DISPLAYCAL_PRESET_RG35XXPLUS : + deviceInfo.getModel() == DeviceInfo::RG35XXH ? DISPLAYCAL_PRESET_RG35XXH : + deviceInfo.getModel() == DeviceInfo::RG35XXSP ? DISPLAYCAL_PRESET_RG35XXSP : + deviceInfo.getModel() == DeviceInfo::RG35XXPRO ? DISPLAYCAL_PRESET_RG35XXPRO : + deviceInfo.getModel() == DeviceInfo::RG40XXH ? DISPLAYCAL_PRESET_RG40XXH : + deviceInfo.getModel() == DeviceInfo::RG40XXV ? DISPLAYCAL_PRESET_RG40XXV : + deviceInfo.getModel() == DeviceInfo::RGCubeXX ? DISPLAYCAL_PRESET_RGCUBEXX : + DISPLAYCAL_PRESET_DEFAULT); displayItems.push_back( new MenuItem{ListItemType::Generic, "White point correction", "Corrects the display white point to better match the \nsRGB standard, at the expense of some peak brightness.", {false, true}, on_off, []() -> std::any { return GetDisplayCalEnabled() != 0; }, [](const std::any &value) @@ -1180,11 +1253,14 @@ int main(int argc, char *argv[]) // present GFX_flip(ctx.screen); ctx.dirty = false; - - // hdmimon(); } else GFX_sync(); + + // exit so the relauncher can re-init video at the new output + // resolution (no-op on platforms whose GetHDMI() is stubbed) + if (GFX_hdmiChanged()) + appQuit = true; } delete ctx.menu; diff --git a/workspace/all/syncsettings/syncsettings.c b/workspace/all/syncsettings/syncsettings.c index 2bf4c5934..e0410705f 100644 --- a/workspace/all/syncsettings/syncsettings.c +++ b/workspace/all/syncsettings/syncsettings.c @@ -8,5 +8,14 @@ int main (int argc, char *argv[]) { sleep(1); SetVolume(GetVolume()); SetBrightness(GetBrightness()); + SetColortemp(GetColortemp()); + SetContrast(GetContrast()); + SetSaturation(GetSaturation()); + SetExposure(GetExposure()); + SetRawDisplayCal( + GetDisplayCalEnabled(), + GetDisplayCalRedGain(), + GetDisplayCalGreenGain(), + GetDisplayCalBlueGain()); return 0; } diff --git a/workspace/h700/boot/boot.sh b/workspace/h700/boot/boot.sh new file mode 100755 index 000000000..287d95728 --- /dev/null +++ b/workspace/h700/boot/boot.sh @@ -0,0 +1,143 @@ +#!/bin/sh + +TF1_PATH=/mnt/mmc +TF2_PATH=/mnt/sdcard +COMPAT_PATH=/mnt/SDCARD +PLATFORM=h700 +SYSTEM_PATH="$TF2_PATH/.system/$PLATFORM" +UPDATE_PATH="$TF2_PATH/MinUI.zip" +LOG_PATH=/tmp/nextui-h700.log + +trap '' USR1 + +if mountpoint -q "$TF1_PATH"; then + LOG_PATH="$TF1_PATH/nextui-h700.log" +fi +: > "$LOG_PATH" 2>/dev/null || true + +raw_log() { + echo "$@" >> "$LOG_PATH" 2>/dev/null || true +} + +has_pakz() { + for pakz in "$TF2_PATH"/*.pakz; do + [ -e "$pakz" ] && return 0 + done + return 1 +} + +extract_payload() { + if [ -x /tmp/nextui-h700-unzip ] && [ -x /tmp/nextui-h700-fbsplash ] && [ -f /tmp/nextui-h700/shim-common.sh ]; then + return 0 + fi + + LINE=$(($(grep -na '^BINARY' "$0" | cut -d ':' -f 1 | head -1) + 1)) + tail -n +"$LINE" "$0" > /tmp/nextui-h700-data.tar.gz + mkdir -p /tmp/nextui-h700 + if ! tar -xzf /tmp/nextui-h700-data.tar.gz -C /tmp/nextui-h700 >> "$LOG_PATH" 2>&1; then + raw_log "embedded payload extraction failed" + return 1 + fi + cp /tmp/nextui-h700/unzip /tmp/nextui-h700-unzip + chmod +x /tmp/nextui-h700-unzip + if [ -x /tmp/nextui-h700/fbsplash ]; then + cp /tmp/nextui-h700/fbsplash /tmp/nextui-h700-fbsplash + chmod +x /tmp/nextui-h700-fbsplash + fi +} + +load_common() { + extract_payload || return 1 + if [ ! -f /tmp/nextui-h700/shim-common.sh ]; then + raw_log "embedded common helper missing" + return 1 + fi + SHIM_LOG_PATH="$LOG_PATH" + SHIM_LOG_PREFIX="" + SHIM_LOG_DATES=0 + . /tmp/nextui-h700/shim-common.sh +} + +show_splash() { + extract_payload || return 0 + [ -x /tmp/nextui-h700-fbsplash ] || return 0 + /tmp/nextui-h700-fbsplash "$1" >/dev/null 2>&1 || true +} + +find_unzip() { + for unzip_path in /usr/bin/unzip /bin/unzip /mnt/vendor/bin/unzip /tmp/nextui-h700-unzip; do + if [ -x "$unzip_path" ]; then + echo "$unzip_path" + return 0 + fi + done + + if extract_payload; then + echo /tmp/nextui-h700-unzip + return 0 + fi + + return 1 +} + +fallback_stock() { + raw_log "falling back to stock frontend" + if [ -x /mnt/vendor/bin/dmenu.bin ]; then + exec /mnt/vendor/bin/dmenu.bin + fi + exit 1 +} + +if ! load_common; then + show_splash "NEXTUI INSTALL MISSING" + fallback_stock +fi + +if [ -f /mnt/vendor/muos1.ini ] || [ -f /mnt/vendor/muos2.ini ]; then + shim_log "stockmod muOS override is present; NextUI requires the stock boot target" + show_splash "STOCK TARGET REQUIRED" +fi + +if ! mount_tf2 "$TF2_PATH"; then + repair_tf2 +fi + +if ! mount_tf2 "$TF2_PATH"; then + shim_log "TF2 mount failed" + show_splash "INSERT NEXTUI TF2 CARD" + fallback_stock +fi + +ensure_compat_path "$TF2_PATH" "$COMPAT_PATH" + +if [ -f "$UPDATE_PATH" ]; then + shim_log "install/update zip detected" + show_splash "INSTALLING NEXTUI" + if [ ! -x "$TF2_PATH/.tmp_update/$PLATFORM.sh" ]; then + UNZIP_CMD=$(find_unzip) + if [ -z "$UNZIP_CMD" ]; then + shim_log "unzip helper unavailable" + fallback_stock + fi + if ! "$UNZIP_CMD" -o "$UPDATE_PATH" ".tmp_update/*" -d "$TF2_PATH" >> "$LOG_PATH" 2>&1; then + shim_log "updater bootstrap extraction failed" + fallback_stock + fi + fi +fi + +if [ -x "$TF2_PATH/.tmp_update/$PLATFORM.sh" ] && { [ -f "$UPDATE_PATH" ] || has_pakz; }; then + show_splash "INSTALLING NEXTUI" + "$TF2_PATH/.tmp_update/$PLATFORM.sh" >> "$LOG_PATH" 2>&1 +elif [ -x "$SYSTEM_PATH/bin/install.sh" ] && [ -f "$UPDATE_PATH" ]; then + show_splash "UPDATING NEXTUI" + "$SYSTEM_PATH/bin/install.sh" >> "$LOG_PATH" 2>&1 +fi + +if [ -x "$SYSTEM_PATH/paks/MinUI.pak/launch.sh" ]; then + exec "$SYSTEM_PATH/paks/MinUI.pak/launch.sh" +fi + +shim_log "NextUI launch script missing" +show_splash "NEXTUI INSTALL MISSING" +fallback_stock diff --git a/workspace/h700/boot/build.sh b/workspace/h700/boot/build.sh new file mode 100755 index 000000000..5adbb1e84 --- /dev/null +++ b/workspace/h700/boot/build.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +SOURCE=boot.sh +TARGET=dmenu.bin + +mkdir -p output +${CROSS_COMPILE}gcc -Os -s fbsplash.c -o ./output/fbsplash +cp ../other/unzip60/unzip ./output/ +cp ../shim-common.sh ./output/ + +cd output || exit 1 +tar -czf data fbsplash unzip shim-common.sh +cat ../$SOURCE > $TARGET +echo BINARY >> $TARGET +cat data >> $TARGET +chmod +x $TARGET + +PAYLOAD_LINE=$(($(grep -na '^BINARY' "$TARGET" | cut -d: -f1 | head -1) + 1)) +tail -n +"$PAYLOAD_LINE" "$TARGET" | gzip -t diff --git a/workspace/h700/boot/fbsplash.c b/workspace/h700/boot/fbsplash.c new file mode 100644 index 000000000..d40618faa --- /dev/null +++ b/workspace/h700/boot/fbsplash.c @@ -0,0 +1,180 @@ +// Minimal framebuffer splash for the H700 boot shim. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + uint8_t rows[7]; +} Glyph; + +typedef struct { + char c; + Glyph g; +} GlyphMap; + +static const GlyphMap glyphs[] = { + {' ', {{0x00,0x00,0x00,0x00,0x00,0x00,0x00}}}, + {'!', {{0x04,0x04,0x04,0x04,0x04,0x00,0x04}}}, + {'-', {{0x00,0x00,0x00,0x1f,0x00,0x00,0x00}}}, + {'.', {{0x00,0x00,0x00,0x00,0x00,0x0c,0x0c}}}, + {'0', {{0x0e,0x11,0x13,0x15,0x19,0x11,0x0e}}}, + {'1', {{0x04,0x0c,0x04,0x04,0x04,0x04,0x0e}}}, + {'2', {{0x0e,0x11,0x01,0x02,0x04,0x08,0x1f}}}, + {'3', {{0x1e,0x01,0x01,0x0e,0x01,0x01,0x1e}}}, + {'4', {{0x02,0x06,0x0a,0x12,0x1f,0x02,0x02}}}, + {'5', {{0x1f,0x10,0x10,0x1e,0x01,0x01,0x1e}}}, + {'6', {{0x0e,0x10,0x10,0x1e,0x11,0x11,0x0e}}}, + {'7', {{0x1f,0x01,0x02,0x04,0x08,0x08,0x08}}}, + {'8', {{0x0e,0x11,0x11,0x0e,0x11,0x11,0x0e}}}, + {'9', {{0x0e,0x11,0x11,0x0f,0x01,0x01,0x0e}}}, + {'A', {{0x0e,0x11,0x11,0x1f,0x11,0x11,0x11}}}, + {'B', {{0x1e,0x11,0x11,0x1e,0x11,0x11,0x1e}}}, + {'C', {{0x0e,0x11,0x10,0x10,0x10,0x11,0x0e}}}, + {'D', {{0x1e,0x11,0x11,0x11,0x11,0x11,0x1e}}}, + {'E', {{0x1f,0x10,0x10,0x1e,0x10,0x10,0x1f}}}, + {'F', {{0x1f,0x10,0x10,0x1e,0x10,0x10,0x10}}}, + {'G', {{0x0e,0x11,0x10,0x17,0x11,0x11,0x0f}}}, + {'H', {{0x11,0x11,0x11,0x1f,0x11,0x11,0x11}}}, + {'I', {{0x0e,0x04,0x04,0x04,0x04,0x04,0x0e}}}, + {'J', {{0x07,0x02,0x02,0x02,0x12,0x12,0x0c}}}, + {'K', {{0x11,0x12,0x14,0x18,0x14,0x12,0x11}}}, + {'L', {{0x10,0x10,0x10,0x10,0x10,0x10,0x1f}}}, + {'M', {{0x11,0x1b,0x15,0x15,0x11,0x11,0x11}}}, + {'N', {{0x11,0x19,0x15,0x13,0x11,0x11,0x11}}}, + {'O', {{0x0e,0x11,0x11,0x11,0x11,0x11,0x0e}}}, + {'P', {{0x1e,0x11,0x11,0x1e,0x10,0x10,0x10}}}, + {'Q', {{0x0e,0x11,0x11,0x11,0x15,0x12,0x0d}}}, + {'R', {{0x1e,0x11,0x11,0x1e,0x14,0x12,0x11}}}, + {'S', {{0x0f,0x10,0x10,0x0e,0x01,0x01,0x1e}}}, + {'T', {{0x1f,0x04,0x04,0x04,0x04,0x04,0x04}}}, + {'U', {{0x11,0x11,0x11,0x11,0x11,0x11,0x0e}}}, + {'V', {{0x11,0x11,0x11,0x11,0x11,0x0a,0x04}}}, + {'W', {{0x11,0x11,0x11,0x15,0x15,0x15,0x0a}}}, + {'X', {{0x11,0x11,0x0a,0x04,0x0a,0x11,0x11}}}, + {'Y', {{0x11,0x11,0x0a,0x04,0x04,0x04,0x04}}}, + {'Z', {{0x1f,0x01,0x02,0x04,0x08,0x10,0x1f}}}, +}; + +static const Glyph *glyph_for(char c) { + c = (char)toupper((unsigned char)c); + for (size_t i = 0; i < sizeof(glyphs) / sizeof(glyphs[0]); i++) { + if (glyphs[i].c == c) + return &glyphs[i].g; + } + return &glyphs[0].g; +} + +static uint32_t make_pixel(struct fb_var_screeninfo *v, uint8_t r, uint8_t g, uint8_t b) { + uint32_t pixel = 0; + pixel |= ((uint32_t)(r >> (8 - v->red.length))) << v->red.offset; + pixel |= ((uint32_t)(g >> (8 - v->green.length))) << v->green.offset; + pixel |= ((uint32_t)(b >> (8 - v->blue.length))) << v->blue.offset; + return pixel; +} + +static void put_pixel(uint8_t *fb, struct fb_var_screeninfo *v, struct fb_fix_screeninfo *f, int x, int y, uint32_t pixel) { + if (x < 0 || y < 0 || x >= (int)v->xres || y >= (int)v->yres) + return; + + uint8_t *dst = fb + y * f->line_length + x * (v->bits_per_pixel / 8); + switch (v->bits_per_pixel) { + case 16: + *(uint16_t *)dst = (uint16_t)pixel; + break; + case 24: + dst[0] = pixel & 0xff; + dst[1] = (pixel >> 8) & 0xff; + dst[2] = (pixel >> 16) & 0xff; + break; + case 32: + *(uint32_t *)dst = pixel; + break; + } +} + +static void fill_rect(uint8_t *fb, struct fb_var_screeninfo *v, struct fb_fix_screeninfo *f, int x, int y, int w, int h, uint32_t pixel) { + for (int yy = y; yy < y + h; yy++) { + for (int xx = x; xx < x + w; xx++) + put_pixel(fb, v, f, xx, yy, pixel); + } +} + +static int text_width(const char *text, int scale) { + return (int)strlen(text) * 6 * scale - scale; +} + +static void draw_text(uint8_t *fb, struct fb_var_screeninfo *v, struct fb_fix_screeninfo *f, int x, int y, const char *text, int scale, uint32_t pixel) { + for (const char *p = text; *p; p++, x += 6 * scale) { + const Glyph *glyph = glyph_for(*p); + for (int row = 0; row < 7; row++) { + for (int col = 0; col < 5; col++) { + if (glyph->rows[row] & (1 << (4 - col))) + fill_rect(fb, v, f, x + col * scale, y + row * scale, scale, scale, pixel); + } + } + } +} + +int main(int argc, char **argv) { + const char *message = argc > 1 ? argv[1] : "STARTING NEXTUI"; + int fd = open("/dev/fb0", O_RDWR); + if (fd < 0) + return 1; + + struct fb_var_screeninfo v; + struct fb_fix_screeninfo f; + if (ioctl(fd, FBIOGET_VSCREENINFO, &v) < 0 || ioctl(fd, FBIOGET_FSCREENINFO, &f) < 0) { + close(fd); + return 1; + } + if (v.bits_per_pixel != 16 && v.bits_per_pixel != 24 && v.bits_per_pixel != 32) { + close(fd); + return 1; + } + + size_t map_len = f.smem_len ? f.smem_len : (size_t)f.line_length * v.yres; + uint8_t *fb = mmap(NULL, map_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (fb == MAP_FAILED) { + close(fd); + return 1; + } + + uint32_t bg = make_pixel(&v, 13, 17, 20); + uint32_t panel = make_pixel(&v, 29, 36, 40); + uint32_t accent = make_pixel(&v, 85, 214, 183); + uint32_t text = make_pixel(&v, 235, 241, 241); + uint32_t dim = make_pixel(&v, 120, 134, 134); + + fill_rect(fb, &v, &f, 0, 0, v.xres, v.yres, bg); + int scale = v.xres < 600 ? 3 : 4; + int logo_scale = v.xres < 600 ? 6 : 8; + int center_x = (int)v.xres / 2; + int center_y = (int)v.yres / 2; + + int panel_w = (int)v.xres * 7 / 10; + int panel_h = (int)v.yres / 3; + int panel_x = center_x - panel_w / 2; + int panel_y = center_y - panel_h / 2; + fill_rect(fb, &v, &f, panel_x, panel_y, panel_w, panel_h, panel); + fill_rect(fb, &v, &f, panel_x, panel_y, panel_w, 4, accent); + + int logo_w = text_width("NEXTUI", logo_scale); + draw_text(fb, &v, &f, center_x - logo_w / 2, panel_y + panel_h / 4 - 24, "NEXTUI", logo_scale, text); + + char msg[64]; + snprintf(msg, sizeof(msg), "%s", message); + int msg_w = text_width(msg, scale); + draw_text(fb, &v, &f, center_x - msg_w / 2, panel_y + panel_h * 2 / 3, msg, scale, dim); + + msync(fb, map_len, MS_SYNC); + munmap(fb, map_len); + close(fd); + return 0; +} diff --git a/workspace/h700/check-settings-ldd.sh b/workspace/h700/check-settings-ldd.sh new file mode 100755 index 000000000..1b6fcbf6f --- /dev/null +++ b/workspace/h700/check-settings-ldd.sh @@ -0,0 +1,39 @@ +#!/bin/sh +set -eu + +ROOT_DIR="${1:-$(cd "$(dirname "$0")/../.." && pwd)}" +SETTINGS_ELF="${SETTINGS_ELF:-$ROOT_DIR/build/EXTRAS/Tools/h700/Settings.pak/settings.elf}" +H700_LIB_DIR="${H700_LIB_DIR:-$ROOT_DIR/build/SYSTEM/h700/lib}" + +if [ ! -f "$SETTINGS_ELF" ]; then + echo "missing settings.elf: $SETTINGS_ELF" >&2 + exit 1 +fi + +if [ ! -d "$H700_LIB_DIR" ]; then + echo "missing h700 lib dir: $H700_LIB_DIR" >&2 + exit 1 +fi + +export LD_LIBRARY_PATH="$H700_LIB_DIR:${LD_LIBRARY_PATH:-}" +ldd_output="$(ldd "$SETTINGS_ELF" 2>&1)" || { + echo "$ldd_output" + exit 1 +} + +echo "$ldd_output" + +if echo "$ldd_output" | grep -q "not found"; then + echo "settings.elf has unresolved runtime libraries" >&2 + exit 1 +fi + +if ! echo "$ldd_output" | grep -q "libgio-2.0"; then + echo "settings.elf is expected to link gio-2.0 on h700" >&2 + exit 1 +fi + +if ! echo "$ldd_output" | grep -q "libglib-2.0"; then + echo "settings.elf is expected to link glib-2.0 on h700" >&2 + exit 1 +fi diff --git a/workspace/h700/cores/makefile b/workspace/h700/cores/makefile new file mode 100755 index 000000000..5d03b8f4a --- /dev/null +++ b/workspace/h700/cores/makefile @@ -0,0 +1,135 @@ +CORES= a2600 +CORES+= a5200 +CORES+= a7800 +CORES+= handy +CORES+= c64 +CORES+= c128 +CORES+= fake-08 +CORES+= fbneo +CORES+= fceumm +CORES+= gambatte +CORES+= gpsp +CORES+= libretro-cap32 +CORES+= libretro-uae +CORES+= mednafen_pce_fast +CORES+= mednafen_supafaust +CORES+= mednafen_vb +CORES+= mgba +CORES+= pcsx_rearmed +CORES+= pet +CORES+= picodrive +CORES+= plus4 +CORES+= pokemini +CORES+= race +CORES+= snes9x +CORES+= vic +CORES+= prboom +CORES+= bluemsx +CORES+= gearcoleco + +############################### + +# optional core vars +# *_REPO= +# *_HASH= +# *_CORE= +# *_FLAGS= +# *_MAKEFILE= +# *_BUILD_PATH= +# *_SUBMODULES= + +a2600_REPO = https://github.com/libretro/stella2014-libretro +a2600_CORE = stella2014_libretro.so + +a5200_CORE = a5200_libretro.so + +a7800_CORE = prosystem_libretro.so +a7800_REPO = https://github.com/libretro/prosystem-libretro + +handy_REPO = https://github.com/libretro/libretro-handy + +fbneo_REPO = https://github.com/libretro/FBNeo +fbneo_CORE = fbneo_libretro.so +fbneo_BUILD_PATH = fbneo/src/burner/libretro +fbneo_MAKE = make +fbneo_HASH = 6a5cc250c2db8d874a06ee86e302a2a78918b4c1 + +mednafen_pce_fast_REPO = https://github.com/libretro/beetle-pce-fast-libretro +mednafen_vb_REPO = https://github.com/libretro/beetle-vb-libretro + +fake-08_REPO = https://github.com/jtothebell/fake-08 +fake-08_CORE = fake08_libretro.so +fake-08_BUILD_PATH = fake-08/platform/libretro + +fceumm_REPO = https://github.com/libretro/libretro-fceumm + +gambatte_REPO = https://github.com/libretro/gambatte-libretro + +mednafen_supafaust_REPO = https://github.com/libretro/supafaust + +# mGBA replaced Makefile.libretro with a CMake-based libretro build. +mgba_CORE = build-h700/mgba_libretro.so +mgba_MAKE = cmake -S . -B build-h700 -DCMAKE_BUILD_TYPE=Release -DLIBMGBA_ONLY=ON -DBUILD_LIBRETRO=ON -DLIBRETRO_STATIC=OFF -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=aarch64 -DCMAKE_C_COMPILER=$(CROSS_COMPILE)gcc -DCMAKE_CXX_COMPILER=$(CROSS_COMPILE)g++ -DCMAKE_C_FLAGS="-fomit-frame-pointer -ffast-math -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a -fno-common -ftree-vectorize -funswitch-loops" -DCMAKE_CXX_FLAGS="-fomit-frame-pointer -ffast-math -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a -fno-common -ftree-vectorize -funswitch-loops" && cmake --build build-h700 --target mgba_libretro -- $(PROCS) + +pcsx_rearmed_MAKEFILE = Makefile.libretro +# pcsx has a disabled submodule for gnulib, which takes forever to check out and is unused - skil checkout +pcsx_rearmed_SUBMODULES = frontend/libpicofe + +picodrive_REPO = https://github.com/irixxxx/picodrive +picodrive_MAKEFILE = Makefile.libretro +# No background Audio on Sega CD +# https://github.com/LoveRetro/NextUI/issues/68 +picodrive_HASH = b0be121b7d58d6ee1ee2809974e62893c80a8264 + +pokemini_REPO = https://github.com/libretro/PokeMini +pokemini_MAKEFILE = Makefile.libretro +# Our patchfile doesn't work on latest Pokemon mini commits, pinning to last working hash for now +pokemini_HASH = 78656d4615691c393e65e48672ce5fff5b1f97d3 + +prboom_REPO = https://github.com/libretro/libretro-prboom + +snes9x2005_plus_REPO = https://github.com/libretro/snes9x2005 +snes9x2005_plus_FLAGS = USE_BLARGG_APU=1 + +snes9x_REPO = https://github.com/libretro/snes9x +snes9x_CORE = snes9x_libretro.so +snes9x_BUILD_PATH = snes9x/libretro + +libretro-uae_REPO = https://github.com/libretro/libretro-uae +libretro-uae_BRANCH = 2.6.1 +libretro-uae_CORE = puae2021_libretro.so + +libretro-cap32_REPO = https://github.com/libretro/libretro-cap32 +libretro-cap32_CORE = cap32_libretro.so + +c64_REPO = https://github.com/libretro/vice-libretro +c64_CORE = vice_x64_libretro.so +c64_FLAGS = EMUTYPE=x64 + +c128_REPO = https://github.com/libretro/vice-libretro +c128_CORE = vice_x128_libretro.so +c128_FLAGS = EMUTYPE=x128 + +vic_REPO = https://github.com/libretro/vice-libretro +vic_CORE = vice_xvic_libretro.so +vic_FLAGS = EMUTYPE=xvic + +pet_REPO = https://github.com/libretro/vice-libretro +pet_CORE = vice_xpet_libretro.so +pet_FLAGS = EMUTYPE=xpet + +plus4_REPO = https://github.com/libretro/vice-libretro +plus4_CORE = vice_xplus4_libretro.so +plus4_FLAGS = EMUTYPE=xplus4 + +bluemsx_REPO = https://github.com/libretro/blueMSX-libretro +bluemsx_CORE = bluemsx_libretro.so +bluemsx_MAKEFILE = Makefile.libretro + +gearcoleco_REPO = https://github.com/drhelius/Gearcoleco.git +gearcoleco_CORE = gearcoleco_libretro.so +gearcoleco_BUILD_PATH = gearcoleco/platforms/libretro + +############################### + +include ../../all/cores/makefile diff --git a/workspace/h700/cores/patches/a2600.patch b/workspace/h700/cores/patches/a2600.patch new file mode 100644 index 000000000..b4ce3be9f --- /dev/null +++ b/workspace/h700/cores/patches/a2600.patch @@ -0,0 +1,24 @@ +diff --git a/Makefile b/Makefile +index a22eb5d..c55c8cf 100644 +--- a/Makefile ++++ b/Makefile +@@ -383,6 +383,19 @@ else ifeq ($(platform), miyoo) + FLAGS += -fomit-frame-pointer -march=armv5te -mtune=arm926ej-s + fpic := -fPIC + ++# target platform h700 trimUI brick ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CC = $(CROSS_COMPILE)gcc ++ CXX = $(CROSS_COMPILE)g++ ++ AR = $(CROSS_COMPILE)ar ++ SHARED := -shared -Wl,--no-undefined ++ LDFLAGS += -shared -Wl,--version-script=link.T ++ FLAGS += -DARM -DALIGN_DWORD -falign-functions=16 -pipe -fstack-protector ++ FLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ fpic := -fPIC ++ HAVE_NEON = 1 ++ + # Windows MSVC 2003 Xbox 1 + else ifeq ($(platform), xbox1_msvc2003) + TARGET := $(TARGET_NAME)_libretro_xdk1.lib diff --git a/workspace/h700/cores/patches/a5200.patch b/workspace/h700/cores/patches/a5200.patch new file mode 100644 index 000000000..ed62d8633 --- /dev/null +++ b/workspace/h700/cores/patches/a5200.patch @@ -0,0 +1,23 @@ +diff --git a/Makefile b/Makefile +index 67a7e1f..184ec33 100644 +--- a/Makefile ++++ b/Makefile +@@ -326,6 +326,18 @@ else ifeq ($(platform), miyoo) + FLAGS += -fomit-frame-pointer -ffast-math -mcpu=arm926ej-s + fpic := -fPIC + ++# target platform h700 trimUI brick ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CC = $(CROSS_COMPILE)gcc ++ CXX = $(CROSS_COMPILE)g++ ++ AR = $(CROSS_COMPILE)ar ++ SHARED := -shared -Wl,--no-undefined ++ LDFLAGS += -shared -Wl,--version-script=link.T ++ FLAGS += -fomit-frame-pointer -ffast-math -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ fpic := -fPIC ++ HAVE_NEON = 1 ++ + # Raspberry Pi 1 + else ifeq ($(platform), rpi1) + TARGET := $(TARGET_NAME)_libretro.so diff --git a/workspace/h700/cores/patches/a7800.patch b/workspace/h700/cores/patches/a7800.patch new file mode 100644 index 000000000..7b07efb9b --- /dev/null +++ b/workspace/h700/cores/patches/a7800.patch @@ -0,0 +1,23 @@ +diff --git a/Makefile b/Makefile +index dc2a31c..2a8bca2 100644 +--- a/Makefile ++++ b/Makefile +@@ -328,6 +328,18 @@ else ifeq ($(platform), miyoo) + FLAGS += -fomit-frame-pointer -ffast-math -march=armv5te -mtune=arm926ej-s + fpic := -fPIC + ++# target platform h700 trimUI brick ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CC = $(CROSS_COMPILE)gcc ++ CXX = $(CROSS_COMPILE)g++ ++ AR = $(CROSS_COMPILE)ar ++ SHARED := -shared -Wl,--no-undefined ++ LDFLAGS += -shared -Wl,--version-script=link.T ++ FLAGS += -fomit-frame-pointer -ffast-math -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ fpic := -fPIC ++ HAVE_NEON = 1 ++ + # Raspberry Pi 1 + else ifeq ($(platform), rpi1) + TARGET := $(TARGET_NAME)_libretro.so diff --git a/workspace/h700/cores/patches/bluemsx.patch b/workspace/h700/cores/patches/bluemsx.patch new file mode 100644 index 000000000..f1ab4b2bd --- /dev/null +++ b/workspace/h700/cores/patches/bluemsx.patch @@ -0,0 +1,30 @@ +diff --git a/Makefile.libretro b/Makefile.libretro +index 6f412c7..9a8a14a 100644 +--- a/Makefile.libretro ++++ b/Makefile.libretro +@@ -188,6 +188,25 @@ else ifeq ($(platform), classic_armv8_a35) + LDFLAGS += -marm -mcpu=cortex-a35 -mfpu=neon-fp-armv8 -mfloat-abi=hard -Ofast -flto -fuse-linker-plugin + ####################################### + ++# (Trimui Brick/Smart Pro) ### ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CC = $(CROSS_COMPILE)gcc ++ CXX = $(CROSS_COMPILE)g++ ++ AR = $(CROSS_COMPILE)ar ++ fpic := -fPIC ++ SHARED := -shared -Wl,-version-script=link.T -Wl,-no-undefined ++ CFLAGS += -Ofast \ ++ -fuse-linker-plugin \ ++ -fno-stack-protector -fno-ident -fomit-frame-pointer \ ++ -fmerge-all-constants -ffast-math -funroll-all-loops \ ++ -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ CPPFLAGS += $(CFLAGS) ++ HAVE_NEON = 1 ++ LDFLAGS += -lrt ++ LDFLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a -Ofast -flto -fuse-linker-plugin ++####################################### ++ + # OS X + else ifeq ($(platform), osx) + TARGET := $(TARGET_NAME)_libretro.dylib diff --git a/workspace/h700/cores/patches/c128.patch b/workspace/h700/cores/patches/c128.patch new file mode 100644 index 000000000..6516d1ca5 --- /dev/null +++ b/workspace/h700/cores/patches/c128.patch @@ -0,0 +1,21 @@ +diff --git a/Makefile b/Makefile +index 62cb321..e50aa6e 100644 +--- a/Makefile ++++ b/Makefile +@@ -380,6 +380,16 @@ else ifneq (,$(findstring armv,$(platform))) + endif + CFLAGS += -DARM -marm -DALIGN_DWORD -mthumb-interwork -falign-functions=16 -pipe -fstack-protector + ++# TrimUI Brick ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ fpic := -fPIC ++ SHARED := -shared -Wl,--no-undefined ++ LDFLAGS += -shared -Wl,--version-script=$(CORE_DIR)/libretro/link.T ++ HAVE_NEON = 1 ++ CFLAGS += -DARM -DALIGN_DWORD -falign-functions=16 -pipe -fstack-protector ++ CFLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ + # Wincross64 + else ifeq ($(platform), wincross64) + AR = x86_64-w64-mingw32-ar diff --git a/workspace/h700/cores/patches/c64.patch b/workspace/h700/cores/patches/c64.patch new file mode 100644 index 000000000..6516d1ca5 --- /dev/null +++ b/workspace/h700/cores/patches/c64.patch @@ -0,0 +1,21 @@ +diff --git a/Makefile b/Makefile +index 62cb321..e50aa6e 100644 +--- a/Makefile ++++ b/Makefile +@@ -380,6 +380,16 @@ else ifneq (,$(findstring armv,$(platform))) + endif + CFLAGS += -DARM -marm -DALIGN_DWORD -mthumb-interwork -falign-functions=16 -pipe -fstack-protector + ++# TrimUI Brick ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ fpic := -fPIC ++ SHARED := -shared -Wl,--no-undefined ++ LDFLAGS += -shared -Wl,--version-script=$(CORE_DIR)/libretro/link.T ++ HAVE_NEON = 1 ++ CFLAGS += -DARM -DALIGN_DWORD -falign-functions=16 -pipe -fstack-protector ++ CFLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ + # Wincross64 + else ifeq ($(platform), wincross64) + AR = x86_64-w64-mingw32-ar diff --git a/workspace/h700/cores/patches/fake-08.patch b/workspace/h700/cores/patches/fake-08.patch new file mode 100644 index 000000000..8d9bbf454 --- /dev/null +++ b/workspace/h700/cores/patches/fake-08.patch @@ -0,0 +1,22 @@ +diff --git forkSrcPrefix/platform/libretro/Makefile forkDstPrefix/platform/libretro/Makefile +index be0f1b46bb3ab10be4a9f896f5e8841dd630b35b..f6b4d892627ec2a81b01ddb4da7f0c7a8022221f 100644 +--- forkSrcPrefix/platform/libretro/Makefile ++++ forkDstPrefix/platform/libretro/Makefile +@@ -123,7 +123,16 @@ else ifeq ($(platform), miyoomini) + CXXFLAGS += -marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7ve -D_NEED_FULL_PATH_ + fpic := -fPIC + SHARED := -shared -Wl,--version-script=link.T +- ++# TRIMUI SMART PRO ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CC = $(CROSS_COMPILE)gcc ++ CXX = $(CROSS_COMPILE)g++ ++ AR = $(CROSS_COMPILE)ar ++ STRIP = $(CROSS_COMPILE)strip ++ CXXFLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ fpic := -fPIC ++ SHARED := -shared -Wl,--version-script=link.T + else ifeq ($(platform), gcw0) + TARGET := $(TARGET_NAME)_libretro_gcw0.so + CC = /opt/gcw0-toolchain/usr/bin/mipsel-linux-gcc diff --git a/workspace/h700/cores/patches/fbneo.patch b/workspace/h700/cores/patches/fbneo.patch new file mode 100644 index 000000000..60ed40322 --- /dev/null +++ b/workspace/h700/cores/patches/fbneo.patch @@ -0,0 +1,108 @@ +diff --git a/src/burner/libretro/Makefile b/src/burner/libretro/Makefile +old mode 100644 +new mode 100755 +index 0b7d646c7..2784aa150 +--- a/src/burner/libretro/Makefile ++++ b/src/burner/libretro/Makefile +@@ -346,6 +346,22 @@ else ifeq ($(platform), classic_armv7_a7) + CFLAGS += $(PLATFORM_FLAGS) + CXXFLAGS += $(PLATFORM_FLAGS) + ++# target platform h700 trimUI brick ++else ifneq (,$(findstring h700,$(platform))) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CXX=$(CROSS_COMPILE)g++ ++ fpic := -fPIC ++ SHARED := -shared -Wl,-no-undefined -Wl,--version-script=$(VERSION_SCRIPT) ++ PLATFORM_FLAGS := -O3 -Ofast -DNDEBUG=1 -fomit-frame-pointer -ffast-math -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a+simd ++ USE_EXPERIMENTAL_FLAGS = 0 ++ HAVE_NEON = 1 ++ USE_CYCLONE = 1 ++ ARCH = arm ++ ENDIANNESS_DEFINES := -DLSB_FIRST ++ LDFLAGS += -lstdc++ -static-libgcc -static-libstdc++ -lpthread -lm -flto ++ CFLAGS += $(PLATFORM_FLAGS) ++ CXXFLAGS += $(PLATFORM_FLAGS) ++ + # (armv8 a35, hard point, neon based) ### + # Playstation Classic + else ifeq ($(platform), classic_armv8_a35) +diff --git a/src/burner/libretro/libretro.cpp b/src/burner/libretro/libretro.cpp +index 3726ec60f..30a6c8cd6 100644 +--- a/src/burner/libretro/libretro.cpp ++++ b/src/burner/libretro/libretro.cpp +@@ -78,7 +78,7 @@ INT32 nAudSegLen = 0; + + static UINT8* pVidImage = NULL; + static bool bVidImageNeedRealloc = false; +-static bool bRotationDone = false; ++static bool bRotationDone = true; + static int16_t *pAudBuffer = NULL; + static char text_missing_files[2048] = ""; + +@@ -1550,8 +1550,46 @@ void retro_run() + // current frame will be corrupted, let's dupe instead + pBurnDraw = NULL; + } ++ // get flags ++ UINT32 flags = BurnDrvGetFlags(); ++ ++ if (pBurnDraw && flags & BDF_ORIENTATION_VERTICAL) { ++ int y=0; ++ ++ UINT8 *pTMP = (UINT8*)malloc(nGameWidth * nGameHeight * nBurnBpp); ++ memcpy(pTMP, pBurnDraw, nGameWidth * nGameHeight * nBurnBpp); ++ ++ int newGameWidth = nGameHeight; ++ int newGameHeight = nGameWidth; ++ int newBurnPitch = newGameWidth * nBurnBpp; ++ ++ if ((BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL)) ++ while (y < newGameHeight) { ++ int x = 0; ++ ++ if ( flags & BDF_ORIENTATION_FLIPPED ) { ++ while (x < newGameWidth) ++ { ++ for (int i = 0; i < nBurnBpp; i++) ++ pBurnDraw[x * nBurnBpp + y * newBurnPitch + i] = pTMP[(nGameHeight - x - 1) * nBurnPitch + y * nBurnBpp + i]; ++ x++; ++ } ++ } else { ++ while (x < newGameWidth) ++ { ++ for (int i = 0; i < nBurnBpp; i++) ++ pBurnDraw[x * nBurnBpp + y * newBurnPitch + i] = pTMP[x * nBurnPitch + (nGameWidth - y - 1) * nBurnBpp + i]; ++ x++; ++ } ++ } ++ y++; ++ } ++ free(pTMP); ++ video_cb(pBurnDraw, newGameWidth, newGameHeight, newBurnPitch); ++ } else { ++ video_cb(pBurnDraw, nGameWidth, nGameHeight, nBurnPitch); ++ } + +- video_cb(pBurnDraw, nGameWidth, nGameHeight, nBurnPitch); + + bool updated = false; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) +@@ -1567,7 +1605,7 @@ void retro_run() + // change orientation/geometry if vertical mode was toggled on/off + if (old_nVerticalMode != nVerticalMode) + { +- SetRotation(); ++ //SetRotation(); + struct retro_system_av_info av_info; + retro_get_system_av_info(&av_info); + environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &av_info); +@@ -2184,7 +2222,7 @@ static bool retro_load_game_common() + + // Initializing display, autorotate if needed + BurnDrvGetFullSize(&nGameWidth, &nGameHeight); +- SetRotation(); ++ //SetRotation(); + SetColorDepth(); + + VideoBufferInit(); diff --git a/workspace/h700/cores/patches/fceumm.patch b/workspace/h700/cores/patches/fceumm.patch new file mode 100644 index 000000000..b8520f0f6 --- /dev/null +++ b/workspace/h700/cores/patches/fceumm.patch @@ -0,0 +1,27 @@ +diff --git forkSrcPrefix/Makefile.libretro forkDstPrefix/Makefile.libretro +index 5b90d409271332a48ae726dca48a712c3be413be..8b6fc14db737e32d47b0c8ad449b0b03e78548c1 100644 +--- forkSrcPrefix/Makefile.libretro ++++ forkDstPrefix/Makefile.libretro +@@ -458,5 +458,22 @@ else ifeq ($(platform), miyoo) + PLATFORM_DEFINES += -fomit-frame-pointer -ffast-math -mcpu=arm926ej-s + ++# TRIMUI SMART PRO ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CC = $(CROSS_COMPILE)gcc ++ CXX = $(CROSS_COMPILE)g++ ++ AR = $(CROSS_COMPILE)ar ++ SHARED := -shared -Wl,--version-script=src/drivers/libretro/link.T -Wl,-no-undefined ++ LDFLAGS += -fPIC -flto ++ CFLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ CFLAGS += -fomit-frame-pointer -ffast-math -fPIC -flto ++ OPTIMIZE := -Ofast -DNDEBUG ++ EXTERNAL_ZLIB = 1 ++ HAVE_NTSC = 0 ++ ifeq (,$(DEBUG)) ++ # LDFLAGS += -s ++ endif ++ + # Windows MSVC 2017 all architectures + else ifneq (,$(findstring windows_msvc2017,$(platform))) + CC = cl.exe diff --git a/workspace/h700/cores/patches/gambatte.patch b/workspace/h700/cores/patches/gambatte.patch new file mode 100644 index 000000000..841b073ed --- /dev/null +++ b/workspace/h700/cores/patches/gambatte.patch @@ -0,0 +1,24 @@ +diff --git forkSrcPrefix/Makefile.libretro forkDstPrefix/Makefile.libretro +index ffaba21e7a88f90786d818ab550b68acd05738bf..2095b2f843eaf6be9abec24ce3da69b551da86a6 100644 +--- forkSrcPrefix/Makefile.libretro ++++ forkDstPrefix/Makefile.libretro +@@ -381,6 +381,19 @@ else ifeq ($(platform), gcw0) + CFLAGS += -fomit-frame-pointer -ffast-math -march=mips32 -mtune=mips32r2 -mhard-float + CXXFLAGS += $(CFLAGS) + ++# TRIMUI SMART PRO ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CC = $(CROSS_COMPILE)gcc ++ CXX = $(CROSS_COMPILE)g++ ++ AR = $(CROSS_COMPILE)ar ++ SHARED := -shared -Wl,--version-script=$(version_script) ++ LDFLAGS += -fPIC -flto ++ PLATFORM_DEFINES := -DCC_RESAMPLER -DCC_RESAMPLER_NO_HIGHPASS ++ CFLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ CFLAGS += -fomit-frame-pointer -ffast-math -fPIC -flto ++ CXXFLAGS += $(CFLAGS) ++ + # RETROFW + else ifeq ($(platform), retrofw) + TARGET := $(TARGET_NAME)_libretro.so diff --git a/workspace/h700/cores/patches/gearcoleco.patch b/workspace/h700/cores/patches/gearcoleco.patch new file mode 100644 index 000000000..f43dfd6be --- /dev/null +++ b/workspace/h700/cores/patches/gearcoleco.patch @@ -0,0 +1,29 @@ +diff --git a/platforms/libretro/Makefile b/platforms/libretro/Makefile +index 581ee84..d9db102 100644 +--- a/platforms/libretro/Makefile ++++ b/platforms/libretro/Makefile +@@ -274,6 +274,24 @@ else ifeq ($(platform), miyoo) + PLATFORM_DEFINES := -DCC_RESAMPLER -DCC_RESAMPLER_NO_HIGHPASS + CFLAGS += -fomit-frame-pointer -ffast-math -march=armv5te -mtune=arm926ej-s + CXXFLAGS += $(CFLAGS) ++# TrimUI Brick/Smart Pro ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CC = $(CROSS_COMPILE)gcc ++ CXX = $(CROSS_COMPILE)g++ ++ AR = $(CROSS_COMPILE)ar ++ fpic := -fPIC ++ SHARED := -shared -Wl,-version-script=$(CORE_DIR)/link.T ++ PLATFORM_DEFINES := -DCC_RESAMPLER -DCC_RESAMPLER_NO_HIGHPASS ++ CFLAGS += -Ofast \ ++ -fuse-linker-plugin \ ++ -fno-stack-protector -fno-ident -fomit-frame-pointer \ ++ -fmerge-all-constants -ffast-math -funroll-all-loops \ ++ -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ CXXFLAGS += $(CFLAGS) ++ HAVE_NEON = 1 ++ USE_DYNAREC = 1 ++ LDFLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a -Ofast -flto -fuse-linker-plugin + # PS2 + else ifeq ($(platform), ps2) + TARGET := $(TARGET_NAME)_libretro_$(platform).a diff --git a/workspace/h700/cores/patches/gpsp.patch b/workspace/h700/cores/patches/gpsp.patch new file mode 100644 index 000000000..5857b3ad9 --- /dev/null +++ b/workspace/h700/cores/patches/gpsp.patch @@ -0,0 +1,26 @@ +diff --git forkSrcPrefix/Makefile forkDstPrefix/Makefile +index dc4b60dec7f70a153dbc2eb849cd5acfc90f9d4d..94c7f8dd037284153b6858730a10b6aaaafd5ad4 100644 +--- forkSrcPrefix/Makefile ++++ forkDstPrefix/Makefile +@@ -524,6 +524,21 @@ else ifeq ($(platform), miyoomini) + ARCH = arm + BUILTIN_GPU = neon + ++# TRIMUI SMART PRO ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CC = $(CROSS_COMPILE)gcc ++ CXX = $(CROSS_COMPILE)g++ ++ AR = $(CROSS_COMPILE)ar ++ SHARED := -shared -Wl,--version-script=link.T ++ fpic := -fPIC -DPIC ++ CFLAGS += -fomit-frame-pointer -ffast-math ++ CFLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ ARCH = arm64 ++ CPU_ARCH := arm64 ++ MMAP_JIT_CACHE = 1 ++ HAVE_DYNAREC = 1 ++ + # Windows + else + TARGET := $(TARGET_NAME)_libretro.dll diff --git a/workspace/h700/cores/patches/handy.patch b/workspace/h700/cores/patches/handy.patch new file mode 100644 index 000000000..b1024fca7 --- /dev/null +++ b/workspace/h700/cores/patches/handy.patch @@ -0,0 +1,22 @@ +diff --git a/Makefile b/Makefile +index 088c344..9573f27 100644 +--- a/Makefile ++++ b/Makefile +@@ -270,6 +270,17 @@ else ifeq ($(platform), gcw0) + SHARED := -shared -Wl,--no-undefined -Wl,-version-script=$(LIBRETRO_DIR)/link.T + FLAGS += -DDINGUX -fomit-frame-pointer -ffast-math -march=armv5te -mtune=arm926ej-s + ++# target platform h700 trimUI brick ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CC = $(CROSS_COMPILE)gcc ++ CXX = $(CROSS_COMPILE)g++ ++ AR = $(CROSS_COMPILE)ar ++ fpic := -fPIC ++ SHARED := -shared -Wl,--no-undefined -Wl,-version-script=$(LIBRETRO_DIR)/link.T ++ FLAGS += -fomit-frame-pointer -ffast-math -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ HAVE_NEON = 1 ++ + # Nintendo Switch (libnx) + else ifeq ($(platform), libnx) + include $(DEVKITPRO)/libnx/switch_rules diff --git a/workspace/h700/cores/patches/libretro-cap32.patch b/workspace/h700/cores/patches/libretro-cap32.patch new file mode 100644 index 000000000..45add2b00 --- /dev/null +++ b/workspace/h700/cores/patches/libretro-cap32.patch @@ -0,0 +1,29 @@ +diff --git a/Makefile b/Makefile +index 1aa1720..228fb6b 100644 +--- a/Makefile ++++ b/Makefile +@@ -390,6 +390,24 @@ else ifeq ($(platform), miyoo) + CFLAGS += -funsafe-math-optimizations -fsingle-precision-constant -fexpensive-optimizations + CFLAGS += -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-unroll-loops + ++# TrimUI Brick ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CC = $(CROSS_COMPILE)gcc ++ CXX = $(CROSS_COMPILE)g++ ++ AR = $(CROSS_COMPILE)ar ++ SHARED := -shared -Wl,--version-script=link.T -Wl,-no-undefined ++ LDFLAGS += -fPIC -flto ++ CFLAGS := -DFRONTEND_SUPPORTS_RGB565 -DINLINE="inline" -DM16BPP ++ CFLAGS += -ffast-math ++ CFLAGS += -falign-functions=1 -falign-jumps=1 -falign-loops=1 ++ CFLAGS += -fomit-frame-pointer -ffast-math ++ CFLAGS += -funsafe-math-optimizations -fsingle-precision-constant -fexpensive-optimizations ++ CFLAGS += -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-unroll-loops ++ CFLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ CFLAGS += -fomit-frame-pointer -ffast-math -fPIC -flto ++ OPTIMIZE := -Ofast -DNDEBUG ++ + # emscripten + else ifeq ($(platform), emscripten) + TARGET := $(TARGET_NAME)_libretro_$(platform).bc diff --git a/workspace/h700/cores/patches/libretro-uae.patch b/workspace/h700/cores/patches/libretro-uae.patch new file mode 100644 index 000000000..6c0e513cd --- /dev/null +++ b/workspace/h700/cores/patches/libretro-uae.patch @@ -0,0 +1,45 @@ +diff --git a/Makefile b/Makefile +index 7e5ff625..d0e5bdf9 100644 +--- a/Makefile ++++ b/Makefile +@@ -37,6 +37,18 @@ ifneq (,$(findstring unix,$(platform))) + endif + endif + ++# TrimUI Brick ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ SHARED := -shared -Wl,--version-script=$(CORE_DIR)/libretro/link.T -Wl,--no-undefined ++ LDFLAGS += -lm -lpthread -ldl ++ LDFLAGS += -fPIC -flto ++ fpic := -fPIC ++ CFLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a+crc+simd ++ CFLAGS += -fomit-frame-pointer -ffast-math -fPIC -flto ++ CFLAGS += -Ofast -flto=4 -fmerge-all-constants -fno-math-errno ++ CXXFLAGS += $(CFLAGS) ++ + # Raspberry Pi 4 + else ifneq (,$(findstring rpi4,$(platform))) + TARGET := $(TARGET_NAME)_libretro.so +diff --git a/sources/src/misc.c b/sources/src/misc.c +index a97b28bc..b328969d 100644 +--- a/sources/src/misc.c ++++ b/sources/src/misc.c +@@ -543,7 +543,7 @@ char *ua_fs_copy (char *dst, int maxlen, const TCHAR *src, int defchar) + char *ua_copy (char *dst, int maxlen, const char *src) + { + dst[0] = 0; +- strncpy (dst, src, maxlen); ++ strncpy (dst, src, maxlen & 0xffffffff); + return dst; + } + +@@ -555,7 +555,7 @@ TCHAR *au (const char *s) + TCHAR *au_copy (TCHAR *dst, int maxlen, const char *src) + { + dst[0] = 0; +- memcpy (dst, src, maxlen); ++ memcpy (dst, src, maxlen & 0xffffffff); + return dst; + } + diff --git a/workspace/h700/cores/patches/mednafen_pce_fast.patch b/workspace/h700/cores/patches/mednafen_pce_fast.patch new file mode 100644 index 000000000..c2ca9beb9 --- /dev/null +++ b/workspace/h700/cores/patches/mednafen_pce_fast.patch @@ -0,0 +1,25 @@ +diff --git forkSrcPrefix/Makefile forkDstPrefix/Makefile +index 5b54403d915e46cb0df8f428355665fbe26e05b4..f72733d9689aa78795ce8b9d777b0ab9fcc5b65e 100644 +--- forkSrcPrefix/Makefile ++++ forkDstPrefix/Makefile +@@ -380,6 +380,20 @@ else ifeq ($(platform), miyoo) + CXXFLAGS += -std=c++11 + CFLAGS += -std=gnu11 + ++# TRIMUI SMART PRO ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CC = $(CROSS_COMPILE)gcc ++ CXX = $(CROSS_COMPILE)g++ ++ AR = $(CROSS_COMPILE)ar ++ fpic := -fPIC ++ SHARED := -shared -Wl,--no-undefined -Wl,--version-script=link.T ++ LDFLAGS += -lrt ++ FLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ FLAGS += -fomit-frame-pointer -ffast-math -D_GNU_SOURCE ++ CXXFLAGS += -std=c++11 ++ CFLAGS += -std=gnu11 ++ + # Windows MSVC 2017 all architectures + else ifneq (,$(findstring windows_msvc2017,$(platform))) + diff --git a/workspace/h700/cores/patches/mednafen_supafaust.patch b/workspace/h700/cores/patches/mednafen_supafaust.patch new file mode 100644 index 000000000..b99224544 --- /dev/null +++ b/workspace/h700/cores/patches/mednafen_supafaust.patch @@ -0,0 +1,34 @@ +diff --git forkSrcPrefix/Makefile forkDstPrefix/Makefile +index f34a01587cda48cc28ebdfd7f00151b06ea88c42..6966d3c4802b200dea33bdbe8e96b2082a36d577 100644 +--- forkSrcPrefix/Makefile ++++ forkDstPrefix/Makefile +@@ -88,6 +88,29 @@ else ifeq ($(platform), classic_armv8_a35) + ARCH = arm + CFLAGS += -march=armv8-a + LDFLAGS += -static-libgcc -static-libstdc++ ++ ++# TRIMUI SMART PRO ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CC = $(CROSS_COMPILE)gcc ++ CXX = $(CROSS_COMPILE)g++ ++ AR = $(CROSS_COMPILE)ar ++ STRIP = $(CROSS_COMPILE)strip ++ NEED_BPP := 16 ++ fpic := -fPIC ++ SHARED := -shared -Wl,--no-undefined -Wl,--version-script=link.T ++ CFLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ CFLAGS += -Ofast \ ++ -flto=4 -fwhole-program -fuse-linker-plugin \ ++ -fdata-sections -ffunction-sections -Wl,--gc-sections \ ++ -fno-stack-protector -fno-ident -fomit-frame-pointer \ ++ -falign-functions=1 -falign-jumps=1 -falign-loops=1 \ ++ -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-unroll-loops \ ++ -fmerge-all-constants -fno-math-errno ++ CXXFLAGS += $(CFLAGS) ++ HAVE_NEON = 1 ++ ARCH = arm64 ++ + ####################################### + + else ifeq ($(platform), osx) diff --git a/workspace/h700/cores/patches/mednafen_vb.patch b/workspace/h700/cores/patches/mednafen_vb.patch new file mode 100644 index 000000000..a6ea64e00 --- /dev/null +++ b/workspace/h700/cores/patches/mednafen_vb.patch @@ -0,0 +1,29 @@ +diff --git forkSrcPrefix/Makefile forkDstPrefix/Makefile +index c3d5d3b30d71a8f9ed332482fa2af1c21b02605d..5e710154e499ddd7b1ae699122c38753b0f4bb4c 100644 +--- forkSrcPrefix/Makefile ++++ forkDstPrefix/Makefile +@@ -217,6 +217,24 @@ else ifneq (,$(filter $(platform), ps3 psl1ght)) + endif + FLAGS += -D__PS3__ + ++# TRIMUI SMART PRO ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CC = $(CROSS_COMPILE)gcc ++ CXX = $(CROSS_COMPILE)g++ ++ AR = $(CROSS_COMPILE)ar ++ NEED_BPP := 16 ++ fpic := -fPIC ++ SHARED := -shared -Wl,--no-undefined -Wl,--version-script=link.T ++ LDFLAGS += -lrt ++ CFLAGS += -fomit-frame-pointer -ffast-math -fPIC -flto ++ CFLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ CPPFLAGS += $(CFLAGS) ++ LDFLAGS += -flto ++ ifeq (,$(DEBUG)) ++ LDFLAGS += -s ++ endif ++ + # PSP + else ifeq ($(platform), psp1) + TARGET := $(TARGET_NAME)_libretro_$(platform).a diff --git a/workspace/h700/cores/patches/pcsx_rearmed.patch b/workspace/h700/cores/patches/pcsx_rearmed.patch new file mode 100644 index 000000000..732843eb2 --- /dev/null +++ b/workspace/h700/cores/patches/pcsx_rearmed.patch @@ -0,0 +1,30 @@ +diff --git a/Makefile.libretro b/Makefile.libretro +index 2197946c..df72d03d +--- a/Makefile.libretro ++++ b/Makefile.libretro +@@ -518,6 +518,25 @@ else ifeq ($(platform), rpi4_64) + fpic := -fPIC + CFLAGS += -march=armv8-a+crc+simd -mtune=cortex-a72 -ftree-vectorize + ++# TRIMUI SMART PRO ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CC = $(CROSS_COMPILE)gcc ++ CXX = $(CROSS_COMPILE)g++ ++ AR = $(CROSS_COMPILE)ar ++ CFLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a+simd -fomit-frame-pointer ++ CFLAGS += -ffast-math -fdata-sections -ffunction-sections -fsingle-precision-constant -flto -fPIC ++ LDFLAGS += -flto -fPIC ++ ifeq (,$(DEBUG)) ++ # LDFLAGS += -s ++ endif ++ CPU_ARCH := arm64 ++ OPTIMIZE := -O3 -Ofast -DNDEBUG ++ HAVE_NEON = 1 ++ BUILTIN_GPU = neon ++ ARCH = arm64 ++ DYNAREC = ari64 ++ + # Classic Platforms #################### + # Platform affix = classic__<µARCH> + # Help at https://modmyclassic.com/comp diff --git a/workspace/h700/cores/patches/pet.patch b/workspace/h700/cores/patches/pet.patch new file mode 100644 index 000000000..6516d1ca5 --- /dev/null +++ b/workspace/h700/cores/patches/pet.patch @@ -0,0 +1,21 @@ +diff --git a/Makefile b/Makefile +index 62cb321..e50aa6e 100644 +--- a/Makefile ++++ b/Makefile +@@ -380,6 +380,16 @@ else ifneq (,$(findstring armv,$(platform))) + endif + CFLAGS += -DARM -marm -DALIGN_DWORD -mthumb-interwork -falign-functions=16 -pipe -fstack-protector + ++# TrimUI Brick ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ fpic := -fPIC ++ SHARED := -shared -Wl,--no-undefined ++ LDFLAGS += -shared -Wl,--version-script=$(CORE_DIR)/libretro/link.T ++ HAVE_NEON = 1 ++ CFLAGS += -DARM -DALIGN_DWORD -falign-functions=16 -pipe -fstack-protector ++ CFLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ + # Wincross64 + else ifeq ($(platform), wincross64) + AR = x86_64-w64-mingw32-ar diff --git a/workspace/h700/cores/patches/picodrive.patch b/workspace/h700/cores/patches/picodrive.patch new file mode 100644 index 000000000..3eccb3658 --- /dev/null +++ b/workspace/h700/cores/patches/picodrive.patch @@ -0,0 +1,48 @@ +diff --git forkSrcPrefix/Makefile.libretro forkDstPrefix/Makefile.libretro +index 0d1dc08f81a11cef6b3b7238367b1ff27fcf1ead..1f87c76c3242023c4095f0c9087c52765d93c33c 100644 +--- forkSrcPrefix/Makefile.libretro ++++ forkDstPrefix/Makefile.libretro +@@ -497,6 +497,31 @@ else ifeq ($(platform), miyoo) + HAVE_ARMv6 = 0 + LOW_MEMORY = 1 + ++# TRIMUI SMART PRO ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CC = $(CROSS_COMPILE)gcc ++ CXX = $(CROSS_COMPILE)g++ ++ AR = $(CROSS_COMPILE)ar ++ SHARED := -shared -Wl,--no-undefined ++ DONT_COMPILE_IN_ZLIB = 1 ++ CFLAGS += -Ofast \ ++ -fdata-sections -ffunction-sections -Wl,--gc-sections \ ++ -fno-stack-protector -fno-ident -fomit-frame-pointer \ ++ -falign-functions=1 -falign-jumps=1 -falign-loops=1 \ ++ -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-unroll-loops \ ++ -fmerge-all-constants -fno-math-errno ++ CFLAGS += -fPIC ++ CFLAGS += -fomit-frame-pointer -ffast-math -D__GCW0__ ++ CFLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ HAVE_NEON = 1 ++ BUILTIN_GPU = neon ++ ARCH = aarch64 ++ override PLATFORM := libretro ++ ifeq (,$(DEBUG)) ++ LDFLAGS += -s ++ endif ++ + # Windows MSVC 2017 all architectures + else ifneq (,$(findstring windows_msvc2017,$(platform))) + NO_GCC := 1 +@@ -725,6 +750,11 @@ PLATFORM_ZLIB ?= 1 + + include Makefile + ++ifeq ($(platform), h700) ++ CFLAGS := $(filter-out -flto -flto=4 -fuse-linker-plugin -fwhole-program,$(CFLAGS)) ++ LDFLAGS := $(filter-out -flto -flto=4 -fuse-linker-plugin -fwhole-program,$(LDFLAGS)) ++endif ++ + ifeq ($(platform), osx) + pico/cd/libchdr/src/libchdr_chd.o: CFLAGS += -D__MACTYPES__=1 + endif diff --git a/workspace/h700/cores/patches/plus4.patch b/workspace/h700/cores/patches/plus4.patch new file mode 100644 index 000000000..6516d1ca5 --- /dev/null +++ b/workspace/h700/cores/patches/plus4.patch @@ -0,0 +1,21 @@ +diff --git a/Makefile b/Makefile +index 62cb321..e50aa6e 100644 +--- a/Makefile ++++ b/Makefile +@@ -380,6 +380,16 @@ else ifneq (,$(findstring armv,$(platform))) + endif + CFLAGS += -DARM -marm -DALIGN_DWORD -mthumb-interwork -falign-functions=16 -pipe -fstack-protector + ++# TrimUI Brick ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ fpic := -fPIC ++ SHARED := -shared -Wl,--no-undefined ++ LDFLAGS += -shared -Wl,--version-script=$(CORE_DIR)/libretro/link.T ++ HAVE_NEON = 1 ++ CFLAGS += -DARM -DALIGN_DWORD -falign-functions=16 -pipe -fstack-protector ++ CFLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ + # Wincross64 + else ifeq ($(platform), wincross64) + AR = x86_64-w64-mingw32-ar diff --git a/workspace/h700/cores/patches/pokemini.patch b/workspace/h700/cores/patches/pokemini.patch new file mode 100644 index 000000000..3d7dfa181 --- /dev/null +++ b/workspace/h700/cores/patches/pokemini.patch @@ -0,0 +1,27 @@ +diff --git forkSrcPrefix/Makefile.libretro forkDstPrefix/Makefile.libretro +index ef2f9e7d1c6041bea8e2c8a61cdd363ed73a7482..ada8785f566af89cc77f5ab2dd9e670b0a998545 100644 +--- forkSrcPrefix/Makefile.libretro ++++ forkDstPrefix/Makefile.libretro +@@ -504,6 +504,22 @@ else ifeq ($(platform), retrofw) + CFLAGS += -ffast-math -fomit-frame-pointer -march=mips32 -mtune=mips32 -mhard-float + CFLAGS += -DDINGUX + ++# TRIMUI SMART PRO ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CC = $(CROSS_COMPILE)gcc ++ CXX = $(CROSS_COMPILE)g++ ++ AR = $(CROSS_COMPILE)ar ++ SHARED := -shared -Wl,--version-script=libretro/link.T -Wl,--no-undefined ++ fpic := -fPIC ++ CFLAGS += -DARM ++ CFLAGS += $(PTHREAD_FLAGS) ++ CFLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ CFLAGS += -ffast-math -fomit-frame-pointer ++ CFLAGS += -DDINGUX ++ HAVE_NEON = 1 ++ ARCH = arm64 ++ + else ifeq ($(platform), msvc) + OBJOUT = -Fo + diff --git a/workspace/h700/cores/patches/prboom.patch b/workspace/h700/cores/patches/prboom.patch new file mode 100644 index 000000000..11184040b --- /dev/null +++ b/workspace/h700/cores/patches/prboom.patch @@ -0,0 +1,30 @@ +diff --git a/Makefile b/Makefile +index 3d068a5..7d14f14 100644 +--- a/Makefile ++++ b/Makefile +@@ -378,7 +378,24 @@ else ifeq ($(platform), miyoo) + SHARED := -shared -Wl,--version-script=libretro/link.T -Wl,-no-undefined + CFLAGS += -ffast-math -march=armv5te -mtune=arm926ej-s -fomit-frame-pointer + HAVE_LOW_MEMORY = 1 +- ++# target platform h700 trimUI brick ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CC = $(CROSS_COMPILE)gcc ++ CXX = $(CROSS_COMPILE)g++ ++ AR = $(CROSS_COMPILE)ar ++ fpic := -fPIC ++ LDFLAGS += -s $(fpic) -shared -Wl,--version-script=libretro/link.T -Wl,-no-undefined ++ CFLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ CFLAGS += -fomit-frame-pointer -ffast-math -fPIC -flto ++ $(MYARCH) ++ CXXFLAGS += $(CFLAGS) ++ CPPFLAGS += $(CFLAGS) ++ ASFLAGS += $(CFLAGS) ++ HAVE_NEON = 1 ++ HAVE_LOW_MEMORY = 1 ++ CPU_ARCH := arm64 ++ ARM = 1 + # Windows MSVC 2003 Xbox 1 + else ifeq ($(platform), xbox1_msvc2003) + TARGET := $(TARGET_NAME)_libretro_xdk1.lib diff --git a/workspace/h700/cores/patches/race.patch b/workspace/h700/cores/patches/race.patch new file mode 100644 index 000000000..55e331d2d --- /dev/null +++ b/workspace/h700/cores/patches/race.patch @@ -0,0 +1,23 @@ +diff --git forkSrcPrefix/Makefile forkDstPrefix/Makefile +index 792a6d82915c32edd3df6ceec541499f6ca25ac5..dc02b361d7db47e011b6d3addf89cfb31503575a 100644 +--- forkSrcPrefix/Makefile ++++ forkDstPrefix/Makefile +@@ -373,6 +373,18 @@ else ifeq ($(platform), miyoo) + CFLAGS += -fomit-frame-pointer -ffast-math -march=armv5te -mtune=arm926ej-s + CXXFLAGS += $(CFLAGS) + ++# TRIMUI SMART PRO ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CC = $(CROSS_COMPILE)gcc ++ CXX = $(CROSS_COMPILE)g++ ++ AR = $(CROSS_COMPILE)ar ++ fpic := -fPIC ++ SHARED := -shared -Wl,-version-script=$(LIBRETRO_DIR)/link.T ++ PLATFORM_DEFINES := -DCC_RESAMPLER -DCC_RESAMPLER_NO_HIGHPASS ++ CFLAGS += -fomit-frame-pointer -ffast-math -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ CXXFLAGS += $(CFLAGS) ++ + # Windows MSVC 2010 x64 + else ifeq ($(platform), windows_msvc2010_x64) + CC = cl.exe diff --git a/workspace/h700/cores/patches/snes9x.patch b/workspace/h700/cores/patches/snes9x.patch new file mode 100644 index 000000000..a7b1c3988 --- /dev/null +++ b/workspace/h700/cores/patches/snes9x.patch @@ -0,0 +1,22 @@ +diff --git a/libretro/Makefile b/libretro/Makefile +index 466fa6b..ec40f1a +--- a/libretro/Makefile ++++ b/libretro/Makefile +@@ -82,6 +82,17 @@ ifneq (,$(findstring unix,$(platform))) + endif + endif + ++# h700 ++else ifneq (,$(findstring h700,$(platform))) ++ CC=$(CROSS_COMPILE)gcc ++ CXX=$(CROSS_COMPILE)g++ ++ CFLAGS += $(LTO) ++ CXXFLAGS += $(LTO) -O3 -Ofast -march=armv8-a+simd -mtune=cortex-a53 -ffast-math ++ LDFLAGS += $(LTO) -lstdc++ -flto ++ TARGET := $(TARGET_NAME)_libretro.so ++ fpic := -fPIC ++ LIBS += -lz ++ SHARED := -shared -Wl,--version-script=link.T -Wl,-z,defs + # ODROIDN2 + else ifneq (,$(findstring CortexA73_G12B,$(platform))) + TARGET := $(TARGET_NAME)_libretro.so diff --git a/workspace/h700/cores/patches/snes9x2005_plus.patch b/workspace/h700/cores/patches/snes9x2005_plus.patch new file mode 100644 index 000000000..08ec84a9c --- /dev/null +++ b/workspace/h700/cores/patches/snes9x2005_plus.patch @@ -0,0 +1,36 @@ +diff --git forkSrcPrefix/Makefile forkDstPrefix/Makefile +index 07d5368a8e78a020813732239ec369d83e931ede..009f13b8e61c634de4cb83e97785a10b83b4322d 100644 +--- forkSrcPrefix/Makefile ++++ forkDstPrefix/Makefile +@@ -288,6 +288,31 @@ else ifeq ($(platform), miyoo) + FLAGS += -fomit-frame-pointer -ffast-math -march=armv5te -mtune=arm926ej-s + FLAGS += -DFAST_ALIGNED_LSB_WORD_ACCESS -fno-unroll-loops + ++# TRIMUI SMART PRO ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ CC = $(CROSS_COMPILE)gcc ++ CXX = $(CROSS_COMPILE)g++ ++ AR = $(CROSS_COMPILE)ar ++ SHARED := -shared -Wl,--version-script=link.T ++ LIBM := ++ CFLAGS += -Ofast \ ++ -flto=4 -fwhole-program -fuse-linker-plugin \ ++ -fdata-sections -ffunction-sections -Wl,--gc-sections \ ++ -fno-stack-protector -fno-ident -fomit-frame-pointer \ ++ -falign-functions=1 -falign-jumps=1 -falign-loops=1 \ ++ -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-unroll-loops \ ++ -fmerge-all-constants -fno-math-errno ++ CFLAGS += -fPIC ++ CFLAGS += -DLSB_FIRST -DFAST_ALIGNED_LSB_WORD_ACCESS -DRIGHTSHIFT_IS_SAR ++ CFLAGS += -std=c99 -fomit-frame-pointer -ffast-math ++ CFLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ LDFLAGS += -flto ++ OPTIMIZE += -Ofast -DNDEBUG=1 ++ ifeq (,$(DEBUG)) ++ LDFLAGS += -s ++ endif ++ + # (armv7 a7, hard point, neon based) ### + # NESC, SNESC, C64 mini + else ifeq ($(platform), classic_armv7_a7) diff --git a/workspace/h700/cores/patches/vic.patch b/workspace/h700/cores/patches/vic.patch new file mode 100644 index 000000000..6516d1ca5 --- /dev/null +++ b/workspace/h700/cores/patches/vic.patch @@ -0,0 +1,21 @@ +diff --git a/Makefile b/Makefile +index 62cb321..e50aa6e 100644 +--- a/Makefile ++++ b/Makefile +@@ -380,6 +380,16 @@ else ifneq (,$(findstring armv,$(platform))) + endif + CFLAGS += -DARM -marm -DALIGN_DWORD -mthumb-interwork -falign-functions=16 -pipe -fstack-protector + ++# TrimUI Brick ++else ifeq ($(platform), h700) ++ TARGET := $(TARGET_NAME)_libretro.so ++ fpic := -fPIC ++ SHARED := -shared -Wl,--no-undefined ++ LDFLAGS += -shared -Wl,--version-script=$(CORE_DIR)/libretro/link.T ++ HAVE_NEON = 1 ++ CFLAGS += -DARM -DALIGN_DWORD -falign-functions=16 -pipe -fstack-protector ++ CFLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a ++ + # Wincross64 + else ifeq ($(platform), wincross64) + AR = x86_64-w64-mingw32-ar diff --git a/workspace/h700/curl/.gitignore b/workspace/h700/curl/.gitignore new file mode 100644 index 000000000..06ae7d588 --- /dev/null +++ b/workspace/h700/curl/.gitignore @@ -0,0 +1,4 @@ +/curl-* +/musl-* +/openssl-* +/output/ diff --git a/workspace/h700/curl/build.sh b/workspace/h700/curl/build.sh new file mode 100755 index 000000000..8f7a5fbb2 --- /dev/null +++ b/workspace/h700/curl/build.sh @@ -0,0 +1,141 @@ +#!/bin/sh +# Build the curl CLI used by NextUI's HTTP layer without relying on the stock OS. +set -eu + +: "${CROSS_COMPILE:?CROSS_COMPILE is required}" + +CURL_VERSION=8.21.0 +CURL_SHA256=aa1b66a70eace83dc624508745646c08ae561de512ab403adffb93ac87fc72e6 +OPENSSL_VERSION=3.5.7 +OPENSSL_SHA256=a8c0d28a529ca480f9f36cf5792e2cd21984552a3c8e4aa11a24aa31aeac98e8 +MUSL_VERSION=1.2.6 +MUSL_SHA256=d585fd3b613c66151fc3249e8ed44f77020cb5e6c1e635a616d3f9f82460512a +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname "$0")" && pwd) +ARCHIVE="$SCRIPT_DIR/curl-$CURL_VERSION.tar.xz" +SOURCE_DIR="$SCRIPT_DIR/curl-$CURL_VERSION" +MUSL_ARCHIVE="$SCRIPT_DIR/musl-$MUSL_VERSION.tar.gz" +MUSL_SOURCE_DIR="$SCRIPT_DIR/musl-$MUSL_VERSION" +MUSL_PREFIX="$SCRIPT_DIR/musl-prefix" +MUSL_STAMP="$MUSL_PREFIX/.musl-$MUSL_VERSION-$MUSL_SHA256" +MUSL_CC="$MUSL_PREFIX/bin/musl-gcc" +OPENSSL_ARCHIVE="$SCRIPT_DIR/openssl-$OPENSSL_VERSION.tar.gz" +OPENSSL_SOURCE_DIR="$SCRIPT_DIR/openssl-$OPENSSL_VERSION" +OPENSSL_PREFIX="$SCRIPT_DIR/openssl-prefix" +OPENSSL_STAMP="$OPENSSL_PREFIX/.openssl-$OPENSSL_VERSION-$OPENSSL_SHA256-musl-$MUSL_VERSION-$MUSL_SHA256" +OUTPUT_DIR="$SCRIPT_DIR/output" +STAMP="$OUTPUT_DIR/.curl-$CURL_VERSION-$CURL_SHA256-openssl-$OPENSSL_VERSION-$OPENSSL_SHA256-musl-$MUSL_VERSION-$MUSL_SHA256" + +if [ -x "$OUTPUT_DIR/curl" ] && [ -s "$OUTPUT_DIR/ca-certificates.crt" ] && [ -f "$STAMP" ]; then + exit 0 +fi + +mkdir -p "$OUTPUT_DIR" +if [ ! -f "$ARCHIVE" ]; then + wget -q "https://curl.se/download/curl-$CURL_VERSION.tar.xz" -O "$ARCHIVE.tmp" + mv "$ARCHIVE.tmp" "$ARCHIVE" +fi +if ! echo "$CURL_SHA256 $ARCHIVE" | sha256sum -c -; then + rm -f "$ARCHIVE" + exit 1 +fi + +if [ ! -f "$MUSL_ARCHIVE" ]; then + wget -q "https://musl.libc.org/releases/musl-$MUSL_VERSION.tar.gz" -O "$MUSL_ARCHIVE.tmp" + mv "$MUSL_ARCHIVE.tmp" "$MUSL_ARCHIVE" +fi +if ! echo "$MUSL_SHA256 $MUSL_ARCHIVE" | sha256sum -c -; then + rm -f "$MUSL_ARCHIVE" + exit 1 +fi + +if [ ! -f "$MUSL_STAMP" ] || [ ! -x "$MUSL_CC" ] || [ ! -f "$MUSL_PREFIX/lib/libc.a" ]; then + chmod -R u+w "$MUSL_PREFIX" 2>/dev/null || true + rm -rf "$MUSL_SOURCE_DIR" "$MUSL_PREFIX" + tar -xzf "$MUSL_ARCHIVE" -C "$SCRIPT_DIR" + cd "$MUSL_SOURCE_DIR" + CROSS_COMPILE="$CROSS_COMPILE" \ + ./configure --target=aarch64 --prefix="$MUSL_PREFIX" >/dev/null + make -j"$(nproc)" >/dev/null + make install >/dev/null + touch "$MUSL_STAMP" +fi + +if [ ! -f "$OPENSSL_ARCHIVE" ]; then + wget -q "https://github.com/openssl/openssl/releases/download/openssl-$OPENSSL_VERSION/openssl-$OPENSSL_VERSION.tar.gz" -O "$OPENSSL_ARCHIVE.tmp" + mv "$OPENSSL_ARCHIVE.tmp" "$OPENSSL_ARCHIVE" +fi +if ! echo "$OPENSSL_SHA256 $OPENSSL_ARCHIVE" | sha256sum -c -; then + rm -f "$OPENSSL_ARCHIVE" + exit 1 +fi + +if [ ! -f "$OPENSSL_STAMP" ] || [ ! -f "$OPENSSL_PREFIX/lib/libssl.a" ] || [ ! -f "$OPENSSL_PREFIX/lib/libcrypto.a" ]; then + rm -rf "$OPENSSL_SOURCE_DIR" "$OPENSSL_PREFIX" + tar -xzf "$OPENSSL_ARCHIVE" -C "$SCRIPT_DIR" + cd "$OPENSSL_SOURCE_DIR" + REALGCC="${CROSS_COMPILE}gcc" \ + CROSS_COMPILE= CC="$MUSL_CC" AR="${CROSS_COMPILE}ar" RANLIB="${CROSS_COMPILE}ranlib" \ + ./Configure linux-aarch64 \ + --prefix="$OPENSSL_PREFIX" \ + --libdir=lib \ + no-shared no-tests no-docs no-apps no-module no-dso \ + no-secure-memory no-afalgeng no-ktls >/dev/null + REALGCC="${CROSS_COMPILE}gcc" CROSS_COMPILE= make -j"$(nproc)" >/dev/null + REALGCC="${CROSS_COMPILE}gcc" CROSS_COMPILE= make install_sw >/dev/null + touch "$OPENSSL_STAMP" +fi + +rm -rf "$SOURCE_DIR" +tar -xJf "$ARCHIVE" -C "$SCRIPT_DIR" + +cd "$SOURCE_DIR" +# NextUI's HTTP client does not request compressed transfer encoding, so zlib +# is deliberately omitted instead of linking the glibc SDK's archive into musl. +REALGCC="${CROSS_COMPILE}gcc" \ +CC="$MUSL_CC" \ +AR="${CROSS_COMPILE}ar" \ +RANLIB="${CROSS_COMPILE}ranlib" \ +STRIP="${CROSS_COMPILE}strip" \ +PKG_CONFIG=false \ +PKG_CONFIG_SYSROOT_DIR= \ +CPPFLAGS="-I$OPENSSL_PREFIX/include" \ +LDFLAGS="-L$OPENSSL_PREFIX/lib" \ +./configure \ + --host=aarch64-linux-musl \ + --disable-shared \ + --enable-static \ + --with-openssl="$OPENSSL_PREFIX" \ + --without-zlib \ + --with-ca-bundle=/mnt/SDCARD/.system/h700/etc/ssl/certs/ca-certificates.crt \ + --without-ca-path \ + --without-libpsl \ + --without-brotli \ + --without-zstd \ + --without-libidn2 \ + --without-nghttp2 \ + --disable-ldap \ + --disable-ldaps \ + --disable-rtsp \ + --disable-dict \ + --disable-telnet \ + --disable-tftp \ + --disable-pop3 \ + --disable-imap \ + --disable-smb \ + --disable-smtp \ + --disable-gopher \ + --disable-mqtt \ + --disable-manual >/dev/null +REALGCC="${CROSS_COMPILE}gcc" \ +make -j"$(nproc)" LDFLAGS="-all-static -L$OPENSSL_PREFIX/lib" >/dev/null + +"${CROSS_COMPILE}strip" src/curl +cp src/curl "$OUTPUT_DIR/curl" +cp /etc/ssl/certs/ca-certificates.crt "$OUTPUT_DIR/ca-certificates.crt" +chmod 755 "$OUTPUT_DIR/curl" + +file "$OUTPUT_DIR/curl" | grep -q 'ARM aarch64' +file "$OUTPUT_DIR/curl" | grep -q 'statically linked' +test -s "$OUTPUT_DIR/ca-certificates.crt" +rm -f "$OUTPUT_DIR"/.curl-* +touch "$STAMP" diff --git a/workspace/h700/install/boot.sh b/workspace/h700/install/boot.sh new file mode 100755 index 000000000..d22fd5d67 --- /dev/null +++ b/workspace/h700/install/boot.sh @@ -0,0 +1,107 @@ +#!/bin/sh +# NOTE: becomes .tmp_update/h700.sh + +PLATFORM="h700" +SDCARD_PATH="/mnt/SDCARD" +REAL_SDCARD_PATH="/mnt/sdcard" +UPDATE_PATH="$SDCARD_PATH/MinUI.zip" +PAKZ_PATH="$SDCARD_PATH/*.pakz" +SYSTEM_PATH="$SDCARD_PATH/.system" +USERDATA_PATH="$SDCARD_PATH/.userdata/h700" +LOGS_PATH="$USERDATA_PATH/logs" +INSTALL_LOG="$LOGS_PATH/install.txt" +SCRIPT_DIR="$(dirname "$0")" +COMMON_PATH="$SCRIPT_DIR/$PLATFORM/shim-common.sh" + +if [ ! -f "$COMMON_PATH" ]; then + echo "install: missing $COMMON_PATH $(date)" >> /tmp/nextui-h700-install.log 2>/dev/null || true + exit 1 +fi +SHIM_LOG_PATH="$INSTALL_LOG" +SHIM_LOG_PREFIX="install: " +SHIM_LOG_DATES=1 +. "$COMMON_PATH" + +ensure_compat_path "$REAL_SDCARD_PATH" "$SDCARD_PATH" + +export LD_LIBRARY_PATH="$SYSTEM_PATH/$PLATFORM/lib:/usr/lib:/usr/lib/aarch64-linux-gnu:/lib/aarch64-linux-gnu:$LD_LIBRARY_PATH" +export PATH="$SYSTEM_PATH/$PLATFORM/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH" +export PLATFORM + +cd "$SCRIPT_DIR/$PLATFORM" || exit 1 + +mkdir -p "$LOGS_PATH" +echo "install: starting $(date)" > "$INSTALL_LOG" + +log_install() { + shim_log "$@" +} + +show_progress() { + log_install "$1" + if [ -x ./show2.elf ]; then + ./show2.elf --mode=daemon --image="logo.png" --text="$1" --logoheight=128 --progress=-1 >/dev/null 2>&1 & + fi +} + +show_progress "Installing..." +sh "$SYSTEM_PATH/$PLATFORM/bin/governor.sh" performance 2>/dev/null || true +systemctl stop NetworkManager 2>/dev/null || true +killall brightCtrl.bin cexpert 2>/dev/null || true + +for pakz in $PAKZ_PATH; do + if [ ! -e "$pakz" ]; then continue; fi + echo "TEXT:Extracting $pakz" > /tmp/show2.fifo 2>/dev/null || true + log_install "extracting $pakz" + ./unzip -o -d "$SDCARD_PATH" "$pakz" >> "$INSTALL_LOG" 2>&1 + unzip_status=$? + log_install "extracting $pakz exited $unzip_status" + [ "$unzip_status" = "0" ] || exit "$unzip_status" + rm -f "$pakz" + + if [ -f "$SDCARD_PATH/post_install.sh" ]; then + echo "TEXT:Installing $pakz" > /tmp/show2.fifo 2>/dev/null || true + log_install "running post_install.sh for $pakz" + sh "$SDCARD_PATH/post_install.sh" >> "$INSTALL_LOG" 2>&1 + post_status=$? + log_install "post_install.sh exited $post_status" + [ "$post_status" = "0" ] || exit "$post_status" + rm -f "$SDCARD_PATH/post_install.sh" + fi +done + +if [ -f "$UPDATE_PATH" ]; then + if [ -d "$SYSTEM_PATH/$PLATFORM" ]; then + echo "TEXT:Updating NextUI" > /tmp/show2.fifo 2>/dev/null || true + else + echo "TEXT:Installing NextUI" > /tmp/show2.fifo 2>/dev/null || true + fi + + rm -rf "$SYSTEM_PATH/$PLATFORM/bin" + rm -rf "$SYSTEM_PATH/$PLATFORM/lib" + rm -rf "$SYSTEM_PATH/$PLATFORM/paks/MinUI.pak" + + log_install "extracting $UPDATE_PATH" + ./unzip -o "$UPDATE_PATH" -d "$SDCARD_PATH" >> "$INSTALL_LOG" 2>&1 + unzip_status=$? + log_install "extracting $UPDATE_PATH exited $unzip_status" + [ "$unzip_status" = "0" ] || exit "$unzip_status" + rm -f "$UPDATE_PATH" +fi + +if [ -x "$SYSTEM_PATH/$PLATFORM/bin/install.sh" ]; then + log_install "running platform install.sh" + "$SYSTEM_PATH/$PLATFORM/bin/install.sh" >> "$INSTALL_LOG" 2>&1 + install_status=$? + log_install "platform install.sh exited $install_status" + [ "$install_status" = "0" ] || exit "$install_status" +fi + +LAUNCH_PATH="$SYSTEM_PATH/$PLATFORM/paks/MinUI.pak/launch.sh" +if [ -x "$LAUNCH_PATH" ]; then + log_install "exec $LAUNCH_PATH" + exec "$LAUNCH_PATH" +fi + +log_install "missing launch path; powering off" +poweroff diff --git a/workspace/h700/install/logo.png b/workspace/h700/install/logo.png new file mode 100644 index 000000000..d19816bb3 Binary files /dev/null and b/workspace/h700/install/logo.png differ diff --git a/workspace/h700/install/update.sh b/workspace/h700/install/update.sh new file mode 100755 index 000000000..46cc35c18 --- /dev/null +++ b/workspace/h700/install/update.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +SDCARD_PATH="/mnt/SDCARD" +REAL_SDCARD_PATH="/mnt/sdcard" +SYSTEM_PATH="$SDCARD_PATH/.system/h700" +TF1_DMENU="/mnt/mmc/dmenu.bin" +TF2_DMENU="$SYSTEM_PATH/dat/dmenu.bin" + +if ! mountpoint -q "$SDCARD_PATH" && [ ! -L "$SDCARD_PATH" ]; then + if [ -e "$SDCARD_PATH" ]; then + mount --bind "$REAL_SDCARD_PATH" "$SDCARD_PATH" 2>/dev/null || true + else + ln -s "$REAL_SDCARD_PATH" "$SDCARD_PATH" 2>/dev/null || true + fi +fi + +mkdir -p "$SYSTEM_PATH/dat" + +if [ -f "$TF2_DMENU" ] && mountpoint -q /mnt/mmc; then + if ! cmp -s "$TF2_DMENU" "$TF1_DMENU" 2>/dev/null; then + cp "$TF2_DMENU" "$TF1_DMENU" 2>/dev/null || true + sync + fi +fi + +exit 0 diff --git a/workspace/h700/keymon/credits.txt b/workspace/h700/keymon/credits.txt new file mode 100644 index 000000000..e885e5dd1 --- /dev/null +++ b/workspace/h700/keymon/credits.txt @@ -0,0 +1,3 @@ +based on eggs custom keymon for Trimui: + https://www.dropbox.com/sh/5e9xwvp672vt8cr/AABUIdw1vLYp9h0waoCUqHPOa/source?dl=0&subfolder_nav_tracking=1 +modified to use libmsettings \ No newline at end of file diff --git a/workspace/h700/keymon/keymon.c b/workspace/h700/keymon/keymon.c new file mode 100644 index 000000000..ff50de9a9 --- /dev/null +++ b/workspace/h700/keymon/keymon.c @@ -0,0 +1,173 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define VOLUME_MIN 0 +#define VOLUME_MAX 20 +#define BRIGHTNESS_MIN 0 +#define BRIGHTNESS_MAX 10 +#define COLORTEMP_MIN 0 +#define COLORTEMP_MAX 40 + +#define CODE_MENU 312 +#define CODE_MENU_ALT 354 +#define CODE_SELECT 310 +#define CODE_PLUS 115 +#define CODE_MINUS 114 + +#define RELEASED 0 +#define PRESSED 1 +#define REPEAT 2 + +#define INPUT_COUNT 3 + +static int inputs[INPUT_COUNT] = {}; +static volatile int quit = 0; + +static void on_term(int sig) { + (void)sig; + quit = 1; +} + +static uint32_t now_ms(void) { + struct timeval tod; + gettimeofday(&tod, NULL); + return tod.tv_sec * 1000 + tod.tv_usec / 1000; +} + +static void adjust_up(int menu_pressed, int select_pressed) { + uint32_t val; + + if (menu_pressed) { + val = GetBrightness(); + if (val < BRIGHTNESS_MAX) SetBrightness(++val); + } + else if (select_pressed) { + val = GetColortemp(); + if (val < COLORTEMP_MAX) SetColortemp(++val); + } + else { + val = GetVolume(); + if (val < VOLUME_MAX) SetVolume(++val); + } +} + +static void adjust_down(int menu_pressed, int select_pressed) { + uint32_t val; + + if (menu_pressed) { + val = GetBrightness(); + if (val > BRIGHTNESS_MIN) SetBrightness(--val); + } + else if (select_pressed) { + val = GetColortemp(); + if (val > COLORTEMP_MIN) SetColortemp(--val); + } + else { + val = GetVolume(); + if (val > VOLUME_MIN) SetVolume(--val); + } +} + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + + struct sigaction sa = {0}; + sa.sa_handler = on_term; + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + + InitSettings(); + + char path[32]; + for (int i = 0; i < INPUT_COUNT; i++) { + snprintf(path, sizeof(path), "/dev/input/event%i", i); + inputs[i] = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + } + + struct input_event ev; + uint32_t then = now_ms(); + uint32_t up_repeat_at = 0; + uint32_t down_repeat_at = 0; + int menu_pressed = 0; + int select_pressed = 0; + int up_pressed = 0; + int up_just_pressed = 0; + int down_pressed = 0; + int down_just_pressed = 0; + + while (!quit) { + uint32_t now = now_ms(); + int ignore = (now - then) > 1000; + + for (int i = 0; i < INPUT_COUNT; i++) { + if (inputs[i] < 0) continue; + + while (read(inputs[i], &ev, sizeof(ev)) == sizeof(ev)) { + if (ignore) continue; + if (ev.type != EV_KEY || ev.value > REPEAT) continue; + + switch (ev.code) { + case CODE_MENU: + // Only the real MENU code (312) tracks the physical button. + // CODE_MENU_ALT (354/KEY_GOTO) is a synthetic post-tap pulse + // (see platform.c) and must not be treated as MENU held, or a + // stray tap could momentarily divert vol +/- to brightness. + menu_pressed = ev.value; + break; + case CODE_SELECT: + select_pressed = ev.value; + break; + case CODE_PLUS: + up_pressed = up_just_pressed = ev.value; + if (ev.value) up_repeat_at = now + 300; + break; + case CODE_MINUS: + down_pressed = down_just_pressed = ev.value; + if (ev.value) down_repeat_at = now + 300; + break; + default: + break; + } + } + } + + if (ignore) { + menu_pressed = 0; + select_pressed = 0; + up_pressed = up_just_pressed = 0; + down_pressed = down_just_pressed = 0; + up_repeat_at = 0; + down_repeat_at = 0; + } + + if (up_just_pressed || (up_pressed && now >= up_repeat_at)) { + adjust_up(menu_pressed, select_pressed); + if (up_just_pressed) up_just_pressed = 0; + else up_repeat_at += 100; + } + + if (down_just_pressed || (down_pressed && now >= down_repeat_at)) { + adjust_down(menu_pressed, select_pressed); + if (down_just_pressed) down_just_pressed = 0; + else down_repeat_at += 100; + } + + then = now; + usleep(16666); + } + + for (int i = 0; i < INPUT_COUNT; i++) + if (inputs[i] >= 0) close(inputs[i]); + + QuitSettings(); + return 0; +} diff --git a/workspace/h700/keymon/makefile b/workspace/h700/keymon/makefile new file mode 100755 index 000000000..c2752ebd2 --- /dev/null +++ b/workspace/h700/keymon/makefile @@ -0,0 +1,22 @@ +ifeq (,$(CROSS_COMPILE)) +$(error missing CROSS_COMPILE for this toolchain) +endif + +ifeq (,$(PLATFORM)) +PLATFORM=$(UNION_PLATFORM) +endif + +TARGET = keymon +PRODUCT = $(TARGET).elf + +CC = $(CROSS_COMPILE)gcc +CFLAGS = -Os -lmsettings -lpthread -lrt -ldl -Wl,--gc-sections -s +CFLAGS += -I. -I../../all/common -I../platform/ -I$(PREFIX_LOCAL)/include -L$(PREFIX_LOCAL)/lib -DPLATFORM=\"$(UNION_PLATFORM)\" + +all: $(PREFIX)/include/msettings.h + $(CC) $(TARGET).c -o $(PRODUCT) $(CFLAGS) +clean: + rm -rf $(PRODUCT) + +$(PREFIX)/include/msettings.h: + cd /root/workspace/$(PLATFORM)/libmsettings && make diff --git a/workspace/h700/libmsettings/makefile b/workspace/h700/libmsettings/makefile new file mode 100644 index 000000000..e666406ff --- /dev/null +++ b/workspace/h700/libmsettings/makefile @@ -0,0 +1,33 @@ +ifeq (,$(CROSS_COMPILE)) +$(error missing CROSS_COMPILE for this toolchain) +endif +ifeq (,$(PREFIX)) +$(error missing PREFIX for this toolchain) +endif + +TARGET=msettings + +.PHONY: build +.PHONY: clean + +CC = $(CROSS_COMPILE)gcc + +CFLAGS = -I../../all/common +LDFLAGS = -ltinyalsa -ldl -lrt -lm -s + +OPTM=-Ofast + +build: + $(CC) -c -Werror -fpic "$(TARGET).c" $(CFLAGS) -Wl,--no-as-needed $(LDFLAGS) + $(CC) -c -Werror -fpic "../../all/common/displaycal.c" $(CFLAGS) -Wl,--no-as-needed $(LDFLAGS) + $(CC) -shared -o "lib$(TARGET).so" "$(TARGET).o" "displaycal.o" $(LDFLAGS) + mkdir -p "$(PREFIX_LOCAL)/include" + mkdir -p "$(PREFIX_LOCAL)/lib" + cp "$(TARGET).h" "$(PREFIX_LOCAL)/include" + cp "lib$(TARGET).so" "$(PREFIX_LOCAL)/lib" + +clean: + rm -f *.o + rm -f "lib$(TARGET).so" + rm -f $(PREFIX_LOCAL)/include/$(TARGET).h + rm -f $(PREFIX_LOCAL)/lib/lib$(TARGET).so diff --git a/workspace/h700/libmsettings/msettings.c b/workspace/h700/libmsettings/msettings.c new file mode 100644 index 000000000..a55a7b42e --- /dev/null +++ b/workspace/h700/libmsettings/msettings.c @@ -0,0 +1,1576 @@ +// h700 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "displaycal.h" +#include "msettings.h" +#include "sunxi_display2_min.h" + +/////////////////////////////////////// + +// Legacy MinUI settings +typedef struct SettingsV3 { + int version; // future proofing + int brightness; + int headphones; + int speaker; + int mute; + int unused[2]; + int jack; +} SettingsV3; + +// First NextUI settings format +typedef struct SettingsV4 { + int version; // future proofing + int brightness; + int colortemperature; // 0-20 + int headphones; + int speaker; + int mute; + int unused[2]; + int jack; +} SettingsV4; + +// Second NextUI settings format +typedef struct SettingsV5 { + int version; // future proofing + int brightness; + int colortemperature; + int headphones; + int speaker; + int mute; + int unused[2]; // for future use + // NOTE: doesn't really need to be persisted but still needs to be shared + int jack; +} SettingsV5; + +// Third NextUI settings format +typedef struct SettingsV6 { + int version; // future proofing + int brightness; + int colortemperature; + int headphones; + int speaker; + int mute; + int contrast; + int saturation; + int exposure; + int unused[2]; // for future use + // NOTE: doesn't really need to be persisted but still needs to be shared + int jack; +} SettingsV6; + +typedef struct SettingsV7 { + int version; // future proofing + int brightness; + int colortemperature; + int headphones; + int speaker; + int mute; + int contrast; + int saturation; + int exposure; + int mutedbrightness; + int mutedcolortemperature; + int mutedcontrast; + int mutedsaturation; + int mutedexposure; + int unused[2]; // for future use + // NOTE: doesn't really need to be persisted but still needs to be shared + int jack; +} SettingsV7; + +typedef struct SettingsV8 { + int version; // future proofing + int brightness; + int colortemperature; + int headphones; + int speaker; + int mute; + int contrast; + int saturation; + int exposure; + int toggled_brightness; + int toggled_colortemperature; + int toggled_contrast; + int toggled_saturation; + int toggled_exposure; + int toggled_volume; + int unused[2]; // for future use + // NOTE: doesn't really need to be persisted but still needs to be shared + int jack; +} SettingsV8; + +typedef struct SettingsV9 { + int version; // future proofing + int brightness; + int colortemperature; + int headphones; + int speaker; + int mute; + int contrast; + int saturation; + int exposure; + int toggled_brightness; + int toggled_colortemperature; + int toggled_contrast; + int toggled_saturation; + int toggled_exposure; + int toggled_volume; + int disable_dpad_on_mute; + int emulate_joystick_on_mute; + int turbo_a; + int turbo_b; + int turbo_x; + int turbo_y; + int turbo_l1; + int turbo_l2; + int turbo_r1; + int turbo_r2; + int unused[2]; // for future use + // NOTE: doesn't really need to be persisted but still needs to be shared + int jack; +} SettingsV9; + +typedef struct SettingsV10 { + int version; // future proofing + int brightness; + int colortemperature; + int headphones; + int speaker; + int mute; + int contrast; + int saturation; + int exposure; + int toggled_brightness; + int toggled_colortemperature; + int toggled_contrast; + int toggled_saturation; + int toggled_exposure; + int toggled_volume; + int disable_dpad_on_mute; + int emulate_joystick_on_mute; + int turbo_a; + int turbo_b; + int turbo_x; + int turbo_y; + int turbo_l1; + int turbo_l2; + int turbo_r1; + int turbo_r2; + int unused[2]; // for future use + // NOTE: doesn't really need to be persisted but still needs to be shared + int jack; + int audiosink; // was bluetooth true/false before +} SettingsV10; + +typedef struct SettingsV11 { + int version; // future proofing + int brightness; + int colortemperature; + int headphones; + int speaker; + int mute; + int contrast; + int saturation; + int exposure; + int toggled_brightness; + int toggled_colortemperature; + int toggled_contrast; + int toggled_saturation; + int toggled_exposure; + int toggled_volume; + int disable_dpad_on_mute; + int emulate_joystick_on_mute; + int turbo_a; + int turbo_b; + int turbo_x; + int turbo_y; + int turbo_l1; + int turbo_l2; + int turbo_r1; + int turbo_r2; + int unused[2]; // for future use + // NOTE: doesn't really need to be persisted but still needs to be shared + int jack; + int audiosink; // was bluetooth true/false before + int displaycal_enabled; + int displaycal_red_gain; + int displaycal_green_gain; + int displaycal_blue_gain; +} SettingsV11; + +// When incrementing SETTINGS_VERSION, update the Settings typedef and add +// backwards compatibility to InitSettings! +#define SETTINGS_VERSION 11 +typedef SettingsV11 Settings; +static Settings DefaultSettings = { + .version = SETTINGS_VERSION, + .brightness = SETTINGS_DEFAULT_BRIGHTNESS, + .colortemperature = SETTINGS_DEFAULT_COLORTEMP, + .headphones = SETTINGS_DEFAULT_HEADPHONE_VOLUME, + .speaker = SETTINGS_DEFAULT_VOLUME, + .mute = 0, + .contrast = SETTINGS_DEFAULT_CONTRAST, + .saturation = SETTINGS_DEFAULT_SATURATION, + .exposure = SETTINGS_DEFAULT_EXPOSURE, + .toggled_brightness = SETTINGS_DEFAULT_MUTE_NO_CHANGE, + .toggled_colortemperature = SETTINGS_DEFAULT_MUTE_NO_CHANGE, + .toggled_contrast = SETTINGS_DEFAULT_MUTE_NO_CHANGE, + .toggled_saturation = SETTINGS_DEFAULT_MUTE_NO_CHANGE, + .toggled_exposure = SETTINGS_DEFAULT_MUTE_NO_CHANGE, + .toggled_volume = 0, // mute is default + .disable_dpad_on_mute = 0, + .emulate_joystick_on_mute = 0, + .turbo_a = 0, + .turbo_b = 0, + .turbo_x = 0, + .turbo_y = 0, + .turbo_l1 = 0, + .turbo_l2 = 0, + .turbo_r1 = 0, + .turbo_r2 = 0, + .jack = 0, + .audiosink = AUDIO_SINK_DEFAULT, + .displaycal_enabled = DISPLAYCAL_DEFAULT_ENABLED, + .displaycal_red_gain = DISPLAYCAL_DEFAULT_RED_GAIN, + .displaycal_green_gain = DISPLAYCAL_DEFAULT_GREEN_GAIN, + .displaycal_blue_gain = DISPLAYCAL_DEFAULT_BLUE_GAIN, +}; +static Settings* settings; + +#define SHM_KEY "/SharedSettings" +static char SettingsPath[256]; +static int shm_fd = -1; +static int is_host = 0; +static int shm_size = sizeof(Settings); + +int scaleBrightness(int); +int scaleColortemp(int); +int scaleContrast(int); +int scaleSaturation(int); +int scaleExposure(int); +int scaleVolume(int); + +void disableDpad(int); +void emulateJoystick(int); +void turboA(int); +void turboB(int); +void turboX(int); +void turboY(int); +void turboL1(int); +void turboL2(int); +void turboR1(int); +void turboR2(int); + +int getInt(char* path) { + int i = 0; + FILE *file = fopen(path, "r"); + if (file!=NULL) { + fscanf(file, "%i", &i); + fclose(file); + } + return i; +} +void putFile(char* path, char* contents) { + FILE* file = fopen(path, "w"); + if (file) { + fputs(contents, file); + fclose(file); + } +} +void putInt(char* path, int value) { + char buffer[8]; + sprintf(buffer, "%d", value); + putFile(path, buffer); +} + +void touch(char* path) { + close(open(path, O_RDWR|O_CREAT, 0777)); +} +int exactMatch(char* str1, char* str2) { + if (!str1 || !str2) return 0; // NULL isn't safe here + int len1 = strlen(str1); + if (len1!=strlen(str2)) return 0; + return (strncmp(str1,str2,len1)==0); +} + +int peekVersion(const char *filename) { + int version = 0; + FILE *file = fopen(filename, "r"); + if (file) { + fread(&version, sizeof(int), 1, file); + fclose(file); + } + return version; +} + +static int prefixMatch(char* pre, char* str) { + if (!pre || !str) return 0; + return (strncmp(pre, str, strlen(pre))==0); +} + +// Displaycal defaults for this DEVICE. Measured panels keep their gains; +// everything else stays uncalibrated (off + 100/100/100). +static enum DisplayCalPreset displayCalPresetForDevice(void) { + char* device = getenv("DEVICE"); + + if (exactMatch("rg28xx", device)) return DISPLAYCAL_PRESET_RG28XX; + if (exactMatch("rgsp", device)) return DISPLAYCAL_PRESET_RGSP; + if (exactMatch("rg34xxsp", device)) return DISPLAYCAL_PRESET_RG34XXSP; + if (exactMatch("rg34xx", device)) return DISPLAYCAL_PRESET_RG34XX; + if (exactMatch("rg40xxv", device)) return DISPLAYCAL_PRESET_RG40XXV; + if (exactMatch("rg40xxh", device)) return DISPLAYCAL_PRESET_RG40XXH; + if (exactMatch("rgcubexx", device)) return DISPLAYCAL_PRESET_RGCUBEXX; + if (exactMatch("rg35xxsp", device)) return DISPLAYCAL_PRESET_RG35XXSP; + if (exactMatch("rg35xxpro", device)) return DISPLAYCAL_PRESET_RG35XXPRO; + if (exactMatch("rg35xxh", device)) return DISPLAYCAL_PRESET_RG35XXH; + if (exactMatch("rg35xxplus", device)) return DISPLAYCAL_PRESET_RG35XXPLUS; + return DISPLAYCAL_PRESET_DEFAULT; +} + +static void applyDisplayCalDefaultsForDevice(Settings *target) { + DisplayCalDefaults defaults = DisplayCal_getDefaultSettings(displayCalPresetForDevice()); + target->displaycal_enabled = defaults.enabled; + target->displaycal_red_gain = defaults.red_gain; + target->displaycal_green_gain = defaults.green_gain; + target->displaycal_blue_gain = defaults.blue_gain; +} + +void InitSettings(void) { + int seed_displaycal = 0; + sprintf(SettingsPath, "%s/msettings.bin", getenv("USERDATA_PATH")); + + shm_fd = shm_open(SHM_KEY, O_RDWR | O_CREAT | O_EXCL, 0644); // see if it exists + if (shm_fd==-1 && errno==EEXIST) { // already exists + // puts("Settings client"); + shm_fd = shm_open(SHM_KEY, O_RDWR, 0644); + settings = mmap(NULL, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); + } + else { // host + // puts("Settings host"); // keymon + is_host = 1; + // we created it so set initial size and populate + ftruncate(shm_fd, shm_size); + settings = mmap(NULL, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); + + // peek the first int from fd, it's the version + int version = peekVersion(SettingsPath); + if(version > 0) { + int fd = open(SettingsPath, O_RDONLY); + if (fd>=0) { + if (version == SETTINGS_VERSION) { + read(fd, settings, shm_size); + } + else { + // initialize with defaults + memcpy(settings, &DefaultSettings, shm_size); + // no displaycal fields before v11, seed device defaults + seed_displaycal = 1; + + // overwrite with migrated data + if(version==10) { + printf("Found settings v10.\n"); + SettingsV10 old; + read(fd, &old, sizeof(SettingsV10)); + + memcpy(settings, &old, sizeof(SettingsV10)); + settings->version = SETTINGS_VERSION; + } + else if(version==9) { + printf("Found settings v9.\n"); + SettingsV9 old; + read(fd, &old, sizeof(SettingsV9)); + + settings-> disable_dpad_on_mute = old.disable_dpad_on_mute; + settings-> emulate_joystick_on_mute = old.emulate_joystick_on_mute; + settings-> turbo_a = old.turbo_a; + settings-> turbo_b = old.turbo_b; + settings-> turbo_x = old.turbo_x; + settings-> turbo_y = old.turbo_y; + settings-> turbo_l1 = old.turbo_l1; + settings-> turbo_l2 = old.turbo_l2; + settings-> turbo_r1 = old.turbo_r1; + settings-> turbo_r2 = old.turbo_r2; + + settings->toggled_volume = old.toggled_volume; + + settings->toggled_brightness = old.toggled_brightness; + settings->toggled_colortemperature = old.toggled_colortemperature; + settings->toggled_contrast = old.toggled_contrast; + settings->toggled_exposure = old.toggled_exposure; + settings->toggled_saturation = old.toggled_saturation; + + settings->saturation = old.saturation; + settings->contrast = old.contrast; + settings->exposure = old.exposure; + + settings->colortemperature = old.colortemperature; + + settings->brightness = old.brightness; + settings->headphones = old.headphones; + settings->speaker = old.speaker; + settings->mute = old.mute; + settings->jack = old.jack; + } + else if(version==8) { + printf("Found settings v8.\n"); + SettingsV8 old; + read(fd, &old, sizeof(SettingsV8)); + + settings->toggled_volume = old.toggled_volume; + + settings->toggled_brightness = old.toggled_brightness; + settings->toggled_colortemperature = old.toggled_colortemperature; + settings->toggled_contrast = old.toggled_contrast; + settings->toggled_exposure = old.toggled_exposure; + settings->toggled_saturation = old.toggled_saturation; + + settings->saturation = old.saturation; + settings->contrast = old.contrast; + settings->exposure = old.exposure; + + settings->colortemperature = old.colortemperature; + + settings->brightness = old.brightness; + settings->headphones = old.headphones; + settings->speaker = old.speaker; + settings->mute = old.mute; + settings->jack = old.jack; + } + else if(version==7) { + printf("Found settings v7.\n"); + SettingsV7 old; + read(fd, &old, sizeof(SettingsV7)); + + // muted* -> toggled* + settings->toggled_brightness = old.mutedbrightness; + settings->toggled_colortemperature = old.mutedcolortemperature; + settings->toggled_contrast = old.mutedcontrast; + settings->toggled_exposure = old.mutedexposure; + settings->toggled_saturation = old.mutedsaturation; + + settings->saturation = old.saturation; + settings->contrast = old.contrast; + settings->exposure = old.exposure; + + settings->colortemperature = old.colortemperature; + + settings->brightness = old.brightness; + settings->headphones = old.headphones; + settings->speaker = old.speaker; + settings->mute = old.mute; + settings->jack = old.jack; + } + else if(version==6) { + printf("Found settings v6.\n"); + SettingsV6 old; + read(fd, &old, sizeof(SettingsV6)); + + settings->saturation = old.saturation; + settings->contrast = old.contrast; + settings->exposure = old.exposure; + + settings->colortemperature = old.colortemperature; + + settings->brightness = old.brightness; + settings->headphones = old.headphones; + settings->speaker = old.speaker; + settings->mute = old.mute; + settings->jack = old.jack; + } + else if(version==5) { + printf("Found settings v5.\n"); + SettingsV5 old; + read(fd, &old, sizeof(SettingsV5)); + + settings->colortemperature = old.colortemperature; + + settings->brightness = old.brightness; + settings->headphones = old.headphones; + settings->speaker = old.speaker; + settings->mute = old.mute; + settings->jack = old.jack; + } + else if(version==4) { + printf("Found settings v4.\n"); + SettingsV4 old; + read(fd, &old, sizeof(SettingsV4)); + + // colortemp was 0-20 here + settings->colortemperature = old.colortemperature * 2; + + settings->brightness = old.brightness; + settings->headphones = old.headphones; + settings->speaker = old.speaker; + settings->mute = old.mute; + settings->jack = old.jack; + } + else if(version==3) { + printf("Found settings v3.\n"); + SettingsV3 old; + read(fd, &old, sizeof(SettingsV3)); + + settings->brightness = old.brightness; + settings->headphones = old.headphones; + settings->speaker = old.speaker; + settings->mute = old.mute; + settings->jack = old.jack; + } + else { + printf("Found unsupported settings version: %i.\n", version); + } + } + + close(fd); + } + else { + // load defaults + memcpy(settings, &DefaultSettings, shm_size); + seed_displaycal = 1; + } + } + else { + // load defaults + memcpy(settings, &DefaultSettings, shm_size); + seed_displaycal = 1; + } + + // these shouldn't be persisted + // settings->jack = 0; + settings->mute = 0; + } + // printf("brightness: %i\nspeaker: %i \n", settings->brightness, settings->speaker); + // Make sure the H700 codec is routed to speaker/lineout before NextUI owns volume. + if(GetAudioSink() == AUDIO_SINK_DEFAULT) { + system("amixer -q sset 'SPK' on >/dev/null 2>&1"); + system("amixer -q sset 'LINEOUT' on >/dev/null 2>&1"); + system("amixer -q sset 'OutputL Mixer DACL' on >/dev/null 2>&1"); + system("amixer -q sset 'OutputR Mixer DACR' on >/dev/null 2>&1"); + } + + // only the host seeds displaycal defaults, and only when the persisted + // settings predate them — a clean current-version load keeps user values + if (is_host && seed_displaycal) applyDisplayCalDefaultsForDevice(settings); + + // This will implicitly update all other settings based on FN switch state + SetMute(settings->mute); +} +int InitializedSettings(void) { + return (settings != NULL); +} +void QuitSettings(void) { + munmap(settings, shm_size); + if (is_host) shm_unlink(SHM_KEY); +} +static inline void SaveSettings(void) { + int fd = open(SettingsPath, O_CREAT|O_WRONLY, 0644); + if (fd>=0) { + write(fd, settings, shm_size); + close(fd); + sync(); + } +} + +static inline void applyDisplayCalSettings(void) { + if (settings->displaycal_enabled) + SetRawDisplayCal(1, settings->displaycal_red_gain, settings->displaycal_green_gain, settings->displaycal_blue_gain); +} + +///////// Getters exposed in public API + +int GetBrightness(void) { // 0-10 + if (settings->mute && GetMutedBrightness() != SETTINGS_DEFAULT_MUTE_NO_CHANGE) + return GetMutedBrightness(); + + return settings->brightness; +} +int GetColortemp(void) { // 0-10 + if (settings->mute && GetMutedColortemp() != SETTINGS_DEFAULT_MUTE_NO_CHANGE) + return GetMutedColortemp(); + + return settings->colortemperature; +} +int GetVolume(void) { // 0-20 + if (settings->mute && GetMutedVolume() != SETTINGS_DEFAULT_MUTE_NO_CHANGE) + return GetMutedVolume(); + + if(settings->jack || settings->audiosink != AUDIO_SINK_DEFAULT) + return settings->headphones; + + return settings->speaker; +} +int GetContrast(void) +{ + if (settings->mute && GetMutedContrast() != SETTINGS_DEFAULT_MUTE_NO_CHANGE) + return GetMutedContrast(); + + return settings->contrast; +} +int GetSaturation(void) +{ + if (settings->mute && GetMutedSaturation() != SETTINGS_DEFAULT_MUTE_NO_CHANGE) + return GetMutedSaturation(); + + return settings->saturation; +} +int GetExposure(void) +{ + if (settings->mute && GetMutedExposure() != SETTINGS_DEFAULT_MUTE_NO_CHANGE) + return GetMutedExposure(); + + return settings->exposure; +} +int GetDisplayCalEnabled(void) +{ + return settings->displaycal_enabled; +} +int GetDisplayCalRedGain(void) +{ + return settings->displaycal_red_gain; +} +int GetDisplayCalGreenGain(void) +{ + return settings->displaycal_green_gain; +} +int GetDisplayCalBlueGain(void) +{ + return settings->displaycal_blue_gain; +} +// monitored and set by thread in keymon +int GetJack(void) { + return settings->jack; +} +// monitored and set by thread in audiomon +int GetAudioSink(void) { + return settings->audiosink; +} + +int GetHDMI(void) { + if (getInt("/sys/class/extcon/hdmi/state") > 0) + return 1; + if (getInt("/sys/class/extcon/hdmi/cable.0/state") > 0) + return 1; + if (getInt("/sys/class/extcon/hdmi/cable.1/state") > 0) + return 1; + return 0; +}; + +int GetMute(void) { + return settings->mute; +} +int GetMutedBrightness(void) +{ + return settings->toggled_brightness; +} +int GetMutedColortemp(void) +{ + return settings->toggled_colortemperature; +} +int GetMutedContrast(void) +{ + return settings->toggled_contrast; +} +int GetMutedSaturation(void) +{ + return settings->toggled_saturation; +} +int GetMutedExposure(void) +{ + return settings->toggled_exposure; +} +int GetMutedVolume(void) +{ + return settings->toggled_volume; +} +int GetMuteDisablesDpad(void) +{ + return settings->disable_dpad_on_mute; +} +int GetMuteEmulatesJoystick(void) +{ + return settings->emulate_joystick_on_mute; +} +int GetMuteTurboA(void) +{ + return settings->turbo_a; +} +int GetMuteTurboB(void) +{ + return settings->turbo_b; +} +int GetMuteTurboX(void) +{ + return settings->turbo_x; +} +int GetMuteTurboY(void) +{ + return settings->turbo_y; +} +int GetMuteTurboL1(void) +{ + return settings->turbo_l1; +} +int GetMuteTurboL2(void) +{ + return settings->turbo_l2; +} +int GetMuteTurboR1(void) +{ + return settings->turbo_r1; +} +int GetMuteTurboR2(void) +{ + return settings->turbo_r2; +} + +///////// Setters exposed in public API + +void SetBrightness(int value) { + if (settings->mute && GetMutedBrightness() != SETTINGS_DEFAULT_MUTE_NO_CHANGE) + return SetRawBrightness(scaleBrightness(GetMutedBrightness())); + + SetRawBrightness(scaleBrightness(value)); + settings->brightness = value; + SaveSettings(); +} +void SetColortemp(int value) { + if (settings->mute && GetMutedColortemp() != SETTINGS_DEFAULT_MUTE_NO_CHANGE) + return SetRawColortemp(scaleColortemp(GetMutedColortemp())); + + SetRawColortemp(scaleColortemp(value)); + settings->colortemperature = value; + SaveSettings(); +} +void SetContrast(int value) { + if (settings->mute && GetMutedContrast() != SETTINGS_DEFAULT_MUTE_NO_CHANGE) + return SetRawContrast(scaleContrast(GetMutedContrast())); + + SetRawContrast(scaleContrast(value)); + settings->contrast = value; + SaveSettings(); +} +void SetSaturation(int value) { + if (settings->mute && GetMutedSaturation() != SETTINGS_DEFAULT_MUTE_NO_CHANGE) + return SetRawSaturation(scaleSaturation(GetMutedSaturation())); + + SetRawSaturation(scaleSaturation(value)); + settings->saturation = value; + SaveSettings(); +} +void SetExposure(int value){ + if (settings->mute && GetMutedExposure() != SETTINGS_DEFAULT_MUTE_NO_CHANGE) + return SetRawExposure(scaleExposure(GetMutedExposure())); + + SetRawExposure(scaleExposure(value)); + settings->exposure = value; + SaveSettings(); +} +void SetDisplayCalEnabled(int is_enabled) { + int was_enabled = settings->displaycal_enabled; + is_enabled = (is_enabled != 0); + settings->displaycal_enabled = is_enabled; + + // Disabling only needs hardware writes when we are turning an active LUT off. + if (is_enabled) + applyDisplayCalSettings(); + else if (was_enabled) + SetRawDisplayCal(0, settings->displaycal_red_gain, settings->displaycal_green_gain, settings->displaycal_blue_gain); + SaveSettings(); +} +void SetDisplayCalRedGain(int value) { + value = DisplayCal_clampGainValue(value); + settings->displaycal_red_gain = value; + applyDisplayCalSettings(); + SaveSettings(); +} +void SetDisplayCalGreenGain(int value) { + value = DisplayCal_clampGainValue(value); + settings->displaycal_green_gain = value; + applyDisplayCalSettings(); + SaveSettings(); +} +void SetDisplayCalBlueGain(int value) { + value = DisplayCal_clampGainValue(value); + settings->displaycal_blue_gain = value; + applyDisplayCalSettings(); + SaveSettings(); +} +void SetVolume(int value) // 0-20 +{ + if (settings->mute && GetMutedVolume() != SETTINGS_DEFAULT_MUTE_NO_CHANGE) + return SetRawVolume(scaleVolume(GetMutedVolume())); + + SetRawVolume(scaleVolume(value)); + if (settings->jack || settings->audiosink != AUDIO_SINK_DEFAULT) + settings->headphones = value; + else + settings->speaker = value; + SaveSettings(); +} +// monitored and set by thread in keymon +void SetJack(int value) { + settings->jack = value; + SetVolume(GetVolume()); +} +// monitored and set by thread in audiomon +void SetAudioSink(int value) { + settings->audiosink = value; + SetVolume(GetVolume()); +} + +// HDMI output switching (sunxi disp2, kernel 4.9 BSP). The dispdbg debugfs +// interface flips disp0 between the LCD and the HDMI TX; the framebuffer is +// then resized so the mali EGL winsys (which latches fb0 geometry at video +// init) comes up at the matching resolution on the next app start. Sequence +// and parameters replicate the old rg35xxplus port's hdmimon.sh (proven on +// this hardware family): HDMI is a 1080p60 signal fed by a 1280x720 fb that +// the display engine hardware-scales up. Callers are expected to restart the +// UI afterwards; the switch itself must run while no EGL surface exists. + +#define DISPDBG_PATH "/sys/kernel/debug/dispdbg" +#define FB_BLANK_PATH "/sys/class/graphics/fb0/blank" +// must match HDMI_WIDTH/HDMI_HEIGHT in platform.h +#define HDMI_LOGICAL_WIDTH 1280 +#define HDMI_LOGICAL_HEIGHT 720 +// dispdbg switch params: " ..." — type 4=HDMI, mode 10=1080p60; type 1=LCD +#define DISP_SWITCH_HDMI_PARAM "4 10 0 0 0x4 0x101 0 0 0 8" +#define DISP_SWITCH_LCD_PARAM "1 0" +#define ASOUNDRC_HDMI_MARKER "# nextui-hdmi" + +static void panelSize(int* w, int* h) { + char* device = getenv("DEVICE"); + *w = 640; *h = 480; + if (exactMatch("rgcubexx", device)) { *w = 720; *h = 720; } + else if (exactMatch("rg34xx", device) || exactMatch("rg34xxsp", device) + || exactMatch("rgsp", device)) { *w = 720; *h = 480; } + else if (exactMatch("rg28xx", device)) { *w = 480; *h = 640; } // physical portrait panel +} + +// the live output type, read back from the disp driver so a stale state file +// can never desync us from the hardware +static int hdmiOutputActive(void) { + char buffer[4096] = {0}; + FILE* file = fopen("/sys/class/disp/disp/attr/sys", "r"); + if (!file) return 0; + size_t len = fread(buffer, 1, sizeof(buffer)-1, file); + fclose(file); + buffer[len] = '\0'; + return strstr(buffer, "hdmi output") != NULL; +} + +// The dispdbg switch is asynchronous and slow — the LCD panel init sequence +// alone takes ~700ms ("attached ok" in dmesg). The fb geometry set below is +// what rebuilds the DE layer against the new output, so it must not run until +// the attach has completed or the rebuild is computed against the old output +// and the panel shows a stale (blank) layer. +static void waitForOutput(int hdmi) { + for (int i = 0; i < 60; i++) { // up to 3s + if (hdmiOutputActive() == hdmi) break; + usleep(50000); + } + usleep(150000); // settle margin after the attach shows up in sysfs +} + +static void dispdbgSwitch(char* param) { + putFile(DISPDBG_PATH "/name", "disp0"); + putFile(DISPDBG_PATH "/command", "switch"); + putFile(DISPDBG_PATH "/param", param); + putFile(DISPDBG_PATH "/start", "1"); +} + +static void clearFramebuffer(void) { + int fd = open("/dev/fb0", O_WRONLY); + if (fd < 0) return; + char zeros[4096] = {0}; + while (write(fd, zeros, sizeof(zeros)) > 0); + close(fd); +} + +static void setFramebufferSize(int w, int h) { + int fd = open("/dev/fb0", O_RDWR); + if (fd < 0) return; + struct fb_var_screeninfo vinfo; + if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == 0) { + // zero geometry first ("fbset -g 0 0 0 0 32" in the old port) so the + // driver drops the old allocation before sizing the new one + vinfo.xres = vinfo.yres = vinfo.xres_virtual = vinfo.yres_virtual = 0; + vinfo.bits_per_pixel = 32; + ioctl(fd, FBIOPUT_VSCREENINFO, &vinfo); // failure is fine, best effort + usleep(250000); + vinfo.xres = w; + vinfo.yres = h; + vinfo.xres_virtual = w; + vinfo.yres_virtual = h * 2; // double buffered + // The pan offset survives the resize: coming off the 640x480 panel it is + // still 480, which is not a page boundary of the new geometry. Left + // there it wedges the winsys — measured on RG40XXV, fb0 then never pans + // again and every frame lands in page 0. Reset it so the buffer starts + // on page 0 and the blob's flips work from a sane origin. + vinfo.xoffset = vinfo.yoffset = 0; + vinfo.bits_per_pixel = 32; + // FORCE so set_par runs (and rebuilds the DE layer for the new output) + // even when the geometry is unchanged + vinfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; + if (ioctl(fd, FBIOPUT_VSCREENINFO, &vinfo) < 0) + fprintf(stderr, "SetHDMI: FBIOPUT_VSCREENINFO %dx%d failed: %s\n", w, h, strerror(errno)); + } + close(fd); +} + +// The fbdev glue in this BSP has no set_par hook: FBIOPUT only records the new +// var, and pan_display only rewrites the layer *crop* from it — the scanout +// layer's buffer dimensions and output window are never updated by any fbdev +// call. Left alone, whichever values the switch path last committed stay live +// (blank panel after unplug, page-offset ghosting after plug). So after every +// switch we read-modify-write the fb0 layer ourselves with the geometry that +// matches the new framebuffer and output; the blob's per-flip pans then keep +// the crop in sync against our committed config. +// The crop we commit must name page 0, matching the pan offset setFramebufferSize +// just reset. Naming page 1 was only ever right if a flip landed before the first +// scanout; when none does — which is what happens if the winsys is wedged, and +// what happened on BaseOS — the display shows a page nothing has written, i.e. +// black on both the TV and the panel. +// The switch path restores the previous mode's layer config on device attach, +// asynchronously and sometimes AFTER we've already written ours — whichever +// commit lands last wins. So: commit, read back, and retry until it sticks. +// (The app hasn't started yet when this runs, so there are no competing pans.) +static void commitLayerGeometry(int fbW, int fbH, int outW, int outH) { + int fd = open("/dev/disp", O_RDWR); + if (fd < 0) return; + struct disp_layer_config config; + unsigned long param[4] = {0, (unsigned long)&config, 1, 0}; + int applied = 0; + for (int attempt = 0; attempt < 20 && !applied; attempt++) { // up to ~2s + memset(&config, 0, sizeof(config)); + config.channel = 1; // fb0 is bound to channel 1, layer 0 (FBIO_ALLOC in dev_fb.c) + config.layer_id = 0; + if (ioctl(fd, DISP_LAYER_GET_CONFIG, param) < 0) { + fprintf(stderr, "SetHDMI: DISP_LAYER_GET_CONFIG failed: %s\n", strerror(errno)); + break; + } + config.enable = 1; + for (int i = 0; i < 3; i++) { + config.info.fb.size[i].width = fbW; + config.info.fb.size[i].height = fbH * 2; // whole double buffer + } + config.info.fb.crop.x = 0; + config.info.fb.crop.y = 0; // page 0 — see above + config.info.fb.crop.width = ((long long)fbW) << 32; + config.info.fb.crop.height = ((long long)fbH) << 32; + config.info.screen_win.x = 0; + config.info.screen_win.y = 0; + config.info.screen_win.width = outW; + config.info.screen_win.height = outH; + if (ioctl(fd, DISP_LAYER_SET_CONFIG, param) < 0) { + fprintf(stderr, "SetHDMI: DISP_LAYER_SET_CONFIG failed: %s\n", strerror(errno)); + break; + } + usleep(100000); // let the vsync apply run (and any late restore overwrite us) + memset(&config, 0, sizeof(config)); + config.channel = 1; + config.layer_id = 0; + if (ioctl(fd, DISP_LAYER_GET_CONFIG, param) < 0) + break; + applied = config.info.fb.size[0].width == (unsigned)fbW + && config.info.screen_win.width == (unsigned)outW + && config.info.fb.crop.y == 0; // a late restore can revive the old page offset + } + if (!applied) + fprintf(stderr, "SetHDMI: layer geometry %dx%d->%dx%d did not stick\n", fbW, fbH, outW, outH); + close(fd); +} + +// route ALSA "default" to the HDMI TX while connected; only ever touch an +// .asoundrc we wrote ourselves so audiomon's Bluetooth/USB routing wins +static void setHDMIAudioRoute(int on) { + char* home = getenv("USERDATA_PATH"); + if (!home) home = getenv("HOME"); + if (!home) return; + char path[512]; + snprintf(path, sizeof(path), "%s/.asoundrc", home); + + char buffer[64] = {0}; + FILE* file = fopen(path, "r"); + if (file) { + fread(buffer, 1, sizeof(buffer)-1, file); + fclose(file); + if (!prefixMatch(ASOUNDRC_HDMI_MARKER, buffer)) return; // not ours + } + + if (on) { + putFile(path, + ASOUNDRC_HDMI_MARKER "\n" + "pcm.!default {\n" + " type plug\n" + " slave.pcm {\n" + " type hw\n" + " card ahubhdmi\n" + " }\n" + "}\n" + "ctl.!default {\n" + " type hw\n" + " card ahubhdmi\n" + "}\n"); + } + else if (file) unlink(path); // only removes the file when it carried our marker +} + +void SetHDMI(int value) { + value = value ? 1 : 0; + if (hdmiOutputActive() == value) { + setHDMIAudioRoute(value); // keep audio routing consistent even when the output already matches + return; + } + + putFile(FB_BLANK_PATH, "4"); + clearFramebuffer(); + + dispdbgSwitch(value ? DISP_SWITCH_HDMI_PARAM : DISP_SWITCH_LCD_PARAM); + waitForOutput(value); + + // 1080p60 signal (mode 10): the DE scales the 720p fb up to it + int fbW = HDMI_LOGICAL_WIDTH, fbH = HDMI_LOGICAL_HEIGHT, outW = 1920, outH = 1080; + if (!value) { + panelSize(&fbW, &fbH); + outW = fbW; + outH = fbH; + } + setFramebufferSize(fbW, fbH); + commitLayerGeometry(fbW, fbH, outW, outH); + usleep(250000); + putFile(FB_BLANK_PATH, "0"); + commitLayerGeometry(fbW, fbH, outW, outH); // unblank can trigger another restore; re-verify + + // Re-enabling the LCD brings it up with whatever backlight/LUT state the + // driver has, and the usual apply happened while the panel was disabled + // (InitSettings runs before GFX_init/PLAT_initPlatform in nextui), so the + // panel stays dark unless we re-apply here, after the switch. + if (!value) { + if (settings) { + SetBrightness(GetBrightness()); + SetColortemp(GetColortemp()); + applyDisplayCalSettings(); + } + else { + // process hasn't mapped the settings shm yet (e.g. minarch races a + // cable change during startup); a visible panel beats a dark one, + // the correct value is re-applied on the next InitSettings + SetRawBrightness(96); + } + } + + setHDMIAudioRoute(value); +} + +void SetMute(int value) { + settings->mute = value; + + SetVolume(GetVolume()); + SetBrightness(GetBrightness()); + SetColortemp(GetColortemp()); + SetContrast(GetContrast()); + SetSaturation(GetSaturation()); + SetExposure(GetExposure()); + applyDisplayCalSettings(); + + if(GetMuteTurboA()) + turboA(settings->mute); + if(GetMuteTurboB()) + turboB(settings->mute); + if(GetMuteTurboX()) + turboX(settings->mute); + if(GetMuteTurboY()) + turboY(settings->mute); + if(GetMuteTurboL1()) + turboL1(settings->mute); + if(GetMuteTurboL2()) + turboL2(settings->mute); + if(GetMuteTurboR1()) + turboR1(settings->mute); + if(GetMuteTurboR2()) + turboR2(settings->mute); +} + +void SetMutedBrightness(int value) +{ + settings->toggled_brightness = value; + SaveSettings(); +} + +void SetMutedColortemp(int value) +{ + settings->toggled_colortemperature = value; + SaveSettings(); +} + +void SetMutedContrast(int value) +{ + settings->toggled_contrast = value; + SaveSettings(); +} + +void SetMutedSaturation(int value) +{ + settings->toggled_saturation = value; + SaveSettings(); +} + +void SetMutedExposure(int value) +{ + settings->toggled_exposure = value; + SaveSettings(); +} + +void SetMutedVolume(int value) +{ + settings->toggled_volume = value; + SaveSettings(); +} + +void SetMuteDisablesDpad(int value) +{ + settings->disable_dpad_on_mute = value; + SaveSettings(); +} +void SetMuteEmulatesJoystick(int value) +{ + settings->emulate_joystick_on_mute = value; + SaveSettings(); +} + +void SetMuteTurboA(int value) +{ + settings->turbo_a = value; + SaveSettings(); +} + +void SetMuteTurboB(int value) +{ + settings->turbo_b = value; + SaveSettings(); +} + +void SetMuteTurboX(int value) +{ + settings->turbo_x = value; + SaveSettings(); +} + +void SetMuteTurboY(int value) +{ + settings->turbo_y = value; + SaveSettings(); +} + +void SetMuteTurboL1(int value) +{ + settings->turbo_l1 = value; + SaveSettings(); +} + +void SetMuteTurboL2(int value) +{ + settings->turbo_l2 = value; + SaveSettings(); +} + +void SetMuteTurboR1(int value) +{ + settings->turbo_r1 = value; + SaveSettings(); +} + +void SetMuteTurboR2(int value) +{ + settings->turbo_r2 = value; + SaveSettings(); +} + +///////// H700 has no stock input daemon modifiers yet. + +void disableDpad(int value) { +} + +void emulateJoystick(int value) { +} + +void turboA(int value) { +} +void turboB(int value) { +} +void turboX(int value) { +} +void turboY(int value) { +} +void turboL1(int value) { +} +void turboL2(int value) { +} +void turboR1(int value) { +} +void turboR2(int value) { +} + +///////// Platform specific scaling + +int scaleVolume(int value) { + return value * 5; // scale 0-20 to 0-100 +} + +int scaleBrightness(int value) { + int raw; + switch (value) { + case 0: raw=4; break; + case 1: raw=6; break; + case 2: raw=10; break; + case 3: raw=16; break; + case 4: raw=32; break; + case 5: raw=48; break; + case 6: raw=64; break; + case 7: raw=96; break; + case 8: raw=128; break; + case 9: raw=192; break; + case 10: raw=255; break; + default: raw=64; break; + } + return raw; +} +int scaleColortemp(int value) { + int raw; + + switch (value) { + case 0: raw=-200; break; // 8 + case 1: raw=-190; break; // 8 + case 2: raw=-180; break; // 16 + case 3: raw=-170; break; // 16 + case 4: raw=-160; break; // 24 + case 5: raw=-150; break; // 24 + case 6: raw=-140; break; // 32 + case 7: raw=-130; break; // 32 + case 8: raw=-120; break; // 32 + case 9: raw=-110; break; // 64 + case 10: raw=-100; break; // 0 + case 11: raw=-90; break; // 8 + case 12: raw=-80; break; // 8 + case 13: raw=-70; break; // 16 + case 14: raw=-60; break; // 16 + case 15: raw=-50; break; // 24 + case 16: raw=-40; break; // 24 + case 17: raw=-30; break; // 32 + case 18: raw=-20; break; // 32 + case 19: raw=-10; break; // 32 + case 20: raw=0; break; // 64 + case 21: raw=10; break; // 0 + case 22: raw=20; break; // 8 + case 23: raw=30; break; // 8 + case 24: raw=40; break; // 16 + case 25: raw=50; break; // 16 + case 26: raw=60; break; // 24 + case 27: raw=70; break; // 24 + case 28: raw=80; break; // 32 + case 29: raw=90; break; // 32 + case 30: raw=100; break; // 32 + case 31: raw=110; break; // 64 + case 32: raw=120; break; // 0 + case 33: raw=130; break; // 8 + case 34: raw=140; break; // 8 + case 35: raw=150; break; // 16 + case 36: raw=160; break; // 16 + case 37: raw=170; break; // 24 + case 38: raw=180; break; // 24 + case 39: raw=190; break; // 32 + case 40: raw=200; break; // 32 + default: raw=0; break; + } + return raw; +} +int scaleContrast(int value) { + int raw; + + switch (value) { + // dont offer -5/ raw 0, looks like it might turn off the display completely? + case -4: raw=10; break; + case -3: raw=20; break; + case -2: raw=30; break; + case -1: raw=40; break; + case 0: raw=50; break; + case 1: raw=60; break; + case 2: raw=70; break; + case 3: raw=80; break; + case 4: raw=90; break; + case 5: raw=100; break; + default: raw=50; break; + } + return raw; +} +int scaleSaturation(int value) { + int raw; + + switch (value) { + case -5: raw=0; break; + case -4: raw=10; break; + case -3: raw=20; break; + case -2: raw=30; break; + case -1: raw=40; break; + case 0: raw=50; break; + case 1: raw=60; break; + case 2: raw=70; break; + case 3: raw=80; break; + case 4: raw=90; break; + case 5: raw=100; break; + default: raw=50; break; + } + return raw; +} +int scaleExposure(int value) { + int raw; + + switch (value) { + // stock OS also avoids setting anything lower, so we do the same here. + case -4: raw=10; break; + case -3: raw=20; break; + case -2: raw=30; break; + case -1: raw=40; break; + case 0: raw=50; break; + case 1: raw=60; break; + case 2: raw=70; break; + case 3: raw=80; break; + case 4: raw=90; break; + case 5: raw=100; break; + default: raw=50; break; + } + return raw; +} + +///////// Platform specific, unscaled accessors + +#define DISP_LCD_SET_BRIGHTNESS 0x102 +void SetRawBrightness(int val) { // 0 - 255 + int fd = open("/dev/disp", O_RDWR); + if (fd >= 0) { + unsigned long param[4]={0,val,0,0}; + ioctl(fd, DISP_LCD_SET_BRIGHTNESS, ¶m); + close(fd); + } +} +void SetRawColortemp(int val) { // 0 - 255 + FILE *fd = fopen("/sys/class/disp/disp/attr/color_temperature", "w"); + if (fd) { + fprintf(fd, "%i", val); + fclose(fd); + } +} + +// Find the first A2DP playback volume control via amixer +static int get_a2dp_simple_control_name(char *buf, size_t buflen) { + FILE *fp = popen("amixer -D bluealsa scontrols 2>/dev/null", "r"); + if (!fp) return 0; + + char line[256]; + while (fgets(line, sizeof(line), fp)) { + char *start = strchr(line, '\''); + char *end = strrchr(line, '\''); + if (start && end && end > start) { + size_t len = end - start - 1; + if (len < buflen) { + strncpy(buf, start + 1, len); + buf[len] = '\0'; + if (strstr(buf, "A2DP")) { // first A2DP simple control + pclose(fp); + char esc_buf[128]; + char *src = buf; + char *dst = esc_buf; + while(*src && (dst - esc_buf) < (sizeof(esc_buf) - 4)) { + if(*src == '\"') { + *dst++ = '\\'; + *dst++ = '\"'; + } else { + *dst++ = *src; + } + src++; + } + *dst = '\0'; + strncpy(buf, esc_buf, buflen); + buf[buflen - 1] = '\0'; + return 1; + } + } + } + } + + pclose(fp); + return 0; +} + +static int get_usbc_card_num() { + FILE *fp = popen("cat /proc/asound/cards", "r"); + if (!fp) return -1; + + char line[256]; + while (fgets(line, sizeof(line), fp)) { + if (strstr(line, "audiocodec") == NULL) { // skip the built-in codec + int card_num; + if (sscanf(line, " %d ", &card_num) == 1) { + pclose(fp); + return card_num; + } + } + } + + pclose(fp); + return -1; +} + +static int get_audiocodec_card_num() { + FILE *fp = popen("cat /proc/asound/cards", "r"); + if (!fp) return -1; + + char line[256]; + while (fgets(line, sizeof(line), fp)) { + if (strstr(line, "audiocodec") != NULL) { // look for the built-in codec + int card_num; + if (sscanf(line, " %d ", &card_num) == 1) { + pclose(fp); + return card_num; + } + } + } + + pclose(fp); + return -1; +} + +void SetRawVolume(int val) { // in: 0-100 + if (settings->mute && GetMutedVolume() != SETTINGS_DEFAULT_MUTE_NO_CHANGE) + val = scaleVolume(GetMutedVolume()); + + if (GetAudioSink() == AUDIO_SINK_BLUETOOTH) { + // bluealsa is a mixer plugin, not exposed as a separate card + char ctl_name[128] = {0}; + int found = 0; + for (int tries = 0; tries < 20; tries++) { + if ((found = get_a2dp_simple_control_name(ctl_name, sizeof(ctl_name)))) + break; + usleep(100000); + } + if (found) { + char cmd[256]; + // Update volume on the device + snprintf(cmd, sizeof(cmd), "amixer -D bluealsa sset \"%s\" -M %d%% > /dev/null 2>&1", ctl_name, val); + system(cmd); + //printf("Set '%s' to %d%%\n", ctl_name, val); fflush(stdout); + } + } + else if (GetAudioSink() == AUDIO_SINK_USBDAC) { + // USB DAC path: grab the first card that is not called "audiocodec" + int card_num = get_usbc_card_num(); + if(card_num < 0) { + printf("Failed to find USB audio card\n"); fflush(stdout); + return; + } + + struct mixer *mixer = mixer_open(card_num); + if (!mixer) { + printf("Failed to open mixer\n"); fflush(stdout); + return; + } + + const unsigned int num_controls = mixer_get_num_ctls(mixer); + for (unsigned int i = 0; i < num_controls; i++) { + struct mixer_ctl *ctl = mixer_get_ctl(mixer, i); + const char *name = mixer_ctl_get_name(ctl); + if (!name) continue; + + if ((strstr(name, "PCM") || strstr(name, "Playback")) && (strstr(name, "Volume") || strstr(name, "volume"))) { + if (mixer_ctl_get_type(ctl) == MIXER_CTL_TYPE_INT) { + int min = mixer_ctl_get_range_min(ctl); + int max = mixer_ctl_get_range_max(ctl); + int volume = min + (val * (max - min)) / 100; + unsigned int num_values = mixer_ctl_get_num_values(ctl); + for (unsigned int i = 0; i < num_values; i++) + mixer_ctl_set_value(ctl, i, volume); + } + break; + } + } + mixer_close(mixer); + } + else { + // Speaker path: grab the card that is called "audiocodec" + int card_num = get_audiocodec_card_num(); + if(card_num < 0) { + card_num = 0; // fallback to card 0 if we can't find it + } + + struct mixer *mixer = mixer_open(card_num); + if (!mixer) { + printf("Failed to open mixer\n"); fflush(stdout); + return; + } + + struct mixer_ctl *digital = mixer_get_ctl_by_name(mixer, "digital volume"); + if (digital) { + mixer_ctl_set_percent(digital, 0, 100 - val); // reversed mapping + //printf("Set 'digital volume' to %d%%\n", val); fflush(stdout); + } + + struct mixer_ctl *lineout = mixer_get_ctl_by_name(mixer, "lineout volume"); + if (lineout) { + mixer_ctl_set_percent(lineout, 0, val); + //printf("Set 'lineout volume' to %d%%\n", val); fflush(stdout); + } + + struct mixer_ctl *spk = mixer_get_ctl_by_name(mixer, "SPK"); + if (spk) + mixer_ctl_set_value(spk, 0, val == 0 ? 0 : 1); + + struct mixer_ctl *lineout_switch = mixer_get_ctl_by_name(mixer, "LINEOUT"); + if (lineout_switch) + mixer_ctl_set_value(lineout_switch, 0, val == 0 ? 0 : 1); + + mixer_close(mixer); + } +} + +void SetRawContrast(int val){ + FILE *fd = fopen("/sys/class/disp/disp/attr/enhance_contrast", "w"); + if (fd) { + fprintf(fd, "%i", val); + fclose(fd); + } +} +void SetRawSaturation(int val){ + FILE *fd = fopen("/sys/class/disp/disp/attr/enhance_saturation", "w"); + if (fd) { + fprintf(fd, "%i", val); + fclose(fd); + } +} +void SetRawExposure(int val){ + FILE *fd = fopen("/sys/class/disp/disp/attr/enhance_bright", "w"); + if (fd) { + fprintf(fd, "%i", val); + fclose(fd); + } +} +void SetRawDisplayCal(int enabled, int red_gain, int green_gain, int blue_gain) { + int ret = enabled + ? DisplayCal_enableWithValues(red_gain, green_gain, blue_gain) + : DisplayCal_disable(); + if (ret != 0) { + fprintf(stderr, "SetRawDisplayCal failed to %s display calibration: %i\n", + enabled ? "enable" : "disable", ret); + fflush(stderr); + } +} diff --git a/workspace/h700/libmsettings/msettings.h b/workspace/h700/libmsettings/msettings.h new file mode 100644 index 000000000..aedf077a9 --- /dev/null +++ b/workspace/h700/libmsettings/msettings.h @@ -0,0 +1,108 @@ +#ifndef __msettings_h__ +#define __msettings_h__ + +#define SETTINGS_DEFAULT_BRIGHTNESS 4 +#define SETTINGS_DEFAULT_COLORTEMP 20 +#define SETTINGS_DEFAULT_CONTRAST 0 +#define SETTINGS_DEFAULT_SATURATION 0 +#define SETTINGS_DEFAULT_EXPOSURE 0 +#define SETTINGS_DEFAULT_VOLUME 8 +#define SETTINGS_DEFAULT_HEADPHONE_VOLUME 4 +#define SETTINGS_DEFAULT_FAN_SPEED 0 + +#define SETTINGS_DEFAULT_MUTE_NO_CHANGE -69 + +void InitSettings(void); +void QuitSettings(void); +int InitializedSettings(void); + +int GetBrightness(void); +int GetColortemp(void); +int GetContrast(void); +int GetSaturation(void); +int GetExposure(void); +int GetDisplayCalEnabled(void); +int GetDisplayCalRedGain(void); +int GetDisplayCalGreenGain(void); +int GetDisplayCalBlueGain(void); +int GetVolume(void); + +void SetRawBrightness(int value); // 0-255 +void SetRawColortemp(int value); // 0-255 +void SetRawContrast(int value); // 0-100 +void SetRawSaturation(int value); // 0-100 +void SetRawExposure(int value); // 0-100 +void SetRawDisplayCal(int enabled, int red_gain, int green_gain, int blue_gain); +void SetRawVolume(int value); // 0-100 + +void SetBrightness(int value); // 0-10 +void SetColortemp(int value); // 0-40 +void SetContrast(int value); // -4-5 +void SetSaturation(int value); // -5-5 +void SetExposure(int value); // -4-5 +void SetDisplayCalEnabled(int value); // 0-1 +void SetDisplayCalRedGain(int value); // 0-200, 100 is neutral +void SetDisplayCalGreenGain(int value); // 0-200, 100 is neutral +void SetDisplayCalBlueGain(int value); // 0-200, 100 is neutral +void SetVolume(int value); // 0-20 + +int GetJack(void); +void SetJack(int value); // 0-1 + +#define AUDIO_SINK_DEFAULT 0 // use system default, usually speaker (or jack if plugged in) +#define AUDIO_SINK_BLUETOOTH 1 // software control via bluealsa, not a separate card +#define AUDIO_SINK_USBDAC 2 // assumes being exposed as card 1 to alsa +int GetAudioSink(void); +void SetAudioSink(int value); + +int GetHDMI(void); +void SetHDMI(int value); // 0-1 + +int GetMute(void); +void SetMute(int value); // 0-1 + +// unused +inline int GetFanSpeed(void) { + return 0; +} +inline void SetFanSpeed(int value) { + // do nothing +} + +// custom mute mode persistence layer + +int GetMutedBrightness(void); +int GetMutedColortemp(void); +int GetMutedContrast(void); +int GetMutedSaturation(void); +int GetMutedExposure(void); +int GetMutedVolume(void); +int GetMuteDisablesDpad(void); +int GetMuteEmulatesJoystick(void); +int GetMuteTurboA(void); +int GetMuteTurboB(void); +int GetMuteTurboX(void); +int GetMuteTurboY(void); +int GetMuteTurboL1(void); +int GetMuteTurboL2(void); +int GetMuteTurboR1(void); +int GetMuteTurboR2(void); + +void SetMutedBrightness(int); +void SetMutedColortemp(int); +void SetMutedContrast(int); +void SetMutedSaturation(int); +void SetMutedExposure(int); +void SetMutedVolume(int); +void SetMuteDisablesDpad(int); +void SetMuteEmulatesJoystick(int); +void SetMuteTurboA(int); +void SetMuteTurboB(int); +void SetMuteTurboX(int); +void SetMuteTurboY(int); +void SetMuteTurboL1(int); +void SetMuteTurboL2(int); +void SetMuteTurboR1(int); +void SetMuteTurboR2(int); + +#endif // __msettings_h__ diff --git a/workspace/h700/libmsettings/sunxi_display2_min.h b/workspace/h700/libmsettings/sunxi_display2_min.h new file mode 100644 index 000000000..83b2f2fb2 --- /dev/null +++ b/workspace/h700/libmsettings/sunxi_display2_min.h @@ -0,0 +1,68 @@ +// Minimal subset of the sunxi disp2 UAPI (include/video/sunxi_display2.h from +// the 4.9 sun50iw9 BSP kernel) — just enough to read-modify-write the fb0 +// scanout layer via DISP_LAYER_GET_CONFIG/DISP_LAYER_SET_CONFIG. Field order, +// sizes and the ioctl numbers must match the kernel ABI exactly; do not edit +// without checking against the BSP header. +#ifndef SUNXI_DISPLAY2_MIN_H +#define SUNXI_DISPLAY2_MIN_H + +#include + +#define DISP_LAYER_SET_CONFIG 0x47 +#define DISP_LAYER_GET_CONFIG 0x48 + +struct disp_rect { + int x; + int y; + unsigned int width; + unsigned int height; +}; + +struct disp_rectsz { + unsigned int width; + unsigned int height; +}; + +struct disp_rect64 { + long long x; + long long y; + long long width; + long long height; +}; + +struct disp_fb_info { + unsigned long long addr[3]; + struct disp_rectsz size[3]; + unsigned int align[3]; + int format; /* enum disp_pixel_format */ + int color_space; /* enum disp_color_space */ + unsigned int trd_right_addr[3]; + bool pre_multiply; + struct disp_rect64 crop; + int flags; /* enum disp_buffer_flags */ + int scan; /* enum disp_scan_flags */ +}; + +struct disp_layer_info { + int mode; /* enum disp_layer_mode */ + unsigned char zorder; + unsigned char alpha_mode; + unsigned char alpha_value; + struct disp_rect screen_win; + bool b_trd_out; + int out_trd_mode; /* enum disp_3d_out_mode */ + union { + unsigned int color; + struct disp_fb_info fb; + }; + unsigned int id; +}; + +struct disp_layer_config { + struct disp_layer_info info; + bool enable; + unsigned int channel; + unsigned int layer_id; +}; + +#endif diff --git a/workspace/h700/makefile b/workspace/h700/makefile new file mode 100644 index 000000000..33b9bb2fa --- /dev/null +++ b/workspace/h700/makefile @@ -0,0 +1,72 @@ +########################################################### + +ifeq (,$(PLATFORM)) +PLATFORM=$(UNION_PLATFORM) +endif + +ifeq (,$(PLATFORM)) +$(error please specify PLATFORM, eg. PLATFORM=rgb30 make) +endif + +########################################################### + +REQUIRES_EVTEST=other/evtest +REQUIRES_JSTEST=other/jstest +REQUIRES_UNZIP60=other/unzip60 +REQUIRES_FILEMGR=other/NextCommander +REQUIRES_SDL2=other/sdl2 + +.PHONY: curl-runtime +FILEMGR_PATCH=patches/NextCommander-h700.patch +FILEMGR_STAMP=.patched-h700-v3 + +all: readmes + +# SDL2 (mali-fbdev, alsa-shared, joystick patch) is prebaked into h700-toolchain +# at PREFIX_LOCAL. Stage it + SDK companion libs into other/sdl2/output for packaging. +# Rebuild only via the toolchain image (support/build-sdl2.sh + support/sdl2-h700.patch). +early: $(REQUIRES_EVTEST) $(REQUIRES_JSTEST) $(REQUIRES_UNZIP60) $(REQUIRES_FILEMGR) curl-runtime + mkdir -p other + cd $(REQUIRES_EVTEST) && $(CROSS_COMPILE)gcc -o evtest evtest.c + cd $(REQUIRES_JSTEST) && $(CROSS_COMPILE)gcc -o jstest jstest.c + cd $(REQUIRES_UNZIP60) && make -f unix/Makefile.trimuismart unzip + @test -e "$(PREFIX_LOCAL)/lib/libSDL2.so" -o -e "$(PREFIX_LOCAL)/lib/libSDL2-2.0.so.0" || \ + (echo "error: prebaked SDL2 missing from PREFIX_LOCAL=$(PREFIX_LOCAL); use ghcr.io/loveretro/h700-toolchain" >&2; exit 1) + mkdir -p $(REQUIRES_SDL2)/output + cp -a $(PREFIX_LOCAL)/lib/libSDL2*.so* $(REQUIRES_SDL2)/output/ + cp -a $(PREFIX)/lib/libSDL2_image*.so* $(REQUIRES_SDL2)/output/ 2>/dev/null || true + cp -a $(PREFIX)/lib/libSDL2_ttf*.so* $(REQUIRES_SDL2)/output/ 2>/dev/null || true + cp -L $(PREFIX)/lib/libtinyalsa.so* $(REQUIRES_SDL2)/output/ 2>/dev/null || true + # SDL2_image dlopens libpng12.so.0 at runtime; the H700 stock OS only has + # a 32-bit copy under /mnt/vendor/lib, so bundle the toolchain's 64-bit one + cp -L $(PREFIX)/lib/libpng12.so.0 $(REQUIRES_SDL2)/output/ + cd $(REQUIRES_FILEMGR) && ([ -f $(FILEMGR_STAMP) ] || (git checkout -- . && git apply --unidiff-zero ../../$(FILEMGR_PATCH) && touch $(FILEMGR_STAMP))) + cd $(REQUIRES_FILEMGR) && ([ -f output/.platform-h700 ] || make clean PLATFORM=h700) + cd $(REQUIRES_FILEMGR) && make -j PLATFORM=h700 && touch output/.platform-h700 + cd boot && sh build.sh + +curl-runtime: curl/build.sh + cd curl && sh build.sh + +clean: + cd $(REQUIRES_FILEMGR) && make clean PLATFORM=h700 + cd $(REQUIRES_UNZIP60) && make -f unix/Makefile.trimuismart clean + rm -rf $(REQUIRES_SDL2)/output + rm -rf curl/output curl/curl-* curl/musl-* curl/openssl-* + rm -rf boot/output + +########################################################### + +$(REQUIRES_FILEMGR): + git clone --depth 1 https://github.com/LoveRetro/NextCommander.git $(REQUIRES_FILEMGR) + +$(REQUIRES_EVTEST): + git clone --depth 1 https://github.com/freedesktop-unofficial-mirror/evtest.git $(REQUIRES_EVTEST) + +$(REQUIRES_JSTEST): + git clone --depth 1 https://github.com/datrh/joyutils.git $(REQUIRES_JSTEST) + +$(REQUIRES_UNZIP60): + git clone --depth 1 https://github.com/shauninman/unzip60.git $(REQUIRES_UNZIP60) + +include ../all/readmes/makefile diff --git a/workspace/h700/patches/NextCommander-h700.patch b/workspace/h700/patches/NextCommander-h700.patch new file mode 100644 index 000000000..c3cc96e8d --- /dev/null +++ b/workspace/h700/patches/NextCommander-h700.patch @@ -0,0 +1,109 @@ +diff --git a/Makefile b/Makefile +index d16a23d..3b979ff 100644 +--- a/Makefile ++++ b/Makefile +@@ -8,8 +8,43 @@ endif + CXXFLAGS := -Os + #endif + ++# platform dependant stuff - h700 ++ifeq ($(PLATFORM),h700) ++SDCARD_ROOT := /mnt/SDCARD ++NEXTUI_SYSTEM_PATH := $(SDCARD_ROOT)/.system ++ ++CXXFLAGS += -DPATH_DEFAULT=\"$(SDCARD_ROOT)\" ++CXXFLAGS += -DPATH_DEFAULT_RIGHT=\"$(SDCARD_ROOT)\" ++CXXFLAGS += -DFILE_SYSTEM=\"/dev/mmcblk1p1\" ++ ++# Keys ++# Joys for Anbernic RG XX H700. The bundled SDL fork assigns joystick button ++# indices in ascending evdev keycode order, and the built-in pad exposes ++# ESC/VOL-/VOL+ (keycodes 1/114/115) before the gamepad buttons (304..316), ++# so the gamepad buttons start at index 3. ++CXXFLAGS += -DCMDR_KEY_UP=SDLK_UP ++CXXFLAGS += -DCMDR_KEY_RIGHT=SDLK_RIGHT ++CXXFLAGS += -DCMDR_KEY_DOWN=SDLK_DOWN ++CXXFLAGS += -DCMDR_KEY_LEFT=SDLK_LEFT ++CXXFLAGS += -DCMDR_KEY_OPEN=3 # A (304) ++CXXFLAGS += -DCMDR_KEY_PARENT=4 # B (305) ++CXXFLAGS += -DCMDR_KEY_OPERATION=6 # X (307) ++CXXFLAGS += -DCMDR_KEY_SYSTEM=5 # Y (306) ++CXXFLAGS += -DCMDR_KEY_PAGEUP=7 # L1 (308) ++CXXFLAGS += -DCMDR_KEY_PAGEDOWN=8 # R1 (309) ++CXXFLAGS += -DCMDR_KEY_SELECT=9 # SELECT (310) ++CXXFLAGS += -DCMDR_KEY_TRANSFER=10 # START (311) ++CXXFLAGS += -DCMDR_KEY_MENU=11 # MENU (312) ++ ++# Screen ++CXXFLAGS += -DAUTOSCALE=1 ++CXXFLAGS += -DAUTOSCALE_DPI=0 ++CXXFLAGS += -DPPU_X=2 ++CXXFLAGS += -DPPU_Y=2 ++CXXFLAGS += -DSCREEN_BPP=32 ++ + # platform dependant stuff - tg5040 and tg5050 +-ifneq (,$(findstring tg50,$(PLATFORM))) ++else ifneq (,$(findstring tg50,$(PLATFORM))) + SDCARD_ROOT := /mnt/SDCARD + NEXTUI_SYSTEM_PATH := $(SDCARD_ROOT)/.system + +@@ -84,7 +119,13 @@ CXXFLAGS += -DSCREEN_BPP=32 + endif + + SDL := SDL2 ++ifeq ($(PLATFORM),h700) ++CXXFLAGS += -I$(PREFIX_LOCAL)/include/$(SDL) -I$(PREFIX)/include/$(SDL) ++LINKFLAGS += -L$(PREFIX_LOCAL)/lib -L$(PREFIX)/lib ++else + CXXFLAGS += -I$(PREFIX)/include/$(SDL) -DUSE_$(SDL) ++endif ++CXXFLAGS += -DUSE_$(SDL) + + #CXXFLAGS += $$(pkg-config --cflags sdl2 SDL2_image SDL2_ttf) + #LINKFLAGS += $$(pkg-config --libs sdl2 SDL2_image SDL2_ttf) +diff --git a/src/screen.cpp b/src/screen.cpp +index 43d31fa..c9818b1 100644 +--- a/src/screen.cpp ++++ b/src/screen.cpp +@@ -80,8 +80,17 @@ int Screen::init() + + int window_w = screen.actual_w; + int window_h = screen.actual_h; ++ // When autoscaling, size the window to the display: deriving it from ++ // disp_width * ppu can exceed what the driver supports (e.g. mali-fbdev ++ // fails to create a 3840x2880 surface on a 640x480 panel at high PPU). ++ SDL_DisplayMode dm; ++ if (cfg.disp_autoscale && SDL_GetCurrentDisplayMode(0, &dm) == 0 ++ && dm.w > 0 && dm.h > 0) { ++ window_w = dm.w; ++ window_h = dm.h; ++ } + window = SDL_CreateWindow("Commander", SDL_WINDOWPOS_UNDEFINED, +- SDL_WINDOWPOS_UNDEFINED, window_h, window_h, window_flags); ++ SDL_WINDOWPOS_UNDEFINED, window_w, window_h, window_flags); + if (window == nullptr) { + SDL_Log("Failed to create window: %s", SDL_GetError()); + return 1; +diff --git a/src/window.cpp b/src/window.cpp +index e3e646e..b42bb89 100644 +--- a/src/window.cpp ++++ b/src/window.cpp +@@ -62,9 +62,18 @@ int CWindow::execute() + SDL_Event event; + bool l_loop(true); + bool l_render(true); ++ // Re-render the first few frames: on fbdev-style double-buffered targets a ++ // single startup flip can land on a page that the previous app (or the ++ // launcher handing off to us) still overwrites, leaving a stale screen ++ // until the next input-triggered render. ++ int l_warmup(8); + // Main loop + while (l_loop) + { ++ if (l_warmup > 0) { ++ --l_warmup; ++ l_render = true; ++ } + // Handle key press + while (SDL_PollEvent(&event)) + { diff --git a/workspace/h700/platform/led.c b/workspace/h700/platform/led.c new file mode 100644 index 000000000..7db232fe0 --- /dev/null +++ b/workspace/h700/platform/led.c @@ -0,0 +1,482 @@ +// h700 RGB LEDs +// +// Included from platform.c (like generic_video.c et al) so the 13 makefiles +// that compile platform.c directly don't each need a new source file. +// +// Only three SKUs have RGB LEDs: rg40xxh, rg40xxv, and rgcubexx. +// They are NOT in /sys/class/leds and there is no led_anim driver (that is +// TrimUI only) -- they hang off a separate MCU reached over UART5 at 115200 +// 8N1, powered by the axp2202 mcu_pwr rail. The protocol is +// +// +// +// with checksum = sum(preceding bytes) & 0xFF, written as raw bytes. +// +// mode 1 solid, payload 8x(R,G,B) for one bank then 8x(R,G,B) for the +// other -- 16 LED positions in two banks of 8, and the only +// mode with per-bank colour +// mode 2/3/4 breath fast/med/slow, payload 16x(R,G,B), one colour for all +// mode 5/6 rainbow mono/multi, payload <1> <1> +// +// The MCU animates on its own, exactly like the led_anim kernel driver does on +// TrimUI, so there is no userspace animation here -- we translate NextUI's +// effect ids onto the modes above and let the firmware run them. +// +// Hardware limits that shape the design: one brightness byte per frame (global, +// not per zone) and a single effect for the whole strip. Zone 0 governs the +// effect and speed; brightness is the max across zones; colour is per-bank in +// solid mode and zone 0's colour everywhere else. + +#include +#include +#include + +// H700_LED_TTY / H700_MCU_PWR live in platform.c: detect_device() probes for +// them, and it runs before this file is included. + +// MCU modes +#define MCU_SOLID 1 +#define MCU_BREATH_FAST 2 +#define MCU_BREATH_MED 3 +#define MCU_BREATH_SLOW 4 +#define MCU_RAINBOW 5 +#define MCU_RAINBOW_MULTI 6 + +#define LED_PIXELS 16 // addressable positions, two banks of 8 +#define LED_BANK (LED_PIXELS / 2) // positions per bank +#define LED_FRAME_MAX (2 + LED_PIXELS * 3 + 1) // mode + brightness + payload + checksum + +// muOS sends the right-hand bank first, and we follow it. +// +// This only matters on the H and the CubeXX: the RG40XXV has one populated bank +// and gets the same colour in both halves regardless. Testing on a V showed its +// single (left) stick lit by the *first* bank, which looks like a contradiction +// -- but a one-bank device says nothing about how a two-bank one is ordered, and +// the far likelier reading is that the only populated channel is wired to +// channel 1 whichever stick it belongs to. muOS's ordering was written against +// hardware that actually has both banks, so it wins here. +// +// If an H or CubeXX ever turns up with left and right swapped, this is the only +// line that changes. +#define H700_LED_RIGHT_FIRST 1 + +// NextUI effect ids are a shared, TrimUI-derived space (see api.h). We expose +// the subset the MCU can render and translate the rest to the nearest mode. +// Id 9 is "Twinkle" on TrimUI; we reuse it for the MCU's second rainbow, which +// is safe because h700 keeps its own settings file (PLAT_getLedSettingsFile). +#define H700_EFFECT_BREATHE 2 +#define H700_EFFECT_STATIC 4 +#define H700_EFFECT_RAINBOW 8 +#define H700_EFFECT_RAINBOW_MULTI 9 + +static const struct { + int id; + const char *name; +} h700_led_effects[] = { + {H700_EFFECT_STATIC, "Static"}, + {H700_EFFECT_BREATHE, "Breathe"}, + {H700_EFFECT_RAINBOW, "Rainbow"}, + {H700_EFFECT_RAINBOW_MULTI, "Rainbow Multi"}, +}; +#define H700_EFFECT_COUNT ((int)(sizeof(h700_led_effects) / sizeof(h700_led_effects[0]))) + +typedef struct { + uint32_t color; // 0xRRGGBB + int effect; // shared effect id + int speed; // ms, as LedControl stores it + int brightness; // 0-100 +} LedZone; + +static struct { + int fd; + pthread_mutex_t lock; + LedZone zone[MAX_LIGHTS]; + uint8_t last[LED_FRAME_MAX]; + int last_len; // 0 = cache invalid, always resend +} led = { + .fd = -1, + .lock = PTHREAD_MUTEX_INITIALIZER, +}; + +/////////////////////////////// +// frame assembly + +static int LED_breathModeForSpeed(int speed) { + // LedControl's speed row runs 0-4900 in steps of 100; the MCU only offers + // three breath rates, so split that range into thirds. + if (speed < 1700) return MCU_BREATH_FAST; + if (speed < 3300) return MCU_BREATH_MED; + return MCU_BREATH_SLOW; +} + +static int LED_modeForEffect(int effect, int speed) { + switch (effect) { + case 1: return MCU_BREATH_FAST; // Linear + case H700_EFFECT_BREATHE: return LED_breathModeForSpeed(speed); + case 3: return MCU_BREATH_SLOW; // Interval Breathe (low/critical battery) + case H700_EFFECT_STATIC: return MCU_SOLID; + case 5: return MCU_BREATH_FAST; // Blink 1 - the MCU has no blink + case 6: return MCU_BREATH_MED; // Blink 2 + case 7: return MCU_BREATH_SLOW; // Blink 3 + case H700_EFFECT_RAINBOW: return MCU_RAINBOW; + case H700_EFFECT_RAINBOW_MULTI: return MCU_RAINBOW_MULTI; + default: return MCU_SOLID; // per-position effects we can't render + } +} + +static void LED_putColor(uint8_t *buf, int *n, uint32_t color, int repeat) { + uint8_t r = (color >> 16) & 0xFF; + uint8_t g = (color >> 8) & 0xFF; + uint8_t b = color & 0xFF; + for (int i = 0; i < repeat; i++) { + buf[(*n)++] = r; + buf[(*n)++] = g; + buf[(*n)++] = b; + } +} + +// builds a frame from the current zone state, returns its length +static int LED_buildFrame(uint8_t *buf) { + int count = dev_num_leds; + if (count < 1) return 0; + if (count > MAX_LIGHTS) count = MAX_LIGHTS; + + // brightness is a single byte for the whole strip + int brightness = 0; + for (int i = 0; i < count; i++) + if (led.zone[i].brightness > brightness) brightness = led.zone[i].brightness; + if (brightness > 100) brightness = 100; + if (brightness < 0) brightness = 0; + + // LIGHT_PROFILE_OFF zeroes brightness and must actually extinguish, so + // force a black solid frame rather than leaving an effect running dim. + int mode = brightness == 0 + ? MCU_SOLID + : LED_modeForEffect(led.zone[0].effect, led.zone[0].speed); + + uint32_t color_a = brightness == 0 ? 0 : led.zone[0].color; + // with a single populated bank we send the same colour to both, so the + // frame is correct either way round + uint32_t color_b = (brightness == 0 || count < 2) ? color_a : led.zone[1].color; + + int n = 0; + buf[n++] = mode; + buf[n++] = (brightness * 255) / 100; + + if (mode == MCU_RAINBOW || mode == MCU_RAINBOW_MULTI) { + int speed = led.zone[0].speed; + if (speed < 0) speed = 0; + if (speed > 4900) speed = 4900; + buf[n++] = 1; + buf[n++] = 1; + buf[n++] = (speed * 255) / 4900; + } + else if (mode == MCU_SOLID) { +#if H700_LED_RIGHT_FIRST + LED_putColor(buf, &n, color_b, LED_BANK); // right bank + LED_putColor(buf, &n, color_a, LED_BANK); // left bank +#else + LED_putColor(buf, &n, color_a, LED_BANK); + LED_putColor(buf, &n, color_b, LED_BANK); +#endif + } + else { + // breath modes take one colour for the whole strip + LED_putColor(buf, &n, color_a, LED_PIXELS); + } + + int sum = 0; + for (int i = 0; i < n; i++) + sum += buf[i]; + buf[n++] = sum & 0xFF; + + return n; +} + +// caller must hold led.lock +static void LED_commitLocked(void) { + if (led.fd < 0) return; + + uint8_t buf[LED_FRAME_MAX]; + int len = LED_buildFrame(buf); + if (len <= 0) return; + + if (led.last_len == len && memcmp(buf, led.last, len) == 0) + return; // nothing changed, don't touch the wire + + // The fd is non-blocking on purpose: ambient mode repaints from the + // libretro per-frame input poll, and a blocking write of a 51 byte frame + // costs 4.4ms at 115200 -- a quarter of a 60fps frame budget. Writing into + // the tty buffer instead is a memcpy, and the frame drains long before the + // next one arrives (51 bytes every 16.7ms against 11520 bytes/sec). + ssize_t written = write(led.fd, buf, len); + if (written != len) { + // EAGAIN means the buffer is full; leave the cache alone so the next + // commit retries rather than assuming this frame landed + led.last_len = 0; + return; + } + + memcpy(led.last, buf, len); + led.last_len = len; +} + +static void LED_commit(void) { + pthread_mutex_lock(&led.lock); + LED_commitLocked(); + pthread_mutex_unlock(&led.lock); +} + +// The MCU loses its state when mcu_pwr is cut over sleep, so the cached frame +// must not suppress the repaint on wake. +static void LED_invalidateCache(void) { + pthread_mutex_lock(&led.lock); + led.last_len = 0; + pthread_mutex_unlock(&led.lock); +} + +/////////////////////////////// +// port lifecycle + +static void LED_openPort(void) { + if (led.fd >= 0) return; + + putInt(H700_MCU_PWR, 1); + usleep(100 * 1000); // let the MCU rail come up before the first frame + + int fd = open(H700_LED_TTY, O_WRONLY | O_NOCTTY | O_NONBLOCK | O_CLOEXEC); + if (fd < 0) { + LOG_warn("LED: unable to open %s: %s\n", H700_LED_TTY, strerror(errno)); + return; + } + + // nextui hands off to minarch and back; if both ever held the port at once + // their frames would interleave into garbage the MCU can't parse + if (flock(fd, LOCK_EX | LOCK_NB) < 0) { + LOG_warn("LED: %s already claimed, skipping\n", H700_LED_TTY); + close(fd); + return; + } + + struct termios tio; + if (tcgetattr(fd, &tio) < 0) { + LOG_warn("LED: tcgetattr failed: %s\n", strerror(errno)); + close(fd); + return; + } + cfmakeraw(&tio); + cfsetispeed(&tio, B115200); + cfsetospeed(&tio, B115200); + tio.c_cflag |= CLOCAL | CREAD | CS8; + tio.c_cflag &= ~(PARENB | CSTOPB | CRTSCTS); + if (tcsetattr(fd, TCSANOW, &tio) < 0) { + LOG_warn("LED: tcsetattr failed: %s\n", strerror(errno)); + close(fd); + return; + } + + led.fd = fd; + led.last_len = 0; + LOG_info("LED: %s open, %i zone(s)\n", H700_LED_TTY, dev_num_leds); +} + +// turn the LEDs off and drop the MCU rail - poweroff only, never on a normal +// process exit (nextui <-> minarch handoffs would blink the LEDs dark) +static void LED_shutdown(void) { + if (led.fd < 0) return; + + pthread_mutex_lock(&led.lock); + for (int i = 0; i < MAX_LIGHTS; i++) + led.zone[i].brightness = 0; + led.last_len = 0; + LED_commitLocked(); + // the frame is queued in the tty buffer; give it the ~4.4ms it needs to + // reach the MCU before the rail goes away + tcdrain(led.fd); + close(led.fd); + led.fd = -1; + pthread_mutex_unlock(&led.lock); + + putInt(H700_MCU_PWR, 0); +} + +/////////////////////////////// +// platform hooks + +int PLAT_getNumLeds(void) { + detect_device(); + return dev_num_leds; +} + +const char *PLAT_getLedSettingsFile(void) { + // deliberately not "ledsettings.txt": shared userdata can come off a card + // that was in a TrimUI, and its 3-5 sections would be mis-assigned here + return "ledsettings_h700.txt"; +} + +const char *PLAT_getLedLabel(int index) { + switch (index) { + case 0: return "Left"; + case 1: return "Right"; + default: return NULL; + } +} + +int PLAT_getLedEffectCount(void) { return H700_EFFECT_COUNT; } + +int PLAT_getLedEffectId(int index) { + if (index < 0 || index >= H700_EFFECT_COUNT) return H700_EFFECT_STATIC; + return h700_led_effects[index].id; +} + +const char *PLAT_getLedEffectName(int effect_id) { + for (int i = 0; i < H700_EFFECT_COUNT; i++) + if (h700_led_effects[i].id == effect_id) return h700_led_effects[i].name; + return NULL; +} + +void PLAT_initDefaultLeds(void) { + detect_device(); + if (dev_num_leds > 0) + lightsDefault[0] = (LightSettings){"Left", "l", H700_EFFECT_STATIC, 1000, 100, 0x440044, 0x440044, 0, {}, 1, 100, 0}; + if (dev_num_leds > 1) + lightsDefault[1] = (LightSettings){"Right", "r", H700_EFFECT_STATIC, 1000, 100, 0x440044, 0x440044, 0, {}, 1, 100, 0}; +} + +void PLAT_initLeds(LightSettings *lights) { + PLAT_initDefaultLeds(); + if (dev_num_leds < 1) return; + + FILE *file = PLAT_OpenSettings(PLAT_getLedSettingsFile()); + if (file == NULL) { + LOG_warn("Unable to open led settings file\n"); + } + else { + char line[256]; + int current_light = -1; + while (fgets(line, sizeof(line), file)) { + if (line[0] == '[') { + char light_name[255]; + if (sscanf(line, "[%49[^]]]", light_name) == 1) { + current_light++; + if (current_light < dev_num_leds) { + strncpy(lights[current_light].name, light_name, 255 - 1); + lights[current_light].name[255 - 1] = '\0'; + // cycles is never persisted by LedControl, and anything + // other than -1 would make every effect a one-shot + lights[current_light].cycles = -1; + } + else { + LOG_info("Maximum number of lights (%d) exceeded. Ignoring further sections.\n", dev_num_leds); + current_light = -1; + } + } + } + else if (current_light >= 0 && current_light < dev_num_leds) { + int temp_value; + uint32_t temp_color; + char filename[255]; + + if (sscanf(line, "filename=%s", filename) == 1) { + strncpy(lights[current_light].filename, filename, 255 - 1); + lights[current_light].filename[255 - 1] = '\0'; + continue; + } + if (sscanf(line, "effect=%d", &temp_value) == 1) { + lights[current_light].effect = temp_value; + continue; + } + if (sscanf(line, "color1=%x", &temp_color) == 1) { + lights[current_light].color1 = temp_color; + continue; + } + if (sscanf(line, "color2=%x", &temp_color) == 1) { + lights[current_light].color2 = temp_color; + continue; + } + if (sscanf(line, "speed=%d", &temp_value) == 1) { + lights[current_light].speed = temp_value; + continue; + } + if (sscanf(line, "brightness=%d", &temp_value) == 1) { + lights[current_light].brightness = temp_value; + continue; + } + if (sscanf(line, "trigger=%d", &temp_value) == 1) { + lights[current_light].trigger = temp_value; + continue; + } + if (sscanf(line, "inbrightness=%d", &temp_value) == 1) { + lights[current_light].inbrightness = temp_value; + continue; + } + } + } + fclose(file); + } + + LED_openPort(); +} + +// The setters below only stage state. LEDS_updateLeds() calls all five of them +// for every light, so committing eagerly would put four redundant frames (and +// one with the second zone still stale) on the wire per update. PLAT_setLedEffect +// is the last call for a given light -- as on TrimUI, where it is likewise the +// point the settings get applied -- so the frame goes out once the final zone +// has been staged. + +static int LED_zoneIndex(LightSettings *led_settings) { + if (!led_settings) return -1; + if (exactMatch(led_settings->filename, "l")) return 0; + if (exactMatch(led_settings->filename, "r")) return 1; + return -1; +} + +// returns the staged zone, or NULL if this light isn't ours +static LedZone *LED_zoneFor(LightSettings *led_settings) { + int index = LED_zoneIndex(led_settings); + if (index < 0 || index >= dev_num_leds) return NULL; + return &led.zone[index]; +} + +void PLAT_setLedInbrightness(LightSettings *led_settings) { + pthread_mutex_lock(&led.lock); + LedZone *zone = LED_zoneFor(led_settings); + if (zone) zone->brightness = led_settings->inbrightness; + pthread_mutex_unlock(&led.lock); +} + +void PLAT_setLedBrightness(LightSettings *led_settings) { + pthread_mutex_lock(&led.lock); + LedZone *zone = LED_zoneFor(led_settings); + if (zone) zone->brightness = led_settings->brightness; + pthread_mutex_unlock(&led.lock); +} + +void PLAT_setLedColor(LightSettings *led_settings) { + pthread_mutex_lock(&led.lock); + LedZone *zone = LED_zoneFor(led_settings); + if (zone) zone->color = led_settings->color1; + pthread_mutex_unlock(&led.lock); +} + +void PLAT_setLedEffectSpeed(LightSettings *led_settings) { + pthread_mutex_lock(&led.lock); + LedZone *zone = LED_zoneFor(led_settings); + if (zone) zone->speed = led_settings->speed; + pthread_mutex_unlock(&led.lock); +} + +// the MCU has no cycle count - effects run until something replaces them +void PLAT_setLedEffectCycles(LightSettings *led_settings) {} + +void PLAT_setLedEffect(LightSettings *led_settings) { + pthread_mutex_lock(&led.lock); + int index = LED_zoneIndex(led_settings); + LedZone *zone = (index >= 0 && index < dev_num_leds) ? &led.zone[index] : NULL; + if (zone) zone->effect = led_settings->effect; + // commit once the last zone of this pass has been staged + int commit = zone && index == dev_num_leds - 1; + if (commit) LED_commitLocked(); + pthread_mutex_unlock(&led.lock); +} diff --git a/workspace/h700/platform/makefile.copy b/workspace/h700/platform/makefile.copy new file mode 100644 index 000000000..bfac9c0f6 --- /dev/null +++ b/workspace/h700/platform/makefile.copy @@ -0,0 +1,29 @@ +$(PLATFORM): + mkdir -p ./build/BASE/h700 + cp ./workspace/$@/boot/output/dmenu.bin ./build/BASE/h700/ + + # installer + cp ./workspace/$@/install/boot.sh ./build/BOOT/common/$@.sh + cp ./workspace/$@/install/update.sh ./build/SYSTEM/$@/bin/install.sh + mkdir -p ./build/SYSTEM/$@/dat + cp ./workspace/$@/boot/output/dmenu.bin ./build/SYSTEM/$@/dat/ + mkdir -p ./build/BOOT/common/$@/ + cp ./workspace/$@/install/*.png ./build/BOOT/common/$@/ + cp ./workspace/$@/shim-common.sh ./build/BOOT/common/$@/ + cp ./workspace/all/show2/build/$@/show2.elf ./build/BOOT/common/$@/ + cp ./workspace/$@/other/unzip60/unzip ./build/BOOT/common/$@/ + cp -a ./workspace/$@/other/sdl2/output/libSDL2*.so* ./build/SYSTEM/$@/lib/ + cp -a ./workspace/$@/other/sdl2/output/libtinyalsa.so* ./build/SYSTEM/$@/lib/ 2>/dev/null || true + cp -a ./workspace/$@/other/sdl2/output/libpng12.so* ./build/SYSTEM/$@/lib/ + # rfkill + cp ./workspace/$@/rfkill/rfkill.elf ./build/SYSTEM/$@/bin/ + cp ./workspace/$@/other/evtest/evtest ./build/SYSTEM/$@/bin/ + cp ./workspace/$@/other/jstest/jstest ./build/SYSTEM/$@/bin/ + # Private curl runtime for stock Anbernic OS, which does not ship curl. + cp ./workspace/$@/curl/output/curl ./build/SYSTEM/$@/bin/ + mkdir -p ./build/SYSTEM/$@/etc/ssl/certs + cp ./workspace/$@/curl/output/ca-certificates.crt ./build/SYSTEM/$@/etc/ssl/certs/ + + # extras + cp ./workspace/$@/other/NextCommander/output/NextCommander ./build/EXTRAS/Tools/$@/Files.pak/ + cp -r ./workspace/$@/other/NextCommander/res ./build/EXTRAS/Tools/$@/Files.pak/ diff --git a/workspace/h700/platform/makefile.env b/workspace/h700/platform/makefile.env new file mode 100644 index 000000000..96b9969bd --- /dev/null +++ b/workspace/h700/platform/makefile.env @@ -0,0 +1,24 @@ +# h700 +OPT = -O3 -Ofast -fomit-frame-pointer +# -mtune/-march/-mpcu +# "When porting from x86 to Arm, you should replace any occurrences of -march +# with -mcpu and remove any instances of -mtune. +# This will have the desired effect of simultaneously tuning for the target +# architecture and microarchitecture." +# https://developer.arm.com/community/arm-community-blogs/b/tools-software-ides-blog/posts/compiler-flags-across-architectures-march-mtune-and-mcpu +CFLAGS = -mcpu=cortex-a53 -flto +SDL = SDL2 +GL = GLES +# legacy linux paths +CFLAGS += -I$(PREFIX_LOCAL)/include -I$(PREFIX)/include +LDFLAGS = -L$(PREFIX_LOCAL)/lib -L$(PREFIX)/lib +# multiarch support +CFLAGS += -I$(PREFIX)/include/$(CROSS_TRIPLE) +LDFLAGS += -L$(PREFIX_LOCAL)/lib/$(CROSS_TRIPLE) -L$(PREFIX)/lib/$(CROSS_TRIPLE) +# pkg-config +export PKG_CONFIG_PATH := $(PREFIX_LOCAL)/lib/pkgconfig:$(PREFIX_LOCAL)/lib/$(CROSS_TRIPLE)/pkgconfig:$(PKG_CONFIG_PATH) +CFLAGS += $$(pkg-config --cflags sdl2 glesv2) +LDFLAGS += $$(pkg-config --libs sdl2) -lGLESv2 +# not handled by pkg-config +CFLAGS += -DUSE_$(SDL) -DUSE_$(GL) -DGL_GLEXT_PROTOTYPES +LDFLAGS += -l$(SDL)_image -l$(SDL)_ttf -lpthread -ldl -lm -lz diff --git a/workspace/h700/platform/platform.c b/workspace/h700/platform/platform.c new file mode 100644 index 000000000..fbf2b3321 --- /dev/null +++ b/workspace/h700/platform/platform.c @@ -0,0 +1,1052 @@ +// h700 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "defines.h" +#include "platform.h" +#include "api.h" +#include "utils.h" + +#include "scaler.h" +#include +#include +#include + +#include +#include + +int panel_w = 640; +int panel_h = 480; +int needs_portrait_sdl = 0; +int hdmi_active = 0; +int dev_has_lstick = 0; +int dev_has_rstick = 0; +int dev_has_rgb = 0; +int dev_num_leds = 0; +static int wake_fd = -1; + +// RGB LEDs hang off an MCU on UART5, gated by the axp2202 mcu_pwr rail. +// See led.c, which is included at the bottom of this file. +#define H700_LED_TTY "/dev/ttyS5" +#define H700_MCU_PWR "/sys/class/power_supply/axp2202-battery/mcu_pwr" +static void LED_invalidateCache(void); +static void LED_shutdown(void); + +#define H700_INPUT_COUNT 12 +#define EV_KEY 0x01 +#define EV_ABS 0x03 + +// Built-in controls use raw evdev codes. The in-tree SDL patch restores joystick +// enumeration, but platform input deliberately skips this device because its SDL +// button ordering differs from the external-pad JOY_* mapping and would duplicate +// the evdev events. +#define RAW_HATY 17 +#define RAW_HATX 16 +#define RAW_LSY 3 +#define RAW_LSX 2 +#define RAW_RSY 5 +#define RAW_RSX 4 + +struct input_event { + struct timeval time; + uint16_t type; + uint16_t code; + int32_t value; +}; + +static int input_fds[H700_INPUT_COUNT]; +static uint32_t last_input_scan = 0; + +static void close_evdev_input(int i) { + if (i < 0 || i >= H700_INPUT_COUNT || input_fds[i] < 0) + return; + close(input_fds[i]); + input_fds[i] = -1; +} + +static void open_evdev_input(int i) { + char path[64]; + snprintf(path, sizeof(path), "/dev/input/event%i", i); + + input_fds[i] = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (input_fds[i] < 0) + return; + + char name_path[128]; + char name[256] = {0}; + snprintf(name_path, sizeof(name_path), "/sys/class/input/event%i/device/name", i); + getFile(name_path, name, sizeof(name)); + if (name[0]) + LOG_info("Opening input event%i: %s\n", i, name); + else + LOG_info("Opening input event%i\n", i); +} + +static void scan_evdev_inputs(void) { + uint32_t now = SDL_GetTicks(); + if (last_input_scan && now - last_input_scan < 2000) + return; + last_input_scan = now; + + for (int i = 0; i < H700_INPUT_COUNT; i++) { + char path[64]; + snprintf(path, sizeof(path), "/dev/input/event%i", i); + int connected = exists(path); + if (input_fds[i] < 0 && connected) + open_evdev_input(i); + else if (input_fds[i] >= 0 && !connected) + close_evdev_input(i); + } +} + +static void apply_button_state(int btn, int id, int pressed, uint32_t tick) { + if (btn == BTN_NONE || id < 0) + return; + + if (!pressed) { + if (pad.is_pressed & btn) { + pad.is_pressed &= ~btn; + pad.just_repeated &= ~btn; + pad.just_released |= btn; + } + } + else if ((pad.is_pressed & btn) == BTN_NONE) { + pad.just_pressed |= btn; + pad.just_repeated |= btn; + pad.is_pressed |= btn; + pad.repeat_at[id] = tick + PAD_REPEAT_DELAY; + } +} + +static int button_from_code(int code, int *id) { + if (code == CODE_UP) { *id = BTN_ID_DPAD_UP; return BTN_DPAD_UP; } + else if (code == CODE_DOWN) { *id = BTN_ID_DPAD_DOWN; return BTN_DPAD_DOWN; } + else if (code == CODE_LEFT) { *id = BTN_ID_DPAD_LEFT; return BTN_DPAD_LEFT; } + else if (code == CODE_RIGHT) { *id = BTN_ID_DPAD_RIGHT; return BTN_DPAD_RIGHT; } + else if (code == CODE_A) { *id = BTN_ID_A; return BTN_A; } + else if (code == CODE_B) { *id = BTN_ID_B; return BTN_B; } + else if (code == CODE_X) { *id = BTN_ID_X; return BTN_X; } + else if (code == CODE_Y) { *id = BTN_ID_Y; return BTN_Y; } + else if (code == CODE_START) { *id = BTN_ID_START; return BTN_START; } + else if (code == CODE_SELECT) { *id = BTN_ID_SELECT; return BTN_SELECT; } + else if (code == CODE_MENU) { *id = BTN_ID_MENU; return BTN_MENU; } + // NOTE: CODE_MENU_ALT (354/KEY_GOTO) is deliberately NOT mapped to BTN_MENU. + // The H700 firmware reports the physical MENU button faithfully on CODE_MENU + // (312/BTN_TL2) — down while held, up on release. On a *short* tap it also + // emits a synthetic KEY_GOTO pulse that starts the instant CODE_MENU releases + // and lasts ~190ms. Mapping both to BTN_MENU stretches every tap past the + // 250ms long-press threshold, so a quick MENU tap wrongly registers as a hold + // (brightness overlay instead of the shortcuts overlay). Ignore the synthetic + // pulse and let NextUI derive tap-vs-hold from the clean CODE_MENU timing. + else if (code == CODE_L1) { *id = BTN_ID_L1; return BTN_L1; } + else if (code == CODE_L2) { *id = BTN_ID_L2; return BTN_L2; } + else if (code == CODE_L3) { *id = BTN_ID_L3; return BTN_L3; } + else if (code == CODE_R1) { *id = BTN_ID_R1; return BTN_R1; } + else if (code == CODE_R2) { *id = BTN_ID_R2; return BTN_R2; } + else if (code == CODE_R3) { *id = BTN_ID_R3; return BTN_R3; } + else if (code == CODE_PLUS) { *id = BTN_ID_PLUS; return BTN_PLUS; } + else if (code == CODE_MINUS) { *id = BTN_ID_MINUS; return BTN_MINUS; } + else if (code == CODE_POWER) { *id = BTN_ID_POWER; return BTN_POWER; } + return BTN_NONE; +} + +static int button_from_joy(int joy, int *id) { + if (joy == JOY_UP) { *id = BTN_ID_DPAD_UP; return BTN_DPAD_UP; } + else if (joy == JOY_DOWN) { *id = BTN_ID_DPAD_DOWN; return BTN_DPAD_DOWN; } + else if (joy == JOY_LEFT) { *id = BTN_ID_DPAD_LEFT; return BTN_DPAD_LEFT; } + else if (joy == JOY_RIGHT) { *id = BTN_ID_DPAD_RIGHT; return BTN_DPAD_RIGHT; } + else if (joy == JOY_A) { *id = BTN_ID_A; return BTN_A; } + else if (joy == JOY_B) { *id = BTN_ID_B; return BTN_B; } + else if (joy == JOY_X) { *id = BTN_ID_X; return BTN_X; } + else if (joy == JOY_Y) { *id = BTN_ID_Y; return BTN_Y; } + else if (joy == JOY_START) { *id = BTN_ID_START; return BTN_START; } + else if (joy == JOY_SELECT) { *id = BTN_ID_SELECT; return BTN_SELECT; } + else if (joy == JOY_MENU) { *id = BTN_ID_MENU; return BTN_MENU; } + else if (joy == JOY_MENU_ALT) { *id = BTN_ID_MENU; return BTN_MENU; } + else if (joy == JOY_MENU_ALT2){ *id = BTN_ID_MENU; return BTN_MENU; } + else if (joy == JOY_L1) { *id = BTN_ID_L1; return BTN_L1; } + else if (joy == JOY_L2) { *id = BTN_ID_L2; return BTN_L2; } + else if (joy == JOY_L3) { *id = BTN_ID_L3; return BTN_L3; } + else if (joy == JOY_R1) { *id = BTN_ID_R1; return BTN_R1; } + else if (joy == JOY_R2) { *id = BTN_ID_R2; return BTN_R2; } + else if (joy == JOY_R3) { *id = BTN_ID_R3; return BTN_R3; } + else if (joy == JOY_PLUS) { *id = BTN_ID_PLUS; return BTN_PLUS; } + else if (joy == JOY_MINUS) { *id = BTN_ID_MINUS; return BTN_MINUS; } + else if (joy == JOY_POWER) { *id = BTN_ID_POWER; return BTN_POWER; } + return BTN_NONE; +} + +static void apply_hat_axis(int neg_id, int pos_id, int value, uint32_t tick) { + apply_button_state(1 << neg_id, neg_id, value < 0, tick); + apply_button_state(1 << pos_id, pos_id, value > 0, tick); +} + +static void detect_device(void) { + char *device = getenv("DEVICE"); + if (!device) device = "rg35xxplus"; + + // App framebuffer size. RG28XX's panel is physically 480x640 portrait, but + // SDL_ROTATION presents a 640x480 landscape app space — keep FIXED_* there + // and set needs_portrait_sdl for the driver/bootlogo. + panel_w = 640; + panel_h = 480; + needs_portrait_sdl = exactMatch("rg28xx", device); + if (exactMatch("rg34xx", device) || exactMatch("rg34xxsp", device) + || exactMatch("rgsp", device)) { + panel_w = 720; + panel_h = 480; + } else if (exactMatch("rgcubexx", device)) { + panel_w = 720; + panel_h = 720; + } + + // RGB LEDs: rg40xxv (1 bank), rg40xxh / rgcubexx (2 banks). Require MCU. + int is_rg40xxv = exactMatch("rg40xxv", device); + int model_has_rgb = is_rg40xxv || exactMatch("rg40xxh", device) + || exactMatch("rgcubexx", device); + dev_has_rgb = model_has_rgb && exists(H700_LED_TTY) && exists(H700_MCU_PWR); + dev_num_leds = !dev_has_rgb ? 0 : (is_rg40xxv ? 1 : 2); + + // Analog sticks per SKU; every stick clicks (L3 / R3). + dev_has_lstick = 0; + dev_has_rstick = 0; + if (is_rg40xxv) { + dev_has_lstick = 1; + } else if (exactMatch("rg40xxh", device) || exactMatch("rgcubexx", device) + || exactMatch("rg34xxsp", device) || exactMatch("rg35xxh", device) + || exactMatch("rg35xxpro", device)) { + dev_has_lstick = dev_has_rstick = 1; + } +} + +void PLAT_initPlatform(void) { + detect_device(); + + // GFX_init() runs this before PLAT_initVideo(), so the output switch (and + // the fb resize it implies) happens while no EGL surface exists — the mali + // winsys then latches the new fb geometry when SDL video comes up. SetHDMI + // is idempotent, so every app start converges the output to the cable + // state; hotplug while running is handled by the existing GFX_hdmiChanged + // quit-and-relaunch plumbing landing back here. + hdmi_active = GetHDMI(); + SetHDMI(hdmi_active); + + // NOTE: should_rotate must stay 0 even on the RG28XX. Its portrait panel is + // handled entirely by the mali SDL driver (SDL_ROTATION=1 in launch.sh), so + // the app-side coordinate space is plain 640x480 landscape; setting the flag + // makes setRectToAspectRatio() swap axes a second time and break minarch's + // Aspect/Fullscreen scaling. + // On HDMI the fb is 1280x720 landscape, so that rotation must be off; this + // overrides the launch.sh export for the lifetime of this process. + if (needs_portrait_sdl) + setenv("SDL_ROTATION", hdmi_active ? "0" : "1", 1); +} + +static SDL_Joystick **joysticks = NULL; +static int num_joysticks = 0; + +// The built-in gpio-keys pad is handled via raw evdev (above); opening it as an +// SDL joystick too would feed poll_sdl_input() duplicate events interpreted with +// the Bluetooth-pad JOY_* layout (and the pad's SDL button indices are shifted +// by its ESC/VOL keys anyway). SDL joysticks are for external pads only. +static int is_builtin_pad(const char *name) { + return name && strcmp(name, "ANBERNIC-keys") == 0; +} + +void PLAT_initInput(void) { + detect_device(); + for (int i = 0; i < H700_INPUT_COUNT; i++) + input_fds[i] = -1; + last_input_scan = 0; + + if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) + LOG_error("Failed initializing joysticks: %s\n", SDL_GetError()); + SDL_JoystickEventState(SDL_ENABLE); + int total = SDL_NumJoysticks(); + if (total > 0) { + joysticks = (SDL_Joystick **)malloc(sizeof(SDL_Joystick *) * total); + for (int i = 0; i < total; i++) { + const char *name = SDL_JoystickNameForIndex(i); + if (is_builtin_pad(name)) { + LOG_info("Skipping built-in joystick %d: %s (handled via evdev)\n", i, name); + continue; + } + SDL_Joystick *joy = SDL_JoystickOpen(i); + if (!joy) { + LOG_error("Failed to open joystick %d: %s\n", i, SDL_GetError()); + continue; + } + joysticks[num_joysticks++] = joy; + LOG_info("Opening joystick %d: %s\n", i, SDL_JoystickName(joy)); + } + } + scan_evdev_inputs(); +} + +void PLAT_quitInput(void) { + for (int i = 0; i < H700_INPUT_COUNT; i++) + close_evdev_input(i); + + if (joysticks) { + for (int i = 0; i < num_joysticks; i++) { + if (SDL_JoystickGetAttached(joysticks[i])) { + LOG_info("Closing joystick %d: %s\n", i, SDL_JoystickName(joysticks[i])); + SDL_JoystickClose(joysticks[i]); + } + } + free(joysticks); + joysticks = NULL; + num_joysticks = 0; + } + if (wake_fd >= 0) { + close(wake_fd); + wake_fd = -1; + } + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); +} + +static void poll_sdl_input(uint32_t tick) { + SDL_Event event; + while (SDL_PollEvent(&event)) { + int btn = BTN_NONE; + int pressed = 0; + int id = -1; + + if (event.type == SDL_JOYBUTTONDOWN || event.type == SDL_JOYBUTTONUP) { + pressed = event.type == SDL_JOYBUTTONDOWN; + btn = button_from_joy(event.jbutton.button, &id); + } + else if (event.type == SDL_JOYHATMOTION) { + int hat = event.jhat.value; + apply_button_state(BTN_DPAD_UP, BTN_ID_DPAD_UP, hat & SDL_HAT_UP, tick); + apply_button_state(BTN_DPAD_DOWN, BTN_ID_DPAD_DOWN, hat & SDL_HAT_DOWN, tick); + apply_button_state(BTN_DPAD_LEFT, BTN_ID_DPAD_LEFT, hat & SDL_HAT_LEFT, tick); + apply_button_state(BTN_DPAD_RIGHT, BTN_ID_DPAD_RIGHT, hat & SDL_HAT_RIGHT, tick); + continue; + } + else if (event.type == SDL_JOYAXISMOTION) { + int axis = event.jaxis.axis; + int val = event.jaxis.value; + + if (axis == AXIS_L2) { + btn = BTN_L2; + id = BTN_ID_L2; + pressed = val > 0; + } + else if (axis == AXIS_R2) { + btn = BTN_R2; + id = BTN_ID_R2; + pressed = val > 0; + } + else if (axis == AXIS_LX) { + pad.laxis.x = val; + PAD_setAnalog(BTN_ID_ANALOG_LEFT, BTN_ID_ANALOG_RIGHT, val, tick + PAD_REPEAT_DELAY); + continue; + } + else if (axis == AXIS_LY) { + pad.laxis.y = val; + PAD_setAnalog(BTN_ID_ANALOG_UP, BTN_ID_ANALOG_DOWN, val, tick + PAD_REPEAT_DELAY); + continue; + } + else if (axis == AXIS_RX) { + pad.raxis.x = val; + continue; + } + else if (axis == AXIS_RY) { + pad.raxis.y = val; + continue; + } + + if (!pressed && btn != BTN_NONE && !(pad.is_pressed & btn)) + btn = BTN_NONE; + } + else if (event.type == SDL_QUIT) { + PWR_powerOff(0); + continue; + } + else if (event.type == SDL_JOYDEVICEADDED || event.type == SDL_JOYDEVICEREMOVED) { + PAD_update(&event); + continue; + } + + apply_button_state(btn, id, pressed, tick); + } +} + +static void poll_evdev_input(uint32_t tick) { + struct input_event event; + + for (int i = 0; i < H700_INPUT_COUNT; i++) { + int input = input_fds[i]; + if (input < 0) + continue; + + errno = 0; + while (read(input, &event, sizeof(event)) == sizeof(event)) { + if (event.type != EV_KEY && event.type != EV_ABS) + continue; + + int btn = BTN_NONE; + int pressed = 0; + int id = -1; + int code = event.code; + int value = event.value; + + if (event.type == EV_KEY) { + if (value > 1) + continue; + pressed = value; + btn = button_from_code(code, &id); + } + else if (event.type == EV_ABS) { + if (code == RAW_HATY) { + apply_hat_axis(BTN_ID_DPAD_UP, BTN_ID_DPAD_DOWN, value, tick); + continue; + } + else if (code == RAW_HATX) { + apply_hat_axis(BTN_ID_DPAD_LEFT, BTN_ID_DPAD_RIGHT, value, tick); + continue; + } + else if (code == RAW_LSX) { + pad.laxis.x = (value * 32767) / 4096; + PAD_setAnalog(BTN_ID_ANALOG_LEFT, BTN_ID_ANALOG_RIGHT, pad.laxis.x, tick + PAD_REPEAT_DELAY); + continue; + } + else if (code == RAW_LSY) { + pad.laxis.y = (value * 32767) / 4096; + PAD_setAnalog(BTN_ID_ANALOG_UP, BTN_ID_ANALOG_DOWN, pad.laxis.y, tick + PAD_REPEAT_DELAY); + continue; + } + else if (code == RAW_RSX) { + pad.raxis.x = (value * 32767) / 4096; + continue; + } + else if (code == RAW_RSY) { + pad.raxis.y = (value * 32767) / 4096; + continue; + } + } + + apply_button_state(btn, id, pressed, tick); + } + + if (errno && errno != EAGAIN && errno != EWOULDBLOCK) + close_evdev_input(i); + } +} + +// wake_fd is a second, independent open of event0 used by PLAT_shouldWake. +// It must be kept drained while awake, otherwise the power-key release that +// triggers the next sleep is still buffered when PWR_waitForWake starts +// polling and the device wakes back up instantly. +static void drain_wake_fd(void) { + if (wake_fd < 0) + wake_fd = open("/dev/input/event0", O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (wake_fd < 0) return; + + struct input_event event; + errno = 0; + while (read(wake_fd, &event, sizeof(event)) == sizeof(event)); + if (errno && errno != EAGAIN && errno != EWOULDBLOCK) { + close(wake_fd); + wake_fd = -1; + } +} + +void PLAT_pollInput(void) { + pad.just_pressed = BTN_NONE; + pad.just_released = BTN_NONE; + pad.just_repeated = BTN_NONE; + + uint32_t tick = SDL_GetTicks(); + for (int i = 0; i < BTN_ID_COUNT; i++) { + int btn = 1 << i; + if ((pad.is_pressed & btn) && (tick >= pad.repeat_at[i])) { + pad.just_repeated |= btn; + pad.repeat_at[i] += PAD_REPEAT_INTERVAL; + } + } + + scan_evdev_inputs(); + poll_sdl_input(tick); + poll_evdev_input(tick); + + drain_wake_fd(); + + int lid_open; + if (lid.has_lid && PLAT_lidChanged(&lid_open) && !lid_open) + PWR_requestSleep(); +} + +void PLAT_updateInput(const SDL_Event *event) { + switch (event->type) { + case SDL_JOYDEVICEADDED: { + int device_index = event->jdevice.which; + const char *name = SDL_JoystickNameForIndex(device_index); + if (is_builtin_pad(name)) { + LOG_info("Skipping built-in joystick %d: %s (handled via evdev)\n", device_index, name); + break; + } + SDL_Joystick *new_joy = SDL_JoystickOpen(device_index); + if (new_joy) { + joysticks = realloc(joysticks, sizeof(SDL_Joystick *) * (num_joysticks + 1)); + joysticks[num_joysticks++] = new_joy; + LOG_info("Joystick added at index %d: %s\n", device_index, SDL_JoystickName(new_joy)); + } else { + LOG_error("Failed to open added joystick at index %d: %s\n", device_index, SDL_GetError()); + } + break; + } + + case SDL_JOYDEVICEREMOVED: { + SDL_JoystickID removed_id = event->jdevice.which; + for (int i = 0; i < num_joysticks; ++i) { + if (SDL_JoystickInstanceID(joysticks[i]) == removed_id) { + LOG_info("Joystick removed: %s\n", SDL_JoystickName(joysticks[i])); + SDL_JoystickClose(joysticks[i]); + + // Shift down the remaining entries + for (int j = i; j < num_joysticks - 1; ++j) + joysticks[j] = joysticks[j + 1]; + num_joysticks--; + + if (num_joysticks == 0) { + free(joysticks); + joysticks = NULL; + } else { + joysticks = realloc(joysticks, sizeof(SDL_Joystick *) * num_joysticks); + } + break; + } + } + break; + } + + default: + break; + } +} + +void PLAT_getBatteryStatus(int* is_charging, int* charge) { + PLAT_getBatteryStatusFine(is_charging, charge); + + // worry less about battery and more about the game you're playing + if (*charge>80) *charge = 100; + else if (*charge>60) *charge = 80; + else if (*charge>40) *charge = 60; + else if (*charge>20) *charge = 40; + else if (*charge>10) *charge = 20; + else *charge = 10; +} + +void PLAT_getCPUTemp() { + perf.cpu_temp = getInt("/sys/devices/virtual/thermal/thermal_zone0/temp")/1000; +} + +void PLAT_getCPUSpeed() +{ + perf.cpu_speed = getInt("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq")/1000; +} + +void PLAT_getGPUTemp() { + perf.gpu_temp = getInt("/sys/devices/virtual/thermal/thermal_zone1/temp")/1000; +} + +void PLAT_getGPUSpeed() { + static char* path = NULL; + static int resolved = 0; + + if (!resolved) { + static char* candidates[] = { + "/sys/class/devfreq/gpu/cur_freq", + "/sys/devices/platform/gpu/devfreq/gpu/cur_freq", + "/sys/devices/platform/soc@03000000/1800000.gpu/devfreq/1800000.gpu/cur_freq", + "/sys/devices/platform/soc/1800000.gpu/devfreq/1800000.gpu/cur_freq", + "/sys/kernel/debug/clk/gpu0/clk_rate", + "/sys/kernel/debug/clk/pll_gpu/clk_rate", + NULL, + }; + for (int i = 0; candidates[i]; i++) { + if (access(candidates[i], R_OK) == 0) { + path = candidates[i]; + break; + } + } + resolved = 1; + } + + int speed = path ? getInt(path) : 0; + perf.gpu_speed = speed > 0 ? speed / 1000000 : 648; // MHz +} + +static struct WIFI_connection connection = { + .valid = false, + .freq = -1, + .link_speed = -1, + .noise = -1, + .rssi = -1, + .ip = {0}, + .ssid = {0}, +}; + +static inline void connection_reset(struct WIFI_connection *connection_info) +{ + connection_info->valid = false; + connection_info->freq = -1; + connection_info->link_speed = -1; + connection_info->noise = -1; + connection_info->rssi = -1; + *connection_info->ip = '\0'; + *connection_info->ssid = '\0'; +} + +static bool bluetoothConnected = false; + +void PLAT_getNetworkStatus(int* is_online) +{ + if(WIFI_enabled()) + WIFI_connectionInfo(&connection); + else + connection_reset(&connection); + + if(is_online) + *is_online = (connection.valid && connection.ssid[0] != '\0'); + + if(BT_enabled()) { + bluetoothConnected = PLAT_bluetoothConnected(); + } + else + bluetoothConnected = false; +} + +void PLAT_getBatteryStatusFine(int *is_charging, int *charge) +{ + if(is_charging) { + int charger_present = getInt("/sys/class/power_supply/axp2202-usb/online"); + *is_charging = (charger_present == 1); + } + if(charge) { + *charge = getInt("/sys/class/power_supply/axp2202-battery/capacity"); + } +} + +int PLAT_isUSBConnected(void) +{ + // Not implemented for this platform yet. + return 0; +} + +void PLAT_enableBacklight(int enable) { + if (enable) { + putInt("/sys/class/power_supply/axp2202-battery/work_led", 0); + putInt("/sys/class/graphics/fb0/blank", 0); + SetBrightness(GetBrightness()); + // the suspend script drops mcu_pwr while we sleep, so the MCU comes + // back blank -- forget the cached frame so the next commit repaints it + LED_invalidateCache(); + } + else { + SetRawBrightness(0); + putInt("/sys/class/graphics/fb0/blank", 1); + putInt("/sys/class/power_supply/axp2202-battery/work_led", 1); + } +} + +void PLAT_powerOff(int reboot) { + if (CFG_getHaptics()) { + VIB_singlePulse(VIB_bootStrength, VIB_bootDuration_ms); + } + system("rm -f /tmp/nextui_exec && sync"); + sleep(2); + + SetRawVolume(MUTE_VOLUME_RAW); + PLAT_enableBacklight(0); + LED_shutdown(); + SND_quit(); + VIB_quit(); + PWR_quit(); + GFX_quit(); + + system("cat /dev/zero > /dev/fb0 2>/dev/null"); + if(reboot > 0) + touch("/tmp/reboot"); + else + touch("/tmp/poweroff"); + sync(); + exit(0); +} + +int PLAT_supportsDeepSleep(void) { return 1; } + +#define LID_PATH "/sys/class/power_supply/axp2202-battery/hallkey" + +void PLAT_initLid(void) { + lid.has_lid = exists(LID_PATH); + if (lid.has_lid) + lid.is_open = getInt(LID_PATH); +} + +int PLAT_lidChanged(int* state) { + if (!lid.has_lid) return 0; + + int lid_open = getInt(LID_PATH); + if (lid_open != lid.is_open) { + lid.is_open = lid_open; + if (state) *state = lid_open; + return 1; + } + return 0; +} + +int PLAT_shouldWake(void) { + int lid_open = 1; + if (lid.has_lid && PLAT_lidChanged(&lid_open) && lid_open) + return 1; + + if (wake_fd < 0) + wake_fd = open("/dev/input/event0", O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (wake_fd < 0) return 0; + + struct input_event event; + int should_wake = 0; + errno = 0; + while (read(wake_fd, &event, sizeof(event)) == sizeof(event)) { + if (event.type == EV_KEY && event.code == CODE_POWER && event.value == 0) { + if (lid.has_lid && !lid.is_open) { + should_wake = 0; + continue; + } + LOG_debug("PLAT_shouldWake: power key release, waking\n"); + should_wake = 1; + } + } + if (errno && errno != EAGAIN && errno != EWOULDBLOCK) { + close(wake_fd); + wake_fd = -1; + } + return should_wake; +} + +/////////////////////////////// + +double get_time_sec() { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + return ts.tv_sec + ts.tv_nsec / 1e9; // Convert to seconds +} +double get_process_cpu_time_sec() { + // this gives cpu time in nanoseconds needed to accurately calculate cpu usage in very short time frames. + // unfortunately about 20ms between meassures seems the lowest i can go to get accurate results + // maybe in the future i will find and even more granual way to get cpu time, but might just be a limit of C or Linux alltogether + struct timespec ts; + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); + return ts.tv_sec + ts.tv_nsec / 1e9; // Convert to seconds +} + +static pthread_mutex_t currentcpuinfo; +// a roling average for the display values of about 2 frames, otherwise they are unreadable jumping too fast up and down and stuff to read +#define ROLLING_WINDOW 120 + +void *PLAT_cpu_monitor(void *arg) { + if (!Perf_tryBeginCPUMonitor()) return NULL; + + double prev_real_time = get_time_sec(); + double prev_cpu_time = get_process_cpu_time_sec(); + + double cpu_usage_history[ROLLING_WINDOW] = {0}; + int history_index = 0; + int history_count = 0; + + while (Perf_isCPUMonitorEnabled()) { + double curr_real_time = get_time_sec(); + double curr_cpu_time = get_process_cpu_time_sec(); + + double elapsed_real_time = curr_real_time - prev_real_time; + double elapsed_cpu_time = curr_cpu_time - prev_cpu_time; + + if (elapsed_real_time > 0) { + double cpu_usage = (elapsed_cpu_time / elapsed_real_time) * 100.0; + + pthread_mutex_lock(¤tcpuinfo); + + cpu_usage_history[history_index] = cpu_usage; + history_index = (history_index + 1) % ROLLING_WINDOW; + if (history_count < ROLLING_WINDOW) history_count++; + + double sum_cpu_usage = 0; + for (int i = 0; i < history_count; i++) sum_cpu_usage += cpu_usage_history[i]; + perf.cpu_usage = sum_cpu_usage / history_count; + + pthread_mutex_unlock(¤tcpuinfo); + } + + prev_real_time = curr_real_time; + prev_cpu_time = curr_cpu_time; + usleep(100000); + } + + Perf_endCPUMonitor(); + return NULL; +} + +void PLAT_setCPUSpeed(int speed) { + const char* mode; + switch (speed) { + case CPU_SPEED_AUTO: mode = "auto"; break; + case CPU_SPEED_PERFORMANCE: mode = "performance"; break; + case CPU_SPEED_POWERSAVE: mode = "powersave"; break; + default: return; + } + + const char* system_path = getenv("SYSTEM_PATH"); + if (!system_path) { + LOG_info("WARNING: SYSTEM_PATH not set, cannot run governor script\n"); + return; + } + char cmd[512]; + int n = snprintf(cmd, sizeof(cmd), "sh \"%s/bin/governor.sh\" \"%s\"", system_path, mode); + if (n < 0 || n >= (int)sizeof(cmd)) { + LOG_info("WARNING: SYSTEM_PATH too long for governor script path\n"); + return; + } + int ret = system(cmd); + if (ret != 0) LOG_info("WARNING: governor script exited with status %d for mode '%s'\n", ret, mode); +} + +#define MAX_STRENGTH 0xFFFF +#define MIN_VOLTAGE 500000 +#define MAX_VOLTAGE 3300000 +#define RUMBLE_PATH "/sys/class/power_supply/axp2202-battery/moto" + +void PLAT_setRumble(int strength) { + putInt(RUMBLE_PATH, (strength) ? 1 : 0); +} + +int PLAT_pickSampleRate(int requested, int max) { + // bluetooth: allow limiting the maximum to improve compatibility + // NOTE: called from SND_init before InitSettings, so msettings shared + // memory (GetAudioSink) must not be touched here + if(PLAT_bluetoothConnected()) + return MIN(requested, CFG_getBluetoothSamplingrateLimit()); + + return MIN(requested, max); +} + +void PLAT_overrideMute(int mute) { + system(mute ? "amixer -q sset 'SPK' off" : "amixer -q sset 'SPK' on"); +} + +char* PLAT_getModel(void) { + static char model_buf[64]; + char* model = getenv("RGXX_MODEL"); + if (model) { + snprintf(model_buf, sizeof(model_buf), "%s", model); + return model_buf; + } + return "Anbernic RG XX"; +} + +void PLAT_getOsVersionInfo(char* output_str, size_t max_len) +{ + char os_release[512] = {0}; + char kernel[128] = {0}; + FILE *fp = popen(". /etc/os-release 2>/dev/null; printf '%s' \"$PRETTY_NAME\"", "r"); + if (fp) { + fgets(os_release, sizeof(os_release), fp); + pclose(fp); + } + getFile("/proc/sys/kernel/osrelease", kernel, sizeof(kernel)); + trimTrailingNewlines(os_release); + trimTrailingNewlines(kernel); + snprintf(output_str, max_len, "%s%s%s", os_release[0] ? os_release : "Anbernic stock OS", kernel[0] ? " / Linux " : "", kernel); +} + +bool PLAT_btIsConnected(void) +{ + return bluetoothConnected; +} + +ConnectionStrength PLAT_connectionStrength(void) { + if(!WIFI_enabled() || !connection.valid || connection.rssi == -1) + return SIGNAL_STRENGTH_OFF; + else if (connection.rssi == 0) + return SIGNAL_STRENGTH_DISCONNECTED; + else if (connection.rssi >= -60) + return SIGNAL_STRENGTH_HIGH; + else if (connection.rssi >= -70) + return SIGNAL_STRENGTH_MED; + else + return SIGNAL_STRENGTH_LOW; +} + +// LED support lives in led.c, included at the bottom of this file. + +////////////////////////////////////////////// + +bool PLAT_canTurbo(void) { return false; } + +int PLAT_toggleTurbo(int btn_id) +{ + return 0; +} + +void PLAT_clearTurbo() { +} + +////////////////////////////////////////////// + +int PLAT_setDateTime(int y, int m, int d, int h, int i, int s) { + char cmd[512]; + int n = snprintf(cmd, sizeof(cmd), "date -s '%d-%d-%d %d:%d:%d'; hwclock -u -w", y,m,d,h,i,s); + if (n < 0 || n >= (int)sizeof(cmd)) return -1; + system(cmd); + return 0; // why does this return an int? +} + +#define MAX_LINE_LENGTH 200 +#define ZONE_PATH "/usr/share/zoneinfo" +#define ZONE_TAB_PATH ZONE_PATH "/zone.tab" + +static char cached_timezones[MAX_TIMEZONES][MAX_TZ_LENGTH]; +static int cached_tz_count = -1; + +int compare_timezones(const void *a, const void *b) { + return strcmp((const char *)a, (const char *)b); +} + +void PLAT_initTimezones() { + if (cached_tz_count != -1) { // Already initialized + return; + } + + FILE *file = fopen(ZONE_TAB_PATH, "r"); + if (!file) { + LOG_info("Error opening file %s\n", ZONE_TAB_PATH); + return; + } + + char line[MAX_LINE_LENGTH]; + cached_tz_count = 0; + + while (fgets(line, sizeof(line), file)) { + // Skip comment lines + if (line[0] == '#' || strlen(line) < 3) { + continue; + } + + char *token = strtok(line, "\t"); // Skip country code + if (!token) continue; + + token = strtok(NULL, "\t"); // Skip latitude/longitude + if (!token) continue; + + token = strtok(NULL, "\t\n"); // Extract timezone + if (!token) continue; + + // Check for duplicates before adding + int duplicate = 0; + for (int i = 0; i < cached_tz_count; i++) { + if (strcmp(cached_timezones[i], token) == 0) { + duplicate = 1; + break; + } + } + + if (!duplicate && cached_tz_count < MAX_TIMEZONES) { + strncpy(cached_timezones[cached_tz_count], token, MAX_TZ_LENGTH - 1); + cached_timezones[cached_tz_count][MAX_TZ_LENGTH - 1] = '\0'; // Ensure null-termination + cached_tz_count++; + } + } + + fclose(file); + + // Sort the list alphabetically + qsort(cached_timezones, cached_tz_count, MAX_TZ_LENGTH, compare_timezones); +} + +void PLAT_getTimezones(char timezones[MAX_TIMEZONES][MAX_TZ_LENGTH], int *tz_count) { + if (cached_tz_count == -1) { + LOG_warn("Error: Timezones not initialized. Call PLAT_initTimezones first.\n"); + *tz_count = 0; + return; + } + + memcpy(timezones, cached_timezones, sizeof(cached_timezones)); + *tz_count = cached_tz_count; +} + +char *PLAT_getCurrentTimezone() { + char *output = (char *)malloc(256); + if (!output) { + return NULL; + } + FILE *fp = popen("timedatectl show -p Timezone --value 2>/dev/null", "r"); + if (!fp) { + free(output); + return NULL; + } + fgets(output, 256, fp); + pclose(fp); + trimTrailingNewlines(output); + + return output; +} + +void PLAT_setCurrentTimezone(const char* tz) { + if (cached_tz_count == -1) { + LOG_warn("Error: Timezones not initialized. Call PLAT_initTimezones first.\n"); + return; + } + + char cmd[512]; + snprintf(cmd, sizeof(cmd), "timedatectl set-timezone '%s'", tz); + system(cmd); +} + +bool PLAT_getNetworkTimeSync(void) { + char output[16] = {0}; + FILE *fp = popen("timedatectl show -p NTP --value 2>/dev/null", "r"); + if (!fp) { + return false; + } + fgets(output, sizeof(output), fp); + pclose(fp); + return output[0] == 'y' || output[0] == 'Y'; +} + +void PLAT_setNetworkTimeSync(bool on) { + system(on ? "timedatectl set-ntp true" : "timedatectl set-ntp false"); +} + +///////////////////////// + +// We use the generic video implementation here +#include "generic_video.c" + +///////////////////////// + +// We use the generic wifi implementation here +#define WIFI_SOCK_DIR "/tmp/wifi/sockets" +#include "generic_wifi.c" + +///////////////////////// + +// We use the generic bluetooth implementation here +#include "generic_bt.c" + +///////////////////////// + +// RGB LEDs (RG40XX H/V and RG CubeXX only) +#include "led.c" diff --git a/workspace/h700/platform/platform.h b/workspace/h700/platform/platform.h new file mode 100644 index 000000000..4487c3a10 --- /dev/null +++ b/workspace/h700/platform/platform.h @@ -0,0 +1,202 @@ +// h700 + +#ifndef PLATFORM_H +#define PLATFORM_H + +/////////////////////////////// + +#ifdef SDL +# include "sdl.h" +#endif + +/////////////////////////////// + +extern int panel_w; +extern int panel_h; +extern int hdmi_active; +extern int dev_has_lstick; +extern int dev_has_rstick; +extern int dev_has_rgb; +extern int dev_num_leds; +extern int needs_portrait_sdl; // DEVICE=rg28xx: SDL rotates onto the portrait panel + +/////////////////////////////// + +#define BUTTON_UP BUTTON_NA +#define BUTTON_DOWN BUTTON_NA +#define BUTTON_LEFT BUTTON_NA +#define BUTTON_RIGHT BUTTON_NA + +#define BUTTON_SELECT BUTTON_NA +#define BUTTON_START BUTTON_NA + +#define BUTTON_A BUTTON_NA +#define BUTTON_B BUTTON_NA +#define BUTTON_X BUTTON_NA +#define BUTTON_Y BUTTON_NA + +#define BUTTON_L1 BUTTON_NA +#define BUTTON_R1 BUTTON_NA +#define BUTTON_L2 BUTTON_NA +#define BUTTON_R2 BUTTON_NA +#define BUTTON_L3 BUTTON_NA +#define BUTTON_R3 BUTTON_NA +#define BUTTON_L4 BUTTON_NA +#define BUTTON_R4 BUTTON_NA + +#define BUTTON_MENU BUTTON_NA +#define BUTTON_MENU_ALT BUTTON_NA +#define BUTTON_POWER 116 +#define BUTTON_PLUS BUTTON_NA +#define BUTTON_MINUS BUTTON_NA + +/////////////////////////////// + +#define CODE_UP 103 +#define CODE_DOWN 108 +#define CODE_LEFT 105 +#define CODE_RIGHT 106 + +#define CODE_SELECT 310 +#define CODE_START 311 + +#define CODE_A 304 +#define CODE_B 305 +#define CODE_X 307 +#define CODE_Y 306 + +#define CODE_L1 308 +#define CODE_R1 309 +#define CODE_L2 314 +#define CODE_R2 315 +#define CODE_L4 CODE_NA +#define CODE_R4 CODE_NA +#define CODE_L3 (dev_has_lstick ? 313 : CODE_NA) +#define CODE_R3 (dev_has_rstick ? 316 : CODE_NA) + +#define CODE_MENU 312 +#define CODE_MENU_ALT 354 +#define CODE_POWER 116 + +#define CODE_PLUS 115 +#define CODE_MINUS 114 + +/////////////////////////////// + // HATS +#define JOY_UP JOY_NA +#define JOY_DOWN JOY_NA +#define JOY_LEFT JOY_NA +#define JOY_RIGHT JOY_NA + +#define JOY_SELECT 6 +#define JOY_START 7 + +#define JOY_A 0 +#define JOY_B 1 +#define JOY_X 3 +#define JOY_Y 2 + +#define JOY_L1 4 +#define JOY_R1 5 +#define JOY_L2 10 +#define JOY_R2 11 +#define JOY_L4 JOY_NA +#define JOY_R4 JOY_NA +#define JOY_L3 (dev_has_lstick ? 9 : JOY_NA) +#define JOY_R3 (dev_has_rstick ? 12 : JOY_NA) + +#define JOY_MENU 8 +#define JOY_POWER JOY_NA +#define JOY_PLUS 16 +#define JOY_MINUS 15 + +/////////////////////////////// +// USER-ASSIGNABLE BUTTONS +// H700 devices have no dedicated FN1/FN2/HOME buttons for pak launch actions. +#define BTN_FN1 BTN_NONE +#define BTN_FN2 BTN_NONE +#define BTN_FN3 BTN_NONE +#define BTN_FN1_NAME "" +#define BTN_FN2_NAME "" +#define BTN_FN3_NAME "" + +/////////////////////////////// + +#define AXIS_L2 AXIS_NA +#define AXIS_R2 AXIS_NA + +#define AXIS_LX (dev_has_lstick ? 0 : AXIS_NA) +#define AXIS_LY (dev_has_lstick ? 1 : AXIS_NA) +#define AXIS_RX (dev_has_rstick ? 2 : AXIS_NA) +#define AXIS_RY (dev_has_rstick ? 3 : AXIS_NA) + +/////////////////////////////// + +#define BTN_RESUME BTN_X +#define BTN_SLEEP BTN_POWER +#define BTN_WAKE BTN_POWER +#define BTN_MOD_VOLUME BTN_NONE +#define BTN_MOD_BRIGHTNESS BTN_MENU +#define BTN_MOD_COLORTEMP BTN_SELECT +#define BTN_MOD_PLUS BTN_PLUS +#define BTN_MOD_MINUS BTN_MINUS + +/////////////////////////////// + +// While an HDMI cable is connected the whole app runs at 1280x720 (the fb is +// hardware-scaled to a 1080p60 signal by the display engine — see SetHDMI in +// libmsettings). hdmi_active and panel_w/panel_h are latched once per process +// in PLAT_initPlatform; the existing hotplug quit-and-relaunch plumbing +// restarts apps on cable changes. +// Values must match HDMI_LOGICAL_* in libmsettings/msettings.c. +#define HAS_HDMI 1 +#define HDMI_WIDTH 1280 +#define HDMI_HEIGHT 720 +#define HDMI_PITCH (HDMI_WIDTH * FIXED_BPP) +#define HDMI_SIZE (HDMI_PITCH * HDMI_HEIGHT) + +#define FIXED_SCALE 2 +// panel_w/panel_h: app framebuffer — 720x480 (rg34xx/rg34xxsp/rgsp), +// 720x720 (rgcubexx), else 640x480. RG28XX stays 640x480 here; portrait is +// handled by SDL_ROTATION via needs_portrait_sdl. +#define FIXED_WIDTH (hdmi_active?HDMI_WIDTH:panel_w) +#define FIXED_HEIGHT (hdmi_active?HDMI_HEIGHT:panel_h) +#define FIXED_BPP 2 +#define FIXED_DEPTH (FIXED_BPP * 8) +#define FIXED_PITCH (FIXED_WIDTH * FIXED_BPP) +#define FIXED_SIZE (FIXED_PITCH * FIXED_HEIGHT) + +/////////////////////////////// + +// Rows that fit above the button hints: (FIXED_HEIGHT/FIXED_SCALE - 2*PADDING - PILL_SIZE) / PILL_SIZE. +// The 480p layout needs the standard 10-unit padding so six rows and the +// bottom hints keep the same vertical spacing. The roomier 720p layouts retain +// their existing 5-unit edge padding. +#define MAIN_ROW_COUNT ((hdmi_active||panel_h>=720)?10:6) +#define QUICK_SWITCHER_COUNT 3 +#define PADDING ((hdmi_active||panel_h>=720)?5:10) + +/////////////////////////////// + +#define SDCARD_PATH "/mnt/SDCARD" +#define MUTE_VOLUME_RAW 0 + +#define SCREEN_FPS 60.0 +// ceiling, not the count: only rg40xxh/v and rgcubexx have RGB LEDs, and +// the V populates one bank where the others populate two. PLAT_getNumLeds() +// reports what the running device actually has. +#define MAX_LIGHTS 2 + +// stock Anbernic boot logo: bootlogo.bmp on the vfat boot-resource partition +#define BOOTLOGO_PARTITION "/dev/mmcblk0p2" +// presets are keyed by panel resolution, not device name +#define BOOTLOGO_RESOLUTION_DIRS 1 +// The RG28XX panel is mounted portrait: the UI is rotated onto it by the SDL +// driver, but the bootloader blits bootlogo.bmp panel-native, so the 480x640 +// presets are authored 90° CCW and must be rotated CW to preview how they +// will actually appear at boot. +#define BOOTLOGO_PREVIEW_ROTATE_CW (needs_portrait_sdl) + +/////////////////////////////// + +#endif diff --git a/workspace/h700/poweroff_next/makefile b/workspace/h700/poweroff_next/makefile new file mode 100644 index 000000000..f44ffc30d --- /dev/null +++ b/workspace/h700/poweroff_next/makefile @@ -0,0 +1,39 @@ +########################################################### + +ifeq (,$(PLATFORM)) +PLATFORM=$(UNION_PLATFORM) +endif + +ifeq (,$(PLATFORM)) + $(error please specify PLATFORM, eg. PLATFORM=h700 make) +endif + +ifeq (,$(CROSS_COMPILE)) + $(error missing CROSS_COMPILE for this toolchain) +endif + +########################################################### + +include ../platform/makefile.env + +########################################################### + +INCDIR = -I. -I../../all/common -I../platform +SOURCE = poweroff_next.c ../../all/common/utils.c ../../all/common/config.c + +CC = $(CROSS_COMPILE)gcc +# Override CFLAGS and LDFLAGS to not include SDL2 dependencies +CFLAGS = $(OPT) -g -std=gnu11 -Wall -Wextra +CFLAGS += $(INCDIR) -DPLATFORM=\"$(PLATFORM)\" +LDFLAGS = -lpthread -ldl + +BUILDDIR = build/$(PLATFORM) + +# One source, two binaries: reboot_next skips the PMIC power-off sequence. +all: + mkdir -p $(BUILDDIR) + $(CC) $(SOURCE) -o $(BUILDDIR)/poweroff_next.elf $(CFLAGS) $(LDFLAGS) + $(CC) $(SOURCE) -o $(BUILDDIR)/reboot_next.elf $(CFLAGS) -DREBOOT_NEXT $(LDFLAGS) + +clean: + rm -rf $(BUILDDIR) diff --git a/workspace/h700/poweroff_next/poweroff_next.c b/workspace/h700/poweroff_next/poweroff_next.c new file mode 100644 index 000000000..185160608 --- /dev/null +++ b/workspace/h700/poweroff_next/poweroff_next.c @@ -0,0 +1,406 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defines.h" +#include "config.h" + +// H700 counterpart of tg5040's poweroff_next: the AXP2202 needs an explicit +// software power-off, because the kernel's generic axp20x pm_power_off handler +// writes AXP20X_OFF_CTRL (0x32), which is not the power-off register on this +// chip. Without the sequence below the CPU halts but the rails stay up, which +// reads to the user as "the screen went black but it never turned off" — the +// same limbo the Brick had. +// +// Deliberately *not* a straight copy of the tg5040 tool. See run_flush(). + +#define AXP_I2C_ADDR 0x34 +#define AXP_FALLBACK_DEVICE "/dev/i2c-5" +#define I2C_DEVICES_DIR "/sys/bus/i2c/devices" + +// AXP2202 registers (Allwinner BSP names). NOTE the AXP2202 moved the on/off +// control group that the AXP2101 keeps at 0x10 out to 0x27 — writing 0x10 or +// the generic axp20x 0x32 does nothing on this part. +#define AXP_IRQ_EN_FIRST 0x40 +#define AXP_IRQ_EN_LAST 0x44 +#define AXP_IRQ_STATE_FIRST 0x48 +#define AXP_IRQ_STATE_LAST 0x4C +#define AXP_PWROFF_EN 0x22 +#define AXP_SOFT_PWROFF 0x27 + +// PWROFF_EN: bit3 LDO over-current as power-off source, bit1 long-press as +// power-off source, bit2 (die over-temp) cleared, bit0 cleared so a button +// event powers off instead of restarting. +#define AXP_PWROFF_EN_VALUE 0x0A +// SOFT_PWROFF bit0 = power off now. Written as a plain store, not a +// read-modify-write: that also clears bit3 (PWROK pulled low restarts the +// system), which is set on stock H700 firmware and can otherwise bounce the +// SoC back up as the rails collapse. +#define AXP_SOFT_PWROFF_VALUE 0x01 + +// Deliberately tmpfs, not the card: this path unmounts the card, and the only +// case where the log matters is the one where we failed to power off — in which +// case the device is still running and /tmp is right there over SSH. Keeps the +// shutdown path free of card writes. +#define LOG_PATH "/tmp/poweroff_next.txt" + +static FILE *log_fp = NULL; + +#ifdef REBOOT_NEXT +#define TOOL_NAME "reboot_next" +#else +#define TOOL_NAME "poweroff_next" +#endif + +static void log_msg(const char *format, ...) +{ + va_list args; + + if (log_fp) + { + va_start(args, format); + vfprintf(log_fp, format, args); + va_end(args); + fflush(log_fp); + } + + va_start(args, format); + vprintf(format, args); + va_end(args); + fflush(stdout); +} + +static void open_log(void) +{ + log_fp = fopen(LOG_PATH, "w"); + if (log_fp) + setvbuf(log_fp, NULL, _IONBF, 0); // unbuffered: we may lose power mid-write +} + +/////////////////////////////// + +// /mnt/SDCARD is a symlink (or bind mount) onto /mnt/sdcard on H700, so +// /proc/mounts and /proc/*/fd both name the resolved path. Everything that +// compares against the mount point has to use the resolved one. +static void resolve_sdcard(char *out, size_t len) +{ + char resolved[PATH_MAX]; + if (realpath(SDCARD_PATH, resolved) != NULL) + snprintf(out, len, "%s", resolved); + else + snprintf(out, len, "%s", SDCARD_PATH); +} + +static bool is_mounted(const char *path) +{ + FILE *fp = setmntent("/proc/mounts", "r"); + if (!fp) + { + log_msg(TOOL_NAME ": fopen(/proc/mounts): %s\n", strerror(errno)); + return false; + } + + bool mounted = false; + struct mntent *ent; + while ((ent = getmntent(fp)) != NULL) + { + if (strcmp(ent->mnt_dir, path) == 0) + { + mounted = true; + break; + } + } + + endmntent(fp); + return mounted; +} + +static void swapoff_all(void) +{ + FILE *swaps = fopen("/proc/swaps", "r"); + if (!swaps) + return; + + char line[256]; + if (!fgets(line, sizeof(line), swaps)) // header + { + fclose(swaps); + return; + } + + while (fgets(line, sizeof(line), swaps)) + { + char device[128]; + if (sscanf(line, "%127s", device) == 1) + { + if (swapoff(device) != 0 && errno != ENOENT && errno != EINVAL) + log_msg(TOOL_NAME ": swapoff(%s): %s\n", device, strerror(errno)); + } + } + + fclose(swaps); +} + +// Best-effort card flush. Unlike the tg5040 tool this does NOT kill processes. +// On the H700 base OS init respawns the frontend session (`::respawn:` in +// /etc/inittab), so SIGKILLing launch.sh mid-shutdown starts a *new* frontend +// racing the power-off — the exact failure we are here to remove. The PMIC cut +// below is instantaneous and total, so nothing needs to be reaped first; a +// sync plus an unmount attempt is all the protection that buys anything. +static void run_flush(const char *sdcard) +{ + sync(); + swapoff_all(); + + if (umount2(sdcard, MNT_DETACH) != 0) + { + if (errno != EINVAL && errno != ENOENT) + log_msg(TOOL_NAME ": umount2(%s): %s\n", sdcard, strerror(errno)); + } + + if (is_mounted(sdcard)) + log_msg(TOOL_NAME ": %s still mounted; relying on sync\n", sdcard); + + sync(); +} + +/////////////////////////////// + +#ifndef REBOOT_NEXT + +static int axp_open(void) +{ + char device[PATH_MAX]; + snprintf(device, sizeof(device), "%s", AXP_FALLBACK_DEVICE); + + DIR *dir = opendir(I2C_DEVICES_DIR); + if (dir) + { + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) + { + int bus; + unsigned int addr; + if (sscanf(entry->d_name, "%d-%x", &bus, &addr) != 2) + continue; + if (addr != AXP_I2C_ADDR) + continue; + + char name_path[PATH_MAX]; + snprintf(name_path, sizeof(name_path), "%s/%s/name", I2C_DEVICES_DIR, entry->d_name); + + FILE *fp = fopen(name_path, "r"); + if (!fp) + continue; + + char name[64] = {0}; + bool is_axp = fgets(name, sizeof(name), fp) != NULL && strncmp(name, "axp", 3) == 0; + fclose(fp); + + if (is_axp) + { + name[strcspn(name, "\r\n")] = '\0'; + snprintf(device, sizeof(device), "/dev/i2c-%d", bus); + log_msg(TOOL_NAME ": found %s at %s addr 0x%02x\n", name, device, AXP_I2C_ADDR); + break; + } + } + closedir(dir); + } + else + { + log_msg(TOOL_NAME ": opendir(%s): %s\n", I2C_DEVICES_DIR, strerror(errno)); + } + + int fd = open(device, O_RDWR | O_CLOEXEC); + if (fd < 0) + { + log_msg(TOOL_NAME ": open(%s): %s\n", device, strerror(errno)); + return -1; + } + + if (ioctl(fd, I2C_SLAVE, AXP_I2C_ADDR) < 0 && ioctl(fd, I2C_SLAVE_FORCE, AXP_I2C_ADDR) < 0) + { + log_msg(TOOL_NAME ": ioctl(I2C_SLAVE[_FORCE]): %s\n", strerror(errno)); + close(fd); + return -1; + } + + return fd; +} + +static int axp_write(int fd, uint8_t reg, uint8_t value) +{ + uint8_t buffer[2] = {reg, value}; + if (write(fd, buffer, sizeof(buffer)) != (ssize_t)sizeof(buffer)) + { + log_msg(TOOL_NAME ": write 0x%02x to reg 0x%02x failed: %s\n", value, reg, strerror(errno)); + return -1; + } + return 0; +} + +// Mask and clear every PMIC interrupt before cutting the rails. A pending, +// unmasked IRQ holds the AXP's IRQ pin low, and >16ms of that powers the PMU +// straight back on. The power-key edge interrupts (PONP/PONN in IRQ_EN1) are +// armed by stock firmware, so the press that asked for power-off is itself the +// most likely thing to undo it. Status registers are write-1-to-clear. +static void axp_quiesce_irqs(int fd) +{ + for (int reg = AXP_IRQ_EN_FIRST; reg <= AXP_IRQ_EN_LAST; ++reg) + axp_write(fd, (uint8_t)reg, 0x00); + + for (int reg = AXP_IRQ_STATE_FIRST; reg <= AXP_IRQ_STATE_LAST; ++reg) + axp_write(fd, (uint8_t)reg, 0xFF); +} + +static int axp_power_off(bool dry_run) +{ + int fd = axp_open(); + if (fd < 0) + return -1; + + if (dry_run) + { + log_msg(TOOL_NAME ": dry run, would write 0x%02x<-0x%02x then 0x%02x<-0x%02x" + " after masking 0x%02x-0x%02x and clearing 0x%02x-0x%02x\n", + AXP_PWROFF_EN, AXP_PWROFF_EN_VALUE, AXP_SOFT_PWROFF, AXP_SOFT_PWROFF_VALUE, + AXP_IRQ_EN_FIRST, AXP_IRQ_EN_LAST, AXP_IRQ_STATE_FIRST, AXP_IRQ_STATE_LAST); + close(fd); + return 0; + } + + axp_quiesce_irqs(fd); + + axp_write(fd, AXP_PWROFF_EN, AXP_PWROFF_EN_VALUE); + + struct timespec settle = {.tv_sec = 0, .tv_nsec = 50000000}; // 50ms + nanosleep(&settle, NULL); + + int ret = axp_write(fd, AXP_SOFT_PWROFF, AXP_SOFT_PWROFF_VALUE); + close(fd); + + // The rails should drop within milliseconds; give them a moment before the + // kernel fallback so we do not race the PMIC. + struct timespec latch = {.tv_sec = 1, .tv_nsec = 0}; + nanosleep(&latch, NULL); + + return ret; +} + +#endif // !REBOOT_NEXT + +/////////////////////////////// + +static void finalize(void) +{ + sync(); + +#ifdef REBOOT_NEXT + int cmd = LINUX_REBOOT_CMD_RESTART; +#else + int cmd = LINUX_REBOOT_CMD_POWER_OFF; +#endif + + if (syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, NULL) != 0) + log_msg(TOOL_NAME ": reboot syscall failed: %s\n", strerror(errno)); + +#ifdef REBOOT_NEXT + execlp("busybox", "busybox", "reboot", "-f", NULL); + reboot(RB_AUTOBOOT); +#else + execlp("busybox", "busybox", "poweroff", "-f", NULL); + reboot(RB_POWER_OFF); +#endif + + log_msg(TOOL_NAME ": every shutdown method failed: %s\n", strerror(errno)); +} + +int main(int argc, char **argv) +{ + // --dry-run reports what would happen (PMIC bus detection, resolved card + // path, protection setting) and touches nothing. Safe to run on a live + // device; that is the point of it. + bool dry_run = false; + for (int i = 1; i < argc; ++i) + { + if (strcmp(argv[i], "--dry-run") == 0) + dry_run = true; + } + + open_log(); + + // init's shutdown sweep must not take us out mid-sequence. + sigset_t block_set; + sigemptyset(&block_set); + sigaddset(&block_set, SIGTERM); + sigaddset(&block_set, SIGINT); + sigaddset(&block_set, SIGHUP); + sigprocmask(SIG_BLOCK, &block_set, NULL); + + CFG_init(NULL, NULL); + + char sdcard[PATH_MAX]; + resolve_sdcard(sdcard, sizeof(sdcard)); + + bool flush = CFG_getPowerOffProtection(); + log_msg(TOOL_NAME ": sdcard=%s mounted=%s flush=%s dry_run=%s\n", + sdcard, is_mounted(sdcard) ? "yes" : "no", + flush ? "yes" : "no", dry_run ? "yes" : "no"); + +#ifndef REBOOT_NEXT + // Reboot deliberately skips the PMIC: a restart is the SoC's job, and + // AXP2202 soft-reset is a different bit we have no need to poke. + if (dry_run) + { + int ret = axp_power_off(true); + CFG_quit(); + return ret == 0 ? 0 : EXIT_FAILURE; + } +#else + if (dry_run) + { + CFG_quit(); + return 0; + } +#endif + + if (flush) + run_flush(sdcard); + else + sync(); + +#ifndef REBOOT_NEXT + if (axp_power_off(false) != 0) + log_msg(TOOL_NAME ": PMIC power-off failed; falling back to the kernel\n"); +#endif + + finalize(); + + // finalize() only returns when every shutdown path failed. Exit non-zero so + // the `poweroff_next || poweroff` fallback in launch.sh actually fires. + log_msg(TOOL_NAME ": still running after finalize; deferring to the caller\n"); + CFG_quit(); + return EXIT_FAILURE; +} diff --git a/workspace/h700/rfkill/makefile b/workspace/h700/rfkill/makefile new file mode 100644 index 000000000..55c8ade45 --- /dev/null +++ b/workspace/h700/rfkill/makefile @@ -0,0 +1,14 @@ +ifeq (,$(CROSS_COMPILE)) +$(error missing CROSS_COMPILE for this toolchain) +endif + +TARGET = rfkill +PRODUCT = $(TARGET).elf + +CC = $(CROSS_COMPILE)gcc +FLAGS = -Os -lrt -ldl -Wl,--gc-sections -s + +all: + $(CC) $(TARGET).c -o $(PRODUCT) $(FLAGS) +clean: + rm -rf $(PRODUCT) \ No newline at end of file diff --git a/workspace/h700/rfkill/rfkill.c b/workspace/h700/rfkill/rfkill.c new file mode 100644 index 000000000..3a35feae4 --- /dev/null +++ b/workspace/h700/rfkill/rfkill.c @@ -0,0 +1,117 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void show_usage(const char *prog) { + fprintf(stderr, + "Usage:\n" + " %s list [INDEX|TYPE]\n" + " %s block INDEX|TYPE\n" + " %s unblock INDEX|TYPE\n", prog, prog, prog); + exit(EXIT_FAILURE); +} + +int get_rfkill_type(const char *name) { + static const char *types[] = { + "all", "wlan", "bluetooth", "uwb", "wimax", "wwan", "gps", "fm", NULL + }; + if (strcmp(name, "wifi") == 0) name = "wlan"; + if (strcmp(name, "ultrawideband") == 0) name = "uwb"; + + for (int i = 0; types[i]; ++i) { + if (strcmp(name, types[i]) == 0) + return i; + } + return -1; +} + +void list_devices(const char *filter) { + int fd = open("/dev/rfkill", O_RDONLY | O_NONBLOCK); + if (fd < 0) { + perror("/dev/rfkill"); + exit(EXIT_FAILURE); + } + + struct rfkill_event ev; + ssize_t len; + + int rf_type = -1, rf_idx = -1; + if (filter) { + rf_type = get_rfkill_type(filter); + if (rf_type < 0) + rf_idx = atoi(filter); + } + + while ((len = read(fd, &ev, sizeof(ev))) == sizeof(ev)) { + if ((rf_type >= 0 && ev.type != rf_type) || + (rf_idx >= 0 && ev.idx != rf_idx)) + continue; + + char path[128], line[128], name[64] = "", type[64] = ""; + snprintf(path, sizeof(path), "/sys/class/rfkill/rfkill%u/uevent", ev.idx); + FILE *f = fopen(path, "r"); + if (!f) continue; + + while (fgets(line, sizeof(line), f)) { + if (sscanf(line, "RFKILL_NAME=%63s", name) == 1) continue; + if (sscanf(line, "RFKILL_TYPE=%63s", type) == 1) continue; + } + fclose(f); + + printf("%u: %s: %s\n", ev.idx, name, type); + printf("\tSoft blocked: %s\n", ev.soft ? "yes" : "no"); + printf("\tHard blocked: %s\n", ev.hard ? "yes" : "no"); + } + + close(fd); +} + +void change_block(const char *target, int block) { + int fd = open("/dev/rfkill", O_WRONLY); + if (fd < 0) { + perror("/dev/rfkill"); + exit(EXIT_FAILURE); + } + + struct rfkill_event ev = {0}; + int type = get_rfkill_type(target); + int idx = (type < 0) ? atoi(target) : -1; + + ev.op = (idx >= 0) ? RFKILL_OP_CHANGE : RFKILL_OP_CHANGE_ALL; + ev.soft = block; + if (type >= 0) ev.type = type; + if (idx >= 0) ev.idx = idx; + + if (write(fd, &ev, sizeof(ev)) != sizeof(ev)) { + perror("write"); + close(fd); + exit(EXIT_FAILURE); + } + + close(fd); +} + +int main(int argc, char **argv) { + if (argc < 2 || argc > 3) + show_usage(argv[0]); + + if (strcmp(argv[1], "list") == 0) { + list_devices(argv[2]); + } else if (strcmp(argv[1], "block") == 0 && argc == 3) { + change_block(argv[2], 1); + } else if (strcmp(argv[1], "unblock") == 0 && argc == 3) { + change_block(argv[2], 0); + } else { + show_usage(argv[0]); + } + + return 0; +} \ No newline at end of file diff --git a/workspace/h700/shim-common.sh b/workspace/h700/shim-common.sh new file mode 100755 index 000000000..8829e8876 --- /dev/null +++ b/workspace/h700/shim-common.sh @@ -0,0 +1,56 @@ +#!/bin/sh + +: "${SHIM_LOG_PATH:=/tmp/nextui-h700.log}" +: "${SHIM_LOG_PREFIX:=}" +: "${SHIM_LOG_DATES:=0}" + +shim_log() { + if [ "$SHIM_LOG_DATES" = "1" ]; then + echo "${SHIM_LOG_PREFIX}$* $(date)" >> "$SHIM_LOG_PATH" 2>/dev/null || true + else + echo "${SHIM_LOG_PREFIX}$*" >> "$SHIM_LOG_PATH" 2>/dev/null || true + fi +} + +ensure_compat_path() { + real_path="$1" + compat_path="$2" + + if mountpoint -q "$compat_path"; then + return 0 + fi + if [ -L "$compat_path" ]; then + return 0 + fi + if [ -e "$compat_path" ]; then + mount --bind "$real_path" "$compat_path" 2>/dev/null || true + else + ln -s "$real_path" "$compat_path" 2>/dev/null || true + fi +} + +mount_tf2() { + tf2_path="$1" + tf2_device="${2:-/dev/mmcblk1p1}" + + mkdir -p "$tf2_path" + if mountpoint -q "$tf2_path"; then + return 0 + fi + mount -t vfat -o rw,utf8,noatime "$tf2_device" "$tf2_path" 2>/dev/null || + mount -t exfat -o rw,noatime "$tf2_device" "$tf2_path" 2>/dev/null || + mount -o rw,noatime "$tf2_device" "$tf2_path" 2>/dev/null +} + +repair_tf2() { + tf2_device="${1:-/dev/mmcblk1p1}" + fstype=$(blkid -o value -s TYPE "$tf2_device" 2>/dev/null) + case "$fstype" in + vfat|msdos|fat) + command -v fsck.fat >/dev/null 2>&1 && fsck.fat -a "$tf2_device" >> "$SHIM_LOG_PATH" 2>&1 || true + ;; + exfat) + command -v fsck.exfat >/dev/null 2>&1 && fsck.exfat -a "$tf2_device" >> "$SHIM_LOG_PATH" 2>&1 || true + ;; + esac +} diff --git a/workspace/makefile b/workspace/makefile index f71af4d62..e0306251a 100644 --- a/workspace/makefile +++ b/workspace/makefile @@ -34,6 +34,10 @@ ifeq ($(PLATFORM), tg5040) cd ./$(PLATFORM)/rfkill && make all cd ./$(PLATFORM)/btmanager && make all cd ./$(PLATFORM)/poweroff_next/ && make +endif +ifeq ($(PLATFORM), h700) + cd ./$(PLATFORM)/rfkill && make all + cd ./$(PLATFORM)/poweroff_next/ && make endif cd ./$(PLATFORM)/libmsettings && make cd ./$(PLATFORM) && make early # eg. other libs @@ -51,8 +55,12 @@ endif cd ./all/syncsettings/ && make cd ./all/nextval/ && make cd ./all/settings/ && make +ifneq (,$(filter $(PLATFORM),tg5040 tg5050 h700)) cd ./all/ledcontrol/ && make +endif +ifneq (,$(filter $(PLATFORM),tg5040 tg5050 h700)) cd ./all/bootlogo/ && make +endif cd ./all/audiomon && make all cd ./all/show2/ && make endif @@ -76,8 +84,12 @@ clean: ifneq ($(PLATFORM), desktop) cd ./$(PLATFORM)/keymon && make clean cd ./all/syncsettings/ && make clean +ifneq (,$(filter $(PLATFORM),tg5040 tg5050 h700)) cd ./all/ledcontrol/ && make clean +endif +ifneq (,$(filter $(PLATFORM),tg5040 tg5050 h700)) cd ./all/bootlogo/ && make clean +endif cd ./all/show2/ && make clean cd ./all/batmon/ && make clean ifeq ($(PLATFORM), tg5040) @@ -85,6 +97,10 @@ ifeq ($(PLATFORM), tg5040) cd ./$(PLATFORM)/btmanager && make clean cd ./$(PLATFORM)/poweroff_next/ && make clean endif +ifeq ($(PLATFORM), h700) + cd ./$(PLATFORM)/rfkill && make clean + cd ./$(PLATFORM)/poweroff_next/ && make clean +endif endif cd ./$(PLATFORM)/libmsettings && make clean cd ./all/nextui/ && make clean diff --git a/workspace/tg5040/btmanager/support/upgrade_bluez.sh b/workspace/tg5040/btmanager/support/upgrade_bluez.sh index dc8d38b8f..b00349252 100755 --- a/workspace/tg5040/btmanager/support/upgrade_bluez.sh +++ b/workspace/tg5040/btmanager/support/upgrade_bluez.sh @@ -1,5 +1,10 @@ #! /bin/sh +if [ "$PLATFORM" = "h700" ]; then + echo "Skipping tg5040 BlueZ update on h700" + exit 0 +fi + TRIMUI_MODEL=`strings /usr/trimui/bin/MainUI | grep ^Trimui` if [ "$TRIMUI_MODEL" = "Trimui Smart Pro S" ]; then return 0 diff --git a/workspace/tg5040/cores/makefile b/workspace/tg5040/cores/makefile index a224ff179..9eeb5dd9d 100755 --- a/workspace/tg5040/cores/makefile +++ b/workspace/tg5040/cores/makefile @@ -67,6 +67,10 @@ gambatte_REPO = https://github.com/libretro/gambatte-libretro mednafen_supafaust_REPO = https://github.com/libretro/supafaust +# mGBA replaced Makefile.libretro with a CMake-based libretro build. +mgba_CORE = build-tg5040/mgba_libretro.so +mgba_MAKE = cmake -S . -B build-tg5040 -DCMAKE_BUILD_TYPE=Release -DLIBMGBA_ONLY=ON -DBUILD_LIBRETRO=ON -DLIBRETRO_STATIC=OFF -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=aarch64 -DCMAKE_C_COMPILER=$(CROSS_COMPILE)gcc -DCMAKE_CXX_COMPILER=$(CROSS_COMPILE)g++ -DCMAKE_C_FLAGS="-fomit-frame-pointer -ffast-math -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a -fno-common -ftree-vectorize -funswitch-loops" -DCMAKE_CXX_FLAGS="-fomit-frame-pointer -ffast-math -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a -fno-common -ftree-vectorize -funswitch-loops" && cmake --build build-tg5040 --target mgba_libretro -- $(PROCS) + pcsx_rearmed_MAKEFILE = Makefile.libretro # pcsx has a disabled submodule for gnulib, which takes forever to check out and is unused - skil checkout pcsx_rearmed_SUBMODULES = frontend/libpicofe diff --git a/workspace/tg5040/cores/patches/fceumm.patch b/workspace/tg5040/cores/patches/fceumm.patch index 2131c17be..92e8343ec 100644 --- a/workspace/tg5040/cores/patches/fceumm.patch +++ b/workspace/tg5040/cores/patches/fceumm.patch @@ -1,10 +1,9 @@ diff --git forkSrcPrefix/Makefile.libretro forkDstPrefix/Makefile.libretro -index 036c41f48b087c99b2276b2d41a71d661fd85145..891eb96ceeb1da868d6d2ed40392b51b65dcbb20 100644 +index 5b90d409271332a48ae726dca48a712c3be413be..02958b2d0e6612539ae4545df7bb28a8395c060e 100644 --- forkSrcPrefix/Makefile.libretro +++ forkDstPrefix/Makefile.libretro -@@ -461,6 +461,23 @@ else ifeq ($(platform), miyoo) +@@ -458,5 +458,22 @@ else ifeq ($(platform), miyoo) PLATFORM_DEFINES += -fomit-frame-pointer -ffast-math -mcpu=arm926ej-s - EXTERNAL_ZLIB = 1 +# TRIMUI SMART PRO +else ifeq ($(platform), tg5040) diff --git a/workspace/tg5040/cores/patches/mgba.patch b/workspace/tg5040/cores/patches/mgba.patch deleted file mode 100644 index b0145a5b3..000000000 --- a/workspace/tg5040/cores/patches/mgba.patch +++ /dev/null @@ -1,31 +0,0 @@ -diff --git forkSrcPrefix/Makefile.libretro forkDstPrefix/Makefile.libretro -index 108148f4579f4727146e5b8c1e05ef7382654208..35e6399147a4ef75947ecb2ad4a94f0820ef24d0 100644 ---- forkSrcPrefix/Makefile.libretro -+++ forkDstPrefix/Makefile.libretro -@@ -417,6 +417,26 @@ else ifeq ($(platform), miyoo) - CFLAGS += -fno-common -ftree-vectorize -funswitch-loops - DEFINES += -std=c99 - -+# TRIMUI SMART PRO -+else ifeq ($(platform), tg5040) -+ TARGET := $(TARGET_NAME)_libretro.so -+ CC = $(CROSS_COMPILE)gcc -+ CXX = $(CROSS_COMPILE)g++ -+ AR = $(CROSS_COMPILE)ar -+ SHARED := -shared -Wl,--version-script=link.T -+ fpic := -fPIC -+ PLATFORM_DEFINES += -D_GNU_SOURCE -DHAVE_STRTOF_L -DHAVE_LOCALE -+ CFLAGS += -fomit-frame-pointer -ffast-math -+ CFLAGS += -mtune=cortex-a53 -mcpu=cortex-a53 -march=armv8-a -+ CFLAGS += -fno-common -ftree-vectorize -funswitch-loops -+ HAVE_NEON = 1 -+ ARCH = arm64 -+ BUILTIN_GPU = neon -+ CPU_ARCH := arm -+ MMAP_JIT_CACHE = 1 -+ HAVE_DYNAREC = 1 -+ DEFINES += -std=c99 -+ - # Windows - else - TARGET := $(TARGET_NAME)_libretro.dll diff --git a/workspace/tg5040/platform/platform.c b/workspace/tg5040/platform/platform.c index 0ef532ff5..278d09816 100644 --- a/workspace/tg5040/platform/platform.c +++ b/workspace/tg5040/platform/platform.c @@ -407,6 +407,17 @@ ConnectionStrength PLAT_connectionStrength(void) { return SIGNAL_STRENGTH_LOW; } +int PLAT_getNumLeds(void) { + // PLAT_initPlatform() sets is_brick/is_brickpro and may not have run yet + // (LedControl asks for the count before GFX_init); it is idempotent. + PLAT_initPlatform(); + // must match how many slots PLAT_initDefaultLeds() below actually fills: + // the spare MAX_LIGHTS slots are zeroed, and a zeroed slot passes the + // filename != "f2" test in PLAT_setLedBrightness and writes brightness 0 + // to the global max_scale, killing every LED. + return is_brickpro ? 5 : is_brick ? 4 : 3; +} + void PLAT_initDefaultLeds() { PLAT_initPlatform(); if(is_brickpro) { diff --git a/workspace/tg5050/cores/makefile b/workspace/tg5050/cores/makefile index a224ff179..2cd263250 100755 --- a/workspace/tg5050/cores/makefile +++ b/workspace/tg5050/cores/makefile @@ -67,6 +67,10 @@ gambatte_REPO = https://github.com/libretro/gambatte-libretro mednafen_supafaust_REPO = https://github.com/libretro/supafaust +# mGBA replaced Makefile.libretro with a CMake-based libretro build. +mgba_CORE = build-tg5050/mgba_libretro.so +mgba_MAKE = cmake -S . -B build-tg5050 -DCMAKE_BUILD_TYPE=Release -DLIBMGBA_ONLY=ON -DBUILD_LIBRETRO=ON -DLIBRETRO_STATIC=OFF -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=aarch64 -DCMAKE_C_COMPILER=$(CROSS_COMPILE)gcc -DCMAKE_CXX_COMPILER=$(CROSS_COMPILE)g++ -DCMAKE_C_FLAGS="-fomit-frame-pointer -ffast-math -mcpu=cortex-a55 -fno-common -ftree-vectorize -funswitch-loops" -DCMAKE_CXX_FLAGS="-fomit-frame-pointer -ffast-math -mcpu=cortex-a55 -fno-common -ftree-vectorize -funswitch-loops" && cmake --build build-tg5050 --target mgba_libretro -- $(PROCS) + pcsx_rearmed_MAKEFILE = Makefile.libretro # pcsx has a disabled submodule for gnulib, which takes forever to check out and is unused - skil checkout pcsx_rearmed_SUBMODULES = frontend/libpicofe diff --git a/workspace/tg5050/cores/patches/fceumm.patch b/workspace/tg5050/cores/patches/fceumm.patch index c4f8e1ddb..8ed07e929 100644 --- a/workspace/tg5050/cores/patches/fceumm.patch +++ b/workspace/tg5050/cores/patches/fceumm.patch @@ -1,10 +1,9 @@ diff --git forkSrcPrefix/Makefile.libretro forkDstPrefix/Makefile.libretro -index 036c41f48b087c99b2276b2d41a71d661fd85145..891eb96ceeb1da868d6d2ed40392b51b65dcbb20 100644 +index 5b90d409271332a48ae726dca48a712c3be413be..cbdaf093812ebe934b915e9087e7f8518f45a611 100644 --- forkSrcPrefix/Makefile.libretro +++ forkDstPrefix/Makefile.libretro -@@ -461,6 +461,23 @@ else ifeq ($(platform), miyoo) +@@ -458,5 +458,22 @@ else ifeq ($(platform), miyoo) PLATFORM_DEFINES += -fomit-frame-pointer -ffast-math -mcpu=arm926ej-s - EXTERNAL_ZLIB = 1 +# target platform tg5050 trimUI smart pro s +else ifeq ($(platform), tg5050) diff --git a/workspace/tg5050/cores/patches/mgba.patch b/workspace/tg5050/cores/patches/mgba.patch deleted file mode 100644 index 31e8ce9b6..000000000 --- a/workspace/tg5050/cores/patches/mgba.patch +++ /dev/null @@ -1,31 +0,0 @@ -diff --git forkSrcPrefix/Makefile.libretro forkDstPrefix/Makefile.libretro -index 108148f4579f4727146e5b8c1e05ef7382654208..35e6399147a4ef75947ecb2ad4a94f0820ef24d0 100644 ---- forkSrcPrefix/Makefile.libretro -+++ forkDstPrefix/Makefile.libretro -@@ -417,6 +417,26 @@ else ifeq ($(platform), miyoo) - CFLAGS += -fno-common -ftree-vectorize -funswitch-loops - DEFINES += -std=c99 - -+# target platform tg5050 trimUI smart pro s -+else ifeq ($(platform), tg5050) -+ TARGET := $(TARGET_NAME)_libretro.so -+ CC = $(CROSS_COMPILE)gcc -+ CXX = $(CROSS_COMPILE)g++ -+ AR = $(CROSS_COMPILE)ar -+ SHARED := -shared -Wl,--version-script=link.T -+ fpic := -fPIC -+ PLATFORM_DEFINES += -D_GNU_SOURCE -DHAVE_STRTOF_L -DHAVE_LOCALE -+ CFLAGS += -fomit-frame-pointer -ffast-math -+ CFLAGS += -mcpu=cortex-a55 -+ CFLAGS += -fno-common -ftree-vectorize -funswitch-loops -+ HAVE_NEON = 1 -+ ARCH = arm64 -+ BUILTIN_GPU = neon -+ CPU_ARCH := arm -+ MMAP_JIT_CACHE = 1 -+ HAVE_DYNAREC = 1 -+ DEFINES += -std=c99 -+ - # Windows - else - TARGET := $(TARGET_NAME)_libretro.dll diff --git a/workspace/tg5050/platform/platform.c b/workspace/tg5050/platform/platform.c index 4cd03c15e..c5660fc3d 100644 --- a/workspace/tg5050/platform/platform.c +++ b/workspace/tg5050/platform/platform.c @@ -416,6 +416,14 @@ ConnectionStrength PLAT_connectionStrength(void) { return SIGNAL_STRENGTH_LOW; } +int PLAT_getNumLeds(void) { + // MAX_LIGHTS is 4 but PLAT_initDefaultLeds() below only fills 3. The + // spare slot is a zeroed global, and a zeroed slot passes the + // filename != "f2" test in PLAT_setLedBrightness and writes brightness 0 + // to the global max_scale, killing every LED. + return 3; +} + void PLAT_initDefaultLeds() { lightsDefault[0] = (LightSettings) { "Joystick L",