【ZYNQ】裸机 PS + PL 双网口实现之 SDK 程序设计

涉及 lwip 库文件及 ZYNQ 配置相关可参考以下文章:

【ZYNQ】裸机 PS + PL 双网口实现之 LWIP 库文件修改

【ZYNQ】裸机 PS + PL 双网口实现之 ZYNQ 配置

工程配置

  • 启动 SDK ,创建模板工程,配置 BSP。

在这里插入图片描述

  • 勾选 lwip141 库。

在这里插入图片描述

  • 对 lwip 做如下配置,如没有此选项请先参考【ZYNQ】裸机 PS + PL 双网口实现之 lwip 库文件修改。

use_axieth_on_zynquse_emaclite_on_zynq 设为 0。将 use_gmii2rgmii_core_on_eth1 设置为 true,GMII to RGMII IP 核对应的 PHY 地址为 8,即 gmii2rgmii_core_address_on_eth1 设为 8。ETH0 不使用 EMIO,因此 use_gmii2rgmii_core_on_eth0falsegmii2rgmii_core_address_on_eth0 无需进行设置。

在这里插入图片描述

程序设计

  • 添加定时器,用来调用 tcp 服务,其中,250ms 和 500ms 是必须的。相关代码如下:

  • main.c

/**
 * Copyright (c) 2022-2023,HelloAlpha
 * 
 * Change Logs:
 * Date           Author       Notes
 */
#include "platform_config.h"
#include "service/timer/app_timer.h"

#define USING_ULOG
#include "ulog.h"

#define _EXPORT_FUNC(function)     \
    do                             \
    {                              \
        extern int function(void); \
        function();                \
    } while (0)

int lwip_tcp_init(void);
int app_timer_init(void);

int func_doing_always(void)
{
    static timer_flag_t *_timer_flag = &g_timer_flag;

#ifdef USING_ETHERNET_TCP
    _EXPORT_FUNC(tcp_func_always);
#endif

    if(_timer_flag->timer_flag_250ms == 1)
    {
        _timer_flag->timer_flag_250ms = 0;
#ifdef USING_ETHERNET_TCP
    _EXPORT_FUNC(tcp_func_per_250ms);
#endif
    }

    if(_timer_flag->timer_flag_500ms)
    {
        _timer_flag->timer_flag_500ms = 0;
#ifdef USING_ETHERNET_TCP
    _EXPORT_FUNC(tcp_func_per_500ms);
#endif
    }

    if(_timer_flag->timer_flag_1s == 1)
    {
        _timer_flag->timer_flag_1s = 0;
#ifdef USING_ETHERNET_TCP
        _EXPORT_FUNC(tcp_func_per_1s);
#endif
    }

    return 0;
}

int main(void)
{
    ULOG("\r\n------ Main Function Running ------\r\n");

    app_timer_init();

#ifdef USING_ETHERNET_TCP
    _EXPORT_FUNC(lwip_tcp_init);
#endif

    while(1)
    {
        func_doing_always();
    }

    return 0;
}
  • 基于 LWIP 创建网卡,这里配置为静态 IP,代码如下:

  • lwip_tcp.c

/**
 * Copyright (c) 2022-2023,HelloAlpha
 * 
 * Change Logs:
 * Date           Author       Notes
 */
#include "tcp_config.h"
#ifdef USING_ETHERNET_TCP

#include "lwip/init.h"
#include "lwip/err.h"
#include "netif/xadapter.h"

#define USING_ULOG
#include "ulog.h"

err_t accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err);

static void print_ip(char *msg, struct ip_addr *ip)
{
    kprintf(msg);
    kprintf("%d.%d.%d.%d\r\n", ip4_addr1(ip), ip4_addr2(ip),
                            ip4_addr3(ip), ip4_addr4(ip));
}

void tcp_node_printf(char *tcp_node_name, tcp_node_t *tcp_node)
{
    kprintf("------------- %s -------------\r\n", tcp_node_name);
    print_ip("local addr: ", &(tcp_node->local_addr));
    kprintf("local port: %d \r\n" ,tcp_node->local_port);
    print_ip("target addr: ", &(tcp_node->target_addr));
    kprintf("remote port: %d \r\n", tcp_node->remote_port);
    kprintf("-------------------------------------\r\n");
}

static void print_app_header()
{
    kprintf("\n\r----- lwIP TCP ------\r\n");
}

/**
 * @brief
 *
 * @return err_t
 */
