RT-Thread 使用 webserver (lwip协议栈 自带httpd )

avatar
作者
筋斗云
阅读量:1

参考正点原子的 网络实验10 NETCONN_WEBserver实验和《lwIP开发指南》。

开发环境:野火的stm32f407,rt-thread studio版本是: 2.2.6,stm32f4的资源包为0.2.2,rt-thread版本为4.0.3。

以RT-Thread中Lan8720和lwip协议栈的使用文章创建的工程为基础。

httpd(The Apache HTTP Server)的官方网址:

官方网址](https://httpd.apache.org/

在rtthread工程中新建文件夹webserver,存放webserver相关文件。

先对工程进行编译,正常通过。

需要修改的代码,过程如下:

  1. rt-thread\components\net\lwip-2.0.2\src\include\lwip\apps\httpd_opts.h 文件中的宏定义

  • LWIP_HTTPD_CGI 默认为0,改为1

  • LWIP_HTTPD_SSI 默认为0,改为1

  • HTTPD_USE_CUSTOM_FSDATA默认为0

  • LWIP_HTTPD_DYNAMIC_FILE_READ默认为0,改为1

2. 将 rt-thread\components\net\lwip-2.0.2\src\apps\httpd文件夹 添加构建

3. httpd文件夹下的fsdata.c 排除构建。

4. 在主函数中增加如下代码:

extern void httpd_init(void);   httpd_init();   while (count++)   {           LOG_D("Hello RT-Thread!");           rt_thread_mdelay(10000);   }

编译正常,下载到开发板,在浏览器输入ip地址,效果如图1:

fa1c9703fa5c5e7c069faf9818693c33.png

如何使用自己的网页呢?

修改如下:

将rt-thread\components\net\lwip-2.0.2\src\apps\httpd文件夹下的fsdata.c替换成自己的fsdata.c,(使用makefsdata.exe这个软件自动生成即可)。

在webserve文件夹下创建httpd_cgi_ssi.c文件(CGI和SSI句柄函数)

代码如下:

#include <lwip/apps/httpd.h> #include "lwip/tcp.h" #include <lwip/apps/fs.h>   #include <string.h> #include <stdlib.h>     int LED1=0; int BEEP=0;       #define NUM_CONFIG_CGI_URIS (sizeof(ppcURLs) / sizeof(tCGI)) #define NUM_CONFIG_SSI_TAGS (sizeof(ppcTAGs) / sizeof(char *))   //extern short Get_Temprate(void); //extern void RTC_Get_Time(u8 *hour,u8 *min,u8 *sec,u8 *ampm); //extern void RTC_Get_Date(u8 *year,u8 *month,u8 *date,u8 *week);   //控制LED的CGI handler const char* LEDS_CGI_Handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]); const char* BEEP_CGI_Handler(int iIndex,int iNumParams,char *pcParam[],char *pcValue[]);   static const char *ppcTAGs[]=  //SSI的Tag {     "t", //ADC值     "w", //温度值     "h", //时间     "y"  //日期 };     static const tCGI ppcURLs[]= //cgi程序 {     {"/leds.cgi",LEDS_CGI_Handler},     {"/beep.cgi",BEEP_CGI_Handler}, };     //当web客户端请求浏览器的时候,使用此函数被CGI handler调用 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); }     //SSIHandlerÖ中adc处理函数 void ADC_Handler(char *pcInsert) {      char Digit1=0, Digit2=0, Digit3=0, Digit4=0;     static uint32_t ADCVal = 0;          //ADCVal = Get_Adc_Average(5,10);//ADC1_CH5的电压值     ADCVal+=10;     ADCVal=ADCVal%3000;        //转换为 ADCVval * 0.8mv      ADCVal = (uint32_t)(ADCVal * 0.8);        Digit1= ADCVal/1000;      Digit2= (ADCVal-(Digit1*1000))/100 ;      Digit3= (ADCVal-((Digit1*1000)+(Digit2*100)))/10;      Digit4= ADCVal -((Digit1*1000)+(Digit2*100)+ (Digit3*10));        /* 准备添加到html中的数据 */      *pcInsert       = (char)(Digit1+0x30);      *(pcInsert + 1) = (char)(Digit2+0x30);      *(pcInsert + 2) = (char)(Digit3+0x30);      *(pcInsert + 3) = (char)(Digit4+0x30); }   //SSIHandler中需要用到的内部处理温度传感器 void Temperate_Handler(char *pcInsert) {     char Digit1=0, Digit2=0, Digit3=0, Digit4=0,Digit5=0;     static short Temperate = 0;       //Temperate = Get_Temprate();     Temperate+=1.3;     Digit1 = Temperate / 10000;     Digit2 = (Temperate % 10000)/1000;     Digit3 = (Temperate % 1000)/100 ;     Digit4 = (Temperate % 100)/10;     Digit5 = Temperate % 10;     /* 准备添加到html中的数据 */     *pcInsert       = (char)(Digit1+0x30);     *(pcInsert+1) = (char)(Digit2+0x30);     *(pcInsert+2)   =   (char)(Digit3+0x30);     *(pcInsert+3) = '.';     *(pcInsert+4) = (char)(Digit4+0x30);     *(pcInsert+5) = (char)(Digit5+0x30); }   //SSIHandler中需要用到的处理RTC日时间的函数 void RTCTime_Handler(char *pcInsert) {     static uint8_t  hour,min,sec,ampm;       hour++;     min++;     sec++;     ampm++;     //RTC_Get_Time(&hour,&min,&sec,&ampm);         /* 准备添加到html中的数据 */     *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); }   //SSIHandler中需要用到的处理RTC日期的函数 void RTCdate_Handler(char *pcInsert) {     static uint8_t year,month,date,week;     //RTC_Get_Date(&year,&month,&date,&week);     year++;     month++;     date++;     week++;       /* 准备添加到html中的数据 */     *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);   } //SSI的 Handler 句柄 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); }   //CGI LED控制句柄 const char* LEDS_CGI_Handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) {     uint8_t i=0;  //注意根据自己的GET的参数的多少来选择i值范围       iIndex = FindCGIParameter("LED1",pcParam,iNumParams);  //找到LED的索引号     //只有一个CGI句柄 iIndex=0     if (iIndex != -1)     {         LED1=1;         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=0;                 rt_kprintf("LED1ON\n");             }             else if(strcmp(pcValue[i],"LED1OFF") == 0)             {                 LED1=1;                 rt_kprintf("LED1OFF\n");             }           }         }      }     if(LED1 == 0 && BEEP == 0)      return "/STM32F407LED_ON_BEEP_OFF.shtml";   //     else if(LED1 == 0 && BEEP == 1) return "/STM32F407LED_ON_BEEP_ON.shtml";    //     else if(LED1 == 1 && BEEP == 1) return "/STM32F407LED_OFF_BEEP_ON.shtml";   //     else return "/STM32F407LED_OFF_BEEP_OFF.shtml";                             // }   //BEEP的CGI控制句柄 const char *BEEP_CGI_Handler(int iIndex,int iNumParams,char *pcParam[],char *pcValue[]) {     uint8_t i=0;     iIndex = FindCGIParameter("BEEP",pcParam,iNumParams);  //找到BEEP的索引号     if(iIndex != -1) //找到BEEP的索引号     {         BEEP=0;  //         for(i = 0;i < iNumParams;i++)         {             if(strcmp(pcParam[i],"BEEP") == 0)  //             {                 if(strcmp(pcValue[i],"BEEPON") == 0) //                 {                     BEEP = 1;                     rt_kprintf("BEEPON\n");                 }                 else if(strcmp(pcValue[i],"BEEPOFF") == 0) //                 {                     BEEP = 0;                     rt_kprintf("BEEPOFF\n");                 }             }         }     }     if(LED1 == 0 && BEEP == 0)      return "/STM32F407LED_ON_BEEP_OFF.shtml";   //     else if(LED1 == 0 && BEEP == 1) return "/STM32F407LED_ON_BEEP_ON.shtml";    //     else if(LED1 == 1 && BEEP == 1) return "/STM32F407LED_OFF_BEEP_ON.shtml";   //     else return "/STM32F407LED_OFF_BEEP_OFF.shtml";   //   }   //SSI句柄初始化 void httpd_ssi_init(void) {       //配置内部温度传感器的SSI句柄     http_set_ssi_handler(SSIHandler,ppcTAGs,NUM_CONFIG_SSI_TAGS); }   //CGI句柄初始化 void httpd_cgi_init(void) {    //配置CGI句柄 LEDs control CGI) */   http_set_cgi_handlers(ppcURLs, NUM_CONFIG_CGI_URIS); }

主函数中代码如下:

extern void httpd_ssi_init(void);     extern void httpd_cgi_init(void);     extern void httpd_init(void);     httpd_cgi_init();     httpd_ssi_init();     httpd_init();

 重新编译,下载到开发板,在浏览器输入开发板ip地址,查看效果。效果如图2:

b356631ad0508004c80bafa8a2d31f74.jpeg

LWIP HTTP 协议中默认只支持GET方法 但是一般提交表单时都用POST方法 而LWIPPOST方案需要自己实现 不过LWIP已经需要实现的函数声明在httpd.h中了。post的例程:

lwip/post_example.c at master · particle-iot/lwip (github.com)

5ec4adc3b510a2d1e42bde52786d5cd1.jpeg

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!