العمل مع ROMFS

نظرة عامة

ROMFS (نظام ملفات الذاكرة للقراءة فقط) هو نظام ملفات خفيف الوزن للقراءة فقط مصمم لأجهزة MicroPython. وهو محسّن للمتحكمات الدقيقة والأنظمة المضمّنة حيث يلزم تخزين الشيفرة والبيانات في ذاكرة فلاش والوصول إليها بكفاءة دون نسخها إلى RAM.

تتمثل الفوائد الرئيسية لـ ROMFS فيما يلي:

  • الاستيراد بدون نسخ: يمكن تنفيذ ملفات الشيفرة الثنائية .mpy المخزّنة في ROMFS مباشرة من ذاكرة فلاش (مُسقَطة في الذاكرة) بدلاً من نسخها أولاً إلى RAM. وهذا مشابه لطريقة عمل الوحدات المجمّدة، لكنه لا يتطلب إعادة تحميل البرنامج الثابت بالكامل.

  • انخفاض استهلاك RAM: تُشار الكائنات الثابتة (السلاسل النصية والبايتات وما إلى ذلك) في ملفات .mpy المحمّلة من ROMFS مباشرة من ذاكرة فلاش، ولا تُكرّر في RAM.

  • نشر مرن: يمكن بناء صورة ROMFS على حاسوب مضيف ونشرها على الجهاز باستخدام mpremote، دون إعادة بناء البرنامج الثابت.

  • واجهة نظام ملفات قياسية: تُركَّب ROMFS في VFS ويُوصَل إليها عبر عمليات ملفات Python العادية (open وos.listdir وimport وما إلى ذلك).

تُعد ROMFS مكمّلة لكل من أنظمة ملفات FAT/LittleFS القابلة للقراءة والكتابة (التي توجد في أقسام فلاش أخرى) ولـ الوحدات المجمّدة (التي تُجمَّع داخل البرنامج الثابت نفسه).

دعم اللوحات

تكون ROMFS ممكّنة في برنامج OpenMV الثابت على كل لوحة كاميرا تحتوي على قسم ROMFS محجوز في تخطيط ذاكرة فلاش الخاص بها. على هذه اللوحات يُكتشف قسم ROMFS تلقائياً عند الإقلاع ويُركَّب عند /rom؛ ويُضاف كل من /rom و/rom/lib إلى sys.path بحيث يمكن استيراد الوحدات المخزّنة هناك مباشرة.

اللوحة

دعم ROMFS

OpenMV Cam N6

نعم

OpenMV AE3

نعم

OpenMV Cam RT1062

نعم

OpenMV Cam Pure Thermal

نعم

OpenMV Cam M4 / M7 / H7 / H7 Plus

نعم

Arduino Giga

نعم

Arduino Portenta H7

نعم

Arduino Nicla Vision

نعم

Arduino Nano 33 BLE Sense

لا (لا يوجد قسم ROMFS)

Arduino Nano RP2040 Connect

لا (لا يوجد قسم ROMFS)

راجع romfs للحصول على أداة مساعدة خاصة بـ OpenMV تفحص ROMFS المُركَّبة عند /rom.

سير العمل

سير العمل النموذجي لاستخدام ROMFS هو:

  1. أنشئ دليلاً على حاسوبك يحتوي على ملفات Python (أو ملفات .mpy) التي تريد نشرها.

  2. استخدم mpremote romfs deploy <directory> لبناء صورة ROMFS ونشرها على الجهاز.

  3. ستُركَّب ROMFS عند /rom في الإقلاع التالي (أو يمكن تركيبها فوراً إذا أُعيد إقلاع الجهاز).

  4. يمكن لشيفرة Python على الجهاز بعد ذلك import الوحدات من ROMFS تماماً كما من أي نظام ملفات آخر.

على سبيل المثال:

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

بعد إعادة تعيين برمجية، سيكون لدى الجهاز /rom/app.py (أو /rom/app.mpy إذا كان mpy_cross مثبتاً) متاحاً للاستيراد.

راجع قسم الأوامر الفرعية mpremote romfs أدناه للحصول على التفاصيل الكاملة للأوامر الفرعية لـ mpremote.

واجهة برمجة تطبيقات Python

تُوفَّر واجهة برمجة تطبيقات Python الخاصة بـ ROMFS عبر الوحدة vfs.

class vfs.VfsRom(buffer)

أنشئ كائن نظام ملفات ROMFS من buffer، الذي يجب أن يكون كائناً يدعم بروتوكول المخزن المؤقت (مثل كائن bytes أو bytearray أو memoryview) يحتوي على صورة ROMFS صالحة.

يتحقق المُنشئ من أن buffer يبدأ ببايتات ROMFS السحرية (b"\xd2\xcd\x31"). إذا كان المخزن المؤقت صغيراً جداً أو ليس ROMFS صالحة، فسيُطلَق OSError(ENODEV).

