rtthread AT指令下发程序

238 阅读2分钟

本来想用现成的AT组件的,结果发现添加后,程序压缩后还比原来大了20k,可能是因为下图几个服务层都选中了,AT和SAL是自动选中,libc不选中会出现[makefile:87: rtthread.elf] 的报错。

程序太大了,单片机放不下了,只能自己写了一个简易的at下发程序,在之前串口不定长基础上,参考往期博客 rtthread串口接收不定长数据 (关于伪帧尾那有改动,因为返回值有'\n'时会误判断)  具体如下:

#define PASS_MODE    0 //透传模式
#define AT_MODE      1 //AT模式
struct rt_semaphore at_rx_sem2;
char at_rx_data[50];
enum {WiFi = 1, NBIOT, BLE, lora, Zigbee, MCU}; //五种通信方式
enum {atWiFi, atTCP, at_check}; //要处理的AT相关信息
struct wifi_nbiot //wifi_nbiot相关信息
{
    char netmode;
    uint8_t transmode;//目前传输方式 wifi/nbiot
    bool atmode; //透传模式/at模式
    uint8_t data_sta;
    char WiFi_name[20];
    char WiFi_pswd[20];
    char ip[20];
    char port[4];
    char MAC[17];
};
struct wifi_nbiot  mycfg_tcp;


/****通过AT指令配置相关设备*******/

/***********/
/*
at指令下发及检测是否成功
tx_data:下发的AT数据
tx_num: 循环下发次数
rx_wait: 循环下发回馈等待时间
return: 0-发送读取失败 1-发送读取成功
*/
uint8_t at_tx_sta(char *tx_data, uint8_t tx_num, uint16_t rx_wait)
{
    uint8_t tx_len = strlen(tx_data);
    memset(at_rx_data, 0, sizeof(at_rx_data));
    memcpy(at_rx_data, tx_data, tx_len);
    for(uint8_t i=0; i<tx_num; i++)
    {
        rt_device_write(serial2, 0, at_rx_data, tx_len);
        rt_sem_control(&at_rx_sem2, RT_IPC_CMD_RESET, RT_NULL);
        if(RT_EOK == rt_sem_take(&at_rx_sem2, rx_wait))//rx_wait ms内获得at反馈
        {
            return 1;
        }
    }

    rt_kprintf("AT client send %s failed or return response error!", tx_data);
    return 0;
}

/*
处理远端tcp配置指令 进入at模式---读取或者设置参数---进入透传模式
dev_typ:设备类型 wifi nbiot ble lora
dev_parm:设备参数 wifi相关 tcp相关 检测参数
注意:此函数因为涉及到阻塞信号,不适合放到对时间有要求的线程里面,比如串口接收到配置信息后要在另一个线程里面调用此函数,否则会造成阻塞
*/
void cfg_dev_at(uint8_t dev_typ, uint8_t dev_parm)
{
    uint8_t check_flag = 0;
#define at_tx_delay 1000
    if(dev_typ == WiFi)
    {
        mycfg_tcp.atmode = AT_MODE;
        if(!at_tx_sta("+++", 6, at_tx_delay))//间隔at_tx_delayms 连发5次 +++ 进入at模式
        {
            mycfg_tcp.atmode = PASS_MODE;//进入失败
            rt_device_write(serial2, 0, "into AT mode failed,please try again", sizeof("into AT mode failed,please try again"));
            return;
        }

        if(dev_parm == atWiFi)
        {
            char set_wifi_head[100] = "at+wifi_conf=,wpa2_aes,\r\n";//at+wifi_conf=HI-LINK,wpa2_aes,12345678\r\n
            Insert_String(set_wifi_head, mycfg_tcp.WiFi_name, 14, strlen(mycfg_tcp.WiFi_name));//插入wifi名字到数组中
            Insert_String(set_wifi_head, mycfg_tcp.WiFi_pswd, 24+strlen(mycfg_tcp.WiFi_name), strlen(mycfg_tcp.WiFi_pswd));//插入wifi密码到数组中
            at_tx_sta(set_wifi_head, 5, at_tx_delay);
        }
        else if(dev_parm == atTCP)
        {
            char set_tcp_ip[50] = "at+remoteip=\r\n", set_tcp_port[30] = "at+remoteport=\r\n";//at+remoteip=192.168.11.245\r\n\ at+remoteport=8080\r\n
            Insert_String(set_tcp_ip, mycfg_tcp.ip, 13, strlen(mycfg_tcp.ip));//插入tcp ip到数组中
            Insert_String(set_tcp_port, mycfg_tcp.port, 15, strlen(mycfg_tcp.port));//插入tcp port到数组中
            at_tx_sta(set_tcp_ip, 5, at_tx_delay);
            at_tx_sta(set_tcp_port, 5, at_tx_delay);
        }
        else if(dev_parm == at_check)
        {
            if(at_tx_sta("at+netmode=?\r\n", 5, at_tx_delay))//获取netmode成功
            {
                mycfg_tcp.netmode = at_rx_data[15];
                if(at_tx_sta("at+Get_MAC=?\r\n", 5, at_tx_delay))
                {
                    memcpy(mycfg_tcp.MAC, at_rx_data+15, sizeof(mycfg_tcp.MAC));
                    check_flag = 1;
                }
            }
            rt_thread_mdelay(1000);
            if(at_tx_sta("at+out_trans=0\r\n", 6, at_tx_delay))//进入透传 退出at模式
                tx_cfg_hard_dev(serial2, check_flag);
            else//退出失败就重启
            {
                rst_my_dev(WiFi);
            }
        }
        if((dev_parm == atWiFi) || (dev_parm == atTCP))//提交网络设置
        {
            at_tx_sta("at+net_commit=1\r\n", 6, at_tx_delay);
            at_tx_sta("at+reconn=1\r\n", 6, at_tx_delay);
            at_tx_sta("at+out_trans=0\r\n", 6, at_tx_delay);
        }

        mycfg_tcp.atmode = PASS_MODE;
    }
    else if(dev_typ == NBIOT)
    {
        if(dev_parm == atWiFi)
        {

        }
        else if(dev_parm == atTCP)
        {

        }
        else if(dev_parm == at_check)
        {

        }
    }
}



