การทำงานกับ ROMFS¶
ภาพรวม¶
ROMFS (Read-Only Memory Filesystem) คือระบบไฟล์แบบอ่านอย่างเดียวที่มีน้ำหนักเบา ออกแบบมาสำหรับอุปกรณ์ MicroPython โดยเฉพาะ เหมาะสำหรับไมโครคอนโทรลเลอร์และระบบฝังตัวที่ต้องเก็บโค้ดและข้อมูลไว้ในหน่วยความจำแฟลช และเข้าถึงได้อย่างมีประสิทธิภาพโดยไม่ต้องคัดลอกเข้า RAM
ประโยชน์หลักของ ROMFS ได้แก่:
การนำเข้าแบบ Zero-copy: ไฟล์ไบต์โค้ด
.mpyที่เก็บอยู่ใน ROMFS สามารถรันได้โดยตรงจากหน่วยความจำแฟลช (memory-mapped) โดยไม่ต้องคัดลอกเข้า RAM ก่อน ซึ่งคล้ายกับวิธีการทำงานของ frozen modules แต่ไม่จำเป็นต้องแฟลช เฟิร์มแวร์ทั้งหมดใหม่RAM overhead ต่ำ: อ็อบเจกต์ค่าคงที่ (สตริง, bytes เป็นต้น) ในไฟล์
.mpyที่โหลดจาก ROMFS จะอ้างอิงโดยตรงจากแฟลช ไม่มีการซ้ำซ้อนใน RAMการปรับใช้ที่ยืดหยุ่น: สามารถสร้างอิมเมจ ROMFS บน PC แม่ข่ายแล้วปรับใช้กับอุปกรณ์ผ่าน mpremote โดยไม่ต้องสร้าง เฟิร์มแวร์ใหม่
อินเทอร์เฟซระบบไฟล์มาตรฐาน: ROMFS ถูก mount ใน VFS และเข้าถึงได้ผ่านการดำเนินการไฟล์ Python ปกติ (
open,os.listdir,importเป็นต้น)
ROMFS เป็นส่วนเสริมทั้งระบบไฟล์ FAT/LittleFS แบบอ่าน-เขียน (ซึ่งอยู่ในพาร์ทิชันแฟลชอื่น) และ frozen modules (ซึ่งถูกคอมไพล์เข้าไปใน เฟิร์มแวร์โดยตรง)
การรองรับบอร์ด¶
ROMFS ถูกเปิดใช้งานใน เฟิร์มแวร์ OpenMV บนบอร์ดกล้องทุกรุ่นที่มีพาร์ทิชัน ROMFS สำรองไว้ในเลย์เอาต์แฟลช บนบอร์ดเหล่านี้ พาร์ทิชัน ROMFS จะถูกตรวจจับอัตโนมัติตอนบูตและ mount ที่ /rom พร้อมกันนั้น /rom และ /rom/lib จะถูกเพิ่มเข้า sys.path เพื่อให้สามารถ import โมดูลที่เก็บอยู่ที่นั่นได้โดยตรง
บอร์ด |
การรองรับ 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 ที่ mount ไว้ที่ /rom
ขั้นตอนการทำงาน¶
ขั้นตอนทั่วไปสำหรับการใช้ ROMFS มีดังนี้:
สร้างไดเรกทอรีบน PC ของคุณพร้อมไฟล์ Python (หรือไฟล์
.mpy) ที่ต้องการปรับใช้ใช้
mpremote romfs deploy <directory>เพื่อสร้างและปรับใช้อิมเมจ ROMFS กับอุปกรณ์ROMFS จะถูก mount ที่
/romในการบูตครั้งถัดไป (หรือสามารถ mount ได้ทันทีหากรีบูตอุปกรณ์)โค้ด Python บนอุปกรณ์สามารถ
importโมดูลจาก ROMFS ได้เหมือนกับระบบไฟล์อื่น ๆ
ตัวอย่าง:
# On the host PC, with a directory "myapp/" containing app.py:
$ mpremote romfs deploy myapp/
หลังจาก soft-reset อุปกรณ์จะมี /rom/app.py (หรือ /rom/app.mpy หากติดตั้ง mpy_cross ไว้) พร้อมสำหรับการ import
ดูส่วน mpremote romfs sub-commands ด้านล่างสำหรับรายละเอียดทั้งหมดของ sub-commands mpremote
Python API¶
ROMFS Python API ให้บริการผ่านโมดูล vfs
- class vfs.VfsRom(buffer)
สร้าง อ็อบเจกต์ระบบไฟล์ ROMFS จาก buffer ซึ่งต้องเป็นอ็อบเจกต์ที่รองรับ buffer protocol (เช่น อ็อบเจกต์
bytes,bytearrayหรือmemoryview) ที่ประกอบด้วยอิมเมจ ROMFS ที่ถูกต้องคอนสตรักเตอร์จะตรวจสอบว่า buffer เริ่มต้นด้วย magic bytes ของ ROMFS (
b"\xd2\xcd\x31") หาก buffer มีขนาดเล็กเกินไปหรือไม่ใช่ ROMFS ที่ถูกต้อง จะเกิดOSError(ENODEV)อ็อบเจกต์ที่สร้างโดยคอนสตรักเตอร์นี้สามารถ mount ได้โดยใช้
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')
หรือ mount อิมเมจ 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()สำหรับไฟล์ไบนารีที่เปิดในโหมดอ่าน อ็อบเจกต์ที่ส่งกลับมายังรองรับ buffer protocol เพื่อให้สามารถรับmemoryviewของข้อมูลไฟล์ได้ ซึ่งอ้างอิงโดยตรงไปยังหน่วยความจำ ROMFS (zero-copy)
- VfsRom.ilistdir(path)
ส่งคืนตัววนซ้ำผ่านรายการในไดเรกทอรี path แต่ละรายการเป็น tuple
(name, type, inode, size)โดย type คือ0x8000สำหรับไฟล์หรือ0x4000สำหรับไดเรกทอรี
- VfsRom.stat(path)
ส่งคืน tuple 10 ค่าคล้าย
os.statสำหรับ path เกิดOSError(ENOENT)หากไม่พบ path
- VfsRom.statvfs(path)
ส่งคืนสถิติระบบไฟล์ ขนาดบล็อกถูกรายงานเป็น 1 และจำนวนบล็อกแสดงขนาดรวมของอิมเมจ ROMFS เป็นไบต์ บล็อกว่างและไฟล์ว่างจะเป็น 0 เสมอ (ระบบไฟล์แบบอ่านอย่างเดียว)
- VfsRom.chdir(path)
เปลี่ยนไดเรกทอรีภายใน ROMFS รองรับเฉพาะ root (
'/') เท่านั้น การเปลี่ยนไปยัง subdirectory ใด ๆ จะเกิดOSError(EOPNOTSUPP)
- VfsRom.getcwd()
ส่งคืนไดเรกทอรีทำงานปัจจุบันภายใน ROMFS จะส่งคืน
'/'เสมอ
- vfs.rom_ioctl(op, ...)
อินเทอร์เฟซระดับต่ำสำหรับเข้าถึงพาร์ทิชัน read-only memory (ROM) ของอุปกรณ์
การดำเนินการที่รองรับมีดังนี้:
vfs.rom_ioctl(1)-- ส่งคืนจำนวนพาร์ทิชัน ROM ที่มีอยู่vfs.rom_ioctl(2, id)-- ส่งคืนพาร์ทิชัน ROM ที่มี index id เป็นอ็อบเจกต์memoryviewหน่วยความจำสามารถอ่านได้แต่ไม่สามารถเขียนโดยตรงได้vfs.rom_ioctl(3, id, length)-- เตรียมพาร์ทิชัน ROM สำหรับการเขียน ลบ length ไบต์แรกของพาร์ทิชันที่มี index id ส่งคืนขนาดการเขียนขั้นต่ำเป็นไบต์ (การจัดตำแหน่งที่จำเป็นสำหรับการเขียนครั้งถัดไป)vfs.rom_ioctl(4, id, offset, buf)-- เขียน buf (อ็อบเจกต์คล้าย bytes) ไปยังพาร์ทิชัน ROM ที่มี index id ที่ byte offsetvfs.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")
การ mount อัตโนมัติตอนบูต¶
เมื่อเปิดใช้งานการรองรับ ROMFS ใน เฟิร์มแวร์ MicroPython จะพยายาม mount พาร์ทิชัน ROM แรกที่ /rom โดยอัตโนมัติระหว่างการเริ่มต้นระบบ หากพาร์ทิชันมีอิมเมจ ROMFS ที่ถูกต้อง ระบบจะ mount และเพิ่มทั้ง /rom และ /rom/lib เข้า sys.path โดยอัตโนมัติ
ซึ่งหมายความว่าหลังจากปรับใช้อิมเมจ ROMFS ด้วย mpremote การ soft-reset เพียงครั้งเดียวก็เพียงพอที่จะทำให้โมดูลใหม่ import ได้
หากไม่พบอิมเมจ ROMFS ที่ถูกต้องในพาร์ทิชัน (เช่น บนบอร์ดที่เพิ่งโปรแกรมใหม่) การ mount จะถูกข้ามอย่างเงียบ ๆ
การใช้ mpremote เพื่อจัดการ ROMFS¶
เครื่องมือ mpremote มี sub-commands สามรายการสำหรับจัดการอิมเมจ ROMFS บนอุปกรณ์ที่เชื่อมต่อ
romfs query¶
$ mpremote romfs query
แสดงรายการพาร์ทิชัน ROMFS ทั้งหมดที่มีอยู่บนอุปกรณ์และขนาดของแต่ละพาร์ทิชัน นอกจากนี้ยังแสดง 12 ไบต์แรกของแต่ละพาร์ทิชันในรูปแบบ hex และรายงานว่ามีอิมเมจ 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 บน PC แม่ข่าย อิมเมจจะถูกเขียนไปยัง output (ค่าเริ่มต้น: <source>.romfs)
ตัวเลือก:
-o <output>,--output <output>: ระบุ path ไฟล์ผลลัพธ์-m,--mpy(ค่าเริ่มต้น): คอมไพล์ไฟล์.pyเป็น.mpyโดยอัตโนมัติโดยใช้mpy_crossก่อนเพิ่มเข้าอิมเมจ ต้องติดตั้ง Python packagempy_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>: ระบุ index พาร์ทิชันเป้าหมาย (ค่าเริ่มต้น:0)-m,--mpy(ค่าเริ่มต้น): คอมไพล์.pyเป็น.mpyเมื่อ source เป็นไดเรกทอรี--no-mpy: ปิดการคอมไพล์ไฟล์.pyอัตโนมัติ
หลังการปรับใช้ อุปกรณ์ต้องถูก soft-reset เพื่อให้ ROMFS ใหม่ถูก mount ที่ /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/
หลังจาก soft-reset โมดูลสามารถ import ได้จาก ROMFS:
import main
import utils
from lib import helper
การแสดงเนื้อหา ROMFS จาก Python¶
หลังจาก mount สามารถสำรวจเนื้อหา ROMFS ได้เหมือนกับระบบไฟล์อื่น ๆ:
import os
for entry in os.ilistdir('/rom'):
print(entry)
# Or simply:
print(os.listdir('/rom'))
OpenMV ยังมี helper romfs ขนาดเล็กที่แสดงรายการที่จัดรูปแบบรวมถึงที่อยู่ memory-mapped และการจัดตำแหน่งของแต่ละไฟล์:
from omv import romfs
romfs.ls_romfs()
การซ้อน ROMFS ภายใน ROMFS¶
อิมเมจ ROMFS ที่เก็บเป็นไฟล์ภายใน ROMFS ภายนอกสามารถ mount เป็นระบบไฟล์ซ้อนกันได้ ตัวอย่างเช่น หากมี /rom/inner.romfs เนื่องจาก /rom เป็น ROMFS อ็อบเจกต์ไฟล์ที่เปิดจากมันจะรองรับ buffer protocol ดังนั้นจึงสามารถรับ 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'))
รูปแบบอิมเมจ ROMFS¶
รูปแบบอิมเมจ ROMFS เป็นรูปแบบไบนารีขนาดกะทัดรัดออกแบบมาสำหรับการเข้าถึงแบบ memory-mapped บนไมโครคอนโทรลเลอร์ ภาพรวมสั้น ๆ:
อิมเมจเริ่มต้นด้วย magic bytes
0xd2 0xcd 0x31(เข้ารหัสเป็น"RM1"โดยมีบิตสูงของสองไบต์แรกถูกตั้งค่า)ส่วนที่เหลือของอิมเมจประกอบด้วย records แต่ละรายการมี type tag (varuint), ความยาว (varuint) และ payload
ประเภทของ record ได้แก่: padding, verbatim data, indirect data pointer, directory, file
ชื่อไดเรกทอรีและไฟล์ถูกเก็บเป็น byte strings ที่นำหน้าด้วยความยาว
ข้อมูลไฟล์สามารถเก็บแบบ verbatim (inline) หรือผ่าน indirect pointer ไปยังตำแหน่งอื่นในอิมเมจ ซึ่งช่วยให้จัดตำแหน่งสำหรับการเข้าถึงแบบ memory-mapped
ประเภท record ที่ไม่รู้จักจะถูกข้ามอย่างเงียบ ๆ เพื่อรองรับความเข้ากันได้ในอนาคต
รูปแบบนี้ถูกกำหนดไว้ใน extmod/vfs_rom.c ในซอร์สโค้ดของ MicroPython การใช้งาน Python ที่ mpremote ใช้สร้างอิมเมจอยู่ใน tools/mpremote/mpremote/romfs.py
See also
การทำงานกับระบบไฟล์ -- ภาพรวมของ MicroPython VFS และประเภทระบบไฟล์ที่รองรับ
ไฟล์แมนิเฟสต์ของ MicroPython -- วิธีการ freeze โมดูล Python เข้าใน เฟิร์มแวร์
ไฟล์ .mpy ของ MicroPython -- รูปแบบไฟล์ไบนารี .mpy ของ MicroPython
MicroPython การควบคุมระยะไกล: mpremote -- เอกสารอ้างอิงคำสั่ง mpremote ฉบับสมบูรณ์
romfs -- helper ของ OpenMV สำหรับตรวจสอบระบบไฟล์ /rom ที่ mount ไว้