前言
之前ZYNQ与PC之间的网络连接依赖于外接硬件协议栈芯片,虽然C驱动非常简单,但网络带宽受限。现采用LWIP+PS端MAC控制器+PHY芯片的通用架构。关于LWIP库,已经有很多现成的资料和书籍。其有两套API,一个是SOCKET,另一个是本例中要用到的RAW。RAW API理解起来较为复杂,整个程序基于中断机制运行,通过函数指针完成多层回调函数的执行。SOCKET API需要支持多线程操作系统的支持,也牺牲了效率,但理解和编程都较为容易。实际上SOCKET API是对RAW API的进一步封装。
二、LWIP Echo Server demo解读
首先打开Xilinx SDK自带的LwIP Echo Server demo.
echo整体流程为:初始化LWIP、添加网络接口(MAC)、使能中断、设置回调函数。最终进入主循环,内部不断检测定时器中断标志位,当标志位TcpFastTmrFlag或TcpSlowTmrFlag为1则调用相应的处理函数,完成超时重传等任务。接下来查看回调函数的设置:
start_application创建PCB(protocol control block)建立连接、绑定IP地址和端口号、监听请求,最后tcp_accept函数用于指定当监听到连接请求时调用的函数accept_callback。进入该函数内部查看:
accept_callback内部主要通过tcp_recv函数来指定当收到TCP包后调用的函数recv_callback。我们再次观察其内容:
recv_callbacktcp_recved函数指示用来告知LWIP接收数据量,然后检测发送缓冲区是否足够容纳接收内容,若大于则调用tcp_write函数将接收数据写入发送缓冲区等待发送。综上,整体的调用流程为:tcp_accept -> accept_callback -> tcp_recv -> recv_callback -> tcp_recved和tcp_write。前四个用于接收,后两个用于发送。
函数解析完毕,之后改动上位机网络参数,使PC机IP地址与Board在同一网段内,这里设置为192.168.1.11.打开网络调试助手,设置PC为TCP Client。以下是ZYNQ串口打印及网络调试结果。


三、TCP Client Send data
现在我们来改动demo,设计一个客户端发送数据包的示例工程,功能是循环发送一个常数数组中数据到远程服务器。该工程参考米联客教程中相关章节内容。代码如下:
main函数定义:
tcp_trans可以看出还是一样的套路,在client_application函数中设置回调函数。首先新建PCB,tcp_connect函数设定要连接远程服务器的IP地址和端口号,连接建立时将调用回调函数tcp_connected_callback。tcp_connected_callback内部tcp_sent函数用于指定当发送数据包完成后执行的tcp_sent_callback。tcp_sent_callback内部只利用tcp_trans_done变量计数发送次数。而真正的发送处理任务则交给主循环中的send_data。若处于连接状态,且发送缓冲区容量比带发送数据量大,则调用tcp_write将待发送数据写入发送缓冲区,之后调用tcp_output函数立即传输发送缓冲区内容。如果不调用tcp_output,LWIP会等待数据量达到一定值时一起发送来提高效率,是否调用tcp_output函数可根据具体需求而定。
接下来看下实验结果:

PC端正确接收到常数数组,实验无误。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
参考文献:
1 LWIP 无OS RAW-API 函数 - 专注的力量 - CSDN博客 https://blog.csdn.net/liang890319/article/details/8574603
2 解读TCP 四种定时器 - xiaofei0859的专栏 - CSDN博客 https://blog.csdn.net/xiaofei0859/article/details/52794576https://www.cnblogs.com/moluoqishi/p/9865480.html
