简直就是体力劳动,kinetis单片机lwip裸机代码分析

kinetis单片机lwip裸机代码分析

主文件

/*
 * Copyright (c) 2016, Freescale Semiconductor, Inc.
 * Copyright 2016-2019 NXP
 * All rights reserved.
 *
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

/*******************************************************************************
 * Includes
 ******************************************************************************/
#include "lwip/opt.h"

#if LWIP_TCP

#include "tcpecho_raw.h"
#include "lwip/timeouts.h"
#include "lwip/init.h"
#include "netif/ethernet.h"
#include "enet_ethernetif.h"   //lwip的接口管理文件

#include "board.h"

#include "fsl_device_registers.h"
#include "pin_mux.h"
#include "clock_config.h"
/*******************************************************************************
 * Definitions
 ******************************************************************************/

/* IP address configuration. 配置IP地址 */
#define configIP_ADDR0 192
#define configIP_ADDR1 168
#define configIP_ADDR2 0
#define configIP_ADDR3 102

/* Netmask configuration. 配置子网掩码 */
#define configNET_MASK0 255
#define configNET_MASK1 255
#define configNET_MASK2 255
#define configNET_MASK3 0

/* Gateway address configuration. 配置网关 */
#define configGW_ADDR0 192
#define configGW_ADDR1 168
#define configGW_ADDR2 0
#define configGW_ADDR3 1

/* MAC address configuration. 配置MAC地址 */
#define configMAC_ADDR                     \
    {                                      \
        0x02, 0x12, 0x13, 0x10, 0x15, 0x11 \
    }

/* Address of PHY interface. PHY接口地址 为0x00U  */
#define EXAMPLE_PHY_ADDRESS BOARD_ENET0_PHY_ADDRESS

/* System clock name. 系统时钟 ,为单片机的系统时钟*/
#define EXAMPLE_CLOCK_NAME kCLOCK_CoreSysClk


#ifndef EXAMPLE_NETIF_INIT_FN
/*! @brief Network interface initialization function.  网络接口初始化函数,专门为kinetis编写,属于lwip*/
#define EXAMPLE_NETIF_INIT_FN ethernetif0_init
#endif /* EXAMPLE_NETIF_INIT_FN */

/*******************************************************************************
 * Prototypes
 ******************************************************************************/

/*******************************************************************************
 * Variables
 ******************************************************************************/

/*******************************************************************************
 * Code
 ******************************************************************************/

/*!
 * @brief Interrupt service for SysTick timer.每1ms计数器加1,由time_init启动
 */
void SysTick_Handler(void)
{
    time_isr();
}

/*!
 * @brief Main function.
 */
int main(void)
{
    struct netif netif;   //用于所有lwIP网络接口的通用数据结构体
    ip4_addr_t netif_ipaddr, netif_netmask, netif_gw;
#if defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0)
    mem_range_t non_dma_memory[] = NON_DMA_MEMORY_ARRAY;
#endif /* FSL_FEATURE_SOC_LPC_ENET_COUNT */
    //网口配置
    ethernetif_config_t enet_config = {
        .phyAddress = EXAMPLE_PHY_ADDRESS,
        .clockName  = EXAMPLE_CLOCK_NAME,
        .macAddress = configMAC_ADDR,
#if defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0)
        .non_dma_memory = non_dma_memory,
#endif /* FSL_FEATURE_SOC_LPC_ENET_COUNT */
    };

    SYSMPU_Type *base = SYSMPU;    //找到SYSMPU然后禁用
    BOARD_InitPins();
    BOARD_BootClockRUN();
    BOARD_InitDebugConsole();
    /* Disable SYSMPU.  禁用SYSMPU */
    base->CESR &= ~SYSMPU_CESR_VLD_MASK;

    time_init();	//定时器初始化

    IP4_ADDR(&netif_ipaddr, configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3);
    IP4_ADDR(&netif_netmask, configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3);
    IP4_ADDR(&netif_gw, configGW_ADDR0, configGW_ADDR1, configGW_ADDR2, configGW_ADDR3);

    lwip_init();    //lwip初始化

    //向内核注册一个网络接口,设置网卡相关地址,并初始化
    netif_add(&netif, &netif_ipaddr, &netif_netmask, &netif_gw, &enet_config, EXAMPLE_NETIF_INIT_FN, ethernet_input);
    //设置系统默认网络接口
    netif_set_default(&netif);
    //启用网卡
    netif_set_up(&netif);

    tcpecho_raw_init();

    PRINTF("\r\n************************************************\r\n");
    PRINTF(" TCP Echo example\r\n");
    PRINTF("************************************************\r\n");
    PRINTF(" IPv4 Address     : %u.%u.%u.%u\r\n", ((u8_t *)&netif_ipaddr)[0], ((u8_t *)&netif_ipaddr)[1],
           ((u8_t *)&netif_ipaddr)[2], ((u8_t *)&netif_ipaddr)[3]);
    PRINTF(" IPv4 Subnet mask : %u.%u.%u.%u\r\n", ((u8_t *)&netif_netmask)[0], ((u8_t *)&netif_netmask)[1],
           ((u8_t *)&netif_netmask)[2], ((u8_t *)&netif_netmask)[3]);
    PRINTF(" IPv4 Gateway     : %u.%u.%u.%u\r\n", ((u8_t *)&netif_gw)[0], ((u8_t *)&netif_gw)[1],
           ((u8_t *)&netif_gw)[2], ((u8_t *)&netif_gw)[3]);
    PRINTF("************************************************\r\n");

    while (1)
    {
        /* Poll the driver, get any outstanding frames */
        ethernetif_input(&netif);

        sys_check_timeouts(); /* Handle all system timeouts for all core protocols */
    }
}
#endif

