Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
How to make a dedicated MAME Appliance on a Raspberry Pi 4B | Comment réaliser un système MAME dédié sur un Raspberry Pi 4/Pi 400

How to make a dedicated MAME Appliance on a Raspberry Pi 4/Pi 400

Note: the following steps are written in French. Feel free to translate to English.

Comment réaliser un système MAME dédié sur un Raspberry Pi 4/Pi 400

Pour la génération comme la mienne qui a connu l’époque des arcades, où nous nous retrouvions dans un local sombre, bruyant et souvent enfumé abritant des dizaines de cabinets de jeux vidéos de tous les styles, cette époque a laissée des traces dans la mémoire de plusieurs d'entre nous. Nous en gardons en général de bons souvenirs, parfois même avec une pointe de nostalgie d'une jeunesse, de son innocence ou de son insouciance et du sentiment de liberté qui y était jadis associé.

Aujourd’hui, beaucoup d’entre nous rêvent de pouvoir un jour ressusciter l’ambiance unique de ces lieux et pouvoir jouer à nouveau aux jeux de leur jeunesse avec comme avantage de pouvoir partager ce plaisir et ce bonheur avec leur famille et amis.

Avec l’arrivé du Raspberry Pi, petit ordinateur abordable au format carte de crédit, et tout particulièrement depuis la disponibilité de la version 4 (sortie à l’été 2019) et Pi 400 (sortie à l'automne 2020), il s’avère désormais possible de faire tourner, sur un système optimisé adéquatement, la grande majorité des jeux des années 80 et 90 et même certains jeux des années 2000 et plus récents.

La problématique ?

J'ai longtemps cherché une solution tout-en-un, simple et robuste qui serait dédiée exclusivement à l'émulation des systèmes d'arcade et basée sur le célèbre émulateur Multiple Arcade Machine Emulator (MAME). Pour répondre à mes besoins, cette solution se devait d'être compacte et optimisée. Malheureusement pour moi et à mon grand désarroi, rien de tel n'existait. D'un côté, on retrouve les solutions d'émulation rétro (RetroPie, Lakka, Recalbox) qui émulent des consoles de jeux domestiques et qui permettent également d'émuler les jeux d'arcades à l'aide de versions de MAME adaptées, mais qui toutefois introduisent, de mon opinion personnelle, leur lot de contraintes (devoir posséder les versions de ROMs précises, la configuration des manettes d'arcades n'est pas native, l'interface de navigation n'est pas adaptée spécifiquement à l'émulation d'arcade, etc.). D'un autre côté, on a AdvanceMAME qui est optimisé pour le Raspberry Pi, mais aucune mise à jour n'a été effectuée depuis novembre 2018. De plus, ce dernier est basé sur une version de MAME (0.106) remontant à 2006.

La solution ?

Le faire soi-même : utiliser un OS minimal, compiler la toute dernière version de MAME (0.236 au moment d'écrire ces lignes) satisfaire ses dépendances et configurer le système de sorte qu'il démarre directement dans MAME, rien de plus, rien de moins. De cette façon, on peut utiliser les versions de ROMs les plus récentes, le soutien pour les manettes d'arcade est non seulement possible, mais facile et on utilise l'interface de sélection des ROMs native à MAME, qui est simple et efficace (nul besoin de prévoir un quelconque frontend pour lancer les ROMs).

Ce projet s’inspire de la philosophie du Just Enough Operating System (JeOS) : un système compact et minimal pour faire tourner, de manière la plus optimisée possible, une application. À titre d’exemples de JeOS, mentionnons LibreELEC (media center Kodi), Lakka (émulation de consoles de jeux) et Volumio (lecteur de musique Hi-Fi pour audiophiles).

L’objectif de ce tutoriel est de vous guider à partir de zéro pour monter, étape par étape, un système tout-en-un, minimal, optimisé et dédié qui fera tourner exclusivement la plus récente version de MAME.

Caractéristiques et fonctionnalités :

  • Basé sur Raspberry Pi OS Lite (anciennement Raspbian Lite, édition de Linux minimale basée sur Debian) ;
  • Au démarrage, affichage d'un splash personnalisé (par exemple, le logo de MAME) ;
  • La version courante de l'émulateur MAME démarre automatiquement, puis affiche l'écran de sélection des ROMs (GUI) ;
  • Lorsque l'on quitte MAME, le système initie un arrêt (shutdown) ;
  • Pendant l'arrêt (shutdown), affichage d'un splash personnalisé (par exemple, le logo de MAME) ;
  • Lorsque les opérations d'arrêt sont complétées, le système s'éteint (power off) ;
  • Pour préserver la durée de vie de la carte SD, le système de fichiers racine (root filesystem) est maintenu en mode lecture-seule ;
  • Les meilleurs pointages (hiscores) de chaque ROMs sont sauvegardés et sont donc persistants ;
  • Un mode pour la maintenance est proposé (appelé le mode Service) afin de permettre les mises à jour du système et effectuer la gestion des ROMs et des Snapshots (via un partage de fichiers Samba).
  • Gestion automatisée du matériel graphique associé aux ROMs dès l'ajout ou le retrait de ceux-ci au sein du système.

À noter que grâce aux optimisations proposées à travers ce guide, un Raspberry Pi 4/Pi 400 muni d'aussi peu que 1 Go de mémoire vive peut être considéré comme adéquat. À noter toutefois que si vous compilez MAME depuis le Pi 4/Pi 400 lui-même, vous devrez posséder les 4 Go de mémoire vive afin que la compilation puisse s'effectuer correctement.

Bien que je crois me débrouiller pas trop mal avec Linux, je ne me considère pas pour autant un expert. Dans ce contexte, il est toujours possible que des erreurs ou incohérences se soient glissées au sein de ce guide. Ce document est le fruit de deux mois d'expérimentations, d'essais et d'optimisations de manière itérative. Si vous relevez des incohérences ou des erreurs, n'hésitez pas à me le laisser savoir, question que je puisse apporter la ou les corrections.

En terminant, si vous décidez de suivre cette procédure, vous le faites à vos propres risques et je ne peux nullement être tenu responsable pour quelque préjudice que ce soit (notamment les pertes de données, mais sans s'y limiter).

Voici ci-dessous une brève démonstration :

Courte démonstration

-------------- DÉBUT DE LA PROCÉDURE --------------

Téléchargement de Raspberry Pi OS (32-bit) Lite (anciennement Raspbian Lite) et écriture sur carte microSD :

Page de téléchargement : https://www.raspberrypi.org/downloads/raspberry-pi-os/

Les étapes ci-dessous sont destinées à un ordinateur tournant sous Linux :

wget https://downloads.raspberrypi.org/raspios_lite_armhf_latest -O raspios-buster-lite-armhf-latest.zip

Pour déterminer le nom du block device associé à la carte microSD :

lsblk

Si la carte était déjà formatée, il est possible que vous deviez démonter la (les) partition(s) présentes :

sudo umount /dev/sdd1	# Exemple : Carte SD détectée comme /dev/sdd, partition #1
sudo umount /dev/sdd2	# Exemple : Carte SD détectée comme /dev/sdd, partition #2

Décompression de l’archive .zip qui contient le fichier-image (.img)

unzip raspios-buster-lite-armhf-latest.zip

Écriture de l’image sur la carte microSD (remplacez /dev/sdd par le block device associé à votre carte) :

sudo dd if=$(echo *-raspios-buster-armhf-lite.img) of=/dev/sdd bs=8192

Ajustement de la taille du système de fichiers racine à 10 Go

Si tout s'est bien déroulé à l'étape précédente, il est possible que votre système Linux monte automatiquement à nouveau les deux partitions boot et rootfs.

Si tel est le cas, vous devrez démonter ces partitions (boot et rootfs) à l'aide des commandes suivantes (remplacez /dev/sdd par le block device de votre carte) :

sudo umount /dev/sdd1
sudo umount /dev/sdd2

Ouverture du gestionnaire de partitions fdisk :

sudo fdisk /dev/sdd
  1. Afficher la table des partitions (p)
  2. Supprimer la seconde partition (d, 2)
  3. Re-créer la partition (n, p, 2)
  4. À l'étape First sector, spécifier l'ancienne valeur du premier secteur (vous référer à la table précédamment affichée)
  5. À l'étape Last sector, inscrire +10G (valeur de 10 Go recommandée) ou toute autre taille que vous jugez appropriée
  6. À la question Do you want to remove the signature?, répondez par non (N)
  7. Afficher la table des partitions (p)
  8. Créer une nouvelle partition (n, p, 3)
  9. À l'étape First sector, spécifier la valeur End de la partition #2, en y additionnant le nombre 1
  10. À l'étape Last sector, accepter la valeur par défaut afin d'allouer tout l'espace non-partitionné
  11. Sauvegarder la table des partitions et quitter (w).

Forcez le système à relie la nouvelle table des partitions (remplacez /dev/sdd par le block device de votre carte) :

sudo partprobe /dev/sdd

Effectuez une vérification du système de fichiers, puis ajustez-le à la nouvelle taille de partition (remplacez /dev/sdd par le block device de votre carte) :

sudo e2fsck -f /dev/sdd2
sudo resize2fs /dev/sdd2
sync

Premier démarrage

À ce stade, les périphériques suivants doivent avoir été branchés à votre Raspberry Pi 4/Pi 400 :

  • Un clavier USB dans un port USB libre (non-applicable à la Pi 400) ;
  • Un écran (téléviseur ou moniteur d'ordinateur) via un câble micro-HDMI vers HDMI ;
  • Un câble Ethernet branché au connecteur RJ-45.

Insérer la carte microSD dans la fente de votre Raspberry Pi 4/Pi 400 et mettez l'unité sous tension.

Lors du premier démarrage, le système vous indiquera le message suivant :

Root partition should be last partition

Ceci est normal, nous avons créé une partition qui est positionnée après la partition du système de fichiers racine (root filesystem). Veuillez simplement ignorer ce message et le système redémarrera.

Première ouverture de session sur la console

login: pi
password: raspberry

Changement du mot de passe pour le compte pi

passwd

Activation de l’accès via SSH

sudo systemctl enable ssh
sudo systemctl start ssh

Pour obtenir l’adresse IP courante du système :

hostname -I

À partir de ce point, vous pouvez poursuivre à partir d’une session SSH.

Mise à jour des paquets

Le noyau (kernel) 5.10 incorpore des ajouts de fonctionnalités au niveau USB (soutien pour USB4) et introduit un bug intermittent sur le bus USB : le bus gèle momentanément (durée d'environ 4 ou 5 secondes), puis redevient disponible. Les événements survenus pendant le gel sont perdus. Pour contourner ce problème, je recommande de rester sur le noyau 5.4 jusqu'à ce que le noyau 5.10 soit plus mature. Nous allons utiliser une version récente du noyau 5.4 qui n'est pas impactée par ce bug, soit la version 5.4.77.

Mise à niveau à la version 5.4.77 du noyau :

sudo rpi-update cc9ff6c7d1b9be5465c24c75941b049f94a6bd32

Mise sur hold de la version du noyau :

sudo apt-mark hold raspberrypi-kernel

Mise à jour des paquets du système :

sudo apt-get update && sudo apt-get upgrade -y

Création des alias

L’idée, c’est de créer deux modes :

  • Le mode Arcade (alias arcademode) : ce mode démarre automatiquement et directement l’émulateur MAME (et rien d'autre).
  • Le mode Service (alias servicemode) :
    • Aucun démmarrage automatique de MAME ;
    • Permet le login depuis la console ;
    • Active le partage de fichier réseau (via Samba) de la partition /data pour permettre la gestion des ROMs et Snapshots.
    • Surveille l'emplacement des fichiers de ROM et :
      • télécharge automatiquement le matériel graphique associé lors d'un ajout ;
      • supprime automatiquement le matériel graphique associé lors d'un retrait/suppression.

Édition du fichier de définition des alias du shell Bash :

nano ~/.bash_aliases

Ajouter ces lignes pour créer les alias dont nous avons besoin :

alias update='sudo apt-get update && sudo apt-get upgrade -y'
alias cputemp='/opt/vc/bin/vcgencmd measure_temp'
alias cpufreq="echo Clock Speed=$(($(/opt/vc/bin/vcgencmd measure_clock arm | awk -F '=' '{print $2}')/1000000)) MHz"
alias frontend='_frontend(){ if [[ "$1" =~ ^(mame|attract|advance)$ ]]; then sudo sed -i "s/FRONTEND=.*$/FRONTEND="$1"/g" /etc/environment && echo "Frontend set to: "$1" (reboot to apply)."; else echo "Invalid or missing argument. Try: mame, attract or advance"; fi;}; _frontend'

# Aliases to switch between Arcade Mode and Service Mode
alias arcademode='sudo systemctl enable mame-autostart.service'
alias servicemode='sudo systemctl disable mame-autostart.service'

Sauvegarder, logout et login à nouveau pour appliquer les nouveaux alias.

Supprimer l’avertissement (disclaimer) ci-dessous au login :

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.

À l’aide de cette commande :

sudo rm /etc/motd

Script de vérification de la plus récente version de MAME

nano ~/scripts/mame-versioncheck.sh

Coller les lignes ci-dessous, puis sauvegarder :

#!/bin/bash

# This script check the latest available version of MAME and display a notice if the current version is older.

CHECKURL=https://github.com/mamedev/mame/releases/latest
HTMLTAG='<title>Release MAME'

function version { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; }

if [ ! -z $MAMEVER ]; then
    echo -n "MAME $MAMEVER."
    LATESTMAMEVER=$(wget -q -O - $CHECKURL | grep "$HTMLTAG" | awk '{print $3}')

    if [ -z $LATESTMAMEVER ]; then exit; fi  # We make sure wget was successful

    if [ $(version $LATESTMAMEVER) -gt $(version $MAMEVER) ]; then
        echo -n " A new version of MAME is available ($LATESTMAMEVER)."
    fi
    echo
fi

Ajustement des permissions pour permettre l’exécution du script :

chmod +x ~/scripts/mame-versioncheck.sh

Script de vérification de la plus récente version de Hypseus Singe

nano ~/scripts/hypseus-versioncheck.sh

Coller les lignes ci-dessous, puis sauvegarder :

#!/bin/bash

# This script check the latest available version of Hypseus Singe and display a notice if the current version is older.

CHECKURL=https://github.com/DirtBagXon/hypseus-singe/releases/latest
HTMLTAG='<title>Release hypseus-singe'
HYPSEUSPATH=/home/pi/hypseus

function version { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; }

[ -x $HYPSEUSPATH/hypseus ] && HYPSEUSVER=$($HYPSEUSPATH/hypseus -v | awk '/^\[version\]/{print $4}')

if [ ! -z $HYPSEUSVER ]; then
    echo -n "Hypseus Singe $HYPSEUSVER."
    LATESTHYPSEUSVER=$(wget -q -O - $CHECKURL | grep "$HTMLTAG" | awk '{print $3}')

    if [ -z $LATESTHYPSEUSVER ]; then exit; fi  # We make sure wget was successful

    LATESTHYPSEUSVER=${LATESTHYPSEUSVER##v}             # Strip the leading v
    HYPSEUSVER=$(echo $HYPSEUSVER | sed 's/^v*//' | sed 's/-RPi$//')    # Strip the leading v and trailing -RPi

    if [ $(version $LATESTHYPSEUSVER) -gt $(version $HYPSEUSVER) ]; then
        echo -n " A new version of Hypseus Singe is available ($LATESTHYPSEUSVER)."
    fi
    echo
fi

Ajustement des permissions pour permettre l’exécution du script :

chmod +x ~/scripts/hypseus-versioncheck.sh

Affichage des notices au login

sudo nano /etc/bash.bashrc

Pour afficher le mode actif (Service ou Arcade), la version de MAME active, le Frontend courant, ainsi que le ROM couramment émulé par MAME (si applicable), coller les lignes ci-dessous à la fin du fichier :

[ -z $MAMEVER ] && [ -x /home/pi/mame/mame ] && export MAMEVER=$(/home/pi/mame/mame -version | cut -d' ' -f1)

echo '----------------------------------------------------------------------'
echo "The system is currently in $(systemctl -q is-active mame-autostart.service && echo ARCADE || echo SERVICE) mode."
echo "Current Frontend is: $(case $(grep FRONTEND= /etc/environment | cut -d= -f2) in attract) echo "Attract Mode$([ -x /usr/local/bin/attract ] && attract -v | awk '/Attract-Mode/ {print " " $2}')" ;; advance) echo AdvanceMENU ;; mame) echo 'MAME GUI' ;; *) echo 'NOT SET' ;; esac)."
MAMEROM=$(ps h -C mame -o cmd | awk '{print $2}')
[ ! -z $MAMEROM ] && echo Currently emulated ROM: $(/home/pi/mame/mame -listfull $MAMEROM | awk -F '"' '!/Description:$/ {print $2}').

Pour afficher un message lorsqu'une nouvelle version de MAME ou Hypseus Singe sont disponibles, coller les lignes ci-dessous à la suite de celles ci-dessus, puis sauvegarder :

[ -x ~/scripts/mame-versioncheck.sh    ] && . ~/scripts/mame-versioncheck.sh
[ -x ~/scripts/hypseus-versioncheck.sh ] && . ~/scripts/hypseus-versioncheck.sh

Ajouter la mention indiquant que le mode Service est en fonction lorsque le getty de la console (getty@tty1.service) est actif :

sudo nano /etc/issue

Ajouter les lignes SERVICE MODE et IP Address: \4 (tel qu'indiqué ci-dessous) sous le texte déjà présent (laisser deux lignes vides en dessous), puis sauvegarder :

Raspbian GNU/Linux 10 \n \l

S E R V I C E      M O D E

IP Address: \4

Personnalisations du système

Réglage du fuseau horaire :

sudo dpkg-reconfigure tzdata

[Optionnel] Configuration de la langue du clavier et de l'emplacement :

sudo dpkg-reconfigure keyboard-configuration
sudo dpkg-reconfigure locales

[Optionnel] Configuration du serveur de synchronisation de l'heure sur internet (NTP) :

sudo nano /etc/systemd/timesyncd.conf

À la ligne NTP=, spécifier le nom du serveur NTP (ou du pool de serveurs, selon NTP Pool Project) à utiliser, puis sauvegarder :

NTP=ca.pool.ntp.org

Changement du nom d’hôte :

sudo nano /etc/hostname
sudo nano /etc/hosts

Repérer la ligne qui débute par 127.0.0.1 et remplacer raspberrypi à droite par le nom désiré (par exemple : arcade), puis redémarrer à l'aide de la commande ci-dessous :

sudo reboot

Ajustement des privilèges du compte pi

Afin que SDL2 puisse accéder directement au noeud de rendu graphique DRM /dev/dri/renderD128, nous devons ajouter le groupe render au compte pi. Pour ce faire :

sudo usermod -a -G render pi

[Optionnel] Désactivation du Wi-Fi

Comme je ne compte utiliser que l’interface Ethernet filaire, je désactive Wi-Fi.

sudo nano /etc/modprobe.d/raspi-blacklist.conf

Coller les lignes ci-dessous :

# WiFi
blacklist brcmfmac
blacklist brcmutil

Désactiver WPA Supplicant (lié au Wi-Fi) :

sudo apt-get remove wpasupplicant -y

[Optionnel] Désactivation de Bluetooth

Comme je ne compte pas utiliser de périphériques Bluetooth, je le désactive et le désinstalle.

sudo nano /etc/modprobe.d/raspi-blacklist.conf

Coller les lignes ci-dessous :

# Bluetooth
blacklist btbcm
blacklist hci_uart

Retrait des paquets liés à Bluetooth :

sudo apt-get remove bluez pi-bluetooth -y

[Optionnel] Désactivation de IPv6

Si vous n'utilisez pas IPv6, vous pouvez le désactiver comme suit :

sudo nano /boot/cmdline.txt

Ajoutez la commande suivante à la ligne de commande du kernel (sur la même ligne que les autres commandes), puis sauvegardez :

ipv6.disable=1

Nous devons également ajuster le drop-in du client DHCP afin d'ignorer complètement IPv6 :

sudo nano /etc/systemd/system/dhcpcd.service.d/wait.conf

À la ligne :

ExecStart=/usr/lib/dhcpcd5/dhcpcd -q -w

Ajoutez -4 après dhcpcd, puis sauvegardez :

ExecStart=/usr/lib/dhcpcd5/dhcpcd -4 -q -w

Désactivation de Avahi (mDNS)

sudo apt-get remove avahi-daemon -y

Augmentation des performances (Overclocking)

IMPORTANT : votre Raspberry Pi 4 doit être adéquatement refroidi (soit passivement par des dissipateurs de chaleur ou encore par un boîtier en métal spécialement adapté avec contact sur le CPU et qui agit à titre de dissipateur, soit par une ventilation adéquate).

À NOTER que si vous décidez de faire ce changement, vous le faites à vos propres risques et périls, je ne peux être tenu responsable de quoi que ce soit.

sudo nano /boot/config.txt

Ajouter ce bloc à la fin du fichier, puis sauvegarder :

# Overclocking
over_voltage=2
arm_freq=1750

Pour appliquer le changement, redémarrer le système à l'aide de cette commande :

sudo reboot

Bascule du CPU Governor en mode Performance

Afin de prévenir l'abaissement automatique de la fréquence du CPU lorsque celui-ci est moins sollicité (c'est le comportement du mode On Demand), nous devons ajuster le réglage du Governor et l'affecter à la valeur Performance.

Pour ce faire :

sudo apt-get install cpufrequtils -y
grep -q GOVERNOR= /etc/init.d/cpufrequtils && sudo sed -i "s/GOVERNOR=.*$/GOVERNOR=\"performance\"/g" /etc/init.d/cpufrequtils

Appliquer les changements :

sudo systemctl daemon-reload
sudo systemctl restart cpufrequtils.service

Valider les changements :

cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

La commande ci-dessus devrait retourner la valeur performance à 4 reprises (une pour chaque coeur de CPU).

cpufreq

L'invocation de l'alias ci-dessus (que nous avons défini plus haut) devrait retourner Clock Speed=1750 MHz, qui correspond à la fréquence d'overclocking que nous avons spécifiée plus haut.

Activation du pilote DRM VC4 V3D

sudo nano /boot/config.txt

Ajouter ce bloc à la fin du fichier, puis sauvegarder :

[pi4]
# Enable DRM VC4 V3D driver on top of the dispmanx display stack
dtoverlay=vc4-fkms-v3d
max_framebuffers=2

Compilation de SDL2 (optimisé, sans X11)

Comme nous utilisons un système Linux minimal sans système graphique de fenêtrage comme X11 et que nous voulons tirer parti au maximum des ressources du Raspberry Pi 4, nous devons compiler la librairie graphique SDL2 sans le soutien pour X11 et également lui indiquer d’offrir le soutien pour les pilotes de type Kernel Mode-Setting/Direct Rendering Manager (KMS/DRM).

Installer les dépendances pour pouvoir compiler :

sudo apt-get install build-essential -y

Selon la page Compile SDL2 from source, installer les dépendances SDL2 :

sudo apt-get install libfreetype6-dev libdrm-dev libgbm-dev libudev-dev libdbus-1-dev libasound2-dev liblzma-dev libjpeg-dev libtiff-dev libwebp-dev -y

Installer les dépendance OpenGL ES 2 :

sudo apt-get install libgles2-mesa-dev -y

Télécharger, décompresser, puis lancer l'utilitaire de configuration de SDL 2.0.16 (plus récente version au moment d'écrire ces lignes) :

wget https://libsdl.org/release/SDL2-2.0.16.zip
unzip SDL2-2.0.16.zip
cd SDL2-2.0.16
./configure --disable-video-opengl --disable-video-opengles1 --disable-video-x11 --disable-pulseaudio --disable-esd --disable-video-wayland --disable-video-rpi --disable-video-vulkan --enable-video-kmsdrm --enable-video-opengles2 --enable-alsa --enable-arm-neon --enable-arm-simd

Le sommaire du programme de configuration devrait afficher un sommaire similaire à celui-ci :

SDL2 Configure Summary:
Building Shared Libraries
Building Static Libraries
Enabled modules : atomic audio video render events joystick haptic sensor power filesystem threads timers file loadso cpuinfo assembly
Assembly Math   :
Audio drivers   : disk dummy oss alsa(dynamic)
Video drivers   : dummy kmsdrm(dynamic) opengl_es2
Input drivers   : linuxev linuxkd
Using libsamplerate : NO
Using libudev       : YES
Using dbus          : YES
Using ime           : YES
Using ibus          : NO
Using fcitx         : NO

Confirmer qu’on a bien le soutien pour KMS/DRM (ligne Video drivers) et Alsa (ligne Audio drivers) et lancer la compilation et l’installation :

Démarrer la compilation optimisée et l'installation à l'aide de ces commandes :

make -j $(nproc) CFLAGS='-mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard'

sudo make install

Compilation de SDL2_ttf

MAME utilise les polices True Type. Le soutien dans SDL2 réside dans un module à part nommé SDL2_ttf. Nous allons le télécharger, le compiler et l’installer à l’aide des commandes suivantes :

cd ~
wget https://libsdl.org/projects/SDL_ttf/release/SDL2_ttf-2.0.15.tar.gz

tar zxvf SDL2_ttf-2.0.15.tar.gz
cd SDL2_ttf-2.0.15
./configure
make -j $(nproc)
sudo make install
sudo ldconfig -v

Retrait du code source de SDL2 :

cd ~
rm SDL2-2.0.16.zip
rm SDL2_ttf-2.0.15.tar.gz
rm -R SDL2-2.0.16
rm -R SDL2_ttf-2.0.15

Compilation de MAME (optimisé, sans X11)

Nous devons d'abord créer une patch pour ajuster un fichier source de MAME (dans BGFX, une référence est effectuée à X11, même lorsqu’on passe NO_X11=1 au compilateur -- un bug a été soumis à cet effet).

Création du fichier de patch pour drawbgfx.cpp :

mkdir ~/scripts
nano ~/scripts/drawbgfx.cpp.patch

Coller les lignes ci-dessous dans l'éditeur, puis sauvegarder :

diff -ruN a/src/osd/modules/render/drawbgfx.cpp b/src/osd/modules/render/drawbgfx.cpp
--- a/src/osd/modules/render/drawbgfx.cpp	2021-12-28 10:17:03.000000000 -0500
+++ b/src/osd/modules/render/drawbgfx.cpp	2022-01-04 14:34:02.279472253 -0500
@@ -171,7 +171,8 @@
 	}
 
 #   if BX_PLATFORM_LINUX || BX_PLATFORM_BSD || BX_PLATFORM_RPI
-	return (void*)wmi.info.x11.window;
+	// return (void*)wmi.info.x11.window;
+	return (void*)_window;
 #   elif BX_PLATFORM_OSX
 	return wmi.info.cocoa.window;
 #   elif BX_PLATFORM_WINDOWS
@@ -192,8 +193,10 @@
 
 	bgfx::PlatformData pd;
 #   if BX_PLATFORM_LINUX || BX_PLATFORM_BSD
-	pd.ndt          = wmi.info.x11.display;
-	pd.nwh          = (void*)(uintptr_t)wmi.info.x11.window;
+//	pd.ndt          = wmi.info.x11.display;
+//	pd.nwh          = (void*)(uintptr_t)wmi.info.x11.window;
+	pd.ndt = NULL;
+	pd.nwh = _window;
 #   elif BX_PLATFORM_OSX
 	pd.ndt          = NULL;
 	pd.nwh          = wmi.info.cocoa.window;

Création du script automatisé de compilation de MAME :

nano ~/scripts/mame-updater.sh

Coller les lignes ci-dessous dans l'éditeur, puis sauvegarder :

#!/bin/bash

# This script update MAME to the specified version.

# GCC compiler optimization for ARM-based systems : https://gist.github.com/fm4dd/c663217935dc17f0fc73c9c81b0aa845
#ARCHOPTS='-march=armv8-a+crc+simd -mcpu=cortex-a72 -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard -mneon-for-64bits -funsafe-math-optimizations -munaligned-access -fexpensive-optimizations'

# A tester.....
ARCHOPTS='-march=armv8-a+crc+simd -mcpu=cortex-a72 -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard -funsafe-math-optimizations -fprefetch-loop-arrays -fexpensive-optimizations'
MAKEOPTS='TARGETOS=linux NO_X11=1 NOWERROR=1 NO_USE_XINPUT=1 NO_USE_XINPUT_WII_LIGHTGUN_HACK=1 NO_OPENGL=1 USE_QTDEBUG=0 DEBUG=0 REGENIE=1 NO_BGFX=1 FORCE_DRC_C_BACKEND=1 NO_USE_PORTAUDIO=1'
MAXTHREAD=3  # From MAME version 0.227 and up, we should use a max. of 3 threads to avoid an out of memory error.

secs_to_human() {
    echo "$(( ${1} / 3600 ))h $(( (${1} / 60) % 60 ))m $(( ${1} % 60 ))s"
    }

fs_unlock() {	# Put root filesystem in read/write mode
    if [ $(findmnt -no OPTIONS /) = 'ro,noatime' ]; then
        sudo mount -o remount,rw /
        FSWASRO=1
    fi
    }

fs_lock() {	# Put root filesystem in read-only mode
    if [ "$FSWASRO" = "1" ]; then
        sleep 5
        sudo mount -o remount,ro /
    fi
    }

set_env() {	# Make an environment variable persistent
    local KEY=$(echo $1 | awk -F '=' '{print $1}')
    local VALUE=$(echo $1 | awk -F '=' '{print $2}')
    grep -q $KEY= /etc/environment && sudo sed -i "s%$KEY=.*$%$KEY=$VALUE%g" /etc/environment
    grep -q $KEY= /etc/environment || echo "$KEY=$VALUE" | sudo tee -a /etc/environment
    }

get_history() {      # Grab the latest history.xml file
    local BASEURL=https://www.arcade-history.com
    local BASETAG='<a class="noir" rel="nofollow" href="../dats/'
    local REGEX='[^*]*(<a class="noir" rel="nofollow" href="../dats/)(.*?)("><img src="images/design/download1.gif" height="40px" /><br />History XML )[^*]*'

    HISTORYFILE=$(wget -q -O - $BASEURL/index.php?page=download | grep "$BASETAG" | sed -nE "s%$REGEX%\2%p")
    wget -q $BASEURL/dats/$HISTORYFILE -P ~    # Download the file
    unzip -o ~/$HISTORYFILE history.xml -d ~/.mame  # From MAME 0.228 and up, we use history.xml, instead of history.dat
    if [ -d ~/.mame/history ]; then	           # Check if history folder exist
        mv ~/.mame/history.xml ~/.mame/history
    fi
    rm ~/$HISTORYFILE                          # Cleanup
    }

if (systemctl -q is-active mame-autostart.service) then
    echo "The system must be put in SERVICE Mode first."
    exit
fi

if [ ! $1 ]; then
    echo Usage: $0 VER
    echo '  Where VER is the 4-digit version number of MAME to update (for example: 0224).'
else
    if [ $(free -g | awk '/^Mem:/{print $2}') -lt 3 ]; then
        echo You need 4 GB of RAM to compile MAME with multithread support.
        exit
    fi
    SCRIPTPATH=${0%/*}
    MAMEVER=$1
    MAMEBINPATH=/home/pi/mame$MAMEVER

    fs_unlock

    if [ ! -d $MAMEBINPATH ]; then
        cd ~
        if [ ! -f ~/mame$MAMEVER.zip ]; then	# Not already downloaded
            wget https://github.com/mamedev/mame/archive/mame$MAMEVER.zip
        fi

        if [ -f ~/mame$MAMEVER.zip ]; then	# If download successful, uncompress ...
            unzip mame$MAMEVER.zip
            mv mame-mame$MAMEVER mame$MAMEVER
            rm mame$MAMEVER.zip
        fi
    fi

    if [ ! -x $MAMEBINPATH/mame ]; then		# We build only if not already built
        # Build of MAME

        # Dependencies
        # Swap requirement
        sudo apt-get install dphys-swapfile -y
        if [ "$(cat /etc/dphys-swapfile | grep '^CONF_SWAPSIZE' | awk -F '=' '{print $2}')" != "2048" ]; then
            sudo sed -i 's/^\(#\)\{0,1\}\( \)\{0,8\}CONF_SWAPSIZE=.*$/CONF_SWAPSIZE=2048/g' /etc/dphys-swapfile
        fi
        # The swap value should be 2048

        # Activate the swap...
        sudo systemctl stop dphys-swapfile.service
        sudo systemctl start dphys-swapfile.service
        # Build dependencies
        sudo apt-get install build-essential -y

        # Patching drawbgfx.cpp...
        if [ -f $SCRIPTPATH/drawbgfx.cpp.patch ]; then
            patch -r - -Ni $SCRIPTPATH/drawbgfx.cpp.patch $MAMEBINPATH/src/osd/modules/render/drawbgfx.cpp
        fi
        cd $MAMEBINPATH
        echo MAKE CMDLINE=make -j $MAXTHREAD ARCHOPTS=\"$ARCHOPTS\" $MAKEOPTS
        BUILDSTART=$(date +%s)
        echo Build start time: $(date +"%T")
        echo -----------------------------------------------------------------------------------
        echo Please wait until the build is completed \(about 5 hours\)...
        echo -----------------------------------------------------------------------------------
        make -j $MAXTHREAD ARCHOPTS="$ARCHOPTS" $MAKEOPTS
        echo Build time took: $(secs_to_human "$(($(date +%s) - ${BUILDSTART}))").

        if [ -x $MAMEBINPATH/mame ]; then
            echo -----------------------------------------------------------------------------------
            echo Build Success!
            echo -----------------------------------------------------------------------------------
            # Successful build!
            # We make sure the SDL2 environment variables are persistent...
            set_env SDL_VIDEODRIVER=kmsdrm
            set_env SDL_RENDER_DRIVER=opengles2
            set_env SDL_RENDER_VSYNC=1
            set_env SDL_GRAB_KEYBOARD=1
            set_env SDL_VIDEO_GLES2=1
            
            # MAME data path symlink creation (if /data partition is available)
            if [ -d /data/mame ]; then
                if [ ! -L ~/.mame ]; then ln -s /data/mame ~/.mame; fi
            else
                if [ ! -d ~/.mame ]; then mkdir ~/.mame; fi     # This directory is temporary, used for mame.ini creation
            fi
            
            # MAME binary symlink creation or update
            if [ -L ~/mame ]; then rm ~/mame; fi
            ln -s $MAMEBINPATH ~/mame
            
            # If mame.ini does not exist, let's create it
            if [ ! -f ~/.mame/mame.ini ]; then
                cd ~/.mame
                $MAMEBINPATH/mame -cc
            fi
            
            if [ -z $FRONTEND ]; then set_env FRONTEND=mame; fi

            # Get the latest history.xml file
            echo Applying latest history.xml...
            get_history

            # Freeing some space...
            for f in src build 3rdparty roms
            do
                rm -Rf $MAMEBINPATH/$f
            done
            
            # Removing dependencies
            echo Removing dependencies...
            # Removing swap...
            sudo systemctl stop dphys-swapfile.service
            sudo rm /var/swap
            sudo apt-get remove dphys-swapfile build-essential -y
            sudo apt-get autoremove -y
        else
            echo -----------------------------------------------------------------------------------
            echo Build FAILED.
            echo -----------------------------------------------------------------------------------
        fi
    fi
    fs_lock
fi

Ajustement des permissions pour permettre l’exécution du script :

chmod +x ~/scripts/mame-updater.sh

Installer les dépendances de MAME :

sudo apt-get install fontconfig libfontconfig-dev libx11-dev libpulse-dev -y

Compilation de MAME 0.233 :

./scripts/mame-updater.sh 0233

Patienter environ 5 heures et demie (ce temps est obtenu avec un Raspberry Pi 4 overclocked), afin que la compilation se complète…

À noter que des avertissements (de couleur cyan) apparaîtront, ici et là, lors de la compilation : il suffit de les ignorer, ils ne compromettent pas le processus.

Installation de la police TTF « Liberation Sans » pour MAME

Exécuter ces commandes :

cd ~
wget http://dl.dafont.com/dl/?f=liberation_sans -O liberation_sans.zip
sudo mkdir /usr/share/fonts/truetype/liberation-fonts
sudo unzip /home/pi/liberation_sans.zip *.ttf -d /usr/share/fonts/truetype/liberation-fonts
rm liberation_sans.zip

Redémarrer le système à ce stade afin de mettre en force les variables d'environnement propres à MAME :

sudo reboot

Configuration de MAME

Spécifier les réglages ci-dessous dans le fichier mame.ini :

nano ~/.mame/mame.ini

Externalisation des dossiers vers le profil. Coller les lignes ci-dessous aux endroits appropriés, puis sauvegarder :

rompath                   $HOME/.mame/roms
inipath                   $HOME/.mame/ini
artpath                   $HOME/.mame/artwork
ctrlrpath                 $HOME/.mame/ctrlr
homepath                  $HOME/.mame/lua
samplepath                $HOME/.mame/samples
hashpath                  $HOME/mame/hash
pluginspath               $HOME/mame/plugins
languagepath              $HOME/mame/language

state_directory           $HOME/.mame/sta
cfg_directory             $HOME/.mame/cfg
nvram_directory           $HOME/.mame/nvram
memcard_directory         $HOME/.mame/memcard
snapshot_directory        $HOME/.mame/snap
input_directory           $HOME/.mame/inp
diff_directory            $HOME/.mame/diff

Réglages divers - Coller les lignes ci-dessous aux endroits appropriés et sauvegarder :

#
# OSD VIDEO OPTIONS
#
video                     accel

#
# OSD INPUT OPTIONS
#
multimouse                1

#
# CORE SOUND OPTIONS
#
samplerate                22050

#
# CORE MISC OPTIONS
#

skip_gameinfo             1

#
# SDL LOW-LEVEL DRIVER OPTIONS
#
videodriver               kmsdrm
renderdriver              opengles2
audiodriver               alsa

[Optionnel] Personnalisations additionnelles de MAME

J’ajoute personnellement un filtre pour créer un effet semblable aux écrans cathodiques (scanlines). De plus, pour tester je possè un contrôleur X-Arcade Solo pour lequel je spécifie le fichier de mappings associé :

nano ~/.mame/mame.ini

Coller ces lignes :

effect                    scanlines
ctrlr                     xarcade

[Optionnel] Personnalisations X-Arcade Solo

J'apporte certains ajustements au fichier de mappings de ma manette X-Arcade Solo de sorte qu'aucun clavier ne soit nécessaire pour naviguer dans les menus et quitter MAME.

nano ~/mame/ctrlr/xarcade.cfg

Coller le texte ci-dessous pour UI_FOCUS_NEXT, UI_PAUSE et ajuster les éléments déjà présents UI_CONFIGURE et UI_CANCEL, puis sauvegarder :

                        <port type="UI_FOCUS_NEXT">     <!-- Custom remap to cycle through each section in main selection screen -->
                            <newseq type="standard">KEYCODE_TAB OR KEYCODE_LALT KEYCODE_4</newseq>
                        </port>

                        <port type="UI_PAUSE">          <!-- Custom remap to pause the game -->
                                <newseq type="standard">KEYCODE_P OR KEYCODE_3 KEYCODE_4</newseq>
                        </port>

                        <port type="UI_CONFIGURE">      <!-- Custom remap to get the in-game menu -->
                                <newseq type="standard">KEYCODE_TAB OR KEYCODE_LALT KEYCODE_4</newseq>
                        </port>

                        <port type="UI_CANCEL">         <!-- Custom remap to quit emulation and exit MAME if in the main selection screen -->
                                <newseq type="standard">KEYCODE_ESC OR KEYCODE_LALT KEYCODE_1</newseq>
                        </port>

Ajustements d'emplacements additionnels

Édition du fichier plugin.ini pour activer deux plugins (data et hiscore) :

nano ~/.mame/plugin.ini

Coller les lignes ci-dessous, puis sauvegarder :

#
# PLUGINS OPTIONS
#
cheat                     0
cheatfind                 0
console                   0
data                      1
dummy                     0
gdbstub                   0
hiscore                   1
layout                    0
portname                  0
timer                     0

Création du fichier hiscore.ini pour pouvoir ajuster le chemin des sauvegardes :

nano ~/.mame/hiscore.ini

Coller la ligne ci-dessous, puis sauvegarder :

hi_path                   $HOME/.mame/hi

Externalisation de dossiers additionnels au sein de ui.ini vers le profil :

nano ~/.mame/ui.ini

Ajuster les chemins ci-dessous en spécifiant le préfixe $HOME/.mame/ suivi du nom du dossier :

cabinets_directory        $HOME/.mame/cabinets
cpanels_directory         $HOME/.mame/cpanels
pcbs_directory            $HOME/.mame/pcb
flyers_directory          $HOME/.mame/flyers
historypath               $HOME/.mame/history
titles_directory          $HOME/.mame/titles
marquees_directory        $HOME/.mame/marquees
icons_directory           $HOME/.mame/icons
ui_path                   $HOME/.mame/ui

Script de démarrage de MAME/Front-end

Le script de démarrage de MAME ou d'un Front-end relancera l’exécutable sélectionné tant et aussi longtemps que l’applicatif ne sera pas quitté de façon normale (code de sortie à 0).

Création du script :

nano ~/scripts/autostart.sh

Coller les lignes ci-dessous et sauvegarder :

#!/bin/bash

# This script launch the selected application (front-end or MAME emulator) and respawn it if quit unexpectedly.

if [ ! -z $FRONTEND ]; then
  while
    case ${FRONTEND,,} in
      attract)  # Attract Mode
        stty -echo
        /usr/local/bin/attract --loglevel silent >/dev/null 2>&1
        ;;
      advance)  # AdvanceMENU
        /home/pi/frontend/advance/advmenu
        ;;
      mame)     # MAME GUI
        /home/pi/mame/mame >/dev/null 2>/dev/null
        ;;
    esac
    (( $? != 0 ))
  do
    :
  done
else
    echo $0 - Variable FRONTEND is not defined!
    read -n 1 -s -r -p "Press any key to continue..."
    echo
fi

Ajustement des permissions pour permettre l’exécution du script :

chmod +x ~/scripts/autostart.sh

Démarrage automatique de l'émulateur MAME/Front-end

L'objectif est de créer un service systemd qui sera responsable de démarrer automatiquement l'émulateur MAME ou le Front-end sélectionné.

Lorsque ce service est activé, nous sommes en mode Arcade :

  • Désactivation du getty de la console (getty@tty1.service)
  • Désactivation du serveur Samba (smbd.service) afin maximiser les ressources pour l'émulation
  • Désactivation d'autres services pour maximiser les ressources
  • Démarrage automatique de l'émulateur MAME ou du Frond-end sélectionné

Lorsque ce service est désactivé, nous sommes en mode Service :

  • Activation du getty de la console (getty@tty1.service)
  • Activation du serveur Samba (smbd.service) afin de permettre la gestion des ROMs ainsi que le matériel graphique associé
  • Activation du service de gestion automatisé (mame-artwork-mgmt.service) du matériel graphique associé aux fichiers de ROM

Création du service systemd :

sudo systemctl edit mame-autostart.service --force --full

Coller les lignes ci-dessous et sauvegarder :

[Unit]
Description=MAME Appliance Autostart service
Conflicts=getty@tty1.service smbd.service nmbd.service rng-tools.service cron.service mame-artwork-mgmt.service
Requires=local-fs.target
After=local-fs.target

[Service]
User=pi
Group=pi
PAMName=login
Type=simple
ExecStart=/home/pi/scripts/autostart.sh
Restart=on-abort
RestartSec=5
TTYPath=/dev/tty1
StandardInput=tty

[Install]
WantedBy=multi-user.target
Also=shutdown.service

Puisque nous n'avons pas complété toutes les étapes, nous allons pour le moment désactiver le service :

sudo systemctl disable mame-autostart.service

Réactivation du curseur dans la console lorsque le getty@tty1 est activé (Service Mode) :

nano ~/.bashrc

Ajouter la ligne suivante à la fin, puis sauvegarder :

setterm --cursor on

Shutdown automatique du système dès qu’on quitte MAME

Dès que le service mame-autostart.service est arrêté, ceci déclenche le shutdown...

Création du service systemd :

sudo systemctl edit shutdown.service --force --full

Coller les lignes ci-dessous et sauvegarder :

[Unit]
Description=Shutdown and poweroff service
After=mame-autostart.service

[Service]
TTYPath=/dev/tty1
ExecStart=/sbin/poweroff
StandardInput=tty

[Install]
WantedBy=multi-user.target

Désactivation du service (pour le moment) :

sudo systemctl disable shutdown.service

Préparatifs pour l’écran de démarrage au logo de MAME

Retrait du splash en arc-en-ciel lors de la mise sous tension :

sudo nano /boot/config.txt

Ajouter cette ligne à la fin du fichier, puis sauvegarder :

disable_splash=1

Éditer le fichier associé à la ligne de commande passée au kernel :

sudo nano /boot/cmdline.txt

Ajouter les options ci-dessous à la ligne de commande passée au kernel :

Rediriger l’affichage des messages sur la console (tty1) vers tty3. Pour ce faire, changer console=tty1 pour console=tty3.

Cacher le logo du Raspberry Pi, ajouter :

logo.nologo

Cacher le curseur qui clignote, ajouter :

vt.global_cursor_default=0

Cacher l’affichage des messages et démarrage rapide, ajouter :

quiet fsck.mode=skip

Ce qui nous donne au final les options suivantes à ajouter à la ligne de commande :

console=tty3 logo.nologo vt.global_cursor_default=0 quiet fsck.mode=skip

Affichage de l’écran de démarrage (Custom Boot Splash)

Installation du binaire FIM qui permet d’afficher une image :

sudo apt-get install fim -y

Création du dossier des images de splash et copie de l’image du logo de MAME (mame.jpg) :

mkdir ~/splash
sudo mv ~/mame.jpg ~/splash

Pour le moment j’utilise le même splash pour le boot et le shutdown :

ln -s ~/splash/mame.jpg ~/splash/mame-boot.jpg
ln -s ~/splash/mame.jpg ~/splash/mame-shutdown.jpg

Création du service systemd :

sudo systemctl edit mame-bootsplash.service --force --full

Coller le texte ci-dessous et sauvegarder :

[Unit]
Description=MAME boot splash screen service
DefaultDependencies=no
After=local-fs.target

[Service]
Type=simple
StandardInput=tty
StandardOutput=tty
ExecStart=/usr/bin/fim -q --no-history /home/pi/splash/mame-boot.jpg
SuccessExitStatus=42

[Install]
WantedBy=sysinit.target

Activation du service :

sudo systemctl enable mame-bootsplash.service

Affichage de l’écran du shutdown (Custom Shutdown Splash)

Création du service systemd :

sudo systemctl edit mame-shutdownsplash.service --force --full

Coller le texte ci-dessous et sauvegarder :

[Unit]
Description=MAME Shutdown/Poweroff/Reboot Splash Screen service
DefaultDependencies=no
Before=halt.target
Conflicts=mame-bootsplash.service

[Service]
Type=simple
ExecStart=/usr/bin/fim -q --no-history /home/pi/splash/mame-shutdown.jpg
SuccessExitStatus=42

[Install]
WantedBy=reboot.target halt.target poweroff.target

Activation et démarrage du service :

sudo systemctl enable mame-shutdownsplash.service
sudo systemctl start mame-shutdownsplash.service

Pour afficher sommaire des unit files de systemd (avec hiérarchie) :

systemd-analyze critical-chain

Création de la partition séparée en lecture-écriture

La partition /data sera en lecture/écriture et utilisera le système de fichiers F2FS (Flash-Friendly File System).

Installer les binaires pour le système de fichiers F2FS :

sudo apt-get install f2fs-tools -y

Puisque la partition de données a été créée au début de la procédure, il ne nous reste plus qu'à la formater avec le système de fichiers F2FS :

sudo mkfs.f2fs -l data /dev/mmcblk0p3

Création du point de montage /data (et des sous-dossiers), ajustement des permissions, du propriétaire (owner) et du groupe :

sudo mkdir /data

Tester pour s'assurer qu'il n'y a pas eu d'erreur en montant manuellement la partition, puis valider le remontage :

sudo mount -t f2fs -o rw /dev/mmcblk0p3 /data
sudo mount -o remount,rw /data

Montage automatique dans fstab :

sudo nano /etc/fstab

Ajouter cette ligne à fstab :

/dev/mmcblk0p3        /data           f2fs    defaults,noatime,discard    0    2

Ajustements au fichier de montage automatique systèmes de fichiers

Afin que le montage de /boot et / s'effectuent sans dépendre d'un identifiant, nous allons basculer l'identification des partitions par leur nom de device.

Pour ce faire, nous éditons /etc/fstab :

sudo nano /etc/fstab

Assurez-vous que /boot et / soient référencés par leur nom de device (/dev/mmcblk0pX) au lieu de l'identifiant PARTUUID :

/dev/mmcblk0p1        /boot           vfat    defaults,rw                 0    2
/dev/mmcblk0p2        /               ext4    defaults,noatime,rw         0    1

Éditer la ligne de commande du kernel Linux :

sudo nano /boot/cmdline.txt

Repérer sur la ligne de commande le paramètre root=PARTUUID=xxxxxxxx et le remplacer par :

root=/dev/mmcblk0p2

Partage de /data via Samba

Installation du serveur Samba et des binaires associés :

sudo apt-get install samba samba-common-bin -y

À la question ci-dessous, répondez par Oui :

Modify smb.conf to use WINS settings from DHCP?

À ce point, il est possible que le système effectue un shutdown, ceci est normal.

Dû au redémarrage, la configuration de Samba ne s'est pas complétée. Pour la compléter, exécutez la commande ci-dessous :

sudo dpkg --configure -a

Configuration du serveur Samba :

sudo nano /etc/samba/smb.conf

À la section [global], retirer le commentaire «;» au début de la ligne suivante :

interfaces = 127.0.0.0/8 eth0

Sous la directive server role = standalone server, ajouter les lignes suivantes :

local master = no
domain master = no
preferred master = no

Comme le partage de fichiers n’est activé qu’en mode Service, j’autorise les connexions au partage en mode anonyme (sans authentification).

Toujours à la section [global], ajouter ces deux lignes :

security = user
guest account = nobody

Commenter (désactiver) en préfixant avec «;» les sections qui définissent les partage suivants :

[homes] [netlogon] [profiles] [printers] [print$]

À la fin de la section des partages, coller ce bloc pour partager /data et sauvegarder :

[Data]
  path = /data
  comment = Raspberry Pi MAME Appliance - Persistent data share.
  available = yes
  browsable = yes
  writable = yes
  guest ok = yes
  create mask = 0644
  directory mask = 0755
  force user = pi

Application des nouveaux réglages en basculant en mode Service :

servicemode
sudo reboot

Valider que le service Samba est bien en exécution à l'aide de la commande suivante :

systemctl status smbd

Tester le partage Samba en tentant d'accéder au partage depuis un ordinateur distant (par exemple : \\arcade\data depuis Windows ou smb://arcade/data depuis Linux). Vous devriez être en mesure de copier des fichiers depuis/vers le partage, ainsi que de les supprimer sans devoir vous authentifier (accès de type anonyme).

Déplacement des données vers la partition persistante /data

Création des dossiers et ajustement des permissions sur la partition persistante :

cd /data
sudo mkdir mame hypseus attract advance
cd mame
sudo mkdir artwork cabinets cfg cpanels ctrlr diff flyers hi history icons ini inp lua marquees memcard pcb nvram roms samples snap sta titles ui
sudo chown -R pi:pi /data
sudo chmod -R 3774 /data

Déplacement des fichiers de configuration de MAME (ui.ini, mame.ini, plugin.ini et hiscore.ini) vers /data/ini (rw)

cd ~/.mame
mv mame.ini ui.ini plugin.ini hiscore.ini /data/mame/ini

Si applicable, déplacer les autres éléments vers /data (rw)

mv ~/.mame/history.xml /data/mame/history
mv ~/mame/roms/*       /data/mame/roms/
mv ~/mame/snap/*       /data/mame/snap/
mv ~/mame/artwork/*    /data/mame/artwork/
mv ~/mame/ctrlr/*      /data/mame/ctrlr/

mv ~/.advance/*        /data/advance/
mv ~/.attract/*        /data/attract/
mv ~/.hypseus/*        /data/hypseus/

Création des symlinks…

Pour assurer la persistance des différents réglages liés à MAME :

ln -s /data/mame/ini/mame.ini    ~/.mame/mame.ini

Redirection des dossiers vers /data afin de permettre la persistence des réglages et données des jeux ainsi qu'une gestion facilitée des ROMs et du matériel graphique associé :

cd ~/mame
rm -R roms ctrlr snap nvram history artwork
cd ~; rmdir .mame .hypseus .advance .attract

ln -s /data/mame    ~/.mame
ln -s /data/attract ~/.attract
ln -s /data/advance ~/.advance
ln -s /data/hypseus ~/.hypseus

Script de téléchargement du matériel graphique de chaque ROMs

Je vous propose le script ci-dessous qui parcourt l'emplacement des fichiers de ROMs et tente de télécharger le matériel graphique associé à chaque ROM (snapshots, écran du titre, marquees, panneaux de commandes, cabinet).

nano ~/scripts/mame-scraper.sh
#!/bin/bash

# This script download the missing artwork files (snapshots, titles screens, marquees,
# control panels and cabinet pictures) based on the content of the ROMs path (ROM files).

# Usage: when a romname is passed (without the .zip extension), only the artwork for this
#        rom is downloaded.

URLPREFIX1=http://mamedb.blu-ferret.co.uk
URLPREFIX2=http://adb.arcadeitalia.net/media/mame.current

get_artworks() {
    # $1 is romname (without .zip)
    if [ ! $1 ]; then
        exit
    fi
    if [ -t 0 ]; then  echo -ne "\e[2K\rProcessing $1..."; fi
    for t in snap titles marquees cpanels cabinets
      do
        if [ ! -f /home/pi/.mame/$t/$1.png ]; then
          wget -q $URLPREFIX1/$t/$1.png -P /home/pi/.mame/$t
          if [ $? = 0 ]; then	# Download OK
              echo -n .
          else		# Download failed, let's try with the 2nd URL...
              case $t in
                  snap)
                      wget -q $URLPREFIX2/ingames/$1.png -P /home/pi/.mame/$t && echo -n .
                      ;;
                  titles)
                      wget -q $URLPREFIX2/$t/$1.png -P /home/pi/.mame/$t && echo -n .
                      ;;
              esac
          fi
        fi
      done
    }

shopt -s nullglob
cd /home/pi/.mame/roms

if [ $1 ]; then
    f=$1.zip
    if [ -f $f ]; then
        get_artworks ${f%.zip}
    fi
else
    for f in *.zip
        do
            get_artworks ${f%.zip}
        done
fi
if [ -t 0 ]; then echo -e '\e[2K\rCompleted!'; fi

Ajustement des permissions pour permettre l'exécution du script :

chmod +x mame-scraper.sh

Utilitaire de nettoyage des ROMs invalides

Je vous propose le script ci-dessous pour nettoyer les ROMs (fichiers .zip) qui sont invalides pour MAME, c'est à dire qu'une version plus récente est nécessaire (un dump de meilleure qualité existe).

nano ~/scripts/mame-badromspurge.sh

Coller le texte ci-dessous, puis sauvegarder :

#!/bin/bash

# This script delete/purge bad or invalid ROMs files.

shopt -s nullglob

for r in $(/home/pi/mame/mame -verifyroms | grep 'is bad' | awk '{print $2 ".zip"}')
  do
    if [ -f /home/pi/.mame/roms/$r ]; then
      sudo rm /home/pi/.mame/roms/$r
      echo -n .
    fi
  done
echo Completed!

Ajustement des permissions pour permettre l'exécution du script :

chmod +x ~/scripts/mame-badromspurge.sh

Utilitaire d'évaluation de la performance des ROMs*

Je vous propose le script ci-dessous pour évaluer la vitesse moyenne de chacun des ROMs, puis optionnellement (lorsque l'argument purge est passé), supprimer les ROMs qui ont une vitesse inférieure à 100 %.

nano ~/scripts/mame-benchmark.sh

Coller le texte ci-dessous, puis sauvegarder :

#!/bin/bash

# This script test every ROMs with a 5 minutes benchmark and display the percentage of speed of the emulation.
# If the 'purge' argument is specified, the script will delete the ROM files that are under 100% of average speed.

shopt -s nullglob

if (systemctl -q is-active mame-autostart.service) then
    echo "The system must be put in SERVICE Mode first."
    exit
fi

cd ~/.mame/roms
for r in *.zip
  do
    FULLNAME=$(/home/pi/mame/mame -listfull ${r%.zip} | awk "/${r%.zip}/ { print $2 }")
    if [ ! -z $FULLNAME ]; then
        echo -n Benchmarking $FULLNAME for 5 minutes...
        RESULT=$(/home/pi/mame/mame -bench 300 ${r%.zip} 2>/dev/null)
        if [ ! -z $RESULT ]; then
            PERCENT=$(echo $RESULT | awk '/Average speed:/ { print $3 }')
            PERCENT=${PERCENT//%/}         # Remove the percentage
            echo " Average speed of $PERCENT %"
            if [ ${PERCENT%.*} -lt 100 ] && [ ${1,,} = 'purge' ]; then
                rm ~/.mame/roms/$r
                echo "  The ROM file $r has been purged."
            fi
        fi
    fi
  done

echo Completed!

Ajustement des permissions pour permettre l'exécution du script :

chmod +x ~/scripts/mame-benchmark.sh

Utilitaire de nettoyage des fichiers graphiques (artworks)

Je vous propose le script ci-dessous pour nettoyer les fichiers .png des fichiers graphiques (artworks) lorsque le fichier ROM correspondant n'existe pas.

nano ~/scripts/mame-delartwork.sh

Coller le texte ci-dessous, puis sauvegarder :

#!/bin/bash

# This script delete unused Artwork files if the corresponding ROM .zip file does not exist.

shopt -s nullglob

if [ $1 ]; then
  if [ ! -f /home/pi/.mame/roms/$1.zip ]; then
    for t in snap titles marquees cpanels cabinets icons
      do
          if [ -f /home/pi/.mame/$t/$1.png ]; then
            sudo rm /home/pi/.mame/$t/$1.png
          fi
      done
  fi
else	# Batch mode
  if [ -t 0 ]; then echo -ne "\e[2K\rProcessing $1..."; fi
  for t in snap titles marquees cpanels cabinets icons
    do
      cd /home/pi/.mame/$t
      for f in *.{png,ico}
        do
          if [ ! -f /home/pi/.mame/roms/${f%.*}.zip ]; then
            sudo rm /home/pi/.mame/$t/$f
            echo -n .
          fi
        done
    done
  if [ -t 0 ]; then echo -e '\e[2K\rCompleted!'; fi
fi

Ajustement des permissions pour permettre l'exécution du script :

chmod +x ~/scripts/mame-delartwork.sh

Gestion automatisée du matériel graphique des ROMs

Un service systemd ainsi qu'un script surveillera l'emplacement des fichiers de ROMs. Dès qu'un changement survient (ajout ou suppression), le matériel graphique associé sera automatiquement mis à jour.

Installation des dépendances :

sudo apt-get install inotify-tools -y

Création du script :

nano ~/scripts/mame-artwork-mgmt.sh

Coller le texte ci-dessous, puis sauvegarder :

#!/bin/bash

# This script watch the ROMs folder and add/remove the corresponding artwork automatically.

inotifywait -m /home/pi/.mame/roms -e create -e moved_to -e delete -e moved_from |
  while read dir action file; do
    case ${action,,} in
      create | moved_to)
        if [ ${file##*.} = zip ]; then /home/pi/scripts/mame-scraper.sh ${file%.zip}; fi
        ;;
      delete | moved_from)
        if [ ${file##*.} = zip ]; then /home/pi/scripts/mame-delartwork.sh ${file%.zip}; fi
        ;;
    esac
  done

Ajustement des permissions pour permettre l'exécution du script :

chmod +x ~/scripts/mame-artwork-mgmt.sh

Création du service systemd associé :

sudo systemctl edit mame-artwork-mgmt.service --force --full

Coller le texte ci-dessous, puis sauvegarder :

[Unit]
Description=MAME Automatic Artwork Management service
After=network.target

[Service]
Type=simple
EnvironmentFile=/etc/environment
ExecStart=/home/pi/scripts/mame-artwork-mgmt.sh
KillSignal=SIGINT
TimeoutStopSec=5
Restart=always

[Install]
WantedBy=sysinit.target

Activer le service :

sudo systemctl enable mame-artwork-mgmt.service 

Ajustement de la mémoire vidéo à 128 Mo

Ajuster la taille de la mémoire vidéo à 128 Mo en éditant le fichier /boot/config.txt :

sudo nano /boot/config.txt

Ajouter la ligne ci-dessous à la fin du fichier, puis sauvegarder :

gpu_mem=128

Mise en lecture-seule du Root FileSystem (Read-Only)

Afin de prolonger la vie la carte SD, nous allons mettre en lecture-seule les partitions suivantes :

/boot (vfat)
/     (ext4)

Pour ce faire, suivre les instructions décrites au sein de la page ci-dessous :

Make your Raspberry Pi file system read-only (Raspbian Buster)

Tel que décrit dans la procédure, deux alias (rw et ro) sont créés afin de basculer du mode lecture-écriture vers lecture-seule et vice-versa.

Ajustements (suite à la procédure de mise en lecture-seule)

Certains ajouts et ajustements s’avèrent nécessaires suite à l’application de la procédure ci-dessus.

Ajustez le fichier bash.bash_logout auquel il manque sudo comme préfixe :

sudo nano /etc/bash.bash_logout

Préfixez la commande mount de sudo, puis sauvegarder :

sudo mount -o remount,ro /
sudo mount -o remount,ro /boot

Ajustement des alias pour basculer du mode Arcade au mode Service et vice-versa :

nano ~/.bash_aliases

Préfixez la définition des deux alias par rw; et suffixez par ; ro, puis sauvegardez :

alias arcademode='rw; sudo systemctl enable mame-autostart.service; ro'
alias servicemode='rw; sudo systemctl disable mame-autostart.service; ro'

Suppression du fichier de swap (swap file) :

sudo rm /var/swap

Purge du contenu des points de montage qui basculeront vers tmpfs :

sudo systemctl stop smbd.service nmbd.service systemd-timesyncd.service

sudo rm -R /var/lib/samba/*
sudo rm -R /var/cache/samba/*
sudo rm -R /tmp/*
sudo rm -R /var/lib/systemd/timesync/*

Le contenu de l'emplacement /var/log/ quant à lui, ne peut être supprimé en ligne, car il est activement utilisé par le système. Une suppression hors-ligne (offline) sera nécessaire en fermant le système et en insérant la carte SD au sein d'un ordinateur hôte et en exécutant la commande suivante :

cd <rootfs mount point>
sudo rm -R ./var/log/*

Ajustement pour le Wi-Fi (configuration hors-ligne)

Un service nommé raspberrypi-net-mods.service permet la configuration du réseau Wi-Fi en plaçant un fichier nommé wpa_supplicant.conf dans /boot. Ce service déplace ce fichier vers /etc/wpa_supplicant et a par conséquent besoin d'écrire dans /etc/wpa_supplicant et /boot (pour supprimer wpa_supplicant.conf une fois déplacé).

Nous allons ajouter un drop-in systemd pour ajuster la configuration du service :

sudo mkdir /etc/systemd/system/raspberrypi-net-mods.service.d
sudo nano /etc/systemd/system/raspberrypi-net-mods.service.d/readonlyfs-fixup.conf

Coller le texte ci-dessous, puis sauvegarder :

[Service]
ExecStartPre=/bin/sh  -c "mount -o remount,rw /boot; mount -o remount,rw /"
ExecStartPost=/bin/sh -c "mount -o remount,ro /boot; mount -o remount,ro /"

Ajustement pour le service SSH (activation hors-ligne)

Un service nommé sshswitch.service permet l'activation du service SSH, simplement en plaçant un fichier vide nommé ssh dans /boot. Lorsque présent, ce service supprime le fichier et active le service SSH, nécessitant temporairement l'écriture dans /boot et /.

Nous allons ajouter un drop-in systemd pour ajuster la configuration du service :

sudo mkdir /etc/systemd/system/sshswitch.service.d
sudo nano /etc/systemd/system/sshswitch.service.d/readonlyfs-fixup.conf

Coller le texte ci-dessous, puis sauvegarder :

[Service]
ExecStartPre=/bin/sh  -c "mount -o remount,rw /boot; mount -o remount,rw /"
ExecStartPost=/bin/sh -c "mount -o remount,ro /boot; mount -o remount,ro /"

Ajustement pour le service de mise à jour du firmware

Un service nommé rpi-eeprom-update.service permet de mettre à jour le firmware du Raspberry Pi. Ce service travaille dans /boot et doit pouvoir supprimer les fichiers une fois la mise à jour terminée. Nous devons donc temporairement autoriser l'écriture dans /boot.

Nous allons ajouter un drop-in systemd pour ajuster la configuration du service :

sudo mkdir /etc/systemd/system/rpi-eeprom-update.service.d
sudo nano /etc/systemd/system/rpi-eeprom-update.service.d/readonlyfs-fixup.conf

Coller le texte ci-dessous, puis sauvegarder :

[Service]
ExecStartPre=/bin/sh  -c "mount -o remount,rw /boot"
ExecStartPost=/bin/sh -c "mount -o remount,ro /boot"

Ajustements pour le service de synchronisation de l'heure

Le service de synchronisation de l'heure via NTP (systemd-timesyncd.service) n'est pas adapté aux systèmes de fichiers racine (root filesystem) en lecture-seule. Certaines adaptations s'avèrent nécessaires.

Ajouter à /etc/fstab, puis sauvegarder :

tmpfs    /var/lib/private           tmpfs   nosuid,mode=0755,nodev     0   0
tmpfs    /var/lib/systemd/timesync  tmpfs   nosuid,mode=0755,nodev     0   0

Nous allons ajouter un drop-in systemd pour ajuster la configuration du service :

sudo mkdir /etc/systemd/system/systemd-timesyncd.service.d
sudo nano /etc/systemd/system/systemd-timesyncd.service.d/readonlyfs-fixup.conf

Coller le texte ci-dessous, puis sauvegarder :

[Service]
PrivateTmp=no
RestartSec=5

Ajustement pour le service de mise à jour automatique

Puisque le système de fichiers racine (root filesystem) est en lecture-seule, il est inutile dans ce contexte de laisser en fonction les unités systemd qui téléchargent automatiquement les mises à jour de paquets. Vous devrez plutôt utiliser la commande update (après avoir fait passer le système en lecture/écriture avec la commande rw) lorsque vous aurez démarré le système en mode Service (commande servicemode).

sudo systemctl stop    systemd-tmpfiles-clean.timer apt-daily.timer apt-daily-upgrade.timer man-db.timer systemd-tmpfiles-clean.service apt-daily-upgrade.service
sudo systemctl disable systemd-tmpfiles-clean.timer apt-daily.timer apt-daily-upgrade.timer man-db.timer systemd-tmpfiles-clean.service apt-daily-upgrade.service
sudo systemctl mask    systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service apt-daily-upgrade.service

Ajustements pour le service Random Seed

Nous allons ajouter un drop-in systemd pour ajuster la configuration de ce service :

sudo mkdir /etc/systemd/system/systemd-random-seed.service.d
sudo nano /etc/systemd/system/systemd-random-seed.service.d/readonlyfs-fixup.conf

Coller le texte ci-dessous, puis sauvegarder :

[Service]
ExecStartPre=/bin/echo "" >/tmp/random-seed

Application des changements au sein de systemd :

sudo systemctl daemon-reload

Ajustements pour le spooler

Les permissions de /tmp sont changées quand on utilise un lien symbolique pour /var/spool. Pour faire en sorte que les permissions de /tmp ne soient pas changées :

Ajout d'un point de montage dédié pour /var/spool :

Au lieu de ces deux commandes (dans la procédure ci-dessus) :

sudo rm -rf /var/spool
sudo ln -s /tmp /var/spool

Si celles-ci ont déjà été exécutées, retirer le lien symbolique (sudo rm /var/spool) et récréer l'emplacement (mkdir /var/spool).

Ajouter plutôt à /etc/fstab l’entrée suivante :

tmpfs        /var/spool         tmpfs   nosuid,nodev            0    0

Ajustements pour Samba

Pour faire tourner correctement le serveur Samba avec un rootfs en lecture-seule :

Ajouter à /etc/fstab :

tmpfs     /var/lib/samba             tmpfs   nosuid,mode=0755,nodev    0   0
tmpfs     /var/lib/samba/private     tmpfs   nosuid,mode=0755,nodev    0   0
tmpfs     /var/log/samba             tmpfs   nosuid,mode=0755,nodev    0   0
tmpfs     /var/cache/samba           tmpfs   nodev,nosuid              0   0
tmpfs     /var/spool/samba           tmpfs   nodev,nosuid              0   0
tmpfs     /var/run/samba             tmpfs   nodev,nosuid              0   0

Redémarrer le système :

sudo reboot

Une fois redémarré, valider que celui-ci est bien en lecture-seule :

  1. Ouvrez une session (console ou SSH)
  2. Une fois logué, l'invite de commande devrait indiquer le suffixe (ro) (pour read-only)

Bascule en mode Arcade

Activer temporairement le mode lecture/écriture du Root FileSystem, basculer en mode Arcade (mode normal) et redémarrer :

arcademode
sudo reboot

Ajustements pour périphérique de sortie (TV ou moniteur)

[Optionnel/TV] Changement de l'identifiant CEC

Si vous utilisez un téléviseur branché via HDMI et que plusieurs sources y sont reliées, vous pouvez personnaliser l'identifiant CEC (Consumer Electronics Control) qui sera affiché pour la source (entrée HDMI) associée au Raspberry Pi :

sudo nano /boot/config.txt

Ajouter la ligne suivante (où Arcade est le nom/identifiant CEC qui sera affiché), puis sauvegarder :

cec_osd_name=Arcade

[Optionnel/Audio] Bascule de l'audio vers la sortie analogique

Si vous voulez utiliser la sortie analogique (audio jack 3.5mm) du Raspberry Pi pour l'aiguiller vers un amplificateur, procédez comme suit.

sudo nano /etc/asound.conf

Coller les lignes ci-dessous, puis sauvegarder :

pcm.!default {
type hw
card 1
}

ctl.!default {
type hw
card 1
}

[Optionnel/Audio] Réglage du volume de sortie audio

Pour régler (ajuster selon vos besoins) le volume de la sortie audio, exécutez la commande suivante :

alsamixer

Faites glisser le curseur du volume selon votre préférence, puis quittez (à l'aide de la touche ESC).

Pour sauvegarder de manière persistante le changement, exécutez :

sudo alsactl store

[Optionnel/Audio] Bascule de l'audio vers Contrôle du volume via bouton physique GPIO

Nous allons relier un bouton à pression à GPIO 4 afin de contrôler le volume global du système. À l'initialisation, le niveau sonore est réglé à 85 % (niveau moyen). À chaque pression du bouton, le niveau baisse d'un cran, jusqu'au silence (mute), puis bascule au niveau maximal, et ainsi de suite.

nano ~/scripts/mame-vol.sh

Coller les lignes ci-dessous, puis sauvegarder :

#!/bin/bash
#file:/home/pi/scripts/mame-vol.sh

HIGH='95%'
MED='85%'
LOW='72%'
MUTE='0%'

GPIOPIN=4   # We use GPIO 4

# Initialize GPIO pin
echo $GPIOPIN > /sys/class/gpio/unexport  # Deactivate GPIO pin
echo $GPIOPIN > /sys/class/gpio/export    # Activate GPIO pin
sleep 0.1                                 # A small delay is required so that the system has time
                                          # to properly create and set the file's permission
echo in > /sys/class/gpio/gpio${GPIOPIN}/direction # Input signal
echo both > /sys/class/gpio/gpio${GPIOPIN}/edge    # We use the interrupt controller to avoid a CPU spin loop

amixer -q cset numid=1 $MED

while true; do
  inotifywait -q -e modify /sys/class/gpio/gpio${GPIOPIN}/value > /dev/null      # CPU efficient wait
  read SIGNAL < /sys/class/gpio/gpio${GPIOPIN}/value     # 0=Pressed, 1=Released/Not pressed

  if [ $SIGNAL -eq 0 ]; then    # 0=Pressed, 1=Released/Not pressed
    # Volume button pressed
    CHECK_VOL=$(amixer | awk -F'[\[\]]' '/Mono: Playback/ {print $2}')

    case $CHECK_VOL in
      $HIGH)
        # Setting volume to medium
        amixer -q cset numid=1 $MED ;;
      $MED)
        # Setting volume to low
        amixer -q cset numid=1 $LOW ;;
      $LOW)
        # Setting volume to mute
        amixer -q cset numid=1 "$MUTE" ;;
      $MUTE)
        # Setting volume to high
        amixer -q cset numid=1 $HIGH ;;
      *)
        # Setting volume to medium (default)
        amixer -q cset numid=1 $MED ;;
    esac
  fi
done

Ajustement des permissions pour permettre l’exécution du script :

chmod +x ~/scripts/mame-vol.sh

Nous allons ajouter un service systemd afin d'exécuter en arrière-plan le script.

Pour ce faire, exécutez les étapes suivantes :

Création du service systemd :

sudo systemctl edit mame-vol.service --force --full

Coller les lignes ci-dessous et sauvegarder :

[Unit]
Description=Controlling volume for MAME with a button
Before=mame-autostart.service

[Service]
Type=simple
User=pi
Group=pi
ExecStart=/bin/bash /home/pi/scripts/mame-vol.sh
KillSignal=SIGINT

[Install]
WantedBy=multi-user.target

Activation et démarrage du service :

sudo systemctl enable mame-vol.service
sudo systemctl start mame-vol.service

[Optionnel/GPIO] Bascule du système au Mode Service via bouton physique GPIO

Au démarrage du système, nous allons présenter une fenêtre temps (de quelques secondes) afin d'offrir le basculement vers le Mode Service, lorsqu'un bouton physique (via GPIO) est appuyé dans le temps imparti. Dès le bouton pressé, un son de confirmation sera émis. Si aucune pression du bouton n'est effectuée, le système va démarrer normalement en Mode Arcade.

Nous allons débuter par créer le script qui sera exécuté au démarrage du système, via un service systemd :

nano ~/scripts/mame-svcmode-check.sh

Coller les lignes ci-dessous et sauvegarder :

#!/bin/bash
#file: /home/pi/scripts/mame-svcmode-check.sh

GPIOPIN=18   # We use GPIO 18 (pin #12)
BOOTSOUND=/home/pi/splash/boot.wav
SVCMSOUND=/home/pi/splash/service-mode.wav
TIMEOUT=5

aplay -q $BOOTSOUND &     # Boot sound

raspi-gpio set $GPIOPIN pu                # Enable the internal pull-up resistor for this GPIO pin
# Initialize GPIO pin
echo $GPIOPIN > /sys/class/gpio/unexport  # Deactivate GPIO pin
echo $GPIOPIN > /sys/class/gpio/export    # Activate GPIO pin
sleep 0.1                                 # A small delay is required so that the system has time
                                          # to properly create and set the file's permission
echo in > /sys/class/gpio/gpio${GPIOPIN}/direction # Input signal
echo both > /sys/class/gpio/gpio${GPIOPIN}/edge    # We use the interrupt controller to avoid a CPU spin loop

read SIGNAL < /sys/class/gpio/gpio${GPIOPIN}/value
if [ $SIGNAL -eq 1 ]; then      # Button not pressed
  inotifywait -q -t $TIMEOUT -e modify /sys/class/gpio/gpio${GPIOPIN}/value > /dev/null
  if [ $? -eq 0 ]; then # Value has changed
    read SIGNAL < /sys/class/gpio/gpio${GPIOPIN}/value
  fi
fi

if [ $SIGNAL -eq 1 ]; then    # 1=Open/Arcade Mode, 0=Closed/Service Mode
  touch /tmp/arcademode-confirm     # Arcade Mode
else
  aplay -q $SVCMSOUND               # Service Mode
fi

Pour le son de démarrage (boot sound) et celui de confirmation du Mode Service, vous devez fournir les fichiers audio au format WAV. Placez-les où vous voulez et ajustez les deux variables ci-dessous en conséquence :

BOOTSOUND=/home/pi/splash/boot.wav
SVCMSOUND=/home/pi/splash/service-mode.wav

Le script utilise GPIO 18 (broche physique numéro 12) pour relier le bouton à une broche Ground. Vous pouvez changer le branchement, assurez-vous simplement d'utiliser un GPIO libre.

Ajustement des permissions pour permettre l’exécution du script :

chmod +x ~/scripts/mame-svcmode-check.sh

Création du service systemd :

sudo systemctl edit mame-svcmode-check.service --force --full

Coller les lignes ci-dessous et sauvegarder :

[Unit]
Description=Checking Pushbutton to switch to Service Mode at boot
After=sound.target
Requires=sound.target

[Service]
Type=oneshot
RemainAfterExit=no
ExecStart=/bin/bash /home/pi/scripts/mame-svcmode-check.sh

[Install]
WantedBy=multi-user.target

Activation et démarrage du service :

sudo systemctl enable mame-svcmode-check.service
sudo systemctl start mame-svcmode-check.service

Ajustements des deux services du Mode Arcade :

sudo systemctl edit mame-autostart.service --force --full

À la section [Unit], sous la ligne After=mame-svcmode-check.service, ajouter la ligne ci-dessous :

ConditionPathExists=/tmp/arcademode-confirm

Retirer la ligne suivante, puis sauvegarder :

Conflicts=getty@tty1.service smbd.service nmbd.service rng-tools.service cron.service mame-artwork-mgmt.service
sudo systemctl edit shutdown.service --force --full

À la section [Unit], sous la ligne Description=Shutdown and poweroff service, ajouter la ligne ci-dessous, puis sauvegarder :

ConditionPathExists=/tmp/arcademode-confirm

Nous devons ajuster les services que nous ne voulons pas lancer en Mode Arcade en ajoutant une condition à leur démarrage via un drop-in systemd.

Pour créer les drop-ins systemd pour chacun de ces services, exécutez cette ligne :

for i in getty@tty1.service \
         smbd.service \
         nmbd.service \
         rng-tools.service \
         cron.service \
         mame-artwork-mgmt.service; do \
sudo mkdir /etc/systemd/system/$i.d \
echo '[Unit]' | sudo tee -a /etc/systemd/system/$i.d/arcademode-fixup.conf; \
echo 'ConditionPathExists=!/tmp/arcademode-confirm' | sudo tee -a /etc/systemd/system/$i.d/arcademode-fixup.conf; \
done; \
echo 'After=' | sudo tee -a /etc/systemd/system/rng-tools.service.d/arcademode-fixup.conf; \
echo 'After=mame-svcmode-check.service' | sudo tee -a /etc/systemd/system/rng-tools.service.d/arcademode-fixup.conf

Appliquer les changements :

sudo systemctl daemon-reload

[Optionnel/TV] Désactivation des bordures noires (Overscan)

sudo nano /boot/config.txt

Décommenter la ligne ci-dessous :

disable_overscan=1

[Optionnel] Rotation de l'écran à 90 degrés

Si vous comptez utiliser votre système d'arcade pour les jeux verticaux (shoot 'em up, par exemple), suivez ces étapes.

Le fait d'utiliser le pilote DRM VC4 V3D (vc4-fkms-v3d) ne nous permet malheureusement pas (du moins en ce moment) d'utiliser la fonctionnalité de rotation de l'écran au niveau du pilote (par le biais du réglage display_hdmi_rotate= dans /boot/config.txt). Nous devrons contourner ce problème en appliquant la rotation à chacune des composantes individuellement (console en mode texte, splash de boot et shutdown et interface graphique de MAME).

Rotation de la console à 90 degrés :

sudo nano /boot/cmdline.txt

Ajouter ceci à la fin de ligne de commande du kernel, puis sauvegarder :

fbcon=rotate:1

Rotation des images de splash (boot et shutdown) :

sudo systemctl edit mame-bootsplash.service --force --full

Ajustez la ligne ExecStart en ajoutant -C _orientation=1, puis sauvegardez :

ExecStart=/usr/bin/fim -q --no-history -C _orientation=1 /home/pi/splash/mame-boot.jpg
sudo systemctl edit mame-shutdownsplash.service --force --full

Ajustez la ligne ExecStart en ajoutant -C _orientation=1, puis sauvegardez :

ExecStart=/usr/bin/fim -q --no-history -C _orientation=1 /home/pi/splash/mame-shutdown.png

Rotation de l'interface graphique de MAME :

nano ~/.mame/mame.ini

Ajustez la section ci-dessous, puis sauvegardez :

#
# CORE ROTATION OPTIONS
#
rotate                    1
ror                       1

Pour maximiser la visibilité du nom des ROMS, nous devons cacher le panneau de gauche qui affiche le filtre actif :

nano ~/.mame/ini/ui.ini

Ajustez le réglage ci-dessous à la valeur 1, puis sauvegardez :

hide_main_panel           1

Amélioration du rendu vidéo pour les téléviseurs

Afin d'améliorer le rendu vidéo, de permettre le bon fonctionnement de la synchronisation verticale (VSync) qui est activée au sein de cette procédure et également de minimiser le délai de latence des contrôles (manette, boutons), assurez-vous de sélectionner le Mode Jeu / Game Mode (ou équivalent) sur votre téléviseur.

C'est complété !

Voilà, c'est terminé ! Vous pouvez maintenant passer à l'étape de l'intégration de votre Raspberry Pi 4 à un projet d'arcade pour la maison : un cabinet de type comptoir (Bartop) ou encore pleine hauteur/format original.

Je vous souhaite la meilleure des chances pour votre projet d'arcade !

-------------- FIN DE LA PROCÉDURE --------------

Si vous appréciez le travail et le soin que j'ai mis à monter cette solution, je vous propose de m'offrir un café, ceci m'encouragera à maintenir cette procédure bien vivante et à jour. :-)

Buy me a coffee

@fxlevy
Copy link

fxlevy commented Oct 22, 2021

Bonjour @sonicprod, merci pour ton retour.
Concernant le boot config, je pense avoir fait ce qu'il fallait.
En voici le contenu actif.

dtparam=audio=on
dtoverlay=vc4-fkms-v3d
max_framebuffers=2
arm_64bit=1
disable_splash=1
gpu_mem=512

En tout cas, tout marche ... mais pas forcément totalement bien.
A chaque fois je compare avec ton image pour voir comment elle réagit, j'observe les même choses.

Pour info, j'ai investi dans une Micro SD ultra rapide et un disque SSD de 4To pour pouvoir stocker tous les CHDs de Mame (pour les Software Lists c'est 2,4To à eux tous seuls dans leur version merged).

Mame tourne bien avec un bon niveau de performance. Mais le souci c'est avec Attract Mode. Il fonctionne mais quand j'utilise le Layout Arcade Flow les performance sont désastreuses. Il est très lent et pourant j'ai tout compilé à la main (le sfml-pi et Attract Mode Plus) De ce que j'ai pu lire, la GPU du PI4 est en 32bits ce qui implique d'avoir des drivers 64bits qui parlent au GPU en 32bits et pour le moment la version Buster 64bit n'en disposerait pas pour DRM. Mais comme tu l'as écrit toi-même 'L'architecture logicielle du graphique sous Linux est assez complexe à comprendre' et je ne suis pas certain de ce que j'écrits.

En conclusion, en terme de jouabilité:

  • Mame=9/10 ce qui me semble excellent.
  • Attract Mode=6/10 car certains layout sont vraiment inutilsiables du à leur lenteur (en particulier Arcade Flow qui est pourtant pour moi le layout le plus aobuti et que je souhaiterais faire foncitonner sur le PI4).

J'essaye de comprendre cette histoire de driver 32/64bits pour la GPU afin de trouver une solution.

J'ai quand même toujours des questions. Je pense avoir compris le script autostart.sh. Mais comment tu lui transmets le paramètre mame ou attract au démarrage? En modifiant le service?

@sonicprod
Copy link
Author

sonicprod commented Oct 22, 2021

@fxlevy,

Au niveau des thèmes Attract Mode, certains, bien que jolis et attrayants, sont passablement complexes et gourmands en thermes de ressources consommées. Il y a l'accélération matérielle que je n'ai malheureusement pas été en mesure de faire fonctionner avec Attract Mode. Possiblement que si quelqu'un réussit à faire tourner Attract Mode avec celle-ci, les thèmes plus complexes et demandants pourraient dès lors tourner adéquatement.

Pour répondre à ta question au sujet du script autostart.sh, celui-ci fait référence à une variable nommée $FRONTEND qui est affectée ailleurs, au démmarrage. C'est au sein du fichier /etc/environment que ça se passe. J'ai fait un petit alias Bash nommé « frontend » qui permet de changer l'affectation de la variable $FRONTEND sans devoir aller éditer /etc/environment. Tu peux visualiser l'alias an tapant « alias » à l'invite de commande Bash.

@alejandrorusso
Copy link

alejandrorusso commented Dec 25, 2021

@sonicprod Hi! I really like your JeOS approach!

I took your build, and I have done some modifications that I'd be great to integrate if you think they are worthy:

No need to decide between arcademode and servicemode

One of the complications I found with your build was to take it out arcademode back into servicemode -- something that you described how to do in a README file. I modified a little bit your systemd files so that the system is always in arcade mode but if you press a bottom and/or move the joystick at boot time, then the system goes into servicemode.

Button to mute/unmute sound

I plan to have my arcade in my office. I am working on adding a button to the raspberry pi (GPIO-based interface) to mute and unmute the sound. In that manner, the arcade can show gameplay but without disturbing the working environment. People that want to play, however, can just unmute and enjoy the arcade from time to time.

If you are interested in what I have done I can give access to my repository (still private) so that you can have a look.

@sonicprod
Copy link
Author

sonicprod commented Dec 29, 2021

Hi @alejandrorusso,

Very interesting improvements! I would be interested to take a look at your repo and eventually (as proposed) integrate your code/modifications to this How To. :)

@alejandrorusso
Copy link

alejandrorusso commented Jan 1, 2022

@sonicprod Great! Please, take a look at the public repo: https://github.com/alejandrorusso/mamearcade

@wimpie3
Copy link

wimpie3 commented Jan 2, 2022

@sonicprod Thank you for this information. I have downloaded the pre-build SD card contents but it's not clear how to switch between arcademode and servicemode. This isn't explained in this document either. Can you please elaborate?

@fxlevy
Copy link

fxlevy commented Jan 2, 2022

Hello @sonicprod, je n’ai pas disparu et je bosse toujours sur ta solution. J’ai créé des nouveaux scripts sur le principe de fonctionnement du raspi-config avec whiptail pour rendre plus souples tes procédures. Dès que j’aurais pu les valider de bout en bout à partir d’une « fresh » install, je les partagereais. En attendant je suis aussi en train de me construire une mini borne d’arcade. Ils proposent d’installer retropie mais je n’en veux pas. Je préfère de loin ta solution. 🥇 . Pour attract mode aurais-tu un thème de prédilection que tu utiliserais sur ta borne? Je suis en train d’en faire un à partir du concept Pandora theme 4 mais il ne fonctionne qu’en 1080P.

@sonicprod
Copy link
Author

sonicprod commented Jan 3, 2022

@wimpie3,

To switch between Arcade Mode and Service Mode, you have to log in to the system (either via the console or network via SSH):

To switch to Service Mode, type:

servicemode
sudo reboot

To switch to Arcade Mode, type:

arcademode
sudo reboot

@sonicprod
Copy link
Author

sonicprod commented Jan 3, 2022

@alejandrorusso,

I took a look at your repo and I can say that you did a very good work of improvements!

Your method to switch from Arcade Mode to Service Mode is clever and it happens to solve the problem I had: I wished to be able to put a rotary 2-position switch (like this one: https://www.amazon.ca/Thread-Position-Selector-Latching-Houseuse/dp/B07HQ7JW9Q) connected to GPIO pins to be able to switch between Arcade Mode and Service Mode, but from the inside of the cabinet (like real arcade cabinets), once unlocked.

I will integrate your code as-is (for the joystick/buttons press at boot) and if you agree, I will also adapt your code to be able to use a switch on GPIO pins at boot.

Your second improvement is also solving a problem I had in my cabinet! I had to rely on a small amplifier (like this one: https://www.amazon.ca/LP-2020A-Class-D-Hi-Fi-Amplifier-Supply/dp/B0049P6OTI) and I had to put it inside the cabinet and as a result, I cannot expose the volume knob to the outside of the cabinet. Now, with a simple pushbutton, I can toggle from High/Low/Mute volume. Very clever!

Thanks very much for your improvements, as soon as I will have some time, I will integrate both to the How To. :-)

@sonicprod
Copy link
Author

sonicprod commented Jan 3, 2022

@fxlevy,

Bien content d'avoir de tes nouvelles ! :) Tu viens de me faire découvrir whiptail, j'ai réalisé qu'il était utilisé abondamment pour les écrans d'installation en mode texte (Ubuntu l'utilise notamment pour sa distro en mode minimal, sans GUI).

Ça semble intéressant ton projet de mini-borne d'arcade, tiens-moi informé si tu peux, je suis curieux de voir le résultat final.

Pour Attract Mode, j'utilise un thème vertical, puisque mon cabinet est vertical (je suis du genre shoot-em ups) et c'est VertiCools Deluxe. Le mieux, pour dénicher des thèmes, c'est cette section du forum d'Attract Mode : http://forum.attractmode.org/index.php?board=6.0

Bonne continuité dans ton projet ! :)

@alejandrorusso
Copy link

alejandrorusso commented Jan 3, 2022

@sonicprod Good that you like them! :)

It seems that we both encountered the same problems! My solution is trying to avoid me opening the cabinet to switch modes as well as introducing new holes. My cabinet was not designed to expose many switches and I am not a "hardware" guy that dares to start making new holes ;) BTW, I use the cheapest speakers I could find with a built-in amplifier https://www.amazon.se/-/en/dp/B00JRW0M32/

Please, go ahead and do the necessary modification -- you are also welcome (if you have time) to do a PR to my repo so I could see the changes that you will do.

@sonicprod
Copy link
Author

sonicprod commented Jan 4, 2022

@alejandrorusso,

Same for me, I'm not a hardware guy, just like you. I'm more on the software side. :)

I tweaked (for performance/low CPU usage) a little bit your volume script and added a Medium volume setting as well.

Below is my modified version:

#!/bin/bash
#file:/home/pi/scripts/mame-vol.sh

HIGH='95%'
MED='85%'
LOW='72%'
MUTE='0%'

GPIOPIN=4   # We use GPIO 4

# Initialize GPIO pin
echo $GPIOPIN > /sys/class/gpio/unexport  # Deactivate GPIO pin
echo $GPIOPIN > /sys/class/gpio/export    # Activate GPIO pin
sleep 0.1                                 # A small delay is required so that the system has time
                                          # to properly create and set the file's permission
echo in > /sys/class/gpio/gpio${GPIOPIN}/direction # Input signal
echo both > /sys/class/gpio/gpio${GPIOPIN}/edge    # We use the interrupt controller to avoid a CPU spin loop

amixer -q cset numid=1 $MED

while true; do
  inotifywait -q -e modify /sys/class/gpio/gpio${GPIOPIN}/value > /dev/null      # CPU efficient wait
  read SIGNAL < /sys/class/gpio/gpio${GPIOPIN}/value     # 0=Pressed, 1=Released/Not pressed

  if [ $SIGNAL -eq 0 ]; then    # 0=Pressed, 1=Released/Not pressed
    # Volume button pressed
    CHECK_VOL=$(amixer | awk -F'[\[\]]' '/Mono: Playback/ {print $2}')

    case $CHECK_VOL in
      $HIGH)
        # Setting volume to medium
        amixer -q cset numid=1 $MED ;;
      $MED)
        # Setting volume to low
        amixer -q cset numid=1 $LOW ;;
      $LOW)
        # Setting volume to mute
        amixer -q cset numid=1 "$MUTE" ;;
      $MUTE)
        # Setting volume to high
        amixer -q cset numid=1 $HIGH ;;
      *)
        # Setting volume to medium (default)
        amixer -q cset numid=1 $MED ;;
    esac
  fi
done

I tested it and it works very very well. Tomorrow, I will continue with your second script (switching from Arcade Mode to Service Mode and vice-versa). I'll keep you updated.

@alejandrorusso
Copy link

alejandrorusso commented Jan 4, 2022

@sonicprod It looks good to me! I didn't know the inotifywait trick, nice :)

Please, take also a look into my TODOs and see if you recognize the same problems -- it could be something that we could work on together in the future.

@sonicprod
Copy link
Author

sonicprod commented Jan 4, 2022

@alejandrorusso,

I took a look at your TODOs and fixed the patch issue with MAME 0.238 and up. The new patch is integrated to the How To.

For the boot sound, to tell the person to press a button or move joystick while booting, you could simply use aplay in your mame-joystick-detect.sh script. Just make sure you put an & at the end (it put the process in background and the execution of the script continue), so to play the sound while your script can continue in parallel. I suggest also you put the -q argument to keep it quiet. You can use a sound sample supported by aplay (basically mp3, flac, ogg or wav) with a duration of 5 seconds. I tend to like this one from Neo-Geo arcade: https://downloads.khinsider.com/game-soundtracks/album/snk-game-sound-music-2-neogeo-sound-power/01%2520Neo-Geo%2520Opening%2520Theme.mp3

@wimpie3
Copy link

wimpie3 commented Jan 6, 2022

When you switch to maintenance mode, does this automatically activate Read/Write as well? It's not entirely clear if you have to use the RW command even after you passed to maintenance mode or not.

@sonicprod
Copy link
Author

sonicprod commented Jan 6, 2022

@wimpie3,

When switching to Service Mode, it does not automatically put the root filesystem in read/write mode. However, the /data partition is always in read/write mode to add/remove ROMs and change the configuration of the MAME emulator (as well as Hypseus) or an included front-end.

To change the system configuration (Linux OS), you need to put the root filesystem in read/write mode with the rw command at the prompt.

@wimpie3
Copy link

wimpie3 commented Jan 6, 2022

@sonicprod OK at least now that's clear. Does going back to ARCADEMODE also switch the file system to read only? Or can RW stay active even in ARCADEMODE?

@sonicprod
Copy link
Author

sonicprod commented Jan 6, 2022

@wimpie3,

As soon as you logout or reboot, the system automatically revert to read-only mode (root filesystem).

@sonicprod
Copy link
Author

sonicprod commented Jan 7, 2022

@alejandrorusso,

I reworked your script to detect input during boot and switch to Service Mode if detected. I adapted it to suit my need for a physical pushbutton controlled by a GPIO input.

#!/bin/bash
#file: /home/pi/scripts/mame-svcmode-probe.sh

GPIOPIN=18   # We use GPIO 18 (pin #12)
BOOTSOUND=/home/pi/scripts/coin.wav
RUNTIME='5 seconds'
ENDTIME=$(date -ud "$RUNTIME" +%s)

aplay -q $BOOTSOUND &     # Boot sound

# Initialize GPIO pin
echo $GPIOPIN > /sys/class/gpio/unexport  # Deactivate GPIO pin
echo $GPIOPIN > /sys/class/gpio/export    # Activate GPIO pin
sleep 0.1                                 # A small delay is required so that the system has time
                                          # to properly create and set the file's permission
echo in > /sys/class/gpio/gpio${GPIOPIN}/direction # Input signal
echo both > /sys/class/gpio/gpio${GPIOPIN}/edge    # We use the interrupt controller to avoid a CPU spin loop
raspi-gpio set $GPIOPIN pu                # Enable the internal pull-up resistor for this GPIO pin

while [[ $(date -u +%s) -le $ENDTIME ]]
do
  # Read the state of the GPIO pin
  read SIGNAL < /sys/class/gpio/gpio${GPIOPIN}/value
  REMAIN=$(($ENDTIME-$(date -u +%s)))
  if [ $REMAIN -gt 0 ]; then
    inotifywait -q -t $REMAIN -e modify /sys/class/gpio/gpio${GPIOPIN}/value > /dev/null
  fi
done

if [ $SIGNAL -eq 1 ]; then    # 1=Open/Arcade Mode, 0=Closed/Service Mode
  touch /tmp/arcademode-confirm                 # Arcade Mode
else
  aplay -q /home/pi/scripts/service-mode.wav    # Service Mode
fi

The script plays early in the boot process a boot sound and wait 5 seconds (in parallel, while playing the sound) for an input on GPIO 18. If input is detected, it plays a "confirmation" sound and the system then toggle to Service Mode. The audio file has to be .wav format for aplay to succeed.

@alejandrorusso
Copy link

alejandrorusso commented Jan 7, 2022

@sonicprod Nice! It looks good and the addition of the sounds is what I had in mind. Well done!

My only question is why do you need to keep track of the time in the script with variables REMAIN and ENDTIME? Is it because of the button you have in mind?

Why not using the command timeout as I had in my script? For instance, something like timeout 5s inotifywait -q -t $REMAIN -e modify /sys/class/gpio/gpio${GPIOPIN}/value > /dev/null

Did you try that?

@sonicprod
Copy link
Author

sonicprod commented Jan 7, 2022

@alejandrorusso,

To answer your question, simply because the inotifywait command support natively a timeout function (-t on the command-line), so I prefer using it instead of an external utility. The idea I have in mind is to turn a rotary switch to close the circuit on the GPIO pin, so I need the 0 value at the end of the timeout. I may adapt it to simply permit a single impulse while in the 5 seconds time window.

@alejandrorusso
Copy link

alejandrorusso commented Jan 7, 2022

@sonicprod I see! I have been playing a bit with inotifywait. Why not changing this code:

while [[ $(date -u +%s) -le $ENDTIME ]]
do
  # Read the state of the GPIO pin
  read SIGNAL < /sys/class/gpio/gpio${GPIOPIN}/value
  REMAIN=$(($ENDTIME-$(date -u +%s)))
  if [ $REMAIN -gt 0 ]; then
    inotifywait -q -t $REMAIN -e modify /sys/class/gpio/gpio${GPIOPIN}/value > /dev/null
  fi
done

by

read SIGNAL < /sys/class/gpio/gpio${GPIOPIN}/value
inotifywait -q -t -e modify /sys/class/gpio/gpio${GPIOPIN}/value > /dev/null
if [ $? -eq 0 ] ; then  # If it has been written a value before the timeout 
   read SIGNAL < /sys/class/gpio/gpio${GPIOPIN}/value 
fi  

So, as soon as you close the switch (before the timeout), then inotifywait will exit -- no need to track time manually in the script.

@sonicprod
Copy link
Author

sonicprod commented Jan 8, 2022

@alejandrorusso,

Thanks for your input! I adapted the logic to your suggestion, with a minor addition (to process the case when the button is already pressed when the script is being executed):

read SIGNAL < /sys/class/gpio/gpio${GPIOPIN}/value
if [ $SIGNAL -eq 1 ]; then      # Button not pressed
  inotifywait -q -t $TIMEOUT -e modify /sys/class/gpio/gpio${GPIOPIN}/value > /dev/null
  if [ $? -eq 0 ]; then # Value has changed
    read SIGNAL < /sys/class/gpio/gpio${GPIOPIN}/value
  fi
fi

@alejandrorusso
Copy link

alejandrorusso commented Jan 8, 2022

@sonicprod It looks good to me now! Well done!

@fxlevy
Copy link

fxlevy commented Jan 16, 2022

Hello @sonicprod , j'avais écrit un peu plus haut que j'avais commencé à élaborer des scripts qui s'appuient sur l'outil Whiptail afin de rendre les scripts d'installation plus intéractifs et plus souples.
J'ai cré un repo Git rpi4mame dans lequel j'ai placé à sa racine deux dossiers 'scripts' et 'patches' qui contiennent tout se qu'il faut pour procéder aux différentes installations de SDL2, SDL2_TTF, SFML-PI, AttractMode Plus et Mame.
Pour que celà fonctionne, les deux dossiers doivent être placés à la racine de /home/pi dans son Raspi.
Les scripts d'installation sont optimisés pour RASPI 4 B avec un OS 64 Bits.
Je les mets à la disposition de la communauté.

Mais avant toute chose, je tiens à te remercier du fond du cœur @sonicprod . Sans ton blog, je ne me serais jamais lancé dans cette entreprise. Pour info, je n'y connais pas grand chose en système Unix et je suis totalement novice sur Git. Ton blog m'a été essentiel pour que j'y arrive.

Quand j'aurais rédigé le Readme, je ferais bien sur référence à ton blog et à ton travail.
Dis-moi déjà ce que tu penses de ce que j'ai fait.
Il faut bien sur traiter les scripts dans l'ordre (sdl2 -> sdl2_ttf -> mame puis sfml2_pi -> attract) pour que toute l'installation fonctionne.

@sonicprod
Copy link
Author

sonicprod commented Jan 18, 2022

@fxlevy,

Je suis allé voir ton repo Git et j'ai jeté un coup d'oeil à tes scripts et... WOW, je peux te dire que tu as fait un beau boulot de clean-up, de structure et tu as amené mon travail à un niveau supérieur ! :) Toutes mes félicitations !

Dis-moi, est-ce que tu observe un gain de performance lorsque tu utilises MAME sur ton OS 64-bit ?

@sonicprod
Copy link
Author

sonicprod commented Jan 18, 2022

@alejandrorusso,

I completed the integration of your work to this How To. :)

The two (2) related sections are:

  • [Optional/Audio] Switch from audio to Volume control via physical GPIO button
  • [Optional/GPIO] System switch to Service Mode via physical GPIO button

Let me know your comments, if any.

@fxlevy
Copy link

fxlevy commented Jan 19, 2022

@sonicprod , merci pour le retour positif. Ça fait plaisir. :)
Je ne saurais t'assurer que la version 64 bits est plus rapide que la 32bits car je n'ai pas de PI avec un système 32Bits. Je n'ai qu'un seul PI pour le moment, un PI4 8GO. C'est la galère en ce moment pour en trouver sur le marché à cause de la pénurie de puces. Mais ce que je peux affirmer par contre, c'est que Attract Plus avec Mame et SDL2 compilés en 64 bits fonctionnent bien à condition d'être en dtoverlay=vc4-fkms-v3d sinon il n'y a pas de son. Dès que j'aurais d'autres Pi 4, je constrirai le Picade que j'ai parlé plus haut et que j'ai déjà reçu. En attendant, j'améliore les scripts pour qu'ils soient plus souples, plus fiables et plus lisibles.

J'ai june remarque, dans mon git, il y a des fichiers Patch que j'ai créé et celui qui corrige le fichier bgfx pour Mame marche aussi bien sur une 239 que sur une 236. Je n'ai pas besoin de l'adapter. Je ne comprends pas pourquoi tu as du modifier celui de ton howto.

@alejandrorusso
Copy link

alejandrorusso commented Jan 19, 2022

Hi @sonicprod !

I am happy to see the integration! It looks good to me!

Keep pushing this amazing work!

My guest is that this project will get more and more fancy and we will need to start thinking about a configuration script that does a bunch of questions and deploys the right setting for the user — just some thoughts.

@sonicprod
Copy link
Author

sonicprod commented Jan 20, 2022

@alejandrorusso,

Thanks! Regarding your suggestion, do you mean creating a CI/CD pipeline? I am able to automate/script the entire process, but to a certain extent: I am not able to cross-compile from an x86 build PC/server to a Raspberry Pi 4B. I am not able to install Raspberry Pi OS (formerly Raspbian) in an emulated environment (with QEMU, for example), because no support is available, yet.

However, I have staging scripts to maintain the disk image I publish. Here they are:

inject-rootfs.raspios.mame.sh

#!/bin/bash

# Script pour extraire la partition 'rootfs' de la carte micro-SD et l'injecter dans le fichier-image
# pour pouvoir le publier en ligne.

if [ ! $1 ]; then
    echo Usage: $0 VER
    echo '  Where VER is the 4-digit version number of the MAME image file (for example: 0224).'
    exit
fi

IMGFILE=rpi4b.raspios.mame-$1.appliance.fe-edition.img
SDDEVICE=/dev/sdb

if [ ! -f ~/$IMGFILE ]; then
    echo $IMGFILE does not exist!
    exit
fi

echo INFO: Block size de ${SDDEVICE}1 = $(lsblk ${SDDEVICE}1 -nt | awk '{ print $6 }') octets.
echo INFO: Block size de ${SDDEVICE}2 = $(lsblk ${SDDEVICE}1 -nt | awk '{ print $6 }') octets.

# Démontage de la partition, si déjà montée
# if [ $(findmnt -n $PART | awk '{print $1}') = '/media/bbegin/rootfs' ]; then
#     sudo umount $PART
# fi

echo Démontage des partitions de la carte micro-SD...
sudo umount ${SDDEVICE}1
sudo umount ${SDDEVICE}2

# Extraction de la partition boot
sudo dd if=${SDDEVICE}1 of=boot.img status=progress bs=1M
# Extraction de la partition rootfs
sudo dd if=${SDDEVICE}2 of=rootfs.img status=progress bs=1M

# Montage du disque virtuel pour présenter les partitions sous /dev/mapper
sudo kpartx -av $IMGFILE
ls -la /dev/mapper

# Écriture de boot et rootfs vers le disque virtuel...
echo Écriture de boot.img vers le disque virtuel...
sudo dd if=boot.img   of=/dev/mapper/loop0p1 status=progress bs=1M
echo Écriture de rootfs.img vers le disque virtuel...
sudo dd if=rootfs.img of=/dev/mapper/loop0p2 status=progress bs=1M

# Retrait du disque virtuel
sync
sudo kpartx -dv $IMGFILE

sudo rm boot.img
sudo rm rootfs.img

echo Opération complétée !
ls -la $IMGFILE

mount-boot.rpi4b.raspios.mame.sh

#!/bin/sh

if [ ! $1 ]; then
    echo Usage: $0 VER
    echo '  Where VER is the 4-digit version number of MAME image file (for example: 0224).'
    exit
fi

# IMGNAME=rpi4b.raspios.mame-$1.appliance.img
IMGNAME=rpi4b.raspios.mame-$1.appliance.fe-edition.img

if [ ! -f ~/$IMGNAME ]; then
    echo $IMGNAME does not exist!
    exit
fi

if [ ! -d /tmp/boot.img ]; then
    sudo mkdir /tmp/boot.img
fi
sudo mount -t vfat -o loop,rw,sync,offset=4194304 ~/$IMGNAME /tmp/boot.img
cd /tmp/boot.img
echo -------------------------------------------
$SHELL
echo -------------------------------------------
echo Unmounting image.....
cd ~
sudo umount /tmp/boot.img
echo Done!

mount-data.rpi4b.raspios.mame.sh

#!/bin/sh

if [ ! $1 ]; then
    echo Usage: $0 VER
    echo '  Where VER is the 4-digit version number of MAME image file (for example: 0224).'
    exit
fi

#IMGNAME=rpi4b.raspios.mame-$1.appliance.img
IMGNAME=rpi4b.raspios.mame-$1.appliance.fe-edition.img

if [ ! -f ~/$IMGNAME ]; then
    echo $IMGNAME does not exist!
    exit
fi

if [ ! -d /tmp/data.img ]; then
    sudo mkdir /tmp/data.img
fi
sudo mount -o loop,rw,sync,offset=13157531648 ~/$IMGNAME /tmp/data.img
cd /tmp/data.img

if [ "$2" = "zero" ]; then
    echo Overwriting free space with zeros...
    dd if=/dev/zero of=zeros bs=8M status=progress
    rm zeros
else
    echo -------------------------------------------
    $SHELL
    echo -------------------------------------------
fi

echo Unmounting image.....
cd ~
sudo umount /tmp/data.img
echo Done!

mount-rootfs.rpi4b.raspios.mame.sh

#!/bin/sh

if [ ! $1 ]; then
    echo Usage: $0 VER
    echo '  Where VER is the 4-digit version number of MAME image file (for example: 0224).'
    exit
fi

# IMGNAME=rpi4b.raspios.mame-$1.appliance.img
IMGNAME=rpi4b.raspios.mame-$1.appliance.fe-edition.img

if [ ! -f ~/$IMGNAME ]; then
    echo $IMGNAME does not exist!
    exit
fi

if [ ! -d /tmp/rootfs.img ]; then
    sudo mkdir /tmp/rootfs.img
fi
sudo mount -o loop,rw,sync,offset=272629760 ~/$IMGNAME /tmp/rootfs.img
cd /tmp/rootfs.img/home/pi

if [ "$2" = "zero" ]; then
    echo Overwriting free space with zeros...
    dd if=/dev/zero of=zeros bs=8M status=progress
    rm zeros
else
    echo -------------------------------------------
    $SHELL
    echo -------------------------------------------
fi
echo Unmounting image.....
cd ~
sudo umount /tmp/rootfs.img
echo Done!

compress-image-file.sh

#!/bin/bash

if [ ! $1 ]; then
    echo Usage: $0 VER [zero]
    echo '  Where VER is the 4-digit version number of MAME to update (for example: 0224).'
    echo '  Where zero overwrite the free space with zeros to optimize compression.'
    exit
fi

# IMGNAME=rpi4b.raspios.mame-$1.appliance.img
IMGNAME=rpi4b.raspios.mame-$1.appliance.fe-edition.img

if [ ! -f ~/$IMGNAME ]; then
    echo $IMGNAME does not exist!
    exit
fi

if [ -f $IMGNAME.gz ]; then
    rm $IMGNAME.gz
fi

# Écrasement de l'espace libre de rootfs avec des zéros
if [ "$2" = "zero" ]; then
    ./mount-rootfs.rpi4b.raspios.mame.sh $1 zero
fi

gzip -9 -k $IMGNAME

ls -la $IMGNAME $IMGNAME.gz

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment