Files
Arch-R/FLASHER.md
Douglas Teles b36a333523 Add Flasher app specification
Complete spec for the Arch R Flasher desktop app: console type selection,
panel identification wizard, image download from GitHub releases, SD card
flashing with panel overlay auto-configuration. Supports Windows/macOS/Linux.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 17:23:03 -03:00

24 KiB

Arch R Flasher

Gravador de SD card + gerenciador de overlays para Arch R.

Conceito

App desktop cross-platform (Windows, Linux, macOS) com duas funcoes:

  1. Flash — Grava a imagem no SD card e aplica o overlay do painel selecionado
  2. Overlay — Altera o painel de um SD card ja gravado (sem re-flash)

O usuario nao precisa saber nada de terminal, DTBs ou overlays. Inspirado no Raspberry Pi Imager (flash) + ROCKNIX overlay_server (painel).

Stack

Tauri 2 (Rust backend + web frontend)

Camada Tecnologia Motivo
Backend Rust (Tauri) Acesso raw a disco, download, manipulacao FAT32. Binario ~5MB (vs ~150MB Electron)
Frontend HTML/CSS/JS (vanilla ou Svelte) UI leve, sem framework pesado
Disk write Rust (std::fs::File + raw device) Gravacao direta no block device
FAT32 Rust (fatfs crate) Leitura/escrita na particao BOOT sem montar no OS
Download Rust (reqwest) Busca ultima release no GitHub
Empacotamento Tauri bundler .msi (Windows), .dmg (macOS), .AppImage/.deb (Linux)

Por que Tauri e nao Electron?

  • Binario ~5MB vs ~150MB
  • Sem Node.js runtime
  • Rust da acesso direto a disco sem wrappers
  • Alinhado com o lema: leve como uma pluma

Arquitetura: Overlays (nao DTBs)

A imagem universal (ArchR-R36S-no-panel) contem:

  • /KERNEL — kernel Image
  • /dtbs/ — 13 board DTBs (selecionados por boot.ini via hwrev/ADC)
  • /overlays/ — todos os 20 panel DTBOs disponiveis
  • /boot.ini — carrega board DTB + aplica overlays/mipi-panel.dtbo

O board DTB (hardware: GPIOs, PMIC, joypad, audio) e selecionado automaticamente. O panel overlay (init sequences do display) e o que o Flasher configura.

Como funciona

  1. Boot.ini seleciona o board DTB correto (hwrev ADC)
  2. Boot.ini tenta carregar overlays/mipi-panel.dtbo
  3. Se existir, aplica no DTB via fdt apply → display funciona
  4. Se nao existir, boot continua sem overlay → display pode nao funcionar

O Flasher copia o DTBO do painel selecionado como overlays/mipi-panel.dtbo.


Abas da Interface

Aba 1: Flash (gravar imagem + painel)

┌─────────────────────────────────────────────────┐
│           ARCH R FLASHER                        │
│  ┌──────────┐ ┌──────────┐                      │
│  │  Flash   │ │ Overlay  │                      │
│  └──────────┘ └──────────┘                      │
│                                                 │
│  ┌───────────────────────────────────────────┐  │
│  │  Imagem: ArchR-R36S-no-panel             │  │
│  │  v1.0 beta2 (2026-03-04)                │  │
│  │  [Baixar nova versao] [Selecionar local] │  │
│  └───────────────────────────────────────────┘  │
│                                                 │
│  1. Console:                                    │
│     ┌──────────────┐ ┌──────────────┐           │
│     │ R36S Original│ │  R36S Clone  │           │
│     └──────────────┘ └──────────────┘           │
│                                                 │
│  2. Painel:                                     │
│     ┌───────────────────────────────────────┐   │
│     │ ▼ Panel 4 (padrao, ~60%)              │   │
│     │   Panel 0                             │   │
│     │   Panel 1                             │   │
│     │   Panel 2                             │   │
│     │   Panel 3                             │   │
│     │   Panel 4 ★                           │   │
│     │   Panel 4-V22                         │   │
│     │   Panel 5                             │   │
│     │   R46H (1024x768)                     │   │
│     └───────────────────────────────────────┘   │
│                                                 │
│  3. Destino:                                    │
│     ┌───────────────────────────────────────┐   │
│     │ ▼ /dev/sdc (32GB SD Card)             │   │
│     └───────────────────────────────────────┘   │
│     [Atualizar lista]                           │
│                                                 │
│  ┌───────────────────────────────────────────┐  │
│  │           ★  GRAVAR  ★                   │  │
│  └───────────────────────────────────────────┘  │
│                                                 │
│  ████████████████░░░░░░░░ 67%  2.1GB/3.1GB      │
│  Gravando imagem...                             │
│                                                 │
└─────────────────────────────────────────────────┘

