說在開頭
? ? ? ? 正點原子F429開發板主芯片采用的是STM32F429IGT6,網絡PHY芯片采用的是LAN8720A(V1)和YT8512C(V2),采用的是RMII連接,PHY_ADDR為0;在代碼中將會對不同的芯片做出適配。
? ? ? ? CubeMX版本:6.6.1;
? ? ? ? F4芯片組Pack包版本:STM32Cube FW_F4 V1.27.0;
? ? ? ?
1、實現簡單的http服務端
????????本實驗代碼以《基于正點原子阿波羅F429開發板的LWIP應用(3)——Netbiosns功能》一章的代碼作為基礎;
- 打開"Middlewares/Third_Party/LwIP/src/apps/http”文件夾,僅保留“httpd.c、fsdata.c、fsdata.h、fs.c、httpd_structs.h”五個文件(不刪除也行,就是看著有點礙事);
- 打開"\Middlewares\Third_Party\LwIP\src\include\lwip\apps”文件夾,刪除“altcp_proxyconnect.h”和“http_client.h”兩個文件(不刪除也行,就是看著有點礙事);
- MDK新增http分組,將"httpd.c"和“fs.c”添加到http分組中,并將"Middlewares/Third_Party/LwIP/src/apps/http”文件夾添加到編譯路徑(fsdata.h文件)
- main.c開頭添加頭文件:#include "lwip/apps/httpd.h"
- main函數while(1)前增加以下代碼:httpd_init();
????????至此就修改完成了,編譯0警告0錯誤,下載后在瀏覽器訪問板子IP就可以看到可以打開網頁了。(注意:有部分國產單片機需要在lwipopts.h文件中添加“?#define HTTP_IS_DATA_VOLATILE(hs) TCP_WRITE_FLAG_COPY?”宏定義才可以正常打開網頁)
如果要查看http服務端運行時的log,可以在lwipopts.h文件中添加以下內容打開log輸出:
#define LWIP_DEBUG
#define HTTPD_DEBUG LWIP_DBG_ON
2、實現SSI和CGI功能
2.1、CGI技術介紹??
????????公共網關接口 CGI(Common Gateway Interface) 是 WWW 技術中最重要的技術之一,有著不可替代的重要地位。CGI 是外部應用程序與 Web 服務器之間的接口標準,是在 CGI 程序和Web服務器之間傳遞信息的規程。CGI 規范允許 Web 服務器執行外部程序,并將它們的輸出發送給Web 瀏覽器,CGI 在物理上是一段程序,運行在服務器上,提供同客戶端 HTML 頁面的接口。
????????絕大多數的 CGI 程序被用來解釋處理來自表單的輸入信息,并在服務器產生相應的處理, 或將相應的信息反饋給瀏覽器,CGI 程序使網頁具有交互功能。在我們本章實驗中我們通過瀏覽器控制開發板上的 LED 和蜂鳴器就是使用的 CGI 技術。
2.2、SSI技術介紹
????????服務器端嵌入:Server Side Include,是一種類似于 ASP 的基于服務器的網頁制作技術。大多數的 WEB 服務器等均支持 SSI 命令。將內容發送到瀏覽器之前,可以使用“服務器端包含 (SSI)”指令將文本、圖形或應用程序信息包含到網頁中。因為包含 SSI 指令的文件要求特殊處理,所以必須為所有 SSI 文件賦予 SSI 文件擴展名。默認擴展名是 .stm、.shtm 和 .shtml。
????????SSI 是為 WEB 服務器提供的一套命令,這些命令只要直接嵌入到 HTML 文檔的注釋內容 之中即可。如:<!--#include file="info.htm"-->就是一條 SSI 指令,其作用是將"info.htm"的內容拷貝到當前的頁面中,當訪問者來瀏覽時,會看到其它 HTML 文檔一樣顯示 info.htm 其中的內容。其它的 SSI 指令使用形式基本同剛才的舉例差不多,可見 SSI 使用只是插入一點代碼而已,使用形式非常簡單。<!-- -->是 HTML 語法中表示注釋,當 WEB 服務器不支持 SSI 時,會忽略這些信息。
2.3、網頁數組制作
????????在嵌入式開發中網頁不是以文件的形式保存的,而是以網頁數組的形式保存在“fsdata.c”文件中。正點原子自己開發了一個網頁數組制作工具:makefsdata.exe,使用方法如下:
? ? ? ? 首先將網頁源文件放到makefsdata文件夾中的fd文件夾中(本實驗用到的網頁源文件會放在實驗源碼中);
? ? ? ? 進入makefsdata文件夾,在上面的路徑欄輸入cmd后敲回車打開cmd窗口;
? ? ? ? 在命令行輸入“makefsdata -i”后敲回車,可以看到命令行有提示有哪些文件被制作成了網頁數組,并且makefsdata文件夾中多了一個fsdata.c文件。操作如下圖:
2.4 SSI功能實現
????????本實驗代碼在《實現簡單的http服務端》章節代碼的基礎上修改。
- 將剛才生成的網頁數組文件“fsdata.c”文件替換"Middlewares/Third_Party/LwIP/src/apps/http”文件夾中的同名文件。
- 在“lwipopts.h”文件中添加以下內容:“#define LWIP_HTTPD_SSI ???????????1”
- 在“LWIP/APP”中新建2個文件:“http.c”和“http.h”,分別粘貼以下代碼:
-
/*http.c代碼*/ #include "http.h"/************************SSI相關**************************************/#define NUM_CONFIG_SSI_TAGS 4 /* SSI的TAG數量 */static const char *ppcTAGs[] = /* SSI的Tag */ {"t", /* ADC值 */"w", /* 溫度值 */"h", /* 時間 */"y" /* 日期 */ };/*** @breif SSIHandler中需要用到的處理ADC的函數* @param pcInsert :* @retval 無*/ void ADC_Handler(char *pcInsert) {/* 準備添加到html中的數據 */*pcInsert = (char)(1 + 0x30);*(pcInsert + 1) = (char)(2 + 0x30);*(pcInsert + 2) = (char)(3 + 0x30);*(pcInsert + 3) = (char)(4 + 0x30); }/*** @breif SSIHandler中需要用到的處理內部溫度傳感器的函數* @param pcInsert :* @retval 無*/ void Temperate_Handler(char *pcInsert) {/* 添加到html中的數據 */*pcInsert = (char)(0 + 0x30);*(pcInsert + 1) = (char)(3 + 0x30);*(pcInsert + 2) = (char)(3 + 0x30);*(pcInsert + 3) = '.';*(pcInsert + 4) = (char)(3 + 0x30);*(pcInsert + 5) = (char)(3 + 0x30); }/*** @breif SSIHandler中需要用到的處理RTC時間的函數* @param pcInsert :* @retval 無*/ void RTCTime_Handler(char *pcInsert) {uint8_t hour, min, sec;hour = 9;min = 35;sec = 20;*pcInsert = (char)((hour / 10) + 0x30);*(pcInsert + 1) = (char)((hour % 10) + 0x30);*(pcInsert + 2) = ':';*(pcInsert + 3) = (char)((min / 10) + 0x30);*(pcInsert + 4) = (char)((min % 10) + 0x30);*(pcInsert + 5) = ':';*(pcInsert + 6) = (char)((sec / 10) + 0x30);*(pcInsert + 7) = (char)((sec % 10) + 0x30); }/*** @breif SSIHandler中需要用到的處理RTC日期的函數* @param pcInsert :* @retval 無*/ void RTCdate_Handler(char *pcInsert) {uint8_t year, month, date, week;year =24;month = 8;date = 2;week = 1;*pcInsert = '2';*(pcInsert + 1) = '0';*(pcInsert + 2) = (char)((year / 10) + 0x30);*(pcInsert + 3) = (char)((year % 10) + 0x30);*(pcInsert + 4) = '-';*(pcInsert + 5) = (char)((month / 10) + 0x30);*(pcInsert + 6) = (char)((month % 10) + 0x30);*(pcInsert + 7) = '-';*(pcInsert + 8) = (char)((date / 10) + 0x30);*(pcInsert + 9) = (char)((date % 10) + 0x30);*(pcInsert + 10) = ' ';*(pcInsert + 11) = 'w';*(pcInsert + 12) = 'e';*(pcInsert + 13) = 'e';*(pcInsert + 14) = 'k';*(pcInsert + 15) = ':';*(pcInsert + 16) = (char)(week + 0x30); }/*** @breif SSI的Handler句柄* @param iIndex :* @param pcInsert :* @param iInsertLen :* @retval 無*/ static u16_t SSIHandler(int iIndex, char *pcInsert, int iInsertLen) {switch (iIndex){case 0:ADC_Handler(pcInsert);break;case 1:Temperate_Handler(pcInsert);break;case 2:RTCTime_Handler(pcInsert);break;case 3:RTCdate_Handler(pcInsert);break;}return strlen(pcInsert); }/****************************************************************************/void http_Init(void) {httpd_init();http_set_ssi_handler(SSIHandler, ppcTAGs, NUM_CONFIG_SSI_TAGS); /* 配置SSI句柄 */}
/*http.h文件代碼*/ #ifndef __HTTP_H__ #define __HTTP_H__#include "main.h"#include "lwip/apps/httpd.h"#define READ_LED1 HAL_GPIO_ReadPin(LED0_GPIO_Port, LED0_Pin) #define READ_BEEP HAL_GPIO_ReadPin(LED1_GPIO_Port, LED1_Pin)void http_Init(void);#endif
- 將“http.c”文件添加到工程的http分組中
- 將“Middlewares\Third_Party\LwIP\src\apps\http\httpd.c”文件進行如下修改(注意:此處修改是博主在做項目時遇到問題做出的修改,如果你只是為了跑實驗則可以不改):
-
/*get_tag_insert函數修改成如下內容*/ #if LWIP_HTTPD_SSI /*** Insert a tag (found in an shtml in the form of "<!--#tagname-->" into the file.* The tag's name is stored in ssi->tag_name (NULL-terminated), the replacement* should be written to hs->tag_insert (up to a length of LWIP_HTTPD_MAX_TAG_INSERT_LEN).* The amount of data written is stored to ssi->tag_insert_len.** @todo: return tag_insert_len - maybe it can be removed from struct http_state?** @param hs http connection state*/ static void get_tag_insert(struct http_state *hs) { #if LWIP_HTTPD_SSI_RAWconst char *tag; #else /* LWIP_HTTPD_SSI_RAW */int tag; #endif /* LWIP_HTTPD_SSI_RAW */ // size_t len;struct http_ssi_state *ssi; #if LWIP_HTTPD_SSI_MULTIPARTu16_t current_tag_part; #endif /* LWIP_HTTPD_SSI_MULTIPART */LWIP_ASSERT("hs != NULL", hs != NULL);ssi = hs->ssi;LWIP_ASSERT("ssi != NULL", ssi != NULL); #if LWIP_HTTPD_SSI_MULTIPARTcurrent_tag_part = ssi->tag_part;ssi->tag_part = HTTPD_LAST_TAG_PART; #endif /* LWIP_HTTPD_SSI_MULTIPART */ #if LWIP_HTTPD_SSI_RAWtag = ssi->tag_name; #endif/*這行代碼的作用是清空SSI緩沖區,防止對下一次SSI請求產生干擾*/memset(ssi->tag_insert,NULL,LWIP_HTTPD_MAX_TAG_INSERT_LEN+1);if (httpd_ssi_handler #if !LWIP_HTTPD_SSI_RAW&& httpd_tags && httpd_num_tags #endif /* !LWIP_HTTPD_SSI_RAW */) {/* Find this tag in the list we have been provided. */ #if LWIP_HTTPD_SSI_RAW{ #else /* LWIP_HTTPD_SSI_RAW */for (tag = 0; tag < httpd_num_tags; tag++) {if (strcmp(ssi->tag_name, httpd_tags[tag]) == 0) #endif /* LWIP_HTTPD_SSI_RAW */{ssi->tag_insert_len = httpd_ssi_handler(tag, ssi->tag_insert,LWIP_HTTPD_MAX_TAG_INSERT_LEN #if LWIP_HTTPD_SSI_MULTIPART, current_tag_part, &ssi->tag_part #endif /* LWIP_HTTPD_SSI_MULTIPART */ #if LWIP_HTTPD_FILE_STATE, (hs->handle ? hs->handle->state : NULL) #endif /* LWIP_HTTPD_FILE_STATE */); #if LWIP_HTTPD_SSI_RAWif (ssi->tag_insert_len != HTTPD_SSI_TAG_UNKNOWN) #endif /* LWIP_HTTPD_SSI_RAW */{return;}}}}/*以下代碼是在識別到的未知的SSI標簽的位置插入“<b>***UNKNOWN TAG ***</b>”,屏蔽后將不替換*/// /* If we drop out, we were asked to serve a page which contains tags that // * we don't have a handler for. Merely echo back the tags with an error // * marker. */ //#define UNKNOWN_TAG1_TEXT "<b>***UNKNOWN TAG " //#define UNKNOWN_TAG1_LEN 18 //#define UNKNOWN_TAG2_TEXT "***</b>" //#define UNKNOWN_TAG2_LEN 7 // len = LWIP_MIN(sizeof(ssi->tag_name), LWIP_MIN(strlen(ssi->tag_name), // LWIP_HTTPD_MAX_TAG_INSERT_LEN - (UNKNOWN_TAG1_LEN + UNKNOWN_TAG2_LEN))); // MEMCPY(ssi->tag_insert, UNKNOWN_TAG1_TEXT, UNKNOWN_TAG1_LEN); // MEMCPY(&ssi->tag_insert[UNKNOWN_TAG1_LEN], ssi->tag_name, len); // MEMCPY(&ssi->tag_insert[UNKNOWN_TAG1_LEN + len], UNKNOWN_TAG2_TEXT, UNKNOWN_TAG2_LEN); // ssi->tag_insert[UNKNOWN_TAG1_LEN + len + UNKNOWN_TAG2_LEN] = 0;// len = strlen(ssi->tag_insert); // LWIP_ASSERT("len <= 0xffff", len <= 0xffff); // ssi->tag_insert_len = (u16_t)len; } #endif /* LWIP_HTTPD_SSI *//*http_find_file函數修改成如下內容*/ static err_t http_find_file(struct http_state *hs, const char *uri, int is_09) {size_t loop;struct fs_file *file = NULL;char *params = NULL;err_t err; #if LWIP_HTTPD_CGIint i; #endif /* LWIP_HTTPD_CGI */ #if !LWIP_HTTPD_SSIconst #endif /* !LWIP_HTTPD_SSI *//* By default, assume we will not be processing server-side-includes tags */u8_t tag_check = 0;/* Have we been asked for the default file (in root or a directory) ? */ #if LWIP_HTTPD_MAX_REQUEST_URI_LENsize_t uri_len = strlen(uri);if ((uri_len > 0) && (uri[uri_len - 1] == '/') &&((uri != http_uri_buf) || (uri_len == 1))) {size_t copy_len = LWIP_MIN(sizeof(http_uri_buf) - 1, uri_len - 1);if (copy_len > 0) {MEMCPY(http_uri_buf, uri, copy_len);http_uri_buf[copy_len] = 0;} #else /* LWIP_HTTPD_MAX_REQUEST_URI_LEN */if ((uri[0] == '/') && (uri[1] == 0)) { #endif /* LWIP_HTTPD_MAX_REQUEST_URI_LEN *//* Try each of the configured default filenames until we find onethat exists. */for (loop = 0; loop < NUM_DEFAULT_FILENAMES; loop++) {const char *file_name; #if LWIP_HTTPD_MAX_REQUEST_URI_LENif (copy_len > 0) {size_t len_left = sizeof(http_uri_buf) - copy_len - 1;if (len_left > 0) {size_t name_len = strlen(httpd_default_filenames[loop].name);//index.htmlsize_t name_copy_len = LWIP_MIN(len_left, name_len);MEMCPY(&http_uri_buf[copy_len], httpd_default_filenames[loop].name, name_copy_len);http_uri_buf[copy_len + name_copy_len] = 0;}file_name = http_uri_buf;} else #endif /* LWIP_HTTPD_MAX_REQUEST_URI_LEN */{file_name = httpd_default_filenames[loop].name;//文件名賦值}LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Looking for %s...\n", file_name));err = fs_open(&hs->file_handle, file_name);//打開文件 file_name儲存要打開文件的名稱if (err == ERR_OK) {uri = file_name;file = &hs->file_handle;LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Opened.\n")); #if LWIP_HTTPD_SSItag_check = httpd_default_filenames[loop].shtml; #endif /* LWIP_HTTPD_SSI */break;}}}if (file == NULL) {/* No - we've been asked for a specific file. *//* First, isolate the base URI (without any parameters) */params = (char *)strchr(uri, '?');if (params != NULL) {/* URI contains parameters. NULL-terminate the base URI */*params = '\0';params++;}#if LWIP_HTTPD_CGIhttp_cgi_paramcount = -1;/* Does the base URI we have isolated correspond to a CGI handler? */if (httpd_num_cgis && httpd_cgis) {for (i = 0; i < httpd_num_cgis; i++) {if (strcmp(uri, httpd_cgis[i].pcCGIName) == 0) {/** We found a CGI that handles this URI so extract the* parameters and call the handler.*/ // http_cgi_paramcount = extract_uri_parameters(hs, params); // uri = httpd_cgis[i].pfnCGIHandler(i, http_cgi_paramcount, hs->params, // hs->param_vals);char date[strlen(params)];strcpy(date,params);http_cgi_paramcount = extract_uri_parameters(hs, params);uri = httpd_cgis[i].pfnCGIHandler(i, http_cgi_paramcount, hs->params,hs->param_vals, date);break;}}} #endif /* LWIP_HTTPD_CGI */LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Opening %s\n", uri));err = fs_open(&hs->file_handle, uri);//打開文件名 uri儲存要打開文件的名稱if (err == ERR_OK) {file = &hs->file_handle;} else {file = http_get_404_file(hs, &uri);} #if LWIP_HTTPD_SSIif (file != NULL) {if (file->flags & FS_FILE_FLAGS_SSI) {tag_check = 1;} else { #if LWIP_HTTPD_SSI_BY_FILE_EXTENSIONtag_check = http_uri_is_ssi(file, uri); #endif /* LWIP_HTTPD_SSI_BY_FILE_EXTENSION */}} #endif /* LWIP_HTTPD_SSI */}if (file == NULL) {/* None of the default filenames exist so send back a 404 page */file = http_get_404_file(hs, &uri);}return http_init_file(hs, file, is_09, uri, tag_check, params); }
- main.c開頭的“#include "lwip/apps/httpd.h" ”替換成“#include "http.h" ”
- main函數while(1)前的“httpd_init(); ”替換成“http_Init(); ”
????????至此就修改完成了,編譯0警告0錯誤,下載后在瀏覽器訪問板子IP就可以看到可以打開網頁,之后進入網頁中的“ADC/內部溫度傳感器”或者“RTC實時時鐘”頁面可以看到有數值,里面的內容就是“ADC_Handler”、“Temperate_Handler”、“RTCTime_Handler”、和“RTCdate_Handler”這四個函數中的值,這里博主就沒有編寫ADC、RTC的驅動,只用了幾個固定值代替,讀者可以自行下載源代碼,修改其中的值編譯測試。
2.5 CGI功能實現
?????????本實驗代碼在《SSI功能實現》章節代碼的基礎上修改。
- 在“lwipopts.h”文件中添加以下內容:“#define LWIP_HTTPD_CGI ? ? ? ? ? ?1”
- 在"http.c"文件“http_Init”函數前增加以下內容:
-
/************************CGI相關**************************************/#define NUM_CONFIG_CGI_URIS 2 /* CGI的URI數量 *//* 控制LED和BEEP的CGI handler */ const char *LEDS_CGI_Handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[],char *hotel_str); const char *BEEP_CGI_Handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[],char *hotel_str);static const tCGI ppcURLs[] = /* cgi程序 */ {{"/leds.cgi", LEDS_CGI_Handler},{"/beep.cgi", BEEP_CGI_Handler}, };/*** @breif 當web客戶端請求瀏覽器的時候,使用此函數被CGI handler調用* @param pcToFind :* @param pcParam :* @param iNumParams :* @retval 無*/ static int FindCGIParameter(const char *pcToFind, char *pcParam[], int iNumParams) {int iLoop;for (iLoop = 0; iLoop < iNumParams; iLoop++){if (strcmp(pcToFind, pcParam[iLoop]) == 0){return (iLoop); /* 返回iLOOP */}}return (-1); }/*** @breif CGI LED控制句柄* @param iIndex : CGI句柄索引號* @param iNumParams :* @param pcParam :* @param pcValue :* @retval 無*/ const char *LEDS_CGI_Handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[],char *hotel_str) {uint8_t i = 0; /* 注意根據自己的GET的參數的多少來選擇i值范圍 */iIndex = FindCGIParameter("LED1", pcParam, iNumParams); /* 找到led的索引號 *//* 只有一個CGI句柄 iIndex=0 */if (iIndex != -1){ // HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,GPIO_PIN_SET); // HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_SET);for (i = 0; i < iNumParams; i++) /* 檢查CGI參數: example GET /leds.cgi?led=2&led=4 */{if (strcmp(pcParam[i], "LED1") == 0) /* 檢查參數"led" */{if (strcmp(pcValue[i], "LED1ON") == 0) /* 改變LED1狀態 */{HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_RESET); /* 打開LED1 */}else if (strcmp(pcValue[i], "LED1OFF") == 0){HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_SET); /* 關閉LED1 */}}}}if (READ_LED1 == 0 && READ_BEEP == 0){return "/STM32F407LED_ON_BEEP_ON.shtml"; /* LED1開,BEEP開 */}else if (READ_LED1 == 0 && READ_BEEP == 1){return "/STM32F407LED_ON_BEEP_OFF.shtml"; /* LED1開,BEEP關 */}else if (READ_LED1 == 1 && READ_BEEP == 1){return "/STM32F407LED_OFF_BEEP_OFF.shtml"; /* LED1關,BEEP關 */}else{return "/STM32F407LED_OFF_BEEP_ON.shtml"; /* LED1關,BEEP開 */} }/*** @breif BEEP的CGI控制句柄* @param iIndex : CGI句柄索引號* @param iNumParams :* @param pcParam :* @param pcValue :* @retval 無*/ const char *BEEP_CGI_Handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[],char *hotel_str) {uint8_t i = 0;iIndex = FindCGIParameter("BEEP", pcParam, iNumParams); /* 找到BEEP的索引號 */if (iIndex != -1) /* 找到BEEP索引號 */{ // HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,GPIO_PIN_SET); // HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_SET); for (i = 0; i < iNumParams; i++){if (strcmp(pcParam[i], "BEEP") == 0) /* 查找CGI參數 */{if (strcmp(pcValue[i], "BEEPON") == 0) /* 打開BEEP */{HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);}else if (strcmp(pcValue[i], "BEEPOFF") == 0) /* 關閉BEEP */{HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);}}}}if (READ_LED1 == 0 && READ_BEEP == 0){return "/STM32F407LED_ON_BEEP_ON.shtml"; /* LED1開,BEEP開 */}else if (READ_LED1 == 0 && READ_BEEP == 1){return "/STM32F407LED_ON_BEEP_OFF.shtml"; /* LED1開,BEEP關 */}else if (READ_LED1 == 1 && READ_BEEP == 1){return "/STM32F407LED_OFF_BEEP_OFF.shtml"; /* LED1關,BEEP關 */}else{return "/STM32F407LED_OFF_BEEP_ON.shtml"; /* LED1關,BEEP開 */} }/****************************************************************************/
- 在"http.c"文件“http_Init”函數最后增加以下內容:
-
http_set_cgi_handlers(ppcURLs, NUM_CONFIG_CGI_URIS); /* 配置CGI句柄 */
- 注銷“stm32f4xx_it.c”中關于LED反轉的內容;
- main函數“http_Init();”前添加以下內容:
-
HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,GPIO_PIN_SET);HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_SET);
- 將“Middlewares\Third_Party\LwIP\src\include\lwip\apps\httpd.h”文件中關于“tCGIHandler”的定義修改成如下內容:
-
//typedef const char *(*tCGIHandler)(int iIndex, int iNumParams, char *pcParam[], // char *pcValue[]); /*新增加的參數表示CGI請求的具體內容,可在CGI請求處理函數中通過printf打印具體的請求內容*/ typedef const char *(*tCGIHandler)(int iIndex, int iNumParams, char *pcParam[],char *pcValue[], char *hotel_str);
至此就修改完成了,編譯0警告0錯誤,下載后在瀏覽器訪問板子IP就可以看到可以打開網頁,之后進入網頁中的“LED/BEEP控制”就可以通過按鈕控制板子上的2個LED。
3、實現網頁功能
????????本實驗代碼在《CGI功能實現》章節代碼的基礎上修改。
- 在“lwipopts.h”文件中添加以下內容:“#define LWIP_HTTPD_SUPPORT_POST ? ?? ??? ??? ?1”
- http.c文件最后添加以下內容:
-
/************************************HTTP POST 請求*************************************************/ uint8_t login_flag = 0;/* 開始處理http post請求*/ err_t httpd_post_begin(void *connection, const char *uri, const char *http_request, u16_t http_request_len, int content_len, char *response_uri, u16_t response_uri_len, u8_t *post_auto_wnd) {/*http_request是http header的全部內容,http_request_len是http header的總長度,content_len是全部表單內容的總長度。 */printf("[httpd_post_begin] connection=0x%p, uri=%s\n", connection, uri);//打印請求的內容//printf("%.*s\n", http_request_len, http_request);//打印完整的POST請求if (strcmp(uri, "/checklogin.cgi") == 0)/*如果是提交登錄信息*/{ return ERR_OK;}return ERR_ARG; }char *POST_rec;/* 接收表單數據 */ err_t httpd_post_receive_data(void *connection, struct pbuf *p) {int len;struct pbuf *q;char *p1, *p2;printf("[httpd_post_receive_data] connection=0x%p, payload=0x%p, len=%d\n", connection, p->payload, p->tot_len);for (q = p; q != NULL; q = q->next)printf("\n%.*s", q->len, (char *)q->payload);len = len + p->len;printf("\n");printf("\n密碼判斷\n");p1 = strstr(p->payload, "username=");p2 = strstr(p->payload, "&login=");if( (p1 != NULL)&&(p2 != NULL) ){char user_login[p2-p1];char local_info[50] = "";memcpy(user_login, p1, (p2-p1));sprintf(local_info,"username=%s&password=%s","stm32","stm32");//printf("\nuser_login:%s\n",user_login);//printf("\nlocal_info:%s\n",local_info);if( ((p2-p1)==strlen(local_info))&&(strncmp(p1,local_info,strlen(local_info)) == 0) ){login_flag = 1;printf("\n賬號密碼正確\n");}else{printf("\n賬號密碼錯誤\n");}} return ERR_OK; }/* 結束處理http post請求*/ void httpd_post_finished(void *connection, char *response_uri, u16_t response_uri_len) {/*沒有對response_uri字符數組賦值的話,最終瀏覽器顯示的頁面為404錯誤頁面,提示找不到網頁。如果對response_uri賦了值,那么就顯示response_uri字符串指定的網頁。*///strlcpy(response_uri, "/success.html", response_uri_len);//printf("[httpd_post_finished] connection=0x%p\n", connection);if(login_flag) strlcpy(response_uri, "/index.html",response_uri_len);else strlcpy(response_uri, "/login.html",response_uri_len); } /************************************HTTP POST 請求*************************************************/
- 將“Middlewares\Third_Party\LwIP\src\apps\http\httpd.c”文件進行如下修改:
-
/*開頭增加外部變量聲明*/ extern uint8_t login_flag;/*將http_find_file函數最后一句“return http_init_file(hs, file, is_09, uri, tag_check, params);”替換成如下內容*/// return http_init_file(hs, file, is_09, uri, tag_check, params);if(login_flag){return http_init_file(hs, file, is_09, uri, tag_check, params);}else{uri = "/login.html";fs_open(&hs->file_handle, uri);//′ò?aμ???ò3//printf("?′μ???\n");return http_init_file(hs, file, is_09, uri, tag_check, params);}
- main函數“http_Init();”前添加以下內容:
- 注銷“stm32f4xx_it.c”中關于LED反轉的內容;
- main函數“http_Init();”前添加以下內容:
- 注銷“stm32f4xx_it.c”中關于LED反轉的內容;
- main函數“http_Init();”前添加以下內容:
至此就修改完成了,編譯0警告0錯誤,下載后在瀏覽器訪問板子IP就可以看到登錄頁面,登錄的用戶名和密碼都是“stm32”,登錄成功后就可以看到《CGI功能實現》章節的內容了。同時串口也會打印登錄過程信息:
? 如果要修改登錄的用戶名和密碼僅需修改“http.c”中的“httpd_post_receive_data”以下內容即可:
最后,本次實驗的內容就到此結束了,簡單的向大家介紹了STM32+LWIP實現http server的過程,本章節實驗源碼、網頁源文件、網頁數組生成工具均在此: