Un automate fini est une représentation mathématique abstraite d'un système observé qui est susceptible d'être dans un nombre fini d'états, mais étant un moment donné dans un seul état à la fois.
-
Un état est la description de la configuration d'un système en attente d'exécuter une transition.
-
L'état dans lequel il se trouve alors est appelé l'« état courant ».
-
Le passage (transition ) d'un état à un autre est activé par un événement ou une condition
-
Une transition est un ensemble d'actions à exécuter lorsqu'une condition est remplie ou lorsqu'un événement est reçu
-
Dans certaines représentations, il est possible d'associer des actions à un état :
-
action d'entrée = réalisée lorsque l'on « entre » dans l'état,
-
action de sortie = réalisée lorsque l’on « quitte » l'état.
-
action de répétition = réalisée tous les ∆t au sein d'un même état (eg - led qui clignote)
-
action de transition = réalisée lors d'une transition (peut être une répétition sur l'état lui même)
ainsi qu'à une mémoire (par exemple état précédent ou historique des états et transitions).
Mathématiquement, un automate particulier, pour un système donné, est défini par l'ensemble de ses états et l'ensemble de ses transitions.
-> Ce que je dis c'est qu'il faut suivre un design pattern (méthodologie), si vous êtes intellectuellement capable de visualiser l'automate, vous saurez le coder et si la complexité augmente bien sûr être très strict sur l'application du formalisme - ou faire appel à de l'abstraction (librairies, langages) et/ou de la génération de code.
Il ne manque pas de littérature sur le sujet et d'approches --> modèle du genre langage de spécification et de description (SDL), automates UML, Diagramme états-transitions, machine à états abstraits, Machine de Moore, Machine de Mealy…
Ce que vous décrivez est basé principalement sur du Pub/Sub, il y a l' "Actor model" ou le "State Pattern" (en POO) par exemple qui sont envisageables.
La plupart des frameworks FSM souffrent d'un ou plusieurs des problèmes:
• Les bibliothèques en font trop: de nombreuses bibliothèques gèrent les transitions d'état, mettent à jour des modèles, publient des événements, exécutent des gestionnaires antérieurs / postérieurs, etc. ça peut être trop riche pour le besoin de base.
• Forcent des modèles d'implémentation non naturels, par exemple la logique métier est intégrée dans l'implémentation de la machine. (cf sur un de vos exemples)
• Couplés à un modèle spécifique de communication (cf le modèle Actor genre Erlang et Akka qui sont bcp trop complexes pour la majorité des cas mais bien utiles quand on est sur un gros cas industriel type celui que vous citez)
--> bref ce que je dis c'est qu'il faut appliquer le bon niveau de formalisme, et que souvent quand on a un marteau on a trop souvent la tendance à voir chaque problème comme un clou...
Pour moi - un outil "machines à état" aurait les composants de code suivants:
- Un mécanisme pour empêcher les transitions d'état incorrectes. Cela peut être une "carte de transition" si vous choisissez de modéliser les transitions de manière générique (pas top) ou pour le cas général un modèle où les transitions peuvent être isolées selon des comportements valides de l'état actuel.
- Un mécanisme pour empêcher l'accès à des comportements en dehors de l'état actuel.
- Une description de comportements associés à des états spécifiques. (blink)
- Un mécanisme pour notifier des "observateurs" externes des transitions d'état (susceptible de générer des évènements et donc des transitions)
Dans un de vos exemples ("4.2. Un bouton + mesure de tension batterie") vous avez intégré le clignotement dans la fonction controlLed()
et dans cette fonction vous avez un appel à l'état de la machine
int state = getMachineState();
if (state == STATE_BATT_LOW) {...
Vous avez donc de la logique métier embarquée, vous vous retrouvez au milieu du gué.
Tout dépend bien sûr de ce que vous définissez comme étant le système et les états possibles mais on pourrait dire que le fait que la LED soit allumée ou éteinte sont en fait deux états bien différents et ça peut conduire à des soucis.
Par exemple, si la batterie était faible puis retrouve son autonomie (très possible quand on approche la zone BATT_LIMIT) dans votre exemple, vous pouvez vous retrouver avec la LED allumé (en fonction du clignotement) qui était lié à l'état précédent "batterie faible" (j'ai pas lu en détail, je me trompe peut-être) sans pour autant que l'utilisateur ait appuyé sur le bouton pour demander l'allumage... (et donc vous allez vider la batterie
)
Cet exemple est intéressant parce que vous avez fait le choix de définir STATE_BATT_LOW comme un état alors que c'est éventuellement juste un évènement comme le temps qui passe ou l'appui du bouton. On peut aussi dire qu'il faudrait mémoriser l'état précédent s'il y a possibilité de sortir de l'état batterie faible.
approche avec mémorisation de l'état précédent en créant 2 états:
Approche avec mémorisation de l'état précédent nécessitant une variable supplémentaire état_précédent
que la librairie peut (ou pas) fournir.
Long post pour dire que chacun peut voir du plus et du moins dans une approche donnée, qu'il n'y a pas de réponse universelle et qu'il convient d'utiliser le bon sens et le bon outil pour un cas donné.... 