Le macchine a stati tutorial [chiuso]
-
21-09-2019 - |
Domanda
Mi chiedo solo se qualcuno sa di qualche buon tutorial su Internet per lo sviluppo di macchine a stati. O ebooks?
Sto iniziando a lavorare su macchine a stati e solo bisogno di qualcosa di generale per ottenerlo iniziato.
Soluzione
Le macchine a stati sono molto semplici in C se si utilizza puntatori a funzione.
Fondamentalmente è necessario 2 campi - uno per puntatori a funzione di stato e uno per le regole di transizione di stato. Ogni funzione di stato restituisce il codice, si ricerca nella tabella di transizione di stato per stato e codice di ritorno per trovare lo stato successivo e poi basta eseguirlo.
int entry_state(void);
int foo_state(void);
int bar_state(void);
int exit_state(void);
/* array and enum below must be in sync! */
int (* state[])(void) = { entry_state, foo_state, bar_state, exit_state};
enum state_codes { entry, foo, bar, end};
enum ret_codes { ok, fail, repeat};
struct transition {
enum state_codes src_state;
enum ret_codes ret_code;
enum state_codes dst_state;
};
/* transitions from end state aren't needed */
struct transition state_transitions[] = {
{entry, ok, foo},
{entry, fail, end},
{foo, ok, bar},
{foo, fail, end},
{foo, repeat, foo},
{bar, ok, end},
{bar, fail, end},
{bar, repeat, foo}};
#define EXIT_STATE end
#define ENTRY_STATE entry
int main(int argc, char *argv[]) {
enum state_codes cur_state = ENTRY_STATE;
enum ret_codes rc;
int (* state_fun)(void);
for (;;) {
state_fun = state[cur_state];
rc = state_fun();
if (EXIT_STATE == cur_state)
break;
cur_state = lookup_transitions(cur_state, rc);
}
return EXIT_SUCCESS;
}
Non metto funzione lookup_transitions()
come è banale.
Questo è il mio modo di fare macchine a stati per anni.
Altri suggerimenti
Io preferisco usando puntatori a funzione su dichiarazioni switch
gigantesche, ma in contrasto con la risposta di io di solito non uso i codici di ritorno espliciti o tabelle di transizione.
Inoltre, nella maggior parte dei casi si vorrà un meccanismo per passare lungo i dati aggiuntivi. Ecco un esempio della macchina di stato:
#include <stdio.h>
struct state;
typedef void state_fn(struct state *);
struct state
{
state_fn * next;
int i; // data
};
state_fn foo, bar;
void foo(struct state * state)
{
printf("%s %i\n", __func__, ++state->i);
state->next = bar;
}
void bar(struct state * state)
{
printf("%s %i\n", __func__, ++state->i);
state->next = state->i < 10 ? foo : 0;
}
int main(void)
{
struct state state = { foo, 0 };
while(state.next) state.next(&state);
}
Le macchine a stati non sono qualcosa che ha bisogno di per sé un tutorial per spiegare o addirittura utilizzati. Quello che suggerisco è che si dà un'occhiata ai dati e come è necessario da analizzare.
Per esempio, ho dovuto analizzare il protocollo dati per un Vicino computer di volo in mongolfiera Spazio , che i dati memorizzati sulla scheda SD in un formato specifico (binario), che aveva bisogno di essere analizzato fuori in un file separato da virgole. Utilizzando una macchina a stati per questo ha più senso, perché a seconda di quello che la prossima bit di informazione è che abbiamo bisogno di cambiare ciò che stiamo parsing.
Il codice è scritto in C ++, ed è disponibile come ParseFCU . Come si può vedere, in primo luogo rileva che versione stiamo parsing, e da lì si entra due macchine a stati diversi.
Si entra la macchina dello Stato in una nota buono stato, a quel punto iniziamo l'analisi e la seconda di ciò che i personaggi che incontriamo ci sia mossa allo stato successivo o tornare a uno stato precedente. Questo permette in sostanza il codice di auto-adattarsi al modo in cui i dati vengono memorizzati e se non certo esistono dati a tutti, anche.
Nel mio esempio, la stringa GPS non è un requisito per il computer di volo per accedere, quindi l'elaborazione della stringa GPS può essere saltata se i byte che terminano per quella singola scrittura di registro viene trovato.
Le macchine a stati sono semplici da scrivere, e in generale mi seguono la regola che dovrebbe scorrere. Ingresso passare attraverso il sistema dovrebbe fluire con certa facilità da stato a stato.
Purtroppo, la maggior parte degli articoli su macchine a stati sono scritti per C ++ o altri linguaggi che hanno il supporto diretto per il polimorfismo come è bello per modellare gli stati in un'implementazione FSM come classi che derivano da una classe stato astratto.
Tuttavia, è abbastanza facile da implementare macchine a stati in C utilizzando passare dichiarazioni agli eventi di spedizione per gli stati (per semplici FSM, hanno praticamente codice giusto su) o utilizzando le tabelle per mappare gli eventi a transizioni di stato.
Ci sono un paio di semplici, ma gli articoli decenti su un quadro di base per macchine a stati in C qui:
- http: // www.gedan.net/2008/09/08/finite-state-machine-matrix-style-c-implementation/
- http://www.gedan.net/2009/03/18/finite-state-machine-matrix-style-c-implementation-function-pointers-addon/
Modifica : Sito "in manutenzione", link archivio web:
- http://web.archive.org/web/20160517005245/http://www.gedan.net/2008/09/08/finite-state-machine-matrix-style-c -attuazione
- http://web.archive.org/web/20160808120758/http://www.gedan.net/2009/03/18/finite-state- machine-matrix-style-c-implementazione-funzione-puntatori-addon /
switch
macchine a stati economico-based utilizzano spesso un insieme di macro per 'nascondere' i meccanismi della dichiarazione switch
(o utilizzare un insieme di istruzioni if
/ then
/ else
invece di un switch
) e fare ciò che equivale a un "FSM linguaggio" per descrivere la macchina a stati in C fonte. Io personalmente preferisco l'approccio basato su tabelle, ma questi certamente il merito, sono ampiamente utilizzati, e può essere efficace soprattutto per FSM più semplici.
Un tale quadro è delineato da Steve Rabin nel " gioco Gemme di programmazione" Capitolo 3.0 (Progettazione di un generale robusta AI motore) .
Un simile insieme di macro è discusso qui:
Se siete interessati a C ++ implementazioni macchina a stati anche c'è molto di più che possono essere trovati. Vi posto puntatori se siete interessati.
Real-Time modellazione orientata agli oggetti era fantastico (pubblicato nel 1994 e ora in vendita per meno di 81 centesimi, più $ 3,99 SPEDENDO).
Questo è tutto quello che dovete sapere.
int state = 0;
while (state < 3)
{
switch (state)
{
case 0:
// Do State 0 Stuff
if (should_go_to_next_state)
{
state++;
}
break;
case 1:
// Do State 1 Stuff
if (should_go_back)
{
state--;
}
else if (should_go_to_next_state)
{
state++;
}
break;
case 2:
// Do State 2 Stuff
if (should_go_back_two)
{
state -= 2;
}
else if (should_go_to_next_state)
{
state++;
}
break;
default:
break;
}
}
Ci sono un sacco di lezione da imparare artigianale macchine a stati in C, ma lasciatemi anche suggerire Ragel macchina a stati compilatore:
http://www.complang.org/ragel/
Ha modo molto semplice di definire macchine a stati e quindi è possibile generare grafici, generare il codice in diversi stili (tavolo-driven, goto-driven), analizzare il codice, se si desidera, ecc Ed è potente, può essere utilizzato nel codice di produzione per diversi protocolli.
Le macchine a stati può essere molto complessa per un problema complesso. Essi sono inoltre soggetti a bug inaspettati. Essi possono trasformarsi in un incubo se qualcuno si imbatte in un bug o ha bisogno di cambiare la logica in futuro. Essi sono anche difficili da seguire ed eseguire il debug senza il diagramma di stato. programmazione strutturata è molto meglio (ad esempio si sarebbe probabilmente non si utilizza una macchina a stati a livello di linea principale). È possibile utilizzare la programmazione strutturata anche nel contesto di interrupt (che è dove sono usati solitamente macchine a stati). Si veda questo articolo "Macro per simulare multi- tasking / blocco di codice a livello di interrupt " trovato alla codeproject.com.