主控板建立TCPIP或UDP服务器,局域网PC使用TCPIP或UDP客户端进行连接并发送数据,主控板接收到数据后,送液晶屏显示(没有则通过串口打印显示);通过抓包软件抓取交互报文,展示并分析。(TCP和UDP二选一,或者全都操作)
tcpecho 服务器
LWIP 源码包中也是没有 tcpecho 应用代码的,需要在 contrib 代码包中复制过来
pico (无 OS)
LWIP 在无 OS 的情况下只能使用 raw 的 api,所以把 tcpecho_raw.c 和 tcpecho_raw.h 复制到工程中。
在 while(1) 前加这行代码即可,修改 IP 地址、网关等就和 ping 的操作类似
因为来回的插拔杜邦线不太方便,所以画了一个底板,原理图如下,引出了 485 串口、LCD、按键*3、CH340、两路 ADC
LCD 的驱动是 ST7735S 的,资料很多,就不赘述驱动代码了
然后在 tcpecho_raw.c 中添加 LCD 显示的代码和串口输出的代码,具体就是用 sprintf 来格式化,然后在 LCD 上显示并且行数自增,然后打印到调试串口
static char lcd_buff[512];
static int lcd_line = 0;
sprintf(lcd_buff, "%.*s", p->len, p->payload);
LCD_ShowString(10, lcd_line, lcd_buff, GREEN);
lcd_line += 20;
lcd_line %= 320;
printf("rec msg: %s\n", lcd_buff);
这样 W5500 PICO 服务器端搭建好了,还需要一个客户端,用 js 写一段代码来实现一个连接服务器、发送消息、关闭连接的流程
let net = require('net');
let client = net.Socket();
const host = '192.168.0.188';
var arguments = process.argv;
client.connect(7, host, () => {
arguments.forEach((val, index) => {
if (index > 1) {
console.log(`send: ${val}`);
client.write(`${val}`);
}
});
});
client.on('data', data => {
console.log('rec:', data.toString() );
client.end();
})
client.on('end', () => {
console.log('client end');
})
然后运行,后面的参数就是要发送的内容,可以看到串口输出了发送的内容
同时也在屏幕上面显示,可以看到显示了三行内容,和发送的消息一致
wireshark 抓包
使用如下规则,过滤掉网络质量不佳时候重发的内容,筛选出开发板的 IP
ip.src == 192.168.0.188 || ip.dst == 192.168.0.188 && !tcp.analysis.retransmission && !tcp.analysis.duplicate_ack
可以很清楚的看到非常典型的 TCP 三次握手、ECHO 数据、四次挥手的流程
打开其中一条内容可以看到它的组成比 ICMP 消息包的内容要复杂一些,不过就是加了几个状态位和一些选项,可以在 rfc793 文档中查看具体的格式
然后打开 ECHO 的请求包查看详细内容
可以看到刚刚发送的消息
STM32 (有 OS) 作 Client
当有 RTOS 时, LWIP 可供选择的 API 就多了,这里写一个使用 netconn API 来连接服务器、发送消息、关闭连接的 demo
#include "tcpecho.h"
#include "lwip/opt.h"
#if LWIP_NETCONN
#include "lwip/sys.h"
#include "lwip/api.h"
#include <string.h>
char send_buf[128] = "";
static void
tcpecho_thread(void *arg)
{
struct netconn *conn;
int ret;
ip4_addr_t ipaddr;
IP4_ADDR(&ipaddr,192,168,0,188);
while (1)
{
conn = netconn_new(NETCONN_TCP);
if (conn == NULL)
{
printf("create conn failed!\n");
vTaskDelay(10);
continue;
}
ret = netconn_connect(conn, &ipaddr, 7);
if (ret == -1)
{
printf("Connect failed!\n");
netconn_close(conn);
vTaskDelay(10);
continue;
}
printf("Connect to iperf server successful!\n");
static int tick = 0;
sprintf(send_buf, "STM32 TCP Client %d times.", tick++);
ret = netconn_write(conn,send_buf, sizeof(send_buf), 0);
printf("send msg: %s\n", send_buf);
netconn_close(conn);
netconn_delete(conn);
vTaskDelay(2000);
}
}
void
tcpecho_init(void)
{
sys_thread_new("tcpecho_thread", tcpecho_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
}
#endif /* LWIP_NETCONN */
在 main 函数中暂时关闭掉 Cache,因为 STM32H7 系列的 DCache 有概率影响到上面代码中 sprintf 的输出
烧录到 STM32,把 W5500 pico 和 STM32 都复位,可以查看到屏幕输出 STM32 发来的消息
同时两个开发板的串口都输出了收发消息的内容