static int uart4_ZIGBEE(void)
{
    ·····
    rt_sem_init(&at_rx_sem2, "at_rx_sem2", 0, RT_IPC_FLAG_FIFO);
    ·····
}

static  uint8_t rv_flag = 1;
static char HLK_NB_get_char(void)
{
    char ch;


    while (rt_device_read(serial2, 0, &ch, 1) == 0)
    {
        rt_sem_control(&rx_sem2, RT_IPC_CMD_RESET, RT_NULL);
        if(rv_flag)
            rt_sem_take(&rx_sem2, RT_WAITING_FOREVER);
        else if(-RT_ETIMEOUT == rt_sem_take(&rx_sem2, 100))//超时100ms未获得串口数据
        {
            rv_flag = 1; //收完一帧
//            ch = '\t';
            return;
        }
    }
    rv_flag = 0; //正常获取一个字节
    return ch;
}
/* 数据解析线程 */
static void ZIGBEE_data_parsing(void)
{
    while (1)
    {
        rx_temp = uart_ZIGBEE_get_char();
        if(!rv_flag)
        {
            data_buf[(rx_len++) % 50] = rx_temp;//防止数组越界  大小从30改为50 否则at回馈有可能会覆盖
        }
        else //开始处理一帧数据
        {
            rx_len = 0;
            rt_kprintf("uart4 received data is %s\n", data_buf);
            /* 帧数据处理 */
            
             if(mycfg_tcp.atmode == AT_MODE)//AT模式时不进行反馈
            {
                if((strstr(data_buf, "+++")) || (strstr(data_buf, "at+net_commit=1")) )//没有反馈
                    rt_sem_release(&at_rx_sem2);//发送信号量
                else if(!strncmp(data_buf, at_rx_data, strlen(at_rx_data)-2))//如果data_buf里面存在at_rx_data关键字(at模块端要开回显)  除去\r\n比较
                {
                    if(rx_len_temp - strlen(at_rx_data) > 3)//一般参数多于3个
                    {
                        memcpy(at_rx_data, data_buf, rx_len_temp);
                        rt_sem_release(&at_rx_sem2);//发送信号量
                    }
                }
                memset(data_buf, 0, sizeof(data_buf));
                continue;
            }
            ······
            memset(data_buf, 0, sizeof(data_buf));
        }
    }

}

