/*
* main.c
*
* This is an implementation of a Event Driven Finite State Machine.
*
* Copyright (C) AR2 Labs
*
* Portions derived from Fernando Magro´s code.
* Copyright (C) 2023 Fernando Magro and other contributors.
*
* 2023-02-08 Written by Anderson Costa
*/
#define F_CPU 16500000L
#include <TinyDebug.h>
#include <avr/io.h>
#include <util/delay.h>
#define setBit(valor, bit) (valor |= (1 << bit))
#define clearBit(valor, bit) (valor &= ~(1 << bit))
#define toogleBit(valor, bit) (valor ^= (1 << bit))
#define testBit(valor, bit) (valor & (1 << bit))
#define NUM_STATES 3
#define NUM_EVENTS 4
/* Enum to store the possible states */
typedef enum {
NEUTRAL, /* Neutral state */
FORWARD, /* Forward state */
REVERSE /* Reverse state */
} states_t;
/* Enum to store the possible events */
typedef enum {
NEUTRAL_BTN, /* Neutral button event */
REVERSE_BTN, /* Reverse button event */
FORWARD_BTN, /* Forward button event */
QUIT_BTN /* Quit button event */
} events_t;
/* Current state variable */
unsigned char current_state = NEUTRAL; /* Initial state */
unsigned char current_button = NEUTRAL_BTN; /* Initial state */
void not_valid(void);
void neutral(void);
void forward(void);
void reverse(void);
void quit_program(void);
/* State Event Matrix definition */
void (*state_event_matrix[NUM_EVENTS][NUM_STATES])() = {
/* Event Neutral */
{
not_valid, /* Callback when Neutral at NEUTRAL STATE */
neutral, /* Callback when Neutral at FORWARD STATE */
neutral /* Callback when Neutral at REVERSE STATE */
},
/* Event Reverse */
{
reverse, /* Callback when Reverse at NEUTRAL STATE */
not_valid, /* Callback when Reverse at FORWARD STATE */
not_valid /* Callback when Reverse at REVERSE STATE */
},
/* Event Forward */
{
forward, /* Callback when Forward at NEUTRAL STATE */
not_valid, /* Callback when Forward at FORWARD STATE */
not_valid /* Callback when Forward at REVERSE STATE */
},
/* Event Quit */
{
quit_program, /* Callback when Quit at NEUTRAL STATE */
not_valid, /* Callback when Quit at FORWARD STATE */
not_valid /* Callback when Quit at REVERSE STATE */
}
};
void not_valid(void)
{
/* Print a message indicating the state unchanged */
tdPrintln("**Not valid, state unchanged!**");
clearBit(PORTB, PB0);
clearBit(PORTB, PB1);
clearBit(PORTB, PB2);
}
void neutral(void)
{
/* Print a message indicating the state changed */
tdPrintln("State changed to neutral!");
setBit(PORTB, PB0);
clearBit(PORTB, PB1);
clearBit(PORTB, PB2);
/* Update the current state */
current_state = NEUTRAL;
}
void forward(void)
{
tdPrintln("State changed to forward!");
clearBit(PORTB, PB0);
setBit(PORTB, PB1);
clearBit(PORTB, PB2);
/* Update the current state */
current_state = FORWARD;
}
void reverse(void)
{
tdPrintln("State changed to reverse!");
clearBit(PORTB, PB0);
clearBit(PORTB, PB1);
setBit(PORTB, PB2);
/* Update the current state */
current_state = REVERSE;
}
void quit_program(void)
{
/* Print a message indicating that the State Event Machine has stopped */
tdPrintln("The State Event Machine has stopped!");
clearBit(PORTB, PB0);
clearBit(PORTB, PB1);
clearBit(PORTB, PB2);
/* Exit the program */
exit(0);
}
int main(void)
{
events_t event;
Debug.begin();
// Configuration of pins
DDRB = 0b00000111; // Outputs: PB0, PB1 and PB3
PORTB = 0b00111000; // Inputs with Pullup: PB4, PB3 and PB5
/* Always start the machine in neutral state */
neutral();
tdPrintln("State Event Machine Test");
tdPrintln("Commands:");
tdPrintln(" 'n' -> Change state to neutral");
tdPrintln(" 'f' -> Change state to forward");
tdPrintln(" 'r' -> Change state to reverse");
tdPrintln(" 'q' -> Quit");
while (1) {
/* Read a character from the input stream */
unsigned char c = Debug.read();
/* Check which event has been triggered */
switch (c) {
case 'n':
event = NEUTRAL_BTN;
break;
case 'f':
event = FORWARD_BTN;
break;
case 'r':
event = REVERSE_BTN;
break;
case 'q':
event = QUIT_BTN;
break;
default:
/* Invalid event, skip iteration */
continue;
}
/* Call the appropriate function for the event and state */
(*state_event_matrix[event][current_state])();
}
return 0;
}