zynq 裸核echo 代码简化
zynq 裸核echo 代码简化原因
zynq实例代码中echo、tcp_client、tcp_server都非常复杂,对新手非常不友好,所以我对zynq echo代码进行了改进
zynq echo代码给了一个基于tcp协议回传代码,但是代码结构复杂,涉及好几份文件,包括小项目中不需要的tcp_fasttmr(); tcp_slowtmr();所以我将这个项目重新修改一下
以下代码只要放在hello.c或者main.c里面即可,不要其他文件,相比于zynq官方实例代码简单很多很多
作者使用是黑金的zynq7020的开发板卡
化简之后代码
#include "xparameters.h"
#include "xparameters_ps.h" /* defines XPAR values */
#include "xil_cache.h"
#include "xscugic.h"
#include "lwip/netif.h"
#include "lwip/inet.h"
#include "lwip/err.h"
#include "lwip/tcp.h"
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#define PLATFORM_EMAC_BASEADDR XPAR_XEMACPS_0_BASEADDR
static struct netif server_netif;
struct netif *echo_netif;
err_t accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err);
err_t recv_callback(void *arg, struct tcp_pcb *tpcb,struct pbuf *p, err_t err);
int main()
{
/*********************xil_exception********************************/
//这部分代码是初始化以太网相关中断,源代码中初始化了timer中断和以太网中断
Xil_ExceptionInit();
XScuGic_DeviceInitialize(INTC_DEVICE_ID);
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
(Xil_ExceptionHandler)XScuGic_DeviceInterruptHandler,
(void *)INTC_DEVICE_ID);
Xil_ExceptionEnable();
/*********************create netif********************************/
//这部分代码设置netif,可以将此理解为pcb的底层
ip_addr_t ipaddr, netmask, gw;
IP4_ADDR(&ipaddr, 192, 168, 1, 10);
IP4_ADDR(&netmask, 255, 255, 255, 0);
IP4_ADDR(&gw, 192, 168, 1, 1);
unsigned char mac_ethernet_address[] = {0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };
echo_netif = &server_netif;
/* initialize lwIP */
lwip_init();
/* Add network interface to the netif_list, and set it as default */
if (!xemac_add(echo_netif, &ipaddr, &netmask,&gw, mac_ethernet_address,PLATFORM_EMAC_BASEADDR))
{
xil_printf("Error adding N/W interface\n\r");
return -1;
}
netif_set_default(echo_netif);
netif_set_up(echo_netif);
/*********************create pcb********************************/
//初始化pcb
struct tcp_pcb *pcb;
err_t err;
unsigned port = 7;
/* create new TCP PCB structure */
pcb = tcp_new_ip_type(IPADDR_TYPE_ANY);
if (!pcb)
{
xil_printf("Error creating PCB. Out of Memory\n\r");
return -1;
}
/* bind to specified @port */
err = tcp_bind(pcb, IP_ANY_TYPE, port);
if (err != ERR_OK)
{
xil_printf("Unable to bind to port %d: err = %d\n\r", port, err);
return -2;
}
/* we do not need any arguments to callback functions */
tcp_arg(pcb, NULL);
/* listen for connections */
pcb = tcp_listen(pcb);
if (!pcb)
{
xil_printf("Out of memory while tcp_listen\n\r");
return -3;
}
/* specify callback to use for incoming connections */
tcp_accept(pcb, accept_callback);
tcp_recv(pcb, recv_callback);
xil_printf("TCP echo server started @ port %d\n\r", port);
/*********************死循环********************************/
//xemacif_input函数不断运行,保证整个协议工作
while (1)
{
usleep(1000);
xemacif_input(echo_netif);
}
return 0;
}
/*********************client和zynq对接上之后该函数运行****************************/
err_t accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err)
{
tcp_arg(newpcb, NULL);
tcp_recv(newpcb, recv_callback);
tcp_err(newpcb, NULL);
return ERR_OK;
}
/*********************client和zynq通信之后该函数运行****************************/
err_t recv_callback(void *arg, struct tcp_pcb *tpcb,
struct pbuf *p, err_t err)
{
/* do not read the packet if we are not in ESTABLISHED state */
if (!p) {
tcp_close(tpcb);
tcp_recv(tpcb, NULL);
return ERR_OK;
}
/* indicate that the packet has been received */
tcp_recved(tpcb, p->len);
/* echo back the payload */
/* in this case, we assume that the payload is < TCP_SND_BUF */
if (tcp_sndbuf(tpcb) > p->len)
{
err = tcp_write(tpcb, p->payload, p->len, 1);
} else
xil_printf("no space in tcp_sndbuf\n\r");
/* free the received pbuf */
pbuf_free(p);
return ERR_OK;
}