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

参考正点原子的 网络实验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

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值