Práce s ROMFS

Přehled

ROMFS (Read-Only Memory Filesystem) je odlehčený souborový systém určený pouze pro čtení, navržený pro zařízení s MicroPythonem. Je optimalizovaný pro mikrokontroléry a vestavěné systémy, kde je potřeba ukládat kód a data ve flash paměti a efektivně k nim přistupovat bez nutnosti kopírovat je do RAM.

Hlavní výhody ROMFS jsou:

  • Importy bez kopírování: Soubory s bytecode .mpy uložené v ROMFS lze spouštět přímo z flash paměti (mapované do paměti) místo toho, aby se nejprve kopírovaly do RAM. Je to podobné tomu, jak fungují zamrzlé moduly, ale nevyžaduje to přeflashování celého firmwaru.

  • Nízká režie RAM: Konstantní objekty (řetězce, bajty atd.) v souborech .mpy načtených z ROMFS jsou odkazovány přímo z flash paměti, nikoli duplikovány v RAM.

  • Flexibilní nasazení: Obraz ROMFS lze sestavit na hostitelském PC a nasadit do zařízení pomocí mpremote, aniž by bylo nutné znovu sestavovat firmware.

  • Standardní rozhraní souborového systému: ROMFS je připojen ve VFS a přistupuje se k němu pomocí běžných souborových operací Pythonu (open, os.listdir, import atd.).

ROMFS doplňuje jak souborové systémy FAT/LittleFS pro čtení i zápis (které se nacházejí v jiných oddílech flash paměti), tak zamrzlé moduly (které jsou zkompilovány přímo do firmwaru).

Podpora desek

ROMFS je ve firmwaru OpenMV povolen na každé kameře, která má ve svém rozložení flash paměti vyhrazený oddíl pro ROMFS. Na těchto deskách je oddíl ROMFS automaticky detekován při startu a připojen na /rom; jak /rom, tak /rom/lib jsou přidány do sys.path, takže moduly tam uložené lze importovat přímo.

Deska

Podpora ROMFS

OpenMV Cam N6

Ano

OpenMV AE3

Ano

OpenMV Cam RT1062

Ano

OpenMV Cam Pure Thermal

Ano

OpenMV Cam M4 / M7 / H7 / H7 Plus

Ano

Arduino Giga

Ano

Arduino Portenta H7

Ano

Arduino Nicla Vision

Ano

Arduino Nano 33 BLE Sense

Ne (žádný oddíl ROMFS)

Arduino Nano RP2040 Connect

Ne (žádný oddíl ROMFS)

Viz romfs pro pomocníka specifického pro OpenMV, který zkoumá připojený ROMFS na /rom.

Pracovní postup

Typický pracovní postup pro použití ROMFS je:

  1. Vytvořte na svém PC adresář se soubory Pythonu (nebo soubory .mpy), které chcete nasadit.

  2. Použijte mpremote romfs deploy <directory> k sestavení a nasazení obrazu ROMFS do zařízení.

  3. ROMFS bude připojen na /rom při příštím startu (nebo může být připojen okamžitě, pokud se zařízení restartuje).

  4. Kód Pythonu v zařízení pak může pomocí import importovat moduly z ROMFS stejně jako z jakéhokoli jiného souborového systému.

Například:

# On the host PC, with a directory "myapp/" containing app.py:
$ mpremote romfs deploy myapp/

Po měkkém restartu bude mít zařízení k dispozici pro import /rom/app.py (nebo /rom/app.mpy, pokud je nainstalován mpy_cross).

Úplné podrobnosti o dílčích příkazech mpremote naleznete v sekci dílčí příkazy mpremote romfs níže.

Python API

Python API pro ROMFS je poskytováno prostřednictvím modulu vfs.

class vfs.VfsRom(buffer)

Vytvoří objekt souborového systému ROMFS z buffer, který musí být objektem podporujícím buffer protokol (např. objekt bytes, bytearray nebo memoryview) obsahujícím platný obraz ROMFS.

Konstruktor ověří, že buffer začíná magickými bajty ROMFS (b"\xd2\xcd\x31"). Pokud je buffer příliš malý nebo se nejedná o platný ROMFS, je vyvolána výjimka OSError(ENODEV).

Objekty vytvořené tímto konstruktorem lze připojit pomocí vfs.mount().

Příklad:

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')

