Note: the following steps are written in French. Feel free to translate to English.
However, please take notice that if you copy the scripts on this page from the version translated into English by Google Translate, it is possible that extra characters may appear within some scripts (this is caused by Google Translate), resulting in corruption of the impacted scripts. Consequently, it is better to copy the scripts from the original French version of this page.
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.248 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 Bookworm 64-bit (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) ;
- Un mode (appelé AutoROM) permet le lancement automatique d'un ROM sélectionné au démarrage (utile pour les cabinets dédiés) ;
- 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 persistants ;
- Les réglages audio (volume) sont sauvegardés et sont 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 pour l'émulation. À noter toutefois que si vous compilez MAME depuis le Pi 4/Pi 400 lui-même, vous devrez posséder au minimum 2 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 :
Téléchargement de Raspberry Pi OS Lite Bookworm 64-bit et écriture sur carte microSD :
Page de téléchargement : https://www.raspberrypi.com/software/operating-systems/#raspberry-pi-os-64-bit
Les étapes ci-dessous sont destinées à un ordinateur tournant sous Linux :
wget https://downloads.raspberrypi.org/raspios_lite_arm64/images/raspios_lite_arm64-2024-03-15/2024-03-15-raspios-bookworm-arm64-lite.img.xz -O raspios-lite-arm64-latest.img.xz
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 .xz qui contient le fichier-image (.img)
xz -d raspios-lite-arm64-latest.img.xz
Écriture de l’image sur la carte microSD (remplacez /dev/sdd
par le block device associé à votre carte) :
sudo dd if=raspios-lite-arm64-latest.img of=/dev/sdd status=progress bs=8192
sync
Retirer, puis réinsérez la carte SD au sein du lecteur. Si tout s'est bien déroulé à l'étape précédente, votre système Linux montera automatiquement les deux partitions boot
et rootfs
de la carte SD nouvellement écrite.
Activation de l’accès SSH
En placant un fichier vide nommé ssh
au sein de la partition boot
de la carte SD, ceci activera le serveur SSH au premier démarrage.
sudo touch $(findmnt -t vfat PARTUUID=0ee3e8a8-01 --output=target --noheadings)/ssh
Ajustement de la taille du système de fichiers racine à 15 Go
Démonter les 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
- Afficher la table des partitions (p)
- Supprimer la seconde partition (d, 2)
- Re-créer la partition (n, p, 2)
- À l'étape
First sector
, spécifier l'ancienne valeur du premier secteur (vous référer à la table précédamment affichée) - À l'étape
Last sector
, inscrire+15G
(valeur de 15 Go recommandée) ou toute autre taille que vous jugez appropriée - À la question
Do you want to remove the signature?
, répondez par non (N) - Afficher la table des partitions (p)
- Créer une nouvelle partition (n, p, 3)
- À l'étape
First sector
, spécifier la valeurEnd
de la partition #2, en y additionnant le nombre 1 - À l'étape
Last sector
, accepter la valeur par défaut afin d'allouer tout l'espace non-partitionné - 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, presser la touche ENTER et le système redémarrera.
[Optionnel] Première ouverture de session via la console
login: pi
password: raspberry
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.
Connexion via SSH au Raspberry Pi
Le mot de passe par défaut du compte pi
est : raspberry
Depuis un hôte Linux :
ssh pi@<Adresse IP de votre Raspberry Pi>
Depuis Windows :
Téléchargez et exécutez un client SSH (comme PuTTY) et saisissez l'adresse IP de votre Raspberry Pi.
Changement du mot de passe pour le compte pi
passwd
Mise à jour des paquets
Mise à jour des paquets du système :
sudo apt-get update && sudo apt-get upgrade -y
# Cleanup
sudo apt-get clean -y
sudo apt-get autoclean -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='/usr/bin/vcgencmd measure_temp'
alias cpufreq="echo Clock Speed=$(($(/usr/bin/vcgencmd measure_clock arm | awk -F '=' '{print $2}')/1000000)) MHz"
alias frontend='upd(){ grep -q $1= ~/settings && sed -i "s/^$1=.*$/$2/g" $(readlink -f ~/settings) || echo $2 | tee -a ~/settings;}; _frontend(){ if [[ "${1,,}" =~ ^(mame|attract|advance)$ ]]; then [ ! -f ~/settings ] && touch ~/settings; upd FRONTEND FRONTEND="${1,,}" && echo "Frontend set to: "${1,,}" (reboot to apply)."; case "${1,,}" in mame) [ -z "$2" ] && upd AUTOROM AUTOROM= || (upd AUTOROM AUTOROM="${2,,}"; echo "Automatic ROM Launch set to: "${2,,}".") ;; attract) EMUL=~/.attract/emulators/"$2".cfg; if ([ ! -z "$2" ] && [ ! -z "$3" ] && [ -f $EMUL ]); then (upd AUTOROM "AUTOROM=\""$2" "${3,,}"\""; echo "Automatic ROM Launch set to: "${3,,}" (emulator "$2")."); else [ ! -z "$2" ] && echo "Invalid emulator or missing rom."; upd AUTOROM AUTOROM=; fi; ;; esac; else echo "Invalid or missing argument. Try: mame [rom], attract [emulator rom] 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'
alias mode='echo -n "The system is currently in "; systemctl -q is-active mame-autostart.service && echo -n ARCADE || echo -n SERVICE; echo " mode."'
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 des émulateurs (MAME et Hypseus-Singe)
mkdir ~/scripts
nano ~/scripts/versions-check.sh
Coller les lignes ci-dessous, puis sauvegarder :
#!/bin/bash
function version { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; }
# This function check the latest available version of MAME and display a notice if the current version is older.
function mame-check {
CHECKURL=https://github.com/mamedev/mame/releases/latest
HTMLTAG='<title>Release MAME'
[ -x /home/pi/mame/mame ] && export MAMEVER=$(/home/pi/mame/mame -version | cut -d' ' -f1)
if [ ! -z $MAMEVER ]; then
LATESTMAMEVER=$(wget -q -O - $CHECKURL | grep "$HTMLTAG" | awk '{print $3}')
if [ -z $LATESTMAMEVER ]; then echo $MAMEVER ERROR; exit; fi # We make sure wget was successful
if [ $(version $LATESTMAMEVER) -gt $(version $MAMEVER) ]; then
echo $MAMEVER $LATESTMAMEVER
else
echo $MAMEVER Latest
fi
fi
}
# This script check the latest available version of Hypseus-Singe and display a notice if the current version is older.
function hypseus-check {
CHECKURL=https://github.com/DirtBagXon/hypseus-singe/releases/latest
HTMLTAG='<title>Release hypseus-singe'
HYPSEUSPATH=/home/pi/hypseus
[ -x $HYPSEUSPATH/hypseus ] && export HYPSEUSVER=$($HYPSEUSPATH/hypseus -v | awk '/^\[version\]/{print $4}')
if [ ! -z $HYPSEUSVER ]; then
LATESTHYPSEUSVER=$(wget -q -O - $CHECKURL | grep "$HTMLTAG" | awk '{print $3}')
if [ -z $LATESTHYPSEUSVER ]; then echo $HYPSEUSVER ERROR; exit; fi # We make sure wget was successful
LATESTHYPSEUSVER=${LATESTHYPSEUSVER##v} # Strip the leading v
HYPSEUSVER=$(echo $HYPSEUSVER | sed 's/^v*//; s/-RPi$//') # Strip the leading v and trailing -RPi
if [ $(version $LATESTHYPSEUSVER) -gt $(version $HYPSEUSVER) ]; then
echo $HYPSEUSVER $LATESTHYPSEUSVER
else
echo $HYPSEUSVER Latest
fi
fi
}
if [ -x $HOME/mame/mame ] || [ -x $HOME/hypseus/hypseus ]; then
echo '+---------------+-----------+-----------+'
echo '| EMULATOR | CURRENT | LATEST |'
echo '+---------------+-----------+-----------+'
[ -x $HOME/mame/mame ] && echo -n '| MAME | '; mame-check | awk '{ printf "%-9s | %-9s |\n", $1, $2}'
[ -x $HOME/hypseus/hypseus ] && echo -n '| Hypseus-Singe | '; hypseus-check | awk '{ printf "%-9s | %-9s |\n", $1, $2}'
echo '+---------------+-----------+-----------+'
fi
Ajustement des permissions pour permettre l’exécution du script :
chmod +x ~/scripts/versions-check.sh
Affichage des notices au login
sudo nano /etc/bash.bashrc
Pour afficher le Frontend courant ainsi que le ROM couramment émulé par MAME (si applicable), coller les lignes ci-dessous à la fin du fichier :
echo '----------------------------------------------------------------------'
# Load environment settings...
if [ -f /home/pi/settings ]; then
while IFS="= " read var value; do
[ ! -z $var ] && [ "${var:0:1}" != "#" ] && export $var="$value"
done < /home/pi/settings
fi
MAMEROM=$(ps h -C mame -o cmd | awk '{print $2}'); [ "${MAMEROM:0:1}" == "-" ] && MAMEROM=
echo "Current Frontend: $(case $FRONTEND in \
attract) echo "Attract Mode$([ -x /usr/local/bin/attract ] && attract -v | awk '/Attract-Mode/ {print " " $2}')" ;; \
advance) echo AdvanceMENU ;; \
mame) ([ ! -z $MAMEROM ] && [ "$MAMEROM" == "$AUTOROM" ]) && echo 'None/AutoROM Mode' || echo 'MAME GUI' ;; \
*) echo 'NOT SET' ;; esac)."
[ ! -z $MAMEROM ] && echo Currently emulated ROM: \
$(/home/pi/mame/mame -listfull $MAMEROM | awk -F '"' '!/Description:$/ {print $2}').
Pour afficher un tableau récapitulatif des versions de MAME et de Hypseus-Singe, coller la ligne ci-dessous à la suite de celles ci-dessus, puis sauvegarder :
[ -x $HOME/scripts/versions-check.sh ] && . $HOME/scripts/versions-check.sh
Pour afficher le mode actif (Service ou Arcade), coller la ligne ci-dessous à la suite de celle ci-dessus, puis sauvegarder :
echo "The system is currently in $(systemctl -q is-active mame-autostart.service && echo ARCADE || echo SERVICE) mode."
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 11 \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 /boot/config.txt
Coller les lignes ci-dessous, puis sauvegarder :
# Turns off WiFi (for those who use Ethernet only)
dtoverlay=disable-wifi
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 /boot/config.txt
Coller les lignes ci-dessous, puis sauvegarder :
# Turns off Bluetooth
dtoverlay=disable-bt
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
Éditez le fichier de configuration de dhcpd :
sudo nano /etc/dhcpcd.conf
Ajoutez les lignes suivantes à la fin du fichier, puis sauvegardez :
noarp
ipv4only
noipv6
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
Désactivation du client NFS
sudo apt-get remove nfs-common -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
arm_freq=2000
over_voltage=6
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).
Création du script automatisé de compilation de SDL2 :
nano ~/scripts/sdl2-latest.sh
Coller les lignes ci-dessous dans l'éditeur, puis sauvegarder :
#!/bin/bash
# This script build the latest SDL2 version without X11 dependency.
function sdl2-latest {
CHECKURL=https://github.com/libsdl-org/SDL/releases/latest
HTMLTAG='<title>Release '
LATESTSDL2VER=$(wget -q -O - $CHECKURL | grep "$HTMLTAG" | awk '{print $2}')
if [ -z $LATESTSDL2VER ]; then echo ERROR; exit; fi # We make sure wget was successful
echo $LATESTSDL2VER
}
function sdl2-ttf-latest {
CHECKURL=https://github.com/libsdl-org/SDL_ttf/releases/latest
HTMLTAG='<title>Release '
LATESTSDL2TTFVER=$(wget -q -O - $CHECKURL | grep "$HTMLTAG" | awk '{print $2}')
if [ -z $LATESTSDL2TTFVER ]; then echo ERROR; exit; fi # We make sure wget was successful
echo $LATESTSDL2TTFVER
}
VERSION=$(sdl2-latest)
TTFVERSION=$(sdl2-ttf-latest)
if [ "$(sdl2-config --version)" == "$VERSION" ]; then
echo SDL2 is already at the latest version \($VERSION\).
exit
else
if [ "${1,,}" != "nodep" ]; then
echo Installing SDL2 dependencies...
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
echo OpenGL ES 2 dependencies...
sudo apt-get install libgles2-mesa-dev -y
fi
echo Build dependencies...
sudo apt-get install build-essential -y
cd ~
echo Buiding SDL2 $VERSION...
# Based from "Compile SDL2 from source"
# https://github.com/midwan/amiberry/wiki/Compile-SDL2-from-source
wget https://libsdl.org/release/SDL2-${VERSION}.zip
unzip SDL2-${VERSION}.zip
rm SDL2-${VERSION}.zip
cd SDL2-${VERSION}
./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 --disable-joystick-virtual --enable-arm-neon --enable-arm-simd
[ $(uname -m) == "armv7l" ] && make -j $(nproc) CFLAGS='-mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard'
[ $(uname -m) == "aarch64" ] && make -j $(nproc) CFLAGS='-mcpu=cortex-a72'
sudo make install
# SDL2_ttf
wget https://libsdl.org/projects/SDL_ttf/release/SDL2_ttf-${TTFVERSION}.tar.gz
tar zxvf SDL2_ttf-${TTFVERSION}.tar.gz
rm SDL2_ttf-${TTFVERSION}.tar.gz
cd SDL2_ttf-${TTFVERSION}
./configure
make -j $(nproc)
sudo make install
sudo ldconfig -v
cd ~
sudo rm -R SDL2-${VERSION}
sudo rm -R SDL2_ttf-${TTFVERSION}
sudo apt-get remove build-essential -y
fi
Ajustement des permissions pour permettre l’exécution du script :
chmod +x ~/scripts/sdl2-latest.sh
Lancer la compilation de SDL2 :
~/scripts/sdl2-latest.sh
Compilation de MAME (optimisé, sans X11)
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 latest version or a specific version.
# GCC compiler optimization for ARM-based systems : https://gist.github.com/fm4dd/c663217935dc17f0fc73c9c81b0aa845
#ARCHOPTS='-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.....
ARCHOPTS32='-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'
ARCHOPTS64='-march=armv8-a+crc+simd -mcpu=cortex-a72 -mtune=cortex-a72 -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 SYMBOLS=0'
MAXTHREAD=2 # 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
for o in $(findmnt -n -o OPTIONS / | sed 's/,/ /g'); do
[ "${o,,}" = ro ] && sudo mount -o remount,rw /
done
}
fs_lock() { # Put root filesystem in read-only mode
for o in $(findmnt -n -o OPTIONS / | sed 's/,/ /g'); do
[ "${o,,}" = rw ] && sudo mount -o remount,ro /
done
}
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 || echo "$KEY=$VALUE" | sudo tee -a /etc/environment
}
get_history() { # Grab the latest history.dat 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/download3.gif" height="40px" />)[^*]*'
HISTORYFILE=$(wget -q -O - $BASEURL/index.php?page=download | grep "$BASETAG" | sed -r "s%$REGEX%\2%")
wget -q $BASEURL/dats/$HISTORYFILE -P ~ # Download the file
unzip -o ~/$HISTORYFILE history.dat -d ~/.mame
if [ -L ~/.mame/history ]; then # Symlink is present
mv ~/.mame/history.dat ~/.mame/history
fi
rm ~/$HISTORYFILE # Cleanup
}
mame-latest() { # Get the latest version of MAME
CHECKURL=https://github.com/mamedev/mame/releases/latest
HTMLTAG='<title>Release MAME'
LATESTMAMEVER=$(wget -q -O - $CHECKURL | grep "$HTMLTAG" | awk '{print $3}')
if [ -z $LATESTMAMEVER ]; then echo ERROR; exit; fi # We make sure wget was successful
echo $LATESTMAMEVER
}
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 | Latest
echo ' Where VER is the 4-digit version number of MAME to update (for example: 0224).'
echo ' OR use the argument Latest to update to the latest available MAME version.'
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
if [ "${1,,}" == "latest" ]; then
MAMEVER=$(mame-latest)
MAMEVER=${MAMEVER//./} # Remove the dot
else
MAMEVER=$1
fi
MAMESRCPATH=/home/pi/mame${MAMEVER}
SCRIPTPATH=${0%/*}
echo Installing/uptading to MAME $MAMEVER...
fs_unlock
# Install MAME dependencies...
sudo apt-get install fontconfig libfontconfig-dev libx11-dev libpulse-dev -y
if [ ! -d $MAMESRCPATH ]; 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 $MAMESRCPATH/mame ]; then # We build only if not already built
# Build of MAME
# Dependencies
# Swap requirement
sudo apt-get install dphys-swapfile -y
if [ "$(grep '^CONF_SWAPSIZE' /etc/dphys-swapfile | cut -d= -f2)" != "2048" ]; then
sudo sed -i "s/^#\{0,1\}\s*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
cd $MAMESRCPATH
[ "$(uname -m)" == "armv7l" ] && echo MAKE CMDLINE=make -j$MAXTHREAD ARCHOPTS=\"$ARCHOPTS32\" $MAKEOPTS PLATFORM=arm
[ "$(uname -m)" == "aarch64" ] && echo MAKE CMDLINE=make -j$MAXTHREAD ARCHOPTS=\"$ARCHOPTS64\" $MAKEOPTS PLATFORM=arm64 PTR64=1
BUILDSTART=$(date +%s)
echo Build start time: $(date +"%T")
echo -----------------------------------------------------------------------------------
echo Please wait until the build is completed \(about 10 hours\)...
echo -----------------------------------------------------------------------------------
[ "$(uname -m)" == "armv7l" ] && make -j$MAXTHREAD ARCHOPTS="$ARCHOPTS32" $MAKEOPTS PLATFORM=arm
[ "$(uname -m)" == "aarch64" ] && make -j$MAXTHREAD ARCHOPTS="$ARCHOPTS64" $MAKEOPTS PLATFORM=arm64 PTR64=1
echo Build time took: $(secs_to_human "$(($(date +%s) - ${BUILDSTART}))").
if [ -x $MAMESRCPATH/mame ]; then
echo -----------------------------------------------------------------------------------
echo Build Success!
echo -----------------------------------------------------------------------------------
# Successful build!
# We make sure the MAME environment variable is 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
# Install MAME True-Type Liberation Sans font
if [ ! -d /usr/share/fonts/truetype/liberation-fonts ]; then
echo Installing Liberation Sans font...
cd ~
wget -q https://dl.dafont.com/dl/?f=liberation_sans -O liberation_sans.zip
if [ -f liberation_sans.zip ]; then
sudo mkdir /usr/share/fonts/truetype/liberation-fonts
sudo unzip -o /home/pi/liberation_sans.zip *.ttf -d /usr/share/fonts/truetype/liberation-fonts
rm liberation_sans.zip
sudo fc-cache -f -v
fi
fi
# MAME binary symlink creation or update
if [ -L ~/mame ]; then rm ~/mame; fi
ln -s $MAMESRCPATH ~/mame
if [ ! -L ~/.mame ] && [ ! -d ~/.mame ]; then # MAME data path symlink creation
[ -d /data/mame ] && ln -s /data/mame ~/.mame || mkdir ~/.mame
fi
if [ ! -f ~/.mame/mame.ini ]; then # If mame.ini does not exist, let's create it
cd ~/.mame
$MAMESRCPATH/mame \
-hashpath '$HOME/mame/hash' \
-languagepath '$HOME/mame/language' \
-pluginspath '$HOME/mame/plugins' \
-artpath '$HOME/.mame/artwork' \
-ctrlrpath '$HOME/.mame/ctrlr' \
-inipath '$HOME/.mame/ini' \
-homepath '$HOME/.mame/lua' \
-rompath '$HOME/.mame/roms' \
-cfg_directory '$HOME/.mame/cfg' \
-diff_directory '$HOME/.mame/diff' \
-input_directory '$HOME/.mame/inp' \
-nvram_directory '$HOME/.mame/nvram' \
-snapshot_directory '$HOME/.mame/snap' \
-state_directory '$HOME/.mame/sta' \
-skip_gameinfo \
-video accel \
-videodriver kmsdrm \
-renderdriver opengles2 \
-audiodriver alsa \
-samplerate 22050 \
-createconfig
fi
if [ -z $FRONTEND ]; then
if [ ! -f /home/pi/settings ]; then
echo FRONTEND=mame>/home/pi/settings
else
grep -q FRONTEND= /home/pi/settings && sed -i "s/^FRONTEND=.*$/FRONTEND="${1,,}"/g" $(readlink /home/pi/settings) || (echo AUTOROM="${2,,}" | tee -a /home/pi/settings; echo | tee -a /home/pi/settings)
fi
fi
if [ ! -L /home/pi/settings ] && [[ $(findmnt -n /data) ]]; then # Symlink not found and /data is mounted...
[ ! -f /data/.sys/env/settings ] && mkdir -p /data/.sys/env
if [ ! -f /home/pi/settings ]; then
touch /data/.sys/env/settings
echo 'FRONTEND=mame'>/home/pi/settings
else # File settings already exist
mv /home/pi/settings /data/.sys/env
fi
ln -s /data/.sys/env/settings /home/pi/settings
fi
# Get the latest history.dat file
echo Applying latest history.dat...
# get_history # Broken, to be fixed
# Freeing some space...
for f in src build 3rdparty roms
do
rm -Rf $MAMESRCPATH/$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
Compilation de la plus récente version de MAME :
./scripts/mame-updater.sh latest
Patienter environ 10 heures et demie (ce temps est obtenu avec un Raspberry Pi 4 et un maximum de 2 threads pour la compilation), 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.
[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
Compilation de Hypseus-Singe (émulateur de jeux Laser-Disc d'arcade)
Nous allons créer le script de compilation suivant :
nano ~/scripts/hypseus-build.sh
Coller les lignes ci-dessous, puis sauvegarder :
#!/bin/bash
# This script build and install the latest version of the laserdisc emulator Hypseus-Singe.
function hypseus-latest {
CHECKURL=https://github.com/DirtBagXon/hypseus-singe/releases/latest
HTMLTAG='<title>Release hypseus-singe'
LATESTHYPSEUSVER=$(wget -q -O - $CHECKURL | grep "$HTMLTAG" | awk '{print $3}')
if [ -z $LATESTHYPSEUSVER ]; then echo ERROR; exit; fi # We make sure wget was successful
LATESTHYPSEUSVER=${LATESTHYPSEUSVER##v} # Strip the leading v
echo $LATESTHYPSEUSVER
}
if [ "${1,,}" != "nodep" ]; then
echo Installing dependencies...
# Hypseus-Singe dependencies...
# SDL2_image
cd ~
wget https://libsdl.org/projects/SDL_image/release/SDL2_image-2.0.5.zip
unzip -q SDL2_image-2.0.5.zip
cd SDL2_image-2.0.5
./configure
make -j $(nproc)
sudo make install
sudo ldconfig -v
cd ../
rm SDL2_image-2.0.5.zip
rm -R SDL2_image-2.0.5
sudo apt-get install libmpeg2-4-dev libvorbis-dev libogg-dev zlib1g-dev libzip-dev -y
fi
VERSION=$(hypseus-latest)
if [ ! -d ~/hypseus-singe-${VERSION}-RPi ]; then
echo Downloading Hypseus-Singe $VERSION...
cd ~
wget https://github.com/DirtBagXon/hypseus-singe/archive/refs/tags/v${VERSION}-RPi.zip
unzip -q v${VERSION}-RPi.zip
fi
if [ ! -x ~/hypseus-singe-${VERSION}-RPi/hypseus ]; then
# Dependency to build
sudo apt-get install cmake build-essential -y
echo Building Hypseus-Singe $VERSION...
cd ~/hypseus-singe-${VERSION}-RPi/
mkdir build
cd build
cmake ../src
make -j4
fi
if [ -x ./hypseus ]; then
echo Hypseus-Singe $VERSION build succeeded.
[ ! -d ~/hypseus ] && mkdir ~/hypseus
cd ~/hypseus-singe-${VERSION}-RPi/build
mv hypseus ~/hypseus
[ ! -d /data/hypseus/framefile ] && mkdir /data/hypseus/framefile
[ ! -d /data/hypseus/ram ] && mkdir /data/hypseus/ram
cd ../
[ ! -d ~/hypseus/sound ] && mv doc fonts pics scripts sound ~/hypseus
[ ! -d ~/hypseus/roms ] && mv mv roms/ screenshots/ ~/.hypseus
cd ~/hypseus
[ ! -L ~/hypseus/ram ] && ln -s /data/hypseus/ram ram
[ ! -L ~/hypseus/singe ] && ln -s /data/hypseus/framefile singe
[ ! -L ~/hypseus/roms ] && ln -s /data/hypseus/roms roms
cd
[ -d ~/hypseus-singe-${VERSION}-RPi ] && rm -R ~/hypseus-singe-${VERSION}-RPi
[ -f ~/v${VERSION}-RPi.zip ] && rm ~/v${VERSION}-RPi.zip
sudo apt-get remove cmake -y
# Cleanup
sudo rm -R build sfml-pi-R3
else
echo Hypseus-Singe $VERSION build failed.
fi
Ajustement des permissions pour permettre l’exécution du script :
chmod +x ~/scripts/hypseus-build.sh
Lancement de la compilation de Hypseus-Singe :
~/scripts/hypseus-build.sh
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).
Si le frontend sélectionné est MAME et que la variable AUTOROM
est assignée à la valeur d'un ROM (sans son extension .zip), ce ROM sera alors passé à MAME et sera automatiquement démarré. Voir la commande frontend
pour l'assignation de la variable AUTOROM.
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
if [ ! -z "$AUTOROM" ] && [ $(wc -w <<< "$AUTOROM") == 2 ]; then
read -r EMULNAME ROMNAME <<< "${AUTOROM//\"/}"
CFGFILE=/home/pi/.attract/emulators/$EMULNAME.cfg
if [ -f $CFGFILE ]; then
while read VAR VALUE; do
[ ! -z $VAR ] && [ "${VAR:0:1}" != '#' ] && export $VAR="$VALUE"
done < $CFGFILE
ARGS=${args//\[name\]/$ROMNAME}
ARGS=${ARGS//\$HOME/$HOME}
EXEC=${executable//\$HOME/$HOME}
if [ "${EXEC##*/}" = hypseus ]; then # Hypseus-Singe
FRAMEFILE=$(sed 's/^.*\s-framefile\s\(\S*\)\s.*$/\1/' <<< $ARGS)
fi
fi
if [ ! -z $FRAMEFILE ] && [ -f $FRAMEFILE ] && [ ! -z $EXEC ] && [ -x $EXEC ]; then # Automatic ROM Launch mode
$EXEC $ARGS -nolog >/dev/null 2>/dev/null
else
stty -echo
/usr/local/bin/attract --loglevel silent >/dev/null 2>&1
fi
else
stty -echo
/usr/local/bin/attract --loglevel silent >/dev/null 2>&1
fi
;;
advance) # AdvanceMENU
/home/pi/frontend/advance/advmenu
;;
mame) # MAME GUI or Automatic ROM Launch mode if AUTOROM is set
/home/pi/mame/mame $([ ! -z $AUTOROM ] && [ -f /home/pi/.mame/roms/$AUTOROM.zip ] && echo $AUTOROM) >/dev/null 2>/dev/null
;;
esac
(( $? != 0 ))
do
:
done
else
echo $0 - FRONTEND variable 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
ConditionPathExists=/home/pi/settings
[Service]
User=pi
Group=pi
PAMName=login
Type=simple
EnvironmentFile=/home/pi/settings
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
Forcer Systemd
en tant que système d'initialisation (init) :
init=/bin/systemd
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 init=/bin/systemd
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 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 des deux (2) ligne suivantes :
interfaces = 127.0.0.0/8 eth0
bind interfaces only = yes
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 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/mame/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/
Pour permettre à MAME de trouver son fichier de configuration mame.ini
, un symlink est nécessaire :
ln -s ./ini/mame.ini /data/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
[ -f /data/mame/lua/hiscore/plugin.cfg ] && mv /data/mame/lua/hiscore/plugin.cfg /data/mame/hi
rmdir /data/mame/lua/hiscore
ln -s /data/mame/hi /data/mame/lua/hiscore
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 flyers
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 .
;;
*)
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 ~/scripts/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 pour lister le nom des ROMs présents
nano ~/scripts/mame-romlist.sh
Coller le texte ci-dessous, puis sauvegarder :
#!/bin/bash
# This script list the name of the current MAME ROMs.
cd /home/pi/.mame/roms
for f in *.zip; do
echo -e "[${f%.*}]\t$(/home/pi/mame/mame -listfull ${f%.*} | awk -F '"' '!/Description:$/ {print $2}')"
done
Ajustement des permissions pour permettre l'exécution du script :
chmod +x ~/scripts/mame-romlist.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 mame-autostart.service
[Service]
Type=simple
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
Afin de prolonger la vie la carte SD, nous allons mettre en lecture-seule les partitions suivantes :
/boot (vfat)
/ (ext4)
Pour ce faire, nous allons utiliser le script ci-dessous :
nano ~/scripts/read-only-rootfs.sh
Coller le script bash ci-dessous, puis sauvegarder :
#!/bin/bash
# This script put the root (/) and /boot filesystems in read-only mode.
# Based on: https://medium.com/swlh/make-your-raspberry-pi-file-system-read-only-raspbian-buster-c558694de79
# Check /etc/fstab to see if this script has already been executed
awk '/\/ /{print $4}' /etc/fstab | grep -q ro, && awk '/\/boot/{print $4}' /etc/fstab | grep -q ro, && echo 'This script has already been executed and your system is already in read-only mode.' && exit
echo ---------------------------------------------------------------------
echo This script will convert this system in read-only mode.
echo
echo The system will be automatically rebooted, once the script complete.
echo ---------------------------------------------------------------------
while true; do
read -p "Do you wish to continue? " yn
case ${yn,,} in
y | yes) break;;
n | no) exit;;
*) echo "Please answer yes or no.";;
esac
done
# START
echo ---------------------------------------------------------------------
echo Applying the required changes to the system...
echo ---------------------------------------------------------------------
# Remove swap and other stuff
sudo apt-get remove --purge triggerhappy logrotate dphys-swapfile -y
sudo apt-get autoremove --purge -y
# Disable swap and filesystem check and set it to read-only
sudo sed -ie 's/^console=serial0,115200.*$/& fsck.mode=skip noswap ro/g' /boot/cmdline.txt
# Replace your log manager
sudo apt-get install busybox-syslogd -y
sudo apt-get remove --purge rsyslog -y
# From now on, use sudo logread to check your system logs.
# /etc/fstab: Add read-only mode to /boot or /boot/firmware filesystems
sudo sed -i '/\/boot/{/ro/!s/\S\S*/&,ro/4}' /etc/fstab
# /etc/fstab: Add read-only mode to / root filesystem
sudo sed -i '/\S\s\s*\/\s\s*/{/\(ro,\|,ro\)/!s/\S\S*/&,ro/4}' /etc/fstab
# We append the temporary file systems to fstab
sudo tee -a /etc/fstab << 'EOF'
tmpfs /tmp tmpfs nosuid,nodev 0 0
tmpfs /var/log tmpfs nosuid,nodev 0 0
tmpfs /var/tmp tmpfs nosuid,nodev 0 0
tmpfs /var/spool tmpfs nosuid,nodev 0 0
# Samba
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
EOF
# Move some system files to temp filesystem
sudo rm -rf /var/lib/dhcp /var/lib/dhcpcd5 /var/spool /etc/resolv.conf
sudo ln -s /tmp /var/lib/dhcp
sudo ln -s /tmp /var/lib/dhcpcd5
sudo touch /tmp/dhcpcd.resolv.conf
sudo ln -s /tmp/dhcpcd.resolv.conf /etc/resolv.conf
# Update the systemd random seed
[ -f /var/lib/systemd/random-seed ] && sudo rm /var/lib/systemd/random-seed
[ ! -L /var/lib/systemd/random-seed ] && sudo ln -s /tmp/random-seed /var/lib/systemd/random-seed
# Systemd drop-in to ajust systemd-random-seed.service
if [ ! -f /etc/systemd/system/systemd-random-seed.service.d/readonlyfs-fixup.conf ]; then
[ ! -d /etc/systemd/system/systemd-random-seed.service.d ] && sudo mkdir /etc/systemd/system/systemd-random-seed.service.d
echo '[Service]' | sudo tee -a /etc/systemd/system/systemd-random-seed.service.d/readonlyfs-fixup.conf
echo 'ExecStartPre=/bin/echo "" >/tmp/random-seed' | sudo tee -a /etc/systemd/system/systemd-random-seed.service.d/readonlyfs-fixup.conf
fi
# Shell commands to switch between RO and RW modes
grep -q "alias ro=" /etc/bash.bashrc || sudo tee -a /etc/bash.bashrc << 'EOF'
set_bash_prompt() {
fs_mode=$(mount | sed -n -e "s/^\/dev\/.* on \/ .*(\(r[w|o]\).*/\1/p")
PS1='\[\033[01;32m\]\u@\h${fs_mode:+($fs_mode)}\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
}
alias ro='sudo mount -o remount,ro / ; sudo mount -o remount,ro /boot'
alias rw='sudo mount -o remount,rw / ; sudo mount -o remount,rw /boot'
PROMPT_COMMAND=set_bash_prompt
EOF
# To make sure the file system goes back to read-only once you log out
grep -q "sudo mount -o remount,ro /" /etc/bash.bash_logout || echo 'sudo mount -o remount,ro /' | sudo tee -a /etc/bash.bash_logout
grep -q "sudo mount -o remount,ro /boot" /etc/bash.bash_logout || echo 'sudo mount -o remount,ro /boot' | sudo tee -a /etc/bash.bash_logout
# Alias ajustments
sed -ie "s/^alias arcademode=.*$/alias arcademode=\'rw; sudo systemctl enable mame-autostart.service; ro\'/g" ~/.bash_aliases
sed -ie "s/^alias servicemode=.*$/alias servicemode=\'rw; sudo systemctl disable mame-autostart.service; ro\'/g" ~/.bash_aliases
# Swap file removal
[ -f /var/swap ] && sudo rm /var/swap
# Purge of mount points content that switch to 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/*
sudo rm -R /var/log/*
# Systemd drop-ins for read-only mode ajustments
for i in raspberrypi-net-mods.service \
systemd-rfkill \
sshswitch.service \
rpi-eeprom-update.service
do
if [ ! $(systemctl -q is-enabled $i) ]; then
[ ! -d /etc/systemd/system/$i.d ] && sudo mkdir /etc/systemd/system/$i.d
if [ -f /etc/systemd/system/$i.d/readonlyfs-fixup.conf ]; then
grep -q [Service] /etc/systemd/system/$i.d/readonlyfs-fixup.conf || echo '[Service]' | sudo tee -a /etc/systemd/system/$i.d/readonlyfs-fixup.conf
else
echo '[Service]' | sudo tee -a /etc/systemd/system/$i.d/readonlyfs-fixup.conf
fi
echo 'ExecStartPre=/bin/sh -c "mount -o remount,rw /boot; mount -o remount,rw /"' | sudo tee -a /etc/systemd/system/$i.d/readonlyfs-fixup.conf
echo 'ExecStartPost=/bin/sh -c "mount -o remount,ro /boot; mount -o remount,ro /"' | sudo tee -a /etc/systemd/system/$i.d/readonlyfs-fixup.conf
fi
done
# Systemd drop-in for ajustment for systemd-timesyncd.service
sudo tee -a /etc/fstab << 'EOF'
# Timesyncd
tmpfs /var/lib/private tmpfs nosuid,mode=0755,nodev 0 0
tmpfs /var/lib/systemd/timesync tmpfs nosuid,mode=0755,nodev 0 0
EOF
[ ! -d /etc/systemd/system/systemd-timesyncd.service.d ] && sudo mkdir /etc/systemd/system/systemd-timesyncd.service.d
if [ -f /etc/systemd/system/systemd-timesyncd.service.d/readonlyfs-fixup.conf ]; then
grep -q [Service] /etc/systemd/system/systemd-timesyncd.service.d/readonlyfs-fixup.conf || echo '[Service]' | sudo tee -a /etc/systemd/system/systemd-timesyncd.service.d/readonlyfs-fixup.conf
else
echo '[Service]' | sudo tee -a /etc/systemd/system/systemd-timesyncd.service.d/readonlyfs-fixup.conf
fi
echo 'PrivateTmp=no' | sudo tee -a /etc/systemd/system/systemd-timesyncd.service.d/readonlyfs-fixup.conf
echo 'RestartSec=5' | sudo tee -a /etc/systemd/system/systemd-timesyncd.service.d/readonlyfs-fixup.conf
# Disable auto-update daemons
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
# Systemd daemon reload to update changes
sudo systemctl daemon-reload
echo ---------------------------------------------------------------------
echo Completed.
echo The system will reboot NOW.
echo ---------------------------------------------------------------------
sudo reboot
Ajustement des permissions pour permettre l'exécution du script, puis lancement du script :
chmod +x ~/scripts/read-only-rootfs.sh
~/scripts/read-only-rootfs.sh
Répondez par y
à la demande de confirmation et patientez. Le système redémarrera automatiquement, lorsque les étapes du script seront complétées.
Deux alias (rw
et ro
) sont créés afin de basculer du mode lecture-écriture vers lecture-seule et vice-versa.
Ajustement pour permettre de sauvegarder les réglages audio (volume)
sudo mkdir -p /data/.sys/alsa
sudo chown -R root:pi /data/.sys
# We grant rw to owner pi and pi group
sudo chown -R pi:pi /data/.sys/emv
sudo chmod -R 664 /data/.sys/env/*
# We grant Read+Execute (for directory traversal) to Group+Other
sudo chmod -R 755 /data/.sys
rw
sudo mv /var/lib/alsa/asound.state /data/.sys/alsa
# We revoke the Execute for Group+Other to the files under alsa
sudo chmod -R 744 /data/.sys/alsa/*
sudo rmdir /var/lib/alsa
sudo ln -s /data/.sys/alsa /var/lib/alsa
ro
Vérification
Assurez-vous que la commande ci-dessous ne retourne pas d'erreur :
sudo alsactl store
Redémarrer le système :
sudo reboot
Une fois redémarré, valider que le système est bien en lecture-seule :
- Ouvrez une session (console ou SSH)
- Une fois logué, l'invite de commande devrait indiquer le suffixe
(ro)
(pour read-only)
Activer temporairement le mode lecture/écriture du Root FileSystem, basculer en mode Arcade (mode normal) et redémarrer :
arcademode
sudo reboot
[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 du volume audio via un contrôle physique
Option #1 : Bouton physique relié aux broches 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-volume-ctrl.sh
Coller les lignes ci-dessous, puis sauvegarder :
#!/bin/bash
#file:/home/pi/scripts/mame-vol.sh
function cleanup {
# Deactivate GPIO pin
echo $GPIOPIN >/sys/class/gpio/unexport 2>/dev/null
exit 0
}
function waitStateChange {
while [ $(cat /sys/class/gpio/gpio${GPIOPIN}/value) != $1 ]; do
inotifywait -q -e modify /sys/class/gpio/gpio${GPIOPIN}/value > /dev/null
done
}
# Clean up when exit
trap cleanup EXIT
trap cleanup SIGHUP
trap cleanup SIGQUIT
trap cleanup SIGINT
trap cleanup SIGTERM
HIGH='95%'
MED='85%'
LOW='72%'
MUTE='0%'
GPIOPIN=4 # We use GPIO 4
# Initialize GPIO pin
[ -d /sys/class/gpio/gpio${GPIOPIN} ] && 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
waitStateChange 1 # Wait for button release
while true; do
waitStateChange 0 # Wait for button press
# 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
waitStateChange 1 # Wait for button release
done
Option #2 : Encodeur rotatif relié aux broches GPIO
Nous allons relier un encodeur rotatif bon marché (https://www.aliexpress.com/item/1005002845325794.html) aux broches GPIO afin de contrôler le volume global du système. À chaque degré de rotation, le niveau baisse ou monte d'un cran, dépendamment de la direction.
Pour que l'encodeur rotatif soit utilisable au sein de Linux, nous devons ajouter un overlay au sein du fichier config.txt
:
sudo nano /boot/config.txt
Copier les lignes ci-dessous, remplacer les numéros de broches GPIO selon vos sélections (ici, le terminal A de l'encodeur est reliée à la broche GPIO 17 et le terminal B de l'encodeur est relié à la broche GPIO 27), coller, puis sauvegarder :
# enable rotary encoder
dtoverlay=rotary-encoder,pin_a=17,pin_b=27,relative_axis=1
Réalisation du script qui sera exécuté au sein d'un service systemd
:
nano ~/scripts/mame-volume-ctrl.sh
Coller les lignes ci-dessous, puis sauvegarder :
#!/bin/bash
# GPIO-connected Rotary Encoder
DEVICE='/dev/input/by-path/platform-rotary@1b-event'
EVENT_UP='* code 0 (REL_X), value 1'
EVENT_DOWN='* code 0 (REL_X), value -1'
INCREMENT=3
OUTPUT=Headphone
CURVOL=$(amixer sget $OUTPUT | awk '/Mono.+/ { print $4}' | tr -d '[%]')
evtest "$DEVICE" | while read line; do
case $line in
$EVENT_UP)
# Volume increase
[ $(($CURVOL+$INCREMENT)) -lt 100 ] && CURVOL=$(($CURVOL+$INCREMENT)) || CURVOL=100
;;
$EVENT_DOWN)
# Volume decrease
[ $(($CURVOL-$INCREMENT)) -gt 0 ] && CURVOL=$(($CURVOL-$INCREMENT)) || CURVOL=0
;;
esac
amixer -q cset numid=1 ${CURVOL}%
done
SUITE DES ÉTAPES (après avoir réalisé l'option #1 ou #2) :
Ajustement des permissions pour permettre l’exécution du script :
chmod +x ~/scripts/mame-volume-ctrl.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-volume-ctrl.service --force --full
Coller les lignes ci-dessous et sauvegarder :
[Unit]
Description=MAME Audio Volume Controller service
Before=mame-autostart.service
After=alsa-restore.service
[Service]
Type=simple
User=pi
Group=pi
ExecStart=/bin/bash /home/pi/scripts/mame-volume-ctrl.sh
KillSignal=SIGINT
[Install]
WantedBy=multi-user.target
Activation et démarrage du service :
sudo systemctl enable mame-volume-ctrl.service
sudo systemctl start mame-volume-ctrl.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
function cleanup {
# Deactivate GPIO pin
echo $GPIOPIN >/sys/class/gpio/unexport 2>/dev/null
exit 0
}
# Clean up when exit
trap cleanup SIGHUP
trap cleanup SIGQUIT
trap cleanup SIGINT
trap cleanup SIGTERM
GPIOPIN=18 # We use GPIO 18 (pin #12)
BOOTSOUND=/home/pi/splash/boot.wav
SVCMSOUND=/home/pi/splash/service-mode.wav
TIMEOUT=5
raspi-gpio set $GPIOPIN pu # Enable the internal pull-up resistor for this GPIO pin
aplay -q $BOOTSOUND & # Play Boot sound
# Initialize GPIO pin
[ -d /sys/class/gpio/gpio${GPIOPIN} ] && 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 0 ]; then # 1=Open/Arcade Mode, 0=Closed/Service Mode
aplay -q $SVCMSOUND # Service Mode
touch /tmp/service-mode.flag
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=Boot-time Service Mode Toggle Service
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/service-mode.flag
Retirer la ligne suivante, puis sauvegarder :
Conflicts=getty@tty1.service smbd.service nmbd.service rng-tools.service cron.service mame-artwork-mgmt.service
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/service-mode.flag' | sudo tee -a /etc/systemd/system/$i.d/servicemode-fixup.conf; \
done; \
echo 'After=' | sudo tee -a /etc/systemd/system/rng-tools.service.d/servicemode-fixup.conf; \
echo 'After=mame-svcmode-check.service' | sudo tee -a /etc/systemd/system/rng-tools.service.d/servicemode-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).
sudo nano /boot/cmdline.txt
Ajouter ceci à la fin de ligne de commande du kernel, puis sauvegarder :
fbcon=rotate:1
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.jpg
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.
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 !
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. :-)
Merci beaucoup @fxlevy ! :)