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

歡迎訪問 生活随笔!

生活随笔

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

windows

LwIP应用开发笔记之十:LwIP带操作系统基本移植

發布時間:2024/7/23 windows 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LwIP应用开发笔记之十:LwIP带操作系统基本移植 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

現在,TCP/IP協議的應用無處不在。隨著物聯網的火爆,嵌入式領域使用TCP/IP協議進行通訊也越來越廣泛。在我們的相關產品中,也都有應用,所以我們結合應用實際對相關應用作相應的總結。

1、技術準備

我們采用的開發平臺是STM32F407和LwIP協議棧。在開始之前,我們需要做必要的準備工作。

首先要獲得LwIP的源碼,在網上有很多,不同版本及不同平臺的都有,不過我們還是建議直接從官方網站獲得。其官方網站如下:

http://savannah.nongnu.org/projects/lwip/

其次,需要硬件平臺,我們采用了STM32F407ZG+DM9161的網絡接口方式,這并不是必須的,其他硬件平臺也是一樣的。

最后,因為我們后面要在操作系統下移植,采用的操作系統是FreeRTOS,所以還需下載FreeRTOS的源碼。同樣建議從官網下載:

https://www.freertos.org/index.html

2LwIP簡要說明

LwIP是一款免費的TCP/IP協議棧,但它的功能趨勢十分完備。LwIP 具有三種應用編程接口 (API):

  • Raw API:為原始的 LwIP API。它通過事件回調機制進行應用開發。該 API 提供了最好的性能和優化的代碼長度,但增加了應用開發的復雜性。
  • Netconn API:為高層有序 API,需要實時操作系統 (RTOS)的支持 (提供進程間通訊的方法)。 Netconn API 支持多線程工作。
  • BSD Socket API:類似 Berkeley 的套接字 API (開發于 Netconn API 之上) 。

對于以上三種接口,前一種只需要裸機即可調用,后兩種需要操作系統才能調用。所以據此LwIP存在兩種移植方式:一是,只移植內核,此時應用程序的編寫只能基于RAW/Callback API進行。二是,移植內核和上層API,此時應用程序編寫可以使用3種API,即:RAW/Callback API、Sequential API和Socket API。

3LwIP的帶操作系統基本移植

帶操作系統的移植首先是建立在無操作系統移植基礎之上的。在無操作系統移植時,定義的數據類型和宏都是有效的,只需要對lwipopts.h配置文件做簡單修改,并根據sys_arch.txt移植說明文件編寫sys_arch.c和sys_arch.h兩個文件以實現操作系統模擬層就可以了。

操作系統模擬層的功能再以為協議棧提供郵箱、信號量、互斥量等機制,用以保證內核與上層API的通訊。這些操作系統模擬層函數均在sys.h中已經聲明,我們一般在sys_arch.c文件中完成其定義。所以,我們很清楚,帶操作系統的移植就是在無操作系統的基礎上添加操作系統模擬層。在接下來我們就看看操作系統模擬層的編寫。

在操作系統已經正確移植的基礎上,我們根據sys_arch.txt移植說明文件的描述,還需要移植的宏定義及函數等如下:

名稱

屬性

功能

sys_mbox_t

數據類型

指針類型,指向系統郵箱

sys_sem_t

數據類型

指針類型,指向系統信號量

sys_mutex_t

數據類型

指針類型,指向系統互斥量

sys_thread_t

數據類型

系統任務標識

SYS_MBOX_NULL

郵箱指針指向的空值

SYS_SEM_NULL

信號量指針指向的空值

sys_init

函數

初始化系統模擬層

sys_sem_new

函數

生成一個信號量

sys_sem_free

函數

刪除一個信號量

sys_sem_signal

函數

釋放一個信號量

sys_arch_sem_wait

函數

等待一個信號量

sys_sem_valid

函數

判斷一個信號量是否有效

sys_sem_set_invalid

函數

將一個信號量置為無效

sys_mutex_new

