app 은 하나의 상태로 명명하기로 하였습니다. 예를 들자면 안드로이드 앱의 activity 처럼 시스템의 모든 이벤트를 받고 UI를 이루며 프로그램을 동작시키는 하나의 상태라고 이해하면 될 것 같습니다.
Full src : https://github.com/soloungos/h7_state_machine
위의 예제에서 app states는 세가지의 상태를 가지고 있습니다.
- app_first.c :
- 시스템이 시작할 때 최초의 상태, 그 후 합계를 구하는 알고리즘을 계속적으로 수행하다 key 입력 이벤트를 받으면 app second로 스위칭
- app_second.c :
- 평균을 구하는 알고리즘을 계속적으로 수행하다가 key 입력 이벤트를 받으면 app third로 스위칭
- app_third.c :
- 하는 일 없이 있다가 key 입력 이벤트를 받으면 app first로 스위칭
이전에 정의했던 app 타입을 먼저 보시면 이해가 쉬울 것입니다.
typedef struct
{
app_id_t id;
app_id_t prev_id;
uint32_t flags;
void (*init)(void);
void (*start)(void);
void (*stop)(void);
void (*loop)(void);
void (*on_msg)(msg_t msg, uint32_t param1, uint32_t param2);
}app_t;
첫번째 app first 입니다. 계속 말씀드리지만 app의 원형은 모두 동일합니다.
/*
* app_first.c
*
* Created on: Feb 18, 2021
* Author: soloungos
*/
#include "app.h"
#include "algorithm.h"
#include "algorithm_sum.h"
#define FLAGS_DEFALUT (0x00000000)
static void init(void);
static void start(void);
static void stop(void);
static void loop(void);
static void on_msg(msg_t msg, uint32_t param1, uint32_t param2);
static app_t this =
{
APP_first,
APP_NONE,
0x00000000,
init,
start,
stop,
loop,
on_msg,
};
/**
* @brief This function is executed in case of ...
* @retval ..
*/
void app_first_init(void)
{
app_init_app(&this);
}
/**
* @brief This function is executed in case of ...
* @retval ..
*/
static void init(void)
{
}
/**
* @brief This function is executed in case of ...
* @retval ..
*/
static void start(void)
{
}
/**
* @brief This function is executed in case of ...
* @retval ..
*/
static void stop(void)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
}
/**
* @brief This function is executed in case of ...
* @retval ..
*/
static void loop(void)
{
uint32_t array[10] = {1,2,3,4,5,6,7,8,9,10};
uint32_t length = 10;
uint32_t result = 0;
algorithm_t *algorithm = algorithm_sum();
algorithm->init();
algorithm->execute((void *)array, (void *)&length, (void *)&result);
HAL_Delay(1000);
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
}
/**
* @brief This function is executed in case of ...
* @retval ..
*/
static void on_msg(msg_t msg, uint32_t param1, uint32_t param2)
{
switch(msg)
{
case MSG_KEY_INTERRUPT:
app_switch_app(APP_second);
break;
default:
break;
}
}
loop() 에서 GPIO 토글과 sum algorithm을 strategy 패턴으로 받아와 동작시킵니다. 그리고 메시지로 key 입력을 받으면 app second로 스위칭 됩니다.
두번째 app second입니다.
/*
* app_second.c
*
* Created on: Feb 18, 2021
* Author: soloungos
*/
#include "app.h"
#include "algorithm.h"
#include "algorithm_avg.h"
#define FLAGS_DEFALUT (0x00000000)
static void init(void);
static void start(void);
static void stop(void);
static void loop(void);
static void on_msg(msg_t msg, uint32_t param1, uint32_t param2);
static app_t this =
{
APP_second,
APP_NONE,
0x00000000,
init,
start,
stop,
loop,
on_msg,
};
/**
* @brief This function is executed in case of ...
* @retval ..
*/
void app_second_init(void)
{
app_init_app(&this);
}
/**
* @brief This function is executed in case of ...
* @retval ..
*/
static void init(void)
{
}
/**
* @brief This function is executed in case of ...
* @retval ..
*/
static void start(void)
{
}
/**
* @brief This function is executed in case of ...
* @retval ..
*/
static void stop(void)
{
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, GPIO_PIN_RESET);
}
/**
* @brief This function is executed in case of ...
* @retval ..
*/
static void loop(void)
{
uint32_t array[10] = {1,2,3,4,5,6,7,8,9,10};
uint32_t length = 10;
uint32_t result = 0;
algorithm_t *algorithm = algorithm_avg();
algorithm->init();
algorithm->execute((void *)array, (void *)&length, (void *)&result);
HAL_Delay(250);
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_1);
}
/**
* @brief This function is executed in case of ...
* @retval ..
*/
static void on_msg(msg_t msg, uint32_t param1, uint32_t param2)
{
switch(msg)
{
case MSG_KEY_INTERRUPT:
app_switch_app(APP_third);
break;
default:
break;
}
}
loop() 에서 GPIO 토글과 average algorithm을 strategy 패턴으로 받아와 동작시킵니다. 그리고 메시지로 key 입력을 받으면 app third로 스위칭 됩니다.
마지막으로 app third입니다.
/*
* app_third.c
*
* Created on: Feb 18, 2021
* Author: soloungos
*/
#include "app.h"
#define FLAGS_DEFALUT (0x00000000)
static void init(void);
static void start(void);
static void stop(void);
static void loop(void);
static void on_msg(msg_t msg, uint32_t param1, uint32_t param2);
static app_t this =
{
APP_third,
APP_NONE,
0x00000000,
init,
start,
stop,
loop,
on_msg,
};
/**
* @brief This function is executed in case of ...
* @retval ..
*/
void app_third_init(void)
{
app_init_app(&this);
}
/**
* @brief This function is executed in case of ...
* @retval ..
*/
static void init(void)
{
}
/**
* @brief This function is executed in case of ...
* @retval ..
*/
static void start(void)
{
}
/**
* @brief This function is executed in case of ...
* @retval ..
*/
static void stop(void)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_RESET);
}
/**
* @brief This function is executed in case of ...
* @retval ..
*/
static void loop(void)
{
HAL_Delay(500);
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_14);
}
/**
* @brief This function is executed in case of ...
* @retval ..
*/
static void on_msg(msg_t msg, uint32_t param1, uint32_t param2)
{
switch(msg)
{
case MSG_KEY_INTERRUPT:
app_switch_app(APP_first);
break;
default:
break;
}
}
loop() 에서 GPIO 토글동작을 시킵니다. 그리고 메시지로 key 입력을 받으면 app first로 스위칭 됩니다.
app 의 내부 함수는 필요에 따라 추가 삭제하여도 무방합니다. flag는 해당 app의 전용입니다. 필요에 따라 늘리거나 수정할 수 있습니다.
간단한 세가지 app states machine에 대해 구현해 보았습니다. 어느 어플리케이션에서든지 위와 같은 states machine은 적용될 수 있으며 소프트웨어를 보다 간단하고 유지보수 하기 쉽게 만들어 줍니다. 실제로 많은 어플리케이션에서 사용되는 패턴이며 RTOS와 같이 적용해도 아무런 문제가 되지 않습니다.
이상으로 app states machine에 대한 포스팅을 마치겠습니다.
'▶ C Application > App 만들기' 카테고리의 다른 글
App state machine 만들기 #4 main.c (0) | 2023.11.15 |
---|---|
App state machine 만들기 #3 app_first.c (0) | 2023.11.15 |
App state machine 만들기 #2 app.c (0) | 2023.11.15 |
App state machine 만들기 #1 app.h (0) | 2023.11.15 |
App state machine 개요 (0) | 2023.11.14 |