14.2.2.1. Zamrzavanje skripti u ugrađeni program (firmware)

Zamrznuti modul je .py datoteka prevedena u bajtkod i povezana u sliku ugrađenog programa (firmware) u trenutku izgradnje. Tijekom izvođenja modul se uvozi izravno iz flash memorije, bez ikakvog pristupa datotečnom sustavu na disku. Za gotov proizvod ovo je pravo mjesto za aplikacijski kod: ništa što bi krajnji korisnik mogao izbrisati, ništa što bi zastarjela .py datoteka na SD kartici mogla nadjačati, a kamera pri svakom pokretanju izvodi isti kod bez obzira na to što (ako išta) se nalazi na njezinim pogonima.

Ova stranica obrađuje slijed pokretanja kojeg kamera prati, a zatim kako manifest.py i direktiva freeze ugrađuju aplikaciju u izgradnju.

14.2.2.1.1. Slijed pokretanja

Što se izvodi i kada, na kameri koja izlazi iz ponovnog postavljanja:

  • Pokretač (bootloader). Uključivanje napajanja ulazi u kratak DFU prozor koji IDE koristi za slanje ažuriranja ugrađenog programa (firmware). Prozor se zatvara nakon nekoliko sekundi i pokretač (bootloader) predaje upravljanje MicroPythonu. Skripta koja se izvodi može po potrebi ponovno ući u taj prozor pozivom machine.bootloader().

  • Inicijalizacija zamrznutog datotečnog sustava. Prije nego što se izvede ikakav aplikacijski kod, izvođenje pokreće datotečne sustave. Interna flash memorija montira se na /flash (i formatira se prazno ako ondje ničega nema). Ako je SD kartica prisutna i ako datoteka markera nazvana SKIPSD ne postoji na internoj flash memoriji, SD kartica montira se na /sdcard. ROMFS, kada ga izgradnja uključuje, automatski se montira na /rom. Radni direktorij postavlja se na direktorij pokretanja (/sdcard ako je kartica montirana, inače /flash), a sys.path popunjava se s /flash, /flash/lib, /sdcard, /sdcard/lib, /rom i /rom/lib. Postavljanje koje se nalazi u flash memoriji obrađuje zamrznuti modul nazvan _boot.py – infrastruktura porta i ploče, a ne aplikacijska kuka. Aplikacije ne prilagođavaju _boot.py; to čini izgradnja. Postavljanje datoteke SKIPSD na flash memoriju iz IDE-a podržan je način da se kamera natjera na pokretanje iz interne flash memorije umjesto iz SD kartice.

  • Postavljanje prije REPL-a. boot.py izvodi se pri svakom mekanom ponovnom postavljanju – hladnom pokretanju, Ctrl-D iz REPL-a, vraćanju skripte koja se izvodi te oporavku nadzornog mehanizma – prije nego što REPL postane dostupan. Njegov je posao pripremiti okruženje u kojem se izvodi ostatak sustava: vrstu postavljanja koju REPL, aplikacija i svi alati za oporavak trebaju imati spremnu da bi funkcionirali. To nije mjesto gdje živi sama aplikacija. main.py je ulazna točka aplikacije.

  • Glavna petlja. main.py je glavna petlja aplikacije. Izvodi se jednom pri hladnom pokretanju, neposredno nakon boot.py. Ne izvodi se ponovno pri sljedećim mekanim ponovnim postavljanjima – kamera umjesto toga prelazi na REPL. Ta asimetrija je važna za razvoj (Ctrl-D prelazi na REPL bez ponovnog izvođenja petlje, pa razvojni programer može pregledati stanje), ali ne i za proizvodnju: kamera u upotrebi doživljava uključivanje napajanja, nadzorni mehanizam i tvrda ponovna postavljanja, što su sve hardverska ponovna postavljanja koja ponovno ulaze u put hladnog pokretanja i ponovno izvode main.py.

14.2.2.1.2. Zamrzavanje u ugrađeni program (firmware)

Skup zamrznutih modula ploče deklarira se u boards/<TARGET>/manifest.py u stablu ugrađenog programa (firmware). Manifest je mala Python datoteka koja poziva nekolicinu direktiva:

  • freeze("$(OMV_LIB_DIR)/", "foo.py") – ugrađuje jednu foo.py u izgradnju.

  • package("mylib", base_path="...") – ugrađuje Python paket s više datoteka, čuvajući njegov raspored direktorija ispod zadanog osnovnog puta.

  • include("...") – uvlači drugu datoteku manifesta. Manifesti ploča ovo koriste za dijeljenje zajedničkih skupova modula.

  • require("logging") – uvlači imenovani uzvodni micropython-lib modul po imenu.

