应用实战精解系列(二十):RVB2601之YoC系统

简介: 应用实战精解系列(二十):RVB2601之YoC系统

编辑语:

芯片开放社区(OCC)面向广大开发者推出应用实战系列内容,通过分享开发者实战开发案例,总结应用开发经验,梳理开发中的常见问题及解决方案,为后续参与的开发者提供更多参考与借鉴。


关于YoC系统,我们已经介绍了其KV组件的使用,并成功移植到了RVB2601开发板。本期内容,我们将继续分享YoC的实战应用,带大家了解如何通过使用其AOS的事件标志组,避免定时器回调和w800接收回调相互阻塞的情形。

01 AOS事件标志组

停滞了一段时间,继续RVB2601创意应用的开发工作。本人的创意项目需要RVB2601连接TCP Server——这个Server是建立在LoRa网关设备上的,所以基本就是用RVB2601去做LoRa网关的无线式上位机。


工作流程大体是:RVB2601向网关发送轮询帧,网关转发给LoRa终端,终端则采集传感器数据并通过网关回传到RVB2601。因此,RVB2601既要WiFi联网,又要开启TCP应用,而且还需要接收TCP数据。


好在板子的SDK中有接收回调的注册接口,就是之前帖子已经提到过的w800_packet_input_cb_register(),回调的原型为:

typedef void (*net_data_input_cb_t)(int linkid, void *data, size_t len, char remote_ip[16], uint16_t remote_ports);


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

//w800 input callback function
void aita_w800in_cb(int linkid, void *data, size_t len, char remote_ip[16], uint16_t remote_ports) {
    uint8_t* d;
    d = (uint8_t *)data;
    printf("linkid: %d\n", linkid);
    printf("len: %d\n", len);
    printf("remote_ip: %s\n", remote_ip);
    printf("remote_port: %d\n", remote_ports);
    printf("data:%s\n", d);
    if(remote_ports == GW_PORT) {
    isTimeout = 0;
    memset(USR220resbuff, 0, USR220RES_LEN);
    for(int i=0; i<len; i++) {
    USR220resbuff[i] = d[i];
    }
    }
}
void aita_PollingFunc(void) {
    int i = 0;
    int cyc = 1;
    time_t nowtime, endtime;
    //connect to USR220 TCP Server
    int ret = -1;    
    ret = w800_connect_remote(0, NET_TYPE_TCP_CLIENT, GW_IP, GW_PORT);
    if(ret < 0) return;
    for(i=0; i<endian_count; i++) {
    aita_BuildCommandPack(i); //build polling pack
    cyc = repeat;             //repeat times when timeout
    isOneEndianDone = 0;
    while(cyc--) {
    w800_send_data(comm_pack, COMMPACK_LEN, 3000);
    isTimeout = 1;
    endtime = time(NULL) + timeout;
    while((nowtime=time(NULL)) < endtime) {
    if(!isTimeout) {
    cyc = 0;
    isOneEndianDone = 1;
    break;
    }
    }
    printf("usr220res: %s, len: %d\n", USR220resbuff, sizeof(USR220resbuff));
        }
    if(!isOneEndianDone) {
    printf("%s disconnected\n", EID[i]);
    }
    }
    //断开TCP 连接
    w800_close(0);
}


上述代码的逻辑也很简单,就是基于程序查询思想,发出一帧开始不断通过time(NULL)来获取本地时间,如果时间过去timeout秒,就表示超时了,而w800接收回调会将超时标志isTimeOut清零,帮助结束程序查询的循环——while((nowtime=time(NULL)) < endtime)。


逻辑看似完美,但是在下忽略了这是在实时系统的平台上,而且代码跑在定时器回调中,而网络接收回调抢不到CPU权,所以查询本地时间的循环会阻塞w800接收回调的出现。


当时,为了验证自己的想法,干脆将超时查询改为aos_msleep(timeout*1000),果然接收回调出现了,但是每一次轮询都要固定耗时timeout秒钟显然是不行的。因此,想到了引入事件机制,因为只是简单的条件获取,所以选用了事件标志组。YoC的事件标志组可以查看链接:


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?spm=a2cl5.25411629.0.0.2348180foY12EN


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

#define EVENT_FLAG_3 0x000000F0
aos_event_t usr220res_event;
void aita_InitEvent(void) {
    int ret = -1;
    ret = aos_event_new(&usr220res_event, 0);
    if (ret != 0) {
        printf("event create failed\n");
        return;
    }    
}


