14.2.2.1. Geler des scripts dans le micrologiciel¶
Un module gelé est un fichier .py compilé en bytecode et lié à l’image du micrologiciel au moment de la compilation. L’environnement d’exécution importe un module gelé directement depuis la mémoire flash, sans jamais consulter le système de fichiers sur disque. Pour un produit livré, c’est l’endroit idéal pour le code de l’application : rien que l’utilisateur final puisse supprimer, rien qu’un .py obsolète sur la carte SD puisse remplacer, et la caméra exécute le même code à chaque démarrage, quel que soit le contenu (le cas échéant) de ses lecteurs.
Cette page décrit la séquence de démarrage suivie par la caméra, puis explique comment manifest.py et la directive freeze intègrent une application dans la compilation.
14.2.2.1.1. La séquence de démarrage¶
Ce qui s’exécute, et à quel moment, sur une caméra sortant d’une réinitialisation :
Le programme d’amorçage. La mise sous tension ouvre une courte fenêtre DFU utilisée par l’IDE pour envoyer les mises à jour du micrologiciel. La fenêtre se ferme au bout de quelques secondes et le programme d’amorçage passe le relais à MicroPython. Un script en cours d’exécution peut rouvrir cette fenêtre à la demande en appelant
machine.bootloader().Initialisation du système de fichiers gelé. Avant l’exécution de tout code applicatif, l’environnement d’exécution monte les systèmes de fichiers. La mémoire flash interne est montée sur
/flash(et formatée à vide s’il n’y a rien dessus). Si une carte SD est présente et qu’un fichier marqueur nomméSKIPSDn’existe pas sur la mémoire flash interne, la carte SD est montée sur/sdcard. ROMFS, lorsque la compilation l’inclut, est monté automatiquement sur/rom. Le répertoire de travail est défini sur le répertoire de démarrage (/sdcardsi la carte est montée,/flashsinon), etsys.pathest renseigné avec/flash,/flash/lib,/sdcard,/sdcard/lib,/romet/rom/lib. La configuration résidant en mémoire flash est gérée par un module gelé nommé_boot.py– une infrastructure de port et de carte, pas un point d’accroche applicatif. Les applications ne personnalisent pas_boot.py; c’est la compilation qui le fait. Déposer un fichierSKIPSDsur la mémoire flash depuis l’IDE est la manière prise en charge de faire démarrer la caméra depuis la mémoire flash interne plutôt que depuis la carte SD.Configuration avant REPL.
boot.pys’exécute à chaque réinitialisation logicielle – démarrage à froid,Ctrl-Ddepuis le REPL, retour du script en cours d’exécution et récupération du chien de garde – avant que le REPL ne devienne accessible. Son rôle est de préparer l’environnement dans lequel s’exécute le reste du système : le type de configuration dont le REPL, l’application et tout outil de récupération ont besoin pour fonctionner. Ce n’est pas là que réside l’application elle-même.main.pyest le point d’entrée de l’application.Boucle principale.
main.pyest la boucle principale de l’application. Elle s’exécute une fois au démarrage à froid, immédiatement aprèsboot.py. Elle n’est pas réexécutée lors des réinitialisations logicielles ultérieures – la caméra passe alors au REPL. Cette asymétrie compte pour le développement (un Ctrl-D passe au REPL sans réexécuter la boucle, ce qui permet au développeur d’inspecter l’état) mais pas pour la production : une caméra déployée subit des réinitialisations à la mise sous tension, par le chien de garde et matérielles, qui sont toutes des réinitialisations matérielles réempruntant le chemin de démarrage à froid et réexécutantmain.py.
14.2.2.1.2. Geler dans le micrologiciel¶
L’ensemble des modules gelés d’une carte est déclaré dans boards/<TARGET>/manifest.py au sein de l’arborescence du micrologiciel. Le manifeste est un petit fichier Python qui appelle une poignée de directives :
freeze("$(OMV_LIB_DIR)/", "foo.py")– intègre un uniquefoo.pydans la compilation.package("mylib", base_path="...")– intègre un paquet Python composé de plusieurs fichiers, en préservant l’agencement de ses répertoires sous le chemin de base indiqué.include("...")– importe un autre fichier manifeste. Les manifestes de carte s’en servent pour partager des ensembles de modules communs.require("logging")– importe un module amontmicropython-libnommé par son nom.
Un manifeste d’application minimal ajoute une ligne freeze par script de premier niveau et une ligne package par paquet dont l’application dépend.
14.2.2.1.2.1. Où réside le code source¶
Le code source de l’application réside sous scripts/libraries/ dans l’arborescence du micrologiciel, aux côtés des modules que la compilation gèle déjà. La variable de manifeste $(OMV_LIB_DIR) se développe en ce chemin, ce qui permet de garder les entrées de manifeste courtes. L’édition du manifeste est déjà une opération au sein de l’arborescence, donc conserver le code source dans l’arborescence évite de jongler avec un dépôt de projet séparé lors de la résolution des chemins.
Un agencement typique pour une application qui livre un unique main.py plus un paquet d’appui
scripts/libraries/
main.py
my_lib/
__init__.py
helpers.py
Et dans le boards/<TARGET>/manifest.py de la carte, une ligne freeze pour le script et une ligne package pour le paquet
freeze("$(OMV_LIB_DIR)/", "main.py")
package("my_lib", base_path="$(OMV_LIB_DIR)/my_lib")
Les scripts mono-fichier – main.py ici, mais la même règle s’applique à boot.py ou à tout assistant autonome – utilisent freeze. Les paquets multi-fichiers utilisent package. Ajouter un autre script revient à une ligne freeze de plus ; ajouter un autre paquet revient à une ligne package de plus.
14.2.2.1.2.2. Compilation et flashage¶
Une fois le manifeste en place, compilez le micrologiciel exactement comme le décrit le chapitre sur le micrologiciel
make -j$(nproc) -C lib/micropython/mpy-cross # once, builds the cross-compiler
make -j$(nproc) TARGET=<TARGET> # builds the firmware
La sortie se retrouve dans build/<TARGET>/bin/
build/<TARGET>/bin/
firmware.bin # flash through the IDE
romfs0.img # flash through the IDE in a separate step
Flasher le .bin et le .img via l’IDE produit une caméra dont l’application fait partie de la compilation.
La séquence de démarrage ci-dessus est ce qui rend l’intégration efficace : l’environnement d’exécution résout boot.py et main.py vers les copies gelées avant même de consulter le système de fichiers, de sorte qu’une caméra livrée exécute le code de la compilation même si la carte SD contient un boot.py obsolète laissé lors du développement.
14.2.2.1.2.3. Ordre de recherche¶
La sémantique de remplacement est différente pour le chemin d’exécution de boot.py / main.py et pour les instructions import ordinaires. Savoir laquelle est laquelle compte aussi bien pour la production que pour le développement :
Pour
boot.pyetmain.py: l’environnement d’exécution recherche d’abord une copie gelée, puis le système de fichiers. Unboot.pygelé ne peut pas être remplacé en en déposant un sur la carte SD – quiconque détient la caméra ne peut pas changer le point d’entrée sans reflasher.Pour
import foo: l’environnement d’exécution parcourt d’abordsys.path– qui couvre/flash,/sdcard,/romet leurs sous-répertoireslib– puis les modules gelés. Unfoo.pyde même nom sur la mémoire flash ou la carte SD remplace bien unfoogelé. C’est la commodité de développement : déposez un module corrigé sur la carte, faites une réinitialisation logicielle, constatez le changement sans reflasher.
Un produit livré qui souhaite supprimer le comportement « le système de fichiers remplace le gelé » pour les importations peut vider sys.path tôt dans boot.py
import sys
sys.path.clear()
Avec sys.path vide, toutes les importations se résolvent uniquement à partir des modules gelés ; rien sur la mémoire flash, la carte SD ou ROMFS ne peut les masquer.
14.2.2.1.2.4. Le problème des ressources¶
Le gel est excellent pour le code. Il n’est pas idéal pour les grandes ressources binaires : fichiers de modèles d’apprentissage automatique, tables d’étiquettes, configuration JSON, modèles d’image. Les intégrer en tant que littéraux Python gonfle le code source, ralentit la recompilation et gaspille le conteneur de bytecode pour des données que l’interpréteur va de toute façon simplement lire brutes. La page Construire une image ROMFS couvre le système de fichiers en lecture seule résidant en mémoire flash qui comble cette lacune.