/****发送硬件参数*******/
/*
serial:发送参数的串口号
check_flag:是否要发送
*/
void tx_cfg_hard_dev(rt_device_t serial, uint8_t check_flag)
{
    if(check_flag)
    {
        char str[] = "The configuration of WiFi_name,pswd,tcp_ip,port,MAC,netmode,transmode:";

        rt_device_write(serial, 0, str, sizeof(str));
        rt_device_write(serial, 0, mycfg_tcp.WiFi_name, sizeof(mycfg_tcp.WiFi_name));
        rt_thread_mdelay(200);
        rt_device_write(serial, 0, ",", 1);
        rt_device_write(serial, 0, mycfg_tcp.WiFi_pswd, sizeof(mycfg_tcp.WiFi_pswd));
        rt_thread_mdelay(200);
        rt_device_write(serial, 0, ",", 1);
        rt_device_write(serial, 0, mycfg_tcp.ip, sizeof(mycfg_tcp.ip));
        rt_thread_mdelay(200);
        rt_device_write(serial, 0, ",", 1);
        rt_device_write(serial, 0, mycfg_tcp.port, sizeof(mycfg_tcp.port));
        rt_thread_mdelay(200);
        rt_device_write(serial, 0, ",", 1);
        rt_device_write(serial, 0, mycfg_tcp.MAC, sizeof(mycfg_tcp.MAC));
        rt_thread_mdelay(200);
        rt_device_write(serial, 0, ",", 1);
        rt_device_write(serial, 0, &mycfg_tcp.netmode, 1);
        rt_thread_mdelay(200);
        rt_device_write(serial, 0, ",", 1);
        if(mycfg_tcp.transmode == WiFi)
            rt_device_write(serial, 0, "WiFi", sizeof("WiFi"));
        else if(mycfg_tcp.transmode == NBIOT)
            rt_device_write(serial, 0, "NB-IOT", sizeof("NB-IOT"));
    }
    else
    {
        char str[] = "check config of hardware failed, please try again";
        rt_device_write(serial, 0, str, sizeof(str));
    }
}

/****复位硬件设备*******/
//dev:要复位的设备
void rst_my_dev(uint8_t dev)
{
#define rst_delay 1000

    if(dev == WiFi)
    {
        rt_pin_write(HLK_LDO_EN, 0);
        rt_thread_mdelay(rst_delay);
        rt_pin_write(HLK_LDO_EN, 1);
    }
    else if(dev == NBIOT)
    {
        rt_pin_write(NB_LDO_EN, 0);
        rt_thread_mdelay(rst_delay);
        rt_pin_write(NB_LDO_EN, 1);
    }
    else if(dev == BLE)
    {

    }
    else if(dev == lora)
    {

    }
    else if(dev == Zigbee)
    {

    }
    else if(dev == MCU)
    {
        rt_pin_write(BLE_RST, 0);
        rt_pin_write(NB_LDO_EN, 0);
        rt_pin_write(HLK_LDO_EN, 0);
        rt_thread_mdelay(rst_delay);
        rt_hw_cpu_reset();
    }
}

/**
  * @brief  将指定长度的字符串插入到另一个字符串的指定位置
  * @param  oldstr 旧字符串; instr[] 插入的字符串;location 插入的位置; length 插入的数据长度
  * @retval no
  */
void Insert_String(char *oldstr, char instr[], int location, uint8_t length)
{
    int  j, k;
    char dat_tmp[100];

    for(j=0; j<location-1; j++)//将位置前的数据存到dat_tmp
        dat_tmp[j] = oldstr[j];

    //将instr复制到dat_tmp后面
    j--;
    k = 0;

    while(length --)
    {
        j++;
        dat_tmp[j] = instr[k];
        k++;
    }

    //将oldstr第location位后复制到dat_tmp尾部
    k = location - 1;
    while(oldstr[k] != '\0')
    {
        j++;
        dat_tmp[j] = oldstr[k];
        k++;
    }

    //给dat_tmp字符串添加结束符
    j++;
    dat_tmp[j] = '\0';
    //将dat_tmp字符串复制给oldstr
    for(k=0; k<=j; k++)
        oldstr[k] = dat_tmp[k];
}


例:
void cfg_hard_dev(void)
{
    at_tx_sta("+++", 5, 200);//间隔200ms 连发5次 +++ 进入透传模式
    cfg_dev_at(WiFi, atTCP);//通过wifi设置tcp参数
    cfg_dev_at(WiFi, at_check);//通过wifi获取硬件参数
}