Lucrul cu ROMFS¶
Prezentare generală¶
ROMFS (Read-Only Memory Filesystem) este un sistem de fișiere ușor, doar pentru citire, conceput pentru dispozitivele MicroPython. Este optimizat pentru microcontrolere și sisteme încorporate, unde codul și datele trebuie stocate în memoria flash și accesate eficient, fără a fi copiate în RAM.
Principalele avantaje ale ROMFS sunt:
Importuri zero-copy: fișierele bytecode
.mpystocate într-un ROMFS pot fi executate direct din memoria flash (memory-mapped), în loc să fie copiate mai întâi în RAM. Acest lucru este similar cu modul în care funcționează modulele înghețate, dar nu necesită reflasharea întregului firmware.Consum redus de RAM: obiectele constante (șiruri de caractere, octeți etc.) din fișierele
.mpyîncărcate din ROMFS sunt referențiate direct din memoria flash, nefiind duplicate în RAM.Implementare flexibilă: o imagine ROMFS poate fi construită pe un PC gazdă și implementată pe dispozitiv folosind mpremote, fără a reconstrui firmware-ul.
Interfață standard de sistem de fișiere: un ROMFS este montat în VFS și accesat prin operații normale Python pe fișiere (
open,os.listdir,importetc.).
ROMFS este complementar atât sistemelor de fișiere citire-scriere FAT/LittleFS (care se află în alte partiții flash), cât și modulelor înghețate (care sunt compilate în firmware-ul propriu-zis).
Suport pentru plăci¶
ROMFS este activat în firmware-ul OpenMV pe fiecare placă de cameră care are o partiție ROMFS rezervată în structura sa flash. Pe aceste plăci, partiția ROMFS este detectată automat la pornire și montată la /rom; atât /rom cât și /rom/lib sunt adăugate în sys.path, astfel încât modulele stocate acolo să poată fi importate direct.
Placă |
Suport 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 |
Nu (fără partiție ROMFS) |
Arduino Nano RP2040 Connect |
Nu (fără partiție ROMFS) |
Consultați romfs pentru un ajutor specific OpenMV care inspectează ROMFS-ul montat la /rom.
Flux de lucru¶
Fluxul de lucru tipic pentru utilizarea ROMFS este:
Creați pe PC un director cu fișierele Python (sau fișierele
.mpy) pe care doriți să le implementați.Folosiți
mpremote romfs deploy <directory>pentru a construi și implementa imaginea ROMFS pe dispozitiv.ROMFS-ul va fi montat la
/romla următoarea pornire (sau poate fi montat imediat dacă dispozitivul este repornit).Codul Python de pe dispozitiv poate apoi să facă
importde module din ROMFS exact ca din orice alt sistem de fișiere.
De exemplu:
# On the host PC, with a directory "myapp/" containing app.py:
$ mpremote romfs deploy myapp/
După un soft-reset, dispozitivul va avea /rom/app.py (sau /rom/app.mpy dacă mpy_cross este instalat) disponibil pentru import.
Consultați secțiunea sub-comenzile mpremote romfs de mai jos pentru detalii complete despre sub-comenzile mpremote.
API-ul Python¶
API-ul Python pentru ROMFS este furnizat prin modulul vfs.
- class vfs.VfsRom(buffer)
Creează un obiect sistem de fișiere ROMFS din buffer, care trebuie să fie un obiect ce suportă protocolul de buffer (de exemplu un obiect
bytes,bytearraysaumemoryview) și care conține o imagine ROMFS validă.Constructorul validează faptul că buffer începe cu octeții magici ROMFS (
b"\xd2\xcd\x31"). Dacă buffer-ul este prea mic sau nu este un ROMFS valid, se ridicăOSError(ENODEV).Obiectele create de acest constructor pot fi montate folosind
vfs.mount().Exemplu:
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')
Sau, pentru a monta o imagine ROMFS stocată într-un fișier:
import vfs with open('/flash/app.romfs', 'rb') as f: romfs_data = f.read() fs = vfs.VfsRom(romfs_data) vfs.mount(fs, '/rom2')
Următoarele metode sunt disponibile pentru un obiect
VfsRom:- VfsRom.open(path, mode)
Deschide un fișier din ROMFS. Sunt suportate doar modurile de citire (
'','r','rt','rb'). Încercarea de a deschide un fișier pentru scriere va ridicaOSError(EROFS).Obiectul fișier returnat suportă
read(),seek(),tell()șiclose(). Pentru fișierele binare deschise în mod citire, obiectul returnat suportă de asemenea protocolul de buffer, astfel încât se poate obține unmemoryviewal datelor fișierului, care referențiază direct memoria ROMFS (zero-copy).
- VfsRom.ilistdir(path)
Returnează un iterator peste intrările din directorul path. Fiecare intrare este un tuplu
(name, type, inode, size), unde type este0x8000pentru un fișier sau0x4000pentru un director.
- VfsRom.stat(path)
Returnează un tuplu cu 10 elemente, similar cu
os.stat, pentru path. RidicăOSError(ENOENT)dacă calea nu există.
- VfsRom.statvfs(path)
Returnează statistici despre sistemul de fișiere. Dimensiunea blocului este raportată ca 1, iar numărul de blocuri reprezintă dimensiunea totală a imaginii ROMFS în octeți. Blocurile libere și fișierele libere sunt întotdeauna 0 (sistem de fișiere doar pentru citire).
- VfsRom.chdir(path)
Schimbă directorul în cadrul ROMFS. Este suportat doar rădăcina (
'/'); schimbarea către orice subdirector ridicăOSError(EOPNOTSUPP).
- VfsRom.getcwd()
Returnează directorul de lucru curent în cadrul ROMFS. Returnează întotdeauna
'/'.
- vfs.rom_ioctl(op, ...)
Interfață de nivel scăzut pentru accesarea partiției(lor) de memorie doar pentru citire (ROM) ale dispozitivului.
Operațiile suportate sunt:
vfs.rom_ioctl(1)– Returnează numărul de partiții ROM disponibile.vfs.rom_ioctl(2, id)– Returnează partiția ROM cu indicele id ca obiectmemoryview. Memoria poate fi citită, dar nu scrisă direct.vfs.rom_ioctl(3, id, length)– Pregătește o partiție ROM pentru scriere. Șterge primii length octeți ai partiției cu indicele id. Returnează dimensiunea minimă de scriere în octeți (alinierea necesară pentru scrierile ulterioare).vfs.rom_ioctl(4, id, offset, buf)– Scrie buf (un obiect de tip bytes) în partiția ROM cu indicele id la octetul offset.vfs.rom_ioctl(5, id)– Finalizează o secvență de scriere către partiția id (efectuează orice finalizare necesară după scriere, cum ar fi golirea cache-ului).
Aceste operații sunt utilizate intern de către
mpremotepentru a implementa imagini ROMFS. Majoritatea utilizatorilor nu au nevoie să apeleze directvfs.rom_ioctl().Exemplu (interogarea partițiilor disponibile):
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")
Montare automată la pornire¶
Când suportul ROMFS este activat în firmware, MicroPython va încerca automat să monteze prima partiție ROM la /rom în timpul inițializării. Dacă partiția conține o imagine ROMFS validă, aceasta este montată, iar atât /rom cât și /rom/lib sunt adăugate automat în sys.path.
Aceasta înseamnă că, după implementarea unei imagini ROMFS cu mpremote, un soft-reset este suficient pentru a face noile module importabile.
Dacă nu se găsește nicio imagine ROMFS validă în partiție (de exemplu, pe o placă proaspăt programată), montarea este omisă în mod silențios.
Utilizarea mpremote pentru gestionarea ROMFS¶
Instrumentul mpremote oferă trei sub-comenzi pentru gestionarea imaginilor ROMFS de pe un dispozitiv conectat.
romfs query¶
$ mpremote romfs query
Listează toate partițiile ROMFS disponibile de pe dispozitiv și dimensiunile acestora. De asemenea, afișează primii 12 octeți ai fiecărei partiții în format hexazecimal și raportează dacă este prezentă o imagine ROMFS validă.
Exemplu de ieșire:
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>
Construiește o imagine ROMFS din directorul source de pe PC-ul gazdă. Imaginea este scrisă în output (implicit: <source>.romfs).
Opțiuni:
-o <output>,--output <output>: Specifică calea fișierului de ieșire.-m,--mpy(implicit): Compilează automat fișierele.pyîn.mpyfolosindmpy_crossînainte de a le adăuga în imagine. Necesită pachetul Pythonmpy_cross(pip install mpy_cross).--no-mpy: Dezactivează compilarea automată a fișierelor.py.
Exemplu:
$ 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>
Implementează o imagine ROMFS pe dispozitiv. source poate fi fie:
Un director pe gazdă: imaginea ROMFS este construită în memorie și implementată direct.
Un fișier
.romfssau.img: imaginea este citită de pe disc și implementată.
Opțiuni:
-p <partition>,--partition <partition>: Specifică indicele partiției țintă (implicit:0).-m,--mpy(implicit): Compilează.pyîn.mpycând source este un director.--no-mpy: Dezactivează compilarea automată a fișierelor.py.
După implementare, dispozitivul trebuie să fie supus unui soft-reset pentru ca noul ROMFS să fie montat la /rom.
Exemplu:
$ 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
Exemple¶
Implementarea unei aplicații simple¶
Să presupunem că aveți un director de proiect myapp/ cu următoarea structură:
myapp/
main.py
utils.py
lib/
helper.py
Pentru a-l implementa în ROMFS-ul dispozitivului:
$ mpremote romfs deploy myapp/
După un soft-reset, modulele pot fi importate din ROMFS:
import main
import utils
from lib import helper
Listarea conținutului ROMFS din Python¶
După montare, conținutul ROMFS poate fi explorat ca orice alt sistem de fișiere:
import os
for entry in os.ilistdir('/rom'):
print(entry)
# Or simply:
print(os.listdir('/rom'))
OpenMV include de asemenea un mic ajutor romfs care afișează o listare formatată ce include adresa memory-mapped și alinierea fiecărui fișier:
from omv import romfs
romfs.ls_romfs()
Imbricarea unui ROMFS în interiorul unui ROMFS¶
O imagine ROMFS stocată ca fișier în interiorul unui ROMFS exterior poate fi montată ca sistem de fișiere imbricat. De exemplu, dacă /rom/inner.romfs există. Deoarece /rom este un ROMFS, obiectele fișier deschise din acesta suportă protocolul de buffer, astfel încât se poate obține direct un memoryview zero-copy:
import vfs
with open('/rom/inner.romfs', 'rb') as f:
inner = vfs.VfsRom(memoryview(f))
vfs.mount(inner, '/inner')
print(os.listdir('/inner'))
Formatul imaginii ROMFS¶
Formatul imaginii ROMFS este un format binar compact, conceput pentru acces memory-mapped pe microcontrolere. O scurtă prezentare:
Imaginea începe cu octeții magici
0xd2 0xcd 0x31(codificați ca"RM1"cu biții superiori ai primilor doi octeți setați).Restul imaginii este compus din înregistrări, fiecare având o etichetă de tip (varuint), o lungime (varuint) și o sarcină utilă.
Tipurile de înregistrări includ: umplutură, date verbatim, pointer de date indirect, director, fișier.
Numele directoarelor și fișierelor sunt stocate ca șiruri de octeți prefixate cu lungime.
Datele fișierului pot fi stocate verbatim (inline) sau printr-un pointer indirect către altă locație din imagine, ceea ce permite alinierea pentru accesul memory-mapped.
Tipurile de înregistrări necunoscute sunt omise în mod silențios, asigurând compatibilitatea în avans.
Acest format este definit în extmod/vfs_rom.c în sursa MicroPython. Implementarea Python folosită de mpremote pentru a construi imagini se află în tools/mpremote/mpremote/romfs.py.
Vezi și
Lucrul cu sistemele de fișiere – Prezentare generală a VFS-ului MicroPython și a tipurilor de sisteme de fișiere disponibile.
Fișierele manifest MicroPython – Cum să înghețați module Python în firmware.
Fișiere .mpy MicroPython – Formatul fișierelor binare .mpy MicroPython.
Control la distanță MicroPython: mpremote – Referința completă a comenzilor mpremote.
romfs – Ajutor OpenMV pentru inspectarea sistemului de fișiere montat /rom.