在前面的4.4 章节与6.8 章节中已经讲解了关于底层驱动的函数,这些函数在网卡中至关重要,而ethernetif.c文件就是存放这些函数的,LwIP的contrib包中就包含这个文件的模板,我们直接拿过来修改即可,该文件的路径为“contrib-2.1.0\\examples\\ethernetif”,然后我们拷贝到arch文件夹下,并且创建一个ethernetif.h文件,一同添加到我们的工程中即可。我们直接使用4.4 章节与6.8 章节编写的网卡驱动代码,在编写完成的ethernetif.c文件内容具体见代码清单 7‑4:
```
1 #include "main.h"
2 #include "lwip/opt.h"
3 #include "lwip/mem.h"
4 #include "lwip/memp.h"
5 #include "lwip/timeouts.h"
6 #include "netif/ethernet.h"
7 #include "netif/etharp.h"
8 #include "lwip/ethip6.h"
9 #include "ethernetif.h"
10 #include <string.h>
11
12
13 /* Network interface name */
14 #define IFNAME0 's'
15 #define IFNAME1 't'
16
17
18 struct ethernetif
19 {
20 struct eth_addr *ethaddr;
21 /* Add whatever per-interface state that is needed here. */
22 };
23
24
25 extern ETH_HandleTypeDef heth;
26
27 static void arp_timer(void *arg);
28
29
30 static void low_level_init(struct netif *netif)
31 {
32 HAL_StatusTypeDef hal_eth_init_status;
33
34 //初始化bsp—eth
35 hal_eth_init_status = Bsp_Eth_Init();
36
37 if (hal_eth_init_status == HAL_OK)
38 {
39 /* Set netif link flag */
40 netif->flags |= NETIF_FLAG_LINK_UP;
41 }
42
43 #if LWIP_ARP || LWIP_ETHERNET
44
45 /* set MAC hardware address length */
46 netif->hwaddr_len = ETH_HWADDR_LEN;
47
48 /* set MAC hardware address */
49 netif->hwaddr[0] = heth.Init.MACAddr[0];
50 netif->hwaddr[1] = heth.Init.MACAddr[1];
51 netif->hwaddr[2] = heth.Init.MACAddr[2];
52 netif->hwaddr[3] = heth.Init.MACAddr[3];
53 netif->hwaddr[4] = heth.Init.MACAddr[4];
54 netif->hwaddr[5] = heth.Init.MACAddr[5];
55
56 /* maximum transfer unit */
57 netif->mtu = NETIF_MTU;
58
59 #if LWIP_ARP
60 netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
61 #else
62 netif->flags |= NETIF_FLAG_BROADCAST;
63 #endif /* LWIP_ARP */
64
65 #endif /* LWIP_ARP || LWIP_ETHERNET */
66
67 HAL_ETH_Start(&heth);
68 }
69
70
71 static err_t low_level_output(struct netif *netif, struct pbuf *p)
72 {
73
74 err_t errval;
75 struct pbuf *q;
76
77 uint8_t *buffer = (uint8_t *)(heth.TxDesc->Buffer1Addr);
78
79 __IO ETH_DMADescTypeDef *DmaTxDesc;
80
81 uint32_t bufferoffset = 0;
82 uint32_t framelength = 0;
83
84 uint32_t byteslefttocopy = 0;
85
86 uint32_t payloadoffset = 0;
87
88 DmaTxDesc = heth.TxDesc;
89 bufferoffset = 0;
90
91 if ((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET)
92 {
93 errval = ERR_USE;
94 goto error;
95 }
96
97
98 /* copy frame from pbufs to driver buffers */
99 for (q = p; q != NULL; q = q->next)
100 {
101 /* Get bytes in current lwIP buffer */
102 byteslefttocopy = q->len;
103 payloadoffset = 0;
104
105 /*Check if the length of data to copy is bigger than Tx buffer size*/
106 while ( (byteslefttocopy + bufferoffset) > ETH_TX_BUF_SIZE )
107 {
108 /* Copy data to Tx buffer*/
109 memcpy( (uint8_t*)((uint8_t*)buffer + bufferoffset),
110 (uint8_t*)((uint8_t*)q->payload + payloadoffset),
111 (ETH_TX_BUF_SIZE - bufferoffset) );
112
113 /* Point to next descriptor */
114 DmaTxDesc = (ETH_DMADescTypeDef *)(DmaTxDesc->Buffer2NextDescAddr);
115
116 /* Check if the buffer is available */
117 if ((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET)
118 {
119 errval = ERR_USE;
120 goto error;
121 }
122
123 buffer = (uint8_t *)(DmaTxDesc->Buffer1Addr);
124
125 byteslefttocopy = byteslefttocopy - (ETH_TX_BUF_SIZE - bufferoffset);
126 payloadoffset = payloadoffset + (ETH_TX_BUF_SIZE - bufferoffset);
127 framelength = framelength + (ETH_TX_BUF_SIZE - bufferoffset);
128 bufferoffset = 0;
129 }
130
131 /* Copy the remaining bytes */
132 memcpy( (uint8_t*)((uint8_t*)buffer + bufferoffset),
133 (uint8_t*)((uint8_t*)q->payload + payloadoffset), byteslefttocopy );
134 bufferoffset = bufferoffset + byteslefttocopy;
135 framelength = framelength + byteslefttocopy;
136 }
137
138 /* Prepare transmit descriptors to give to DMA */
139 HAL_ETH_TransmitFrame(&heth, framelength);
140
141 errval = ERR_OK;
142
143 error:
144
145 if ((heth.Instance->DMASR & ETH_DMASR_TUS) != (uint32_t)RESET)
146 {
147 /* Clear TUS ETHERNET DMA flag */
148 heth.Instance->DMASR = ETH_DMASR_TUS;
149
150 /* Resume DMA transmission*/
151 heth.Instance->DMATPDR = 0;
152 }
153
154
155
156 return errval;
157 }
158
159
160 static struct pbuf * low_level_input(struct netif *netif)
161 {
162 struct pbuf *p = NULL;
163 struct pbuf *q = NULL;
164 uint16_t len = 0;
165 uint8_t *buffer;
166 __IO ETH_DMADescTypeDef *dmarxdesc;
167 uint32_t bufferoffset = 0;
168 uint32_t payloadoffset = 0;
169 uint32_t byteslefttocopy = 0;
170 uint32_t i=0;
171
172
173 /* get received frame */
174 if (HAL_ETH_GetReceivedFrame(&heth) != HAL_OK)
175 {
176 PRINT_ERR("receive frame faild\n");
177 return NULL;
178 }
179 /*Obtain the size of the packet and put it into the "len" variable.*/
180 len = heth.RxFrameInfos.length;
181 buffer = (uint8_t *)heth.RxFrameInfos.buffer;
182
183 PRINT_INFO("receive frame len : %d\n", len);
184
185 if (len > 0)
186 {
187 /* We allocate a pbuf chain of pbufs from the Lwip buffer pool */
188 p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
189 }
190
191 if (p != NULL)
192 {
193 dmarxdesc = heth.RxFrameInfos.FSRxDesc;
194 bufferoffset = 0;
195 for (q = p; q != NULL; q = q->next)
196 {
197 byteslefttocopy = q->len;
198 payloadoffset = 0;
199
200
201 while ( (byteslefttocopy + bufferoffset) > ETH_RX_BUF_SIZE )
202 {
203 /* Copy data to pbuf */
204 memcpy( (uint8_t*)((uint8_t*)q->payload + payloadoffset),
205 (uint8_t*)((uint8_t*)buffer + bufferoffset),
206 (ETH_RX_BUF_SIZE - bufferoffset));
207
208 /* Point to next descriptor */
209 dmarxdesc = (ETH_DMADescTypeDef *)(dmarxdesc->Buffer2NextDescAddr);
210 buffer = (uint8_t *)(dmarxdesc->Buffer1Addr);
211
212 byteslefttocopy = byteslefttocopy - (ETH_RX_BUF_SIZE - bufferoffset);
213 payloadoffset = payloadoffset + (ETH_RX_BUF_SIZE - bufferoffset);
214 bufferoffset = 0;
215 }
216 /* Copy remaining data in pbuf */
217 memcpy( (uint8_t*)((uint8_t*)q->payload + payloadoffset),
218 (uint8_t*)((uint8_t*)buffer + bufferoffset), byteslefttocopy);
219 bufferoffset = bufferoffset + byteslefttocopy;
220 }
221 }
222
223 /* Release descriptors to DMA */
224 /* Point to first descriptor */
225 dmarxdesc = heth.RxFrameInfos.FSRxDesc;
226 /* Set Own bit in Rx descriptors: gives the buffers back to DMA */
227 for (i=0; i< heth.RxFrameInfos.SegCount; i++)
228 {
229 dmarxdesc->Status |= ETH_DMARXDESC_OWN;
230 dmarxdesc = (ETH_DMADescTypeDef *)(dmarxdesc->Buffer2NextDescAddr);
231 }
232
233 /* Clear Segment_Count */
234 heth.RxFrameInfos.SegCount =0;
235
236 /* When Rx Buffer unavailable flag is set: clear it and resume reception */
237 if ((heth.Instance->DMASR & ETH_DMASR_RBUS) != (uint32_t)RESET)
238 {
239 /* Clear RBUS ETHERNET DMA flag */
240 heth.Instance->DMASR = ETH_DMASR_RBUS;
241 /* Resume DMA reception */
242 heth.Instance->DMARPDR = 0;
243 }
244 return p;
245 }
246
247
248 void ethernetif_input(struct netif *netif)
249 {
250 err_t err;
251 struct pbuf *p;
252
253 /* move received packet into a new pbuf */
254 p = low_level_input(netif);
255
256 /* no packet could be read, silently ignore this */
257 if (p == NULL) return;
258
259 /* entry point to the LwIP stack */
260 err = netif->input(p, netif);
261
262 if (err != ERR_OK)
263 {
264 LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
265 pbuf_free(p);
266 p = NULL;
267 }
268 }
269
270
271 #if !LWIP_ARP
272
273 static err_t low_level_output_arp_off(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr)
274 {
275 err_t errval;
276 errval = ERR_OK;
277
278 return errval;
279
280 }
281 #endif /* LWIP_ARP */
282
283 err_t ethernetif_init(struct netif *netif)
284 {
285 struct ethernetif *ethernetif;
286
287 // LWIP_ASSERT("netif != NULL", (netif != NULL));
288
289 ethernetif = mem_malloc(sizeof(struct ethernetif));
290
291 if (ethernetif == NULL)
292 {
293 PRINT_ERR("ethernetif_init: out of memory\n");
294 return ERR_MEM;
295 }
296
297 LWIP_ASSERT("netif != NULL", (netif != NULL));
298 //
299 #if LWIP_NETIF_HOSTNAME
300 /* Initialize interface hostname */
301 netif->hostname = "lwip";
302 #endif /* LWIP_NETIF_HOSTNAME */
303 netif->state = ethernetif;
304 netif->name[0] = IFNAME0;
305 netif->name[1] = IFNAME1;
306
307 #if LWIP_IPV4
308 #if LWIP_ARP || LWIP_ETHERNET
309 #if LWIP_ARP
310 netif->output = etharp_output;
311 #else
312 netif->output = low_level_output_arp_off;
313 #endif /* LWIP_ARP */
314 #endif /* LWIP_ARP || LWIP_ETHERNET */
315 #endif /* LWIP_IPV4 */
316
317 #if LWIP_IPV6
318 netif->output_ip6 = ethip6_output;
319 #endif /* LWIP_IPV6 */
320
321 netif->linkoutput = low_level_output;
322
323 /* initialize the hardware */
324 low_level_init(netif);
325 ethernetif->ethaddr = (struct eth_addr *) &(netif->hwaddr[0]);
326
327 return ERR_OK;
328 }
329
330 static void arp_timer(void *arg)
331 {
332 etharp_tmr();
333 sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
334 }
335
336 /* USER CODE BEGIN 6 */
337
338
339 void ethernetif_update_config(struct netif *netif)
340 {
341 __IO uint32_t tickstart = 0;
342 uint32_t regvalue = 0;
343
344 if (netif_is_link_up(netif))
345 {
346 /* Restart the auto-negotiation */
347 if (heth.Init.AutoNegotiation != ETH_AUTONEGOTIATION_DISABLE)
348 {
349 /* Enable Auto-Negotiation */
350 HAL_ETH_WritePHYRegister(&heth, PHY_BCR, PHY_AUTONEGOTIATION);
351
352 /* Get tick */
353 tickstart = HAL_GetTick();
354
355 /* Wait until the auto-negotiation will be completed */
356 do
357 {
358 HAL_ETH_ReadPHYRegister(&heth, PHY_BSR, ®value);
359
360 /* Check for the Timeout ( 1s ) */
361 if ((HAL_GetTick() - tickstart ) > 1000)
362 {
363 /* In case of timeout */
364 goto error;
365 }
366 }
367 while (((regvalue & PHY_AUTONEGO_COMPLETE) != PHY_AUTONEGO_COMPLETE));
368
369 /* Read the result of the auto-negotiation */
370 HAL_ETH_ReadPHYRegister(&heth, PHY_SR, ®value);
371
372
373 if ((regvalue & PHY_DUPLEX_STATUS) != (uint32_t)RESET)
374 {
375
376 heth.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
377 }
378 else
379 {
380
381 heth.Init.DuplexMode = ETH_MODE_HALFDUPLEX;
382 }
383
384 if (regvalue & PHY_SPEED_STATUS)
385 {
386 /* Set Ethernet speed to 10M following the auto-negotiation */
387 heth.Init.Speed = ETH_SPEED_10M;
388 }
389 else
390 {
391 /* Set Ethernet speed to 100M following the auto-negotiation */
392 heth.Init.Speed = ETH_SPEED_100M;
393 }
394 }
395 else /* AutoNegotiation Disable */
396 {
397 error :
398 /* Check parameters */
399 assert_param(IS_ETH_SPEED(heth.Init.Speed));
400 assert_param(IS_ETH_DUPLEX_MODE(heth.Init.DuplexMode));
401
402 /* Set MAC Speed and Duplex Mode to PHY */
403 HAL_ETH_WritePHYRegister(&heth, PHY_BCR,
404 ((uint16_t)(heth.Init.DuplexMode >> 3) |
405 (uint16_t)(heth.Init.Speed >> 1)));
406 }
407
408 /* ETHERNET MAC Re-Configuration */
409 HAL_ETH_ConfigMAC(&heth, (ETH_MACInitTypeDef *) NULL);
410
411 /* Restart MAC interface */
412 HAL_ETH_Start(&heth);
413 }
414 else
415 {
416 /* Stop MAC interface */
417 HAL_ETH_Stop(&heth);
418 }
419
420 ethernetif_notify_conn_changed(netif);
421 }
```
当然,我们还需要一个ethernetif.h文件,主要是对函数的一些声明,其内容具体见代码清单 7‑5。
```
1 #ifndef __ETHERNETIF_H__
2 #define __ETHERNETIF_H__
3
4 #include "lwip/err.h"
5 #include "lwip/netif.h"
6
7 err_t ethernetif_init(struct netif *netif);
8
9 void ethernetif_input(struct netif *netif);
10 void ethernetif_update_config(struct netif *netif);
11 void ethernetif_notify_conn_changed(struct netif *netif);
12
13 #endif
```
- 说明
- 第1章:网络协议简介
- 1.1:常用网络协议
- 1.2:网络协议的分层模型
- 1.3:协议层报文间的封装与拆封
- 第2章:LwIP简介
- 2.1:LwIP的优缺点
- 2.2:LwIP的文件说明
- 2.2.1:如何获取LwIP源码文件
- 2.2.2:LwIP文件说明
- 2.3:查看LwIP的说明文档
- 2.4:使用vscode查看源码
- 2.4.1:查看文件中的符号列表(函数列表)
- 2.4.2:函数定义跳转
- 2.5:LwIP源码里的example
- 2.6:LwIP的三种编程接口
- 2.6.1:RAW/Callback API
- 2.6.2:NETCONN API
- 2.6.3:SOCKET API
- 第3章:开发平台介绍
- 3.1:以太网简介
- 3.1.1:PHY层
- 3.1.2:MAC子层
- 3.2:STM32的ETH外设
- 3.3:MII 和 RMII 接口
- 3.4:PHY:LAN8720A
- 3.5:硬件设计
- 3.6:软件设计
- 3.6.1:获取STM32的裸机工程模板
- 3.6.2:添加bsp_eth.c与bsp_eth.h
- 3.6.3:修改stm32f4xx_hal_conf.h文件
- 第4章:LwIP的网络接口管理
- 4.1:netif结构体
- 4.2:netif使用
- 4.3:与netif相关的底层函数
- 4.4:ethernetif.c文件内容
- 4.4.1:ethernetif数据结构
- 4.4.2:ethernetif_init()
- 4.4.3:low_level_init()
- 第5章:LwIP的内存管理
- 5.1:几种内存分配策略
- 5.1.1:固定大小的内存块
- 5.1.2:可变长度分配
- 5.2:动态内存池(POOL)
- 5.2.1:内存池的预处理
- 5.2.2:内存池的初始化
- 5.2.3:内存分配
- 5.2.4:内存释放
- 5.3:动态内存堆
- 5.3.1:内存堆的组织结构
- 5.3.2:内存堆初始化
- 5.3.3:内存分配
- 5.3.4:内存释放
- 5.4:使用C库的malloc和free来管理内存
- 5.5:LwIP中的配置
- 第6章:网络数据包
- 6.1:TCP/IP协议的分层思想
- 6.2:LwIP的线程模型
- 6.3:pbuf结构体说明
- 6.4:pbuf的类型
- 6.4.1:PBUF_RAM类型的pbuf
- 6.4.2:PBUF_POOL类型的pbuf
- 6.4.3:PBUF_ROM和PBUF_REF类型pbuf
- 6.5:pbuf_alloc()
- 6.6:pbuf_free()
- 6.7:其它pbuf操作函数
- 6.7.1:pbuf_realloc()
- 6.7.2:pbuf_header()
- 6.7.3:pbuf_take()
- 6.8:网卡中使用的pbuf
- 6.8.1:low_level_output()
- 6.8.2:low_level_input()
- 6.8.3:ethernetif_input()
- 第7章:无操作系统移植LwIP
- 7.1:将LwIP添加到裸机工程
- 7.2:移植头文件
- 7.3:移植网卡驱动
- 7.4:LwIP时基
- 7.5:协议栈初始化
- 7.6:获取数据包
- 7.6.1:查询方式
- 7.6.2:ping命令详解
- 7.6.3:中断方式
- 第8章:有操作系统移植LwIP
- 8.1:LwIP中添加操作系统
- 8.1.1:拷贝FreeRTOS源码到工程文件夹
- 8.1.2:添加FreeRTOS源码到工程组文件夹
- 8.1.3:指定FreeRTOS头文件的路径
- 8.1.4:修改stm32f10x_it.c
- 8.2:lwipopts.h文件需要加入的配置
- 8.3:sys_arch.c/h文件的编写
- 8.4:网卡底层的编写
- 8.5:协议栈初始化
- 8.6:移植后使用ping测试基本响应
- 第9章:LwIP一探究竟
- 9.1:网卡接收数据的流程
- 9.2:内核超时处理
- 9.2.1:sys_timeo结构体与超时链表
- 9.2.2:注册超时事件
- 9.2.3:超时检查
- 9.3:tcpip_thread线程
- 9.4:LwIP中的消息
- 9.4.1:消息结构
- 9.4.2:数据包消息
- 9.4.3:API消息
- 9.5:揭开LwIP神秘的面纱
- 第10章:ARP协议
- 10.1:链路层概述
- 10.2:MAC地址的基本概念
- 10.3:初识ARP
- 10.4:以太网帧结构
- 10.5:IP地址映射为物理地址
- 10.6:ARP缓存表
- 10.7:ARP缓存表的超时处理
- 10.8:ARP报文
- 10.9:发送ARP请求包
- 10.10:数据包接收流程
- 10.10.1:以太网之数据包接收
- 10.10.2:ARP数据包处理
- 10.10.3:更新ARP缓存表
- 10.11:数据包发送流程
- 10.11.1:etharp_output()函数
- 10.11.2:etharp_output_to_arp_index()函数
- 10.11.3:etharp_query()函数
- 第11章:IP协议
- 11.1:IP地址.md
- 11.1.1:概述
- 11.1.2:IP地址编址
- 11.1.3:特殊IP地址