ROMFS ile Çalışma

Genel Bakış

ROMFS (Read-Only Memory Filesystem), MicroPython cihazları için tasarlanmış hafif, salt okunur bir dosya sistemidir. Kod ve verinin flash bellekte saklanması ve RAM’e kopyalanmadan verimli bir şekilde erişilmesi gereken mikrodenetleyiciler ve gömülü sistemler için optimize edilmiştir.

ROMFS’in başlıca avantajları şunlardır:

  • Sıfır kopyalı içe aktarmalar: Bir ROMFS içinde saklanan .mpy bytecode dosyaları, önce RAM’e kopyalanmak yerine doğrudan flash bellekten (bellekle eşlenmiş) çalıştırılabilir. Bu, dondurulmuş modüllerin çalışma şekline benzer, ancak tüm aygıt yazılımının (firmware) yeniden flash’lanmasını gerektirmez.

  • Düşük RAM yükü: ROMFS’ten yüklenen .mpy dosyalarındaki sabit nesneler (dizeler, baytlar vb.) RAM’de çoğaltılmaz, doğrudan flash bellekten referans alınır.

  • Esnek dağıtım: Bir ROMFS imajı bir ana bilgisayar PC’sinde oluşturulabilir ve aygıt yazılımını yeniden derlemeye gerek kalmadan mpremote kullanılarak cihaza dağıtılabilir.

  • Standart dosya sistemi arabirimi: Bir ROMFS, VFS içine bağlanır ve normal Python dosya işlemleri (open, os.listdir, import vb.) aracılığıyla erişilir.

ROMFS, hem okuma-yazma FAT/LittleFS dosya sistemlerini (bunlar diğer flash bölümlerinde bulunur) hem de dondurulmuş modülleri (bunlar doğrudan aygıt yazılımının içine derlenir) tamamlar.

Kart desteği

ROMFS, flash düzeninde ayrılmış bir ROMFS bölümü olan her kamera kartında OpenMV aygıt yazılımında etkindir. Bu kartlarda ROMFS bölümü önyükleme sırasında otomatik olarak algılanır ve /rom konumuna bağlanır; orada saklanan modüllerin doğrudan içe aktarılabilmesi için hem /rom hem de /rom/lib sys.path‘e eklenir.

Kart

ROMFS desteği

OpenMV Cam N6

Evet

OpenMV AE3

Evet

OpenMV Cam RT1062

Evet

OpenMV Cam Pure Thermal

Evet

OpenMV Cam M4 / M7 / H7 / H7 Plus

Evet

Arduino Giga

Evet

Arduino Portenta H7

Evet

Arduino Nicla Vision

Evet

Arduino Nano 33 BLE Sense

Hayır (ROMFS bölümü yok)

Arduino Nano RP2040 Connect

Hayır (ROMFS bölümü yok)

/rom konumuna bağlanmış ROMFS’i inceleyen OpenMV’ye özgü bir yardımcı için romfs bölümüne bakın.

İş Akışı

ROMFS kullanmaya yönelik tipik iş akışı şöyledir:

  1. PC’nizde, dağıtmak istediğiniz Python dosyalarını (veya .mpy dosyalarını) içeren bir dizin oluşturun.

  2. ROMFS imajını oluşturup cihaza dağıtmak için mpremote romfs deploy <directory> komutunu kullanın.

  3. ROMFS, bir sonraki önyüklemede /rom konumuna bağlanır (veya cihaz yeniden başlatılırsa hemen bağlanabilir).

  4. Cihazdaki Python kodu, ardından ROMFS’ten modülleri tıpkı başka herhangi bir dosya sisteminden olduğu gibi import edebilir.

Örneğin:

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

Bir yazılım sıfırlamasından sonra cihazda içe aktarılmaya hazır /rom/app.py (veya mpy_cross yüklüyse /rom/app.mpy) bulunur.

mpremote alt komutlarının tüm ayrıntıları için aşağıdaki mpremote romfs alt komutları bölümüne bakın.

Python API’si

ROMFS Python API’si vfs modülü aracılığıyla sağlanır.

class vfs.VfsRom(buffer)

Geçerli bir ROMFS imajı içeren ve arabellek protokolünü destekleyen bir nesne (örneğin bir bytes, bytearray veya memoryview nesnesi) olması gereken buffer‘dan bir ROMFS dosya sistemi nesnesi oluşturur.

Yapıcı, buffer‘ın ROMFS sihirli baytlarıyla (b"\xd2\xcd\x31") başladığını doğrular. Arabellek çok küçükse veya geçerli bir ROMFS değilse OSError(ENODEV) hatası ortaya çıkar.

Bu yapıcı tarafından oluşturulan nesneler vfs.mount() kullanılarak bağlanabilir.

Örnek:

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

