32blit / 32blit-sdk

32blit SDK
https://32blit.com
MIT License
193 stars 68 forks source link

port: Miyoo Mini Plus #839

Open Gadgetoid opened 11 months ago

Gadgetoid commented 11 months ago

I picked up a Miyoo Mini Plus recently so I had something to distract me from all the Linux gpio tomfoolery. The few 32blit examples I've managed to port over run pretty well.

https://droix.co.uk/product/miyoo-mini-plus/

TODO

  1. [ ] New toolchain file
  2. [x] Expand SDL bindings, or find a way to overload the config to support MMPs key binding (see below)
  3. [x] Figure out how to build our own SDL2 without the DraStic specific hacks
  4. [ ] GitHub actions autobuild? Looks like OnionOS does this via Docker
  5. [ ] Build and populate an app dir with config.json, launch.sh, libs/, icon and binary.
  6. [ ] Icon image looks to be 74x74 pixels so we might need some conversion?

Notes

I used https://github.com/shauninman/union-miyoomini-toolchain or, more specifically, https://github.com/shauninman/miyoomini-toolchain-buildroot/ and added the SDL2 libs via the buildroot make menuconfig, then used the following toolchain file to configure 32blit-sdk:

set(COMMON_FLAGS "-Os -marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7ve+simd")

set(CMAKE_C_FLAGS_INIT "${COMMON_FLAGS}")
set(CMAKE_CXX_FLAGS_INIT "${COMMON_FLAGS} -fno-exceptions")

set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)

set(CMAKE_FIND_ROOT_PATH
/root/buildroot/output/host/arm-buildroot-linux-gnueabihf/sysroot)

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)

# search headers and libraries in the target environment
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

SDL2

It looks like SDL2 is not natively supported, and the SDL2 libraries nabbed from the buildroot don't seem to work. I had to borrow the ones from https://github.com/steward-fu/sdl/tree/sdl-2.0.20_ssd202d_miyoo-mini though I just grabbed the compiled binaries out of the DraStic port and added SDL2 net.

I dumped these into a libs dir inside the app dir (as per DraStic) and then used the following launch.sh:

#!/bin/sh
echo $0 $*

mydir=`dirname "$0"`

export HOME=$mydir
export PATH=$mydir:$PATH
export LD_LIBRARY_PATH=$mydir/libs:$LD_LIBRARY_PATH
export SDL_VIDEODRIVER=mmiyoo
export SDL_AUDIODRIVER=mmiyoo
export EGL_VIDEODRIVER=mmiyoo

cd $mydir
./geometry --fullscreen > geometry.log 2>&1

Input

The SDL scancodes for input are:

    SDLK_UP,
    SDLK_DOWN,
    SDLK_LEFT,
    SDLK_RIGHT,

    SDLK_SPACE,     // A
    SDLK_LCTRL,     // B
    SDLK_LSHIFT,    // X
    SDLK_LALT,      // Y

    SDLK_e,         // L1
    SDLK_t,         // R1
    SDLK_TAB,       // L2
    SDLK_BACKSPACE, // R2

    SDLK_RCTRL,     // Select
    SDLK_RETURN,    // Start

    SDLK_HOME,      // MENU
    SDLK_0,         // Quick Save
    SDLK_1,         // Quick Load

    SDLK_2,         // Exit
    SDLK_3,         // Power
    SDLK_HOME,      // Vol Up
    SDLK_BACKSPACE  // Vol Down

The following patch handles key bindings and makes "menu" exit, note that the LCTRL for B conflicts with our use of Ctrl for something, I forget what:

