应用实战精解系列(七):RVB2601以太网通讯测试

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

在介绍Web播放器开发时,我们简单讲解了RVB2601开发板的Wi-Fi联网操作。为了给予大家更详细的操作指导,本期内容将讲解RVB2601开发板的软硬件接口原理和以太网通讯测试的步骤,并在最后为大家总结测试过程中遇到的问题及解决办法。


01 概述

RVB2601中集成的CH2601通过W800提供了AT透传的wifi 功能,可以完成和外界进行数据交换的需要。


02 驱动描述

2.1 硬件接口原理

image.png


CH2601采用SPI接口和W800进行数据交换,如图所示。

序号

W800

GPIO

1

SPI CS

PA15(SPI0_CS)

2

SPI MOSI

PA17(SPI0_MOSI)

3

SPI MISO

PA18(SPI0_MISO)

4

SPI  CLK

PA16(SPI0_CLK)

5

RST_N

PA21

6

WAKEUP

PA25


2.2 软件驱动设计

2.2.1 网络管理

网络管理支持有线网络、无线网络、GPRS网络、NB-IOT网络。我们只涉及到无线网络,所以这里就研究和网线网络相关的接口。网络管理接口如下所示:


函数

说明

netmgr_dev_wifi_init

无线设备初始化

netmgr_service_init

服务初始化

netmgr_config_wifi

无线配置

netmgr_start

使能网络设备

netmgr_reset

重置网络设备

netmgr_stop

停止网络链接

netmgr_is_gotip

网络设备是否获取到ip


1)网络管理接口详细说明

网络设备初始化


netmgr_hdl_t netmgr_dev_wifi_init()


函数说明:

该函数会注册netmgr_dev_t结构中的provision配网等回调函数。同时打开已注册的wifi设备节点,调用该设备实现的hal层初始化接口。同时将该设备加入到网络设备列表中统一管理。


返回值:

调用失败时返回NULL


服务初始化


void netmgr_service_init(utask_t *task)


初始化网络管理微服务。若外部微任务task为空,则内部创建微任务。同时将微服务加入到微任务中。


无线网络设备配置


int netmgr_config_wifi(netmgr_hdl_t hdl, char *ssid, uint8_t ssid_length, char *psk, uint8_t psk_length)


配置无线设备的ssid名称和对应的秘钥psk。


若定义了CONFIG_KV_SMART配置,如在某solution下的package.yaml中配置了CONFIG_KV_SMART: 1,则ssid和psk同时会被存储到kv文件系统中。对应的key定义如下:


#define KV_WIFI_SSID        "wifi_ssid"
#define KV_WIFI_PSK         "wifi_psk"


返回值:

调用成功时返回0,否则返回-1。


使能网络设备


int netmgr_start(netmgr_hdl_t hdl)


当网络参数配置后,就可以调用该接口使能指定网络设备开始正常工作。该函数最终会调用到对应网络设备初始化配置的provision配网回调。


该接口是非阻塞的,网络连接成功后,网络管理器会上报EVENT_NETMGR_GOT_IP事件,否则上报EVENT_NETMGR_NET_DISCON事件。应用开发者可通过event_subscribe接口订阅这两个消息来判断网络是否连接成功。用户也可通过调用netmgr_is_gotip判断是否正常获取到ip。


返回值:

调用成功时返回0,否则返回-1。


重置网络设备


int netmgr_reset(netmgr_hdl_t hdl, uint32_t sec)


复位网络设备连接,并在指定sec秒后自动重连。当sec为0时,复位后立即重连。该函数最终会调用到对应网络设备初始化配置的reset配网回调。该接口是非阻塞的。


返回值:

调用成功时返回0,否则返回-1。


停止网络设备


int netmgr_stop(netmgr_hdl_t hdl)


停止指定网络设备运行。该函数最终会调用到对应网络设备初始化配置的unprovision配网回调。该接口是阻塞的。


返回值:

调用成功时返回0,否则返回-1。

网络设备是否获取到ip


int netmgr_is_gotip(netmgr_hdl_t hdl)


指定hdl的网络设备是否获取到ip。


返回值:

当前网络设备已经成功获取到ip时返回1,否则返回0


2) SAL套接字适配层

SAL组件完成对不同网络实现接口的抽象并对上层提供一组标准的 BSD Socket API,开发者只需关心和使用标准网络接口,而无需关心底层具体实现,极大的提高了系统的兼容性,方便开发者完成协议栈的适配和网络通信相关的开发。


如下图所示,本次试用的RVB2601评估板采用的AT通道透传与W800芯片通讯完成以太网通讯功能。

image.gifimage.png


系统中提供了W800模块驱动中已经完成了SAL层接口的移植工作,因此在完成W800设备注册后,软件打开该设备的时候,驱动自动注册进SAL接口。后续的使用过程中,上层软件就感受不到ATPaser的存在了。