يمكن تركيب الكائنات التي ينشئها هذا المُنشئ باستخدام vfs.mount().

مثال:

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

أو، لتركيب صورة ROMFS مخزّنة في ملف:

import vfs

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

الأساليب التالية متاحة على كائن VfsRom:

VfsRom.open(path, mode)

افتح ملفاً من ROMFS. لا تُدعم إلا أوضاع القراءة ('' و'r' و'rt' و'rb'). ستؤدي محاولة فتح ملف للكتابة إلى إطلاق OSError(EROFS).

يدعم كائن الملف المُعاد read() وseek() وtell() وclose(). بالنسبة للملفات الثنائية المفتوحة في وضع القراءة، يدعم الكائن المُعاد أيضاً بروتوكول المخزن المؤقت بحيث يمكن الحصول على memoryview لبيانات الملف، والتي تشير مباشرة إلى ذاكرة ROMFS (بدون نسخ).

VfsRom.ilistdir(path)

أعِد مكرّراً على المدخلات في الدليل path. كل مدخل عبارة عن صف (name, type, inode, size) حيث type هو 0x8000 للملف أو 0x4000 للدليل.

VfsRom.stat(path)

أعِد صفاً عشارياً يشبه os.stat لـ path. يُطلق OSError(ENOENT) إذا كان المسار غير موجود.

VfsRom.statvfs(path)

أعِد إحصاءات نظام الملفات. يُبلَّغ عن حجم الكتلة بالقيمة 1 ويمثّل عدد الكتل الحجم الإجمالي لصورة ROMFS بالبايتات. تكون الكتل الحرة والملفات الحرة دائماً 0 (نظام ملفات للقراءة فقط).

VfsRom.chdir(path)

غيّر الدليل داخل ROMFS. لا يُدعم إلا الجذر ('/')؛ يؤدي التغيير إلى أي دليل فرعي إلى إطلاق OSError(EOPNOTSUPP).

VfsRom.getcwd()

أعِد دليل العمل الحالي داخل ROMFS. يُعيد دائماً '/'.

vfs.rom_ioctl(op, ...)

واجهة منخفضة المستوى للوصول إلى أقسام ذاكرة القراءة فقط (ROM) في الجهاز.

العمليات المدعومة هي:

  • vfs.rom_ioctl(1) -- أعِد عدد أقسام ROM المتاحة.

  • vfs.rom_ioctl(2, id) -- أعِد قسم ROM ذا الفهرس id ككائن memoryview. يمكن قراءة الذاكرة لكن لا يمكن الكتابة إليها مباشرة.

  • vfs.rom_ioctl(3, id, length) -- جهّز قسم ROM للكتابة. يمحو أول length بايتاً من القسم ذي الفهرس id. يُعيد الحد الأدنى لحجم الكتابة بالبايتات (المحاذاة المطلوبة للكتابات اللاحقة).

  • vfs.rom_ioctl(4, id, offset, buf) -- اكتب buf (كائن يشبه البايتات) إلى قسم ROM ذي الفهرس id عند البايت offset.

  • vfs.rom_ioctl(5, id) -- أكمِل تسلسل كتابة إلى القسم id (ينفّذ أي إنهاء مطلوب بعد الكتابة، مثل تفريغ ذاكرة التخزين المؤقت).

تُستخدم هذه العمليات داخلياً بواسطة mpremote لنشر صور ROMFS. لا يحتاج معظم المستخدمين إلى استدعاء vfs.rom_ioctl() مباشرة.

مثال (الاستعلام عن الأقسام المتاحة):

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

التركيب التلقائي عند الإقلاع

عند تمكين دعم ROMFS في البرنامج الثابت، سيحاول MicroPython تلقائياً تركيب قسم ROM الأول عند /rom أثناء التهيئة. إذا كان القسم يحتوي على صورة ROMFS صالحة، فإنه يُركَّب ويُضاف كل من /rom و/rom/lib إلى sys.path تلقائياً.

هذا يعني أنه بعد نشر صورة ROMFS باستخدام mpremote، تكفي إعادة تعيين برمجية لجعل الوحدات الجديدة قابلة للاستيراد.

إذا لم يُعثر على صورة ROMFS صالحة في القسم (مثلاً على لوحة مبرمجة حديثاً)، فيُتخطّى التركيب بصمت.

استخدام mpremote لإدارة ROMFS

توفّر أداة mpremote ثلاثة أوامر فرعية لإدارة صور ROMFS على جهاز متصل.

romfs query

$ mpremote romfs query

تسرد جميع أقسام ROMFS المتاحة على الجهاز وأحجامها. كما تُظهر أول 12 بايتاً من كل قسم بالنظام الست عشري وتُبلِّغ عما إذا كانت توجد صورة ROMFS صالحة.