diff --git a/32blit-sdl/Input.cpp b/32blit-sdl/Input.cpp
index c1d65f0..e2bdcb4 100644
--- a/32blit-sdl/Input.cpp
+++ b/32blit-sdl/Input.cpp
@@ -23,6 +23,12 @@ std::map<int, int> Input::keys = {
        {SDLK_c,       blit::Button::X},
        {SDLK_v,       blit::Button::Y},

+    //  Miyoo Mini Plus XBXY
+    {SDLK_SPACE,   blit::Button::A},
+    {SDLK_LCTRL,   blit::Button::B},
+    {SDLK_LSHIFT,  blit::Button::X},
+    {SDLK_LALT,    blit::Button::Y},
+
        {SDLK_u,       blit::Button::A},
        {SDLK_i,       blit::Button::B},
        {SDLK_o,       blit::Button::X},
@@ -33,7 +39,8 @@ std::map<int, int> Input::keys = {
        {SDLK_2,       blit::Button::MENU},
        {SDLK_3,       blit::Button::JOYSTICK},

-  {SDLK_ESCAPE,  blit::Button::MENU},
+    {SDLK_ESCAPE,  blit::Button::MENU},
+    {SDLK_RCTRL,   blit::Button::HOME},
 };

 std::map<int, int> Input::buttons = {
diff --git a/32blit-sdl/Main.cpp b/32blit-sdl/Main.cpp
index 4eb6a2c..e7e06ed 100644
--- a/32blit-sdl/Main.cpp
+++ b/32blit-sdl/Main.cpp
@@ -63,6 +63,10 @@ void handle_event(SDL_Event &event) {
                        break;

                case SDL_KEYDOWN: // fall-though
+            if (event.key.keysym.sym == SDLK_HOME) {
+                running = false;
+                break;
+            }
                case SDL_KEYUP:
                        if (!blit_input->handle_keyboard(event.key.keysym.sym, event.type == SDL_KEYDOWN)) {
 #ifdef VIDEO_CAPTURE

Geometry.zip

Daft-Freak commented 11 months ago

I'm guessing the SDL2 port doesn't expose the buttons as a gamepad. (As "mapping random devices to a standard layout" is kinda what SDL's "gamepad" support is for...)

Too bad there's nobody with knowledge of SDL2 internals here... wait.

Gadgetoid commented 11 months ago

We might fare better by using something less custom than the incredibly DraStic specific hack of SDL I used to get stuff up and running quick.

It seems to include input plus some integrated menu and a mousekeys mode since the device has no touchscreen - https://github.com/steward-fu/sdl/blob/sdl-2.0.20_ssd202d_miyoo-mini_drastic/src/video/mmiyoo/SDL_video_mmiyoo.c

This is a much more succinct version of the Miyoo SDL video driver, without all the input hacks and menus. I’ve no idea how to invoke the OS menu so I just bound the menu button to quit 😬 when using the DraStic SDL libs: https://github.com/steward-fu/sdl/blob/sdl-2.0.20_ssd202d_miyoo-mini/src/video/mmiyoo/SDL_video_mmiyoo.c

I guess the next step is to figure out what the vanilla SDL2 port does for input!

Okay, roughy the same - reading the scancodes from a hard-coded keyboard device path and packing them into a bitmap for some reason- https://github.com/steward-fu/sdl/blob/sdl-2.0.20_ssd202d_miyoo-mini/src/video/mmiyoo/SDL_event_mmiyoo.c

Also some mouse keys support in there, but fewer available “buttons” because there’s no soft menu injecting SDL input events.

Daft-Freak commented 11 months ago

Ouch that repo is nasty. input handling in the video driver... aaaaa

Though if the input driver is using /dev/event0 maybe some of the standard evdev stuff in SDL would work :thinking:

Gadgetoid commented 11 months ago

Yeah it’s doing some hacky stuff to intercept input which we don’t need- I’ll have to bite the bullet, rip out the bits we don’t need and try to compile it from source.

Goal is to get a generic Docker image with the buildroot/toolchain preconfigured to build SDL2 apps for Miyoo. Then it’s useful to anyone who wants to make a port!

Daft-Freak commented 11 months ago

Hah, I was just trying to find the actual diff from upstream SDL, but there are a mountain of unrelated (formatting?) changes.

May be too far to stop now though. So uh, that might help...

Daft-Freak commented 11 months ago

There: https://github.com/Daft-Freak/SDL/tree/ssd202d_miyoo-mini

It looks like there is a joystick driver so it should just need a mapping defined for gamecontroller to work. (Likely in a similar way to the emscripten or psp one)

Some other fun stuff:

Gadgetoid commented 11 months ago

You're a gosh darn wizard!

It's your chaotic influence that had me trying to port 32blit to something random in the first place :laughing:

Gadgetoid commented 11 months ago

Okay for audio we need something like:

#!/bin/sh
echo $0 $*
progdir=`dirname "$0"`
cd $progdir
export HOME=$progdir
export PATH=$progdir:$PATH
export LD_LIBRARY_PATH=$progdir/libs:$LD_LIBRARY_PATH
export SDL_VIDEODRIVER=mmiyoo
export SDL_AUDIODRIVER=mmiyoo
export EGL_VIDEODRIVER=mmiyoo

. /mnt/SDCARD/.tmp_update/script/stop_audioserver.sh

./geometry --fullscreen

And possibly this change to config.json from Vitty85 on the RGH Discord-

{
    "label":"Geometry (32blit)",
    "icon":"geometry.png",
    "iconsel":"geometry.png",
    "launch":"launch.sh",
    "useswap":1,
    "noaudiofix":1,
    "description":"Asteroids with a twist."
}

And they also had some interesting changes to the launch script which might come in handy:

#!/bin/sh
get_curvol() {
    awk '/LineOut/ {if (!printed) {gsub(",", "", $8); print $8; printed=1}}' /proc/mi_modules/mi_ao/mi_ao0
}

set_snd_level() {
    local target_vol="$1"
    local current_vol
    local start_time
    local elapsed_time

    start_time=$(date +%s)
    while [ ! -e /proc/mi_modules/mi_ao/mi_ao0 ]; do
        sleep 0.2
        elapsed_time=$(( $(date +%s) - start_time ))
        if [ "$elapsed_time" -ge 30 ]; then
            echo "Timed out waiting for /proc/mi_modules/mi_ao/mi_ao0"
            return 1
        fi
    done

    start_time=$(date +%s)
    while true; do
        echo "set_ao_volume 0 ${target_vol}dB" > /proc/mi_modules/mi_ao/mi_ao0
        echo "set_ao_volume 1 ${target_vol}dB" > /proc/mi_modules/mi_ao/mi_ao0
        current_vol=$(get_curvol)

        if [ "$current_vol" = "$target_vol" ]; then
            echo "Volume set to ${current_vol}dB"
            return 0
        fi

        elapsed_time=$(( $(date +%s) - start_time ))
        if [ "$elapsed_time" -ge 30 ]; then
            echo "Timed out trying to set volume"
            return 1
        fi

        sleep 0.2
    done
}

echo $0 $*
progdir=`dirname "$0"`
cd $progdir
export HOME=$progdir
export PATH=$progdir:$PATH
export LD_LIBRARY_PATH=$progdir/libs:$LD_LIBRARY_PATH
export SDL_VIDEODRIVER=mmiyoo
export SDL_AUDIODRIVER=mmiyoo
export EGL_VIDEODRIVER=mmiyoo

curvol=$(get_curvol) # grab current volume

if [ -f /mnt/SDCARD/.tmp_update/script/stop_audioserver.sh ]; then
    /mnt/SDCARD/.tmp_update/script/stop_audioserver.sh
else
    killall audioserver
    killall audioserver.mod
fi

CUST_CPUCLOCK=1

sv=`cat /proc/sys/vm/swappiness`

# 60 by default
echo 10 > /proc/sys/vm/swappiness

if [ "$CUST_CPUCLOCK" == "1" ]; then
    echo "set customized cpuspeed"
    cpuclock 1500
fi

set_snd_level "${curvol}" &

./geometry --fullscreen

if [ "$CUST_CPUCLOCK" == "1" ]; then
    echo "set customized cpuspeed"
    cpuclock 1200
fi

echo $sv > /proc/sys/vm/swappiness
sync
Gadgetoid commented 11 months ago

Hmm I'm getting a right mess of conflicting types from somehow including both /root/buildroot/output/staging/usr/include/SDL2/SDL_sensor.h and /root/workspace/SDL/include/SDL_sensor.h :thinking:

This was due to an effort to resolve a missing SDL_ttf.h using the buildroot supplied version -

In file included from /root/workspace/SDL/src/render/mmiyoo/SDL_render_mmiyoo.c:30:
/root/workspace/SDL/src/render/mmiyoo/../../video/mmiyoo/SDL_video_mmiyoo.h:36:10: fatal error: SDL_ttf.h: No such file or directory
 #include "SDL_ttf.h"
          ^~~~~~~~~~~

I deeply suspect I'm doing buildroot hardmode here by having no clue what I'm doing!

Daft-Freak commented 11 months ago

That looks like an SDL1 vs SDL2 conflict (so I guess wrong SDL_ttf version?)... but an SDL video driver really shouldn't have a dependency on a font rendering library...

See if anything explodes with that include deleted? :shrug:

Gadgetoid commented 11 months ago

That's a point, it might be specifically for the onscreen menu stuff in the DraStic version!

:eyes:

ln -s /root/buildroot/output/staging/usr/include/SDL2/SDL_image.h SDL_image.h

...

...

OH COME ON! :laughing:

/root/workspace/SDL/src/video/mmiyoo/SDL_video_mmiyoo.c:39:10: fatal error: json-c/json.h: No such file or directory
 #include <json-c/json.h>
Gadgetoid commented 11 months ago

Oh now a thing has happened:

libtool:   error: cannot determine absolute directory name of 'mmiyoo/libs'

ahh...

/root/my283/usr/lib/
Daft-Freak commented 11 months ago

That might be some binaries that got (correctly) .gitignore'd... At least, I see a mmiyoo/libs dir in that SDL repo.

SDL_image and a JSON lib as well? In a low-level driver? :facepalm: mumbles something about layers

Gadgetoid commented 11 months ago

Right getting somewhere, I need a couple more libs... EGL and GLESv2, so back to the buildroot config.

Okay using the mystery meat libs from here works: https://github.com/steward-fu/sdl/tree/sdl-2.0.20_ssd202d_miyoo-mini

Both libEGL.so and libGLESv2.so are in the root of that repository and get linked in. Probably don't need these for 32blit but I don't know what horror might befall me if I try to remove them.

Gadgetoid commented 11 months ago

Well this explains what all those includes are doing with the DraStic SDL-

/mnt/SDCARD/App/Geometry # cat geometry.log 
Geometry v1.0.0
Powered by 32Blit SDL2 runtime - github.com/32blit/32blit-sdk

Surface for convert: 0x8a4b8
How many pen:0
How many theme:0
How many overlay:0
Couldn't open resources/menu/bg.png
Couldn't open resources/menu/cursor.png
Menu cursor: (nil)
Couldn't open resources/menu/drastic_bg.png
Couldn't open resources/menu/drastic_cursor.png
Couldn't open resources/menu/drastic_yes.png
Couldn't open resources/menu/drastic_no.png
Couldn't open resources/font/font.ttf
nds.font: (nil)
Failed to read settings from json file (/mnt/SDCARD/App/Geometry/resources/settings.json)
MMIYOO_CreateWindow, w:0, h:0
MMIYOO_OpenDevice, freq:22050 sample:256 channels:1
[MI ERR ]: MI_AO_SetPubAttr[3364]: Dev0 failed to set pub attr!!! error number:0xa0052009!!!
MMIYOO_OpenDevice, failed to set PubAttr
[MI ERR ]: MI_AO_DisableChn[3667]: Dev0 has not been enabled.
Audio Init Failed: 
Invalid audio device ID
Failed to write settings to json file (/mnt/SDCARD/App/Geometry/resources/settings.json)

Unfortunately the SDL that I - finally - compiled from sauce is not working.

Gadgetoid commented 11 months ago
/mnt/SDCARD/App/Geometry # cat geometry.log 
Geometry v1.0.0
Powered by 32Blit SDL2 runtime - github.com/32blit/32blit-sdk

MMIYOO_CreateWindow, w:0, h:0
MMIYOO_OpenDevice, freq:22050 sample:256 channels:1
[MI ERR ]: MI_AO_SetPubAttr[3364]: Dev0 failed to set pub attr!!! error number:0xa0052009!!!
MMIYOO_OpenDevice, failed to set PubAttr
[MI ERR ]: MI_AO_DisableChn[3667]: Dev0 has not been enabled.
Audio Init Failed:

More or less the same error, too, so I'm not sure what's awry here.

Daft-Freak commented 11 months ago

:thinking: Looking at one of those "trade secret" header files (mi_common_datatype.h)

#define MI_DEF_ERR( module, level, errid) \
    ((MI_S32)( (MI_ERR_ID) | ((module) << 16 ) | ((level)<<12) | (errid) ))

So a0052009 is:

Which seems plausible to be coming from audio init.

Gadgetoid commented 11 months ago

Okay grabbing the vanilla SDL from Stewart's repo, removing the vestigial libs/includes and building that seems to work - https://github.com/Gadgetoid/steward-fu-sdl/tree/vanilla

That gets me... somewhere... I think

Daft-Freak commented 11 months ago

So there's something broken in my "clean" branch then...

(Also, stole your patch :laughing:)

Gadgetoid commented 11 months ago

I'm up and running with a custom SDL, though I've made no effort to unpick the input handling.

Audio is extremely delayed (about one second) and I don't really have the first clue why.

Removing all the custom input stuff definitely makes input not work... that's an... uh... start...

Daft-Freak commented 11 months ago

Theoretically the linux joystick driver should do... something. (that's the driver for /dev/eventX). Though I can't say whether or not it will detect the device as a "joystick". The custom one looks like a stub.

You'd need to get a joystick test running to figure out the gamepad mapping...

Gadgetoid commented 11 months ago

I've figured out what you mean by emscripten/psp joysticks so I'm deep in populating the empty miyoo joystick driver to see if it will... do a thing.

Darn Miyoo wont connect to my wifi so I'm stuck pulling the SD card, moving SDL out of my docker container, and then scp'ing it from my remote dev machine onto the SD card aaaah

Gadgetoid commented 11 months ago

https://github.com/Gadgetoid/steward-fu-sdl/commit/dfef26c830259da55e51f76b24c9eddbfdd67596

😬 I must be missing some secret sauce because the compiler is picking up these changes but driver does nada, never gets probed, or who really knows!

Gadgetoid commented 11 months ago

TIL SDL_gamecontrollerdb.h

For posterity: "4d4d69796f6f204a6f79737469636b00,MMiyoo Joystick,dpup:b0,dpdown:b1,dpleft:b2,dpright:b3,a:b4,b:b5,x:b6,y:b7,leftshoulder:b8,lefttrigger:b9,rightshoulder:b10,righttrigger:b11,back:b12,start:b13,guide:b14,",

Name -> GUID: "".join([hex(n)[2:] for n in list(bytes("MMiyoo Joystick", "utf-8"))])

Gadgetoid commented 11 months ago

Okay the mapping works and coaxes SDL into “opening” the joystick, but still no input 🤔

https://github.com/Gadgetoid/steward-fu-sdl/commit/aaafe38bea154ac6119fad7f5e58315729f57a3c

Sort-of debug:

Geometry v1.0.0
Powered by 32Blit SDL2 runtime - github.com/32blit/32blit-sdk

 _MI_AO_OpenVqeLib: success
 _MI_AO_OpenSrcLib: success
 _MI_AO_OpenG711Lib: success
 _MI_AO_OpenG726Lib: success
miyoo: hello joystick!
miyoo: running, I guess...!
miyoo: MMIYOO_JoystickGetCount 1
miyoo: MMIYOO_JoystickGetCount 1
miyoo: MMIYOO_JoystickGetCount 1
miyoo: MMIYOO_JoystickGetCount 1
miyoo: MMIYOO_JoystickGetCount 1
MMIYOO_CreateWindow, w:0, h:0
miyoo: JoystickUpdate 1
miyoo: MMIYOO_JoystickGetCount 1
miyoo: MMIYOO_JoystickGetCount 1
miyoo: MMIYOO_JoystickGetCount 1
miyoo: MMIYOO_JoystickGetCount 1
miyoo: MMIYOO_JoystickGetCount 1
miyoo: MMIYOO_JoystickGetDeviceInstanceID 0
miyoo: MMIYOO_JoystickGetCount 1
miyoo: MMIYOO_JoystickGetCount 1
miyoo: MMIYOO_JoystickGetCount 1
miyoo: MMIYOO_JoystickGetCount 1
miyoo: MMIYOO_JoystickGetDeviceInstanceID 0
miyoo: joystick open 0
miyoo: MMIYOO_JoystickGetCount 1
miyoo: MMIYOO_JoystickGetCount 1
miyoo: MMIYOO_JoystickGetCount 1
SDL_joystick.c: MMiyoo Joystick 1
miyoo: MMIYOO_JoystickRumble
That operation is not supported
miyoo: MMIYOO_JoystickGetCount 1
MMIYOO_OpenDevice, freq:22050 sample:256 channels:1
miyoo: MMIYOO_JoystickGetCount 1
miyoo: MMIYOO_JoystickGetDeviceInstanceID 0
miyoo: MMIYOO_JoystickRumble
That operation is not supported
User code appears to have frozen. Detaching thread.
miyoo: joystick closed
miyoo: goodbye joystick!

Hmm getting and sending button states, but 32blit seems to be ignoring gamepad input 🤔

miyoo: input: btn 8 1
miyoo: input: btn 8 0
miyoo: input: btn 10 1
miyoo: input: btn 10 0
miyoo: input: btn 11 1
miyoo: input: btn 11 0
miyoo: input: btn 9 1
miyoo: input: btn 9 0
miyoo: input: btn 11 1
miyoo: input: btn 10 1
miyoo: input: btn 11 0
miyoo: input: btn 10 0
miyoo: input: btn 9 1
miyoo: input: btn 8 1
miyoo: input: btn 9 0
miyoo: input: btn 8 0
miyoo: input: btn 14 1
miyoo: input: btn 14 0
miyoo: input: btn 4 1
Gadgetoid commented 11 months ago

Seems the bit that should be transforming SDL_PrivateJoystickButton into SDL_PrivateGameControllerButton just isn't happening... and that the SDL_JOYBUTTONDOWN and SDL_JOYBUTTONUP events never make it to 32blit's event loop. I'm baffled!

Daft-Freak commented 11 months ago

That suggests that the gamecontroller mapping isn't working :thinking:. 32blit won't get joystick events as it opens the device a controller and not a joystick (I think).

Daft-Freak commented 11 months ago

Or it could be a keyboard focus issue. Try adding SDL_SetKeyboardFocus(window) in CreateWindow.

(Remembering some of the issues from getting controllers working in emscripten)

Gadgetoid commented 11 months ago

Sigh after hours of debugging and tinkering and losing sleep yes, it was an SDL_SetKeyboardFocus(window) needed in the miyoo video driver. Thank you!

Patch https://github.com/Gadgetoid/steward-fu-sdl/commit/7141343b764bb5fe967eb514d1d9b3938ce2c653

Gadgetoid commented 8 months ago

Due to reasons, I've been avoiding pursuing any work-adjacent hobbies for the time being... this is on the backburner for now, but I think it's still worth solving some of the pieces of this puzzle since it will make future ports easier.

Daft-Freak commented 8 months ago

I think I have a tools patch somewhere for outputting different size icons, if that helps. (Needed to generate 256x256 JPEGs for the switch stuff)

Daft-Freak commented 8 months ago

Some other relevant stuff before I forget again:

https://github.com/Daft-Freak/sdl-cross-build https://github.com/Daft-Freak/32blit-boilerplate/tree/arm-cross-test

Gadgetoid commented 8 months ago

By the time I get back to this, there will be another handheld to try.

Still thinking about the feasibility of a Taito Super Pocket port 😆