#pragma once // lets assume we have some app with 4 states, 3 differnet input that change the state // states : [locked, unlocked, off, debug] // change actions : lock, str_input, power button // // pwr ┌──────────┐ pwr // ┌─────┴┬────►│off state │◄────┴┐ // │ │ └────┬─────┘ │ // │ │ │ │ // │ │ ┌─────┘ │ // │ │ ├ pwr │ // │ │ ▼ │ // │ ┌──┴─────┐ str=pwd ┌────┴───┐ // │ │lock ├─────┴─────►│unlock │ // │ │state │ │state │ // │ └──────┬─┘◄───┬───────┴──┬─────┘ // │ ▲ │ lck │ // │ lck ┤ ├ str=dbg ├ str=dbg // │ │ │ │ // │ │ │ │ // │ │ ▼ │ // │ ┌─┴──────┐ │ // └───┤debug │◄──────────────┘ // │ │ // └────────┘ // the state pattern was primarly made in languages that had access to such great things // like object and interfaces but in c we must implement these ourselves // forward decl for Device struct typedef struct Device_s Device_t; // the interface that you would use to interface with the state typedef struct DeviceInterface_s{ // all the actions that change the state // normally there wouldnt be any args // but as we dont have a protected keyword // we have to pass in the device to change // the state // the function called when the power button is pressed void (*pressPwr)(Device_t*); // the function called when we want to enter the string void (*pressStrInput)(Device_t*); // the function called when the lock button is pressed void (*pressLock)(Device_t*); } DeviceInterface_t; // the states themselves typedef struct DeviceState_s{ // the name of the current state the device is in // i mainly use this for debugging const char* state_name; // the methods that this struct has (also called a vtable) DeviceInterface_t methods; } DeviceState_t; // the device struct Device_s{ // the current state of the device DeviceState_t state; // the string that the user has inputed null terminated char* entered_string; }; /// @brief creates a new device at the given pointer /// @arg device: a pointer to where the struct is created void initDevice(Device_t* device); // this is your interface between the state /// @brief presses the Pwr button on the device /// @arg device: the device that has it button pressed void pressPwrButton(Device_t *device); /// @brief presses the StrInput button on the device /// @arg device: the device that has it button pressed void pressStrInputButton(Device_t *device); /// @brief presses the Lock button on the device /// @arg device: the device that has it button pressed void pressLockButton(Device_t *device);