err_t start_tcp_application(tcp_node_t *tcp_node)
{
    err_t err;

   if(!tcp_node)
   {
       ULOG("TCP node is empty!\r\n");
       return ERR_ARG;
   }
   /* create pcb */
    tcp_node->pcb_obj = tcp_new();
    if (!tcp_node->pcb_obj)
    {
        ULOG("Error creating PCB. Out of Memory!\r\n");
        return ERR_MEM;
    }
    /* bind to specified @port */
    err = tcp_bind(tcp_node->pcb_obj, &(tcp_node->local_addr), tcp_node->local_port);
    if (err != ERR_OK)
    {
        ULOG("Unable to bind to port %d: err = %d!\r\n", tcp_node->local_port, err);
        return ERR_ABRT;
    }
    /* we do not need any arguments to callback functions */
    tcp_arg(tcp_node->pcb_obj, NULL);
    /* listen for connections */
    tcp_node->pcb_obj = tcp_listen(tcp_node->pcb_obj);
    if (!tcp_node->pcb_obj)
    {
        ULOG("Out of memory while tcp_listen!\r\n");
        return ERR_MEM;
    }
    /* specify callback to use for incoming connections */
    tcp_accept(tcp_node->pcb_obj, accept_callback);
    return err;
}

#ifdef USING_ETHERNET0
static int ethernet0_init(void)
{
    err_t err;
    struct netif *echo_netif0 = &server_netif0;
    struct ip_addr ipaddr0, netmask0, gw0;
    /* the mac address of the board. this should be unique per board */
    unsigned char mac_ethernet_address0[] = { 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };

    /* initliaze IP addresses to be used */
    IP4_ADDR(&ipaddr0,  192, 168,   6, 10);
    IP4_ADDR(&netmask0, 255, 255, 255,  0);
    IP4_ADDR(&gw0,      192, 168,   1,  1);

    /* Add network interface to the netif_list, and set it as default */
    if (!xemac_add(echo_netif0, &ipaddr0, &netmask0,
                        &gw0, mac_ethernet_address0,
                        PLATFORM_EMAC_BASEADDR))
    {
        kprintf("ENET0 Error adding N/W interface!\r\n");
        return -1;
    }
    netif_set_default(echo_netif0);
    /* specify that the network if is up */
    netif_set_up(echo_netif0);

    /* initialize TCP0 node */
    tcp_node_t *tcp0_node = &g_tcp0_node;
    /* local IP */
     tcp0_node->local_addr.addr = ipaddr0.addr;
    /* local port */
    tcp0_node->local_port = DEFAULT_PORT0;
    /* target IP */
    IP4_ADDR(&(tcp0_node->target_addr), 192,168,6,81);
    /* target port */
    tcp0_node->remote_port = 8080;
    /* clear the connection flag */
    tcp0_node->connected_flag = 0;

    /* start the application */
    err = start_tcp_application(tcp0_node);
    if(err != ERR_OK)
    {
        kprintf("Start TCP0 application failed!\r\n");
        return -1;
    }
    else
    {
        tcp_node_printf("TCP0 Node", tcp0_node);
    }

    return 0;
}
#endif

#ifdef USING_ETHERNET1
static int ethernet1_init(void)
{
    err_t err;
    struct netif *echo_netif1 = &server_netif1;
    struct ip_addr ipaddr1, netmask1, gw1;
    /* the mac address of the board. this should be unique per board */
    unsigned char mac_ethernet_address1[] =	{ 0x00, 0x0a, 0x35, 0x00, 0x01, 0x03 };

    /* initliaze IP addresses to be used */
    IP4_ADDR(&ipaddr1,  192, 168,   6, 20);
    IP4_ADDR(&netmask1, 255, 255, 255,  0);
    IP4_ADDR(&gw1,      192, 168,   1,  1);

    if (!xemac_add(echo_netif1, &ipaddr1, &netmask1,
                        &gw1, mac_ethernet_address1,
                        PLATFORM_EMAC1_BASEADDR))
    {
        kprintf("ENET1 Error adding N/W interface!\r\n");
        return -1;
    }
    netif_set_default(echo_netif1);
    /* specify that the network if is up */
    netif_set_up(echo_netif1);

    /* initialize TCP1 node */
    tcp_node_t *tcp1_node = &g_tcp1_node;
    /* local IP */
     tcp1_node->local_addr.addr = ipaddr1.addr;
    /* local port */
    tcp1_node->local_port = DEFAULT_PORT1;
    /* target IP */
    IP4_ADDR(&(tcp1_node->target_addr), 192,168,6,81);
    /* target port */
    tcp1_node->remote_port = 8081;
    /* clear the connection flag */
    tcp1_node->connected_flag = 0;

    /* start the application */
    err = start_tcp_application(tcp1_node);
    if(err != ERR_OK)
    {
        kprintf("Start TCP1 application failed!\r\n");
        return -1;
    }
    else
    {
        tcp_node_printf("TCP1 Node", tcp1_node);
    }

    return 0;
}
#endif

int lwip_tcp_init(void)
{
    print_app_header();
    lwip_init();

#ifdef USING_ETHERNET0
    ethernet0_init();
#endif

#ifdef USING_ETHERNET1
    ethernet1_init();
#endif

    return 0;
}

#endif
  • tcp_service.c 主要实现一些功能服务。

  • tcp_service.c

/**
 * Copyright (c) 2022-2023,HelloAlpha
 * 
 * Change Logs:
 * Date           Author       Notes
 */
#include "tcp_config.h"
#ifdef USING_ETHERNET_TCP

#include "lwip/err.h"
#include <string.h>

#define USING_ULOG
#include "ulog.h"

#ifdef USING_ETHERNET0
static tcp_node_t *tcp0_node = &g_tcp0_node;
#endif
#ifdef USING_ETHERNET1
static tcp_node_t *tcp1_node = &g_tcp1_node;
#endif

/**
 * @brief TCP data sending function
 * 
 * @return err_t 
 */
err_t tcp_transfer_data(struct tcp_pcb *tpcb, const uint8_t *pData, int plen)
{
    err_t err;
    static struct pbuf *tcp_pbuf = NULL;
    static int tcp_len = 0;

    /* If parameter length bigger than tcp_len, reallocate memory space */
    if(plen > tcp_len)
    {
        if(tcp_pbuf)
        {
            /* free pbuf */
            pbuf_free(tcp_pbuf);
        }
        tcp_len = plen;
        /* allocate memory space to pbuf */
        tcp_pbuf = pbuf_alloc(PBUF_TRANSPORT, tcp_len, PBUF_RAM);
        if(!tcp_pbuf)
        {
            ULOG("pbuf_alloc %d fail!\r\n", tcp_len);
            tcp_len = 0;
            return ERR_BUF;
        }
    }

    /* copy data to pbuf payload */
    memcpy(tcp_pbuf->payload, pData, plen);
    tcp_pbuf->len = plen;
    tcp_pbuf->tot_len = plen;

    /* Start to send udp data */
    err = tcp_write(tpcb, (tcp_pbuf->payload), (tcp_pbuf->len), 
                        TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
    if (err != ERR_OK)
    {
        ULOG("Error on tcp_write: %d!\r\n", err);
        return err;
    }

    err = tcp_output(tpcb);
    if (err != ERR_OK)
    {
        ULOG("Error on tcp_output: %d!\r\n", err);
        return err;
    }

    return err;
}

/**
 * @brief TCP data sending function
 * 
 * @return err_t 
 */
err_t tcp_send(tcp_node_t *tcp_node, tcp_msg_t *tcp_msg)
{
    err_t err;
    if(!tcp_node)
    {
        ULOG("Empty TCP node!\r\n");
        return ERR_ARG;
    }
    else if(!tcp_msg)
    {
        ULOG("Empty TCP message!\r\n");
        return ERR_ARG;
    }
    else if(!tcp_node->connected_flag)
    {
        ULOG("TCP%d is not currently connected!\r\n",
                (tcp_node->local_port == DEFAULT_PORT0) ? 0 : 1);
        tcp_msg->tx_vflag = 0;
        return ERR_CONN;
    }
    else if(!tcp_msg->tx_vflag)
    {
        ULOG("Flag indicates message is not ready!\r\n");
        return ERR_ARG;
    }
    else
    {
        err = tcp_transfer_data(tcp_node->pcb_obj,
                    (uint8_t *)tcp_msg->tx_pdata, tcp_msg->tx_plen);
        tcp_msg->tx_vflag = 0;
    }

    return err;
}

/**
 * @brief close the TCP connection
 *
 * @return int
 */
static int tcp_connection_close(struct tcp_pcb *tpcb)
{
    tcp_close(tpcb);
    tcp_arg(tpcb, NULL);
    tcp_recv(tpcb, NULL);
    tcp_sent(tpcb, NULL);
    tcp_poll(tpcb, NULL, 0);
    tcp_err(tpcb, NULL);

#ifdef USING_ETHERNET0
    if(tpcb->local_port == DEFAULT_PORT0)
    {
        if(tcp0_node->connected_flag == 1)
        {
            /* reset the connection flag */
            tcp0_node->connected_flag = 0;
        }
    }
#endif

#ifdef USING_ETHERNET1
    if (tpcb->local_port == DEFAULT_PORT1)
    {
        if(tcp1_node->connected_flag == 1)
        {
            /* reset the connection flag */
            tcp1_node->connected_flag = 0;
        }
    }
#endif

    return ERR_OK;
}

/**
 * @brief TCP data receiving callback function
 * 
 * @return err_t 
 */
static err_t recv_callback(void *arg, struct tcp_pcb *tpcb,
                               struct pbuf *p_rx, err_t err)
{
    /* do not read the packet if we are not in ESTABLISHED state */
    if (!p_rx)
    {
        tcp_connection_close(tpcb);
        return ERR_OK;
    }

    /* indicate that the packet has been received */
    tcp_recved(tpcb, p_rx->len);

    /* the data is processed here. */
    {
#ifndef USING_TCP_LOOKBACK

#ifdef USING_ETHERNET0
        static tcp_msg_t *tcp0_msg = &g_tcp0_msg;

        if(tpcb->local_port == DEFAULT_PORT0)
        {
            if(!tcp0_msg->rx_vflag)
            {
                tcp0_msg->rx_pdata = tcp0_msg->rx_pdata_buf;
                memcpy(tcp0_msg->rx_pdata, (char *) p_rx->payload, p_rx->len);
                tcp0_msg->rx_plen = p_rx->len;
                tcp0_msg->rx_vflag = 1;
            }
        }
#endif

#ifdef USING_ETHERNET1
        static tcp_msg_t *tcp1_msg = &g_tcp1_msg;

        if(tpcb->local_port == DEFAULT_PORT1)
        {
            if(!tcp1_msg->rx_vflag)
            {
                tcp1_msg->rx_pdata = tcp1_msg->rx_pdata_buf;
                memcpy(tcp1_msg->rx_pdata, (char *) p_rx->payload, p_rx->len);
                tcp1_msg->rx_plen = p_rx->len;
                tcp1_msg->rx_vflag = 1;
            }
        }
#endif

#else
        char TcpSend[] = "> LookBack Test Running... \r\n> Rec Data: ";

        tcp_transfer_data(tpcb, (uint8_t *)TcpSend, strlen(TcpSend));

        /* echo back the payload */
        /* in this case, we assume that the payload is < TCP_SND_BUF */
        if (tcp_sndbuf(tpcb) > p_rx->len)
        {
            err = tcp_write(tpcb, p_rx->payload, p_rx->len, 1);
        }
        else
        {
            ULOG("No space in tcp_sndbuf...\n\r");
        }
#endif
    }

    /* free the received pbuf */
    pbuf_free(p_rx);

    return ERR_OK;
}

/**
 * @brief TCP Callback function for successful TCP data sending
 *
 * @return err_t
 */
static err_t tcp_sent_callback(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
#ifdef USING_ETHERNET0
    static uint32_t tcp0_trans_cnt = 0;
    if(tpcb->local_port == DEFAULT_PORT0)
    {
        ULOG("TCP0 Send Success Count: %d \r\n", tcp0_trans_cnt++);
    }
#endif

#ifdef USING_ETHERNET1
    static uint32_t tcp1_trans_cnt = 0;
    if (tpcb->local_port == DEFAULT_PORT1)
    {
        ULOG("TCP1 Send Success Count: %d \r\n", tcp1_trans_cnt++);
    }
#endif

    return ERR_OK;
}

static err_t tcp_poll_callback(void *arg, struct tcp_pcb *tpcb)
{
    /* it is executed every 500ms */
#ifdef USING_ETHERNET0
    if(tpcb->local_port == DEFAULT_PORT0)
    {
        tcp0_node->connected_count++;
    }
#endif

#ifdef USING_ETHERNET1
    if(tpcb->local_port == DEFAULT_PORT1)
    {
        tcp1_node->connected_count++;
    }
#endif

    return ERR_OK;
}

static void tcp_err_callback(void *arg, err_t err)
{
    LWIP_UNUSED_ARG(err);
    ULOG("TCP error: %x \r\n", (uint32_t)arg);

    if(NULL != arg)
    {

    }
}

/**
 * @brief When TCP is in LISTEN state, listen for a new connection 
 * 		  and execute this function
 *
 * @return err_t 
 */
err_t accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err)
{
    static int connection = 1;

    /* set the receive callback for this connection */
    tcp_recv(newpcb, recv_callback);

    /* set the sent callback for this connection */
    tcp_sent(newpcb, tcp_sent_callback);

    tcp_poll(newpcb, tcp_poll_callback, 1);

    tcp_err(newpcb, tcp_err_callback);

    {
        ULOG("\r\n----- TCP Connection -----\r\n");
        ULOG(" Local IP: %d.%d.%d.%d, Local Port: %d \r\n",
            (newpcb->local_ip.addr) & 0xff, (newpcb->local_ip.addr >> 8) & 0xff,
            (newpcb->local_ip.addr >> 16) & 0xff, (newpcb->local_ip.addr >> 24) & 0xff,
            newpcb->local_port);
        ULOG(" Remote IP: %d.%d.%d.%d, Remote Port: %d \r\n",
            (newpcb->remote_ip.addr) & 0xff, (newpcb->remote_ip.addr >> 8) & 0xff,
            (newpcb->remote_ip.addr >> 16) & 0xff, (newpcb->remote_ip.addr >> 24) & 0xff,
            newpcb->remote_port);

#ifdef USING_ETHERNET0
        if(newpcb->local_port == DEFAULT_PORT0)
        {
            if(tcp0_node->connected_flag == 0)
            {
                /* set the connection flag */
                tcp0_node->connected_flag = 1;
                tcp0_node->pcb_obj = newpcb;
            }
        }
#endif

#ifdef USING_ETHERNET1
        if (newpcb->local_port == DEFAULT_PORT1)
        {
            if(tcp1_node->connected_flag == 0)
            {
                /* set the connection flag */
                tcp1_node->connected_flag = 1;
                tcp1_node->pcb_obj = newpcb;
            }
        }
#endif
    }

    /* just use an integer number indicating the connection id as the
       callback argument */
    tcp_arg(newpcb, (void*)(UINTPTR)connection);

    /* increment for subsequent accepted connections */
    connection++;

    return ERR_OK;
}