如下代码:


static int w800_dev_open(aos_dev_t *dev)
{
    // power on device
    sal_module_register(&w800_sal_driver);
    sal_init();
    return 0;
}


03 程序测试

本测试程序通过RVB2601建立一个TCPclient测试程序,与TCPServer通讯,完成TCPClient向TCPServer定时数据传递的功能。


3.1 初始化

注册的以太网事件回调接口函数


static void network_event(uint32_t event_id, const void *param, void *context)
{
    switch(event_id) {
    case EVENT_NETMGR_GOT_IP: {
        LOGD(TAG, "EVENT_NETMGR_GOT_IP");
    }
        break;
    case EVENT_NETMGR_NET_DISCON:
        LOGD(TAG, "EVENT_NETMGR_NET_DISCON");
        break;
    }
    /*do exception process */
    // app_exception_event(event_id);
}


以太网设备初始化函数


static void network_init()
{
    w800_wifi_param_t w800_param;
    /* init wifi driver and network */
    w800_param.reset_pin      = PA21;
    w800_param.baud           = 1*1000000;
    w800_param.cs_pin         = PA15;
    w800_param.wakeup_pin     = PA25;
    w800_param.int_pin        = PA22;
    w800_param.channel_id     = 0;
    w800_param.buffer_size    = 4*1024;
    wifi_w800_register(NULL, &w800_param);
    app_netmgr_hdl = netmgr_dev_wifi_init();
    if (app_netmgr_hdl) {
        utask_t *task = utask_new("netmgr", 2 * 1024, QUEUE_MSG_COUNT, AOS_DEFAULT_APP_PRI);
        netmgr_service_init(task);
        netmgr_config_wifi(app_netmgr_hdl, "Baidu-jy", 10, "12345678", 10);
        netmgr_start(app_netmgr_hdl);
        event_subscribe(EVENT_NETMGR_GOT_IP, network_event, NULL);
        event_subscribe(EVENT_NETMGR_NET_DISCON, network_event, NULL);
    }
}


3.2 TCPClient程序


static char lan_buf[1600];
int tcpclient(void)
{
    int                 iCounter;
    struct sockaddr_in  sAddr;
    int                 iAddrSize;
    int                 iSockFD;
    int                 iStatus;
    long                lLoopCount = 0;
    char            *cBsdBuf = NULL;
    int time_ms = aos_now_ms();
    int time_ms_step = aos_now_ms();
    int send_bytes = 0;
     running = 1;
    cBsdBuf = lan_buf;
    //filling the TCP server socket address
    FD_ZERO(&sAddr);
    sAddr.sin_family = AF_INET;
    sAddr.sin_port = htons(26666);
    sAddr.sin_addr.s_addr = inet_addr("192.168.95.5");
    iAddrSize = sizeof(struct sockaddr_in);
    // creating a TCP socket
    iSockFD = socket(AF_INET, SOCK_STREAM, 0);
    if (iSockFD < 0) {
        LOGE(TAG, "TCP ERROR: create tcp client socket fd error!");
        goto Exit1;
    }
    LOGD(TAG, "ServerIP=%s port=%d.", "192.168.95.5", 26666);
    LOGD(TAG, "Create socket %d.", iSockFD);
    // connecting to TCP server
   iStatus = connect(iSockFD, (struct sockaddr *)&sAddr, iAddrSize);
    if (iStatus < 0) {
        LOGE(TAG, "TCP ERROR: tcp client connect server error! ");
        goto Exit;
    }
    LOGD(TAG, "TCP: Connect server successfully.");
    // sending multiple packets to the TCP server
    printf("[  ID] Interval       Transfer     Bandwidth\n");
    while (running) {
         sprintf(cBsdBuf,"%02d",lLoopCount);
        // sending packet
        iStatus = send(iSockFD, cBsdBuf, strlen(cBsdBuf)+1, 0);
        if (iStatus <= 0) {
            printf("TCP ERROR: tcp client send data error!  iStatus:%d", iStatus);
            goto Exit;
        }
        lLoopCount++;
        aos_msleep(100);
        if ((aos_now_ms() - time_ms) / 1000 >  2) {
            break;
        }
    }
    LOGD(TAG, "TCP: Sent packets successfully.");
Exit:
    //closing the socket after sending 1000 packets
    close(iSockFD);
return 0;
}


3.3 通过console中断调用


int tcpclient(void);
static void cmd_tcp_client_handler(char *wbuf, int wbuf_len, int argc, char **argv)
{
    tcpclient();
}
int cli_reg_cmd_ft(void)
{
    static const struct cli_command tcp_cmd_info = {
        "tcptest",
        "tcp client test",
        cmd_tcp_client_handler,
    };
    aos_cli_register_command(&tcp_cmd_info);
    return 0;
}


