Last update: 240319 12:35:14

About State Machines.

First litterature then in bottom more nerd c code

Litterater/links



Two videos (in danish)

State Machines based on function pointers

Three based on function pointers

State Machine based on C case switch construction

Maybe the most readable and therefore simple

The one I use

no more to say

Video

A video and the written code for the case-swicth state machine idea

Designing state machines

A whiteboard or blackboard is very usefull for discussing designs of your SM.

Online tools (based on dot language e.g a->b; b->a; etc) might be what you need.

http://viz-js.com/ is a dynamic that redraw during editing. The state machine can be downloaded as png or other formats.

more to come

fra https://stackoverflow.com/questions/68953216/hierarchical-state-machine-with-graphviz

file [vendingsm here

digraph vendorMachine {
    compound=true
    graph [color=red]
    node [color=red]  // yuck style=filled fillcolor=yellow]
    edge [color=red]

    Entry[shape="point" label=""]

    subgraph cluster_cancel {
        label = "Cancel"
        style = rounded

    E2   [shape=rect label="" width=2 style=invis]
    E2:sw->C0  [label=cancel]


        C0 [label = <
            <table cellborder="0" style="rounded">
                <tr><td>C0</td></tr>
                <hr/>
                <tr><td></td></tr>
            </table>
        > margin=0 shape=none]

        C25 [label = <
            <table cellborder="0" style="rounded">
                <tr><td>C25</td></tr>
                <hr/>
                <tr><td></td></tr>
            </table>
        > margin=0 shape=none]

        C50 [label = <
            <table cellborder="0" style="rounded">
                <tr><td>C50</td></tr>
                <hr/>
                <tr><td></td></tr>
            </table>
        > margin=0 shape=none]

        C75 [label = <
            <table cellborder="0" style="rounded">
                <tr><td>C75</td></tr>
                <hr/>
                <tr><td></td></tr>
            </table>
        > margin=0 shape=none]

        subgraph cluster_DispenseC100Drink {
            label = "DispenseC100Drink"
            style = rounded

            C100 [label = <
                <table cellborder="0" style="rounded">
                    <tr><td>C100</td></tr>
                    <hr/>
                    <tr><td></td></tr>
                </table>
            > margin=0 shape=none]

            subgraph cluster_DispenseC125Drink {
                label = "DispenseC125Drink"
                style = rounded

                C125 [label = <
                    <table cellborder="0" style="rounded">
                        <tr><td>C125</td></tr>
                        <hr/>
                        <tr><td></td></tr>
                    </table>
                > margin=0 shape=none]

                C150 [label = <
                    <table cellborder="0" style="rounded">
                        <tr><td>C150</td></tr>
                        <hr/>
                        <tr><td></td></tr>
                    </table>
                > margin=0 shape=none]

                C175 [label = <
                    <table cellborder="0" style="rounded">
                        <tr><td>C175</td></tr>
                        <hr/>
                        <tr><td></td></tr>
                    </table>
                > margin=0 shape=none]

                C200 [label = <
                    <table cellborder="0" style="rounded">
                        <tr><td>C200</td></tr>
                        <hr/>
                        <tr><td></td></tr>
                    </table>
                > margin=0 shape=none]
                    }
                }
    }

    Entry -> C0
    C0 -> C25[label=" Add\n$0.25 "]
    C0 -> C50[label=" Add\n$0.50 "]

    C25 -> C50[label=" Add\n$0.25 "]
    C25 -> C75[label=" Add\n$0.50 "]

    C50 -> C75[label=" Add\n$0.25 "]
    C50 -> C100[label=" Add\n$0.50 "]

    C100 -> C0[label=" Dispense\n $1.00 Drink " ltail="cluster_DispenseC100Drink"]
    C75 -> C100[label=" Add\n$0.25 "]
    C75 -> C125[label=" Add\n$0.50 "]
    C100 -> C125[label=" Add\n$0.25 "]
    C100 -> C150[label=" Add\n$0.50 "]
    C125 -> C150[label=" Add\n$0.25 "]
    C125 -> C175[label=" Add\n$0.50 "]
    C125 -> C0[label=" Dispense\n $1.25 Drink "  ltail="cluster_DispenseC125Drink"]
    C150 -> C175[label=" Add\n$0.25 "]
    C150 -> C200[label=" Add\n$0.50 "]
    C175 -> C200[label=" Add\n$0.25 "]
    C200 -> C0[label=" Dispense\n $2.00 Drink "]
}

ANOTHER FSM IN DOT

digraph finite_state_machine {
	fontname="Helvetica,Arial,sans-serif"
	node [fontname="Helvetica,Arial,sans-serif"]
	edge [fontname="Helvetica,Arial,sans-serif"]
	rankdir=LR;
	node [shape = doublecircle]; 0 3 4 8;
	node [shape = circle];
	0 -> 2 [label = "SS(B)"];
	0 -> 1 [label = "SS(S)"];
	1 -> 3 [label = "S($end)"];
	2 -> 6 [label = "SS(b)"];
	2 -> 5 [label = "SS(a)"];
	2 -> 4 [label = "S(A)"];
	5 -> 7 [label = "S(b)"];
	5 -> 5 [label = "S(a)"];
	6 -> 6 [label = "S(b)"];
	6 -> 5 [label = "S(a)"];
	7 -> 8 [label = "S(b)"];
	7 -> 5 [label = "S(a)"];
	8 -> 6 [label = "S(b)"];
	8 -> 5 [label = "S(a)"];
}

My own litle system


#include <stdio.h>
#include <unistd.h>  // sleep


// States -- you need this forward dcl for the compiler and calling

// define NEXT(next,here,cond)
//                 |---- condition to be put on the arc in state machine
//             |-------- state we are in just now (just for graph)
//       |-------------- next state we will jump to
//
// all driven from main (or here setup fct)

typedef void *(*pFct)(void); // for typecast for calling function

#define NEXT(x,y,z) return ((pFct)x)


// my states
pFct led_on();      // as name indicates ...
pFct led_off();
pFct main_state();

pFct led_on() {
	printf("on\n");
	NEXT(main_state,led_on,back);
}


pFct led_off() {
	printf("off\n");
	NEXT(main_state,led_off,back);
}



pFct main_state()
{
	static int t=0;

	// pausefire
	if (t==0) {
		t = 1;
		printf("main1\n");
		NEXT(led_on, main_state, toOn);
	}
	else {
		t = 0;
		//delay
		printf("main2\n");
		NEXT(led_off, main_state, toOff);
	}
	// delay

}
void main() {
	while(1) {
		sleep(1);
		statefunc = (*statefunc)();
	}
}

Running the scripts in smdy.zip gives