Aba 2: Overlay (trocar painel sem re-flash)

┌─────────────────────────────────────────────────┐
│           ARCH R FLASHER                        │
│  ┌──────────┐ ┌──────────┐                      │
│  │  Flash   │ │ Overlay  │                      │
│  └──────────┘ └──────────┘                      │
│                                                 │
│  SD Card com Arch R:                            │
│     ┌───────────────────────────────────────┐   │
│     │ ▼ /dev/sdc (32GB SD Card)             │   │
│     └───────────────────────────────────────┘   │
│     [Atualizar lista]                           │
│                                                 │
│  Overlay atual: panel4.dtbo                     │
│  Console detectado: original                    │
│                                                 │
│  Novo painel:                                   │
│     ┌───────────────────────────────────────┐   │
│     │ ▼ Panel 3                             │   │
│     └───────────────────────────────────────┘   │
│                                                 │
│  Ajustes (opcional):                            │
│     ┌─────────────────────────────────────┐     │
│     │  Rotacao:  [0°] [90°] [180°] [270°] │     │
│     │                                     │     │
│     │  Inversao de stick:                 │     │
│     │    [ ] Esquerdo   [ ] Direito       │     │
│     │                                     │     │
│     │  Audio:                             │     │
│     │    (•) Auto  ( ) Amplificado        │     │
│     │    ( ) Simples                      │     │
│     │                                     │     │
│     │  Inversao HP: [ ]                   │     │
│     └─────────────────────────────────────┘     │
│                                                 │
│  ┌───────────────────────────────────────────┐  │
│  │          ★  APLICAR OVERLAY  ★           │  │
│  └───────────────────────────────────────────┘  │
│                                                 │
│  ✓ Overlay aplicado! Insira o SD e reinicie.    │
│                                                 │
└─────────────────────────────────────────────────┘

Paineis por Console

Cada painel tem seu proprio DTBO com init sequences nativas. O Flasher copia o DTBO selecionado como overlays/mipi-panel.dtbo.

R36S Original (8 paineis)

Nome DTBO Padrao
Panel 0 panel0.dtbo
Panel 1 panel1.dtbo
Panel 2 panel2.dtbo
Panel 3 panel3.dtbo
Panel 4 panel4.dtbo ★ padrao
Panel 4-V22 panel4-v22.dtbo
Panel 5 panel5.dtbo
R46H (1024x768) r46h.dtbo

R36S Clone (12 paineis)

Nome DTBO Padrao
Clone 1 (ST7703) clone_panel_1.dtbo
Clone 2 (ST7703) clone_panel_2.dtbo
Clone 3 (NV3051D) clone_panel_3.dtbo
Clone 4 (NV3051D) clone_panel_4.dtbo
Clone 5 (ST7703) clone_panel_5.dtbo
Clone 6 (NV3051D) clone_panel_6.dtbo
Clone 7 (JD9365DA) clone_panel_7.dtbo
Clone 8 G80CA (ST7703) clone_panel_8.dtbo ★ padrao
Clone 9 (NV3051D) clone_panel_9.dtbo
Clone 10 (ST7703) clone_panel_10.dtbo
R36 Max (ST7703 720x720) r36_max.dtbo
RX6S (NV3051D) rx6s.dtbo