#ifdef USING_TCP_STATUS

#ifdef USING_ETHERNET0
static int tcp0_check_connect_status(void)
{
    static uint32_t last_tcp0_count = 0;
    static uint8_t tcp0_status = 0;

    if(tcp0_node->connected_count > last_tcp0_count)
    {
        if(tcp0_status == 0)
        {
            tcp0_status = 1;
            ULOG("Tcp0 Connected!\r\n");
        }

        if(tcp0_node->connected_count > 65530)
        {
            tcp0_node->connected_count = 1;
        }
        last_tcp0_count = tcp0_node->connected_count;
    }
    else
    {
        tcp0_node->connected_flag = 0;
        if(tcp0_status == 1)
        {
            tcp0_status = 0;
            ULOG("Tcp0 Disconnected!\r\n");
        }
    }

    return 0;
}
#endif

#ifdef USING_ETHERNET1
static int tcp1_check_connect_status(void)
{
    static uint32_t last_tcp1_count = 0;
    static uint8_t tcp1_status = 0;

    if(tcp1_node->connected_count > last_tcp1_count)
    {
        if(tcp1_status == 0)
        {
            tcp1_status = 1;
            ULOG("Tcp1 Connected!\r\n");
        }

        if(tcp1_node->connected_count > 65530)
        {
            tcp1_node->connected_count = 1;
        }
        last_tcp1_count = tcp1_node->connected_count;
    }
    else
    {
        tcp1_node->connected_flag = 0;
        if(tcp1_status == 1)
        {
            tcp1_status = 0;
            ULOG("Tcp1 Disconnected!\r\n");
        }
    }

    return 0;
}
#endif

