14.2.2.1. Înghețarea scripturilor în firmware¶
Un modul înghețat (frozen) este un fișier .py compilat în bytecode și legat în imaginea firmware-ului la momentul compilării. La execuție, runtime-ul importă un modul înghețat direct din memoria flash, fără a se uita vreodată la sistemul de fișiere de pe disc. Pentru un produs livrat, acesta este locul potrivit pentru codul aplicației: nimic pe care utilizatorul final să poată șterge, niciun fișier .py învechit de pe cardul SD care să îl suprascrie, iar camera rulează același cod la fiecare pornire, indiferent de ce se află (dacă se află ceva) pe unitățile sale.
Această pagină acoperă secvența de pornire pe care camera o urmează, apoi modul în care manifest.py și directiva freeze integrează o aplicație în build.
14.2.2.1.1. Secvența de pornire¶
Ce rulează și când, pe o cameră care iese din reset:
Bootloader-ul. Pornirea intră într-o scurtă fereastră DFU pe care OpenMV IDE o folosește pentru a trimite actualizări de firmware. Fereastra se închide după câteva secunde, iar bootloader-ul predă controlul către MicroPython. Un script în execuție poate reintra în această fereastră la cerere apelând
machine.bootloader().Inițializarea sistemului de fișiere înghețat. Înainte ca orice cod al aplicației să ruleze, runtime-ul aduce sistemele de fișiere în stare de funcționare. Memoria flash internă este montată la
/flash(și formatată în gol dacă nu se află nimic acolo). Dacă este prezent un card SD și nu există un fișier marcator numitSKIPSDîn memoria flash internă, cardul SD este montat la/sdcard. ROMFS, atunci când build-ul îl include, este montat automat la/rom. Directorul de lucru este setat la directorul de pornire (/sdcarddacă s-a montat cardul,/flashîn caz contrar), iarsys.patheste populat cu/flash,/flash/lib,/sdcard,/sdcard/lib,/romși/rom/lib. Configurarea rezidentă în flash este gestionată de un modul înghețat numit_boot.py– infrastructură de port și placă, nu un punct de extindere al aplicației. Aplicațiile nu personalizează_boot.py; build-ul o face. Plasarea unui fișierSKIPSDîn flash din OpenMV IDE este modalitatea acceptată de a face camera să pornească din memoria flash internă în loc de cardul SD.Configurarea înainte de REPL.
boot.pyrulează la fiecare soft reset – pornire la rece,Ctrl-Ddin REPL, scriptul în execuție care se încheie și recuperarea prin watchdog – înainte ca REPL-ul să devină accesibil. Sarcina sa este de a pregăti mediul în care rulează restul sistemului: tipul de configurare de care REPL-ul, aplicația și orice instrument de recuperare au nevoie pentru a funcționa. Nu este locul unde se află aplicația propriu-zisă.main.pyeste punctul de intrare al aplicației.Bucla principală.
main.pyeste bucla principală a aplicației. Rulează o singură dată la pornirea la rece, imediat dupăboot.py. Nu este re-rulat la soft reset-urile ulterioare – în schimb, camera revine la REPL. Această asimetrie contează pentru dezvoltare (un Ctrl-D revine la REPL fără a re-rula bucla, astfel încât dezvoltatorul să poată inspecta starea), dar nu și pentru producție: o cameră instalată în teren vede porniri, watchdog și reset-uri hardware, care sunt toate reset-uri hardware ce reintră pe calea de pornire la rece și rulează din noumain.py.
14.2.2.1.2. Înghețarea în firmware¶
Setul de module înghețate al unei plăci este declarat în boards/<TARGET>/manifest.py în arborele firmware-ului. Manifestul este un mic fișier Python care apelează câteva directive:
freeze("$(OMV_LIB_DIR)/", "foo.py")– integrează un singur fișierfoo.pyîn build.package("mylib", base_path="...")– integrează un pachet Python format din mai multe fișiere, păstrându-i structura de directoare sub calea de bază dată.include("...")– include un alt fișier manifest. Manifestele plăcilor folosesc acest lucru pentru a partaja seturi comune de module.require("logging")– include un modulmicropython-libdin amonte specificat după nume.
Un manifest minimal de aplicație adaugă o linie freeze per script de nivel superior și o linie package per pachet de care depinde aplicația.
14.2.2.1.2.1. Unde se află sursa¶
Sursa aplicației se află sub scripts/libraries/ în arborele firmware-ului, alături de modulele pe care build-ul le îngheață deja. Variabila de manifest $(OMV_LIB_DIR) se extinde la acea cale, astfel încât intrările din manifest rămân scurte. Editarea manifestului este deja o operațiune în interiorul arborelui, așa că păstrarea sursei în interiorul arborelui evită jonglarea cu un depozit de proiect separat la rezolvarea căilor.
O structură tipică pentru o aplicație care livrează un singur main.py plus un pachet de suport:
scripts/libraries/
main.py
my_lib/
__init__.py
helpers.py
Iar în fișierul boards/<TARGET>/manifest.py al plăcii, o linie freeze pentru script și o linie package pentru pachet:
freeze("$(OMV_LIB_DIR)/", "main.py")
package("my_lib", base_path="$(OMV_LIB_DIR)/my_lib")
Scripturile dintr-un singur fișier – main.py aici, dar aceeași regulă se aplică pentru boot.py sau orice modul ajutător independent – folosesc freeze. Pachetele cu mai multe fișiere folosesc package. Adăugarea unui alt script înseamnă încă o linie freeze; adăugarea unui alt pachet înseamnă încă o linie package.
14.2.2.1.2.2. Compilarea și programarea¶
Odată ce manifestul este la locul lui, compilați firmware-ul exact așa cum descrie capitolul despre firmware
make -j$(nproc) -C lib/micropython/mpy-cross # once, builds the cross-compiler
make -j$(nproc) TARGET=<TARGET> # builds the firmware
Rezultatul ajunge în build/<TARGET>/bin/
build/<TARGET>/bin/
firmware.bin # flash through the IDE
romfs0.img # flash through the IDE in a separate step
Programarea fișierelor .bin și .img prin OpenMV IDE produce o cameră a cărei aplicație face parte din build.
Secvența de pornire de mai sus este ceea ce face integrarea eficientă: runtime-ul rezolvă boot.py și main.py la copiile înghețate înainte de a verifica vreodată sistemul de fișiere, astfel încât o cameră livrată rulează codul build-ului chiar dacă pe cardul SD se află un fișier boot.py învechit lăsat din timpul dezvoltării.
14.2.2.1.2.3. Ordinea de căutare¶
Semantica de suprascriere este diferită pentru calea de execuție boot.py / main.py față de instrucțiunile import obișnuite. A ști care este care contează atât pentru producție, cât și pentru dezvoltare:
Pentru
boot.pyșimain.py: runtime-ul caută mai întâi o copie înghețată, apoi sistemul de fișiere. Unboot.pyînghețat nu poate fi suprascris prin plasarea unuia pe cardul SD – cine deține camera nu poate schimba punctul de intrare fără a reprograma firmware-ul.Pentru
import foo: runtime-ul caută mai întâi însys.path– care acoperă/flash,/sdcard,/romși subdirectoarele lorlib– apoi modulele înghețate. Un fișierfoo.pycu același nume pe flash sau SD suprascrie într-adevăr unfooînghețat. Aceasta este facilitatea pentru dezvoltare: plasați un modul corectat pe card, faceți un soft reset, vedeți modificarea fără a reprograma firmware-ul.
Un produs livrat care dorește să suprime comportamentul de suprascriere a modulelor înghețate de către sistemul de fișiere la importuri poate goli sys.path devreme în boot.py
import sys
sys.path.clear()
Cu sys.path gol, toate importurile se rezolvă numai din modulele înghețate; nimic de pe flash, SD sau ROMFS nu le poate eclipsa.
14.2.2.1.2.4. Problema activelor¶
Înghețarea este excelentă pentru cod. Nu este la fel de bună pentru active binare mari: fișiere de model de învățare automată, tabele de etichete, configurare JSON, șabloane de imagini. Încorporarea acestora ca literali Python umflă sursa, recompilează lent și irosește containerul de bytecode pe date pe care interpretorul oricum doar le va citi brut. Pagina Construirea unei imagini ROMFS acoperă sistemul de fișiere flash de tip read-only care umple acest gol.