App state machine 만들기 #3 app_first.c

이번 포스트에서는 app state 중에 첫번째 first app을 만들도록 하겠습니다. 지난번에 말씀드린 대로 앞으로 만들어질 app states 들은 모두 app controller(app.c)에 등록되어 제어가 될 예정입니다. 그 중에 오늘은 첫번째 app이라서 의미가 있습니다. 사실 첫번째 app 만 이해한다면 두번째, 세번째는 비슷하기 때문에 별도의 설명이 필요없습니다.

 

지난 시간에 우리는 아래 코드 처럼 이미 세개의 app을 만들기 위해 app_id를 app.h에 미리 선언했었습니다.

/* app.h */
typedef enum
{
  APP_first,
  APP_second,
  APP_third,
  APP_COUNT,
  APP_NONE,
}app_id_t;
 

APP_first는 첫번째 app의 id가 되는 것입니다.

 

app_first.h 즉, 첫번째 앱의 헤더파일을 살펴보겠습니다.

#ifndef APP_APP_FIRST_H_
#define APP_APP_FIRST_H_

extern void app_first_init(void);

#endif
 

app_first_init는 첫번째 app을 초기화하고 app controller에 등록하는 일까지 합니다.

그럼 app_first.c의 초기화 함수를 보겠습니다.

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,
};
void app_first_init(void)
{
  app_init_app(&this);
}
 

app_init_app 안에 this를 app cotroller에 등록하는 것으로 초기화를 마칩니다.

그럼 app의 각각의 내장함수 들을 살펴보겠습니다.

/**
  * @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;
  }
}
 

first app이 active 상태가 되면 각각의 내장 함수들이 controller에 의해 호출 될 수 있으며 현재 state에 맞는 코드가 구현되어 있어야 합니다. 위의 예제에서는 loop 함수가 무한으로 돌게 되어 있고 키가 눌리면 second app으로 스위칭 되게 되어 있습니다.

 

loop는 RTOS의 task안에서 동작하는 것이 아니기 때문에 Delay가 발생하면 시스템이 그 만틈 멈추어 있다고 생각하여야 합니다. 즉, 위의 예제의 경우 1초 동안 시스템이 멈추어 있다가 동작할 것입니다.

 

  • init(void)
    • 현재 app을 초기화 합니다. 이는 app 등록시 한번 호출 됩니다.
  • start(void)
    • app이 active 되는 시점에 호출됩니다. 각종 flag 초기화 코드가 들어가면 좋습니다.
  • stop(void)
    • app이 다른 app을 active 상태가 스위칭 되기전 한번 씩 호출됩니다.
    • 현재 상태에서 데이터를 정리하는 코드가 들어가면 됩니다.
  • loop(void)
    • app이 active 되어 있다면 무한정으로 호출됩니다.
  • on_msg(msg_t msg, uint32_t param1, uint32_t param2)
    • app이 active 되어 있다면 시스템으로 부터 메시지를 받을 수 있습니다.

 

오늘은 app state 중에 첫번째 app을 살펴보았습니다.

다음 포스트에서는 main.c을 살펴보도록 하겠습니다.