Werken met ROMFS

Overzicht

ROMFS (Read-Only Memory Filesystem) is een lichtgewicht, alleen-lezen bestandssysteem dat is ontworpen voor MicroPython-apparaten. Het is geoptimaliseerd voor microcontrollers en embedded systemen waar code en gegevens in het flashgeheugen moeten worden opgeslagen en efficiënt toegankelijk moeten zijn zonder naar het RAM te worden gekopieerd.

De belangrijkste voordelen van ROMFS zijn:

  • Zero-copy imports: .mpy-bytecodebestanden die in een ROMFS zijn opgeslagen, kunnen rechtstreeks vanuit het flashgeheugen worden uitgevoerd (memory-mapped) in plaats van eerst naar het RAM te worden gekopieerd. Dit lijkt op de werking van frozen modules, maar vereist niet dat de volledige firmware opnieuw wordt geflasht.

  • Lage RAM-overhead: Constante objecten (strings, bytes, enz.) in .mpy-bestanden die vanuit ROMFS worden geladen, worden rechtstreeks vanuit het flashgeheugen gerefereerd en niet in het RAM gedupliceerd.

  • Flexibele uitrol: Een ROMFS-image kan op een host-pc worden gebouwd en met mpremote naar het apparaat worden uitgerold, zonder de firmware opnieuw te bouwen.

  • Standaard bestandssysteeminterface: Een ROMFS wordt gekoppeld in de VFS en is toegankelijk via normale Python-bestandsbewerkingen (open, os.listdir, import, enz.).

ROMFS is complementair aan zowel de lees-schrijf-bestandssystemen FAT/LittleFS (die zich in andere flashpartities bevinden) als aan frozen modules (die in de firmware zelf worden gecompileerd).

Ondersteuning per board

ROMFS is ingeschakeld in de OpenMV-firmware op elk camerabord dat een ROMFS-partitie heeft gereserveerd in zijn flash-indeling. Op deze boards wordt de ROMFS-partitie automatisch gedetecteerd bij het opstarten en gekoppeld aan /rom; zowel /rom als /rom/lib worden toegevoegd aan sys.path zodat modules die daar zijn opgeslagen rechtstreeks kunnen worden geïmporteerd.

Board

ROMFS-ondersteuning

OpenMV Cam N6

Ja

OpenMV AE3

Ja

OpenMV Cam RT1062

Ja

OpenMV Cam Pure Thermal

Ja

OpenMV Cam M4 / M7 / H7 / H7 Plus

Ja

Arduino Giga

Ja

Arduino Portenta H7

Ja

Arduino Nicla Vision

Ja

Arduino Nano 33 BLE Sense

Nee (geen ROMFS-partitie)

Arduino Nano RP2040 Connect

Nee (geen ROMFS-partitie)

Zie romfs voor een OpenMV-specifieke hulpfunctie die de gekoppelde ROMFS op /rom inspecteert.

Workflow

De typische workflow voor het gebruik van ROMFS is:

  1. Maak een map op uw pc met de Python-bestanden (of .mpy-bestanden) die u wilt uitrollen.

  2. Gebruik mpremote romfs deploy <directory> om de ROMFS-image te bouwen en naar het apparaat uit te rollen.

  3. De ROMFS wordt bij de volgende keer opstarten gekoppeld aan /rom (of kan onmiddellijk worden gekoppeld als het apparaat opnieuw wordt opgestart).

  4. Python-code op het apparaat kan vervolgens modules import-eren vanuit de ROMFS, net als vanuit elk ander bestandssysteem.

Bijvoorbeeld:

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

Na een soft-reset heeft het apparaat /rom/app.py (of /rom/app.mpy als mpy_cross is geïnstalleerd) beschikbaar om te importeren.

Zie de sectie mpremote romfs sub-commands hieronder voor volledige details over de mpremote-subcommando’s.

Python-API

De ROMFS Python-API wordt geleverd via de vfs-module.

class vfs.VfsRom(buffer)

Maak een ROMFS-bestandssysteemobject van buffer, dat een object moet zijn dat het bufferprotocol ondersteunt (bijv. een bytes-, bytearray- of memoryview-object) dat een geldige ROMFS-image bevat.

De constructor controleert of buffer begint met de ROMFS-magic-bytes (b"\xd2\xcd\x31"). Als de buffer te klein is of geen geldige ROMFS is, wordt OSError(ENODEV) opgeworpen.

