sonicfirr 发表于 2022-5-13 22:22

【平头哥RVB2601创意应用开发】使用体验09 -- YoC事件

本帖最后由 sonicfirr 于 2022-5-13 22:23 编辑

<p>&nbsp; &nbsp; &nbsp; &nbsp;停滞了一段时间,继续RVB2601创意应用的开发工作。本人的创意项目需要RVB2601连接TCP Server&mdash;&mdash;这个Server是建立在LoRa网关设备上的,所以基本就是用RVB2601去做LoRa网关的无线式上位机。<br />
&nbsp; &nbsp; &nbsp; &nbsp;工作流程大体是:RVB2601向网关发送轮询帧,网关转发给LoRa终端,终端则采集传感器数据并通过网关回传到RVB2601。因此,RVB2601既要WiFi联网,又要开启TCP应用,而且还需要接收TCP数据。<br />
&nbsp; &nbsp; &nbsp; &nbsp;好在板子的SDK中有接收回调的注册接口,就是之前帖子已经提到过的w800_packet_input_cb_register(),回调的原型为:</p>

<p>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;typedef void (*net_data_input_cb_t)(int linkid, void *data, size_t len, char remote_ip, uint16_t remote_ports);</p>

<p>&nbsp; &nbsp; &nbsp; &nbsp;不过案例的业务逻辑设计了这样一种需求:板子每隔固定周期会发出轮询帧,且发出后等待回复数据一定时间(默认10s),如果超时则再发轮询帧,最多尝试3次(也是默认,可以调整),这个需求通过定时器回调来实现的。好巧不巧上一阶段的工作主要完成NTP功能,自以为对C time库了解的不错,所以本人设计这样&ldquo;有坑版&rdquo;的代码写法:</p>

<p>&nbsp;</p>

<pre>
<code>//w800 input callback function
void aita_w800in_cb(int linkid, void *data, size_t len, char remote_ip, uint16_t remote_ports) {
&nbsp;&nbsp; &nbsp;uint8_t* d;
&nbsp;&nbsp; &nbsp;d = (uint8_t *)data;
&nbsp;&nbsp; &nbsp;printf(&quot;linkid: %d\n&quot;, linkid);
&nbsp;&nbsp; &nbsp;printf(&quot;len: %d\n&quot;, len);
&nbsp;&nbsp; &nbsp;printf(&quot;remote_ip: %s\n&quot;, remote_ip);
&nbsp;&nbsp; &nbsp;printf(&quot;remote_port: %d\n&quot;, remote_ports);
&nbsp;&nbsp; &nbsp;printf(&quot;data:%s\n&quot;, d);
&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;if(remote_ports == GW_PORT) {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;isTimeout = 0;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;memset(USR220resbuff, 0, USR220RES_LEN);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;for(int i=0; i&lt;len; i++) {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;USR220resbuff<i> = d<i>;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}
&nbsp;&nbsp; &nbsp;}
}

