1.LWIP協(xié)議棧內(nèi)存管理
1.1 內(nèi)存管理需求
內(nèi)存管理需求分為兩類:
- 常用內(nèi)存管理需求:靜態(tài)分配的變量(RAM),任務(wù)堆棧,動(dòng)態(tài)存儲(chǔ)器管理malloc/free
- LWIP內(nèi)存管理需求:協(xié)議棧各層封裝的數(shù)據(jù)
1.2 內(nèi)存管理方案
LWIP內(nèi)存管理有兩種方案:堆(heap)和池(pool)
堆:堆內(nèi)存管理機(jī)制會(huì)根據(jù)需要分配的內(nèi)存大小在空閑的內(nèi)存塊中找到最佳擬合(best fit)的內(nèi)存區(qū)域
LWIP內(nèi)存堆管理API函數(shù):
//內(nèi)存堆初始化
void mem_init(void);
//內(nèi)存堆分配內(nèi)存
void *mem_malloc(mem_size_t size);
//內(nèi)存堆釋放內(nèi)存
void mem_free(void *mem);
池:池內(nèi)存管理機(jī)制將內(nèi)存分配成多個(gè)大小不一的內(nèi)存池,每個(gè)內(nèi)存池中又被分為N個(gè)相同大小的內(nèi)存塊。 程序可根據(jù)需要使用的內(nèi)存大小直接到不同的內(nèi)存池中取用即可。 池內(nèi)存管理機(jī)制分配內(nèi)存更快,效率更高
LWIP內(nèi)存池管理API函數(shù):
//內(nèi)存池初始化
void memp_init(void);
//內(nèi)存池分配
void *memp_malloc(memp_t type);
//內(nèi)存池釋放
void memp_free(memp_t type, void *mem);
1.3 網(wǎng)絡(luò)數(shù)據(jù)包管理
pbuf就是一個(gè)描述協(xié)議棧中數(shù)據(jù)包的數(shù)據(jù)結(jié)構(gòu),LWIP 中在 pbuf.c和 pubf.h實(shí)現(xiàn)了協(xié)議棧數(shù)據(jù)包管理的所有函數(shù)與數(shù)據(jù)結(jié)構(gòu)
pbuf數(shù)據(jù)結(jié)構(gòu)
pbuf結(jié)構(gòu)體
//在pbuf.h中定義
struct pbuf {
/** 指向下一個(gè)pbuf結(jié)構(gòu)體,每個(gè)pbuf存放的數(shù)據(jù)有限,若應(yīng)用有大量的數(shù)據(jù)的話
就需要多個(gè)pbuf來存放,可以將同一個(gè)數(shù)據(jù)包的pbuf連接在一起構(gòu)成一個(gè)鏈表 */
struct pbuf *next;
/** 指向該pbuf真正的數(shù)據(jù)存儲(chǔ)區(qū)的首地址。STM32F4內(nèi)部網(wǎng)絡(luò)模塊收到數(shù)據(jù),并
將數(shù)據(jù)提交給LWIP時(shí),就是將數(shù)據(jù)存儲(chǔ)在payload指定的存儲(chǔ)區(qū)中;同樣在發(fā)送數(shù)
據(jù)的時(shí)候?qū)ayload指向的存儲(chǔ)區(qū)數(shù)據(jù)轉(zhuǎn)給STM32F4的網(wǎng)絡(luò)模塊去發(fā)送 */
void *payload;
/** 在接收或發(fā)送數(shù)據(jù)的時(shí)候數(shù)據(jù)會(huì)存放在pbuf鏈表中,tot_Len表示當(dāng)前pbuf和鏈
表中后面所有pbuf的數(shù)據(jù)長(zhǎng)度,它們屬于一個(gè)數(shù)據(jù)包 */
u16_t tot_len;
/** 當(dāng)前pbuf總數(shù)據(jù)的長(zhǎng)度 */
u16_t len;
/** 當(dāng)前pbuf類型,共有四種:PBUF_RAM/PBUF_ROM/PBUF_REF/PBUF_POOL */
u8_t type;
/** 保留位 */
u8_t flags;
/** 該pbuf被引用的次數(shù),當(dāng)還有其他指針指向這個(gè)pbuf的時(shí)候ref字段就加一 */
u16_t ref;
};
pbuf類型:共有四種PBUF_RAM、PBUF_ROM、PBUF_REF、PBUF_POOL
//在pbuf.h中定義
typedef enum {
/** PBUF_RAM類型的pbuf是通過內(nèi)存堆分配來的,其payload并未指向數(shù)據(jù)區(qū)的起始
地址,而是隔了一段區(qū)域,在這個(gè)區(qū)域(offset)里通常存放TCP報(bào)文首部、IP首部
、以太網(wǎng)幀首部等等 */
PBUF_RAM,
/** PBUF_ROM的數(shù)據(jù)指針payload指向外部存儲(chǔ)區(qū),外部存儲(chǔ)區(qū)指不由TCP/IP協(xié)議
棧管理的存儲(chǔ)區(qū),它可以是應(yīng)用程序管理的存儲(chǔ)器為用戶數(shù)據(jù)分配的緩存,也可以是
ROM區(qū)域,如靜態(tài)網(wǎng)頁中的字符串常量等 */
PBUF_ROM,
/** PBUF_REF和PBUF_ROM的特性非常相似,都可以實(shí)現(xiàn)數(shù)據(jù)的零拷貝 */
PBUF_REF,
/** PBUF_POOL類型的pbuf是通過內(nèi)存池分類來的,pbuf鏈表的第一個(gè)pbuf的payload
未指向數(shù)據(jù)區(qū)的起始位置,原因通PBUF_RAM一樣,用來存放一些首部,pbuf鏈表后面
的pbuf結(jié)構(gòu)體中的payload就指向了數(shù)據(jù)區(qū)的起始位置 */
PBUF_POOL
} pbuf_type;
pbuf層:由于LWIP各層禁止數(shù)據(jù)拷貝,所以存在不同層次對(duì)數(shù)據(jù)包pbuf的alloc,前面的offest就是為不同層預(yù)留的頭部字段,下面枚舉了4種層次,分配時(shí)除了要知道大小、類型還要傳入這個(gè)層次
//在pbuf.h中定義
typedef enum {
/** 傳輸層,預(yù)留以太首部+IP首部+TCP首部 */
PBUF_TRANSPORT,
/** 網(wǎng)絡(luò)層,預(yù)留以太首部+IP首部 */
PBUF_IP,
/** 鏈路層,預(yù)留以太首部 */
PBUF_LINK,
/** 原始層,不預(yù)留空間 */
PBUF_RAW_TX,
/** Use this for input packets in a netif driver when calling netif->input()
* in the most common case - ethernet-layer netif driver. */
PBUF_RAW
} pbuf_layer;
pbuf_alloc:內(nèi)存申請(qǐng)函數(shù)
struct pbuf *pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type);
//layer 申請(qǐng)的pbuf所在的層,以此來確定offset值
//length 存放數(shù)據(jù)的大小
//type pbuf的類型
pbuf_free:數(shù)據(jù)包釋放函數(shù)
u8_t pbuf_free(struct pbuf *p);
//p 要釋放的pbuf數(shù)據(jù)包
pbuf_realloc:調(diào)整收縮pbuf的大小,在相應(yīng)pbuf(鏈表)尾部釋放一定的空間,將數(shù)據(jù)包pbuf中的數(shù)據(jù)長(zhǎng)度減少為某個(gè)長(zhǎng)度值
void pbuf_realloc(struct pbuf *p, u16_t new_len);
//p 要收縮的pbuf數(shù)據(jù)包
//new_len 新的長(zhǎng)度值
pbuf_header:調(diào)整payload指針和長(zhǎng)度字段以便為pbuf中的數(shù)據(jù)預(yù)置包頭,常用于實(shí)現(xiàn)對(duì)pbuf預(yù)留孔間的操作
u8_t pbuf_header(struct pbuf *p, s16_t header_size_increment);
//p 要操作的pbuf數(shù)據(jù)包
//header_size_increment 大于0,payload前移,數(shù)據(jù)傳遞下層;
// 小于0,表示payload后移,數(shù)據(jù)傳遞上層
pbuf_take:用于向pbuf的數(shù)據(jù)區(qū)域拷貝數(shù)據(jù)
err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len);
//buf 要填充數(shù)據(jù)的pbuf
//dataptr 應(yīng)用程序中的數(shù)據(jù)緩沖區(qū)
//len 數(shù)據(jù)緩沖區(qū)的長(zhǎng)度
2.LWIP網(wǎng)卡設(shè)計(jì)與實(shí)現(xiàn)
2.1 LWIP網(wǎng)絡(luò)接口管理
在LWIP中對(duì)于網(wǎng)絡(luò)接口的描述是通過一個(gè)netif結(jié)構(gòu)體完成的,netif結(jié)構(gòu)體在netif.h文件中有定義
netif結(jié)構(gòu)體
//在netif.h中定義
struct netif {
struct netif *next; //指向下一個(gè)netif結(jié)構(gòu)體
#if LWIP_IPV4
ip_addr_t ip_addr; //ip地址
ip_addr_t netmask; //子網(wǎng)掩碼
ip_addr_t gw; //網(wǎng)關(guān)地址
#endif /* LWIP_IPV4 */
netif_input_fn input; //netif數(shù)據(jù)包輸入接口函數(shù)指針
#if LWIP_IPV4
netif_output_fn output;//netif數(shù)據(jù)包輸出接口函數(shù)指針
#endif /* LWIP_IPV4 */
netif_linkoutput_fn linkoutput;//鏈路層數(shù)據(jù)輸出接口函數(shù)指針
#if LWIP_NETIF_STATUS_CALLBACK
//當(dāng)netif狀態(tài)發(fā)生變化時(shí),此接口函數(shù)會(huì)調(diào)用
netif_status_callback_fn status_callback;
#endif /* LWIP_NETIF_STATUS_CALLBACK */
#if LWIP_NETIF_LINK_CALLBACK
/* PHY必須和交換機(jī)或者路由器或者其他具備網(wǎng)卡的主機(jī)相連接,
我們才可能正常通信比如路由器突然斷電,這個(gè)函數(shù)就會(huì)被調(diào)用 */
netif_status_callback_fn link_callback;
#endif /* LWIP_NETIF_LINK_CALLBACK */
#if LWIP_NETIF_REMOVE_CALLBACK
//netif移除網(wǎng)絡(luò)驅(qū)動(dòng)接口,這個(gè)函數(shù)會(huì)被調(diào)用
netif_status_callback_fn remove_callback;
#endif /* LWIP_NETIF_REMOVE_CALLBACK */
void *state; //主機(jī)的狀態(tài)
#if LWIP_NETIF_HOSTNAME
const char* hostname; //自定義的主機(jī)名稱
#endif /* LWIP_NETIF_HOSTNAME */
#if LWIP_CHECKSUM_CTRL_PER_NETIF
u16_t chksum_flags;
#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF*/
u16_t mtu; //數(shù)據(jù)鏈路層最大傳輸大小
u8_t hwaddr_len; //mac地址長(zhǎng)度
u8_t hwaddr[NETIF_MAX_HWADDR_LEN];//mac地址
u8_t flags; //當(dāng)前的netif的狀態(tài),其實(shí)就是下面的netif_flag
char name[2]; //網(wǎng)卡驅(qū)動(dòng)的名稱
u8_t num; //網(wǎng)卡驅(qū)動(dòng)的硬件編號(hào)
#if LWIP_IPV4 && LWIP_IGMP
netif_igmp_mac_filter_fn igmp_mac_filter;//組播底層接口
#endif /* LWIP_IPV4 && LWIP_IGMP */
};
netif flag宏定義
/** netif網(wǎng)絡(luò)接口,可以進(jìn)行正常使用(即lwIP可以正常使用)了 */
#define NETIF_FLAG_UP 0x01U
/** 廣播通訊的標(biāo)志 */
#define NETIF_FLAG_BROADCAST 0x02U
/** STM32 MAC和PHY可以正常使用 */
#define NETIF_FLAG_LINK_UP 0x04U
/** ARP標(biāo)志 */
#define NETIF_FLAG_ETHARP 0x08U
/** TCP/IP協(xié)議正常通信 */
#define NETIF_FLAG_ETHERNET 0x10U
2.2 netif典型API函數(shù)
netif的API函數(shù)是供應(yīng)用層調(diào)用的函數(shù)
netif_add:添加網(wǎng)卡驅(qū)動(dòng)到lwip
struct netif *netif_add(struct netif *netif,
const ip4_addr_t *ipaddr,
const ip4_addr_t *netmask,
const ip4_addr_t *gw,
void *state,
netif_init_fn init,
netif_input_fn input);
netif_set_default:把網(wǎng)卡恢復(fù)出廠設(shè)置,目前l(fā)wip有一套默認(rèn)參數(shù)
void netif_set_default(struct netif *netif);
netif_set_up&netif_set_down:設(shè)置我們網(wǎng)卡工作狀態(tài),是上線還是離線
void netif_set_up(struct netif *netif);
void netif_set_down(struct netif *netif);
callback:需要自己實(shí)現(xiàn)link_callback函數(shù)
#if LWIP_NETIF_LINK_CALLBACK
void netif_set_link_callback(struct netif *netif,
netif_status_callback_fn link_callback);
#endif /* LWIP_NETIF_LINK_CALLBACK */
2.3 netif底層接口函數(shù)
netif底層接口即與硬件打交道的函數(shù)接口,主要包括以下函數(shù)
ethernetif_init:初始化網(wǎng)卡驅(qū)動(dòng)(會(huì)調(diào)用底層驅(qū)動(dòng))
err_t ethernetif_init(struct netif *netif){
#if LWIP_IPV4
#if LWIP_ARP || LWIP_ETHERNET
//arp相關(guān)的函數(shù)接口賦值
#if LWIP_ARP
netif->output = etharp_output;
#else
netif->output = low_level_output_arp_off;
#endif /* LWIP_ARP */
#endif /* LWIP_ARP || LWIP_ETHERNET */
#endif /* LWIP_IPV4 */
//鏈路層數(shù)據(jù)輸出函數(shù)接口賦值
netif->linkoutput = low_level_output;
/* 底層接口初始化 */
low_level_init(netif);
return ERR_OK;
}
ethernetif_input:網(wǎng)卡數(shù)據(jù)輸入(會(huì)調(diào)用底層接口)
void ethernetif_input(void const * argument){
struct pbuf *p;
struct netif *netif = (struct netif *) argument;
for( ;; )
{
if (osSemaphoreWait(s_xSemaphore, TIME_WAITING_FOR_INPUT) == osOK)
{
do
{
p = low_level_input( netif );
if (p != NULL)
{
if (netif->input( p, netif) != ERR_OK )
{
pbuf_free(p);
}
}
} while(p!=NULL);
}
}
}
low_level_init:網(wǎng)卡底層驅(qū)動(dòng),主要針對(duì)硬件(STM32網(wǎng)卡初始化會(huì)在此調(diào)用)
/** 硬件初始化,其實(shí)就STM32 ETH外設(shè)初始化 */
static void low_level_init(struct netif *netif){
uint32_t regvalue = 0;
HAL_StatusTypeDef hal_eth_init_status;
/* Init ETH */
uint8_t MACAddr[6] ;
heth.Instance = ETH;
heth.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
heth.Init.PhyAddress = DP83848_PHY_ADDRESS;
MACAddr[0] = 0x00;
MACAddr[1] = 0x80;
MACAddr[2] = 0xE1;
MACAddr[3] = 0x00;
MACAddr[4] = 0x00;
MACAddr[5] = 0x00;
heth.Init.MACAddr = &MACAddr[0];
heth.Init.RxMode = ETH_RXINTERRUPT_MODE;
heth.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
heth.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
hal_eth_init_status = HAL_ETH_Init(&heth);
if (hal_eth_init_status == HAL_OK)
{
/* 當(dāng)初始化成功后,會(huì)置位flag,同時(shí)在tcp/ip初始化完畢后,會(huì)
進(jìn)行判斷,此標(biāo)志位決定網(wǎng)卡驅(qū)動(dòng)是否 可以正常使用 */
netif->flags |= NETIF_FLAG_LINK_UP;
}
/* Initialize Tx Descriptors list: Chain Mode */
HAL_ETH_DMATxDescListInit(&heth, DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
/* Initialize Rx Descriptors list: Chain Mode */
HAL_ETH_DMARxDescListInit(&heth, DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
#if LWIP_ARP || LWIP_ETHERNET
/* MAC地址初始化 */
netif->hwaddr_len = ETH_HWADDR_LEN;
netif->hwaddr[0] = heth.Init.MACAddr[0];
netif->hwaddr[1] = heth.Init.MACAddr[1];
netif->hwaddr[2] = heth.Init.MACAddr[2];
netif->hwaddr[3] = heth.Init.MACAddr[3];
netif->hwaddr[4] = heth.Init.MACAddr[4];
netif->hwaddr[5] = heth.Init.MACAddr[5];
/* maximum transfer unit */
netif->mtu = 1500;
/* Accept broadcast address and ARP traffic */
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
#if LWIP_ARP
netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
#else
netif->flags |= NETIF_FLAG_BROADCAST;
#endif /* LWIP_ARP */
/* 二值信號(hào)量,用于信息同步,當(dāng)網(wǎng)卡接口到數(shù)據(jù)后,會(huì)釋放二值信號(hào)量讓其他任務(wù)進(jìn)行解析 */
osSemaphoreDef(SEM);
s_xSemaphore = osSemaphoreCreate(osSemaphore(SEM), 1);
/* 創(chuàng)建網(wǎng)卡數(shù)據(jù)接收解析任務(wù)-ethernetif_input */
osThreadDef(EthIf, ethernetif_input, osPriorityRealtime, 0, INTERFACE_THREAD_STACK_SIZE);
osThreadCreate (osThread(EthIf), netif);
/* 使能 網(wǎng)卡 發(fā)送和接口 */
HAL_ETH_Start(&heth);
/* 上面的都是針對(duì)STM32 ETH外設(shè)進(jìn)行初始化
但是實(shí)際網(wǎng)絡(luò)交互是用過PHY,下面就是初始化PHY */
/* Read Register Configuration */
HAL_ETH_ReadPHYRegister(&heth, PHY_MICR, ®value);
regvalue |= (PHY_MICR_INT_EN | PHY_MICR_INT_OE);
/* Enable Interrupts */
HAL_ETH_WritePHYRegister(&heth, PHY_MICR, regvalue );
/* Read Register Configuration */
HAL_ETH_ReadPHYRegister(&heth, PHY_MISR, ®value);
regvalue |= PHY_MISR_LINK_INT_EN;
/* Enable Interrupt on change of link status */
HAL_ETH_WritePHYRegister(&heth, PHY_MISR, regvalue);
#endif /* LWIP_ARP || LWIP_ETHERNET */
}
low_level_output:底層網(wǎng)卡的數(shù)據(jù)輸出,實(shí)際的數(shù)據(jù)輸出,是通過pbuf進(jìn)行封裝管理的
static err_t low_level_output(struct netif *netif, struct pbuf *p){
err_t errval;
struct pbuf *q;
uint8_t *buffer = (uint8_t *)(heth.TxDesc->Buffer1Addr);
__IO ETH_DMADescTypeDef *DmaTxDesc;
uint32_t framelength = 0;
uint32_t bufferoffset = 0;
uint32_t byteslefttocopy = 0;
uint32_t payloadoffset = 0;
DmaTxDesc = heth.TxDesc;
bufferoffset = 0;
/* copy frame from pbufs to driver buffers */
for(q = p; q != NULL; q = q->next)
{
/* Is this buffer available? If not, goto error */
if((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET)
{
errval = ERR_USE;
goto error;
}
/* Get bytes in current lwIP buffer */
byteslefttocopy = q->len;
payloadoffset = 0;
/* Check if the length of data to copy is bigger than Tx buffer size*/
while( (byteslefttocopy + bufferoffset) > ETH_TX_BUF_SIZE )
{
/* Copy data to Tx buffer*/
memcpy( (uint8_t*)((uint8_t*)buffer + bufferoffset), (uint8_t*)((uint8_t*)q->payload + payloadoffset), (ETH_TX_BUF_SIZE - bufferoffset) );
/* Point to next descriptor */
DmaTxDesc = (ETH_DMADescTypeDef *)(DmaTxDesc->Buffer2NextDescAddr);
/* Check if the buffer is available */
if((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET)
{
errval = ERR_USE;
goto error;
}
buffer = (uint8_t *)(DmaTxDesc->Buffer1Addr);
byteslefttocopy = byteslefttocopy - (ETH_TX_BUF_SIZE - bufferoffset);
payloadoffset = payloadoffset + (ETH_TX_BUF_SIZE - bufferoffset);
framelength = framelength + (ETH_TX_BUF_SIZE - bufferoffset);
bufferoffset = 0;
}
/* Copy the remaining bytes */
memcpy( (uint8_t*)((uint8_t*)buffer + bufferoffset), (uint8_t*)((uint8_t*)q->payload + payloadoffset), byteslefttocopy );
bufferoffset = bufferoffset + byteslefttocopy;
framelength = framelength + byteslefttocopy;
}
/* 把pbuf里面的數(shù)據(jù),發(fā)送到ETH外設(shè)里面 */
HAL_ETH_TransmitFrame(&heth, framelength);
errval = ERR_OK;
error:
/* When Transmit Underflow flag is set, clear it and issue a Transmit Poll Demand to resume transmission */
if ((heth.Instance->DMASR & ETH_DMASR_TUS) != (uint32_t)RESET)
{
/* Clear TUS ETHERNET DMA flag */
heth.Instance->DMASR = ETH_DMASR_TUS;
/* Resume DMA transmission*/
heth.Instance->DMATPDR = 0;
}
return errval;
}
low_level_input:底層網(wǎng)卡的數(shù)據(jù)接口,當(dāng)接收到網(wǎng)卡數(shù)據(jù)后,會(huì)通過此函數(shù),封裝為pbuf提供上層使用
static struct pbuf * low_level_input(struct netif *netif){
struct pbuf *p = NULL;
struct pbuf *q = NULL;
uint16_t len = 0;
uint8_t *buffer;
__IO ETH_DMADescTypeDef *dmarxdesc;
uint32_t bufferoffset = 0;
uint32_t payloadoffset = 0;
uint32_t byteslefttocopy = 0;
uint32_t i=0;
/* 通過HAL庫,獲取網(wǎng)卡幀數(shù)據(jù) */
if (HAL_ETH_GetReceivedFrame_IT(&heth) != HAL_OK)
return NULL;
/* 獲取網(wǎng)卡數(shù)據(jù)超度,及內(nèi)存地址 */
len = heth.RxFrameInfos.length;
buffer = (uint8_t *)heth.RxFrameInfos.buffer;
//網(wǎng)卡中數(shù)據(jù)有效
if (len > 0){
/* 網(wǎng)卡數(shù)據(jù)不能大于1500,屬于原始層接口 */
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
}
//如果pbuf創(chuàng)建成功,則從ETH中拷貝數(shù)據(jù)到pbuf里,最終把pbuf返回給上層應(yīng)用
if (p != NULL){
dmarxdesc = heth.RxFrameInfos.FSRxDesc;
bufferoffset = 0;
for(q = p; q != NULL; q = q->next){
byteslefttocopy = q->len;
payloadoffset = 0;
/* Check if the length of bytes to copy in current pbuf is bigger than Rx buffer size*/
while( (byteslefttocopy + bufferoffset) > ETH_RX_BUF_SIZE ){
/* Copy data to pbuf */
memcpy( (uint8_t*)((uint8_t*)q->payload + payloadoffset), (uint8_t*)((uint8_t*)buffer + bufferoffset), (ETH_RX_BUF_SIZE - bufferoffset));
/* Point to next descriptor */
dmarxdesc = (ETH_DMADescTypeDef *)(dmarxdesc->Buffer2NextDescAddr);
buffer = (uint8_t *)(dmarxdesc->Buffer1Addr);
byteslefttocopy = byteslefttocopy - (ETH_RX_BUF_SIZE - bufferoffset);
payloadoffset = payloadoffset + (ETH_RX_BUF_SIZE - bufferoffset);
bufferoffset = 0;
}
/* Copy remaining data in pbuf */
memcpy( (uint8_t*)((uint8_t*)q->payload + payloadoffset), (uint8_t*)((uint8_t*)buffer + bufferoffset), byteslefttocopy);
bufferoffset = bufferoffset + byteslefttocopy;
}
}
/* Release descriptors to DMA */
/* Point to first descriptor */
dmarxdesc = heth.RxFrameInfos.FSRxDesc;
/* Set Own bit in Rx descriptors: gives the buffers back to DMA */
for (i=0; i< heth.RxFrameInfos.SegCount; i++){
dmarxdesc->Status |= ETH_DMARXDESC_OWN;
dmarxdesc = (ETH_DMADescTypeDef *)(dmarxdesc->Buffer2NextDescAddr);
}
/* Clear Segment_Count */
heth.RxFrameInfos.SegCount =0;
/* When Rx Buffer unavailable flag is set: clear it and resume reception */
if ((heth.Instance->DMASR & ETH_DMASR_RBUS) != (uint32_t)RESET) {
/* Clear RBUS ETHERNET DMA flag */
heth.Instance->DMASR = ETH_DMASR_RBUS;
/* Resume DMA reception */
heth.Instance->DMARPDR = 0;
}
return p;
}
tcpip_init:工作在操作系統(tǒng)下的初始化
/**
* @工作在操作系統(tǒng)下的初始化:
* - 初始化所有的子功能模塊
* - 啟動(dòng)tcp/ip任務(wù)(tcp/ip網(wǎng)絡(luò)協(xié)議棧的實(shí)現(xiàn)是一個(gè)任務(wù)里面執(zhí)行的)
* @param 用于用戶初始化的函數(shù)指針,在lwip初始化完成,tcp/ip任務(wù)開始執(zhí)行就是進(jìn)行調(diào)用
* @param 用戶初始化相關(guān)參數(shù)傳入
*/
void tcpip_init(tcpip_init_done_fn initfunc, void *arg){
//lwip的初始化---初始化lwip所有功能模塊
lwip_init();
//用戶初始化函數(shù)指針賦值,參數(shù)賦值
tcpip_init_done = initfunc;
tcpip_init_done_arg = arg;
//消息郵箱(freeRTOS是通過消息隊(duì)列實(shí)現(xiàn)),任務(wù)與任務(wù)間消息通信,網(wǎng)卡收到數(shù)據(jù),網(wǎng)絡(luò)分層解析
if (sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) {
LWIP_ASSERT("failed to create tcpip_thread mbox", 0);
}
#if LWIP_TCPIP_CORE_LOCKING
//創(chuàng)建互斥鎖(互斥信號(hào)量),保護(hù)共享資源的
if (sys_mutex_new(&lock_tcpip_core) != ERR_OK) {
LWIP_ASSERT("failed to create lock_tcpip_core", 0);
}
#endif /* LWIP_TCPIP_CORE_LOCKING */
//這是標(biāo)準(zhǔn)的cmis接口,其實(shí)內(nèi)部調(diào)用的freeRTOS的創(chuàng)建任務(wù)接口
sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
}
lwip_init:工作在裸機(jī)模式下的初始化
/**
* @工作在裸機(jī)模式下的初始化
* Use this in NO_SYS mode. Use tcpip_init() otherwise.
*/
void lwip_init(void){
/* Modules initialization */
//狀態(tài)初始化
stats_init();
#if !NO_SYS
//與操作系統(tǒng)相關(guān)的初始化
sys_init();
#endif /* !NO_SYS */
//內(nèi)存堆 內(nèi)存池 pbuf netif初始化
mem_init();
memp_init();
pbuf_init();
netif_init();
#if LWIP_IPV4
//ip層初始化
ip_init();
#if LWIP_ARP
//arp+以太網(wǎng)相關(guān)的初始化
etharp_init();
#endif /* LWIP_ARP */
#endif /* LWIP_IPV4 */
#if LWIP_RAW
//原生接口初始化
raw_init();
#endif /* LWIP_RAW */
#if LWIP_UDP
udp_init();
#endif /* LWIP_UDP */
#if LWIP_TCP
tcp_init();
#endif /* LWIP_TCP */
#if LWIP_IGMP
igmp_init();
#endif /* LWIP_IGMP */
#if LWIP_DNS
dns_init();
#endif /* LWIP_DNS */
#if PPP_SUPPORT
ppp_init();
#endif
#if LWIP_TIMERS
//lwip內(nèi)部有很多超時(shí)機(jī)制,是通過timeouts實(shí)現(xiàn)的(一個(gè)軟件定時(shí)器)
sys_timeouts_init();
#endif /* LWIP_TIMERS */
}
MX_LWIP_Init:HAL庫實(shí)現(xiàn)的lwip初始化函數(shù)
void MX_LWIP_Init(void){
/* IP 地址初始化 */
IP_ADDRESS[0] = 192;
IP_ADDRESS[1] = 168;
IP_ADDRESS[2] = 1;
IP_ADDRESS[3] = 10;
NETMASK_ADDRESS[0] = 255;
NETMASK_ADDRESS[1] = 255;
NETMASK_ADDRESS[2] = 255;
NETMASK_ADDRESS[3] = 0;
GATEWAY_ADDRESS[0] = 192;
GATEWAY_ADDRESS[1] = 168;
GATEWAY_ADDRESS[2] = 1;
GATEWAY_ADDRESS[3] = 1;
/* 初始化lwip協(xié)議棧 */
tcpip_init( NULL, NULL );
/* 數(shù)組格式的IP地址轉(zhuǎn)換為lwip格式的地址 */
IP4_ADDR(&ipaddr, IP_ADDRESS[0], IP_ADDRESS[1], IP_ADDRESS[2], IP_ADDRESS[3]);
IP4_ADDR(&netmask, NETMASK_ADDRESS[0], NETMASK_ADDRESS[1] , NETMASK_ADDRESS[2], NETMASK_ADDRESS[3]);
IP4_ADDR(&gw, GATEWAY_ADDRESS[0], GATEWAY_ADDRESS[1], GATEWAY_ADDRESS[2], GATEWAY_ADDRESS[3]);
/* 裝載網(wǎng)卡驅(qū)動(dòng),并初始化網(wǎng)卡 */
netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, &tcpip_input);
/* gnetif注冊(cè)為默認(rèn)網(wǎng)卡驅(qū)動(dòng) */
netif_set_default(&gnetif);
// 判斷phy和mac層是否正常工作
if (netif_is_link_up(&gnetif)){
/* netif 網(wǎng)卡驅(qū)動(dòng)可以正常使用,上線 */
netif_set_up(&gnetif);
}
else{
/* netif 網(wǎng)卡驅(qū)動(dòng)下線 */
netif_set_down(&gnetif);
}
}
-
存儲(chǔ)器
+關(guān)注
關(guān)注
38文章
7455瀏覽量
163623 -
網(wǎng)卡
+關(guān)注
關(guān)注
3文章
303瀏覽量
27344 -
內(nèi)存管理
+關(guān)注
關(guān)注
0文章
168瀏覽量
14128 -
LwIP
+關(guān)注
關(guān)注
2文章
86瀏覽量
27105 -
協(xié)議棧
+關(guān)注
關(guān)注
2文章
140瀏覽量
33613
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論