العمل مع 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 هو:
أنشئ دليلاً على حاسوبك يحتوي على ملفات Python (أو ملفات
.mpy) التي تريد نشرها.استخدم
mpremote romfs deploy <directory>لبناء صورة ROMFS ونشرها على الجهاز.ستُركَّب ROMFS عند
/romفي الإقلاع التالي (أو يمكن تركيبها فوراً إذا أُعيد إقلاع الجهاز).يمكن لشيفرة 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 المُركَّب.