Emulador de Memory Card sem fio para PlayStation 1 baseado no microcontrolador ESP32, com armazenamento em cartão MicroSD via barramento SPI, servidor web embarcado para gerenciamento remoto de saves, banco de dados global de títulos com cache dinâmico versionado e atualização de firmware over-the-air (Web OTA).
Desenvolvido por Schickacka, baseado na engenharia reversa do projeto OpenMC.
O OpenWirelessMC implementa a emulação completa do protocolo serial SIO do PlayStation 1 em tempo real, dividindo as operações de barramento e gerenciamento entre os dois núcleos do ESP32:
-
Núcleo 1 (Baremetal / SIO dedicado):
- Executa a máquina de estados do barramento SPI/SIO da Sony diretamente a partir da memória IRAM, sem sobrecarga de sistema operacional.
- Temporização de resposta ACK calibrada empiricamente para 84 iterações de espera no Core 1. Cada iteração inclui leitura de registrador e desvio, portanto o tempo em nanossegundos depende do código gerado; a referência teórica de 84 ciclos a 160 MHz (
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=160, valor real do build de 1.3) é de aproximadamente 525 ns, e não os 350 ns que uma versão anterior do README atribuía a 240 MHz. O valor é calibrado contra o console, não derivado de uma frequência teórica, e não deve ser alterado sem revalidar o Crash Bandicoot e os demais títulos sensíveis a timing. - Topologia de barramento com Push-Pull Ativo e Alta Impedância Dinâmica nas linhas
DATA(GPIO 32) eACK(GPIO 33): operam em acionamento ativo de 3.3V durante a seleção de periférico (ActiveMode) para transições de borda ultra-rápidas sem atraso de subida RC, e entram em alta impedância absoluta (Hi-Z) em modo inativo (PassiveMode), garantindo isolamento total contra contenção de barramento com controles, multitaps e periféricos conectados ao Slot 2. - Imagem ativa de 128 KB mantida em DRAM interna (
memory_card_ram), permitindo leitura e gravação com latência zero durante as transações do barramento do console. - Inicialização ultrarrápida do SIO (~1.75 s), ficando operacional aproximadamente 3.5 segundos antes do término da animação de boot da BIOS no PS1.
-
Núcleo 0 (FreeRTOS / Armazenamento e Rede):
- Mecanismo de Escrita In-Place por Setor: Gravação de alterações no MicroSD em modo
r+bcom deslocamento de ponteiro (fseek). Apenas os setores efetivamente modificados (128 bytes por setor) são gravados na mídia física, reduzindo expressivamente o desgaste das células flash do cartão SD e eliminando o risco de corrupção total da imagem em caso de desligamento abrupto do console. - Controle Atômico de Versão de Setores: Matriz estática de rastreamento (
sector_version[1024]) alocada em memória BSS, prevenindo perda de dados quando o console realiza gravações sucessivas e evitando fragmentação do heap. - Exclusão Mútua (
StorageLock): Mutex recursivo que sincroniza com segurança os acessos simultâneos entre o servidor HTTP, a rotina de detecção automática de GameID e a tarefa de persistência de disco. - Suporte Inteligente a Jogos Multi-Disco (Multi-Disc Parent Mapping): Mapeamento automático de 475 títulos com múltiplos discos através de uma tabela de pais compilada em flash (
src/storage/parent_db.cc, gerada portools/make_parent_db.pya partir desdcard_assets/multidisc.txt). Ao trocar para discos subsequentes (ex.: Disco 2 de Final Fantasy, Metal Gear Solid, Resident Evil 2, Policenauts), o sistema resolve o ID pai e monta o cartão deMemoryCards/PS1/<pasta>/<pasta>-<canal>.mcd, preservando o progresso contínuo sem gerar cartões vazios indesejados. O firmware não lê nenhum arquivo do SD para isso; umGame2Folder.iniem.sd2psx/permite renomear a pasta de um jogo. - Catálogo Global com Cache Versionado Dinâmico: Identificação de 23.465 títulos catalogados no MicroSD em
titles.db. O navegador cliente realiza o armazenamento local vialocalStorage, renderizando a biblioteca em menos de 5 ms sem tráfego de rede. O endpoint/api/statusvalida a versão do banco através do hashsize ^ mtimedo arquivo no SD (titles_version), atualizando o cache automaticamente em caso de modificação na mídia. Zero jogos comerciais hardcoded nos arquivos de firmware ou HTML. - Cartão Inicial Padronizado: O arquivo base
default.mcé identificado e exibido oficialmente como "Boot Card" na interface web. - Otimização Crítica de Memória DRAM: Dimensionamento dinâmico dos buffers de transmissão/recepção Wi-Fi e pilha TCP/IP LWIP, preservando ~45 KB de DRAM interna livre para prevenir qualquer risco de esgotamento de memória (OOM panic) durante acessos simultâneos de rede e disco.
- Servidor Web Embarcado: Interface acessível via navegador em
http://wirelessmc.local/(ou pelo endereço IP do dispositivo), com suporte a upload, download, renomeação, criação de novos cartões formatados, desmontagem/remontagem a quente (hot remount) e atualização de firmware over-the-air (Web OTA) com verificação de cabeçalho de integridade.
- Mecanismo de Escrita In-Place por Setor: Gravação de alterações no MicroSD em modo
Para desenvolvedores, engenheiros de firmware e analistas de código, esta seção detalha minuciosamente todas as divergências técnicas entre a implementação original do OpenMC (upstream) e as inovações introduzidas no OpenWirelessMC, explicando as motivações de projeto e os problemas de hardware resolvidos:
| Componente / Recurso | Projeto Original (OpenMC) | OpenWirelessMC (Nosso Projeto) | Motivação Técnica / Benefício |
|---|---|---|---|
| Topologia de Barramento (MISO / ACK) | Open-Drain estático ou acionamento genérico | Push-Pull Ativo (3.3V) + Hi-Z Dinâmico | Pull-ups fracos (~10kΩ) no PS1 causam rampa RC lenta em Open-Drain, corrompendo leituras rápidas (Crash Bandicoot falhava com "Card is not Formatted"). Push-Pull com Hi-Z garante bordas de subida <10 ns sem contenção de barramento. |
| Isolamento de Núcleos (Core 1 vs Core 0) | Execução concorrente com concorrência de memória | Core 1 Baremetal com Core 0 Stall estendido | O Core 0 é paralisado por registrador (core0_stall_start) durante todo o frame SPI e só é liberado após o retorno de SEL para HIGH, evitando jitter de cache/RAM causado por Wi-Fi ou SD. |
| Persistência de Saves no MicroSD | Reescrita destrutiva do arquivo inteiro (fopen("wb")) |
Gravação In-Place Cirúrgica por Setor (r+b / fseek) |
Sobrescrever 128 KB truncava o arquivo para 0 bytes, corrompendo saves em desligamentos acidentais e levando ~400 ms. A escrita in-place grava apenas 128 bytes em ~5 ms sem risco de perda. |
| Versionamento de Setores Modificados | Ausente ou buffer dinâmico no heap | Matriz Estática sector_version[1024] em BSS |
Rastreamento atômico setor a setor. Se o console salvar repetidamente enquanto o SD grava em segundo plano, as versões não são perdidas e não há fragmentação de memória heap. |
| Troca Automática de Saves por Jogo (GameID) | Inexistente (troca exclusivamente manual via web) | Protocolo MemCard PRO / PicoStation (0x21) |
Detecta transmissões de ID de jogos emitidas por xStation, Unirom e Tonyhax, comutando automaticamente para MemoryCards/PS1/<pasta>/<pasta>-1.mcd com barreira multicore (__sync_synchronize). |
| Jogos Multi-Disco | Criação de cartões vazios independentes por disco | Tabela de pais compilada + .sd2psx/Game2Folder.ini |
Mapeamento de 475 títulos (FF7, MGS, RE2, etc.) redirecionando discos 2, 3 e 4 para a pasta do jogo em MemoryCards/PS1/<pasta>/, mantendo o progresso unificado; o override exato permite separar um disco quando desejado. |
| Criação de Cartões Novos Formatados | Preenchimento com bytes nulos ou 0xFF |
Template Autêntico Sony de Fábrica (sd2psX) | Bloco 0 gerado a partir do padrão autêntico Sony com blocos 1–15 em 0xFF. O PS1 e a BIOS reconhecem o cartão imediatamente como formatado sem exigir formatação manual. |
| Catálogo de Jogos da Interface Web | Títulos hardcoded em C/HTML ou ausentes | Banco titles.db + Cache em localStorage |
23.465 títulos catalogados no SD com sincronização delta via hash atômico (titles_version), renderização em <5 ms e zero títulos comerciais fixos no firmware. |
| Consumo de Memória DRAM do ESP32 | Padrão do SDK (~10-15 KB livres, risco de OOM) | Ajuste Fino de Buffers Wi-Fi/LWIP (~45 KB livres) | Buffers estáticos/dinâmicos de rede reduzidos mantendo vazão máxima, eliminando travamentos (OOM panic) durante salvamentos pesados simultâneos ao acesso web. |
| Segurança na Atualização Web OTA | Gravação direta sem validação de cabeçalho | Validação Prévia do Descritor de Partição | Apenas imagens com cabeçalho ESP-IDF válido para o projeto openmc são gravadas na partição flash de boot, prevenindo "bricking" por uploads acidentais. |
| Fluxo de Leitura SIO sem Perda de ACK | Abortos bruscos em setores além de 1024 | Manutenção Rigorosa de ACK e Tolerância de Limite | Evita desconexão de barramento se o software da Sony sondar setores superiores durante a rotina de verificação de formatação. |
- O Problema de Hardware no PS1: No PlayStation 1, a linha
DATA(MISO) é compartilhada com o Slot 2 e os controles, possuindo um resistor de pull-up passivo fraco de aproximadamente 10 kΩ na placa-mãe. Quando configurado em modo Open-Drain puro (GPIO_MODE_INPUT_OUTPUT_OD), o ESP32 atua apenas aterrando a linha para o nível lógico0; para o nível lógico1, o microcontrolador fica em alta impedância e depende exclusivamente do resistor de pull-up do console para elevar a tensão a 3.3V. Devido à capacitância combinada dos cabos, conectores e pinos do ESP32, a constante de tempo RC de subida fica muito lenta. - O Impacto no Crash Bandicoot e Jogos Exigentes: Jogos que utilizam a biblioteca oficial da Sony em velocidade máxima (250 kHz contínuos) realizam a leitura de cada bit de dados em instantes precisos. Com Open-Drain, os bits
1não atingiam a tensão limiar antes do console amostrar o sinal, sendo interpretados como0. Isso corrompia o checksum do setor 0 do diretório, fazendo o jogo exibir "Checking Format" seguido de "Card is not Formatted". - A Solução Adotada: Empregamos acionamento ativo Push-Pull (3.3V com tempos de subida de nanossegundos) através da chamada
ActiveMode()enquanto o pinoSELestiver em nível baixo, garantindo pulsos digitais perfeitamente quadrados. No instante em que o periférico é desmarcado, a chamadaPassiveMode()desabilita imediatamente o driver de saída no registradorGPIO_ENABLE1_W1TC_REG, colocando as linhas em alta impedância (Hi-Z) e eliminando qualquer risco de contenção elétrica no barramento compartilhado.
- O Problema de Jitter no ESP32: O ESP32 possui memória cache compartilhada e barramento de dados interno compartilhado entre os dois núcleos. Tarefas do FreeRTOS executando operações de rede Wi-Fi ou leitura no cartão MicroSD geram acessos constantes à memória flash e ao barramento APB.
- A Solução Adotada: O Core 1 foi configurado para executar código baremetal diretamente a partir da IRAM. No tratador de interrupção em nível de registrador da linha
SEL, o Core 0 é pausado via hardware através da rotinacore0_stall_start(). Essa pausa é mantida durante todo o tráfego SPI e estendida até que a linhaSELretorne comprovadamente para nível alto (ConfirmUnselected()) e os registradores de interrupção APB sejam esvaziados. Somente então o Core 0 é retomado (core0_stall_end()), impedindo colisões de temporização e perda de pulsos de ACK.
- O Perigo do Projeto Original: O OpenMC tradicional tratava o salvamento abrindo o arquivo
.mcde 128 KB com a flag"wb". No sistema de arquivos FAT32,"wb"trunca o tamanho do arquivo para 0 bytes antes de começar a gravar os dados. Caso o usuário desligasse o console ou ocorresse queda de energia nos 300 ms a 500 ms seguintes, o save era destruído de forma irrecuperável. - A Solução Adotada: O OpenWirelessMC opera exclusivamente com abertura em modo de atualização binária (
"r+b"). Quando o console grava um setor de 128 bytes, o ponteiro de arquivo é posicionado cirurgicamente comfseek(f, sector * 128, SEEK_SET)e apenas os 128 bytes modificados são transferidos para o MicroSD. Isso reduz o tempo de persistência para ~5 ms, diminui o desgaste da mídia flash e torna os saves imunes a perdas catastróficas.
- Prevenção de Perda por Gravação Concorrente: Jogos como Gran Turismo ou Tomb Raider realizam múltiplos acessos de gravação em setores sucessivos em curtos intervalos de tempo. O OpenWirelessMC implementa uma matriz estática
uint16_t sector_version[1024]alocada na seção BSS da memória. Toda vez que o Core 1 processa uma gravação na DRAM, o contador do respectivo setor é incrementado. A tarefa de persistência no Core 0 compara essa versão comsaved_version[1024]. Se o console realizar uma nova gravação no mesmo setor enquanto a tarefa de armazenamento ainda está persistindo no disco, o setor permanece marcado como pendente e é regravado na iteração seguinte, sem perdas.
- Automação de Cartões por Título: O OpenWirelessMC suporta o protocolo de transmissão serial de GameID criado pela comunidade (MemCard PRO / PS1Digital / PicoStation no comando
0x21). - Sincronização Segura: O Core 1 intercepta os caracteres do GameID (ex.:
SCUS-94900para Crash Bandicoot), insere a terminação nula e executa uma barreira de memória de hardware (__sync_synchronize()). O Core 0 recebe o evento, resolve a pasta (ID pai, se houver, mais o override deGame2Folder.ini) e comuta o arquivo montado automaticamente paraMemoryCards/PS1/<pasta>/<pasta>-1.mcd. Se o arquivo ainda não existir, o sistema cria a pasta e o cartão em tempo real a partir do template pré-formatado da Sony.
- Continuidade Transparente: Em jogos clássicos divididos em múltiplos CDs (como Final Fantasy VIII, Metal Gear Solid, Resident Evil 2, Chrono Cross), cada disco possui um GameID diferente. Sem mapeamento, o jogador ao inserir o Disco 2 encontrava um cartão vazio e não conseguia carregar o save do Disco 1.
- A Solução Adotada: As 475 associações filho→pai estão compiladas no firmware (
src/storage/parent_db.cc, 356 pastas de jogo) e são consultadas por busca binária no Core 0. Ao detectar o ID do Disco 2 (ex.:SCUS-94164), o sistema resolve o ID pai do Disco 1 (SCUS-94163) e montaMemoryCards/PS1/SCUS-94163/SCUS-94163-<canal>.mcd, permitindo troca de discos transparente e salvamento contínuo. - Overrides (
Game2Folder.ini): o arquivo.sd2psx/Game2Folder.ini, seção[PS1], permite apontar um GameID para outra pasta (SLUS-00592=RE2) ou separar um disco do cartão compartilhado. É o único arquivo de configuração de pastas que o firmware lê; omultidisc.txtque existia na raiz do SD nas versões anteriores não é mais consultado — se estiver presente, o/api/statusavisalegacy.detectede otools/migrate_sd.pycuida da limpeza.
- Formatação Instantânea: O Bloco 0 de um Memory Card do PS1 contém a tabela de alocação de blocos e assinaturas de diretório (
"MC", checksums e flags de estado). Gerar arquivos com bytes nulos obriga o jogador a abrir o BIOS do PlayStation para formatar o cartão. - A Solução Adotada: Incorporamos o template binário oficial de fábrica da Sony (derivado do projeto sd2psX). Todo novo cartão criado pelo OpenWirelessMC já nasce pré-formatado com a estrutura correta, sendo reconhecido no primeiro milissegundo pelo console sem qualquer solicitação de formatação.
- Performance e Escalabilidade: Nenhum nome de jogo comercial está embutido no código C++ ou nos arquivos HTML. Uma base completa de 23.465 títulos reside no arquivo
titles.dbno MicroSD. - Cache Inteligente: O navegador armazena os dados em
localStorage. Ao carregar a interface web, a tabela de jogos é exibida em menos de 5 ms. O endpoint/api/statusenvia o hash atômicotitles_version(tamanho ^ data_modificação). Se o arquivo físico no SD for atualizado pelo usuário, o navegador detecta a divergência e faz o download delta em segundo plano.
- Estabilidade Contra OOM Panic: No ESP-IDF original, os buffers padrão de recepção/transmissão Wi-Fi e os buffers de janela TCP da pilha LWIP consumiam praticamente toda a memória interna livre. Durante sessões em que o console gravava saves enquanto o usuário navegava na página web, o heap caía abaixo de 8 KB, disparando reinicializações por falta de memória (Out of Memory Panic).
- Ajuste Fino: Reconfiguramos os descritores de rede (
STATIC_RX_BUFFER_NUM=6,DYNAMIC_RX_BUFFER_NUM=16,DYNAMIC_TX_BUFFER_NUM=16, janela RX=4 e buffers TCP em4320bytes). Isso estabilizou a DRAM livre em confortáveis ~45 KB (com marca d'água mínima acima de 42 KB), garantindo imunidade absoluta contra reinicializações inesperadas.
- Proteção Contra Imagens Inválidas: O manipulador da rota
POST /api/otanão aceita gravações cegas. Antes de comutar a partição de boot ativa viaesp_ota_set_boot_partition(), o firmware lê o descritor da partição recém-gravada (esp_ota_get_partition_description()) e valida a estrutura de cabeçalho do ESP-IDF, o nome do projeto (openmc) e a integridade da imagem, eliminando o risco de corrupção ou travamento do dispositivo.
- PlayStation 1 (PS1 / PSOne): Compatibilidade total com todos os modelos e revisões de placa-mãe.
- PlayStation 2 (PS2): Compatível exclusivamente com jogos de PlayStation 1 executados no PS2 (o console reduz a frequência do barramento para o padrão do PS1 de ~250 kHz).
Nota técnica sobre jogos nativos de PS2: O OpenWirelessMC não suporta jogos nativos de PlayStation 2. O barramento de Memory Card nativo do PS2 opera a frequências de até 4 MHz, requer cartões de alta capacidade (mínimo de 8 MB, inviáveis na DRAM do ESP32) e exige autenticação criptográfica proprietária por hardware (MagicGate).
[ 9 7 6 ] [ 5 4 3 ] [ 2 1 ] (Porta do Console)
-----------------------------------------
| Pino PS1 | Sinal | Descrição | Pino ESP32 | Modo / Observação |
|---|---|---|---|---|
| 1 | DATA | Linha serial de dados (Memory Card -> Console) | GPIO 32 | Push-Pull Ativo (3.3V) / Hi-Z Dinâmico |
| 2 | CMND | Comandos seriais (Console -> Memory Card) | GPIO 34 | Entrada lógica direta (3.5V) |
| 4 | GND | Referência de terra comum | GND | Nível 0V de referência |
| 6 | ATT (SEL) | Seleção de periférico (ativo em nível baixo) | GPIO 35 | Entrada lógica direta (3.5V) |
| 7 | CLK | Clock de sincronismo serial (~250 kHz) | GPIO 39 (SENSOR_VN) | Entrada lógica direta (3.5V) |
| 8 (MC) / 9 (Pad) | ACK | Pulso de confirmação de recepção de byte | GPIO 33 | Push-Pull Ativo (3.3V) / Hi-Z Dinâmico |
Aviso de segurança: Não conecte os pinos 3 (7.6V) e 8 (N/C) da ranhura de Memory Card diretamente aos pinos de GPIO do ESP32.
| Pino MicroSD | Função SPI | Pino ESP32 |
|---|---|---|
| CS | Chip Select | GPIO 5 |
| SCK | Serial Clock | GPIO 18 |
| MOSI | Master Out Slave In | GPIO 23 |
| MISO | Master In Slave Out | GPIO 19 |
| VCC | Tensão de alimentação | 3.3V ou 5V (VIN) |
| GND | Referência de terra | GND |
A linha de 3.5V da ranhura de Memory Card do PS1 foi dimensionada pela Sony exclusivamente para pequenos chips EEPROM com consumo de 10 mA a 20 mA, sendo protegida por um microfusível de 0.7A (PS605). O microcontrolador ESP32 com o rádio Wi-Fi em transmissão atinge picos de consumo entre 300 mA e 450 mA. Alimentar o ESP32 a partir deste pino provoca quedas bruscas de tensão (brownout) e risco de queima do fusível da placa-mãe.
A porta de controles do PlayStation fornece 7.6V a 8.0V no Pino 3, linha dimensionada para alimentar os motores de vibração de controles DualShock (suporta até 1A contínuo através do fusível de potência PS603/PS604).
Recomenda-se a utilização de um conversor Step-Down chaveado (Buck Converter DC-DC, ex.: MP1584EN regulado para 5.0V):
Porta do Controle PS1 ESP32 DevKit
+---------------------------+ +---------------------+
| Pino 3 (7.6V Motores) |------> [ IN+ ] | |
| Pino 4 (GND Comum) |---+--> [ IN- ] | |
+---------------------------+ | | |
| REGULADOR STEP-DOWN| |
| (Ajustado em 5.0V) | |
| | |
| [ OUT+ (5V) ]--->| VIN (ou 5V) |
+--->[ OUT- (GND) ]-->| GND (Terra Comum) |
+---------------------+
- Regule o módulo Step-Down previamente para fornecer 5.0V estáveis na saída.
- Conecte a entrada
IN+do regulador ao Pino 3 da porta de controle. - Conecte o terra comum
IN-/OUT-ao GND da placa do console. - Conecte a saída
OUT+(5.0V) ao pino VIN do módulo ESP32.
- Formate o cartão MicroSD no sistema de arquivos FAT32.
- Copie dois arquivos da pasta
sdcard_assets/para a raiz do cartão:titles.db: Banco de dados global de identificação de títulos (23.465 entradas), usado pela interface web.config.txt: Parâmetros de rede Wi-Fi (veja §6.1).
- Ligue o aparelho. O firmware cria sozinho a árvore de cartões:
/sdcard/
├── config.txt
├── titles.db
├── .sd2psx/ # opcional
│ └── Game2Folder.ini # overrides de pasta (seção [PS1])
└── MemoryCards/
└── PS1/
├── BOOT/
│ └── BootCard-1.mcd # cartão montado no boot (criado automaticamente)
├── UserCards/
│ └── UserCards-1.mcd # cartões criados com nome livre
└── SLUS-00421/ # uma pasta por jogo
├── SLUS-00421-1.mcd # canal 1
└── SLUS-00421.ini # rótulos dos canais ([ChannelName])
- Pasta = jogo. O nome da pasta é o GameID resolvido (o ID pai, no caso de jogo multi-disco); o número é o canal de cartão (1..8 por padrão), não o número do disco. Discos 1, 2 e 3 de um mesmo jogo compartilham a mesma pasta.
- Vindo da v1.4: não copie nada à mão. Rode
tools/migrate_sd.pyno PC (veja §6.2); ele movedefault.mc, os cartões<GameID>-<n>.mce omultidisc.txt/Game2Folder.inida raiz para o layout acima, sem apagar nada. Odefault.mcnão é usado na raiz: na 1.5 o cartão de boot é criado pelo firmware e odefault.mcsó serve de semente para a migração.
# OpenWirelessMC - Parametros de Rede
# Modos validos: client, ap, none
mode=client
ssid=NomeDaSuaRede
password=SuaSenhaWPA2Se o modo configurado for client e o roteador estiver inacessível, o sistema ativa automaticamente um Ponto de Acesso temporário de recuperação (Rescue AP: SSID: WirelessMC / Senha: SenhaDificil!) em memória RAM, sem sobrescrever o arquivo de configurações salvo no cartão.
python tools/migrate_sd.py --root "X:\" --backup "%USERPROFILE%\owmc-backup" # dry-run
python tools/migrate_sd.py --root "X:\" --apply --yes
python tools/migrate_sd.py --root "X:\" --verifyCom o aparelho ligado na rede, troque --root "X:\" por --root http://<ip>
(migração por Wi-Fi, sem tirar o cartão). Enquanto o SD estiver no layout
antigo, /api/status responde "legacy":{"detected":true}.
O projeto utiliza o ecossistema PlatformIO integrado ao framework ESP-IDF:
# Compilacao do firmware
pio run
# Gravacao direta via porta serial
pio run --target uploadOs binários pré-compilados e scripts de gravação para Windows encontram-se na pasta releases/v1.5_package/:
- Conecte o ESP32 ao computador via cabo USB.
- Execute o script automatizado:
cd releases\v1.5_package flash_windows.bat - Informe a porta COM correspondente ao dispositivo. O script executará a gravação completa (
bootloader.bin,partitions.bin,ota_data_initial.binefirmware_v1.5.bin).
Caso prefira gravar manualmente via terminal:
python -m esptool --chip esp32 --port COMx --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size 4MB 0x1000 bootloader.bin 0x8000 partitions.bin 0xd000 ota_data_initial.bin 0x10000 firmware_v1.5.binCom o dispositivo conectado à rede local, atualizações podem ser realizadas diretamente através da interface web (http://wirelessmc.local/) na seção Atualização de Firmware (Web OTA):
- Selecione o arquivo
firmware_v1.5.bingerado ou obtido emreleases/. - Clique em Atualizar Firmware.
- O servidor validará a integridade do cabeçalho da imagem antes de comutar a partição de boot e reiniciará o microcontrolador automaticamente.
Para consultar o histórico detalhado de alterações de cada versão, consulte o arquivo CHANGELOG.md.
- v1.5.2 (Atual): Troca a quente de Memory Cards com settle delay de 2500 ms (a BIOS do PS1 detecta a desconexão e relê o diretório sem sair da tela) e higienização visual automática de títulos multi-disco (Chrono Cross, Driver 2, Final Fantasy VII, etc., sem marcadores poluentes (Disc 1) na interface web).
- v1.5.1: Correções de integridade e de documentação sobre a 1.5.0: cartão de boot inválido passa a ser preservado como
BootCard-1.mcd.invalidem vez de sobrescrito;/api/renameexige nome simples e a mesma extensão do cartão;/api/card/namevalida pasta e canal; a allowlist de/api/fs/*deixa de aceitar*.mcd/*.ini/*.bakfora deMemoryCards/PS1,.sd2psxegames;/api/fs/deletesó remove pasta quando não há Memory Card dentro (os rótulos[ChannelName]vão junto; raízes como.sd2psxsó saem vazias); o upload de/api/fs/putnão segura mais oStorageLockdurante o recebimento;/api/statusconta os cartões emMemoryCards/PS1e a versão vem do app descriptor; cartões criados com nome livre voltam paraUserCardscom o nome em[ChannelName]. Documentação reescrita (475 pares compilados, layoutMemoryCards/PS1, atualização da 1.4 pelomigrate_sd.py). - v1.5.0: Nova arquitetura de navegação centrada em
/MemoryCards/PS1/, duplicação de cartões com incremento automático de canal (POST /api/card/duplicate), renomeação segura de saves com checagem de colisão e proteção de cartão ativo (POST /api/rename), ordenação natural e alfanumérica de títulos sem poluição por tags de região, contadores de cartões por subpasta, filtro dinâmico de pastas (Todas / Com Saves / Vazias), exclusão assíncrona AJAX com notificação toast e decodificação percentual de URIs (Percent-Decode), padronização visual dos botões de ação e expansão de capacidade da pilha do servidor web. - v1.4.0: Realinhamento do layout GameID
0x21(tick 2 comprimento, tick 3+ caracteres), streaming contínuo no FastRead0x42até desasserção de SEL, recuperação automática e validação estrita de integridade paradefault.mc(com regeneração do asset Sony com checksum0x0E), liberação de barramento SPI em falhas de montagem e unmount, restauração do flag0x08("diretório não lido") após escrita no setor 0, buffer SSID expandido para 32 caracteres completos, stubs de teste host atualizados e sincronização de XTAL para 40 MHz. - v1.3.0: Restauração do acionamento Push-Pull ativo forte nos pinos MISO (DATA) e ACK com alta impedância dinâmica (Hi-Z) em modo passivo (solução definitiva para Crash Bandicoot e jogos com leitura rápida de diretório), remoção de cortes de ACK intempestivos em limites de setor, posicionamento correto de
core0_stall_endpós-desasserção de SEL, documentação comparativa completa contra o OpenMC original e atualização da Web UI. - v1.2.0: Cache versionado dinâmico para
titles.db, zero títulos hardcoded no HTML, identificação dodefault.mccomoBoot Card, otimização crítica de DRAM (~45 KB livres), verificação de integridade no Web OTA e suporte estendido a jogos multi-disco (Policenauts, Resident Evil 3). - v1.1.0: Suporte a multi-disco via
multidisc.txt, desmontagem/remontagem a quente e estabilização de buffers. - v1.0.0: Lançamento inicial estável com escrita in-place por setor, SIO baremetal no Core 1 calibrado a 84 ciclos, servidor web e partição dual-OTA.
- OpenWirelessMC: Desenvolvido e mantido por Schickacka.
- Engenharia Reversa OpenMC: Baseado no trabalho original pioneiro de John Baumann, rama, sickle, Nicolas Noble e danhans42.
- Ecossistema MMCE / sd2psXtd: Referências de boas práticas e padronização baseadas no firmware sd2psXtd.
- Especificações do Protocolo SIO: Documentação de temporização e comportamento de registradores por nocash (psx-spx).
- Catalogação de Jogos: Base de dados derivada das coleções comunitárias do DuckStation e PCSX2. Todos os direitos e marcas comerciais são de propriedade de suas respectivas publicadoras.