应用层代码

/**
 * @file
 * TCP echo server example using raw API.
 *
 * Echos all bytes sent by connecting client,
 * and passively closes when client is done.
 *
 */

#include "lwip/opt.h"
#include "lwip/debug.h"
#include "lwip/stats.h"
#include "lwip/tcp.h"
#include "tcpecho_raw.h"

#if LWIP_TCP && LWIP_CALLBACK_API

static struct tcp_pcb *tcpecho_raw_pcb;

enum tcpecho_raw_states
{
	ES_NONE = 0, ES_ACCEPTED, ES_RECEIVED, ES_CLOSING
};

struct tcpecho_raw_state
{
	u8_t state;
	u8_t retries;
	struct tcp_pcb *pcb;
	/* pbuf (chain) to recycle */
	struct pbuf *p;
};

//释放内存
static void tcpecho_raw_free(struct tcpecho_raw_state *es)
{
	if (es != NULL)
	{
		if (es->p)
		{
			/* free the buffer chain if present */
			pbuf_free(es->p);
		}

		mem_free(es);
	}
}

//关闭连接
static void tcpecho_raw_close(struct tcp_pcb *tpcb,
		struct tcpecho_raw_state *es)
{
	tcp_arg(tpcb, NULL);
	tcp_sent(tpcb, NULL);
	tcp_recv(tpcb, NULL);
	tcp_err(tpcb, NULL);
	tcp_poll(tpcb, NULL, 0);

	tcpecho_raw_free(es);

	tcp_close(tpcb);
}

//发送数据处理函数
static void tcpecho_raw_send(struct tcp_pcb *tpcb, struct tcpecho_raw_state *es)
{
	struct pbuf *ptr;
	err_t wr_err = ERR_OK;

	//如果没有错误,并且发送的数据不为空,并且发送缓冲区的长度大于发送数据的长度
	while ((wr_err == ERR_OK) && (es->p != NULL)
			&& (es->p->len <= tcp_sndbuf(tpcb)))
	{
		ptr = es->p;

		/* enqueue data for transmission */
		wr_err = tcp_write(tpcb, ptr->payload, ptr->len, 1);
		if (wr_err == ERR_OK)
		{
			u16_t plen;

			plen = ptr->len;
			/* continue with next pbuf in chain (if any) */
			es->p = ptr->next;
			if (es->p != NULL)
			{
				/* new reference! */
				pbuf_ref(es->p);
			}
			/* chop first pbuf from chain */
			pbuf_free(ptr);
			/* we can read more data now */
			tcp_recved(tpcb, plen);
		}
		else if (wr_err == ERR_MEM)
		{
			/* we are low on memory, try later / harder, defer to poll */
			es->p = ptr;
		}
		else
		{
			/* other problem ?? */
		}
	}
}

static void tcpecho_raw_error(void *arg, err_t err)
{
	struct tcpecho_raw_state *es;

	LWIP_UNUSED_ARG(err);

	es = (struct tcpecho_raw_state*) arg;

	tcpecho_raw_free(es);
}

//轮询回调函数,es中有数据时发送数据,没数据时关闭连接
static err_t tcpecho_raw_poll(void *arg, struct tcp_pcb *tpcb)
{
	err_t ret_err;
	struct tcpecho_raw_state *es;

	es = (struct tcpecho_raw_state*) arg;
	if (es != NULL)
	{
		if (es->p != NULL)
		{
			/* there is a remaining pbuf (chain)  */
			tcpecho_raw_send(tpcb, es);
		}
		else
		{
			/* no remaining pbuf (chain)  */
			if (es->state == ES_CLOSING)
			{
				tcpecho_raw_close(tpcb, es);
			}
		}
		ret_err = ERR_OK;
	}
	else
	{
		/* nothing to be done */
		tcp_abort(tpcb);
		ret_err = ERR_ABRT;
	}
	return ret_err;
}

//发送回调函数
static err_t tcpecho_raw_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
	struct tcpecho_raw_state *es;

	LWIP_UNUSED_ARG(len);

	es = (struct tcpecho_raw_state*) arg;
	es->retries = 0;   //重试次数

	if (es->p != NULL)    //有要发送的数据
	{
		/* still got pbufs to send */
		//tcp_sent(tpcb, tcpecho_raw_sent);
		tcpecho_raw_send(tpcb, es);     //实际的发送函数
	}
	else     //如果没有数据,则关闭连接
	{
		/* no more pbufs to send */
		if (es->state == ES_CLOSING)
		{
			tcpecho_raw_close(tpcb, es);
		}
	}
	return ERR_OK;
}

