OpenHarmony中AT模块的代码理解(2) 原创 精华

再见南丫岛
发布于 2022-3-17 21:56
浏览
2收藏

开启AT模块的第二篇帖子的整理。第一篇帖子链接如下:OpenHarmony中AT模块的代码理解(1)

1、at_uart_task_body

hi_void *at_uart_task_body(hi_void* param)
{
    hi_unref_param(param);
    hi_char ch;
    hi_s32 n;
    for (;;) {
        if (g_at_input_func == NULL) {
            n = hi_uart_read(g_at_uart_port, (hi_u8 *)&ch, 1);
        } else {
            n = g_at_input_func((UINT8 *)&ch, 1);
        }
        if (n != 1) {
            (hi_void)hi_sleep(AT_UART_SLEEP);
            continue;
        }
        if ((hi_lpc_get_type() != HI_NO_SLEEP) && (g_at_check_empty == HI_TRUE)) {
            g_at_have_uart_data = HI_TRUE;
            hi_timer_start(g_at_uart_timer_handle, HI_TIMER_TYPE_ONCE, AT_WAIT_TIME, timer_handle, 0);
        }

        at_parse_uart_char(ch);
    }
}

该函数的为一个任务,是一个循环函数。除去睡眠的逻辑外,注意的代码功能是通过串口获取一个字节数据。然后使用at_parse_uart_char(ch)函数进行处理。g_at_input_func函数的功能为模拟接收数据,主要用于测试,可以先不考虑。

2、at_parse_uart_char

hi_void at_parse_uart_char(hi_char ch)
{
    switch (g_at_ctrl.at_state) {
        case AT_IDLE:
            g_busy_count = 0;
            at_cmd_line_parse(ch);
            break;
        case AT_CMD_PROCESS:
            hi_cpup_load_check_proc(hi_task_get_current_id(), LOAD_SLEEP_TIME_DEFAULT);

            if (ch == '\n') {
                if (g_busy_count >= SOFT_REBOOT_MAX_BUSY_CNT) {
                    g_busy_count = 0;
                    hi_soft_reboot(HI_SYS_REBOOT_CAUSE_AT_BUSY);
                }
                hi_at_printf("busy!\r\n");
                g_busy_count++;
            }
            break;
        case AT_DATA_RECVING:
            g_busy_count = 0;
            if (at_data_recving() != HI_ERR_SUCCESS) {
                break;
            }
            at_get_send_data(ch);
            break;
        case AT_DATA_SENDING:
            hi_cpup_load_check_proc(hi_task_get_current_id(), LOAD_SLEEP_TIME_DEFAULT);
            if (g_at_ctrl.is_first_over_data) {
                g_at_ctrl.is_first_over_data = HI_FALSE;
                hi_at_printf("busy!\r\n");
            }
            break;
        case AT_TRANSPARENT:
            hi_at_printf("==TBD==\r\n");
            break;
        default:
            break;
    }
}

函数主要是有5个状态机的切换。

typedef enum {
    AT_IDLE,//空闲模式
    AT_CMD_PROCESS,//命令处理模式
    AT_DATA_RECVING,//数据正在接收
    AT_DATA_SENDING,//数据正在发送
    AT_TRANSPARENT,//未实现
} at_state_machine;

在AT_IDLE状态下,at_cmd_line_parse(ch);继续处理接收到的字符。是我们主业务逻辑的函数。
在AT_CMD_PROCESS状态下,输入的字符会被扔掉,且如果数据的指令行数超过次,则会触发软重启操作。这样操作的好处,还不清楚。
在AT_DATA_RECVING和AT_DATA_SENDING状态,处理的典型场景是AT+IPSEND发送TCP/UDP数据的时候。
OpenHarmony中AT模块的代码理解(2)-鸿蒙开发者社区
OpenHarmony中AT模块的代码理解(2)-鸿蒙开发者社区
协议中注明了\0作为发送结束符,如果要发送\0,需转义成\0。这样,就比较好理解hi_void at_get_send_data(hi_char c)的处理模式了。

3、at_cmd_line_parse

hi_void at_cmd_line_parse(hi_char c)
{
    hi_char ch = c;
    static hi_u32 i = 0;
    static hi_s32 key_value = 0;
    static hi_u32 enter_flag = 0;

    if ((i == 0) && (ch != '\n')) {
        (hi_void)memset_s(g_at_buf, CMD_MAX_LEN, 0, CMD_MAX_LEN);
    }

    if (ch == '\n') {
        if (i == 0) {
            hi_at_printf("\r\nERROR\r\n");
            g_at_ctrl.at_state = AT_IDLE;
            return;
        }

        if (enter_flag == (i - 1)) {
            i = 0;
            g_at_ctrl.at_state = AT_CMD_PROCESS;
            at_notify();
        }
        return;
    }

    enter_flag = 0;

    if (ch == '\r') {
        if (i == 0) {
            hi_at_printf("\r\nERROR\r\n");
            g_at_ctrl.at_state = AT_IDLE;
            return;
        }
        if (i < (CMD_MAX_LEN - 1)) {
            g_at_buf[i] = '\0';
        }
        enter_flag = i;
        i++;
        return;
    }

    if (at_key_filter(ch, &i, &key_value) != HI_ERR_SUCCESS) {
        return;
    }

    if (ch != '\n') {
        at_cmd_print_back(i, ch);
        i++;
    }

    key_value = STAT_NOMAL_KEY;
}

该函数主要是几个if的条件判断。

if (ch != '\n') {
   at_cmd_print_back(i, ch);
   i++;
}

当字符串没有到截止符(\R\N)的时候,将接受到的字符通过at_cmd_print_back存储在g_at_buf中。
当if (ch == ‘\r’) 和if (ch == ‘\n’)两个判断的结合,即结尾是\r\n且字符串不为空的时候,将g_at_ctrl.at_state = AT_CMD_PROCESS切换模式,并且发送at_notify(),来通知数据处理的任务,进行AT命令的数据处理。


本篇文章就先介绍到这里。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-3-17 21:56:46修改
4
收藏 2
回复
举报
1条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

关键函数终于来喽

回复
2022-3-18 10:02:12
回复
    相关推荐