RT-Thread-packages / at_device

AT component porting or samples for different devices
Apache License 2.0
214 stars 181 forks source link

第二次提取IP地址后,IP地址是urc返回的,这个导致IP获取失败 #155

Closed majianjia closed 3 years ago

majianjia commented 3 years ago

这个问题出现了几天了,原本以为是ESP8266的问题,后来换了SIM800c也是一样的现象。 这里给出ESP8266的log,请熟悉的大佬帮我看看是啥问题。

平台是STM32L476,LPUART1,115200, RTT 4.0.3, AT Device是latest

LOG 里面第1332行开始,之后就不正常了。1332行本身也是有问题 esp8266.log

我分析的过程如下 1332 之后的,发送close socket,超时返回

[D/AT] sendline: 0000-0020: 41 54 2B 43 49 50 43 4C  4F 53 45 3D 30                                                               AT+CIPCLOSE=0
[D/AT] recvline: 0000-0020: 00 30 2C 43 4C 4F 53 45  44 0D 0A                                                                     .0,CLOSED..
[D/AT] recvline: 0000-0020: 0D 0A                                                                                                 ..
[614885] D/at.clnt: execute command (AT+CIPCLOSE=0) timeout (300 ticks)!

之后mqtt应该是在新建一个socket

[D/AT] sendline: 0000-0020: 41 54 2B 43 49 50 44 4F  4D 41 49 4E 3D 22 71 62  65 32 36 62 34 36 2E 65  6E 2E 65 6D 71 78 2E 63    AT+CIPDOMAIN="qbe26b46.en.emqx.c
[D/AT] sendline: 0020-0040: 6C 6F 75 64 22                                                                                        loud"
[619885] D/mqtt: inter mqtt_connect_callback!
[D/AT] recvline: 0000-0020: 4F 4B 0D 0A                                                                                           OK..
[D/AT] recvline: 0000-0020: 2B 43 49 50 44 4F 4D 41  49 4E 3A 35 34 2E 31 36  36 2E 37 36 2E 31 37 38  0D 0A                      +CIPDOMAIN:54.166.76.178..
[D/AT] recvline: 0000-0020: 0D 0A                                                                                                 ..
[D/AT] sendline: 0000-0020: 41 54 2B 43 49 50 44 4F  4D 41 49 4E 3D 22 71 62  65 32 36 62 34 36 2E 65  6E 2E 65 6D 71 78 2E 63    AT+CIPDOMAIN="qbe26b46.en.emqx.c
[D/AT] sendline: 0020-0040: 6C 6F 75 64 22                                                                                        loud"
[D/AT] recvline: 0000-0020: 4F 4B 0D 0A                                                                                           OK..
[D/AT] recvline: 0000-0020: 2B 43 49 50 44 4F 4D 41  49 4E 3A 35 34 2E 31 36  36 2E 37 36 2E 31 37 38  0D 0A                      +CIPDOMAIN:54.166.76.178..
[D/AT] recvline: 0000-0020: 0D 0A                                                                                                 ..
[D/AT] sendline: 0000-0020: 41 54 2B 43 49 50 44 4F  4D 41 49 4E 3D 22 71 62  65 32 36 62 34 36 2E 65  6E 2E 65 6D 71 78 2E 63    AT+CIPDOMAIN="qbe26b46.en.emqx.c
[D/AT] sendline: 0020-0040: 6C 6F 75 64 22                                                                                        loud"
[D/AT] recvline: 0000-0020: 4F 4B 0D 0A                                                                                           OK..
[D/AT] recvline: 0000-0020: 2B 43 49 50 44 4F 4D 41  49 4E 3A 35 34 2E 31 36  36 2E 37 36 2E 31 37 38  0D 0A                      +CIPDOMAIN:54.166.76.178..
[D/AT] recvline: 0000-0020: 0D 0A                                                                                                 ..
[D/AT] sendline: 0000-0020: 41 54 2B 43 49 50 44 4F  4D 41 49 4E 3D 22 71 62  65 32 36 62 34 36 2E 65  6E 2E 65 6D 71 78 2E 63    AT+CIPDOMAIN="qbe26b46.en.emqx.c
[D/AT] sendline: 0020-0040: 6C 6F 75 64 22                                                                                        loud"
[D/AT] recvline: 0000-0020: 4F 4B 0D 0A                                                                                           OK..
[D/AT] recvline: 0000-0020: 2B 43 49 50 44 4F 4D 41  49 4E 3A 35 34 2E 31 36  36 2E 37 36 2E 31 37 38  0D 0A                      +CIPDOMAIN:54.166.76.178..
[D/AT] recvline: 0000-0020: 0D 0A                                                                                                 ..
[D/AT] sendline: 0000-0020: 41 54 2B 43 49 50 44 4F  4D 41 49 4E 3D 22 71 62  65 32 36 62 34 36 2E 65  6E 2E 65 6D 71 78 2E 63    AT+CIPDOMAIN="qbe26b46.en.emqx.c
[D/AT] sendline: 0020-0040: 6C 6F 75 64 22                                                                                        loud"
[D/AT] recvline: 0000-0020: 4F 4B 0D 0A                                                                                           OK..
[D/AT] recvline: 0000-0020: 2B 43 49 50 44 4F 4D 41  49 4E 3A 35 34 2E 31 36  36 2E 37 36 2E 31 37 38  0D 0A                      +CIPDOMAIN:54.166.76.178..
[D/AT] recvline: 0000-0020: 0D 0A                                                                                                 ..

