日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

uIP无操作系统(裸机)移植

發(fā)布時間:2023/12/20 windows 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 uIP无操作系统(裸机)移植 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

?本文轉(zhuǎn)自music_fong博客:http://blog.csdn.net/music_fong/article/details/7191773

以前自己寫了一個TCP/IP的協(xié)議棧,但是需要的48K的RAM。后來隨著產(chǎn)品功能的增加,RAM資源就越來越不夠用了。在一個偶然的機會下,發(fā)現(xiàn)了一個開源的協(xié)議棧--uIP。于是在網(wǎng)上找了一些資料。

  原來現(xiàn)在比較流行的開源的小型協(xié)議棧有兩個--lwIP和uIP。

  lwIP主頁:http://savannah.nongnu.org/projects/lwip/

? ? ? ?uIP主頁:http://www.sics.se/~adam/old-uip/

  ? uIP文檔:http://www.sics.se/~adam/download/?f=uip-1.0-refman.pdf

  其中l(wèi)wIP實現(xiàn)的功能比較多,所以其會較復雜;uIP主要實現(xiàn)了TCP和UDP以及ARP的等簡單功能。并且兩者都可用于裸機或有操作系統(tǒng)。由于我只需要簡單的功能,所以選擇了簡單的uIP。

  下面概述一下uIP及裸機的移植方法,不足之處,請大家多多指正。

                                  uIP概述

  uIP的結(jié)構(gòu)不是層次式的,其整個處理過程單獨為一個進程,即一個函數(shù),下面就大概分析這個函數(shù)。

一、主循環(huán)控制
  在主循環(huán)中,需要處理兩個事情。
 1. ? ?檢測是否有數(shù)據(jù)到來,當有數(shù)據(jù)到來時調(diào)用uip_input()函數(shù)。
? ? 2. 檢測網(wǎng)絡定時器是否超時,如果超時,則調(diào)用uip_periodic()函數(shù)。

二、體系結(jié)構(gòu)相關功能定義
? ? 1. 檢驗計算,可以手動修改的兩個函數(shù)是uip_ipchksum()和uip_tcpchksum()。
? ? 2. uip不使用32-bit的變量,所以要手動實現(xiàn)uip_add32()這個函數(shù)。
  (這里移植的時候可以不重寫這些函數(shù),按照其默認的算法也可以)

三、內(nèi)存管理
? ? 1. 整個協(xié)議棧使用一個全局的buffer(變量uip_buf)裝載收到的數(shù)據(jù)包,所以有數(shù)據(jù)到來時,必須立刻處理該數(shù)據(jù),或者將數(shù)據(jù)從buffer中考出來;只有buffer中的數(shù)據(jù)處理了,才會接受下一包數(shù)據(jù)。
? ? 2. 當程序正在處理數(shù)據(jù)包時,這時如果有數(shù)據(jù)到來,則需要網(wǎng)卡的驅(qū)動程序去把數(shù)據(jù)按順序緩存
    有一些網(wǎng)卡可以緩存好幾包的數(shù)據(jù)(即網(wǎng)卡或驅(qū)動程序把數(shù)據(jù)包緩存起來),否則丟掉數(shù)據(jù)或
    降低性能。(但這一般只會在多個TCP連接時才會發(fā)生)
? ? 3. 發(fā)送的數(shù)據(jù)的頭部會使用全局buffer,同時uIP沒有重傳緩沖,即沒有把已發(fā)送的數(shù)據(jù)排隊,
? ? ? ?所以當需要重傳數(shù)據(jù)時,需要應用程序再生成重傳數(shù)據(jù)。
? ? 4. 總共需要的內(nèi)存可以按應用程序的發(fā)在來配置。


? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 移植

一、下載源代碼。

  從http://www.sics.se/~adam/old-uip/download.html下載源代碼。解壓后,uip的核心代碼都在uip文件夾中,所以我們只要把該目錄放到自己的工程里面就行了。同時去掉

? ? ? ?clock.h timer.c(因為我不使用這種定時方法,我只是在定時器里自加來做超時)

? ? ? ?psock.c psock.h(因為我是裸機,所以不需用到這個功能)

? ? ? ?uip-split.c?uip-split.h(因為我的程序中不需要分包,所以也沒有這個功能)