Veya bir dosyada saklanan bir ROMFS imajını bağlamak için:

import vfs

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

Bir VfsRom nesnesinde aşağıdaki yöntemler mevcuttur:

VfsRom.open(path, mode)

ROMFS’ten bir dosya açar. Yalnızca okuma modları ('', 'r', 'rt', 'rb') desteklenir. Bir dosyayı yazma için açmaya çalışmak OSError(EROFS) hatasını ortaya çıkarır.

Döndürülen dosya nesnesi read(), seek(), tell() ve close() işlemlerini destekler. Okuma modunda açılan ikili dosyalar için döndürülen nesne aynı zamanda arabellek protokolünü de destekler; böylece dosya verisinin, doğrudan ROMFS belleğine işaret eden (sıfır kopyalı) bir memoryview‘i elde edilebilir.

VfsRom.ilistdir(path)

path dizinindeki girdiler üzerinde bir yineleyici döndürür. Her girdi bir (name, type, inode, size) demetidir; burada type, bir dosya için 0x8000 veya bir dizin için 0x4000 değerini alır.

VfsRom.stat(path)

path için os.stat benzeri 10 elemanlı bir demet döndürür. Yol mevcut değilse OSError(ENOENT) hatasını ortaya çıkarır.

VfsRom.statvfs(path)

Dosya sistemi istatistiklerini döndürür. Blok boyutu 1 olarak bildirilir ve blok sayısı, ROMFS imajının bayt cinsinden toplam boyutunu temsil eder. Boş bloklar ve boş dosyalar her zaman 0’dır (salt okunur dosya sistemi).

VfsRom.chdir(path)

ROMFS içinde dizin değiştirir. Yalnızca kök ('/') desteklenir; herhangi bir alt dizine geçmek OSError(EOPNOTSUPP) hatasını ortaya çıkarır.

VfsRom.getcwd()

ROMFS içindeki geçerli çalışma dizinini döndürür. Her zaman '/' döndürür.

vfs.rom_ioctl(op, ...)

Cihazın salt okunur bellek (ROM) bölüm(ler)ine erişmek için düşük seviyeli arabirim.

Desteklenen işlemler şunlardır:

  • vfs.rom_ioctl(1) – Kullanılabilir ROM bölümlerinin sayısını döndürür.

  • vfs.rom_ioctl(2, id)id indeksine sahip ROM bölümünü bir memoryview nesnesi olarak döndürür. Bellek okunabilir ancak doğrudan yazılamaz.

  • vfs.rom_ioctl(3, id, length) – Bir ROM bölümünü yazmaya hazırlar. id indeksine sahip bölümün ilk length baytını siler. Bayt cinsinden minimum yazma boyutunu (sonraki yazmalar için gereken hizalama) döndürür.

  • vfs.rom_ioctl(4, id, offset, buf)buf‘ı (bayt benzeri bir nesne) id indeksine sahip ROM bölümüne offset baytı konumunda yazar.

  • vfs.rom_ioctl(5, id)id bölümüne bir yazma dizisini tamamlar (yazma sonrası gereken, önbellek temizleme gibi her türlü sonlandırma işlemini gerçekleştirir).

Bu işlemler, ROMFS imajlarını dağıtmak için mpremote tarafından dahili olarak kullanılır. Çoğu kullanıcının vfs.rom_ioctl()‘yi doğrudan çağırmasına gerek yoktur.

Örnek (kullanılabilir bölümlerin sorgulanması):

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

Önyüklemede otomatik bağlama

ROMFS desteği aygıt yazılımında etkin olduğunda, MicroPython başlatma sırasında ilk ROM bölümünü otomatik olarak /rom konumuna bağlamaya çalışır. Bölüm geçerli bir ROMFS imajı içeriyorsa bağlanır ve hem /rom hem de /rom/lib otomatik olarak sys.path‘e eklenir.

Bu, mpremote ile bir ROMFS imajı dağıttıktan sonra yeni modülleri içe aktarılabilir hale getirmek için bir yazılım sıfırlamasının yeterli olduğu anlamına gelir.

Bölümde geçerli bir ROMFS imajı bulunamazsa (örneğin yeni programlanmış bir kartta), bağlama işlemi sessizce atlanır.

ROMFS’i yönetmek için mpremote kullanma

mpremote aracı, bağlı bir cihazdaki ROMFS imajlarını yönetmek için üç alt komut sağlar.

romfs query

$ mpremote romfs query

Cihazdaki kullanılabilir tüm ROMFS bölümlerini ve boyutlarını listeler. Ayrıca her bölümün ilk 12 baytını onaltılık olarak gösterir ve geçerli bir ROMFS imajının mevcut olup olmadığını bildirir.

Örnek çıktı:

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>