//当收到数据时执行的回调函数,变量、连接、收到的数据、错误代码
static err_t tcpecho_raw_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p,err_t err)
{
	struct tcpecho_raw_state *es;
	err_t ret_err;

	LWIP_ASSERT("arg != NULL", arg != NULL);
	es = (struct tcpecho_raw_state*) arg;
	if (p == NULL)     //如果没有收到数据
	{
		/* remote host closed connection */
		es->state = ES_CLOSING;		//将es的状态修改为连接断开
		if (es->p == NULL)			//如果es的数据为空,则不需要发送数据,关闭连接
		{
			/* we're done sending, close it */
			tcpecho_raw_close(tpcb, es);
		}
		else		//如果有数据,则将发送数据
		{
			/* we're not done yet */
			tcpecho_raw_send(tpcb, es);
		}
		ret_err = ERR_OK;
	}
	else if (err != ERR_OK)    //如果收到了数据,但有错误时,则清空接收数据
	{
		/* cleanup, for unknown reason */
		if (p != NULL)
		{
			pbuf_free(p);
		}
		ret_err = err;
	}
	else if (es->state == ES_ACCEPTED)   //第一次收到数据会进入该函数
	{
		/* first data chunk in p->payload */
		es->state = ES_RECEIVED;
		/* store reference to incoming pbuf (chain) */
		es->p = p;
		tcpecho_raw_send(tpcb, es);
		ret_err = ERR_OK;
	}
	else if (es->state == ES_RECEIVED)
	{
		/* read some more data */
		if (es->p == NULL)     //如果es中没有数据时,则发送数据
		{
			es->p = p;
			tcpecho_raw_send(tpcb, es);
		}
		else					//如果es中有数据,则将收到的数据插入到队尾
		{
			struct pbuf *ptr;

			/* chain pbufs to the end of what we recv'ed previously  */
			ptr = es->p;
			pbuf_cat(ptr, p);
		}
		ret_err = ERR_OK;
	}
	else    //其它未知情况下,清除所有收到的数据并返回错误
	{
		/* unkown es->state, trash data  */
		tcp_recved(tpcb, p->tot_len);
		pbuf_free(p);
		ret_err = ERR_OK;
	}
	return ret_err;
}

static err_t tcpecho_raw_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
	err_t ret_err;
	struct tcpecho_raw_state *es;

	LWIP_UNUSED_ARG(arg);
	if ((err != ERR_OK) || (newpcb == NULL))
	{
		return ERR_VAL;
	}

	/* Unless this pcb should have NORMAL priority, set its priority now.
	 When running out of pcbs, low priority pcbs can be aborted to create
	 new pcbs of higher priority. */
	tcp_setprio(newpcb, TCP_PRIO_MIN);

	es = (struct tcpecho_raw_state*) mem_malloc(
			sizeof(struct tcpecho_raw_state));
	if (es != NULL)
	{
		es->state = ES_ACCEPTED;
		es->pcb = newpcb;
		es->retries = 0;
		es->p = NULL;
		/* pass newly allocated es to our callbacks */
		tcp_arg(newpcb, es);    				//指定应该传递给所有回调函数的应用程序的具体状态
		tcp_recv(newpcb, tcpecho_raw_recv);   	//指定当新的数据接收到时调用的回调函数
		tcp_err(newpcb, tcpecho_raw_error);   	//指定处理错误的回调函数
		tcp_poll(newpcb, tcpecho_raw_poll, 0);	//指定轮询的时间间隔以及轮询应用程序时应该调用的回调函数
		tcp_sent(newpcb, tcpecho_raw_sent);		//指定当远程主机成功地接收到数据后,应用程序调用的回调函数
		ret_err = ERR_OK;
	}
	else
	{
		ret_err = ERR_MEM;
	}
	return ret_err;
}

void tcpecho_raw_init(void)
{
	tcpecho_raw_pcb = tcp_new_ip_type(IPADDR_TYPE_ANY);   //新建一个连接
	if (tcpecho_raw_pcb != NULL)
	{
		err_t err;
		err = tcp_bind(tcpecho_raw_pcb, IP_ANY_TYPE, 7);	//绑定到指定端口
		if (err == ERR_OK)
		{
			tcpecho_raw_pcb = tcp_listen(tcpecho_raw_pcb);	//绑定成功后开始监听
			tcp_accept(tcpecho_raw_pcb, tcpecho_raw_accept);//当处于监听的连接与一个新来的连接连接上后, 该函数指定的回调函数将被调用。通常在tcp_listen()函数调用之后调用。
		}
		else
		{
			/* abort? output diagnostic? */
		}
	}
	else
	{
		/* abort? output diagnostic? */
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值