色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

LWIP協議棧內存管理方案 LWIP網卡設計與實現

CHANBAEK ? 來源:嵌入式攻城獅 ? 作者: 安迪西 ? 2023-04-19 11:20 ? 次閱讀

1.LWIP協議棧內存管理

1.1 內存管理需求

內存管理需求分為兩類:

  • 常用內存管理需求:靜態分配的變量(RAM),任務堆棧,動態存儲器管理malloc/free
  • LWIP內存管理需求:協議棧各層封裝的數據

1.2 內存管理方案

LWIP內存管理有兩種方案:堆(heap)和池(pool)

堆:堆內存管理機制會根據需要分配的內存大小在空閑的內存塊中找到最佳擬合(best fit)的內存區域

圖片

LWIP內存堆管理API函數:

//內存堆初始化
void  mem_init(void);
//內存堆分配內存
void *mem_malloc(mem_size_t size);
//內存堆釋放內存
void  mem_free(void *mem);

池:池內存管理機制將內存分配成多個大小不一的內存池,每個內存池中又被分為N個相同大小的內存塊。 程序可根據需要使用的內存大小直接到不同的內存池中取用即可。 池內存管理機制分配內存更快,效率更高

圖片

LWIP內存池管理API函數:

//內存池初始化
void  memp_init(void);
//內存池分配
void *memp_malloc(memp_t type);
//內存池釋放
void  memp_free(memp_t type, void *mem);

1.3 網絡數據包管理

pbuf就是一個描述協議棧中數據包的數據結構,LWIP 中在 pbuf.c和 pubf.h實現了協議棧數據包管理的所有函數與數據結構

圖片

pbuf數據結構

pbuf結構體

//在pbuf.h中定義
struct pbuf {
  /** 指向下一個pbuf結構體,每個pbuf存放的數據有限,若應用有大量的數據的話
  就需要多個pbuf來存放,可以將同一個數據包的pbuf連接在一起構成一個鏈表  */
  struct pbuf *next;
  /** 指向該pbuf真正的數據存儲區的首地址。STM32F4內部網絡模塊收到數據,并
  將數據提交給LWIP時,就是將數據存儲在payload指定的存儲區中;同樣在發送數
  據的時候將payload指向的存儲區數據轉給STM32F4的網絡模塊去發送 */
  void *payload;
  /** 在接收或發送數據的時候數據會存放在pbuf鏈表中,tot_Len表示當前pbuf和鏈
  表中后面所有pbuf的數據長度,它們屬于一個數據包 */
  u16_t tot_len;
  /** 當前pbuf總數據的長度 */
  u16_t len;
  /** 當前pbuf類型,共有四種:PBUF_RAM/PBUF_ROM/PBUF_REF/PBUF_POOL */
  u8_t  type;
  /** 保留位 */
  u8_t flags;
  /** 該pbuf被引用的次數,當還有其他指針指向這個pbuf的時候ref字段就加一 */
  u16_t ref;
};

pbuf類型:共有四種PBUF_RAM、PBUF_ROM、PBUF_REF、PBUF_POOL

//在pbuf.h中定義
typedef enum {
  /** PBUF_RAM類型的pbuf是通過內存堆分配來的,其payload并未指向數據區的起始
  地址,而是隔了一段區域,在這個區域(offset)里通常存放TCP報文首部、IP首部
  、以太網幀首部等等 */
  PBUF_RAM,
  /** PBUF_ROM的數據指針payload指向外部存儲區,外部存儲區指不由TCP/IP協議
  棧管理的存儲區,它可以是應用程序管理的存儲器為用戶數據分配的緩存,也可以是
  ROM區域,如靜態網頁中的字符串常量等 */
  PBUF_ROM,
  /** PBUF_REF和PBUF_ROM的特性非常相似,都可以實現數據的零拷貝 */
  PBUF_REF,
  /** PBUF_POOL類型的pbuf是通過內存池分類來的,pbuf鏈表的第一個pbuf的payload
  未指向數據區的起始位置,原因通PBUF_RAM一樣,用來存放一些首部,pbuf鏈表后面
  的pbuf結構體中的payload就指向了數據區的起始位置 */
  PBUF_POOL
} pbuf_type;