二、配置

  配置文件是uipopt.h和uip-conf.h文件,其中uip-conf.h在解壓后的unix文件夾下,并且include在uipopt.h文件中,具體配置參考其文檔。

  我修改了以下地方

  //#define UIP_CONF_BYTE_ORDER ? ? ?UIP_LITTLE_ENDIAN  // 注釋這行,如果該配置,則默認配置為LITTLE_ENDIAN(小端系統(tǒng))

  #define UIP_CONF_BUFFER_SIZE ? ? 1500    //定義了uip_buf的大小

? ? ? ?#include "client.h" ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//include了我的客戶端程序的頭文件

? ? ? ?

  在uipopt.h中

  #define UIP_APPCALL?HandleClientApp   //“HandleClientApp”是我的客戶端處理函數(shù)。因為其收到數(shù)據(jù)或定時器到期,都會回調(diào)該函數(shù)。

三、結(jié)構(gòu)和變量的定義

  在我的"client.h"文件中定義了

  struct client_state {
  uint8 state;
  };
  typedef struct client_state uip_tcp_appstate_t;   // 這里定義了uip_tcp_appstate_t 結(jié)構(gòu),這個結(jié)構(gòu)在uip_conn結(jié)構(gòu)里引用,其作用是記錄應用程序的狀態(tài)。

四、初始化

  uip_ipaddr_t ipaddr;
struct uip_eth_addr temp_eth_addr;  

  uip_init();
uip_arp_init();
// 設置主機的ip地址
uip_ipaddr(ipaddr, 192, 168, 1,228);
? ?  uip_sethostaddr(ipaddr);


// 設置子網(wǎng)掩碼
? ?  uip_ipaddr(ipaddr, 255, 255, 255,0);
? ?  uip_setnetmask(ipaddr);
? ??
? ?  // 設置網(wǎng)關
? ?  uip_ipaddr(ipaddr, 192, 168, 1,1);
? ?  uip_setdraddr(ipaddr);
? ??
? ?  // 設置mac
? ?  temp_eth_addr.addr[0] = SourceMAC[0];
? ?  temp_eth_addr.addr[1] = SourceMAC[1];
? ?  temp_eth_addr.addr[2] = SourceMAC[2];
? ?  temp_eth_addr.addr[3] = SourceMAC[3];
? ?  temp_eth_addr.addr[4] = SourceMAC[4];
? ?  temp_eth_addr.addr[5] = SourceMAC[5];
? ?  uip_setethaddr(temp_eth_addr);


五、與硬件相關部分(即把數(shù)據(jù)從網(wǎng)卡讀出來或把數(shù)據(jù)發(fā)到網(wǎng)卡)

uint8 temp;
? ?  uint8 *inbuf;
//#define BUF ((struct uip_eth_hdr *)&uip_buf[0])
struct uip_eth_hdr *pfram;

? ?  //檢測是否有數(shù)據(jù)到達
? ?  QueryRTL8019();    // 如果有數(shù)據(jù)到來,就置位EVENT_WORD
? ??
? ?  // 以太網(wǎng)接收數(shù)據(jù) ??
? ? if(EVENT_WORD == VALID_FLAG) {
? ??pfram = (struct uip_eth_hdr *)&uip_buf[0];
? ? ? ? EVENT_WORD = 0;?
? ? ? ? uip_len = RTLReceivePacket(); ? ? ? ? ? ? ? ? ? ? ? ? ? // 這個函數(shù)的作用是吧網(wǎng)卡收到的數(shù)據(jù)拷貝到uip_buf中,并返回數(shù)據(jù)長度
if(uip_len > 0) {
if(pfram->type == HTONS(UIP_ETHTYPE_IP)) {
uip_arp_ipin();
uip_input();
if(uip_len > 0) {
uip_arp_out();
Eth_Send();      //這個函數(shù)發(fā)送網(wǎng)絡數(shù)據(jù)
}
} else if(pfram->type == HTONS(UIP_ETHTYPE_ARP)) {
uip_arp_arpin();
if(uip_len > 0) {
Eth_Send();
}
}
}
}

if(ethernet_timer > 5) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//ethernet_timer在100ms定時器中自加ethernet_timer++
ethernet_timer = 0;
for(temp = 0; temp < UIP_CONNS; temp++) {
uip_periodic(temp);


? ? ? ? ? ? ? ? //
? ? ? ? ? ? ? ? // If the above function invocation resulted in data that
? ? ? ? ? ? ? ? // should be sent out on the network, the global variable
? ? ? ? ? ? ? ? // uip_len is set to a value > 0.
? ? ? ? ? ? ? ? //
if(uip_len > 0) {
uip_arp_out();
Eth_Send();

}
}