/**
 * @brief Check TCP connect status
 *
 */
int tcp_check_connect_status(void)
{
#ifdef USING_ETHERNET0
    tcp0_check_connect_status();
#endif

#ifdef USING_ETHERNET1
    tcp1_check_connect_status();
#endif

    return 0;
}

#endif

#endif
  • tcp_config.h 实现了一些定义及配置。

  • tcp_config.h

/**
 * Copyright (c) 2022-2023,HelloAlpha
 * 
 * Change Logs:
 * Date           Author       Notes
 */
#ifndef __TCP_CONFIG_H__
#define __TCP_CONFIG_H__

#include "xparameters.h"

/**
 * TCP config begin
 * @{
 */
#define USING_ETHERNET_TCP

#if defined USING_ETHERNET_TCP
#define USING_ETHERNET0
#define USING_ETHERNET1
#define USING_TCP_STATUS
//#define USING_TCP_LOOKBACK
//#define USING_TCP_PRINT_MSG
//#define USING_TCP_TEST_CMD
#endif

#ifdef USING_ETHERNET0
#define PLATFORM_EMAC_BASEADDR XPAR_XEMACPS_0_BASEADDR
#endif

#ifdef USING_ETHERNET1
#define PLATFORM_EMAC1_BASEADDR XPAR_XEMACPS_1_BASEADDR
#endif
/**@}*/

#ifdef USING_ETHERNET_TCP

#include "lwip/tcp.h"

/* default IP port */
#define DEFAULT_PORT0       7
#define DEFAULT_PORT1       8

#define MAX_SEND_LEN 		64
#define TCP_MSG_MSG_LEN     256