pbuf層:由于LWIP各層禁止數據拷貝,所以存在不同層次對數據包pbuf的alloc,前面的offest就是為不同層預留的頭部字段,下面枚舉了4種層次,分配時除了要知道大小、類型還要傳入這個層次

//在pbuf.h中定義
typedef enum {
  /** 傳輸層,預留以太首部+IP首部+TCP首部 */
  PBUF_TRANSPORT,
  /** 網絡層,預留以太首部+IP首部 */
  PBUF_IP,
  /** 鏈路層,預留以太首部 */
  PBUF_LINK,
  /** 原始層,不預留空間 */
  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:內存申請函數

struct pbuf *pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type);
//layer 申請的pbuf所在的層,以此來確定offset值
//length 存放數據的大小
//type pbuf的類型

pbuf_free:數據包釋放函數

u8_t pbuf_free(struct pbuf *p);
//p 要釋放的pbuf數據包

pbuf_realloc:調整收縮pbuf的大小,在相應pbuf(鏈表)尾部釋放一定的空間,將數據包pbuf中的數據長度減少為某個長度值

void pbuf_realloc(struct pbuf *p, u16_t new_len);
//p 要收縮的pbuf數據包
//new_len 新的長度值

pbuf_header:調整payload指針和長度字段以便為pbuf中的數據預置包頭,常用于實現對pbuf預留孔間的操作

u8_t pbuf_header(struct pbuf *p, s16_t header_size_increment);
//p 要操作的pbuf數據包
//header_size_increment 大于0,payload前移,數據傳遞下層;
//			小于0,表示payload后移,數據傳遞上層

pbuf_take:用于向pbuf的數據區域拷貝數據

err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len);
//buf 要填充數據的pbuf
//dataptr 應用程序中的數據緩沖區
//len 數據緩沖區的長度

2.LWIP網卡設計與實現

2.1 LWIP網絡接口管理

在LWIP中對于網絡接口的描述是通過一個netif結構體完成的,netif結構體在netif.h文件中有定義

netif結構體

//在netif.h中定義
struct netif {
  struct netif *next;  //指向下一個netif結構體
#if LWIP_IPV4
  ip_addr_t ip_addr;	//ip地址
  ip_addr_t netmask;	//子網掩碼
  ip_addr_t gw;	//網關地址
#endif /* LWIP_IPV4 */
  netif_input_fn input;	//netif數據包輸入接口函數指針
#if LWIP_IPV4
  netif_output_fn output;//netif數據包輸出接口函數指針
#endif /* LWIP_IPV4 */
  netif_linkoutput_fn linkoutput;//鏈路層數據輸出接口函數指針
#if LWIP_NETIF_STATUS_CALLBACK
  //當netif狀態發生變化時,此接口函數會調用
  netif_status_callback_fn status_callback;
#endif /* LWIP_NETIF_STATUS_CALLBACK */
#if LWIP_NETIF_LINK_CALLBACK
  /* PHY必須和交換機或者路由器或者其他具備網卡的主機相連接,
  我們才可能正常通信比如路由器突然斷電,這個函數就會被調用 */
  netif_status_callback_fn link_callback;
#endif /* LWIP_NETIF_LINK_CALLBACK */
#if LWIP_NETIF_REMOVE_CALLBACK
  //netif移除網絡驅動接口,這個函數會被調用
  netif_status_callback_fn remove_callback;
#endif /* LWIP_NETIF_REMOVE_CALLBACK */
  void *state;	//主機的狀態
#if LWIP_NETIF_HOSTNAME
  const char*  hostname;	//自定義的主機名稱
#endif /* LWIP_NETIF_HOSTNAME */
#if LWIP_CHECKSUM_CTRL_PER_NETIF
  u16_t chksum_flags;		
#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF*/
  u16_t mtu;	//數據鏈路層最大傳輸大小
  u8_t hwaddr_len;	//mac地址長度
  u8_t hwaddr[NETIF_MAX_HWADDR_LEN];//mac地址
  u8_t flags;	//當前的netif的狀態,其實就是下面的netif_flag
  char name[2];	//網卡驅動的名稱
  u8_t num;		//網卡驅動的硬件編號
#if LWIP_IPV4 && LWIP_IGMP
  netif_igmp_mac_filter_fn igmp_mac_filter;//組播底層接口
#endif /* LWIP_IPV4 && LWIP_IGMP */
};

netif flag宏定義

