Rad s ROMFS

Pregled

ROMFS (Read-Only Memory Filesystem) je lagani datotečni sustav samo za čitanje, namijenjen MicroPython uređajima. Optimiran je za mikrokontrolere i ugrađene sustave gdje se kôd i podaci moraju pohraniti u flash memoriju i učinkovito im pristupati bez kopiranja u RAM.

Ključne prednosti ROMFS-a su:

  • Uvoz bez kopiranja: .mpy datoteke s bajtkodom pohranjene u ROMFS-u mogu se izvršavati izravno iz flash memorije (mapirane u memoriju) umjesto da se najprije kopiraju u RAM. To je slično načinu na koji rade zamrznuti moduli, ali ne zahtijeva ponovno upisivanje cijelog ugrađenog programa (firmware).

  • Mali zauzet RAM: Konstantni objekti (nizovi, bajtovi itd.) u .mpy datotekama učitanima iz ROMFS-a referenciraju se izravno iz flash memorije, a ne dupliciraju u RAM-u.

  • Fleksibilna implementacija: Slika ROMFS-a može se izraditi na host računalu i postaviti na uređaj pomoću mpremote, bez ponovne izgradnje ugrađenog programa (firmware).

  • Standardno sučelje datotečnog sustava: ROMFS se montira u VFS i pristupa mu se uobičajenim Python operacijama nad datotekama (open, os.listdir, import itd.).

ROMFS nadopunjuje i datotečne sustave FAT/LittleFS za čitanje i pisanje (koji se nalaze u drugim flash particijama) i zamrznute module (koji se kompiliraju u sam ugrađeni program).

Podrška za pločice

ROMFS je omogućen u OpenMV ugrađenom programu (firmware) na svakoj pločici kamere koja ima rezerviranu ROMFS particiju u svom rasporedu flash memorije. Na tim se pločicama ROMFS particija automatski otkriva pri pokretanju i montira na /rom; i /rom i /rom/lib dodaju se u sys.path kako bi se moduli pohranjeni ondje mogli izravno uvoziti.

Pločica

Podrška za ROMFS

OpenMV Cam N6

Da

OpenMV AE3

Da

OpenMV Cam RT1062

Da

OpenMV Cam Pure Thermal

Da

OpenMV Cam M4 / M7 / H7 / H7 Plus

Da

Arduino Giga

Da

Arduino Portenta H7

Da

Arduino Nicla Vision

Da

Arduino Nano 33 BLE Sense

Ne (nema ROMFS particije)

Arduino Nano RP2040 Connect

Ne (nema ROMFS particije)

Pogledajte romfs za OpenMV-specifični pomoćnik koji pregledava montirani ROMFS na /rom.

Tijek rada

Tipičan tijek rada za korištenje ROMFS-a je:

  1. Stvorite direktorij na računalu s Python datotekama (ili .mpy datotekama) koje želite postaviti.

  2. Koristite mpremote romfs deploy <directory> za izgradnju i postavljanje slike ROMFS-a na uređaj.

  3. ROMFS će biti montiran na /rom pri sljedećem pokretanju (ili se može montirati odmah ako se uređaj ponovno pokrene).

  4. Python kôd na uređaju zatim može import module iz ROMFS-a baš kao i iz bilo kojeg drugog datotečnog sustava.

Na primjer:

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

Nakon mekog ponovnog pokretanja, uređaj će imati /rom/app.py (ili /rom/app.mpy ako je instaliran mpy_cross) dostupan za uvoz.

Pogledajte odjeljak mpremote romfs podnaredbe u nastavku za sve pojedinosti o mpremote podnaredbama.

Python API

Python API za ROMFS pružen je putem modula vfs.

class vfs.VfsRom(buffer)

Stvara objekt ROMFS datotečnog sustava iz buffer, koji mora biti objekt koji podržava protokol međuspremnika (npr. objekt bytes, bytearray ili memoryview) koji sadrži valjanu sliku ROMFS-a.

Konstruktor provjerava počinje li buffer magičnim bajtovima ROMFS-a (b"\xd2\xcd\x31"). Ako je međuspremnik premalen ili nije valjan ROMFS, podiže se OSError(ENODEV).

Objekti stvoreni ovim konstruktorom mogu se montirati pomoću vfs.mount().