Minimalni aplikacijski manifest dodaje jedan freeze redak po skripti najviše razine i jedan package redak po paketu o kojem aplikacija ovisi.

14.2.2.1.2.1. Gdje se nalazi izvorni kod

Izvorni kod aplikacije nalazi se pod scripts/libraries/ u stablu ugrađenog programa (firmware), uz module koje izgradnja već zamrzava. Varijabla manifesta $(OMV_LIB_DIR) proširuje se u taj put, pa unosi manifesta ostaju kratki. Uređivanje manifesta već je operacija unutar stabla, pa čuvanje izvornog koda unutar stabla izbjegava žongliranje zasebnim projektnim repozitorijem na putu razrješavanja.

Tipičan raspored za aplikaciju koja isporučuje jedan main.py plus prateći paket:

scripts/libraries/
    main.py
    my_lib/
        __init__.py
        helpers.py

A u ploči boards/<TARGET>/manifest.py, jedan freeze redak za skriptu i jedan package redak za paket:

freeze("$(OMV_LIB_DIR)/", "main.py")
package("my_lib", base_path="$(OMV_LIB_DIR)/my_lib")

Skripte s jednom datotekom – ovdje main.py, ali isto pravilo vrijedi za boot.py ili bilo koji samostalni pomoćnik – koriste freeze. Paketi s više datoteka koriste package. Dodavanje još jedne skripte je još jedan freeze redak; dodavanje još jednog paketa je još jedan package redak.

14.2.2.1.2.2. Izgradnja i prijenos na flash

Kada je manifest na mjestu, izgradite ugrađeni program (firmware) točno onako kako opisuje poglavlje o ugrađenom programu

make -j$(nproc) -C lib/micropython/mpy-cross   # once, builds the cross-compiler
make -j$(nproc) TARGET=<TARGET>                # builds the firmware

Izlaz se pojavljuje u build/<TARGET>/bin/

build/<TARGET>/bin/
    firmware.bin     # flash through the IDE
    romfs0.img       # flash through the IDE in a separate step

Prijenos .bin i .img putem IDE-a daje kameru čija je aplikacija dio izgradnje.

Gore opisani slijed pokretanja čini ugradnju učinkovitom: tijekom izvođenja boot.py i main.py razrješavaju se u zamrznute kopije prije nego što se ikad provjeri datotečni sustav, pa isporučena kamera izvodi kod iz izgradnje čak i ako SD kartica drži zastarjeli boot.py ostavljen iz razvoja.

14.2.2.1.2.3. Redoslijed pretraživanja

Semantika nadjačavanja različita je za izvršni put boot.py / main.py i za obične import naredbe. Poznavanje koje je koje važno je i za proizvodnju i za razvoj:

  • Za boot.py i main.py: tijekom izvođenja prvo se traži zamrznuta kopija, a zatim datotečni sustav. Zamrznuti boot.py ne može se nadjačati postavljanjem na SD karticu – tko god drži kameru ne može promijeniti ulaznu točku bez ponovnog prijenosa na flash.

  • Za import foo: tijekom izvođenja prvo se pretražuje sys.path – koji pokriva /flash, /sdcard, /rom i njihove lib poddirektorije – a zatim zamrznuti moduli. foo.py istog imena na flash memoriji ili SD kartici doista nadjačava zamrznuti foo. Ovo je razvojna pogodnost: postavite ispravljen modul na karticu, mekano ponovno postavite i vidite promjenu bez ponovnog prijenosa na flash.

Isporučeni proizvod koji želi potisnuti ponašanje gdje datotečni sustav nadjačava zamrznute module za uvoze može rano u boot.py isprazniti sys.path

import sys

sys.path.clear()

S praznim sys.path svi se uvozi razrješavaju samo iz zamrznutih modula; ništa na flash memoriji, SD kartici ili ROMFS-u ne može ih zasjeniti.

14.2.2.1.2.4. Problem s resursima

Zamrzavanje je odlično za kod. Nije odlično za velike binarne resurse: datoteke modela strojnog učenja, tablice oznaka, JSON konfiguraciju, predloške slika. Ugrađivanje tih resursa kao Python literala napuhuje izvorni kod, sporo se ponovno prevodi i rasipa spremnik bajtkoda na podatke koje će interpreter ionako samo pročitati sirove. Stranica Izgradnja ROMFS slike obrađuje datotečni sustav samo za čitanje u flash memoriji koji popunjava tu prazninu.