3.4 Linux系统端的TCPServer测试程序


#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <netinet/in.h>
#define SERVPORT 26666
#define BACKLOG 10
#define MAXDATASIZE 1024
int main() {
    struct sockaddr_in server_sockaddr;//声明服务器socket存储结构
    int sin_size,recvbytes;
    int sockfd,client_fd;//socket描述符
    char buf[MAXDATASIZE];//传输的数据
    //1.建立socket
    //AF_INET 表示IPV4
    //SOCK_STREAM 表示TCP
    if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) {
        perror("Socket");
        exit(1);
    }
    printf("Socket successful!,sockfd=%d\n",sockfd);
    //以sockaddt_in结构体填充socket信息
    server_sockaddr.sin_family       = AF_INET;//IPv4
    server_sockaddr.sin_port         = htons(SERVPORT);//端口
    server_sockaddr.sin_addr.s_addr = INADDR_ANY;//本主机的任意IP都可以使用
    bzero(&(server_sockaddr.sin_zero),8);//保留的8字节置零
    //2.绑定 fd与 端口和地址
    if((bind(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(struct sockaddr))) < 0) {
        perror("bind");
        exit(-1);
    }
    printf("bind successful !\n");
    //3.监听
    if(listen(sockfd,BACKLOG) < 0) {
        perror("listen");
       exit(1);
    }
    printf("listening ... \n");
     //4.接收请求,函数在有客户端连接时返回一个客户端socket fd,否则则阻塞
     //优化:这里同样可以使用select,以及poll来实现异步通信
     if((client_fd = accept(sockfd,NULL,&sin_size)) == -1) {
         perror("accept");
         exit(1);
     }
     printf("accept success! client_fd:%d\n",client_fd);
    while(1){
     //5.接收数据
     //注意:这里传入的fd,不是建立的socket fd,而是accept返回的连接客户端 socket fd
     if((recvbytes = read(client_fd,buf,MAXDATASIZE)) == -1) {
         perror("recv");
         exit(1);
     }
    if(recvbytes == 0)
    {
     printf("client quit\n");
    break;
    }
    printf("received data %d: %s\n",recvbytes,buf);
   }
    //6.关闭
    close(sockfd);
}


04 实测效果演示

RVB2601链接wifi并获取IP地址,IP地址为192.168.95.2

image.gif

image.png

服务器的IP地址为:192.168.95.5

image.gifimage.png


为了更好的展示通讯过程,在linux机器上运行tcpdump工具来抓取对应端口的网络数据包,通过wireshark分析这些数据包。


我们在linux系统上打开两个终端。


一个终端运行tcpdump:


sudo tcpdump tcp port 26666 and host 192.168.95.5 -i wlan0 -w ./1.cap


另一个终端运行tcpserver软件。

image.png


在RVB2601评估板的console中执行tcptest命令

image.png


通过wireshark分析tcpdump抓取的以太网TCP数据帧分析

image.png


05 特殊情况总结

RVB2061这种协议栈运行在W800的情况,无法实现TCPServer中accept和listen这些函数,因此,也就无法实现TCPServer这种功能了,只能采用TCPClient方式通讯。

image.png

06 下期预告

有关RVB2601开发板的以太网测试就先讲到这里,下期内容将为大家推荐RVB2601的麦克风录音测试。欢迎大家持续关注应用实战精解系列内容。