Fluxo: Aba Flash

Passo a passo

  1. App inicia e busca a ultima release ArchR-R36S-no-panel-*.img.xz no GitHub Releases
  2. Imagem local ou download: se ja tem uma imagem local, usa ela. Senao, oferece download
  3. Selecionar console: R36S Original ou R36S Clone (dois botoes grandes)
  4. Selecionar painel: dropdown muda conforme o console selecionado
  5. Selecionar destino: lista de discos removiveis (SD cards)
  6. Gravar: confirmacao ("Todos os dados do SD serao apagados"), barra de progresso
  7. Pos-gravacao: injeta overlay + variant no BOOT (FAT32)
  8. Concluido: "SD card pronto! Insira no R36S e ligue."

Etapa 1: Gravar imagem raw

imagem.img.xz  →  descompacta on-the-fly  →  dd no block device
  • Descompressao streaming (xz -> raw -> disco) para nao precisar de espaco extra
  • Gravacao em blocos de 4MB (bs=4M)
  • Barra de progresso baseada no tamanho descomprimido

Etapa 2: Pos-gravacao (injetar configuracao)

Apos gravar a imagem raw, a particao BOOT (FAT32, particao 1) ja existe no SD. O Flasher:

  1. Abre a particao FAT32 diretamente no block device (sem montar no OS)

    • Usa crate fatfs em Rust para ler/escrever FAT32 via offset no disco
    • Offset da particao 1: lido da tabela de particoes (GPT ou MBR)
  2. Copia o DTBO do painel selecionado como overlays/mipi-panel.dtbo:

    • Le o DTBO da pasta overlays/ que ja esta na imagem (ex: overlays/panel3.dtbo)
    • Copia como overlays/mipi-panel.dtbo
    • Boot.ini vai aplicar esse overlay no proximo boot
  3. Escreve panel-confirmed: conteudo "confirmed\n" (wizard nao roda)

  4. Escreve variant: "original\n" ou "clone\n"

    • Arquivo na particao BOOT (FAT32)
    • Systemd service no primeiro boot copia para /etc/archr/variant
  5. Sync e fecha (fsync obrigatorio em FAT32!)

Diagrama

SD Card (pos-gravacao):

Offset 0          32KB           128MB                    ~3.2GB
├─── U-Boot ──────┤── BOOT (FAT32) ──┤──── STORAGE (ext4) ───┤
                  │                   │
                  ├── KERNEL          │
                  ├── boot.ini        │
                  ├── dtbs/           │  13 board DTBs (auto-select)
                  │   ├── rk3326-gameconsole-r36s.dtb
                  │   ├── rk3326-gameconsole-r36max.dtb
                  │   └── ... (13 total)
                  ├── overlays/       │
                  │   ├── mipi-panel.dtbo  ◄── escrito pelo Flasher
                  │   ├── panel0.dtbo
                  │   ├── panel4.dtbo
                  │   ├── clone_panel_8.dtbo
                  │   └── ... (20 total)
                  ├── panel-confirmed ◄── escrito pelo Flasher
                  └── variant         ◄── escrito pelo Flasher

Fluxo: Aba Overlay

Permite trocar o painel de um SD card Arch R sem re-gravar a imagem. Util quando o usuario troca de aparelho ou recebe um com painel diferente.

Passo a passo

  1. Inserir SD card com Arch R ja gravado
  2. Selecionar SD: app detecta que tem Arch R (verifica presenca de KERNEL e dtbs/)
  3. Detectar estado atual: le overlays/mipi-panel.dtbo e compara com os DTBOs conhecidos
  4. Selecionar novo painel: dropdown (mesmo que na aba Flash)
  5. Ajustes opcionais (inspirado no ROCKNIX overlay_server):
    • Rotacao do display (0/90/180/270)
    • Inversao de sticks analogicos (esquerdo/direito)
    • Modo de audio (auto/amplificado/simples)
    • Inversao da deteccao de headphone
  6. Aplicar: copia DTBO selecionado para overlays/mipi-panel.dtbo + fsync
  7. Concluido: "Overlay aplicado!"