Ana bilgisayar PC’sindeki source dizininden bir ROMFS imajı oluşturur. İmaj output‘a yazılır (varsayılan: <source>.romfs).

Seçenekler:

  • -o <output>, --output <output>: Çıktı dosyası yolunu belirtir.

  • -m, --mpy (varsayılan): İmaja eklemeden önce .py dosyalarını mpy_cross kullanarak otomatik olarak .mpy dosyalarına derler. mpy_cross Python paketini gerektirir (pip install mpy_cross).

  • --no-mpy: .py dosyalarının otomatik derlenmesini devre dışı bırakır.

Örnek:

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

Bir ROMFS imajını cihaza dağıtır. source şunlardan biri olabilir:

  • Ana bilgisayardaki bir dizin: ROMFS imajı bellekte oluşturulur ve doğrudan dağıtılır.

  • Bir .romfs veya .img dosyası: imaj diskten okunur ve dağıtılır.

Seçenekler:

  • -p <partition>, --partition <partition>: Hedef bölüm indeksini belirtir (varsayılan: 0).

  • -m, --mpy (varsayılan): source bir dizin olduğunda .py dosyalarını .mpy‘ye derler.

  • --no-mpy: .py dosyalarının otomatik derlenmesini devre dışı bırakır.

Dağıtımdan sonra, yeni ROMFS’in /rom konumuna bağlanması için cihazın yazılım sıfırlamasından geçmesi gerekir.

Örnek:

$ 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

Örnekler

Basit bir uygulamanın dağıtılması

Aşağıdaki yapıya sahip bir myapp/ proje diziniz olduğunu varsayalım:

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

Bunu cihazın ROMFS’ine dağıtmak için:

$ mpremote romfs deploy myapp/

Bir yazılım sıfırlamasından sonra modüller ROMFS’ten içe aktarılabilir:

import main
import utils
from lib import helper

ROMFS içeriğinin Python’dan listelenmesi

Bağladıktan sonra, ROMFS içeriği tıpkı başka herhangi bir dosya sistemi gibi keşfedilebilir:

import os

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

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

OpenMV ayrıca her dosyanın bellekle eşlenmiş adresi ve hizalaması dahil biçimlendirilmiş bir liste yazdıran küçük bir romfs yardımcısı da sunar:

from omv import romfs
romfs.ls_romfs()

Bir ROMFS’i bir ROMFS içine yerleştirme

Bir dış ROMFS içinde dosya olarak saklanan bir ROMFS imajı, iç içe bir dosya sistemi olarak bağlanabilir. Örneğin, /rom/inner.romfs mevcutsa. /rom bir ROMFS olduğundan, ondan açılan dosya nesneleri arabellek protokolünü destekler; böylece sıfır kopyalı bir memoryview doğrudan elde edilebilir:

import vfs

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

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

ROMFS imaj biçimi

ROMFS imaj biçimi, mikrodenetleyicilerde bellekle eşlenmiş erişim için tasarlanmış kompakt bir ikili biçimdir. Kısa bir genel bakış:

  • İmaj, 0xd2 0xcd 0x31 sihirli baytlarıyla başlar (ilk iki baytın yüksek bitleri ayarlanmış olarak "RM1" şeklinde kodlanmıştır).

  • İmajın geri kalanı, her biri bir tür etiketi (varuint), bir uzunluk (varuint) ve bir veri yükü içeren kayıtlardan oluşur.

  • Kayıt türleri şunları içerir: dolgu, birebir veri, dolaylı veri işaretçisi, dizin, dosya.

  • Dizin ve dosya adları, uzunluk önekli bayt dizileri olarak saklanır.

  • Dosya verisi birebir (satır içi) olarak ya da imajın başka bir yerine işaret eden dolaylı bir işaretçi aracılığıyla saklanabilir; bu da bellekle eşlenmiş erişim için hizalamayı mümkün kılar.

  • Bilinmeyen kayıt türleri sessizce atlanır ve böylece ileriye dönük uyumluluk sağlanır.

Bu biçim, MicroPython kaynak kodundaki extmod/vfs_rom.c içinde tanımlanmıştır. İmajları oluşturmak için mpremote tarafından kullanılan Python uygulaması tools/mpremote/mpremote/romfs.py içindedir.

Ayrıca bakınız

Dosya sistemleriyle çalışma – MicroPython VFS’ine ve kullanılabilir dosya sistemi türlerine genel bakış.

MicroPython manifest dosyaları – Python modüllerinin aygıt yazılımına nasıl dondurulacağı.

MicroPython .mpy dosyaları – MicroPython .mpy ikili dosya biçimi.

MicroPython uzaktan kontrol: mpremote – Tam mpremote komut başvurusu.

romfs – Bağlanmış /rom dosya sistemini incelemek için OpenMV yardımcısı.