아트메가/ATMEGA32U4 Breakout

ATMEGA32U4 breakout-보드 사용하기 4편(CLI)

원원 2024. 4. 4. 00:04

안녕하세요. 오늘은 기존의 프로젝트에 CLI기능을 추가하겠습니다.

CLI란 Command Line Interface의 약자이고 명령어를 입력해서 장치의 동작을 제어하고 상태를 모니터링할 수 있는 방법을 의미합니다. 해당 프로젝트는 이미 UART로 송수신기능이 구현되어있으므로 UART로 CLI기능을 추가하겠습니다. 이미 구현되어있는 CLI코드가 있으므로 해당 코드를 이 프로젝트에 옮겨서 사용하겠습니다. 해당코드는 UART통신할때 Write/Read하는 함수만 CLI코드에 동작가능하게 넣으면 되므로 다른 프로젝트에도 적용이 매우 쉽습니다. 그래서 해당코드를 설명하는 방식으로 적겠습니다.
코드 출처 : https://github.com/chcbaram/stm32wb55-ble/tree/main/firmware/exam/EX-04-CLI

기본적인 동작은 타이핑을하면 버퍼에 데이터를 저장해놓고 엔터를치면 해당커맨드들이 정해놓은 코드에 맞게 동작하게 됩니다.


*버퍼에 데이터를 저장하는 코드

    if (uartAvailable(cli_node.ch) > 0)
    {
        cliUpdate(&cli_node, uartRead(cli_node.ch));
    }

데이터 수신을 하나라도 했을때 uartRead함수로 데이터를 읽고 cliUpdate함수로 버퍼를 업데이트합니다.


*엔터를 치면 데이터를 처리하는 코드

        switch(rx_data)
        {
            // 엔터
            //
            case CLI_KEY_ENTER:
            if (line->count > 0)
            {
                cliLineAdd(p_cli);
                cliRunCmd(p_cli);
            }

            line->count = 0;
            line->cursor = 0;
            line->buf[0] = 0;
            cliShowPrompt(p_cli);
            break;

엔터를치면 0x0d (Carriage Return)가 들어오고 코드에서는 0x0d가 들어오면 엔터라고 인식하고 데이터를 처리합니다.


기본적인 동작은 위와 같고 커맨드를 추가하려면 cliAdd함수를 사용해서 추가하면 됩니다.
예를들어 help 커맨드 추가는 cliAdd(help, 함수명)과 같이 추가하면 됩니다. (함수명은 help를 쳤을때 실행되는 함수입니다)

bool cliAdd(const char *cmd_str, void (*p_func)(cli_args_t *))
{
    bool ret = true;
    cli_t *p_cli = &cli_node;
    uint16_t index;

    if (p_cli->cmd_count >= CLI_CMD_LIST_MAX)
    {
        return false;
    }

    index = p_cli->cmd_count;

    strcpy(p_cli->cmd_list[index].cmd_str, cmd_str);
    p_cli->cmd_list[index].cmd_func = p_func;

    cliToUpper(p_cli->cmd_list[index].cmd_str);

    p_cli->cmd_count++;

    return ret;
}

p_cli->cmd_list[index].cmd_str에 커맨드를 추가하게되고 p_cli->cmd_list[index].cmd_func에 실행되는 함수가 추가되게 됩니다. 그래서 엔터를쳤을때 첫번째 매개변수를 p_cli->cmd_list[index].cmd.str와 비교해서 일치하면 매칭되는 함수를 실행합니다.

해당코드에는 cli버퍼 디버깅기능이 있습니다. UART를 2개 사용해서 하나는 cli 동작용으로 사용하고 하나는 cli버퍼 디버깅용으로 볼 수 있습니다. 

    cliOpen(UART_CH2);
    cliOpenLog(UART_CH1);


이제 실제 사용해보겠습니다

help를 치면 저장해놓은 커맨드가 나오고, 우측에는 cli 버퍼정보가 나오게 됩니다.

port커맨드로 PORTD를 제어해보겠습니다.

port d 0 일때는 PORTD 가 0이 됩니다.

port d 16일때는 PORTD 가 16이 됩니다.


port를 타이핑했을때 호출되는 함수입니다. (cliPort)
args는 cli_node가 되게 됩니다. argc로 매개변수를 검사하고 (port제외) 2개면 정해둔 포맷과 일치하므로 if문에 들어가서 처리하게 됩니다. 만약 매개변수가 2개가 아니라면 ret은 false이므로 도움말을 출력하게 됩니다.

void cliPort(cli_args_t *args)
{
    bool ret = false;
    char* port;
    uint8_t port_num;
    int    argc = args->argc;
    char **argv = args->argv;

    if(argc == 2)
    {
        port = (char *)argv[0];
        port_num = (int)strtoul((const char * ) argv[1], (char **)NULL, (int) 0);
        if(port_num > 0xff)
            port_num = 0xff;
        if(strcasecmp(port,"D") == 0)
        {
            PORTD = port_num;
        }
        ret = true;
    }
    
    
    if(ret == false)
    {
        cliPrintf("-------------------\r\n");
        cliPrintf("ex)port d 16   => PORTD=16;\r\n");
        cliPrintf("port gpio_name number\r\n");
        cliPrintf("-------------------\r\n");
    }
}


소스코드(Commits: ADD CLI)
https://github.com/yhunterr/ATMEGA32u4/commits/main/