struct tcp_msg
{
    char rx_pdata_buf[TCP_MSG_MSG_LEN];
    char *rx_pdata;
    uint16_t rx_plen;
    uint8_t rx_vflag;
    char tx_pdata_buf[TCP_MSG_MSG_LEN];
    char *tx_pdata;
    uint16_t tx_plen;
    uint8_t tx_vflag;
};

typedef struct tcp_msg tcp_msg_t;

struct tcp_node
{
    struct tcp_pcb *pcb_obj;
    struct ip_addr local_addr;
    uint16_t local_port;
    struct ip_addr target_addr;
    uint16_t remote_port;
    uint8_t connected_flag;
    struct tcp_msg *msg;
    uint32_t connected_count;
};

typedef struct tcp_node tcp_node_t;

#ifdef USING_ETHERNET0
struct netif server_netif0;
/* definition TCP node */
tcp_node_t g_tcp0_node;
/* definition TCP message node*/
tcp_msg_t g_tcp0_msg;
#endif

#ifdef USING_ETHERNET1
struct netif server_netif1;
/* definition TCP node */
tcp_node_t g_tcp1_node;
/* definition TCP message node*/
tcp_msg_t g_tcp1_msg;
#endif

err_t tcp_transfer_data(struct tcp_pcb *tpcb, const uint8_t *pData, int plen);
err_t tcp_send(tcp_node_t *tcp_node, tcp_msg_t *tcp_msg);
void tcp_node_printf(char *tcp_node_name, tcp_node_t *tcp_node);
int lwip_tcp_init(void);

#endif
#endif
  • tcp_cmd.c 实现了 tcp 的功能调用等。

  • tcp_cmd.c

/**
 * Copyright (c) 2022-2023,HelloAlpha
 * 
 * Change Logs:
 * Date           Author       Notes
 */
#include "tcp_config.h"
#ifdef USING_ETHERNET_TCP

#include "netif/xadapter.h"

#define USING_ULOG
#include "ulog.h"

/* defined by each RAW mode application */
void tcp_fasttmr(void);
void tcp_slowtmr(void);

#ifdef USING_TCP_STATUS
    int tcp_check_connect_status(void);
#endif

#ifdef USING_TCP_PRINT_MSG
void tcp_print_msg(void)
{
#ifdef USING_ETHERNET0
    static tcp_msg_t *tcp0_msg = &g_tcp0_msg;

    if(tcp0_msg->rx_vflag == 1)
    {
        kprintf("> Eth0 Rec: \r\n");
        kprintf("> Data: %s\r\n", tcp0_msg->rx_pdata);
        kprintf("> Size: %d\r\n", tcp0_msg->rx_plen);
        tcp0_msg->rx_vflag = 0;
    }
#endif

#ifdef USING_ETHERNET1
    static tcp_msg_t *tcp1_msg = &g_tcp1_msg;

    if(tcp1_msg->rx_vflag == 1)
    {
        kprintf("> Eth1 Rec: \r\n");
        kprintf("> Data: %s\r\n", tcp1_msg->rx_pdata);
        kprintf("> Size: %d\r\n", tcp1_msg->rx_plen);
        tcp1_msg->rx_vflag = 0;
    }
#endif
}
#endif

#ifdef USING_TCP_TEST_CMD
int tcp_test_cmd(void)
{
    static uint16_t count = 0;
    static char tcp_buff[32];

    count++;
    sprintf(tcp_buff, "Hello! TCP Count: %d \r\n", count);
    kprintf("size: %d  data: %s", strlen(tcp_buff), tcp_buff);

#ifdef USING_ETHERNET0
    static tcp_node_t *tcp0_node = &g_tcp0_node;
    static tcp_msg_t *tcp0_msg = &g_tcp0_msg;
    if(tcp0_msg->tx_vflag == 0)
    {
        tcp0_msg->tx_pdata = tcp_buff;
        tcp0_msg->tx_plen = strlen(tcp_buff);
        tcp0_msg->tx_vflag = 1;
        kprintf("TCP0 tcp_send: %d \r\n", tcp_send(tcp0_node, tcp0_msg));
    }
#endif

#ifdef USING_ETHERNET1
    static tcp_node_t *tcp1_node = &g_tcp1_node;
    static tcp_msg_t *tcp1_msg = &g_tcp1_msg;
    if(tcp1_msg->tx_vflag == 0)
    {
        tcp1_msg->tx_pdata = tcp_buff;
        tcp1_msg->tx_plen = strlen(tcp_buff);
        tcp1_msg->tx_vflag = 1;
        kprintf("TCP1 tcp_send: %d \r\n", tcp_send(tcp1_node, tcp1_msg));
    }
#endif

    return 0;
}
#endif