#if UIP_UDP
for(temp = 0; temp < UIP_UDP_CONNS; temp++) {
uip_udp_periodic(temp);


? ? ? ? ? ? ? ? //
? ? ? ? ? ? ? ? // If the above function invocation resulted in data that
? ? ? ? ? ? ? ? // should be sent out on the network, the global variable
? ? ? ? ? ? ? ? // uip_len is set to a value > 0.
? ? ? ? ? ? ? ? //
if(uip_len > 0) {
uip_arp_out();
Eth_Send();

}
}
#endif
}

//
// Process ARP Timer here.
//
if(arp_timer > 100) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //arp_timer也在100ms定時器中自加
{
arp_timer = 0;
uip_arp_timer();
}


? ? ? ?// 發(fā)送函數(shù)

? ? ?void Eth_Send(void)
{
memcpy(EthernetTxData, uip_buf, UIP_LLH_LEN); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 把uip_buf中的幀的頭部靠到EthernetTxData中
? ??

? ? ? ? // 拷貝uip_buf中的剩下部分
if(uip_len <= UIP_LLH_LEN + UIP_TCPIP_HLEN) {
memcpy(&EthernetTxData[UIP_LLH_LEN], &uip_buf[UIP_LLH_LEN], uip_len - UIP_LLH_LEN);
} else {
memcpy(&EthernetTxData[UIP_LLH_LEN], &uip_buf[UIP_LLH_LEN], UIP_TCPIP_HLEN);
memcpy(&EthernetTxData[UIP_LLH_LEN+UIP_TCPIP_HLEN], uip_appdata, uip_len - UIP_TCPIP_HLEN - UIP_LLH_LEN);
}

? ? ? ? // 把數(shù)據(jù)發(fā)到網(wǎng)卡
RTLSendPacket(EthernetTxData, uip_len);
uip_len = 0;
}


六、于應用程序相關部分

  void HandleClientApp(void)        // 配置中的函數(shù)
{

if (uip_connected()) {
//uip_send("Start\n",6);
ClientLinkStatus = CLIENT_WORK;
return;
}

if (ClientLinkStatus == CLIENT_CLOSING) {
uip_close();
ClientLinkStatus = CLIENT_UNLINK;
return;
}

if (uip_aborted() || uip_closed()) {
ClientLinkStatus = CLIENT_UNLINK;
uip_abort();
return;
}

if (uip_timedout()) {
uip_abort();
ClientLinkStatus = CLIENT_UNLINK;
return;
}

if(uip_acked()) {
ClientAcked();
}

if(uip_newdata()) {
ClientNewData();        // 這個是收到數(shù)據(jù)的處理函數(shù)
}

if(uip_rexmit() ||
uip_newdata() ||
uip_acked() ? ||
uip_poll()) {
ClientSendData();        // 這個函數(shù)的作用是把緩存中的數(shù)據(jù)靠到uip_buf中
}?
}


//我在應用程序中會調(diào)用uint8 ClientSend(uint8 *pdata, uint16 len)函數(shù),把要發(fā)的數(shù)據(jù)緩沖在ClientTxBuf 這個循環(huán)緩存中,然后在這里實際拷貝到uip_buf中發(fā)送

void ClientSendData(void)
{
uint16 len;
uint16 left;

uint8 ?*psend;

? ? ? ?// 緩存中有數(shù)據(jù)

if (ClientTxSize>0) {
len = ClientTxSize > uip_mss() ? uip_mss():ClientTxSize;
if ((pTxBuf+len) > (ClientTxBuf+2048)) {
memcpy(ClientTxTempBuf, pTxBuf, 2048 - (pTxBuf-ClientTxBuf));
left = 2048-(pTxBuf-ClientTxBuf);
memcpy(ClientTxTempBuf+left, ClientTxBuf, len-left);
uip_send(ClientTxTempBuf, len);
} else {
uip_send(pTxBuf, len);
}
}
}

七、總結(jié)

  整個移植主要處理三方面的事情,一是跟應用程序的接口,即應用程序怎么知道收到數(shù)據(jù)(在HandleClientApp里面檢測uip_newdata()是否收到信數(shù)據(jù)),以及怎么發(fā)數(shù)據(jù);二是跟硬件的接口,即怎么知道網(wǎng)口收到了數(shù)據(jù)和怎么發(fā)數(shù)據(jù)(我是通過循環(huán)檢測處理的);三是定時問題,因為整個協(xié)議棧的定時都是通過uip_periodic(uint8 conn_id)處理的。

總結(jié)

以上是生活随笔為你收集整理的uIP无操作系统(裸机)移植的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。