Primjer:

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

Ili, za montiranje slike ROMFS-a pohranjene u datoteci:

import vfs

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

Sljedeće metode dostupne su na VfsRom objektu:

VfsRom.open(path, mode)

Otvara datoteku iz ROMFS-a. Podržani su samo načini čitanja ('', 'r', 'rt', 'rb'). Pokušaj otvaranja datoteke za pisanje podići će OSError(EROFS).

Vraćeni objekt datoteke podržava read(), seek(), tell() i close(). Za binarne datoteke otvorene u načinu čitanja, vraćeni objekt također podržava protokol međuspremnika tako da se može dobiti memoryview podataka datoteke, koji se izravno odnosi na ROMFS memoriju (bez kopiranja).

VfsRom.ilistdir(path)

Vraća iterator nad unosima u direktoriju path. Svaki unos je n-torka (name, type, inode, size) gdje je type jednak 0x8000 za datoteku ili 0x4000 za direktorij.

VfsRom.stat(path)

Vraća 10-torku sličnu os.stat za path. Podiže OSError(ENOENT) ako putanja ne postoji.

VfsRom.statvfs(path)

Vraća statistiku datotečnog sustava. Veličina bloka prijavljuje se kao 1, a broj blokova predstavlja ukupnu veličinu slike ROMFS-a u bajtovima. Slobodni blokovi i slobodne datoteke uvijek su 0 (datotečni sustav samo za čitanje).

VfsRom.chdir(path)

Mijenja direktorij unutar ROMFS-a. Podržan je samo korijenski ('/'); promjena u bilo koji poddirektorij podiže OSError(EOPNOTSUPP).

VfsRom.getcwd()

Vraća trenutni radni direktorij unutar ROMFS-a. Uvijek vraća '/'.

vfs.rom_ioctl(op, ...)

Niskorazinsko sučelje za pristup particiji(ama) memorije samo za čitanje (ROM) na uređaju.

Podržane operacije su:

  • vfs.rom_ioctl(1) – Vraća broj dostupnih ROM particija.

  • vfs.rom_ioctl(2, id) – Vraća ROM particiju s indeksom id kao memoryview objekt. Memorija se može čitati, ali ne i izravno pisati.

  • vfs.rom_ioctl(3, id, length) – Priprema ROM particiju za pisanje. Briše prvih length bajtova particije s indeksom id. Vraća minimalnu veličinu zapisa u bajtovima (poravnanje potrebno za naknadne zapise).

  • vfs.rom_ioctl(4, id, offset, buf) – Upisuje buf (objekt sličan bajtovima) u ROM particiju s indeksom id na bajtnom pomaku offset.

  • vfs.rom_ioctl(5, id) – Dovršava sekvencu pisanja na particiju id (izvodi sve potrebne završne radnje nakon pisanja, poput pražnjenja predmemorije).

Te operacije interno koristi mpremote za postavljanje slika ROMFS-a. Većini korisnika nije potrebno izravno pozivati vfs.rom_ioctl().

Primjer (ispitivanje dostupnih particija):

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

Automatsko montiranje pri pokretanju

Kada je podrška za ROMFS omogućena u ugrađenom programu (firmware), MicroPython će tijekom inicijalizacije automatski pokušati montirati prvu ROM particiju na /rom. Ako particija sadrži valjanu sliku ROMFS-a, montira se i i /rom i /rom/lib automatski se dodaju u sys.path.

To znači da je nakon postavljanja slike ROMFS-a pomoću mpremote meko ponovno pokretanje dovoljno da novi moduli postanu uvozivi.

Ako se u particiji ne pronađe valjana slika ROMFS-a (npr. na svježe programiranoj pločici), montiranje se tiho preskače.

Korištenje mpremote za upravljanje ROMFS-om

Alat mpremote pruža tri podnaredbe za upravljanje slikama ROMFS-a na povezanom uređaju.

romfs query

$ mpremote romfs query

Prikazuje sve dostupne ROMFS particije na uređaju i njihove veličine. Također prikazuje prvih 12 bajtova svake particije u heksadecimalnom obliku i prijavljuje je li prisutna valjana slika ROMFS-a.

Primjer izlaza:

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>