int tcp_func_per_250ms(void)
{
    tcp_fasttmr();
    return 0;
}

int tcp_func_per_500ms(void)
{
    tcp_slowtmr();
    return 0;
}

int tcp_func_per_1s(void)
{
#ifdef USING_TCP_STATUS
    tcp_check_connect_status();
#endif

#ifdef USING_TCP_TEST_CMD
    tcp_test_cmd();
#endif
    return 0;
}

int tcp_func_always(void)
{
    /* receive and process packets */
#ifdef USING_ETHERNET0
    static struct netif *echo_netif0 = &server_netif0;
    xemacif_input(echo_netif0);
#endif

#ifdef USING_ETHERNET1
    static struct netif *echo_netif1 = &server_netif1;
    xemacif_input(echo_netif1);
#endif

#ifdef USING_TCP_PRINT_MSG
    tcp_print_msg();
#endif

    return 0;
}

#endif

功能验证

  • 创建网卡

在这里插入图片描述

  • ping 指令测试

在这里插入图片描述

  • 回环测试

tcp_config.h 中定义使用 tcp 回环测试

在这里插入图片描述

使用网络调试助手连接网络

在这里插入图片描述

进行回环测试

在这里插入图片描述

源码获取

相关代码也可以从此处获取 GitHub。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/126286.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Elastic Observability 8.11:ES|QL、APM 中的通用分析和增强的 SLOs

作者&#xff1a;Tom Grabowski, Katrin Freihofner, Israel Ogbole Elastic Observability 8.11 引入了 ES|QL for Observability&#xff08;技术预览版&#xff09;、Universal ProfilingTM 和 Elastic APM 集成&#xff0c;以及针对 Elastic Observability 的新 SLO &#…

GD32单片机远程升级下载,手机在线升级下载程序,GD32在线固件下载升级,手机下载程序固件方法

GD32、STM32单片机&#xff0c;是我们最常见的一种MCU。通常我们在使用STM32单片机都会遇到程序在线升级下载的问题。 GD32/STM32单片机的在线下载通常需要以下几种方式完成&#xff1a; 1、使用ST/GD提供的串口下载工具&#xff0c;本地完成固件的升级下载。 2、自行完成系统B…

Ubuntu22.04配置Go环境

Ubuntu上配置Go环境biCentOS简单多了&#xff0c;有两种方案&#xff0c;一种直接使用apt进行安装&#xff0c;一种自己从官网下载安装包进行安装。 1、使用apt直接安装 更新apt安装包&#xff0c;常规操作 apt update 然后看看apt自带的Go版本是多少 apt list golang 是1…

数据结构——二叉树(2)

接上一篇文章http://t.csdnimg.cn/nsKsW&#xff0c;本次我们接着讲解关于二叉树的相关知识。 一、二叉树的相关性质&#xff1a; 1. 若规定根节点的层数为 1 &#xff0c;则一棵非空二叉树的 第 i 层上最多有 2^(i-1) 个结点. 2. 若规定根节点的层数为 1 &#xff0c;则 深度…

【QT】QT自定义C++类

在使用Qt的ui设计时&#xff0c;Qt为我们提供了标准的类&#xff0c;但是在很多复杂工程中&#xff0c;标准的类并不能满足所有的需求&#xff0c;这时就需要我们自定义C类。 下面以自定义的QPushButton作一个很简单的例子。 先新建默认Qt Widgets Application项目 一、自定义…

LabVIEW如何才能得到共享变量的引用

LabVIEW如何才能得到共享变量的引用 有一个LabVIEW 库文件 (.lvlib) &#xff0c;其中有一些定义好的共享变量。但需要得到每个共享变量的引用以便在程序运行时访问其属性。 共享变量的属性定义在“变量”类属性节点中。为了访问变量类&#xff0c;共享变量的引用必须连接到变…

Leetcode543. 二叉树的直径

Every day a Leetcode 题目来源&#xff1a;543. 二叉树的直径 解法1&#xff1a;深度优先搜索 首先我们知道一条路径的长度为该路径经过的节点数减 1&#xff0c;所以求直径&#xff08;即求路径长度的最大值&#xff09;等效于求路径经过节点数的最大值减 1。 而任意一条…

linux系统,确认账户密码正确

linux系统&#xff0c;确认账户密码正确 1、问题背景2、解决方法 1、问题背景 有时在linux系统安装软件时&#xff0c;有的软件可能会在安装过程中创建系统用户&#xff0c;同时会给出这个用户的密码。过了一段时间我们不确定这个密码是否还正确&#xff0c;那怎么确认这个密码…

