14.2.2.1. การแช่แข็งสคริปต์ลงในเฟิร์มแวร์¶
โมดูล frozen คือไฟล์ .py ที่ถูกคอมไพล์เป็น bytecode และลิงก์เข้าไปในเฟิร์มแวร์ image ณ เวลาสร้าง (build time) รันไทม์จะนำเข้าโมดูล frozen โดยตรงจากแฟลช โดยไม่ต้องค้นหาจากระบบไฟล์บนดิสก์เลย สำหรับผลิตภัณฑ์ที่จัดส่งแล้ว นี่คือตำแหน่งที่เหมาะสมสำหรับโค้ดแอปพลิเคชัน: ผู้ใช้ปลายทางไม่สามารถลบออกได้ ไฟล์ .py เก่าบน SD card ไม่สามารถแทนที่ได้ และกล้องจะรันโค้ดเดิมทุกครั้งที่บูต ไม่ว่าไดรฟ์จะมีอะไรอยู่หรือไม่ก็ตาม
หน้านี้อธิบายลำดับการเริ่มต้น (startup sequence) ที่กล้องปฏิบัติตาม รวมถึงวิธีที่ manifest.py และคำสั่ง freeze ฝังแอปพลิเคชันเข้าสู่การสร้าง
14.2.2.1.1. ลำดับการเริ่มต้น¶
สิ่งที่รันและเมื่อไหร่ เมื่อกล้องออกจาก reset:
บูตโหลดเดอร์ การเปิดเครื่องจะเข้าสู่ช่วง DFU สั้น ๆ ที่ IDE ใช้ในการส่งอัปเดตเฟิร์มแวร์ ช่วงนี้จะปิดลงหลังจากไม่กี่วินาที และบูตโหลดเดอร์จะส่งต่อให้ MicroPython สคริปต์ที่รันอยู่สามารถกลับเข้าสู่ช่วงนี้ได้ตามต้องการโดยเรียก
machine.bootloader()การเริ่มต้นระบบไฟล์ frozen ก่อนที่โค้ดแอปพลิเคชันใด ๆ จะรัน รันไทม์จะเตรียมระบบไฟล์ให้พร้อม โดยแฟลชภายในถูกเมาท์ที่
/flash(และฟอร์แมตว่างเปล่าหากไม่มีข้อมูลอยู่) หาก SD card มีอยู่ และ ไม่มีไฟล์เครื่องหมายSKIPSDบนแฟลชภายใน SD card จะถูกเมาท์ที่/sdcardROMFS เมื่อการสร้างรวมไว้ จะถูกเมาท์อัตโนมัติที่/romไดเรกทอรีทำงานถูกตั้งเป็นไดเรกทอรีบูต (/sdcardหาก card เมาท์แล้ว หรือ/flashหากไม่ได้เมาท์) และsys.pathจะถูกเติมด้วย/flash,/flash/lib,/sdcard,/sdcard/lib,/rom, และ/rom/libการตั้งค่าที่อยู่ในแฟลชจัดการโดยโมดูล frozen ที่ชื่อ_boot.py-- เป็นโครงสร้างพื้นฐานของ port และ board ไม่ใช่ hook ของแอปพลิเคชัน แอปพลิเคชันไม่ควรปรับแต่ง_boot.py; การสร้างเป็นผู้ดูแล การวางSKIPSDลงบนแฟลชจาก IDE คือวิธีที่รองรับเพื่อให้กล้องบูตจากแฟลชภายในแทน SD cardการตั้งค่าก่อน REPL
boot.pyรันทุก soft reset -- การบูตเย็น,Ctrl-Dจาก REPL, เมื่อสคริปต์ที่รันคืนค่า, และการกู้คืนจาก watchdog -- ก่อนที่ REPL จะสามารถเข้าถึงได้ หน้าที่คือเตรียมสภาพแวดล้อมที่ระบบส่วนที่เหลือใช้: การตั้งค่าประเภทที่ REPL, แอปพลิเคชัน, และเครื่องมือกู้คืนต้องการให้พร้อมใช้งาน ไม่ใช่ที่อยู่ของแอปพลิเคชันเองmain.pyคือจุดเริ่มต้นของแอปพลิเคชันลูปหลัก
main.pyคือลูปหลักของแอปพลิเคชัน รันครั้งเดียวเมื่อบูตเย็น หลังจากboot.pyทันที ไม่ รันซ้ำเมื่อ soft reset ในภายหลัง -- กล้องจะตกลงสู่ REPL แทน ความไม่สมมาตรนี้มีความสำคัญในการพัฒนา (Ctrl-D จะตกลงสู่ REPL โดยไม่รันลูปซ้ำ ทำให้นักพัฒนาตรวจสอบสถานะได้) แต่ไม่สำคัญในการผลิต: กล้องที่ใช้งานจริงรับ power-on, watchdog, และ hard reset ซึ่งล้วนเป็น hardware reset ที่เข้าสู่เส้นทางบูตเย็นและรันmain.pyอีกครั้ง
14.2.2.1.2. การแช่แข็งเข้าสู่เฟิร์มแวร์¶
ชุดโมดูล frozen ของบอร์ดถูกประกาศใน boards/<TARGET>/manifest.py ในต้นไม้เฟิร์มแวร์ manifest คือไฟล์ Python ขนาดเล็กที่เรียกใช้คำสั่งไม่กี่อย่าง:
freeze("$(OMV_LIB_DIR)/", "foo.py")-- ฝังfoo.pyไฟล์เดียวเข้าสู่การสร้างpackage("mylib", base_path="...")-- ฝัง Python package หลายไฟล์โดยรักษาโครงสร้างไดเรกทอรีภายใต้ base path ที่กำหนดinclude("...")-- ดึงไฟล์ manifest อื่นเข้ามา บอร์ด manifests ใช้สิ่งนี้เพื่อแบ่งปันชุดโมดูลร่วมกันrequire("logging")-- ดึงโมดูลmicropython-libupstream ที่มีชื่อมาตามชื่อ
manifest แอปพลิเคชันขั้นต่ำจะเพิ่มบรรทัด freeze หนึ่งบรรทัดต่อสคริปต์ระดับบนสุด และบรรทัด package หนึ่งบรรทัดต่อ package ที่แอปพลิเคชันพึ่งพา
14.2.2.1.2.1. ตำแหน่งของซอร์สโค้ด¶
ซอร์สโค้ดแอปพลิเคชันอยู่ใน scripts/libraries/ ในต้นไม้เฟิร์มแวร์ ข้างๆ โมดูลที่การสร้างแช่แข็งไว้แล้ว ตัวแปร manifest $(OMV_LIB_DIR) ขยายไปยังเส้นทางนั้น ทำให้รายการ manifest สั้น การแก้ไข manifest เป็นการดำเนินการภายใน tree อยู่แล้ว ดังนั้นการเก็บซอร์สใน tree ช่วยหลีกเลี่ยงการจัดการ repo โปรเจกต์แยกต่างหากในการแก้ไขเส้นทาง
โครงสร้างทั่วไปสำหรับแอปพลิเคชันที่จัดส่ง main.py ไฟล์เดียวพร้อม package สนับสนุน:
scripts/libraries/
main.py
my_lib/
__init__.py
helpers.py
และใน boards/<TARGET>/manifest.py ของบอร์ด บรรทัด freeze หนึ่งบรรทัดสำหรับสคริปต์ และบรรทัด package หนึ่งบรรทัดสำหรับ package:
freeze("$(OMV_LIB_DIR)/", "main.py")
package("my_lib", base_path="$(OMV_LIB_DIR)/my_lib")
สคริปต์ไฟล์เดียว -- main.py ที่นี่ แต่กฎเดียวกันใช้กับ boot.py หรือ helper แบบ standalone ใด ๆ -- ใช้ freeze Package หลายไฟล์ใช้ package การเพิ่มสคริปต์อื่นคือบรรทัด freeze อีกหนึ่งบรรทัด; การเพิ่ม package อื่นคือบรรทัด package อีกหนึ่งบรรทัด
14.2.2.1.2.2. การสร้างและการแฟลช¶
เมื่อ manifest พร้อมแล้ว ให้สร้างเฟิร์มแวร์ตามที่ บทเฟิร์มแวร์ อธิบายไว้:
make -j$(nproc) -C lib/micropython/mpy-cross # once, builds the cross-compiler
make -j$(nproc) TARGET=<TARGET> # builds the firmware
ผลลัพธ์จะอยู่ใน build/<TARGET>/bin/
build/<TARGET>/bin/
firmware.bin # flash through the IDE
romfs0.img # flash through the IDE in a separate step
การแฟลช .bin และ .img ผ่าน IDE จะทำให้กล้องมีแอปพลิเคชันที่เป็นส่วนหนึ่งของการสร้าง
ลำดับการเริ่มต้นข้างต้นคือสิ่งที่ทำให้การฝังมีประสิทธิภาพ: รันไทม์แก้ไข boot.py และ main.py ไปยังสำเนา frozen ก่อนที่จะตรวจสอบระบบไฟล์ ดังนั้นกล้องที่จัดส่งจะรันโค้ดของการสร้างแม้ว่า SD card จะมี boot.py เก่าจากการพัฒนาก็ตาม
14.2.2.1.2.3. ลำดับการค้นหา¶
ความหมายของการแทนที่ แตกต่างกัน สำหรับเส้นทางการรัน boot.py / main.py และสำหรับคำสั่ง import ทั่วไป การรู้ว่าสิ่งใดเป็นอะไรมีความสำคัญทั้งในการผลิตและการพัฒนา:
สำหรับ
boot.pyและmain.py: รันไทม์ค้นหาสำเนา frozen ก่อน แล้วจึงค้นหาระบบไฟล์boot.pyfrozen ไม่สามารถถูกแทนที่โดยการวางบน SD card ได้ -- ผู้ที่ถือกล้องไม่สามารถเปลี่ยน entry point ได้โดยไม่ต้องแฟลชใหม่สำหรับ
import foo: รันไทม์ค้นหาsys.pathก่อน -- ซึ่งครอบคลุม/flash,/sdcard,/rom, และไดเรกทอรีย่อยlibของแต่ละ -- จากนั้นค้นหาโมดูล frozenfoo.pyที่มีชื่อเดียวกันบนแฟลชหรือ SD จะ แทนที่foofrozen การนี้คือความสะดวกในการพัฒนา: วางโมดูลที่แก้ไขแล้วบนการ์ด soft-reset แล้วเห็นการเปลี่ยนแปลงโดยไม่ต้องแฟลชใหม่
ผลิตภัณฑ์ที่จัดส่งที่ต้องการปิดกั้นพฤติกรรมที่ระบบไฟล์แทนที่ frozen สำหรับ imports สามารถล้าง sys.path ตั้งแต่ต้นใน boot.py
import sys
sys.path.clear()
เมื่อ sys.path ว่างเปล่า imports ทั้งหมดจะแก้ไขจากโมดูล frozen เท่านั้น ไม่มีสิ่งใดบนแฟลช, SD, หรือ ROMFS สามารถบดบังได้
14.2.2.1.2.4. ปัญหา asset¶
การแช่แข็งเหมาะสำหรับโค้ด แต่ ไม่เหมาะ สำหรับ asset ไบนารีขนาดใหญ่: ไฟล์โมเดล machine learning, ตารางป้ายกำกับ, การกำหนดค่า JSON, เทมเพลตภาพ การฝังสิ่งเหล่านี้เป็น Python literals จะทำให้ซอร์สบวมขึ้น คอมไพล์ช้า และเสียพื้นที่ bytecode container บนข้อมูลที่ interpreter จะต้องอ่านดิบอยู่ดี หน้า การสร้าง ROMFS image อธิบาย read-only flash filesystem ที่เติมเต็มช่องว่างนี้