Izgrađuje sliku ROMFS-a iz direktorija source na host računalu. Slika se upisuje u output (zadano: <source>.romfs).

Opcije:

  • -o <output>, --output <output>: Određuje putanju izlazne datoteke.

  • -m, --mpy (zadano): Automatski kompilira .py datoteke u .mpy pomoću mpy_cross prije njihova dodavanja u sliku. Zahtijeva mpy_cross Python paket (pip install mpy_cross).

  • --no-mpy: Onemogućuje automatsku kompilaciju .py datoteka.

Primjer:

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

Postavlja sliku ROMFS-a na uređaj. source može biti:

  • Direktorij na hostu: slika ROMFS-a izgrađuje se u memoriji i postavlja izravno.

  • Datoteka .romfs ili .img: slika se čita s diska i postavlja.

Opcije:

  • -p <partition>, --partition <partition>: Određuje indeks ciljne particije (zadano: 0).

  • -m, --mpy (zadano): Kompilira .py u .mpy kada je source direktorij.

  • --no-mpy: Onemogućuje automatsku kompilaciju .py datoteka.

Nakon postavljanja, uređaj se mora meko ponovno pokrenuti kako bi se novi ROMFS montirao na /rom.

Primjer:

$ 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

Primjeri

Postavljanje jednostavne aplikacije

Pretpostavimo da imate projektni direktorij myapp/ sa sljedećom strukturom:

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

Za postavljanje na ROMFS uređaja:

$ mpremote romfs deploy myapp/

Nakon mekog ponovnog pokretanja, moduli se mogu uvoziti iz ROMFS-a:

import main
import utils
from lib import helper

Ispisivanje sadržaja ROMFS-a iz Pythona

Nakon montiranja, sadržaj ROMFS-a može se istraživati kao i kod bilo kojeg drugog datotečnog sustava:

import os

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

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

OpenMV također isporučuje mali romfs pomoćnik koji ispisuje formatirani popis uključujući memorijski mapiranu adresu i poravnanje svake datoteke:

from omv import romfs
romfs.ls_romfs()

Ugnježđivanje ROMFS-a unutar ROMFS-a

Slika ROMFS-a pohranjena kao datoteka unutar vanjskog ROMFS-a može se montirati kao ugniježđeni datotečni sustav. Na primjer, ako postoji /rom/inner.romfs. Budući da je /rom ROMFS, objekti datoteka otvoreni iz njega podržavaju protokol međuspremnika, pa se izravno može dobiti memoryview bez kopiranja:

import vfs

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

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

Format slike ROMFS-a

Format slike ROMFS-a kompaktan je binarni format namijenjen pristupu mapiranom u memoriju na mikrokontrolerima. Kratki pregled:

  • Slika počinje magičnim bajtovima 0xd2 0xcd 0x31 (kodirani kao "RM1" s postavljenim visokim bitovima prva dva bajta).

  • Ostatak slike sastoji se od zapisa, svaki s oznakom tipa (varuint), duljinom (varuint) i korisnim sadržajem.

  • Tipovi zapisa uključuju: ispunu, doslovne podatke, neizravni pokazivač na podatke, direktorij, datoteku.

  • Imena direktorija i datoteka pohranjuju se kao bajtni nizovi s prefiksom duljine.

  • Podaci datoteke mogu se pohraniti doslovno (umetnuto) ili putem neizravnog pokazivača na drugo mjesto u slici, što omogućuje poravnanje za pristup mapiran u memoriju.

  • Nepoznati tipovi zapisa tiho se preskaču, čime se osigurava kompatibilnost s budućim verzijama.

Ovaj je format definiran u extmod/vfs_rom.c u izvornom kodu MicroPythona. Python implementacija koju mpremote koristi za izgradnju slika nalazi se u tools/mpremote/mpremote/romfs.py.

Više informacija

Rad s datotečnim sustavima – Pregled MicroPython VFS-a i dostupnih tipova datotečnih sustava.

MicroPython manifest datoteke – Kako zamrznuti Python module u ugrađeni program.

MicroPython .mpy datoteke – MicroPython .mpy format binarne datoteke.

Daljinsko upravljanje MicroPythonom: mpremote – Potpuna referenca naredbi mpremote.

romfs – OpenMV pomoćnik za pregledavanje montiranog /rom datotečnog sustava.