函數

生成一個新的互斥量

sys_mutex_free

函數

刪除一個互斥量

sys_mutex_lock

函數

鎖住一個互斥量

sys_mutex_unlock

函數

解鎖一個互斥量

sys_mutex_valid

函數

判斷一個互斥量是否有效

sys_mutex_set_invalid

函數

將一個互斥量置為無效

sys_mbox_new

函數

新建一個郵箱

sys_mbox_free

函數

刪除一個郵箱

sys_mbox_post

函數

向郵箱投遞消息,阻塞

sys_mbox_trypost

函數

嘗試向郵箱投遞消息,不阻塞

sys_arch_mbox_fetch

函數

從郵箱獲取消息,阻塞

sys_arch_mbox_tryfetch

函數

嘗試從郵箱獲取消息,不阻塞

sys_mbox_valid

函數

判斷一個郵箱是否有效

sys_mbox_set_invalid

函數

將一個郵箱設置為無效

sys_thread_new

函數

創建新進程

sys_arch_protect

函數

臨界區保護

sys_arch_unprotect

函數

退出臨界區保護

從上表中我們可以發現,這些變量和函數主要是面向信號量、互斥量及郵箱,包括新建、刪除、釋放、獲取等各類操作,我們需要根據操作系統的規定來實現這些函數,我們在這里使用的FreeRTOS,所以我根據FreeRTOS對信號量、互斥量及郵箱的操作來實現這些函數。我們列舉郵箱的各操作函數實現如下:

/*創建一個空的郵箱。*/ err_t sys_mbox_new(sys_mbox_t *mbox, int size) {osMessageQDef(QUEUE, size, void *);*mbox = osMessageCreate(osMessageQ(QUEUE), NULL);#if SYS_STATS++lwip_stats.sys.mbox.used;if (lwip_stats.sys.mbox.max < lwip_stats.sys.mbox.used) {lwip_stats.sys.mbox.max = lwip_stats.sys.mbox.used;} #endif /* SYS_STATS */if (*mbox == NULL)return ERR_MEM;return ERR_OK; }/*重新分配一個郵箱。如果郵箱被釋放時,郵箱中仍有消息,在lwIP中這是出現編碼錯誤的指示,并通知開發人員。*/ void sys_mbox_free(sys_mbox_t *mbox) {if( osMessageWaiting(*mbox) ){/* Line for breakpoint.? Should never break here! */portNOP(); #if SYS_STATSlwip_stats.sys.mbox.err++; #endif /* SYS_STATS */}osMessageDelete(*mbox);#if SYS_STATS--lwip_stats.sys.mbox.used; #endif /* SYS_STATS */ }/*發送消息到郵箱*/ void sys_mbox_post(sys_mbox_t *mbox, void *data) {while(osMessagePut(*mbox, (uint32_t)data, osWaitForever) != osOK); }/*嘗試將消息發送到郵箱*/ err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg) { err_t result;if ( osMessagePut(*mbox, (uint32_t)msg, 0) == osOK){result = ERR_OK;}else {// could not post, queue must be fullresult = ERR_MEM;#if SYS_STATSlwip_stats.sys.mbox.err++; #endif /* SYS_STATS */}return result; }/*阻塞進程從郵箱獲取消息*/ u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout) {osEvent event;uint32_t starttime = osKernelSysTick();;if(timeout != 0){event = osMessageGet (*mbox, timeout);if(event.status == osEventMessage){*msg = (void *)event.value.v;return (osKernelSysTick() - starttime);}else{return SYS_ARCH_TIMEOUT;}}else{event = osMessageGet (*mbox, osWaitForever);*msg = (void *)event.value.v;return (osKernelSysTick() - starttime);} }/*嘗試從郵箱獲取消息*/ u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) {osEvent event;event = osMessageGet (*mbox, 0);if(event.status == osEventMessage){*msg = (void *)event.value.v;return ERR_OK;}else{return SYS_MBOX_EMPTY;} }/*判斷一個郵箱是否有效*/ int sys_mbox_valid(sys_mbox_t *mbox)????????? {?????if (*mbox == SYS_MBOX_NULL)return 0;elsereturn 1; }/*設置一個郵箱無效*/????????????????????????????????????????????? void sys_mbox_set_invalid(sys_mbox_t *mbox)?? {????????????????????????????????????????????*mbox = SYS_MBOX_NULL;????????????????????? }?????????????????????????????? ??????????????//? 創建一個新的信號量。而 "count"參數指示該信號量的初始狀態 err_t sys_sem_new(sys_sem_t *sem, u8_t count) {osSemaphoreDef(SEM);*sem = osSemaphoreCreate (osSemaphore(SEM), 1);if(*sem == NULL){ #if SYS_STATS++lwip_stats.sys.sem.err; #endif /* SYS_STATS */?return ERR_MEM;}if(count == 0)? // Means it can't be taken{osSemaphoreWait(*sem,0);}#if SYS_STATS++lwip_stats.sys.sem.used;if (lwip_stats.sys.sem.max < lwip_stats.sys.sem.used) {lwip_stats.sys.sem.max = lwip_stats.sys.sem.used;} #endif /* SYS_STATS */return ERR_OK; }

此外還有一些函數也是協議棧需要的函數,特別是sys_thread_new函數,不但協議棧在初始化是需要用到,在后續我們實現各類基于LwIP的應用時也需要用到,其實現如下:

sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread , void *arg, int stacksize, int prio) {const osThreadDef_t os_thread_def = { (char *)name, (os_pthread)thread, (osPriority)prio, 0, stacksize};return osThreadCreate(&os_thread_def, arg); } osThreadId osThreadCreate (const osThreadDef_t *thread_def, void *argument) {TaskHandle_t handle;#if( configSUPPORT_STATIC_ALLOCATION == 1 ) &&? ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )if((thread_def->buffer != NULL) && (thread_def->controlblock != NULL)) {handle = xTaskCreateStatic((TaskFunction_t)thread_def->pthread,(const portCHAR *)thread_def->name,thread_def->stacksize, argument, makeFreeRtosPriority(thread_def->tpriority),thread_def->buffer, thread_def->controlblock);}else {if (xTaskCreate((TaskFunction_t)thread_def->pthread,(const portCHAR *)thread_def->name,thread_def->stacksize, argument, makeFreeRtosPriority(thread_def->tpriority),&handle) != pdPASS)? {return NULL;}} #elif( configSUPPORT_STATIC_ALLOCATION == 1 )handle = xTaskCreateStatic((TaskFunction_t)thread_def->pthread,(const portCHAR *)thread_def->name,thread_def->stacksize, argument, makeFreeRtosPriority(thread_def->tpriority),thread_def->buffer, thread_def->controlblock); #elseif (xTaskCreate((TaskFunction_t)thread_def->pthread,(const portCHAR *)thread_def->name,thread_def->stacksize, argument, makeFreeRtosPriority(thread_def->tpriority),&handle) != pdPASS)? {return NULL;}???? #endifreturn handle; }

至此,基于FreeRTOS操作系統的LwIP移植結算完成了,我們編譯下載就可以對其進行驗證。

4、結論

前面已經移植了基于操作系統的LwIP,那怎么知道我們的移植是否成功呢?接下來我們對它進行必要的驗證。

首先我們查看目標板在網絡上的配置是否正確。我們打開命令行窗口,運行ipconfig命令,查看MAC地址和IP地址配置:

我們配置的MAC地址00:08:E1:00:00:00和IP地址192.168.2.110顯示正常。接下來我們采用ping命令測試網絡鏈接:

上圖顯示網絡連接正常,經此測試,說明我們的LwIP在有操作系統情況下移植正常。

歡迎關注:

總結

以上是生活随笔為你收集整理的LwIP应用开发笔记之十:LwIP带操作系统基本移植的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。