Nebo, pro připojení obrazu ROMFS uloženého v souboru:

import vfs

with open('/flash/app.romfs', 'rb') as f:
    romfs_data = f.read()
fs = vfs.VfsRom(romfs_data)
vfs.mount(fs, '/rom2')

Na objektu VfsRom jsou k dispozici následující metody:

VfsRom.open(path, mode)

Otevře soubor z ROMFS. Podporovány jsou pouze režimy pro čtení ('', 'r', 'rt', 'rb'). Pokus o otevření souboru pro zápis vyvolá OSError(EROFS).

Vrácený souborový objekt podporuje read(), seek(), tell() a close(). U binárních souborů otevřených v režimu čtení vrácený objekt také podporuje buffer protokol, takže lze získat memoryview dat souboru, který odkazuje přímo do paměti ROMFS (bez kopírování).

VfsRom.ilistdir(path)

Vrátí iterátor přes položky v adresáři path. Každá položka je n-tice (name, type, inode, size), kde type je 0x8000 pro soubor nebo 0x4000 pro adresář.

VfsRom.stat(path)

Vrátí 10prvkovou n-tici podobnou os.stat pro path. Vyvolá OSError(ENOENT), pokud cesta neexistuje.

VfsRom.statvfs(path)

Vrátí statistiky souborového systému. Velikost bloku je uváděna jako 1 a počet bloků představuje celkovou velikost obrazu ROMFS v bajtech. Počet volných bloků a volných souborů je vždy 0 (souborový systém pouze pro čtení).

VfsRom.chdir(path)

Změní adresář v rámci ROMFS. Podporován je pouze kořen ('/'); změna na jakýkoli podadresář vyvolá OSError(EOPNOTSUPP).

VfsRom.getcwd()

Vrátí aktuální pracovní adresář v rámci ROMFS. Vždy vrací '/'.

vfs.rom_ioctl(op, ...)

Nízkoúrovňové rozhraní pro přístup k oddílu (oddílům) paměti pouze pro čtení (ROM) zařízení.

Podporované operace jsou:

  • vfs.rom_ioctl(1) – Vrátí počet dostupných oddílů ROM.

  • vfs.rom_ioctl(2, id) – Vrátí oddíl ROM s indexem id jako objekt memoryview. Paměť lze číst, ale ne přímo zapisovat.

  • vfs.rom_ioctl(3, id, length) – Připraví oddíl ROM pro zápis. Vymaže prvních length bajtů oddílu s indexem id. Vrátí minimální velikost zápisu v bajtech (zarovnání požadované pro následné zápisy).

  • vfs.rom_ioctl(4, id, offset, buf) – Zapíše buf (objekt podobný bytes) do oddílu ROM s indexem id na bajtový posun offset.

  • vfs.rom_ioctl(5, id) – Dokončí sekvenci zápisu do oddílu id (provede případné dokončovací operace potřebné po zápisu, jako je vyprázdnění mezipaměti).

Tyto operace používá interně mpremote k nasazování obrazů ROMFS. Většina uživatelů nepotřebuje volat vfs.rom_ioctl() přímo.

Příklad (dotazování dostupných oddílů):

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")

Automatické připojení při startu

Když je podpora ROMFS povolena ve firmwaru, MicroPython se během inicializace automaticky pokusí připojit první oddíl ROM na /rom. Pokud oddíl obsahuje platný obraz ROMFS, je připojen a jak /rom, tak /rom/lib jsou automaticky přidány do sys.path.

To znamená, že po nasazení obrazu ROMFS pomocí mpremote stačí měkký restart, aby byly nové moduly importovatelné.

Pokud v oddílu není nalezen žádný platný obraz ROMFS (např. na čerstvě naprogramované desce), připojení je tiše přeskočeno.

Použití mpremote ke správě ROMFS

Nástroj mpremote poskytuje tři dílčí příkazy pro správu obrazů ROMFS na připojeném zařízení.

romfs query

$ mpremote romfs query

Vypíše všechny dostupné oddíly ROMFS na zařízení a jejich velikosti. Také zobrazí prvních 12 bajtů každého oddílu v hexadecimálním tvaru a uvede, zda je přítomen platný obraz ROMFS.

Příklad výstupu:

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>

Sestaví obraz ROMFS z adresáře source na hostitelském PC. Obraz je zapsán do output (výchozí: <source>.romfs).