Objecten die door deze constructor zijn gemaakt, kunnen worden gekoppeld met vfs.mount().

Voorbeeld:

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

Of, om een ROMFS-image te koppelen die in een bestand is opgeslagen:

import vfs

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

De volgende methoden zijn beschikbaar op een VfsRom-object:

VfsRom.open(path, mode)

Open een bestand vanuit de ROMFS. Alleen leesmodi ('', 'r', 'rt', 'rb') worden ondersteund. Een poging om een bestand te openen om te schrijven, werpt OSError(EROFS) op.

Het geretourneerde bestandsobject ondersteunt read(), seek(), tell() en close(). Voor binaire bestanden die in leesmodus zijn geopend, ondersteunt het geretourneerde object ook het bufferprotocol, zodat een memoryview van de bestandsgegevens kan worden verkregen, die rechtstreeks naar het ROMFS-geheugen verwijst (zero-copy).

VfsRom.ilistdir(path)

Retourneer een iterator over de items in de map path. Elk item is een tuple (name, type, inode, size) waarbij type gelijk is aan 0x8000 voor een bestand of 0x4000 voor een map.

VfsRom.stat(path)

Retourneer een os.stat-achtige 10-tuple voor path. Werpt OSError(ENOENT) op als het pad niet bestaat.

VfsRom.statvfs(path)

Retourneer statistieken van het bestandssysteem. De blokgrootte wordt gerapporteerd als 1 en het aantal blokken vertegenwoordigt de totale grootte van de ROMFS-image in bytes. Vrije blokken en vrije bestanden zijn altijd 0 (alleen-lezen bestandssysteem).

VfsRom.chdir(path)

Wijzig de map binnen de ROMFS. Alleen de root ('/') wordt ondersteund; overschakelen naar een submap werpt OSError(EOPNOTSUPP) op.

VfsRom.getcwd()

Retourneer de huidige werkmap binnen de ROMFS. Retourneert altijd '/'.

vfs.rom_ioctl(op, ...)

Low-level interface voor toegang tot de alleen-lezen geheugenpartitie(s) (ROM) van het apparaat.

De ondersteunde bewerkingen zijn:

  • vfs.rom_ioctl(1) – Retourneert het aantal beschikbare ROM-partities.

  • vfs.rom_ioctl(2, id) – Retourneert de ROM-partitie met index id als een memoryview-object. Het geheugen kan worden gelezen, maar niet rechtstreeks worden beschreven.

  • vfs.rom_ioctl(3, id, length) – Bereidt een ROM-partitie voor op schrijven. Wist de eerste length bytes van de partitie met index id. Retourneert de minimale schrijfgrootte in bytes (de uitlijning die vereist is voor latere schrijfbewerkingen).

  • vfs.rom_ioctl(4, id, offset, buf) – Schrijft buf (een bytes-achtig object) naar de ROM-partitie met index id op byte-offset offset.

  • vfs.rom_ioctl(5, id) – Voltooit een schrijfsequentie naar partitie id (voert eventuele afronding uit die nodig is na het schrijven, zoals het leegmaken van de cache).

Deze bewerkingen worden intern gebruikt door mpremote om ROMFS-images uit te rollen. De meeste gebruikers hoeven vfs.rom_ioctl() niet rechtstreeks aan te roepen.

Voorbeeld (beschikbare partities opvragen):

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

Automatisch koppelen bij het opstarten

Wanneer ROMFS-ondersteuning is ingeschakeld in de firmware, probeert MicroPython tijdens de initialisatie automatisch de eerste ROM-partitie te koppelen aan /rom. Als de partitie een geldige ROMFS-image bevat, wordt deze gekoppeld en worden zowel /rom als /rom/lib automatisch toegevoegd aan sys.path.

Dit betekent dat na het uitrollen van een ROMFS-image met mpremote een soft-reset voldoende is om de nieuwe modules importeerbaar te maken.

Als er geen geldige ROMFS-image in de partitie wordt gevonden (bijv. op een vers geprogrammeerd board), wordt het koppelen stilzwijgend overgeslagen.

mpremote gebruiken om ROMFS te beheren

Het hulpprogramma mpremote biedt drie subcommando’s voor het beheren van ROMFS-images op een aangesloten apparaat.

romfs query

$ mpremote romfs query

Toont alle beschikbare ROMFS-partities op het apparaat en hun groottes. Toont ook de eerste 12 bytes van elke partitie in hexadecimaal en rapporteert of er een geldige ROMFS-image aanwezig is.

