在前面的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地址