Deteccao do overlay atual

Para mostrar qual painel esta ativo, o Flasher:

  1. Le overlays/mipi-panel.dtbo do SD card
  2. Calcula hash (MD5/SHA256)
  3. Compara com hashes dos 20 DTBOs conhecidos (embutidos no app)
  4. Se match: mostra nome do painel
  5. Se nao match: "Overlay personalizado" (pode ter sido gerado pelo overlay_server)

Ajustes de painel (inspirado ROCKNIX overlay_server)

O overlay_server do ROCKNIX gera overlays a partir de DTBs de estoque, suportando modificacoes como rotacao, inversao de sticks, e audio routing. O Flasher integra essas opcoes diretamente:

Ajuste Flags Descricao
Rotacao DR0, DR90, DR180, DR270 Rotacao do display (0-270 graus)
Inversao stick esquerdo LSi Inverte eixos X/Y do stick esquerdo
Inversao stick direito RSi Inverte eixos RX/RY do stick direito
Audio amplificado SRa Usa amplificador externo (rk817-sound-amplified)
Audio simples SRs Roteamento direto SPK/HP (rk817-sound-simple)
Inversao HP detect HPi Inverte polaridade da deteccao de headphone

Quando o usuario seleciona ajustes, o Flasher modifica o DTBO em memoria antes de gravar no SD card:

  1. Le o DTBO base do painel selecionado
  2. Aplica as modificacoes (altera propriedades no FDT)
  3. Grava o DTBO modificado como overlays/mipi-panel.dtbo

Isso e feito puramente em Rust usando a crate fdt para manipulacao binaria do DTB.


Deteccao de Imagem

Fonte: GitHub Releases

GET https://api.github.com/repos/archr-linux/Arch-R/releases/latest

Procura por asset com nome ArchR-R36S-no-panel-*.img.xz.

Cache local

  • Imagens baixadas ficam em:
    • Windows: %APPDATA%\ArchR-Flasher\images\
    • macOS: ~/Library/Application Support/ArchR-Flasher/images/
    • Linux: ~/.local/share/archr-flasher/images/
  • Se ja tem a versao mais recente localmente, nao baixa de novo
  • Botao "Selecionar arquivo local" para imagens baixadas manualmente

Deteccao de Discos

Linux

// Listar /sys/block/sd* e /sys/block/mmcblk*
// Filtrar por removable=1
// Ler size, vendor, model

macOS

// diskutil list -plist
// Filtrar por removable=true, protocol=USB ou SD

Windows

// WMI: Win32_DiskDrive WHERE MediaType='Removable Media'
// Ou: SetupDiGetClassDevs + DeviceIoControl

Protecoes

  • Nunca listar discos fixos (HDD/SSD do sistema)
  • Filtro de tamanho: ignorar discos > 128GB (provavelmente nao e SD card do R36S)
  • Confirmacao com nome do disco: "Gravar em SANDISK 32GB (/dev/sdc)? TODOS OS DADOS SERAO APAGADOS."
  • Bloquear disco do sistema: nunca permitir gravar no disco onde o OS esta rodando

Validacao de SD Arch R (aba Overlay)

Para a aba Overlay, o Flasher precisa verificar que o SD card ja tem Arch R:

  1. Montar (ou ler via fatfs) a particao 1
  2. Verificar presenca de: KERNEL, dtbs/, overlays/, boot.ini
  3. Se presente: SD valido, mostrar overlay atual
  4. Se ausente: "Este SD card nao contem Arch R"

Permissoes de Disco

