App state machine 만들기 #2 app.c

먼저 우리가 구현해야 할 app controller의 extern 함수들을 확인하겠습니다.

extern int app_init_app(app_t *app);
extern void app_process(void);
extern int app_set_msg(msg_t msg, uint32_t param1, uint32_t param2);
extern int app_start_app(app_id_t id);
extern int app_switch_app(app_id_t id);
extern app_t *app_get_current_app(void);
 

각각의 역할은 지난 포스트에서 기록한 대로입니다.

  • app_init_app - app 등록
  • app_process - 현재 active app의 loop 실행, 메시지 큐에서 빼내어온 메시지 전달
  • app_set_msg - 현재 active app 메시지 전달
  • app_start_app - active app start
  • app_switch_app - app state 전환
  • app_get_current_app - 현재 active app id 전달
static app_id_t current_app_id = APP_NONE;
static app_t *apps[APP_COUNT]={0, };

static int app_loop_current_app(void);
static void app_on_msg_app(void);
 

각 app들의 포인터를 담을 apps 배열과 몇 개의 static 함수들이 있습니다. current_app_id 는 현재 active 상태의 app id 입니다.

 

아래는 app을 등록하는 함수 인데 중요한 점은 등록과 동시에 그 app의 init을 해준다는 것입니다.

int app_init_app(app_t *app)
{
  if(app == NULL)
    return -1;

  apps[app->id] = app;
  apps[app->id]->init();

  return 0;
}
 

아래 app_process는 main.c의 main infinite loop 에서 호출합니다. 계속해서 메세지 큐에서 쌓인 메시지를 현재 active 상태의 app에 전달(app_on_msg_app)하는 것과 app의 loop 함수를 실행(app_loop_current_app) 시키는 역할을 합니다.

void app_process(void)
{
  app_on_msg_app();
  app_loop_current_app();
}
 

app_set_msg는 메시지 큐에 메시지를 송신하는 함수로 msg와 두개의 파라메터로 이루어져 있습니다.

int app_set_msg(msg_t msg, uint32_t param1, uint32_t param2)
{
  msgs_set_msg(msg, param1, param2);

  return 0;
}
 

아래 함수는 app을 active 상태로 만드는 기능을 합니다. app의 id를 넘겨주면 해당 app은 active 상태가 되어 메시지 수신, loop 수행을 할 수 있습니다.

int app_start_app(app_id_t id)
{
  if((id >= APP_COUNT) || (apps[id]->start == NULL))
    return -1;

  current_app_id = id;
  apps[id]->start();

  return 0;
}
 

app_switch_app 는 현재 active 된 app을 바꾸는 기능을 합니다. 그 와중에 이전의 app은 stop 함수를 호출해주어 안전하게 app이 스위칭 될 수 있도록 해줍니다.

int app_switch_app(app_id_t id)
{
  if((id >= APP_COUNT) || (apps[id] == NULL))
    return -1;

  if(current_app_id == id)
    return -1;

  apps[current_app_id]->stop();
  apps[id]->prev_id = current_app_id;
  current_app_id = id;
  apps[id]->start();

  return 0;
}
 

아래 함수는 현재 app의 포인터를 반환하는 함수입니다.

app_t *app_get_current_app(void)
{
  return apps[current_app_id];
}
 

app_on_msg_app는 현재 active 상태의 app에 메시지를 전달하는 함수이며 app_loop_current_app 함수는 현재 active 상태의 app의 loop를 실행시켜주는 역할을 합니다.

static void app_on_msg_app(void)
{
  msg_t msg;
  uint32_t param1;
  uint32_t param2;

  if(apps[current_app_id]->on_msg == NULL)
    return;

  while(msgs_get_msg(&msg, &param1, &param2) != -1)
  {
    apps[current_app_id]->on_msg(msg, param1, param2);
  }
}


static int app_loop_current_app(void)
{
  if(apps[current_app_id]->loop == NULL)
    return -1;

  apps[current_app_id]->loop();
  return 0;
}
 

이렇게 전반적인 app controller에 대해 알아보았습니다. app controller는 중재자 역할을 하며 app에 실제적인 동작을 실행시켜줍니다. 따라서 구체적인 기능 구현은 각각의 app state에 있습니다. 다음에는 이런 app state를 구현해 보도록 하겠습니다.