这里IP请求了5次,全部返回了解析,但是下面没用上,解析不成功

从这里开始IP为0. 很奇怪没有用上上面解析得到的IP地址。

[D/AT] sendline: 0000-0020: 41 54 2B 43 49 50 53 54  41 52 54 3D 30 2C 22 54  43 50 22 2C 22 30 2E 30  2E 30 2E 30 22 2C 31 31    AT+CIPSTART=0,"TCP","0.0.0.0",11
[D/AT] sendline: 0020-0040: 35 32 33 2C 36 30                                                                                     523,60
[D/AT] recvline: 0000-0020: 4F 4B 0D 0A                                                                                           OK..
[D/AT] recvline: 0000-0020: 0D 0A                                                                                                 ..
[D/AT] recvline: 0000-0020: 45 52 52 4F 52 0D 0A                                                                                  ERROR..

再后面就一直报错了


[D/AT] sendline: 0000-0020: 41 54 2B 43 49 50 53 45  4E 44 3D 30 2C 36 30                                                         AT+CIPSEND=0,60
[D/AT] recvline: 0000-0020: 30 2C 43 4C 4F 53 45 44  0D 0A                                                                        0,CLOSED..
[D/AT] recvline: 0000-0020: 6C 69 6E 6B 20 69 73 20  6E 6F 74 20 76 61 6C 69  64 0D 0A                                            link is not valid..
[D/AT] recvline: 0000-0020: 0D 0A                                                                                                 ..
[D/AT] sendline: 0000-0020: 10 3A 00 04 4D 51 54 54  04 CE 00 1E 00 08 51 69  6E 67 37 39 31 31 00 04  74 65 73 74 00 08 47 6F    .:..MQTT......Qing7911..test..Go
[D/AT] sendline: 0020-0040: 6F 64 62 79 65 21 00 0B  71 69 6E 67 73 74 61 74  69 6F 6E 00 07 71 69 6E  67 31 32 33                odbye!..qingstation..qing123
[634248] E/at.skt.esp: esp0 device socket(0) wait connect result timeout.
[634248] E/mqtt: MQTT connect error(-1): UNKNOWN_ERROR.
[634248] D/mqtt: inter mqtt_offline_callback!
[D/AT] sendline: 0000-0020: 41 54 2B 43 49 50 44 4F  4D 41 49 4E 3D 22 71 62  65 32 36 62 34 36 2E 65  6E 2E 65 6D 71 78 2E 63    AT+CIPDOMAIN="qbe26b46.en.emqx.c
[D/AT] sendline: 0020-0040: 6C 6F 75 64 22                                                                                        loud"
[6393[D/AT] recvline: 0000-0020: 45 52 52 4F 52 0D 0A                                                                                  ERROR..
[D/AT] recvline: 0000-0020: 0D 0A                                                                                                 ..

相关代码是这: https://github.com/RT-Thread-packages/at_device/blob/2878647c0c85f376223f333a87ce05cf0c9a8c98/class/esp8266/at_socket_esp8266.c#L309

这个函数里面

static int esp8266_domain_resolve(const char *name, char ip[16])

单步调试,第一次断连的时候,这个地方是可以过的,链接成功恢复。传进来的是IP 第二次断链传进来的就单纯是OK而已 image

问题应该找到了,真正的IP是用URC发回来的,AT 设备已经考虑到了,但是没有实现这部分功能。不清楚其他模块是否也是这样?

        /* parse the third line of response data, get the IP address */
        if (at_resp_parse_line_args_by_kw(resp, "+CIPDOMAIN:", "+CIPDOMAIN:%s", recv_ip) < 0)
        {
            rt_thread_mdelay(100);
            /* resolve failed, maybe receive an URC CRLF */
            continue;
        }

        if (rt_strlen(recv_ip) < 8)
        {
            rt_thread_mdelay(100);
            /* resolve failed, maybe receive an URC CRLF */
            continue;
        }

这是第一次的返回,先返回IP 再返回OK

[D/AT] sendline: 0000-0020: 41 54 2B 43 49 50 44 4F  4D 41 49 4E 3D 22 71 62  65 32 36 62 34 36 2E 65  6E 2E 65 6D 71 78 2E 63    AT+CIPDOMAIN="qbe26b46.en.emqx.c
[D/AT] sendline: 0020-0040: 6C 6F 75 64 22                                                                                        loud"
[D/AT] recvline: 0000-0020: 2B 43 49 50 44 4F 4D 41  49 4E 3A 35 34 2E 31 36  36 2E 37 36 2E 31 37 38  0D 0A                      +CIPDOMAIN:54.166.76.178..
[D/AT] recvline: 0000-0020: 0D 0A                                                                                                 ..
[D/AT] recvline: 0000-0020: 4F 4B 0D 0A                                                                                           OK..

这是往后数次的IP resolve,先返回OK,再返回IP

[D/AT] sendline: 0000-0020: 41 54 2B 43 49 50 44 4F  4D 41 49 4E 3D 22 71 62  65 32 36 62 34 36 2E 65  6E 2E 65 6D 71 78 2E 63    AT+CIPDOMAIN="qbe26b46.en.emqx.c
[D/AT] sendline: 0020-0040: 6C 6F 75 64 22                                                                                        loud"
[D/AT] recvline: 0000-0020: 4F 4B 0D 0A                                                                                           OK..
[D/AT] recvline: 0000-0020: 2B 43 49 50 44 4F 4D 41  49 4E 3A 35 34 2E 31 36  36 2E 37 36 2E 31 37 38  0D 0A                      +CIPDOMAIN:54.166.76.178..
[D/AT] recvline: 0000-0020: 0D 0A                                                                                                 ..
majianjia commented 3 years ago

我感觉可能跟这个也有关系。 https://github.com/RT-Thread-packages/at_device/issues/85#issuecomment-824322499

xiangxistu commented 3 years ago

URC 数据是比较特殊的,每一行数据,都会被 URC 列表里的元素比对一遍;如果不为 URC 数据才会被放在缓存里,等待其他函数来匹配;

所以,+CIPDOMAIN: 这个在设计时,就没有考虑要通过 URC 来处理这个数据。 这个问题像是由于模块提前返回了 OK,导致 at client 认为本次接收已经终止,而没有在缓存区中输入 +CIPDOMAIN: 的数据,导致解析失败;PS:at raw 里有,是因为 at raw 的打印更加底层,而不是仅 response 里的数据。


static void at_response_dump(at_response_t resp)
{
    rt_uint8_t line_num = 0;

    LOG_RAW("response : \n");
    for (line_num = 1; line_num <= resp->line_counts; line_num++)
    {
        const char *resp_line_buf = at_resp_get_line(resp, line_num);

        if (resp_line_buf != RT_NULL)
        {
            LOG_D("line = [%02d], data: %s", line_num, resp_line_buf);
        }
    }
}

可以尝试使用这个函数,来打印这里的 resp 的信息代码

如果问题复现,则可以修改这里的逻辑,来满足这种情况下的 AT 数据判断


可以加个好友,一起解决这个问题。xiangxistu@foxmail.com @majianjia

majianjia commented 3 years ago

可以加个好友,一起解决这个问题。xiangxistu@foxmail.com @majianjia 谢谢,是QQ么?我这搜不到你,或者你加我2759626

majianjia commented 3 years ago

问题解决了,可能是硬件问题。 STM32L476跑80M下的115200波特率中断处理不过来,或者是ESP8266本身处理不过来。 仔细查看log发现出错前会多一个或者少一个字节。 错位后导致后面的命令全部错位,AT卡死。

这个IP地址获取部分也是命令请求应答错位导致的。

xiangxistu commented 3 years ago

看起来问题的一开始是前一个指令 AT+CIPCLOSE 在执行时,还没有接收到 ```OK````,但是这个 OK 被遗留到缓存里了,干扰了后面的解析逻辑。


速度可能是一方面, AT 组件这边应该在创建新的 resp 时,应该先清空缓存区间。


又浏览了代码,确实在 AT+CIPCLOSE 后执行了清空 resp 的操作;有可能是 client_parser 的优先级太低,也可以说模块回复太慢。这两个共同作用,导致了数据的错误现象。