/** netif網絡接口,可以進行正常使用(即lwIP可以正常使用)了 */
#define NETIF_FLAG_UP           0x01U
/** 廣播通訊的標志 */
#define NETIF_FLAG_BROADCAST    0x02U
/** STM32 MAC和PHY可以正常使用 */
#define NETIF_FLAG_LINK_UP      0x04U
/** ARP標志 */
#define NETIF_FLAG_ETHARP       0x08U
/** TCP/IP協議正常通信  */
#define NETIF_FLAG_ETHERNET     0x10U

2.2 netif典型API函數

netif的API函數是供應用層調用的函數

netif_add:添加網卡驅動到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:把網卡恢復出廠設置,目前lwip有一套默認參數

void netif_set_default(struct netif *netif);

netif_set_up&netif_set_down:設置我們網卡工作狀態,是上線還是離線

void netif_set_up(struct netif *netif);
void netif_set_down(struct netif *netif);

callback:需要自己實現link_callback函數

#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底層接口函數

netif底層接口即與硬件打交道的函數接口,主要包括以下函數

ethernetif_init:初始化網卡驅動(會調用底層驅動)

err_t ethernetif_init(struct netif *netif){
#if LWIP_IPV4
#if LWIP_ARP || LWIP_ETHERNET
//arp相關的函數接口賦值
#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 */
  //鏈路層數據輸出函數接口賦值
  netif->linkoutput = low_level_output;
  /* 底層接口初始化 */
  low_level_init(netif);
  return ERR_OK;
}

ethernetif_input:網卡數據輸入(會調用底層接口)

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:網卡底層驅動,主要針對硬件(STM32網卡初始化會在此調用)

/** 硬件初始化,其實就STM32 ETH外設初始化 */
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)
  {
    /* 當初始化成功后,會置位flag,同時在tcp/ip初始化完畢后,會
       進行判斷,此標志位決定網卡驅動是否	可以正常使用 */  
    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 */ 
  /* 二值信號量,用于信息同步,當網卡接口到數據后,會釋放二值信號量讓其他任務進行解析 */
  osSemaphoreDef(SEM);
  s_xSemaphore = osSemaphoreCreate(osSemaphore(SEM), 1);
  /* 創建網卡數據接收解析任務-ethernetif_input */
  osThreadDef(EthIf, ethernetif_input, osPriorityRealtime, 0, INTERFACE_THREAD_STACK_SIZE);
  osThreadCreate (osThread(EthIf), netif);
  /* 使能 網卡 發送和接口 */
  HAL_ETH_Start(&heth); 
  /* 上面的都是針對STM32 ETH外設進行初始化
  	但是實際網絡交互是用過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:底層網卡的數據輸出,實際的數據輸出,是通過pbuf進行封裝管理的

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里面的數據,發送到ETH外設里面 */ 
  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:底層網卡的數據接口,當接收到網卡數據后,會通過此函數,封裝為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庫,獲取網卡幀數據 */
  if (HAL_ETH_GetReceivedFrame_IT(&heth) != HAL_OK)
    return NULL;  
  /* 獲取網卡數據超度,及內存地址 */
  len = heth.RxFrameInfos.length;
  buffer = (uint8_t *)heth.RxFrameInfos.buffer;
  //網卡中數據有效
  if (len > 0){
    /* 網卡數據不能大于1500,屬于原始層接口  */
    p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
  }
  //如果pbuf創建成功,則從ETH中拷貝數據到pbuf里,最終把pbuf返回給上層應用
  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:工作在操作系統下的初始化

/**
 * @工作在操作系統下的初始化:
 * - 初始化所有的子功能模塊
 * - 啟動tcp/ip任務(tcp/ip網絡協議棧的實現是一個任務里面執行的)
 * @param 用于用戶初始化的函數指針,在lwip初始化完成,tcp/ip任務開始執行就是進行調用
 * @param 用戶初始化相關參數傳入
 */
void tcpip_init(tcpip_init_done_fn initfunc, void *arg){
  //lwip的初始化---初始化lwip所有功能模塊
  lwip_init();
  //用戶初始化函數指針賦值,參數賦值
  tcpip_init_done = initfunc;
  tcpip_init_done_arg = arg;
  //消息郵箱(freeRTOS是通過消息隊列實現),任務與任務間消息通信,網卡收到數據,網絡分層解析
  if (sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) {
    LWIP_ASSERT("failed to create tcpip_thread mbox", 0);
  }
#if LWIP_TCPIP_CORE_LOCKING
  //創建互斥鎖(互斥信號量),保護共享資源的
  if (sys_mutex_new(&lock_tcpip_core) != ERR_OK) {
    LWIP_ASSERT("failed to create lock_tcpip_core", 0);
  }
#endif /* LWIP_TCPIP_CORE_LOCKING */
  //這是標準的cmis接口,其實內部調用的freeRTOS的創建任務接口
  sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
}

lwip_init:工作在裸機模式下的初始化

/**
 * @工作在裸機模式下的初始化
 * Use this in NO_SYS mode. Use tcpip_init() otherwise.
 */
void lwip_init(void){
  /* Modules initialization */
  //狀態初始化
  stats_init();
#if !NO_SYS
  //與操作系統相關的初始化
  sys_init();
#endif /* !NO_SYS */
  //內存堆 內存池 pbuf netif初始化
  mem_init();
  memp_init();
  pbuf_init();
  netif_init();
#if LWIP_IPV4
  //ip層初始化
  ip_init();
#if LWIP_ARP
  //arp+以太網相關的初始化
  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內部有很多超時機制,是通過timeouts實現的(一個軟件定時器
  sys_timeouts_init();
#endif /* LWIP_TIMERS */
}

MX_LWIP_Init:HAL庫實現的lwip初始化函數

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協議棧 */
  tcpip_init( NULL, NULL );
  /* 數組格式的IP地址轉換為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]);
  /* 裝載網卡驅動,并初始化網卡 */
  netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, &tcpip_input);
  /* gnetif注冊為默認網卡驅動 */
  netif_set_default(&gnetif);
  // 判斷phy和mac層是否正常工作
  if (netif_is_link_up(&gnetif)){
    /* netif 網卡驅動可以正常使用,上線 */
    netif_set_up(&gnetif);
  }
  else{
    /* netif 網卡驅動下線 */
    netif_set_down(&gnetif);
  }
}
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 存儲器
    +關注

    關注

    38

    文章

    7514

    瀏覽量

    164017
  • 網卡
    +關注

    關注

    4

    文章

    312

    瀏覽量

    27405
  • 內存管理
    +關注

    關注

    0

    文章

    168

    瀏覽量

    14161
  • LwIP
    +關注

    關注

    2

    文章

    87

    瀏覽量

    27235
  • 協議棧
    +關注

    關注

    2

    文章

    143

    瀏覽量

    33665
