Trabalhando com ROMFS¶
Visão geral¶
O ROMFS (Read-Only Memory Filesystem) é um sistema de arquivos leve e somente leitura projetado para dispositivos MicroPython. Ele é otimizado para microcontroladores e sistemas embarcados onde o código e os dados precisam ser armazenados na memória flash e acessados de forma eficiente sem serem copiados para a RAM.
Os principais benefícios do ROMFS são:
Importações zero-copy: arquivos de bytecode
.mpyarmazenados em um ROMFS podem ser executados diretamente da memória flash (mapeada em memória) em vez de serem copiados primeiro para a RAM. Isso é semelhante a como os módulos congelados funcionam, mas não requer reflashar todo o firmware.Baixo consumo de RAM: objetos constantes (strings, bytes, etc.) em arquivos
.mpycarregados a partir do ROMFS são referenciados diretamente da flash, não duplicados na RAM.Implantação flexível: uma imagem ROMFS pode ser construída em um PC host e implantada no dispositivo usando o mpremote, sem reconstruir o firmware.
Interface de sistema de arquivos padrão: um ROMFS é montado no VFS e acessado por meio de operações normais de arquivo do Python (
open,os.listdir,import, etc.).
O ROMFS é complementar tanto aos sistemas de arquivos de leitura e escrita FAT/LittleFS (que residem em outras partições da flash) quanto aos módulos congelados (que são compilados no próprio firmware).
Suporte de placas¶
O ROMFS está habilitado no firmware da OpenMV em todas as placas de câmera que possuem uma partição ROMFS reservada em seu layout de flash. Nessas placas, a partição ROMFS é detectada automaticamente na inicialização e montada em /rom; tanto /rom quanto /rom/lib são adicionados ao sys.path para que os módulos armazenados ali possam ser importados diretamente.
Placa |
Suporte a ROMFS |
|---|---|
OpenMV Cam N6 |
Sim |
OpenMV AE3 |
Sim |
OpenMV Cam RT1062 |
Sim |
OpenMV Cam Pure Thermal |
Sim |
OpenMV Cam M4 / M7 / H7 / H7 Plus |
Sim |
Arduino Giga |
Sim |
Arduino Portenta H7 |
Sim |
Arduino Nicla Vision |
Sim |
Arduino Nano 33 BLE Sense |
Não (sem partição ROMFS) |
Arduino Nano RP2040 Connect |
Não (sem partição ROMFS) |
Consulte romfs para obter um auxiliar específico da OpenMV que inspeciona o ROMFS montado em /rom.
Fluxo de trabalho¶
O fluxo de trabalho típico para usar o ROMFS é:
Crie um diretório no seu PC com os arquivos Python (ou arquivos
.mpy) que você deseja implantar.Use
mpremote romfs deploy <directory>para construir e implantar a imagem ROMFS no dispositivo.O ROMFS será montado em
/romna próxima inicialização (ou pode ser montado imediatamente se o dispositivo for reinicializado).O código Python no dispositivo pode então
importmódulos do ROMFS exatamente como de qualquer outro sistema de arquivos.
Por exemplo:
# On the host PC, with a directory "myapp/" containing app.py:
$ mpremote romfs deploy myapp/
Após um soft-reset, o dispositivo terá /rom/app.py (ou /rom/app.mpy se o mpy_cross estiver instalado) disponível para importação.
Consulte a seção sub-comandos mpremote romfs abaixo para obter detalhes completos dos sub-comandos do mpremote.
API Python¶
A API Python do ROMFS é fornecida por meio do módulo vfs.
- class vfs.VfsRom(buffer)
Cria um objeto de sistema de arquivos ROMFS a partir de buffer, que deve ser um objeto que suporte o protocolo de buffer (por exemplo, um objeto
bytes,bytearrayoumemoryview) que contenha uma imagem ROMFS válida.O construtor valida que buffer começa com os bytes mágicos do ROMFS (
b"\xd2\xcd\x31"). Se o buffer for muito pequeno ou não for um ROMFS válido, entãoOSError(ENODEV)é levantado.Objetos criados por este construtor podem ser montados usando
vfs.mount().Exemplo:
import vfs # Load a ROMFS image from flash into a memoryview. dev = vfs.rom_ioctl(2, 0) # get partition 0 as a memoryview fs = vfs.VfsRom(dev) vfs.mount(fs, '/rom')
Ou, para montar uma imagem ROMFS armazenada em um arquivo:
import vfs with open('/flash/app.romfs', 'rb') as f: romfs_data = f.read() fs = vfs.VfsRom(romfs_data) vfs.mount(fs, '/rom2')
Os seguintes métodos estão disponíveis em um objeto
VfsRom:- VfsRom.open(path, mode)
Abre um arquivo do ROMFS. Apenas os modos de leitura (
'','r','rt','rb') são suportados. Tentar abrir um arquivo para escrita levantaráOSError(EROFS).O objeto de arquivo retornado suporta
read(),seek(),tell()eclose(). Para arquivos binários abertos em modo de leitura, o objeto retornado também suporta o protocolo de buffer, de modo que umamemoryviewdos dados do arquivo pode ser obtida, referenciando diretamente a memória do ROMFS (zero-copy).
- VfsRom.ilistdir(path)
Retorna um iterador sobre as entradas no diretório path. Cada entrada é uma tupla
(name, type, inode, size)onde type é0x8000para um arquivo ou0x4000para um diretório.
- VfsRom.stat(path)
Retorna uma tupla de 10 elementos no estilo
os.statpara path. LevantaOSError(ENOENT)se o caminho não existir.
- VfsRom.statvfs(path)
Retorna estatísticas do sistema de arquivos. O tamanho do bloco é reportado como 1 e a contagem de blocos representa o tamanho total da imagem ROMFS em bytes. Os blocos livres e os arquivos livres são sempre 0 (sistema de arquivos somente leitura).
- VfsRom.chdir(path)
Muda de diretório dentro do ROMFS. Apenas a raiz (
'/') é suportada; mudar para qualquer subdiretório levantaOSError(EOPNOTSUPP).
- VfsRom.getcwd()
Retorna o diretório de trabalho atual dentro do ROMFS. Sempre retorna
'/'.
- vfs.rom_ioctl(op, ...)
Interface de baixo nível para acessar a(s) partição(ões) de memória somente leitura (ROM) do dispositivo.
As operações suportadas são:
vfs.rom_ioctl(1)– Retorna o número de partições ROM disponíveis.vfs.rom_ioctl(2, id)– Retorna a partição ROM com índice id como um objetomemoryview. A memória pode ser lida, mas não escrita diretamente.vfs.rom_ioctl(3, id, length)– Prepara uma partição ROM para escrita. Apaga os primeiros length bytes da partição com índice id. Retorna o tamanho mínimo de escrita em bytes (o alinhamento necessário para escritas subsequentes).vfs.rom_ioctl(4, id, offset, buf)– Escreve buf (um objeto do tipo bytes) na partição ROM com índice id no byte offset.vfs.rom_ioctl(5, id)– Conclui uma sequência de escrita na partição id (realiza qualquer finalização necessária após a escrita, como o esvaziamento do cache).
Essas operações são usadas internamente pelo
mpremotepara implantar imagens ROMFS. A maioria dos usuários não precisa chamarvfs.rom_ioctl()diretamente.Exemplo (consultando partições disponíveis):
import vfs n = vfs.rom_ioctl(1) print("Number of ROM partitions:", n) for i in range(n): dev = vfs.rom_ioctl(2, i) print(f" Partition {i}: {len(dev)} bytes")
Montagem automática na inicialização¶
Quando o suporte a ROMFS está habilitado no firmware, o MicroPython tentará automaticamente montar a primeira partição ROM em /rom durante a inicialização. Se a partição contiver uma imagem ROMFS válida, ela é montada e tanto /rom quanto /rom/lib são adicionados ao sys.path automaticamente.
Isso significa que, após implantar uma imagem ROMFS com o mpremote, um soft-reset é suficiente para tornar os novos módulos importáveis.
Se nenhuma imagem ROMFS válida for encontrada na partição (por exemplo, em uma placa recém-programada), a montagem é silenciosamente ignorada.
Usando o mpremote para gerenciar o ROMFS¶
A ferramenta mpremote fornece três sub-comandos para gerenciar imagens ROMFS em um dispositivo conectado.
romfs query¶
$ mpremote romfs query
Lista todas as partições ROMFS disponíveis no dispositivo e seus tamanhos. Também mostra os primeiros 12 bytes de cada partição em hexadecimal e informa se uma imagem ROMFS válida está presente.
Exemplo de saída:
ROMFS0 partition has size 131072 bytes (32 blocks of 4096 bytes each)
Raw contents: d2:cd:31:XX:XX:XX:XX:XX:XX:XX:XX:XX ...
ROMFS image size: 1234
romfs build¶
$ mpremote romfs [-o <output>] build <source>
Constrói uma imagem ROMFS a partir do diretório source no PC host. A imagem é gravada em output (padrão: <source>.romfs).
Opções:
-o <output>,--output <output>: Especifica o caminho do arquivo de saída.-m,--mpy(padrão): Compila automaticamente os arquivos.pypara.mpyusando ompy_crossantes de adicioná-los à imagem. Requer o pacote Pythonmpy_cross(pip install mpy_cross).--no-mpy: Desabilita a compilação automática dos arquivos.py.
Exemplo:
$ mpremote romfs build myapp/
Building romfs filesystem, source directory: myapp/
/
|-- main.py -> .mpy
\-- lib/
\-- helper.py -> .mpy
Writing 2048 bytes to output file myapp.romfs
romfs deploy¶
$ mpremote romfs [-p <partition>] deploy <source>
Implanta uma imagem ROMFS no dispositivo. source pode ser:
Um diretório no host: a imagem ROMFS é construída em memória e implantada diretamente.
Um arquivo
.romfsou.img: a imagem é lida do disco e implantada.
Opções:
-p <partition>,--partition <partition>: Especifica o índice da partição de destino (padrão:0).-m,--mpy(padrão): Compila.pypara.mpyquando source é um diretório.--no-mpy: Desabilita a compilação automática dos arquivos.py.
Após a implantação, o dispositivo deve passar por um soft-reset para que o novo ROMFS seja montado em /rom.
Exemplo:
$ mpremote romfs deploy myapp/
Building romfs filesystem, source directory: myapp/
/
|-- main.py -> .mpy
\-- lib/
\-- helper.py -> .mpy
Image size is 2048 bytes
ROMFS0 partition has size 131072 bytes (32 blocks of 4096 bytes each)
Preparing ROMFS0 partition for writing
Deploying ROMFS to ROMFS0 partition
ROMFS image deployed
$ mpremote soft-reset
Exemplos¶
Implantando uma aplicação simples¶
Suponha que você tenha um diretório de projeto myapp/ com a seguinte estrutura:
myapp/
main.py
utils.py
lib/
helper.py
Para implantá-lo no ROMFS do dispositivo:
$ mpremote romfs deploy myapp/
Após um soft-reset, os módulos são importáveis a partir do ROMFS:
import main
import utils
from lib import helper
Listando o conteúdo do ROMFS a partir do Python¶
Após a montagem, o conteúdo do ROMFS pode ser explorado como qualquer outro sistema de arquivos:
import os
for entry in os.ilistdir('/rom'):
print(entry)
# Or simply:
print(os.listdir('/rom'))
A OpenMV também fornece um pequeno auxiliar romfs que imprime uma listagem formatada incluindo o endereço mapeado em memória e o alinhamento de cada arquivo:
from omv import romfs
romfs.ls_romfs()
Aninhando um ROMFS dentro de um ROMFS¶
Uma imagem ROMFS armazenada como um arquivo dentro de um ROMFS externo pode ser montada como um sistema de arquivos aninhado. Por exemplo, se /rom/inner.romfs existir. Como /rom é um ROMFS, os objetos de arquivo abertos a partir dele suportam o protocolo de buffer, de modo que uma memoryview zero-copy pode ser obtida diretamente:
import vfs
with open('/rom/inner.romfs', 'rb') as f:
inner = vfs.VfsRom(memoryview(f))
vfs.mount(inner, '/inner')
print(os.listdir('/inner'))
Formato da imagem ROMFS¶
O formato da imagem ROMFS é um formato binário compacto projetado para acesso mapeado em memória em microcontroladores. Uma breve visão geral:
A imagem começa com os bytes mágicos
0xd2 0xcd 0x31(codificados como"RM1"com os bits altos dos dois primeiros bytes definidos).O restante da imagem é composto por registros, cada um com uma tag de tipo (varuint), um comprimento (varuint) e uma carga útil.
Os tipos de registro incluem: preenchimento, dados literais, ponteiro de dados indireto, diretório, arquivo.
Os nomes de diretórios e arquivos são armazenados como strings de bytes prefixadas pelo comprimento.
Os dados de arquivo podem ser armazenados de forma literal (inline) ou por meio de um ponteiro indireto para outro local na imagem, o que permite o alinhamento para acesso mapeado em memória.
Tipos de registro desconhecidos são silenciosamente ignorados, proporcionando compatibilidade futura.
Esse formato é definido em extmod/vfs_rom.c no código-fonte do MicroPython. A implementação Python usada pelo mpremote para construir imagens está em tools/mpremote/mpremote/romfs.py.
Ver também
Trabalhando com sistemas de arquivos – Visão geral do VFS do MicroPython e dos tipos de sistema de arquivos disponíveis.
Arquivos de manifesto do MicroPython – Como congelar módulos Python no firmware.
Arquivos .mpy do MicroPython – Formato de arquivo binário .mpy do MicroPython.
Controle remoto do MicroPython: mpremote – A referência completa de comandos do mpremote.
romfs – Auxiliar da OpenMV para inspecionar o sistema de arquivos /rom montado.