LWIP
LWIP简介
lwip,是由Adam Dunkels开发的小型开源的TCP/IP协议栈;支持TCPIP协议族的核心协议;主要包括:ARP/ICMP/TCP/UDP/IPV4/IPV6/DHCP等;最主要的特点是运行所需的RAM和ROM少(只需十几KB的RAM和四十KB的ROM就可以运行),这使LWIP协议栈适合在低端的嵌入式系统中使用.
LWIP主要特性
- ARP 协议,以太网地址解析协议;
- IP 协议,包括 IPv4 IPv4 和 IPv6 IPv6 ,支持 IP 分片与重装,支持多网络接口下数据转发;
- ICMP 协议,用于网络调试与维护;
- IGMP IGMP 协议,用于网络组管理可以实现多播数据的接收;
- UDP 协议,用户数据报;
- TCP 协议,支持 TCPTCP 拥塞控制, 拥塞控制, RTT估计,快速恢复与重传等;
- 提供三种用户编程接口方式: raw/callback APIraw/callback;
- DNS ,域名解析;
- SNMP ,简单网络管理协议
- DHCP,动态主机配置协议;
- AUTOTP,IP地址自动配置;
- PPP,点对点协议,支持PPPoE
ENC28J60
ENC28J60简介
对于stm32f103来说没有网口,通信就得靠enc28j60
ENC28J60特点
-
兼容 IEEE802.3 IEEE802.3 协议的以太网控制器 。
-
集成 MAC MAC和 10 BASE 10 BASE 10 BASE 10 BASE-T物理层 。
-
支持全双工和半模式 。
-
数据冲突时可编程自动重发 。
-
SPI 接口速度可达 接口速度可达 10Mbps 10Mbps 。
-
8K 数据接收和发送双端口 数据接收和发送双端口 RAM 。
-
提供快速数据移动的内部 DMA 控制器 控制器 。
-
可配置的接收和发送缓冲区大小 。
-
两个可编程 LED 输出 。
-
带 7个中断源的两引脚 个中断源的两引脚 。
-
TTL TTL 电平输入 。
-
提供多种封装: SOIC/SSOP/SPDIP/QFN SOIC/SSOP/SPDIP/QFN 等。
-
SPI接口,充当主控制器和ENC28J60之间的通道
-
控制寄存器,用于控制和监视ENC28J60.
-
双端口RAM缓冲器,用于接收和发送数据包。
-
判优器,当DMA、发送和接受模块发出请求时对RAM缓冲器的访问进行控制。
-
总线接口,对通过SPI接收的数据和命令进行解析。
-
MAC(Medium Access Control),实现符合IEEE802.3标准的MAC逻辑。
-
PHY(物理层)模块,对双绞线上的模拟数据进行编码和译码。
无操作系统LWIP移植
在说移植之前,先说下几个重要的函数功能和数据结构
enc28j60.c文件
主要函数及功能
主要结构体
因为LWIP可以支持的结构体,因为LWIP可以支持多个网络接口,当设备
有多个网络接口的话LWIP就会把所有的netif结构体组成链表来管理这些网络接口
netif结构体定义(netif.h)只列出了比较重要的字段
struct netif {
struct netif *next; //指向下过一个netif 结构体
ip_addr_t ip_addr; //网络接口IP 地址
ip_addr_t netmask; //子网掩码
ip_addr_t gw; //默认网关
netif_input_fn input; //IP 层接收数据函数
netif_output_fn output; //IP 层发送数据包调用
netif_linkoutput_fn linkoutput; //底层数据包发送
void *state; //设备的状态信息
u16_t mtu; //该网络接口最大允许传输的数据长度
u8_t hwaddr_len; //物理地址长度
u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; //该网络接口的物理地址
u8_t flags; //该网络接口的状态和属性
char name[2]; //该网络接口的名字
u8_t num; //该网络接口的编号
}
- input:此字段为一个函数,这个函数将网卡接收到的数据交给IP 层。
- output:此字段为一个函数,当IP 层向接口发送一个数据包时调用此函数。这个函数通常首先解析硬件地址,然后发送数据包。此字段我们一般使用etharp.c 中的etharp_output()函数。
- linkoutput:此字段为一个函数,该函数被ARP 模块调用,完成网络数据的发送。上面说的etharp_output 函数将IP 数据包封装成以太网数据帧以后就会调用linkoutput 函数将数据发送出去。
lwip__comm.c文件
__lwip_dev(lwip__commm.h)存放一些重要信息
typedef struct
{
u8 mac[6]; //MAC 地址
u8 remoteip[4]; // 远端主机 IP 地址
u8 ip[4]; u8 ip[4]; // 本机 IP 地址
u8 netmask[4];
u8 netmask[4];// 子网掩码
u8 gateway[4];// 默认网关的 IP 地址
vu8 dhcpstatus;//dhcp状态
//0, 未获取DHCP 地址 ;
//1,进入 DHCP获取状态
//2,成功获取 DHCP地址
//0XFF,获取失败
}__lwip_dev;
lwip_comm.c文件的API
- u8 lwip_comm_mem_malloc(void) //完成对mem.c和memp.c中内存堆ram_heap和内存池memp_memory的内存分配。
- void lwip_comm_mem_free(void)//释放上个函数申请的内存 mem.c 和memp.c
- void lwip_comm_default_ip_set( lwip_dev *lwipx) //设置本地默认地址和远端默认地址。网关 IP MAC 子网掩码。和DHCP状态
- u8 lwip_comm_init(void)//内核初始化,设置网卡并打开指定的网卡。,下面重点说此函数。
- void lwip_pkt_handle(void) //从网络缓冲区接受数据包并将其发送给LWIP处理
- void lwip_periodic_handle()//完成对LWIP内核的定时器处理函数的周期性调用
- void lwip_dhcp_process_handle(void)//DHCP处理函数,为设备分配IP地址,网关等信息
u8 lwip_comm_init(void)
//LWIP初始化(LWIP启动的时候使用)
//返回值:0,成功
// 1,内存错误
// 2,DM9000初始化失败
// 3,网卡添加失败.
u8 lwip_comm_init(void)
{
struct netif *Netif_Init_Flag; //调用netif_add()函数时的返回值,用于判断网络初始化是否成功
struct ip_addr ipaddr; //ip地址
struct ip_addr netmask; //子网掩码
struct ip_addr gw; //默认网关
if(lwip_comm_mem_malloc())return 1; //内存申请失败
if(ENC28J60_Init())return 2; //初始化ENC28J60
lwip_init(); //初始化LWIP内核
lwip_comm_default_ip_set(&lwipdev); //设置默认IP等信息
#if LWIP_DHCP //使用动态IP
ipaddr.addr = 0;
netmask.addr = 0;
gw.addr = 0;
#else //使用静态IP
IP4_ADDR(&ipaddr,lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]);
IP4_ADDR(&netmask,lwipdev.netmask[0],lwipdev.netmask[1] ,lwipdev.netmask[2],lwipdev.netmask[3]);
IP4_ADDR(&gw,lwipdev