收藏 人收藏

    評論

    相關推薦

    lwip協議代碼分析

    lwIP(Lightweight IP)是一個為嵌入式系統設計的輕量級TCP/IP協議
    的頭像 發表于 10-29 17:37 ?2049次閱讀
    <b class='flag-5'>lwip</b><b class='flag-5'>協議</b><b class='flag-5'>棧</b>代碼分析

    LwIP協議的設計與實現資料分享!

    LwIP協議的設計與實現_中文譯稿LwIP協議
    發表于 07-31 23:47

    嵌入式TCPIP協議LWIP的內部結構

    分析了嵌入式 TCPIP協議主要對LWIP的基本結構,介紹了嵌入式TCPIP協議LWIP
    發表于 02-17 15:55 ?76次下載
    嵌入式TCPIP<b class='flag-5'>協議</b><b class='flag-5'>棧</b><b class='flag-5'>LWIP</b>的內部結構

    Lwip協議的設計方案

    LWIP是TCP/IP協議的一種實現LWIP的主要目的是減少存儲器利用量和代碼尺寸,使LWIP
    發表于 09-16 15:18 ?33次下載
    <b class='flag-5'>Lwip</b><b class='flag-5'>協議</b><b class='flag-5'>棧</b>的設計<b class='flag-5'>方案</b>

    基于ARM的LwIP協議研究與移植

    提出基于ARM的LwIP協議研究與移植
    發表于 10-14 17:50 ?65次下載
    基于ARM的<b class='flag-5'>LwIP</b><b class='flag-5'>協議</b><b class='flag-5'>棧</b>研究與移植

    lwip協議中文版

    LWIP是TCP/IP協議的一種實現LWIP的主要目的是減少存儲器利用量和代碼尺寸,使LWIP
    發表于 02-03 16:47 ?0次下載
    <b class='flag-5'>lwip</b><b class='flag-5'>協議</b>中文版

    uCOS-II下實現lwip協議實現Ping功能

    uCOS-II下實現lwip協議實現Ping功能
    發表于 03-26 15:51 ?143次下載

    LwIP協議詳解

    LwIP協議詳解,LwIP是Light Weight (輕型)IP協議,有無操作系統的支持都可以運行。LwIP
    發表于 11-09 18:25 ?49次下載

    TCPIP協議實現lwip

    TCPIP協議實現lwip方便初學者剛開始接觸lwip,有個大概的了解與認識。
    發表于 03-14 15:40 ?13次下載

    lwip協議源碼詳解說明

    lwip是瑞典計算機科學院(SICS)的Adam Dunkels 開發的一個小型開源的TCP/IP協議實現的重點是在保持TCP協議主要功
    發表于 12-11 15:27 ?3.7w次閱讀
    <b class='flag-5'>lwip</b><b class='flag-5'>協議</b><b class='flag-5'>棧</b>源碼詳解說明

    LWIP內存管理知識匯總

    LWIP內存管理LWIP內存管理使用了2種方式:內存
    的頭像 發表于 03-06 10:01 ?6935次閱讀
    <b class='flag-5'>LWIP</b><b class='flag-5'>內存</b><b class='flag-5'>管理</b>知識匯總

    LWIP協議中Raw TCP中使用

    本文檔的主要內容詳細介紹的是LWIP協議中Raw TCP中使用的資料免費下載
    發表于 11-05 17:36 ?17次下載
    <b class='flag-5'>LWIP</b><b class='flag-5'>協議</b><b class='flag-5'>棧</b>中Raw TCP中使用

    Xilinx LwIP 例程解析:網卡驅動(接收篇)

    對于 LwIP 協議的移植來說,用戶的主要工作是為其提供網卡驅動函數。LwIP 可以運行在多種不同的硬件平臺上,配合不同型號的網絡 Phy
    發表于 02-07 10:09 ?9次下載
    Xilinx <b class='flag-5'>LwIP</b> 例程解析:<b class='flag-5'>網卡</b>驅動(接收篇)

    如何更好的理解LWIP協議

    LwIP(Light weight IP),是一種輕量化且開源的TCP/IP協議,它可以在有限的RAM和ROM條件下,實現一個完整的TCP/IP
    的頭像 發表于 10-27 09:13 ?4246次閱讀

    LwIP協議源碼詳解—TCP/IP協議實現

    電子發燒友網站提供《LwIP協議源碼詳解—TCP/IP協議實現.pdf》資料免費下載
    發表于 07-03 11:22 ?3次下載
    主站蜘蛛池模板: 黑粗硬大欧美在线视频| 印度学生xxxxx性14一16| 国产私拍福利精品视频| 69式国产真人免费视频| 睡觉被偷偷进入magnet| 久久在精品线影院精品国产| 国产超碰AV人人做人人爽| 最新影音先锋av资源台| 亚洲qvod图片区电影| 日本吃孕妇奶水免费观看| 久久亚洲国产成人影院| 国产曰韩无码亚洲视频| 大地影院日本韩国电影免费观看| 6080伦理久久亚洲精品| 亚洲日产2020乱码草莓毕| 忘忧草在线影院WWW日本二 | 国内精品久久人妻无码HD浪潮 | 国家产午夜精品无人区| 福利视频久久| hdsex老太婆70| 99精彩视频在线观看| 在线欧美精品一区二区三区| 亚洲精品色播一区二区| 性色AV一区二区三区V视界影院| 日韩精品a在线视频| 内射一区二区精品视频在线观看 | 精品淑女少妇AV久久免费| 国产精品高潮呻吟AV久久96| 成人啪啪色婷婷久色社区| hd性欧美俱乐部中文| a一级毛片视频免费看| 99精品久久精品一区二区| 91国在线视频| 69国产精品成人无码视频| 777久久人妻少妇嫩草AV| 777久久人妻少妇嫩草AV蜜桃| 13一18TV处流血TV| 97成人免费视频| AV国产乱码一区二区三视频| hdxxxx58丝袜连裤袜| 成人精品视频99在线观看免费|