Linux

  • Precisa de root para gravar em block device
  • Usar pkexec para elevar privilegios (sem terminal)
  • Aba Overlay: tambem precisa de pkexec para escrever no SD

macOS

  • diskutil unmountDisk /dev/diskN antes de gravar
  • Precisa de permissao de admin (Authorization Services)

Windows

  • Precisa de admin para abrir \\.\PhysicalDriveN
  • UAC prompt automatico via manifesto do executavel

Estrutura do Projeto

archr-flasher/
├── src-tauri/
│   ├── src/
│   │   ├── main.rs              # Entry point Tauri
│   │   ├── disk.rs              # Deteccao e listagem de discos
│   │   ├── flash.rs             # Gravacao raw + descompressao xz
│   │   ├── overlay.rs           # Leitura/escrita de overlays no SD
│   │   ├── fat32.rs             # Leitura/escrita FAT32 direta
│   │   ├── github.rs            # Download de releases
│   │   ├── panels.rs            # Definicao dos paineis + hashes DTBOs
│   │   └── dtb_modify.rs        # Modificacao binaria de DTBOs (rotacao, sticks, audio)
│   ├── Cargo.toml
│   └── tauri.conf.json
├── src/
│   ├── index.html               # UI principal (2 abas: Flash + Overlay)
│   ├── style.css                # Estilo (tema escuro, cores Arch R)
│   └── main.js                  # Logica de UI
├── assets/
│   ├── icon.png                 # Icone do app (logo Arch R)
│   └── i18n/                    # Traducoes
│       ├── en.json
│       └── pt-BR.json
└── README.md

Dependencias Rust (Cargo.toml)

