Há alguns meses, adquiri um console portátil R36S. Apesar de gostar de algumas velharias alguns jogos emulados, comprei mais com o objetivo de “hackear” e estudar mesmo, e no último fim de semana, resolvi pôr a mão na massa: fiz um programa simples em linguagem Rust que lê os estados dos botões e joysticks e os exibe na tela. Fiz isso porque eu queria praticar um pouco de cross-compiling em Rust — uma técnica em que desenvolvo um software em uma plataforma, mas compilo gerando um binário que vai rodar em outra.
O R36S é um console portátil fabricado por algumas empresas chinesas (existem “clones” dele), voltado para emulação de consoles antigos. Pode ser encontrado por aí na faixa de “duzentão” ou até menos.
Normalmente ele vem com o sistema operacional ArkOS (baseado na distribuição Ubuntu do Linux), voltado especificamente para a emulação retrô. Sua arquitetura de hardware é voltada para eficiência energética. Possui um chipset RK3326 que integra um processador ARM-Cortex-A35 quad-core de 64 bits.
Pesquisando e experimentando, descobri que as entradas do console podem ser lidas a partir do dispositivo /dev/input/js0. Ele possui 17 botões, que são mapeados de 0 a 16, enquanto os eixos dos joysticks analógicos são mapeados de 0 a 3 (existem alguns botões na lateral do console também, mas resolvi não tentar usá-los, pois normalmente são usados para ligar/desligar o console, reset e controle de volume).
O objetivo, então, era simples: fazer um programa que ficasse “observando” as mudanças de estado nos botões e joysticks e exibindo esses estados na tela. Resolvi fazer a tela do programa em modo texto mesmo, já que o sistema operacional do console é um Linux e concluí que eu poderia usar um “modo terminal”. Para fazer o layout da tela, resolvi usar o ratatui, uma biblioteca para Rust que serve justamente para fazer TUIs (Text User Interfaces).
Para quem quiser reproduzir a experiência, segue o passo a passo do projeto.
Este projeto foi desenvolvido em um ambiente WSL (Ubuntu 24.04.1 no Windows) em um PC de 64 bits. Esse tutorial considera que você está usando esse ambiente de desenvolvimento. Se você está desenvolvendo em um ambiente diferente, deve levar em consideração essas diferenças. O primeiro passo é certificar-se de que o sistema operacional está atualizado. Abra o terminal e digite:
sudo apt update
sudo apt upgrade -y
As linhas de comando abaixo instalam o toolchain (compilador e conjunto de ferramentas):
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
. "$HOME/.cargo/env" -y
Se quiser verificar se Rust foi instalado corretamente, basta digitar:
cargo --version
Cargo é o gerenciador de pacotes e de compilação do ecossistema Rust. Esse comando deverá mostrar a versão instalada do Cargo. No meu caso, 1.91.1.
Vamos lembrar que esse é um projeto de cross-compiling. Na prática, estamos desenvolvendo em um PC Linux de 64bits (Linux x86_64), mas vamos compilar o programa para rodar num ambiente com processador ARM (Linux aarch64). Há um capítulo inteiro falando sobre esse assunto no meu livro. Para que isso seja possível, vamos usar a ferramenta rustup para instalar o target desejado:
rustup target add aarch64-unknown-linux-musl
Para verificar se o target (a nova plataforma-alvo) foi instalado corretamente, digite:
rustup target list --installed
Devem aparecer o target atual (que você está usando para desenvolver) e o novo target instalado. No meu caso:
aarch64-unknown-linux-musl
x86_64-unknown-linux-gnu
Como estamos compilando para a plataforma Linux aarch64, o compilador Rust ainda precisa de ferramentas externas para completar a “linkagem” do binário executável. Ele até consegue fazer o primeiro estágio de compilação, gerando os arquivos “objeto”, mas quem cria o binário final é o “linker” – normalmente o cc, gcc ou clang. Para instalar essas dependências, digite:
sudo apt install build-essential -y
Baixe e acesse o código-fonte do projeto com os comandos:
git clone https://github.com/luizferreira-io/r36s-input-demo
cd r36s-input-demo
Para compilar o projeto, digite:
cargo build --release --target aarch64-unknown-linux-musl
Com esse comando, o Cargo (gerenciador de pacotes e compilação do Rust) vai baixar as bibliotecas necessárias e compilar o projeto, tendo como target (plataforma-alvo) o ambiente aarch64-unknown-linux-musl.
O programa binário compilado estará disponível no subdiretório target/aarch64-unknown-linux-musl/release/.
A estratégia de deploy adotada nesse projeto foi instalar o programa no diretório /roms/ports. No console R36S, esse diretório é um local especial destinado a jogos e aplicações nativas, que não são ROMs de emuladores. Ele funciona como uma espécie de hub para jogos, engines e programas que são executáveis Linux reais — incluindo binários escritos por você.
A estrutura de diretórios deverá ficar assim:
/roms/ports/r36s-input-demo/r36s-input-demo
/roms/ports/R36S_Input_Demo.sh
Os arquivos marcados na cor verde são executáveis. O arquivo R36S_Input_Demo.sh deverá ter o conteúdo mostrado abaixo:
#!/bin/bash
PORTNAME="R36S Input Demo"
GAMEDIR="/roms/ports/r36s_input_demo"
cd "$GAMEDIR"
if [ -z "$ESUDO" ]; then
ESUDO="sudo"
fi
$ESUDO chmod 666 /dev/tty1 2>/dev/null
$ESUDO chmod 666 /dev/input/js0 2>/dev/null
$ESUDO chmod +x ./r36s_input_demo
$ESUDO ./r36s_input_demo < /dev/tty1 > /dev/tty1 2>&1
Para copiar os arquivos para o console, você tem duas opções:
Opção A (mais simples):
Conectar o cartão de memória no PC e copiar diretamente para o diretório correto no cartão de memória.
Opção B (requer algum conhecimento básico de Linux):
Fazer upload para o console. Para isso, você precisará ativar o wifi, se tiver um dispositivo wifi USB que encaixe nele. Também será necessário ativar os serviços remotos, acessando o menu principal Options -> ENABLE REMOTE SERVICES.
Com o serviço ativado, abra o navegador na barra de endereços, digite o endereço IP do console na sua rede wifi. Para ver o IP, acesse o menu principal Options –> WIFI –> Current Network Info.
Use o menu para fazer upload dos arquivos. Usando esse método, normalmente eles são gravados dentro do console, no diretório /roms2. Você terá que acessar o console via SSH para colocá-los no lugar certo. Para fazer isso, digite:
ssh ark@IP_DO_SEU_CONSOLE
Por padrão, a senha de acesso do usuário ark é ark.
Acessando o console, coloque os arquivos nos diretórios indicados e marque-os como executáveis (chmod +x).
Fazendo isso, seu console deverá mostrar a opção PORTS no menu inicial, com o “jogo” R36S_INPUT_DEMO.