概述:
本篇讲述SNTP(SimpleNetwork Time Protocol)简单网络时间协议的通信过程和解析,会访问10个ip地址服务器,他们都支持SNTP协议,如果访问第一个服务器,可能因为服务器本身原因或网络信号弱的原因,在超时时间内没有数据返回,就继续访问下一个ip地址,直到最后一个服务器地址,这期间,只要任何一个IP地址有数据返回,就算通信成功,解析收到的数据,再关闭网络通信。可以参看《运行日志.txt》,此日志记录了在访问第9个ip之后,收到了来自第二个ip的返回信息。本节所讲代码都在sntp目录下的文件中。
1 创建UDP 传输协议的socket id
代码如下图向NB模组发送指令:
AT+NSOCR="DGRAM",17,8080,1\r\n
模组返回:
\r\n 0\r\n\r\nOK\r\n
OK表示创建成功,0表示创建成功的socketid,后面当我们进行发送和接收数据的时候都要用到这个socket id,如果创建失败,原因有2:1是之前创建的socket id在使用后没有关闭,2 是NB模组最多支持0-6共7个socket id,已经超出了最大个数。
上图中的SendCmd函数定义,先发送,再接收,return后面的那个函数在接收的同时还会进行数据的分析,下面第2节详细讲述。
2 针对网络返回数据慢的分析
return后面的那个函数声明如下:
ATBack_t asiacom_analyze_recv_from_nb_module_asynchronous_sntp(u32 timeout, u32 *len, asiacom_pfun_bool pfun_analyze_recv);
此函数实现了上一篇提到的针对NB模组需要网络通信而导致返回数据慢的分析方法。由于在长达几十秒的串口等待接收中,NB模组可能会返回各种数据(包括错误信息,状态信息等其他未知信息),这是不可预知的。同时要保证如果在串口接收超时时间之前已经接收到想要的数据,就立即结束接收,而接收到其他数据或者没有接收到数据,就继续等待直到超时结束。这与上一篇讲的接收数据分析方法不同。参看《运行日志.txt》,在接收到不是想要的数据(+NPSMR:0表示模组上报的工作状态)后依然继续接收。
此函数有3个参数,超时时间,接收字节长度和一个函数指针。函数指针的定义如下,
typedef bool (* asiacom_pfun_bool)(const char *string_src);
因为NB模组返回数据的特性:以\r\n开始,以\r\n结束。所以此函数只有在每一次接收到此特性的数据,才开始进行检测,如果是需要的数据,就结束接收,否则继续等待接收。同时无论收到什么数据,都会输出到RTT日志,这样工程师或者测试人员能看到,了解NB模组的实时工作状态,便于问题与bug的分析和解决。
而如果函数指针pfun_analyze_recv为NULL,此函数就只会判断接收到OK或者ERROR等普通标志的数据,主要用再NB模组很快(毫秒级)就会返回数据的指令,这里跟上一篇的类似。上面的socket id创建指令,接收时此参数就传NULL。下图是此指令执行结果截图。
而如果函数指针pfun_analyze_recv不为NULL,此函数就只会判断接收的数据是否满足pfun_analyze_recv指定的条件,所以想要检测某种数据,只需要传入检测这种数据的函数名称即可,用在NB模组很慢(几十秒级)返回数据的指令,一般都是网络接收指令
3 发送获取网络时间的请求信息
代码如下, 发送指令给模组以后,会收到模组把此指令通过网络发送出去的报告。
执行结果如下,参数顺序依次是socket id=0 ,第二个参数是ip地址,端口号123,发送的字节个数48,最后是48字节的内容,因为是转成十六进制,例如1b就是一个字节,后面的每2个0也是表示一个字节。
asiacom_analyze_recv_from_nb_module_asynchronous_sntp
函数接收到NB模组返回的信息:模组成功收到了mcu发来的指令信息,即在0这个socket id上要发送48个字节。
4 等待接收信息
接收的代码也在上面截图中的atUdpSend函数中,atUdpSend函数在发送请求AT命令后,会立即收到模组接收到此AT命令的回复,接着mcu要继续等待接收模组从服务获取的时间数据,当NB模组接收到服务器返回的数据,会先串口发送一个通知信息告诉mcu我收到数据,mcu此时就应该发送一条接收AT指令来接收模组的数据。
如下代码是mcu接收和解析模组的这个通知消息,可以看到第3个参数传入了一个函数is_recv_flag_of_NSONMI,用来检测是否是这个通知消息(以+_NSONMI:打头的消息)。
检测到此通知消息后,MCU发送接收指令给模组,代码如下,SendCmd函数会完成此指令的发送并接收到包含时间信息的数据。
SendCmd函数执行成功后,对接收的数据再次检测是否是+NSORF:打头,然后提取出表示网络时间的字段,代码也是在atUdpRecv函数中,如下图。
5 解析出时间
这里要说明下,获取的网络时间是UTC时间,就是0时区的时间,而北京时间是8时区的时间,所以二者相差8个小时。当读取或者更新本地RTC时间是用的北京时间,而下一篇计算验证码用的是UTC时间。
如下代码,atUdpRecv函数上面已经讲过,把atUdpRecv函数获取字符串格式的时间buff转换成SNTP数据包结构体变量SNTPData。通过公式减掉网络通信的延时时间,得到以秒为单位的时间值tv.tv_sec,ctime是C语言标准头文件<time.h>中的函数,可以把以秒为单位的时间值tv.tv_sec转换成具体的年月日和时分秒。
最后调用refresh_rtc_time_sntp来更新本地RTC时间,定义如下,此函数定义在rtc.c中。
4,5两步的执行日志如下图:
解析得到的UTC时间 UTC:Fri Feb 3 08:00:44 2023
更新到本地的RTC时间 sntp:2023-02-03,16:00:44
二者相差8小时,也注意看日志中的时间戳变化,之前都是2023-01-12,更新本地RTC时间成功之后就变成2023-02-03。
6关闭scoket id
执行结果如下,注意每次通信完成后都要关闭scoket id,有时候我们在创建scoket id的时候总是返回失败,就需要先关闭上一次创建的scoket id。
附件 本篇中提到的《运行日志.txt》
[2023-01-12T04:22:30] main 114 "wait for nbiot booting......"
[2023-01-12T04:22:30] send_AT_CMD 212 "AT
"
[2023-01-12T04:22:30] asiacom_recv_data_from_nb_module 66 "
ERROR
"
[2023-01-12T04:22:30] send_AT_CMD 212 "AT
"
[2023-01-12T04:22:30] asiacom_recv_data_from_nb_module 66 "
OK
"
[2023-01-12T04:22:30] check_nb_online 254 "1 "
[2023-01-12T04:22:30] send_data_to_nb_module 83 "AT+CGATT?
"
[2023-01-12T04:22:30] asiacom_recv_data_from_nb_module 66 "
+CGATT:1
OK
"
[2023-01-12T04:22:30] send_data_to_nb_module 83 "AT+CSQ
"
[2023-01-12T04:22:30] asiacom_recv_data_from_nb_module 66 "
+CSQ:24,99
OK
"
[2023-01-12T04:22:30] send_data_to_nb_module 83 "AT+NPSMR=1
"
[2023-01-12T04:22:30] asiacom_recv_data_from_nb_module 66 "
OK
"
[2023-01-12T04:22:30] sntp_get_time 191 "isocketflag=-1 "
[2023-01-12T04:22:30] atCreateUdpSockets 87 "AT+NSOCR="DGRAM",17,8080,1
"
[2023-01-12T04:22:30] asiacom_analyze_recv_from_nb_module_asynchronous_sntp 192 "
0
OK
"
[2023-01-12T04:22:30] sntp_get_time 195 "ERROR -1 socketnumber 0 !!!!"
[2023-01-12T04:22:30] atUdpSend 169 ": AT+NSOST=0,120.24.166.46,123,48,1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
"
[2023-01-12T04:22:31] asiacom_analyze_recv_from_nb_module_asynchronous_sntp 192 "
0,48
OK
"
[2023-01-12T04:22:32] asiacom_analyze_recv_from_nb_module_asynchronous_sntp 174 "
+NPSMR:0
"
[2023-01-12T04:22:46] atUdpSend 169 ": AT+NSOST=0,120.25.115.20,123,48,1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
"
[2023-01-12T04:22:46] asiacom_analyze_recv_from_nb_module_asynchronous_sntp 192 "
0,48
OK
"
[2023-01-12T04:23:01] atUdpSend 169 ": AT+NSOST=0,203.107.6.88,123,48,1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
"
[2023-01-12T04:23:01] asiacom_analyze_recv_from_nb_module_asynchronous_sntp 192 "
0,48
OK
"
[2023-01-12T04:23:16] atUdpSend 169 ": AT+NSOST=0,37.187.100.18,123,48,1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
"
[2023-01-12T04:23:16] asiacom_analyze_recv_from_nb_module_asynchronous_sntp 192 "
0,48
OK
"
[2023-01-12T04:23:31] atUdpSend 169 ": AT+NSOST=0,202.112.7.13,123,48,1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
"
[2023-01-12T04:23:32] asiacom_analyze_recv_from_nb_module_asynchronous_sntp 192 "
0,48
OK
"
[2023-01-12T04:23:47] atUdpSend 169 ": AT+NSOST=0,202.120.2.101,123,48,1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
"
[2023-01-12T04:23:47] asiacom_analyze_recv_from_nb_module_asynchronous_sntp 192 "
0,48
OK
"
[2023-01-12T04:24:02] atUdpSend 169 ": AT+NSOST=0,210.72.145.44,123,48,1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
"
[2023-01-12T04:24:02] asiacom_analyze_recv_from_nb_module_asynchronous_sntp 192 "
0,48
OK
"
[2023-01-12T04:24:17] atUdpSend 169 ": AT+NSOST=0,182.92.12.11,123,48,1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
"
[2023-01-12T04:24:18] asiacom_analyze_recv_from_nb_module_asynchronous_sntp 192 "
0,48
OK
"
[2023-01-12T04:24:33] atUdpSend 169 ": AT+NSOST=0,223.113.97.99,123,48,1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
"
[2023-01-12T04:24:33] asiacom_analyze_recv_from_nb_module_asynchronous_sntp 192 "
0,48
OK
"
[2023-01-12T04:24:39] asiacom_analyze_recv_from_nb_module_asynchronous_sntp 174 "
+NSONMI:0,48
"
[2023-01-12T04:24:39] is_recv_flag_of_NSONMI 42 "RECV_NSONMI"
[2023-01-12T04:24:39] atUdpRecv 241 ": AT+NSORF=0,1024
"
[2023-01-12T04:24:39] asiacom_analyze_recv_from_nb_module_asynchronous_sntp 192 "
+NSORF:0,120.25.115.20,123,48,1C0200E7000000080000004B0A893507E78C77CDA314A32D0000000000000000E78C7808CCF3BB69E78C7808CECFFFD6,0
OK
"
[2023-01-12T04:24:39] rev_handle 143 "t1:3884742664 UTC:Tue Feb 7 07:11:09 2023
"
[2023-02-07T15:11:09] refresh_rtc_time_by_sntp 610 "sntp:2023-02-07,15:11:09"
[2023-02-07T15:11:09] atCloseSockets 131 ": AT+NSOCL=0
"
[2023-02-07T15:11:09] asiacom_analyze_recv_from_nb_module_asynchronous_sntp 192 "
+NSONMI:0,48
OK
"