مثال على المخرجات:

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>

ابنِ صورة ROMFS من الدليل source على الحاسوب المضيف. تُكتب الصورة إلى output (الافتراضي: <source>.romfs).

الخيارات:

  • -o <output> و--output <output>: حدّد مسار ملف المخرجات.

  • -m و--mpy (افتراضي): جمّع تلقائياً ملفات .py إلى .mpy باستخدام mpy_cross قبل إضافتها إلى الصورة. يتطلب حزمة Python المسماة mpy_cross (pip install mpy_cross).

  • --no-mpy: عطّل التجميع التلقائي لملفات .py.

مثال:

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

انشر صورة ROMFS على الجهاز. يمكن أن يكون source إما:

  • دليلاً على المضيف: تُبنى صورة ROMFS في الذاكرة وتُنشر مباشرة.

  • ملف .romfs أو .img: تُقرأ الصورة من القرص وتُنشر.

الخيارات:

  • -p <partition> و--partition <partition>: حدّد فهرس القسم الهدف (الافتراضي: 0).

  • -m و--mpy (افتراضي): جمّع .py إلى .mpy عندما يكون source دليلاً.

  • --no-mpy: عطّل التجميع التلقائي لملفات .py.

بعد النشر، يجب إعادة تعيين الجهاز برمجياً لتركيب ROMFS الجديدة عند /rom.

مثال:

$ 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

أمثلة

نشر تطبيق بسيط

لنفترض أن لديك دليل مشروع myapp/ بالبنية التالية:

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

لنشره على ROMFS الخاصة بالجهاز:

$ mpremote romfs deploy myapp/

بعد إعادة تعيين برمجية، تصبح الوحدات قابلة للاستيراد من ROMFS:

import main
import utils
from lib import helper

سرد محتويات ROMFS من Python

بعد التركيب، يمكن استكشاف محتويات ROMFS مثل أي نظام ملفات آخر:

import os

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

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

تشحن OpenMV أيضاً أداة مساعدة صغيرة romfs تطبع سرداً منسّقاً يتضمن عنوان الذاكرة المُسقَط ومحاذاة كل ملف:

from omv import romfs
romfs.ls_romfs()

تداخل ROMFS داخل ROMFS

يمكن تركيب صورة ROMFS مخزّنة كملف داخل ROMFS خارجية بوصفها نظام ملفات متداخلاً. على سبيل المثال، إذا كان /rom/inner.romfs موجوداً. ولأن /rom هي ROMFS، فإن كائنات الملفات المفتوحة منها تدعم بروتوكول المخزن المؤقت، بحيث يمكن الحصول على memoryview بدون نسخ مباشرة:

import vfs

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

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

تنسيق صورة ROMFS

تنسيق صورة ROMFS هو تنسيق ثنائي مدمج مصمم للوصول المُسقَط في الذاكرة على المتحكمات الدقيقة. نظرة عامة موجزة:

  • تبدأ الصورة بالبايتات السحرية 0xd2 0xcd 0x31 (المُرمَّزة كـ "RM1" مع ضبط البتات العالية لأول بايتين).

  • يتألف ما تبقى من الصورة من سجلات، لكل منها وسم نوع (varuint) وطول (varuint) وحمولة.

  • تتضمن أنواع السجلات: الحشو، والبيانات الحرفية، ومؤشر البيانات غير المباشر، والدليل، والملف.

  • تُخزَّن أسماء الأدلة والملفات كسلاسل بايتات مسبوقة بالطول.

  • يمكن تخزين بيانات الملف حرفياً (مضمّنة) أو عبر مؤشر غير مباشر إلى مكان آخر في الصورة، مما يتيح المحاذاة للوصول المُسقَط في الذاكرة.

  • تُتخطّى أنواع السجلات غير المعروفة بصمت، مما يوفر توافقاً أمامياً.

يُعرَّف هذا التنسيق في extmod/vfs_rom.c في مصدر MicroPython. أما تنفيذ Python الذي يستخدمه mpremote لبناء الصور فهو في tools/mpremote/mpremote/romfs.py.

شاهد أيضا

العمل مع أنظمة الملفات -- نظرة عامة على VFS الخاص بـ MicroPython وأنواع أنظمة الملفات المتاحة.

ملفات بيان (manifest) في MicroPython -- كيفية تجميد وحدات Python في البرنامج الثابت.

ملفات ‎.mpy‎ في MicroPython -- تنسيق ملف .mpy الثنائي لـ MicroPython.

التحكم عن بُعد في MicroPython: mpremote -- المرجع الكامل لأمر mpremote.

romfs -- أداة OpenMV المساعدة لفحص نظام ملفات /rom المُركَّب.