Effective C++ 系列和 C++ Core Guidelines 如何选择?

Effective C 系列和 C Core Guidelines 如何选择&#xff1f; 如果一定要二选一&#xff0c;我会选择C Core Guidelines。因为它是开源的&#xff0c;有300多个贡献者&#xff0c;而且还在不断更新&#xff0c;意味着它归纳总结了最新的C实践经验。最近很多小伙伴找我&#xff…

(自适应移动端)响应式门窗定制pbootcms板 门窗门业网站板下载-带视频功能

(自适应移动端)响应式门窗定制pbootcms模板 门窗门业网站模板下载-带视频功能 PbootCMS内核开发的网站模板&#xff0c;该模板适用于门窗门业网站等企业&#xff0c;当然其他行业也可以做&#xff0c;只需要把文字图片换成其他行业的即可&#xff1b; 自适应移动端&#xff0c;…

【ubuntu】ubuntu系统查看服务命令

查看正在运行的服务 sudo service --status-all [] 代表服务是在启动运行的状态 [-] 代表服务是在关闭停止的状态

记录第一次银行测试岗面试【总结几点面试不要犯得错误】

LZ在一个18线小城市做测试&#xff0c;近来想走出自己的舒适区&#xff0c;去做一点不一样的测试工作。 18线地区&#xff0c;测试工作并不多。最好的差不多就是LZ目前待着的公司了。遂决定去魔都闯荡几年&#xff0c;对一个在魔都无房无车无户口的人来讲&#xff0c;这意味着…

LeetCode【30. 串联所有单词的子串】

给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度相同。 s 中的 串联子串 是指一个包含 words 中所有字符串以任意顺序排列连接起来的子串。 例如&#xff0c;如果 words ["ab","cd","ef"]&#xff0c; 那么 "abcdef&…

【hcie-cloud】【3】华为云Stack规划设计之华为云Stack交付综述【上】

文章目录 前言华为云Stack交付综述交付流程华为云Stack交付流程华为云Stack安装部署流程 交付工具链华为云Stack交付工具链eDesigner - 让解决方案销售更智能eDesigner配置页面 - 基本信息eDesigner配置页面 - 服务及组网配置eDesigner配置页面 - 弹性云服务器/ECSeDesigner配置…

C4D移动坐标轴位置的技巧

我们所创建的模型&#xff0c;刚创建的时候中心的位置就是中心坐标的位置了&#xff0c;如图所示 我们可以选择一个视图模式更好的观察效果 文章源自四五设计网-https://www.45te.com/35303.html 然后将模型给C掉 这样模型变成了可以编辑的模式后&#xff0c;选择左侧的坐标选…

把自己本地项目发布到Gitee

目录 1.准备工作 ​2.gitee创建仓库 3.本地上传代码 4.验证​ 1.准备工作 本地安装了git&#xff0c;公钥私钥都配置好了 2.gitee创建仓库 创建仓库&#xff0c;没有仓库放不了代码 只需要选择分支类型&#xff0c;和带星号的 进入下一页 点这个 3.本地上传代码 新建一…

开设自己的网站系类03安装数据库(centos版)

编者买了一个服务器打算自己构建一个网站&#xff0c;用于记录生活。网站大概算是一个个人博客吧。记录创建过程的一些步骤。 前面已经讲过配置服务器的程序运行环境 网站运行还需要数据库&#xff0c;本篇文章则是安装数据库的内容。 卸载mariadb 查看是否有安装 mariadb&…

ChatGPT是什么?黑客试图淹没其服务

上线2个月&#xff0c;月活跃用户破亿&#xff0c;媒体人用它编辑文案&#xff0c;学生用它写作业&#xff0c;程序员用它编辑代码&#xff0c; 它是谁呢&#xff1f; 它就是火爆全网&#xff08;chatgpt&#xff09;,chatgpt是什么呢&#xff0c;chatgpt是美国研发的一款人工…

自动计算零售数据分析指标?BI软件表示可行

随着BI技术的飞速发展&#xff0c;借助系统来计算分析指标也不是什么难事&#xff0c;即便是面对组合多变的零售数据分析指标&#xff0c;奥威BI软件也依旧可以又快又精准地完成指标计算。 BI软件可以自动计算零售数据分析指标&#xff0c;如销售额、库存量、订单量等。在计算…

开设自己的网站系类01购买服务器

开始建设自己的网站吧&#xff01; 编者买了一个服务器打算自己构建一个网站&#xff0c;用于记录生活。网站大概算是一个个人博客吧。记录创建过程的一些步骤 要开设自己的网站&#xff0c;需要执行以下关键步骤 以下只是初步列出了建立自己的网站的大概步骤&#xff0c;后…