接着就是修改aita_PollingFunc()函数,它会在定时器回调中调用。

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


w800接收回调当然就是在收到回复数据包后,发出事件标志EVENT_FLAG_3。

void aita_w800in_cb(int linkid, void *data, size_t len, char remote_ip[16], uint16_t remote_ports) {
    uint8_t* d;
    d = (uint8_t *)data;
    printf("linkid: %d\n", linkid);
    printf("len: %d\n", len);
    printf("remote_ip: %s\n", remote_ip);
    printf("remote_port: %d\n", remote_ports);
    printf("data:%s\n", d);
    if(remote_ports == GW_PORT) {
    isTimeout = 0;
    memset(USR220resbuff, 0, USR220RES_LEN);
    for(int i=0; i<len; i++) {
    USR220resbuff[i] = d[i];
    }
    aos_event_set(&usr220res_event, EVENT_FLAG_3, AOS_EVENT_OR);    
    }
}




相关文章
|
Web App开发 弹性计算 负载均衡
阿里云acp考试时间、内容?阿里ACP认证考试有什么经验?
阿里acp认证考试有什么经验?众所周知,阿里云针对不同云产品类别、用户行业、用户成长阶段,精心打造不同的认证考试。阿里云认证分为四级ACF、ACP、ACA、ACM。拿到阿里云证书即使以后从业相关行业都可以拿到高新、以及相关行业的专业资格
2323 0
阿里云acp考试时间、内容?阿里ACP认证考试有什么经验?
|
存储 边缘计算 固态存储
玄铁RISC-V处理器入门与实战-平头哥玄铁CPU IP-面向高性能领域CPU
玄铁RISC-V处理器入门与实战-平头哥玄铁CPU IP-
2610 1
|
并行计算 安全 开发者
RISC-V生态全景解析(五):Vector向量计算技术与SIMD技术的对比
芯片开放社区(OCC)面向开发者推出RISC-V系列内容,通过多角度、全方位解读RISC-V,系统性梳理总结相关理论知识,构建RISC-V知识图谱,促进开发者对RISC-V生态全貌的了解。
4001 0
RISC-V生态全景解析(五):Vector向量计算技术与SIMD技术的对比
SVN 将文件还原到之前的指定版本
SVN 将文件还原到之前的指定版本
3537 1
SVN 将文件还原到之前的指定版本
|
4月前
|
人工智能 自然语言处理 安全
Lux 上手指南:让 AI 直接操作你的电脑
Lux 是一款能直接操作计算机的AI基础模型,通过视觉理解与动作预测,实现自然语言指令下的自动化任务。它无需依赖API,可像真人一样点击、输入、滚动,完成浏览器操作等复杂工作,准确率超越主流模型,是迈向“意图即执行”的重要突破。(238字)
1312 13
Lux 上手指南:让 AI 直接操作你的电脑
|
资源调度 芯片
流片Corner Wafer介绍
芯片制造是一个物理过程,存在着工艺偏差(包括掺杂浓度、扩散深度、刻蚀程度等),导致不同批次之间,同一批次不同晶圆之间,同一晶圆不同芯片之间情况都是不相同的。
24111 0
流片Corner Wafer介绍
ZYNQ-AXI总线的信号接口要求以及时序关系
ZYNQ-AXI总线的信号接口要求以及时序关系
2366 0
ZYNQ-AXI总线的信号接口要求以及时序关系
|
存储 安全 芯片
封装之打线简介
介绍封装打线的原理,常用材料的优缺点,关键部件,wire bonding 过程,主要参数,线形,线长和主要测试方法。
14290 3
封装之打线简介
智启芯篇·共赴北京|“开放·连接 ”2025玄铁 RISC-V 生态大会议程公布!
2025年2月28日“开放·连接 ”2025玄铁 RISC-V 生态大会议程公布。诚邀您参加“开放·连接”2025玄铁RISC-V生态大会。汇聚全球行业专家、技术领袖及资深工程师于北京,共同探讨RISC-V技术趋势与产业未来,共筑“芯”篇章。席位有限,欢迎扫码锁定参会席位!
715 1
提升个人工作技能
提升个人工作技能
1459 6

热门文章

最新文章

下一篇
开通oss服务