Možnosti:

  • -o <output>, --output <output>: Určuje cestu k výstupnímu souboru.

  • -m, --mpy (výchozí): Automaticky zkompiluje soubory .py na .mpy pomocí mpy_cross před jejich přidáním do obrazu. Vyžaduje balíček Pythonu mpy_cross (pip install mpy_cross).

  • --no-mpy: Zakáže automatickou kompilaci souborů .py.

Příklad:

$ 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>

Nasadí obraz ROMFS do zařízení. source může být buď:

  • Adresář na hostiteli: obraz ROMFS je sestaven v paměti a nasazen přímo.

  • Soubor .romfs nebo .img: obraz je načten z disku a nasazen.

Možnosti:

  • -p <partition>, --partition <partition>: Určuje index cílového oddílu (výchozí: 0).

  • -m, --mpy (výchozí): Zkompiluje .py na .mpy, pokud je source adresář.

  • --no-mpy: Zakáže automatickou kompilaci souborů .py.

Po nasazení musí být zařízení měkce restartováno, aby byl nový ROMFS připojen na /rom.

Příklad:

$ 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

Příklady

Nasazení jednoduché aplikace

Předpokládejme, že máte projektový adresář myapp/ s následující strukturou:

myapp/
    main.py
    utils.py
    lib/
        helper.py

Pro jeho nasazení do ROMFS zařízení:

$ mpremote romfs deploy myapp/

Po měkkém restartu jsou moduly importovatelné z ROMFS:

import main
import utils
from lib import helper

Výpis obsahu ROMFS z Pythonu

Po připojení lze obsah ROMFS prozkoumat jako u jakéhokoli jiného souborového systému:

import os

for entry in os.ilistdir('/rom'):
    print(entry)

# Or simply:
print(os.listdir('/rom'))

OpenMV také dodává malého pomocníka romfs, který vypíše formátovaný výpis včetně do paměti mapované adresy a zarovnání každého souboru:

from omv import romfs
romfs.ls_romfs()

Vnoření ROMFS do ROMFS

Obraz ROMFS uložený jako soubor uvnitř vnějšího ROMFS lze připojit jako vnořený souborový systém. Například pokud existuje /rom/inner.romfs. Protože /rom je ROMFS, souborové objekty z něj otevřené podporují buffer protokol, takže lze získat memoryview bez kopírování přímo:

import vfs

with open('/rom/inner.romfs', 'rb') as f:
    inner = vfs.VfsRom(memoryview(f))
vfs.mount(inner, '/inner')

print(os.listdir('/inner'))

Formát obrazu ROMFS

Formát obrazu ROMFS je kompaktní binární formát navržený pro do paměti mapovaný přístup na mikrokontrolérech. Stručný přehled:

  • Obraz začíná magickými bajty 0xd2 0xcd 0x31 (zakódovanými jako "RM1" s nastavenými horními bity prvních dvou bajtů).

  • Zbytek obrazu se skládá ze záznamů, z nichž každý má typovou značku (varuint), délku (varuint) a obsah.

  • Typy záznamů zahrnují: výplň, doslovná data, nepřímý datový ukazatel, adresář, soubor.

  • Názvy adresářů a souborů jsou uloženy jako bajtové řetězce s předponou délky.

  • Data souboru mohou být uložena doslovně (vložená) nebo prostřednictvím nepřímého ukazatele na jiné místo v obrazu, což umožňuje zarovnání pro do paměti mapovaný přístup.

  • Neznámé typy záznamů jsou tiše přeskočeny, což zajišťuje dopřednou kompatibilitu.

Tento formát je definován v extmod/vfs_rom.c ve zdrojovém kódu MicroPythonu. Implementace v Pythonu používaná nástrojem mpremote k sestavování obrazů se nachází v tools/mpremote/mpremote/romfs.py.

Viz také

Práce se souborovými systémy – Přehled VFS MicroPythonu a dostupných typů souborových systémů.

Soubory manifestu MicroPython – Jak zamrazit moduly Pythonu do firmwaru.

Soubory .mpy v MicroPythonu – Binární formát souborů .mpy MicroPythonu.

Vzdálené ovládání MicroPythonu: mpremote – Úplná referenční příručka příkazu mpremote.

romfs – Pomocník OpenMV pro zkoumání připojeného souborového systému /rom.