【平头哥RVB2601创意应用开发】使用体验05 -- TCP Client
[复制链接]
本帖最后由 sonicfirr 于 2022-4-7 18:22 编辑
RVB2601的Wi-Fi模块工作起来后,自然就是利用其进行通信,最常见的模式就是TCP协议,配置板子作为TCP Client连接PC机运行的TCP Server(网络助手),此篇记录相关过程。
1、网络连接组件介绍
如果说网络管理器“netmgr”实现了接入模块适配,那么套接字适配层SAL就是与协议栈的适配接口(这里面有个大坑,关于NTP,下篇再讲)。
在CH2601 SDK中,SAL向下通过drv_wifi_at_w800组件与W800模块适配,向上则桥接于lwip协议栈。
图5-1 SAL框架示意图
进而,RVB2601实现联网通信,尤其是传输层通信,既可以通过lwip的API,也可以通过drv_wifi_at_w800的API。
对于用户来说,drv_wifi_at_w800组件可能更加直接。其中的“w800_api.c”文件定义了主要的网络通信接口等函数。
图5-2 drv_wifi_at_w800组件主要源文件
图5-3 w800_api.c中部分API
而对于lwip接口来说,按照其API使用方式就可以实现功能,不过这里需要提到的一个“坑”,就是SAL适配的lwip并不完整,如果尝试再添加单独的lwip组件(IDE中支持)这样做,不仅不会补全功能,还会因为存在两套组件源码(即SAL不全版和导入lwip pack)而出现大量报错。
SAL通过sal_opt_t结构体,封装主要的通信功能接口,在w800_devops.c中,w800_dev_open()函数完成了全局sal_opt_t变量——w800_sal_driver的注册。
图5-4 RVB2601中的sal接口定义
2、TCP Client实现案例
本篇利用drv_wifi_at_w800组件实现了TCP Client连接。案例还是基于“Hello World”修改,并在上篇基础上扩充。
在init.c中定义接收回调函数,业务逻辑比较简单,就是将接收内容串口打印输出。
//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);
}
网络初始化函数还是上篇建立的aita_InitNetwork(),现在添加一句注册回调函数的代码。
//network init: open w800,
void aita_InitNetwork(void) {
/*
* by AITA Mr.Fei
* w800 interface struct
*/
w800_wifi_param_t w800_param;
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;
/*
* by AITA Mr.Fei
* from w800_devops.c(drv_wifi_at_w800 pack),
* include w800_module_init(but there is no task, so create a new one) & driver_register.
*/
wifi_w800_register(NULL, &w800_param);
/*
* by AITA Mr.Fei
* register uservice for wifi,
* init netmgr_uservice struct then return the pointer
*/
app_netmgr_hdl = netmgr_dev_wifi_init();
if(app_netmgr_hdl) {
//init uservice for wifi
utask_t *task = utask_new("netmgr", 2 * 1024, QUEUE_MSG_COUNT, AOS_DEFAULT_APP_PRI);
netmgr_service_init(task);
//join AP, WIFI_SSID & WIFI_PSW both are Macro
netmgr_config_wifi(app_netmgr_hdl, WIFI_SSID, 10, WIFI_PSW, 10);
//init w800 AT parser
w800_module_init(task, &w800_param);
//register input event callback for w800 module -- 添加此句代码
w800_packet_input_cb_register(&aita_w800in_cb);
//start uservice
netmgr_start(app_netmgr_hdl);
//subscribe events which is managed by netmgr uservice
event_subscribe(EVENT_NETMGR_GOT_IP, network_event, NULL);
event_subscribe(EVENT_NETMGR_NET_DISCON, network_event, NULL);
}
}
再编写一个TCP连接的测试函数,非常简单,建立TCP Server(手机APP实现),然后发送一条信息,当然连接建立后短时间不会断开,Server也可以回传信息,通过回调函数接收。
//tcp client test func
void aita_tcpclienttest(void) {
char buf[] = "hello from RVB2601 by W800\n";
int ret = -1;
ret = w800_connect_remote(0, NET_TYPE_TCP_CLIENT, GW_IP, GW_PORT);
if(ret < 0) return;
int stat;
w800_get_status(&stat); //[ 16.360]<D>w800_api link status 2 已获取到ip
LOGD(TAG, "connect status: %d\n", stat);
w800_send_data(buf, sizeof(buf), 3000);
}
为了测试方便,cli_cmd.c中添加代码,将aita_tcpclienttest()注册为一条控制台命令,代码如下。
void aita_tcpclienttest(void);
static void cmd_tcp_client_handler(char *wbuf, int wbuf_len, int argc, char **argv) {
aita_tcpclienttest();
}
int cli_reg_cmd_tcp(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;
}
void board_cli_init()
{
aos_cli_init();
extern void cli_reg_cmd_ps(void);
cli_reg_cmd_ps();
extern void cli_reg_cmd_free(void);
cli_reg_cmd_free();
extern void cli_reg_cmd_ping(void);
cli_reg_cmd_ping();
extern void cli_reg_cmd_ifconfig(void);
cli_reg_cmd_ifconfig();
//register tcp client test command
cli_reg_cmd_tcp();
}
图5-5 tcptest命令测试效果
图5-6 TCP Server接收效果
|