目录
打赏
0
0
0
0
1013
分享
相关文章
软件测试的艺术:确保质量的实战策略
在软件开发的舞台上,测试是那把确保每个功能如交响乐般和谐奏响的指挥棒。本文将深入探讨软件测试的重要性、基本类型以及如何设计高效的测试策略。我们将通过一个实际的代码示例,展示如何运用这些策略来提升软件质量和用户体验。
探索自动化测试在敏捷开发中的应用与挑战
本文深入探讨了自动化测试在现代软件开发流程,特别是敏捷开发环境中的重要作用和面临的挑战。通过分析自动化测试的基本原理、实施策略以及在实际项目中的应用案例,揭示了其在提高软件质量和加速产品交付方面的巨大潜力。同时,文章也指出了自动化测试实施过程中可能遇到的技术难题、成本考量及团队协作问题,并提出了相应的解决策略,为软件开发团队提供了有价值的参考和指导。
软件测试中的自动化策略与工具应用
在软件开发的快速迭代中,自动化测试以其高效、稳定的特点成为了质量保证的重要手段。本文将深入探讨自动化测试的核心概念、常见工具的应用,以及如何设计有效的自动化测试策略,旨在为读者提供一套完整的自动化测试解决方案,帮助团队提升测试效率和软件质量。
【03】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-测试hello word效果-虚拟华为手机真机环境调试-为DevEco Studio编译器安装中文插件-测试写一个滑动块效果-介绍诸如ohos.ui等依赖库-全过程实战项目分享-从零开发到上线-优雅草卓伊凡
【03】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-测试hello word效果-虚拟华为手机真机环境调试-为DevEco Studio编译器安装中文插件-测试写一个滑动块效果-介绍诸如ohos.ui等依赖库-全过程实战项目分享-从零开发到上线-优雅草卓伊凡
28 10
【03】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-测试hello word效果-虚拟华为手机真机环境调试-为DevEco Studio编译器安装中文插件-测试写一个滑动块效果-介绍诸如ohos.ui等依赖库-全过程实战项目分享-从零开发到上线-优雅草卓伊凡
一个测试工程师的实战笔记:我是如何在Postman和Apipost之间做出选择的?
优秀的API测试工具应该具备: 分层设计:既有可视化操作,也开放代码层深度定制 场景感知:自动识别加密需求推荐处理方案 协议包容:不强迫开发者为了不同协议切换工具 数据主权:允许自主选择数据存储位置
20 7
MATLAB在风险管理中的应用:从VaR计算到压力测试
本文介绍如何使用MATLAB进行风险管理,涵盖风险度量(如VaR)、压力测试和风险分解。通过历史模拟法、参数法和蒙特卡洛模拟法计算VaR,评估投资组合在极端市场条件下的表现,并通过边际VaR和成分VaR识别风险来源。结合具体案例和代码实现,帮助读者掌握MATLAB在风险管理中的应用,确保投资组合的稳健性。
探秘电商API:从测试到应用的深度解析与实战指南
电商API是电子商务背后的隐形引擎,支撑着从商品搜索、购物车更新到支付处理等各个环节的顺畅运行。它通过定义良好的接口,实现不同系统间的数据交互与功能集成,确保订单、库存和物流等信息的实时同步。RESTful、GraphQL和WebSocket等类型的API各自适用于不同的应用场景,满足多样化的需求。在测试方面,使用Postman、SoapUI和jMeter等工具进行全面的功能、性能和安全测试,确保API的稳定性和可靠性。未来,随着人工智能、大数据和物联网技术的发展,电商API将进一步智能化和标准化,为用户提供更个性化的购物体验,并推动电商行业的持续创新与进步。
61 4
如何在实际项目中应用Python Web开发的安全测试知识?
如何在实际项目中应用Python Web开发的安全测试知识?
121 61
探索自动化测试在持续集成中的应用与挑战
本文深入探讨了自动化测试在现代软件开发流程,特别是持续集成(CI)环境中的关键作用。通过分析自动化测试的优势、实施策略以及面临的主要挑战,旨在为开发团队提供实用的指导和建议。文章不仅概述了自动化测试的基本原理和最佳实践,还详细讨论了如何克服实施过程中遇到的技术难题和管理障碍,以实现更高效、更可靠的软件交付。
104 19
探索自动化测试框架在软件开发中的应用与挑战##
本文将深入探讨自动化测试框架在现代软件开发过程中的应用,分析其优势与面临的挑战。通过具体案例分析,揭示如何有效整合自动化测试以提升软件质量和开发效率。 ##

热门文章

最新文章

  • 1
    PCIe 以太网芯片 RTL8125B 的 spec 和 Linux driver 分析备忘
    8
  • 2
    小鱼深度评测 | 通义灵码2.0,不仅可跨语言编码,自动生成单元测试,更炸裂的是集成DeepSeek模型且免费使用,太炸裂了。
    136656
  • 3
    3天功能开发→3小时:通义灵码2.0+DEEPSEEK实测报告,单元测试生成准确率92%的秘密
    82
  • 4
    Potpie.ai:比Copilot更狠!这个AI直接接管项目代码,自动Debug+测试+开发全搞定
    21
  • 5
    基于FPGA的图像双线性插值算法verilog实现,包括tb测试文件和MATLAB辅助验证
    10
  • 6
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    83
  • 7
    大前端之前端开发接口测试工具postman的使用方法-简单get接口请求测试的使用方法-简单教学一看就会-以实际例子来说明-优雅草卓伊凡
    23
  • 8
    「ximagine」业余爱好者的非专业显示器测试流程规范,同时也是本账号输出内容的数据来源!如何测试显示器?荒岛整理总结出多种测试方法和注意事项,以及粗浅的原理解析!
    12
  • 9
    用户说 | 通义灵码2.0,跨语言编码+自动生成单元测试+集成DeepSeek模型且免费使用
    58
  • 10
    以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
    14
  • AI助理

    你好,我是AI助理

    可以解答问题、推荐解决方案等