Construire des machines d'états avec développement piloté par les tests en C embarqué
Les machines d'états sont fondamentales pour de nombreux systèmes embarqués, pourtant leur développement peut être complexe. Cet article décrit des stratégies éprouvées pour construire du logiciel de machine d'états (ME) en utilisant le développement piloté par les tests (TDD), avec focus sur implémentations C pour environnements à ressources contraintes.
Au cœur, un modèle ME consiste en états, transitions, et actions. Les états représentent des conditions, les transitions définissent le chemin d'un état à un autre — généralement déclenché par un événement — et les actions capturent le comportement exécuté pendant entrée, sortie, ou pendant la transition.
Dans les machines d'états UML, les actions peuvent être attachées à l'entrée/sortie d'état, la transition elle-même, ou réactions internes. Tous les formalismes de machine d'états assumment un modèle d'exécution Run-To-Completion (RTC) : chaque événement est entièrement traité — incluant actions de sortie, actions de transition, et actions d'entrée — avant que le prochain événement ne soit géré.
Avant de plonger dans les stratégies TDD, il est essentiel de comprendre pourquoi le TDD importe. Le TDD est une approche de développement incrémental qui mandate l'écriture d'un test unitaire échouant avant tout code de production. Les tests sont petits, automatisés, et servent de spécification pour le comportement désiré. Le cycle TDD — dérivé de « Test-Driven Development for Embedded C » de James Grenning — inclut :
- Écrire un petit test échouant.
- Exécuter tous tests ; le nouveau test doit échouer.
- Écrire le code minimal pour passer le test.
- Ré-exécuter tous tests pour confirmer que le nouveau test passe.
- Refactorer pour éliminer duplication et améliorer clarté.
Considérez le diagramme ME de la Figure 1. Il commence en StateA et, à la réception de l'événement Alpha, transitionne vers StateB, exécutant xStateA(), effect(), et nStateB() en séquence. Comment valider que ce comportement est correct ?
Figure 1. Machine d'états basique (Source : VortexMakes)
L'approche de test la plus directe implique de vérifier la table de transitions de la ME. Cela crée un cas de test par état, stimulant la ME avec événements pertinents et affirmant l'état résultant et actions exécutées. Actions complexes méritent tests dédiés. (Voir l'article « Testing state machines using unit test » pour discussion approfondie.)
Chaque test suit le pattern quatre phases xUnit :
- Setup — établir préconditions (ex. état courant, événement, état cible attendu, séquence d'actions).
- Exercise — déclencher la ME avec l'événement.
- Verify — affirmer que les résultats correspondent aux attentes.
- Cleanup — réinitialiser la ME à son état initial (optionnel).
Si cette stratégie marche bien pour ME simples, comportement plus complexe — comme une chaîne de transitions où un effet n'est observable qu'après plusieurs étapes — requiert tests de scénarios fonctionnels. Au lieu de checks d'état isolés, on teste une séquence complète exerçant les états, événements, et actions nécessaires.
La Figure 2 illustre ceci avec une ME DoWhile qui imite une boucle do-while traditionnelle. La machine initialise avec valeurs par défaut via x = 0 et output = 0, définit le compteur de boucle avec x++ ou x = (x > 0) ? x-: x, et itère avec i++ jusqu'à ce que la garde i == x échoue, après quoi elle sort output = i.
Figure 2. La machine d'états DoWhile (Source : VortexMakes)
Avant le codage, nous créons une liste de tests dérivée de la spécification. Pour DoWhile, la liste initiale inclut :
- Toutes données aux défauts à l'initialisation.
- Incrémentation de l'attribut X.
- Décrémentation de l'attribut X.
- Exécution boucle single-iteration.
- Exécution multi-iterations.
- Gestion scénario non-itérable.
- Vérification conditions hors-bornes.
Nous employons Ceedling comme système de build et Unity comme harnais de test léger pour le code C. La ME est définie dans DoWhile.h et DoWhile.c, et la suite de tests réside dans test_DoWhile.c. Ci-dessous un extrait concis illustrant le cas de test « single-iteration ».
Code Listing 1: Test single iteration (Source : VortexMakes)
Le test initialise la ME, met le compteur d'itération à zéro, dépêche l'événement Up pour l'incrémenter, déclenche l'événement Start, et finalement envoie Alpha pour exécuter une itération de boucle. Les assertions vérifient que l'attribut out égal le nombre d'itérations et que la ME reste en StateC.
Étendant le même test démontre multi-iterations (voir Code Listing 2). Un test séparé (Listing 3) confirme que la ME n'effectue aucune itération quand Alpha est reçu sans Up préalable.
Code Listing 2: Test multi-iteration (Source : VortexMakes)
Code Listing 3: Test non-iteration (Source : VortexMakes)
Les détails d'implémentation ne sont pas le focus de cet article, mais des extraits de DoWhile.c et DoWhile.h illustrent une approche switch-case propre pour la gestion d'états.
Code Listing 4: Fragment implémentation DoWhile (Source : VortexMakes)
Code Listing 5: Fragment spécification DoWhile (Source : VortexMakes)
En résumé, le TDD fournit deux stratégies complémentaires pour le développement de machines d'états : (1) test de transition état-par-état, et (2) test de scénario fonctionnel couvrant multiples états et actions. Ces méthodes sont language-agnostic, tool-agnostic, et particulièrement bien adaptées aux systèmes embarqués où la logique state-based domine.
Comme le C reste la lingua franca du logiciel embarqué, l'associer à Ceedling et Unity donne un workflow TDD robuste. Adopter ces pratiques mène à un logiciel plus flexible, maintenable, et réutilisable que les approches conventionnelles.
Tout le code et modèles sont disponibles dans le dépôt GitHub https://github.com/leanfrancucci/sm-tdd.git.
Embarqué
- Problèmes courants des machines CNC et solutions d'experts
- Maîtriser les fraiseuses verticales : avantages, opérations et pourquoi elles surpassent les modèles horizontaux
- Fiabilité CNC améliorée : les outils de fraisage modernes offrent vitesse, précision et coûts réduits
- Boy Machines : faire progresser la production à petite échelle avec une technologie de pointe
- Éviter les pièges courants lors de l'achat de machines CNC d'occasion
- Automatisation des tests pilotée par l'IA : Révolutionner l'assurance qualité pour les systèmes ERP modernes
- Le projet Accelerate se lance avec l'externalisation stratégique
- Tendances manufacturières 2021 : Partie 2 – Insights de Make UK
- Obtenir des finitions parfaites avec les machines de rectification de précision Okamoto