Voorbeelduitvoer:

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>

Bouw een ROMFS-image van de map source op de host-pc. De image wordt naar output geschreven (standaard: <source>.romfs).

Opties:

  • -o <output>, --output <output>: Geef het pad van het uitvoerbestand op.

  • -m, --mpy (standaard): Compileert .py-bestanden automatisch naar .mpy met behulp van mpy_cross voordat ze aan de image worden toegevoegd. Vereist het mpy_cross Python-pakket (pip install mpy_cross).

  • --no-mpy: Schakelt automatische compilatie van .py-bestanden uit.

Voorbeeld:

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

Rol een ROMFS-image uit naar het apparaat. source kan een van beide zijn:

  • Een map op de host: de ROMFS-image wordt in het geheugen gebouwd en rechtstreeks uitgerold.

  • Een .romfs- of .img-bestand: de image wordt van schijf gelezen en uitgerold.

Opties:

  • -p <partition>, --partition <partition>: Geef de index van de doelpartitie op (standaard: 0).

  • -m, --mpy (standaard): Compileert .py naar .mpy wanneer source een map is.

  • --no-mpy: Schakelt automatische compilatie van .py-bestanden uit.

Na de uitrol moet het apparaat een soft-reset krijgen om de nieuwe ROMFS te koppelen aan /rom.

Voorbeeld:

$ 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

Voorbeelden

Een eenvoudige applicatie uitrollen

Stel dat u een projectmap myapp/ heeft met de volgende structuur:

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

Om deze uit te rollen naar de ROMFS van het apparaat:

$ mpremote romfs deploy myapp/

Na een soft-reset zijn de modules importeerbaar vanuit de ROMFS:

import main
import utils
from lib import helper

ROMFS-inhoud weergeven vanuit Python

Na het koppelen kan de inhoud van de ROMFS worden verkend zoals elk ander bestandssysteem:

import os

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

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

OpenMV levert ook een kleine romfs-hulpfunctie die een opgemaakte lijst afdrukt, inclusief het memory-mapped adres en de uitlijning van elk bestand:

from omv import romfs
romfs.ls_romfs()

Een ROMFS nesten binnen een ROMFS

Een ROMFS-image die als bestand binnen een buitenste ROMFS is opgeslagen, kan worden gekoppeld als een genest bestandssysteem. Bijvoorbeeld, als /rom/inner.romfs bestaat. Omdat /rom een ROMFS is, ondersteunen bestandsobjecten die daaruit worden geopend het bufferprotocol, zodat een zero-copy memoryview rechtstreeks kan worden verkregen:

import vfs

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

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

ROMFS-imageformaat

Het ROMFS-imageformaat is een compact binair formaat dat is ontworpen voor memory-mapped toegang op microcontrollers. Een kort overzicht:

  • De image begint met de magic-bytes 0xd2 0xcd 0x31 (gecodeerd als "RM1" met de hoge bits van de eerste twee bytes ingesteld).

  • De rest van de image bestaat uit records, elk met een type-tag (varuint), een lengte (varuint) en een payload.

  • Recordtypes zijn onder andere: padding, verbatim-gegevens, indirecte gegevenspointer, map, bestand.

  • Map- en bestandsnamen worden opgeslagen als bytestrings met een lengtevoorvoegsel.

  • Bestandsgegevens kunnen verbatim (inline) worden opgeslagen of via een indirecte pointer naar elders in de image, wat uitlijning voor memory-mapped toegang mogelijk maakt.

  • Onbekende recordtypes worden stilzwijgend overgeslagen, wat voorwaartse compatibiliteit biedt.

Dit formaat is gedefinieerd in extmod/vfs_rom.c in de MicroPython-broncode. De Python-implementatie die door mpremote wordt gebruikt om images te bouwen, bevindt zich in tools/mpremote/mpremote/romfs.py.

Zie ook

Werken met bestandssystemen – Overzicht van de MicroPython VFS en de beschikbare bestandssysteemtypes.

MicroPython manifest-bestanden – Hoe u Python-modules in firmware kunt freezen.

MicroPython .mpy-bestanden – MicroPython .mpy binair bestandsformaat.

MicroPython op afstand bedienen: mpremote – De volledige mpremote-commandoreferentie.

romfs – OpenMV-hulpfunctie voor het inspecteren van het gekoppelde /rom-bestandssysteem.