I have been trying to program a finite state machine using the zephyr RTOS. I chose this framework because of its extensive libraries and its finite state machine framework. However there is not that many examples out there to show how to use the SM framework correctly. The FSM I am trying to implement is for a booking system for a telematics (the box inside cars) in a car sharing system. Basically this system is supposed to receive a booking object, and this object traverses the booking state machine with mock events triggering the transitions. I chose the mock events to be button presses. I am using the nrf52832 Nordic Board to test the code. In zephyr you define the states based on their entry, run, and exit functions. My problem is that the button presses are not causing the state machine to transition. Basically all my transitions follow the same pattern. I will copy paste the code of the WAITING (see UML state chart for ref.) state's entry and run functions, and the ONGOING state's entry and run functions to show where I am stuck. The WAITING state has been working fine, it is when I arrive to the ONGOING state that it stops working the way it is supposed to.
static void waiting_entry(void *o)
{
printk("Entered WAITING state\nBooking No: %u has started\nDriver has 3 mins to start until booking is discarded\n\n", b_data.id);
gpio_pin_toggle_dt(&led1);
gpio_pin_toggle_dt(&led2);
k_timer_start(&waiting_for_start_press_timer, K_MINUTES(3), K_FOREVER);
//find a way to timestamp;
}
static void waiting_run(void *o)
{
int ret = k_event_wait(&booking_t.StartPressed, btn1_press, true, K_MINUTES(3));
if (ret == 0)
{
// discardBooking();
smf_set_state(SMF_CTX(&booking_t), &bsm[IDLE]);
}
// unlockDoor();
smf_set_state(SMF_CTX(&booking_t), &bsm[ONGOING]);
}
/* ONGOING STATE */
static void ongoing_entry(void *o)
{
printk("Entered ONGOING state\n");
gpio_pin_toggle_dt(&led2);
gpio_pin_toggle_dt(&led3);
k_timer_stop(&waiting_for_start_press_timer);
k_timer_start(&duration_of_ride_timer, K_SECONDS(30), K_FOREVER);
}
static void ongoing_run(void *o)
{
printk("\tongoinging run function here\n\n");
smf_set_state(SMF_CTX(&booking_t), &bsm[ONTIME_PARKING]);
}
/* ONTIME & PARKING STATE */
static void ontime_parking_entry(void *o)
{
printk("Entered ONTIME_PARKING state\n");
}
static void ontime_parking_run(void *o)
{
struct booking *b = (struct booking *)o;
k_msleep(10000);
if (b->events & btn1_press)
{
printk("\t\tbtn1_press event\n");
smf_set_state(SMF_CTX(&booking_t), &bsm[FINISHING]);
}
else if (b->events & btn2_press)
{
printk("\t\tbtn2_press event\n");
smf_set_state(SMF_CTX(&booking_t), &bsm[ONTIME_STATIONARY]);
}
}
The states of the state machine and the booking object are the following: enum bsm_state { IDLE, WAITING, ONGOING, ONTIME_PARKING, ONTIME_STATIONARY, ONTIME_MOVING, DELAYED_PARKING, DELAYED_STATIONARY, DELAYED_MOVING, FINISHING, };
/* booking object definition */
struct booking
{
struct smf_ctx ctx;
uint32_t id;
time_t start_tm;
time_t end_tm;
/* events */
struct k_event isStarting;
struct k_event DoneWaiting;
struct k_event StartPressed;
struct k_event FinishPressed;
struct k_event isLate;
struct k_event EngineOn;
struct k_event EngineOff;
struct k_event V_isIncrease;
struct k_event V_isZero;
struct k_event LocationConfirm;
int32_t events;
} booking_t;
I essentially would need some help with the following:
- How to make the transitions happen with the button press event, which mocks the StartPressed event by the driver (can also be seen in the UML statechart)
- How to pass a booking object to the state machine. I should mention that I trigger the start of the ride by defining a thread that enters in a function that posts the event isStarting, triggering the transition from the IDLE to the WAITING state, but I would like to treat this thread as the booking itself such that it starts in 3 minutes after boot-up time, has an id, and a ending time.
What I expeted from following the event-driven example given in the Zephyr website, was for the if statement (b->events & btn1_press) to be entered when the event was posted which is when the button 1 is pressed. I am not entirely sure how the state machine framework works, but given that the states are defined with the entry, run and exit actions, I thought that the run function is what is continuously being executed, so basically when the button is pressed, the callback function posts the event to the address btn1_press and then the if statement will be entered and transition to the corresponding state. What is actually happening is that the if statement is not being entered at all in the first place.