void aita_PollingFunc(void) {
&nbsp;&nbsp; &nbsp;int i = 0;
&nbsp;&nbsp; &nbsp;int cyc = 1;
&nbsp;&nbsp; &nbsp;time_t nowtime, endtime;
&nbsp;&nbsp; &nbsp;//connect to USR220 TCP Server
&nbsp;&nbsp; &nbsp;int ret = -1;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;ret = w800_connect_remote(0, NET_TYPE_TCP_CLIENT, GW_IP, GW_PORT);
&nbsp;&nbsp; &nbsp;if(ret &lt; 0) return;
&nbsp;&nbsp;
&nbsp;&nbsp; &nbsp;for(i=0; i&lt;endian_count; i++) {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;aita_BuildCommandPack(i); //build polling pack
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cyc = repeat; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //repeat times when timeout
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;isOneEndianDone = 0;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;while(cyc--) {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;w800_send_data(comm_pack, COMMPACK_LEN, 3000);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;isTimeout = 1;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;endtime = time(NULL) + timeout;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;while((nowtime=time(NULL)) &lt; endtime) {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if(!isTimeout) {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cyc = 0;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;isOneEndianDone = 1;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;break;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;printf(&quot;usr220res: %s, len: %d\n&quot;, USR220resbuff, sizeof(USR220resbuff));
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if(!isOneEndianDone) {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;printf(&quot;%s disconnected\n&quot;, EID<i>);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}
&nbsp; &nbsp; }
&nbsp;&nbsp; &nbsp;//断开TCP 连接
&nbsp;&nbsp; &nbsp;w800_close(0);
}</i></i></i></code></pre>

<p><i><i><i>&nbsp; &nbsp; &nbsp; &nbsp;</i></i></i></p>

<p><i><i><i>&nbsp; &nbsp; &nbsp; &nbsp;上述代码的逻辑也很简单,就是基于程序查询思想,发出一帧开始不断通过time(NULL)来获取本地时间,如果时间过去timeout秒,就表示超时了,而w800接收回调会将超时标志isTimeOut清零,帮助结束程序查询的循环&mdash;&mdash;while((nowtime=time(NULL)) &lt; endtime)。<br />
&nbsp; &nbsp; &nbsp; &nbsp;逻辑看似完美,但是在下忽略了这是在实时系统的平台上,而且代码跑在定时器回调中,而网络接收回调抢不到CPU权,所以查询本地时间的循环会阻塞w800接收回调的出现。<br />
&nbsp; &nbsp; &nbsp; &nbsp;当时,为了验证自己的想法,干脆将超时查询改为aos_msleep(timeout*1000),果然接收回调出现了,但是每一次轮询都要固定耗时timeout秒钟显然是不行的。因此,想到了引入事件机制,因为只是简单的条件获取,所以选用了事件标志组。YoC的事件标志组可以查看链接:<br />
https://yoc.docs.t-head.cn/yocbook/Chapter3-AliOS/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E6%8E%A5%E5%8F%A3/%E4%BA%8B%E4%BB%B6.html 。</i></i></i></p>

<p><i><i><i>&nbsp; &nbsp; &nbsp; &nbsp;首先定义事件标志组变量和初始化函数,初始化函数会在案例的board_yoc_init()中调用。下述代码中,标志定义为宏EVENT_FLAG_3,选用这个纯粹是从文档抄来也没必要改名字。</i></i></i></p>

<p><i><i><i>&nbsp;</i></i></i></p>

<pre>
<i><i><i>
<code>#define EVENT_FLAG_3 0x000000F0
aos_event_t usr220res_event;

void aita_InitEvent(void) {
&nbsp;&nbsp; &nbsp;int ret = -1;
&nbsp;&nbsp; &nbsp;ret = aos_event_new(&amp;usr220res_event, 0);
&nbsp; &nbsp; if (ret != 0) {
&nbsp; &nbsp; &nbsp; &nbsp; printf(&quot;event create failed\n&quot;);
&nbsp; &nbsp; &nbsp; &nbsp; return;
&nbsp; &nbsp; }&nbsp;&nbsp; &nbsp;
}</code></i></i></i></pre>

<p><i><i><i>&nbsp; &nbsp; &nbsp; &nbsp;</i></i></i></p>

<p><i><i><i>&nbsp; &nbsp; &nbsp; &nbsp;接着就是修改aita_PollingFunc()函数,它会在定时器回调中调用(有不清楚的朋友可以看本人的RVB2601使用<a href="https://bbs.eeworld.com.cn/thread-1198907-1-1.html" target="_blank">帖子03</a>)。</i></i></i></p>

<p><i><i><i>&nbsp;</i></i></i></p>

<pre>
<i><i><i>
<code>void aita_PollingFunc(void) {
&nbsp;&nbsp; &nbsp;int i = 0;
&nbsp;&nbsp; &nbsp;int cyc = 1;
&nbsp;&nbsp; &nbsp;//connect to USR220(LoRa Gateway) TCP Server
&nbsp;&nbsp; &nbsp;int ret = -1;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;ret = w800_connect_remote(0, NET_TYPE_TCP_CLIENT, GW_IP, GW_PORT);
&nbsp;&nbsp; &nbsp;if(ret &lt; 0) return;
&nbsp; &nbsp; //once polling request all endians
&nbsp;&nbsp; &nbsp;for(i=0; i&lt;endian_count; i++) {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;aita_BuildCommandPack(i);//build req pack in USR220 format&nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cyc = repeat;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;isOneEndianDone = 0;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;while(cyc--) {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;w800_send_data(comm_pack, COMMPACK_LEN, 3000);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;isTimeout = 1;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;uint32_t actl_flags;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//wait for flag(0x000000F0) for timeout-seconds, if get the flag then clear the bit
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;aos_event_get(&amp;usr220res_event, EVENT_FLAG_3, AOS_EVENT_OR_CLEAR, &amp;actl_flags, timeout*1000);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if(!isTimeout) {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cyc = 0;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;isOneEndianDone = 1;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;printf(&quot;usr220res: %s, len: %d\n&quot;, USR220resbuff, sizeof(USR220resbuff));
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if(!isOneEndianDone) {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;printf(&quot;%s disconnected\n&quot;, EID<i>);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}
&nbsp; &nbsp; }
&nbsp;&nbsp; &nbsp;//once polling done &amp; disconnect to tcp server
&nbsp;&nbsp; &nbsp;w800_close(0);
}</i></code></i></i></i></pre>

<p><i><i><i><i>&nbsp;</i></i></i></i></p>

<p><i><i><i><i>&nbsp; &nbsp; &nbsp; &nbsp;w800接收回调当然就是在收到回复数据包后,发出事件标志EVENT_FLAG_3。</i></i></i></i></p>

<p><i><i><i><i>&nbsp;</i></i></i></i></p>

<pre>
<i><i><i><i>
<code>void aita_w800in_cb(int linkid, void *data, size_t len, char remote_ip, uint16_t remote_ports) {
&nbsp;&nbsp; &nbsp;uint8_t* d;
&nbsp;&nbsp; &nbsp;d = (uint8_t *)data;
&nbsp;&nbsp; &nbsp;printf(&quot;linkid: %d\n&quot;, linkid);
&nbsp;&nbsp; &nbsp;printf(&quot;len: %d\n&quot;, len);
&nbsp;&nbsp; &nbsp;printf(&quot;remote_ip: %s\n&quot;, remote_ip);
&nbsp;&nbsp; &nbsp;printf(&quot;remote_port: %d\n&quot;, remote_ports);
&nbsp;&nbsp; &nbsp;printf(&quot;data:%s\n&quot;, d);
&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;if(remote_ports == GW_PORT) {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;isTimeout = 0;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;memset(USR220resbuff, 0, USR220RES_LEN);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;for(int i=0; i&lt;len; i++) {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;USR220resbuff<i> = d<i>;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;aos_event_set(&amp;usr220res_event, EVENT_FLAG_3, AOS_EVENT_OR);&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;}
}</i></i></code></i></i></i></i></pre>

<p><i><i><i><i><i><i>&nbsp;</i></i></i></i></i></i></p>

Jacktang 发表于 2022-5-14 07:13

<p>谢谢分享&ldquo;有坑版&rdquo;的代码写法</p>
页: [1]
查看完整版本: 【平头哥RVB2601创意应用开发】使用体验09 -- YoC事件