简介
由于项目需要与上位机通过以太网进行稳定可靠的通信,需要使用Lwip协议栈的TCP部分。zynq的lwip协议栈的版本是1.2,将API模式配置为Socket API。
代码
创建lwip初始化任务
创建lwip初始化任务,在任务中需要对iwip协议栈初始化以及初始化,初始化配置连接配置信息,例如服务器ip地址,掩码,网关等信息。
/*系统任务开启中创建任务LWIP_TASK用于初始化lwip协议栈*/
#define LWIP_TASK__STACKSIZE 1024
#define THREAD_STACKSIZE 1024
int new_sd;
sys_thread_new("LWIP_TASK", (void(*)(void*))Lwip_TASK, 0,
LWIP_TASK__STACKSIZE,
DEFAULT_THREAD_PRIO);//创建LWIP_TASK线程
初始化任务函数
//lwip初始化任务函数
int Lwip_TASK(){
int mscnt = 0;
/* 系统初始化任务 */
lwip_init();
/* 创建NW_THRD任务 */
sys_thread_new("NW_THRD", network_thread, NULL,
THREAD_STACKSIZE,
DEFAULT_THREAD_PRIO);
while (1) {
vTaskDelay(DHCP_FINE_TIMER_MSECS / portTICK_RATE_MS);
mscnt += DHCP_FINE_TIMER_MSECS;
if (mscnt >= 5000) {
xil_printf("Configuring default IP of 192.168.10.10\r\n");
IP4_ADDR(&(server_netif.ip_addr), 192, 168, 10, 10);
IP4_ADDR(&(server_netif.netmask), 255, 255, 255, 0);
IP4_ADDR(&(server_netif.gw), 192, 168, 10, 1);
print_ip_settings(&(server_netif.ip_addr), &(server_netif.netmask), &(server_netif.gw));
/* print all application headers */
sys_thread_new("lwip_listen_TASK",Lwip_Listen_TASK,0,
THREAD_STACKSIZE,
DEFAULT_THREAD_PRIO);
break;
}
}
vTaskDelete(NULL); //删除任务
return 0;
}
配置phy芯片
//用于配置PHY芯片的部分功能
void network_thread(void *p)
{
struct netif *netif;
/* mac地址 每个开发板应该是唯一的 */
unsigned char mac_ethernet_address[] = { 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };
ip_addr_t ipaddr, netmask, gw;
int mscnt = 0;
netif = &server_netif;
ipaddr.addr = 0;
gw.addr = 0;
netmask.addr = 0;
/* 将ip地址、网关、子网掩码加到netif */
if (!xemac_add(netif, &ipaddr, &netmask, &gw, mac_ethernet_address, PLATFORM_EMAC_BASEADDR)) {
xil_printf("Error adding N/W interface\r\n");
return;
}
netif_set_default(netif);
/*启动指定网络*/
netif_set_up(netif);
/*启动数据包接收线程-lwIP操作所需*/
sys_thread_new("xemacif_input_thread", (void(*)(void*))xemacif_input_thread, netif,
THREAD_STACKSIZE,
DEFAULT_THREAD_PRIO);
dhcp_start(netif);
while (1) {
vTaskDelay(DHCP_FINE_TIMER_MSECS / portTICK_RATE_MS);
dhcp_fine_tmr();
mscnt += DHCP_FINE_TIMER_MSECS;
if (mscnt >= DHCP_COARSE_TIMER_SECS*1000) {
dhcp_coarse_tmr();
mscnt = 0;
}
}
return;
}
//该函数是库中的函数,无法使用(调度函数)
/*输入线程调用lwIP来处理任何接收到的数据包。该线程等待直到接收到一个数据包(sem_rx_data_available),然后调用xemacif_input,该线程一次处理1个数据包*/
void xemacif_input_thread(struct netif *netif){
struct xemac_s *emac = (struct xemac_s *)netif->state;
while (1) {
/* 睡眠直到有数据包要处理 这个信号量是由数据包接收中断例程设置的*/
sys_sem_wait(&emac->sem_rx_data_available);
/* 将所有接收到的数据包移动到lwIP */
xemacif_input(netif);
}
}
监听任务
当协议初始化完成后,进入监听和应答任务
void Lwip_Listen_TASK()
{
int sock;
int size;
struct sockaddr_in address, remote;
memset(&address, 0, sizeof(address));
if ((sock = lwip_socket(AF_INET, SOCK_STREAM, 0)) < 0)
return;
address.sin_family = AF_INET;
address.sin_port = htons(LWIP_PORT);
address.sin_addr.s_addr = INADDR_ANY;
if (lwip_bind(sock, (struct sockaddr *)&address, sizeof (address)) < 0)
return;
lwip_listen(sock, 0);//监听
size = sizeof(remote);
while (1) {
/*连接应答任务*/
if ((new_sd = lwip_accept(sock, (struct sockaddr *)&remote, (socklen_t *)&size)) > 0) {
//连接后创建数据应答的任务
printf("Connect SuccessFul !\r\n");
sys_thread_new("lwip_data_TASK",
Lwip_Data_TASK,
(void*)new_sd,
THREAD_STACKSIZE,
FreeRtos_ECHOS_TASK_PRIO);
}
//时间调度 防止任务卡死
vTaskDelay(DHCP_FINE_TIMER_MSECS / portTICK_RATE_MS);
}
}
接收数据后数据处理任务
/* 接收数据后进入任务 */
void Lwip_Data_TASK(void *p)
{
int sd = (int)p;
int RECV_BUF_SIZE = 15;
u8 recv_buf[RECV_BUF_SIZE];
int n,nwrote;
while (1) {
/* 接受数据放到缓存区 */
if ((n = read(sd, recv_buf, RECV_BUF_SIZE)) < 0) {
/*接受数据错误*/
xil_printf("%s: error reading from socket %d, closing socket\r\n", __FUNCTION__, sd);
break;
}
if (!strncmp(recv_buf, "quit", 4)){
break;
}
/*如果客户端关闭连接则中断*/
if (n <= 0){
break;
}
/*将接收的数据返回*/
write(sd, recv_buf, RECV_BUF_SIZE);
}
close(sd);
vTaskDelete(NULL);
}
源码连接
链接:资料连接
提取码:k2cl