[dependencies]
tauri = { version = "2", features = ["shell-open"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
reqwest = { version = "0.12", features = ["json", "stream"] }
tokio = { version = "1", features = ["full"] }
xz2 = "0.1"                    # Descompressao .xz streaming
fatfs = "0.4"                   # Leitura/escrita FAT32 sem montar
gpt = "3"                       # Leitura de tabela de particoes GPT
byteorder = "1"                 # Leitura MBR
fdt = "0.1"                     # Manipulacao binaria de DTB/DTBO
md-5 = "0.10"                   # Hash para identificar overlay atual

UI: Tema Visual

  • Fundo: preto (#0a0a0a)
  • Destaque: azul Arch (#1793D1)
  • Texto: branco (#f0f0f0)
  • Botoes: azul Arch com hover mais claro
  • Progresso: barra azul gradiente
  • Logo: "ARCH R" no topo (mesma fonte Quantico do splash)
  • Abas: Flash e Overlay (tab bar no topo)
  • Ajustes: secao colapsavel na aba Overlay (expandir para ver opcoes avancadas)

Internacionalizacao (i18n)

O Flasher deve ser multilinguagem. O idioma e detectado automaticamente pelo OS, com fallback para ingles.

Idiomas

Codigo Idioma Status
en English Base (fallback)
pt-BR Portugues (Brasil) Prioritario
es Espanol Futuro
zh Chinese Futuro

Implementacao

Arquivo JSON por idioma em assets/i18n/.

Exemplo en.json:

{
  "title": "ARCH R FLASHER",
  "tab_flash": "Flash",
  "tab_overlay": "Overlay",
  "image": "Image",
  "no_image": "No image selected",
  "select_file": "Select file",
  "download_latest": "Download latest version",
  "console": "Console",
  "panel": "Panel",
  "select_panel": "Select panel",
  "destination": "Destination",
  "select_sd": "Select SD card",
  "no_sd": "No SD card found",
  "refresh": "Refresh list",
  "flash": "FLASH",
  "confirm_title": "Confirm flash",
  "confirm_text": "Flash Arch R to {disk}?",
  "confirm_warning": "ALL DATA ON THE SD CARD WILL BE ERASED!",
  "cancel": "Cancel",
  "writing": "Writing image...",
  "syncing": "Syncing...",
  "configuring": "Applying panel overlay...",
  "done": "SD card ready! Insert in R36S and power on.",
  "recommended": "recommended",
  "overlay_current": "Current overlay",
  "overlay_new": "New panel",
  "overlay_custom": "Custom overlay",
  "overlay_apply": "APPLY OVERLAY",
  "overlay_done": "Overlay applied! Insert SD and reboot.",
  "overlay_not_archr": "This SD card does not contain Arch R.",
  "adjustments": "Adjustments (optional)",
  "rotation": "Rotation",
  "stick_inversion": "Stick inversion",
  "stick_left": "Left",
  "stick_right": "Right",
  "audio_mode": "Audio mode",
  "audio_auto": "Auto",
  "audio_amplified": "Amplified",
  "audio_simple": "Simple",
  "hp_inversion": "Invert HP detection"
}

Deteccao de idioma

  1. Tauri detecta o locale do OS via sys_locale crate
  2. Frontend recebe o locale via comando Tauri
  3. Carrega o JSON correspondente (ou en.json como fallback)
  4. Todas as strings da UI vem do arquivo de traducao

Build e Release

Compilacao

# Requisitos: Rust, Node.js (para Tauri CLI)
cargo install tauri-cli

# Dev
cargo tauri dev

# Build release (gera instalador por plataforma)
cargo tauri build

CI/CD (GitHub Actions)

# .github/workflows/flasher-release.yml
# Matrix: ubuntu-latest, macos-latest, windows-latest
# Cada um gera: .AppImage/.deb, .dmg, .msi
# Upload como assets na release do Flasher

Distribuicao

Plataforma Formato Tamanho estimado
Linux .AppImage + .deb ~8MB
macOS .dmg ~10MB
Windows .msi ~8MB

Primeiro Boot (pos-Flasher)

O SD gravado pelo Flasher ja tem tudo configurado:

  1. Boot.ini seleciona board DTB correto via hwrev (automatico)
  2. Boot.ini aplica overlays/mipi-panel.dtbo (painel selecionado pelo Flasher)
  3. Display funciona desde o primeiro boot
  4. variant na particao BOOT = "original" ou "clone"
  5. panel-confirmed presente = wizard nao roda
  6. Systemd service le variant do BOOT e copia para /etc/archr/variant
  7. EmulationStation inicia normalmente

Zero configuracao no device. Liga e usa.

Systemd: Variant Sync Service

Service no rootfs para copiar variant do BOOT:

# /etc/systemd/system/archr-variant-sync.service
[Unit]
Description=Sync variant from BOOT partition
After=local-fs.target
RequiresMountsFor=/boot
ConditionPathExists=!/etc/archr/variant

[Service]
Type=oneshot
ExecStart=/bin/sh -c 'test -f /boot/variant && cp /boot/variant /etc/archr/variant'
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

Roda apenas uma vez (ConditionPathExists). Apos copiar, nao roda mais.

Fases de Desenvolvimento

Fase 1: Core funcional

  • Projeto Tauri inicializado
  • UI basica com 2 abas (Flash + Overlay)
  • Selecao console + painel + disco
  • Gravacao de imagem local (.img, sem .xz)
  • Pos-gravacao: copiar DTBO + variant + panel-confirmed
  • Aba Overlay: trocar overlay sem re-flash
  • Testar em Linux

Fase 2: Polish

  • Descompressao .xz streaming
  • Download automatico do GitHub Releases
  • Cache de imagens
  • Deteccao de overlay atual (hash comparison)
  • Ajustes avancados (rotacao, sticks, audio)
  • Deteccao de discos (Linux + macOS + Windows)
  • Barra de progresso real

Fase 3: Release

  • CI/CD para 3 plataformas
  • Icone e branding
  • i18n (pt-BR + en)
  • Testes em hardware real (Original + Clone)
  • Publicar na pagina do projeto