Exercise-003 Nested switch implementation of an FSM part 2
In this article, let’s continue Nested switch implementations.
Please note that, whenever you see a Guard condition, you have to use an ‘if’ statement while implementing that in the code.
Guard conditions are converted into decision-making statements of any programming language, like the ‘if’ statement.
Let me explain the implementation of the TIME_TICK event(as shown in Figure 2). This is an internal transition, [mobj-> c_time==0] can be an external transition sometimes on the evaluation of this Guard. There is one choice node.
Let’s see how that is implemented in the code.
case TIME_TICK:{ if(((protimer_tick_event_t*)(e))->ss == 10){ --mobj->curr_time; ++mobj->elapsed_time; display_time(mobj->curr_time); if(!mobj->curr_time){ mobj->active_state = IDLE; return EVENT_TRANSITION; } return EVENT_HANDLED; } return EVENT_IGNORED; }
TIME_TICK function code
See TIME_TICK function code. case TIME_TICK. [e-> ss == 10] a guard condition, which is converted into an ‘if’ statement.
if(ss == 10). ‘e’ is the pointer, which is downcasted to protimer_tick_event_t* type. Use one more parenthesis, and you access the member element of this structure.
if(ss == 10), then you have to take action. The actions are current time decremented, elapsed time incremented, then display_time.
And after that [mobj->c_time == 0] is evaluated. Another ‘if’ condition. if(!mobj->curr_time). If curr_time is 0, then the condition will be true; that’s an external transition to the IDLE state if it is true. If it is not true, that remains as an internal transition. So, return EVENT_HANDLED.
If(((protimer_tick_event_t*)(e))->ss == 10) is not true, then we just return EVENT_IGNORED. You have to implement the rest of the code.
In the STAT, ENTRY action, EXIT action are completed. And after that, TIME_TICK is an external transition. This has one Guard.
case TIME_TICK:{ if(((protimer_tick_event_t*)(e))->ss == 10){ mobj->active_state = IDLE; return EVENT_TRANSITION; } return EVENT_IGNORED; }
TIME_TICK event for STAT
How to implement this?
If statement, you take the ‘e’ downcast it. Because I have to access the ‘ss’ member element. protimer_tick_event_t*, and then put one parenthesis to access the ss. If ss = 10, you have to make a transition mobj->active_state = IDLE; and return EVENT_TRANSITION; otherwise, you have to return EVENT_IGNORED.
We have completed the implementation of all the state handlers and now let’s implement the Event dispatcher.
The Event dispatcher dispatches events to the state machine implementation. Event dispatcher that’s a small function we will write in main.cpp as shown below.
#include "main.h" static void protimer_event_dispatcher(protimer_t *const mobj,event_t const *const e); /*Main application object */ static protimer_t protimer; void setup() { // put your setup code here, to run once: protimer_init(&protimer); } void loop() { } static void protimer_event_dispatcher(protimer_t *const mobj,event_t const *const e){ event_status_t status; protimer_state_t source, target; source = mobj->active_state; status = protimer_state_machine(mobj,e); if(status == EVENT_TRANSITION){ target = mobj->active_state; event_t ee; //1. run the exit action for the source state ee.sig = EXIT; mobj->active_state = source; protimer_state_machine(mobj,&ee); //2. run the entry action for the target state ee.sig = ENTRY; mobj->active_state = target; protimer_state_machine(mobj,&ee); } }
Event dispatcher code implementation
First, ‘e’ receives the fresh event and is sent to the protimer_state_machine. The fresh event is sent to the state machine, if there was no transition, then nothing to process. It’s over. That event was handled or ignored; we don’t care.
But, if this status is EVENT_TRANSITION, that means there was a transition, and the active_state of mobj has already been updated.
As per the specification, we must call the first exit action and then the transition action. Still, we have slightly modified that.
First, the transition action is already executed here inside the Protimer_state_machine function. After that, we run the exit action for the source state, which we saved here. And for the Entry action, you have to update the state variable = target.
target = mobj->active_state variable.
If there was really a transition, then the new state or the target state is saved in the target variable, which is used to execute the Entry action. But the source state, which you saved here before processing the event or before sending the event to the state machine, was used to run the EXIT action.
We have completed the protimer_event_dispatcher code, and this event dispatcher is called from the loop function, as shown in Figure 3.
In the loop function, we will be doing three important tasks.
The first one is we have to read the button pad status. We have got three buttons; we will call it a button pad, we have to read the status of that.
And then make an event. Convert that button pad status to an instance of an event structure, that is, make an event. And then send it to the event dispatcher.
So, now to implement the first task, read the button pad status, we have to understand how the button is connected to the Arduino and also have to discuss the software button debouncing.
In the upcoming article, we will explore the hardware connections. Like the connections of the button pad, I will also discuss connections of the LCD to the Arduino board, and then we will code the rest of the program.
FastBit Embedded Brain Academy Courses
Click here: https://fastbitlab.com/course1