硬汉嵌入式论坛

 找回密码
 立即注册
查看: 2338|回复: 8
收起左侧

[RL-TCPnet教程] 【RL-TCPnet网络教程】第47章 RL-TCPnet之Web服务器的CGI实现

[复制链接]

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
发表于 2018-1-12 15:23:22 | 显示全部楼层 |阅读模式
第47章      RL-TCPnet之Web服务器的CGI实现

     本章节为大家讲解RL-TCPnet的CGI脚本实现动态网页,前面第44章讲解了静态网页的设计,本章的动态网页是在静态网页的基础上实现,所以学习本章节前,务必保证已经掌握了静态网页的设计方法。
      本章教程含STM32F407开发板和STM32F429开发板。
47.1 初学者重要提示
47.2 CGI函数
47.3 HTTP配置说明(Net_Config.c)
47.4 HTTP调试说明(Net_Debug.c)
47.5 制作HTML和CGI脚本文件
47.6 访问开发板Web服务器的方法
47.7 HTTP_CGI.c文件中接口函数讲解说明
47.8 实验例程说明(RTX)
47.9      总结



47.1  初学者重要提示
1、学习本章节前,务必保证已经学习了第44,45和46章节,如果没有学习就直接学习本章节的话,将比较吃力,特别是CGI相关知识点的理解、网页制作以及工程建立的时候。
2、使用CGI脚本做网页更新时,整个页面都会重新加载,而后面章节学习的Ajax可以做网页局部刷新。

努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2018-1-12 15:35:23 | 显示全部楼层
本帖最后由 席萌0209 于 2018-1-12 15:36 编辑

47.2  CGI函数
      CGI脚本涉及到以下5个函数:
(1)cgi_func
(2)cgi_process_data
(3)cgi_process_var
(4)http_accept_host
(5)cgx_content_type
关于这5个函数的讲解及其使用方法可以看教程第 3 章 3.4 小节里面说的参考资料 rlarm.chm 文件:
7.1.png
                              
本章节除了讲解以上5个函数外,还需要讲解下面这个函数:http_get_var (这个函数在HTTP函数部分
关于这些函数注意以下两点:
1、CGI的所有函数都不支持重入,也就是不支持多任务调用。
2、通过CGI脚本就可以实现动态HTML网页了。

47.2.1    函数cgi_func
函数原型:
  1. U16 cgi_func (

  2.     U8*  env,       /* 输入字符串地址 */

  3.     U8*  buf,       /* 输出缓冲区地址 */

  4.     U16  buflen,    /* 输出缓冲区大小,单位字节*/

  5.     U32* pcgi );    /* 指针变量,指向一个不会被改变的变量 */
复制代码
函数描述:
函数cgi_func由RL-TCPnet脚本解析器调用,当解析RL-TCPnet的脚本时(以cgi结尾的脚本文件),输出HTTP响应的动态部分。脚本文件每个以命令c开头的语句,脚本解析器都会调用函数cgi_func。所以用户必须要编写此函数,以便解析和使用脚本文件中的输入字符。
1、第1个参数是CGI脚本的输入字符串地址,函数cgi_func需要这个参数创建动态响应。这个字符串就是CGI脚本文件中以命令c开头的语句中的字符串,字节数是相同的(不含控制字符,仅HTTP代码部分)。
2、第2个参数是输出缓冲区地址,用于写入HTTP响应字符串。
3、第3个参数是输出缓冲区大小,单位字节。
4、第4个参数是指向不会被HTTP服务器更改的变量,因此,用户可以用它存储函数cgi_func连续调用的参数,比如循环计数器、发送字节数、状态缓冲区地址等,亦或者任何其它应用均可。
5、返回值,返回写入到输出缓冲区的字节数。返回值是U16类型的,其中bit15和bit14还可以作为其它用途,而剩余的bit0-bit13表示的最大值是16383,足够表示TCP Socket的MSS最大报文段大小的1460字节。
      (1)bit15作为函数cgi_func是否重复调用的标志,如果此位设置为1,表示退出函数后,依然保持参数env, buflen和 pcgi的数值,并再次调用函数cgi_func,而参数buf会根据用户写入到输出缓冲区的字节数进行自动调整。如果此位设置为0,将不再重复调用。
      (2)如果bit14设置为1,取消数据包优化(见下面注意事项4),当前数据包立即被发送。如果bit14为0,不执行此操作。
使用这个函数要注意以下问题:
1.     写入到输出缓冲区的代码必须是HTML格式。
2.     CGI脚本中的c命令才会触发此函数。
3.     输出缓冲区的大小buflen会有所不同,因为输出缓冲区的大小是由TCP Socket的MSS最大报文段大小协商决定,局域网中一般是1400字节左右,但是也可减小到500字节,甚至更小。
4.     输出缓冲区的不同大小还有一个原因是HTTP Server会尝试优化生成的TCP数据包数,并将再次调用函数cgi_func来使用所有可用的缓冲区。当缓冲区中只有240个或更少的字节空闲时,将停止调用函数cgi_func,然后生成并发送数据包。如果要强制HTTP Server发送数据包,则此函数的返回值bit14置1。
5.     写到输出缓冲区的数据,不可以超过第三个参数buflen的大小,否则会造成内存指针链表的损坏,从而很容易造成系统崩溃。
6.     第1个参数的输入字符串可能包含单字符子命令,以此来告诉cgi_func如何正确的处理脚本。这些子命令没有规则,因此用户可以创建和使用自己的命令。
7.     对于每个HTTP会话,*pcgi(注意,这里是指的指针变量pcgi所指向的存储单元)变量都是独立的,也就是说新创建一个会话,都会有一个独立的*pvar变量。另外,每个会话首次调用函数cgi_func之前都会将变量*pcgi清零(注意,这里是指的指针变量pvar所指向的存储单元清零)。
8.     每次调用函数cgi_func必须更新*pcgi(注意,这里是指的指针变量pcgi所指向的存储单元)的内容,用户可以使用这个4字节变量存储任何格式的数据(官方手册中说的是必须更新,实际上,用不上的话,不用管)。
使用举例:
  1. U16 cgi_func (U8 *env, U8 *buf, U16 buflen, U32 *pcgi) {

  2.   U16 len = 0;



  3.   switch (env[0]) {

  4.     /* Analyze the environment string. It is the script 'c' line starting */

  5.     /* at position 2. What you write to the script file is returned here. */

  6.     case 'a' :

  7.       /* Network parameters - file 'network.cgi' */

  8.        ..

  9.       break;



  10.     case 'b':

  11.       /* LED control - file 'led.cgi' */

  12.        ..

  13.       break;



  14.     case 'c':

  15.       /* TCP status - file 'tcp.cgi' */

  16.        ..

  17.       break;



  18.     case 'd':

  19.       /* System password - file 'system.cgi' */

  20.       switch (env[2]) {

  21.         case '1':

  22.           len = sprintf(buf,&env[4],http_EnAuth ? "Enabled" : "Disabled");

  23.           break;

  24.         case '2':

  25.           len = sprintf(buf,&env[4],http_auth_passw);

  26.           break;

  27.       }

  28.       break;

  29.   }

  30.   return (len);

  31. }
复制代码

47.2.2   函数cgi_process_data
函数原型:
  1. void cgi_process_data (

  2.     U8  code,     /* 接收数据缓冲区中的数据类型 */

  3.     U8* dat,      /* 来自POST方式的字符串地址 */

  4.     U16 len );    /* 字符串的字节数 */
复制代码
函数描述:
函数cgi_process_data处理CGI POST方式返回的数据。当用户使用Web浏览器操作POST方式的HTTP表时(如单选按钮、复选框、选择列表等),HTTP服务器会调用此函数。
1、函数cgi_process_data的三个参数与下表的对应关系:
      “代码”对应第1个参数code。
      “dat指针变量含义”对应第2个参数dat。
      “变量len的含义”对应第3个参数len。
7.2.png
使用这个函数要注意以下问题:
1.     仅POST方式才会触发HTTP服务器调用此函数,即METHOD = POST。
  1. <FORM ACTION=index.htm METHOD=POST NAME=CGI>

  2. ..

  3. </FORM>
复制代码
2.     Web浏览器提供HTTP上传文件的文件名及其路径,而删除文件名中的路径信息是用户的责任。
3.     对于大文件,文件数据将分多次数据包进行接收。数据包的大小取决于TCP的MSS最大报文段大小,一般是1460字节。
4.     XML-POST是由webservice application生成的,例如微软的Silverlight。
使用举例:
  1. void cgi_process_data (U8 code, U8 *dat, U16 len) {

  2.   /* This function is called by HTTP server to process the returned Data    */

  3.   /* for the CGI Form POST method. It is called on SUBMIT from the browser. */

  4.   /* Parameters:                                                            */

  5.   /*   code  - callback context code                                        */

  6.   /*           0 = www-url-encoded form data                                */

  7.   /*           1 = filename for file upload (0-terminated string)           */

  8.   /*           2 = file upload raw data                                     */

  9.   /*           3 = end of file upload (file close requested)                */

  10.   /*           4 = any xml encoded POST data (single or last stream)        */

  11.   /*           5 = the same as 4, but with more xml data to follow          */

  12.   /*               Use http_get_content_type() to check the content type    */

  13.   /*   dat   - pointer to POST received data                                */

  14.   /*   len   - received data length                                         */

  15.   U8 *var;



  16.   switch (code) {

  17.     case 0:

  18.       /* Url encoded form data received. */

  19.       break;



  20.     case 1:

  21.       /* Filename for file upload received as encoded by the browser. */

  22.       /* It might contain an absolute path to a file from the sending */

  23.       /* host. Open a file for writing. */

  24.       return;



  25.     case 2:

  26.       /* File content data received. Write data to a file. */

  27.       /* This function will be called several times with   */

  28.       /* code 2 when a big file is being uploaded.         */

  29.       return;



  30.     case 3:

  31.       /* File upload finished. Close a file. */

  32.       return;



  33.     case 4:

  34.       /* XML encoded content type, last packet. */

  35.      // pType = http_get_content_type ();

  36.       /* check the content type for CGX file request. */

  37.       /* pType is a pointer to a 0-terminated string  */

  38.       /* For example: text/xml; charset=utf-8         */

  39.       return;

  40.    

  41.     case 5:

  42.       /* XML encoded as under 4, but with more to follow. */

  43.       return;



  44.     default:

  45.       /* Ignore all other codes. */

  46.       return;

  47.   }



  48.   if (len == 0) {

  49.     /* No data or all items (radio, checkbox) are off. */

  50.     return;

  51.   }



  52.   var = (U8 *)alloc_mem (40);



  53.   do {

  54.     /* Parse all returned parameters. */

  55.     dat = http_get_var (dat, var, 40);

  56.     if (var[0] != 0) {

  57.        if (str_scomp (var, "TICK1=") == __TRUE || str_scomp (var, "pg=") == __TRUE)

  58.        {

  59.           if (str_scomp (var, "pg=") == __TRUE)

  60.           {

  61.               LEDControl = 0;

  62.           }

  63.          

  64.           if(*(var+9) =='1')

  65.           {

  66.             LEDControl |= 0x01;

  67.           }

  68.           else if(*(var+9) =='2')

  69.           {

  70.             LEDControl |= 0x02;

  71.           }

  72.           else if(*(var+9) =='3')

  73.           {

  74.             LEDControl |= 0x04;

  75.           }

  76.       }

  77.     }

  78.   }while (dat);

  79.   free_mem ((OS_FRAME *)var);





  80.   if(LEDControl & 0x01)

  81.   {

  82.      bsp_LedOn(1);

  83.   }

  84.   else

  85.   {

  86.      bsp_LedOff(1);   

  87.   }



  88.   if(LEDControl & 0x02)

  89.   {

  90.      bsp_LedOn(2);

  91.   }

  92.   else

  93.   {

  94.      bsp_LedOff(2);   

  95.   }



  96.   if(LEDControl & 0x04)

  97.   {

  98.      bsp_LedOn(3);

  99.   }

  100.   else

  101.   {

  102.      bsp_LedOff(3);   

  103.   }



  104. }
复制代码

47.2.3   函数cgi_process_var
函数原型:
  1. void cgi_process_var (

  2.     U8* qs );    /* Pointer to QUERY_STRING returned from the GET method. */
复制代码
函数描述:
函数cgi_process_var处理从CGI GET方式返回的环境变量QUERY_STRING(就是个字符串),当用户使用Web浏览器操作GET方式的HTTP表单时(如单选按钮、复选框、选择列表等),HTTP服务器会调用此函数。
1、第1个参数是环境变量QUERY_STRING的地址,实际就是个字符串地址。
使用这个函数要注意以下问题:
1.     环境变量QUERY_STRING以空格结尾,即此字符串以空格结尾。
2.     仅GET方式才会触发HTTP服务器调用此函数,即METHOD = GET。
  1. <FORM ACTION=index.htm METHOD=GET NAME=CGI>

  2. ..

  3. </FORM>
复制代码
使用举例:
  1. void cgi_process_var (U8 *qs) {

  2.   /* This function is called by HTTP server to process the Querry_String   */

  3.   /* for the CGI Form GET method. It is called on SUBMIT from the browser. */

  4.   /*.The Querry_String.is SPACE terminated.                                */

  5.   U8 *var;

  6.   int s[4];



  7.   var = (U8 *)alloc_mem (40);

  8.   do {

  9.     /* Loop through all the parameters. */

  10.     qs = http_get_var (qs, var, 40);

  11.     /* Check the returned string, 'qs' now points to the next. */

  12.     if (var[0] != 0) {

  13.       /* Returned string is non 0-length. */

  14.       if (str_scomp (var, "ip=") == __TRUE) {

  15.         /* My IP address parameter. */

  16.         sscanf ((const char *)&var[3], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);

  17.         LocM.IpAdr[0]   = s[0];

  18.         LocM.IpAdr[1]   = s[1];

  19.         LocM.IpAdr[2]   = s[2];

  20.         LocM.IpAdr[3]   = s[3];

  21.       }

  22.       else if (str_scomp (var, "msk=") == __TRUE) {

  23.         /* Net mask parameter. */

  24.         sscanf ((const char *)&var[4], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);

  25.         LocM.NetMask[0] = s[0];

  26.         LocM.NetMask[1] = s[1];

  27.         LocM.NetMask[2] = s[2];

  28.         LocM.NetMask[3] = s[3];

  29.       }

  30.       else if (str_scomp (var, "gw=") == __TRUE) {

  31.         /* Default gateway parameter. */

  32.         sscanf ((const char *)&var[3], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);

  33.         LocM.DefGW[0]   = s[0];

  34.         LocM.DefGW[1]   = s[1];

  35.         LocM.DefGW[2]   = s[2];

  36.         LocM.DefGW[3]   = s[3];

  37.       }

  38.       else if (str_scomp (var, "pdns=") == __TRUE) {

  39.         /* Default gateway parameter. */

  40.         sscanf ((const char *)&var[5], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);

  41.         LocM.PriDNS[0]  = s[0];

  42.         LocM.PriDNS[1]  = s[1];

  43.         LocM.PriDNS[2]  = s[2];

  44.         LocM.PriDNS[3]  = s[3];

  45.       }

  46.       else if (str_scomp (var, "sdns=") == __TRUE) {

  47.         /* Default gateway parameter. */

  48.         sscanf ((const char *)&var[5], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);

  49.         LocM.SecDNS[0]  = s[0];

  50.         LocM.SecDNS[1]  = s[1];

  51.         LocM.SecDNS[2]  = s[2];

  52.         LocM.SecDNS[3]  = s[3];

  53.       }

  54.     }

  55.   }while (qs);

  56.   free_mem ((OS_FRAME *)var);

  57. }
复制代码

47.2.4   函数http_accept_host
函数原型:
  1. BOOL http_accept_host (

  2.     U8* rem_ip,      /* 远程设备IP地址 */

  3.     U16 rem_port );  /* 远程设备端口号 */
复制代码
函数描述:
函数http_accept_host用于设置是否接受远程连接,用户可以通过此函数选择允许哪些设备可以连接,哪些不可以连接。
1、第1个参数是远程设备的IP地址。
2、第2个参数是远程设备的端口号。
3、返回值,返回__TRUE表示允许此远程连接,返回__FALSE表示不允许此远程连接。
使用这个函数要注意以下问题:
1.     此函数是可选的,如果大家在工程中没有写这个函数,RL-TCPnet库会调用默认的函数,允许所有的连接请求,如果在工程中写了此函数,会执行新写的这个函数。
使用举例:
  1. BOOL http_accept_host (U8 *rem_ip, U16 rem_port) {



  2.   if (rem_ip[0] == 192  &&

  3.       rem_ip[1] == 168  &&

  4.       rem_ip[2] == 1    &&

  5.       rem_ip[3] == 1) {

  6.     /* 接受此连接. */

  7.     return (__TRUE);

  8.   }

  9.   /* 拒绝此连接 */

  10.   return (__FALSE);

  11. }
复制代码

47.2.5   函数cgx_content_type
函数原型:
  1. U8 *cgx_content_type (void);
复制代码
函数描述:
函数cgx_content_type允许用户对Silverlight Web serviceapplication请求的响应中更改Content-Type HTML头。该函数返回一个指向新的Content-Type HTML头的指针。使用了此函数,将覆盖RL-TCPnet库中的默认Content-Type头。这个Content-Type头用于cgx脚本响应,默认的响应如下:
  1. Content-Type: text/xml\r\n
复制代码
如果大家在工程中没有写函数cgx_content_type,RL-TCPnet库会调用上面默认的响应,如果在工程中写了此函数,会执行新写的这个函数。另外,如果这个函数返回值为空指针的话,也是执行默认的响应。
使用这个函数要注意以下问题:
1.     如果大家在工程中没有写函数cgx_content_type,RL-TCPnet库会调用上面默认的响应。
使用举例:
  1. U8 *cgx_content_type (void) {

  2.   /* User configurable Content-type for CGX script files. If this function */

  3.   /* is missing, or returns a NULL pointer, the default 'text/xml' content */

  4.   /* type from the library is used for xml-script file types.              */

  5.   return ("text/xml; charset=utf-8");

  6. }
复制代码

47.2.6   函数http_get_var
函数原型:
  1. U8* http_get_var (

  2.     U8*   env,         /* 环境变量字符串地址 */

  3.     void* ansi,        /* 存储环境字符串的缓冲地址 */

  4.     U16   maxlen );    /* 存储环境变量字符串的缓冲区大小,单位字节 */
复制代码
函数描述:
函数http_get_var处理包含环境变量的字符串env,并标识第一个变量的结尾。函数获取第一个变量及其数值后以ANSI格式存储到指针变量ansi所指向的存储单元中。
1、第1个参数是环境变量字符串地址。
2、第2个参数存储环境变量字符串的缓冲地址。
3、第3个参数指定存储环境变量字符串的缓冲大小,如果解析的环境变量字符串超过此大小,则该函数会仅存储maxlen大小的字符串。
4、返回值,返回环境变量字符串中下一个变量的地址,如果没有要处理的环境变量了,则返回NULL。
使用这个函数要注意以下问题:
1.     函数http_get_var可以处理GET和POST方式的环境变量。
2.     此函数在HTTP_CGI.c文件中调用。
3.     Web浏览器使用环境变量来返回HTTP输入表单(如单选按钮、复选框、选择列表等)中用户输入的信息给Web服务器。
使用举例:
  1. void cgi_process_var (U8 *qs) {

  2.   /* This function is called by HTTP server to process the Querry_String   */

  3.   /* for the CGI Form GET method. It is called on SUBMIT from the browser. */

  4.   /*.The Querry_String.is SPACE terminated.                                */

  5.   U8 *var;

  6.   int s[4];



  7.   var = (U8 *)alloc_mem (40);

  8.   do {

  9.     /* Loop through all the parameters. */

  10.     qs = http_get_var (qs, var, 40);

  11.     /* Check the returned string, 'qs' now points to the next. */

  12.     if (var[0] != 0) {

  13.       /* Returned string is non 0-length. */

  14.       if (str_scomp (var, "ip=") == __TRUE) {

  15.         /* My IP address parameter. */

  16.         sscanf ((const char *)&var[3], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);

  17.         LocM.IpAdr[0]   = s[0];

  18.         LocM.IpAdr[1]   = s[1];

  19.         LocM.IpAdr[2]   = s[2];

  20.         LocM.IpAdr[3]   = s[3];

  21.       }

  22.       else if (str_scomp (var, "msk=") == __TRUE) {

  23.         /* Net mask parameter. */

  24.         sscanf ((const char *)&var[4], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);

  25.         LocM.NetMask[0] = s[0];

  26.         LocM.NetMask[1] = s[1];

  27.         LocM.NetMask[2] = s[2];

  28.         LocM.NetMask[3] = s[3];

  29.       }

  30.       else if (str_scomp (var, "gw=") == __TRUE) {

  31.         /* Default gateway parameter. */

  32.         sscanf ((const char *)&var[3], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);

  33.         LocM.DefGW[0]   = s[0];

  34.         LocM.DefGW[1]   = s[1];

  35.         LocM.DefGW[2]   = s[2];

  36.         LocM.DefGW[3]   = s[3];

  37.       }

  38.       else if (str_scomp (var, "pdns=") == __TRUE) {

  39.         /* Default gateway parameter. */

  40.         sscanf ((const char *)&var[5], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);

  41.         LocM.PriDNS[0]  = s[0];

  42.         LocM.PriDNS[1]  = s[1];

  43.         LocM.PriDNS[2]  = s[2];

  44.         LocM.PriDNS[3]  = s[3];

  45.       }

  46.       else if (str_scomp (var, "sdns=") == __TRUE) {

  47.         /* Default gateway parameter. */

  48.         sscanf ((const char *)&var[5], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);

  49.         LocM.SecDNS[0]  = s[0];

  50.         LocM.SecDNS[1]  = s[1];

  51.         LocM.SecDNS[2]  = s[2];

  52.         LocM.SecDNS[3]  = s[3];

  53.       }

  54.     }

  55.   }while (qs);

  56.   free_mem ((OS_FRAME *)var);

  57. }
复制代码


努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2018-1-12 15:44:38 | 显示全部楼层
47.3 HTTP配置说明(Net_Config.c)
      (本章节配套例子的配置与本小节的说明相同)
      RL-TCPnet的配置工作是通过配置文件Net_Config.c实现。在MDK工程中打开文件Net_Config.c,可以看到下图所示的工程配置向导:
7.3.png
                              
RL-TCPnet要配置的选项非常多,我们这里把几个主要的配置选项简单介绍下。
7.4.png
System Definitions
(1)Local Host Name
      局域网域名。
      这里起名为armfly,使用局域网域名限制为15个字符。
(2)Memory Pool size
      参数范围1536-262144字节。
      内存池大小配置,单位字节。另外注意一点,配置向导这里显示的单位是字节,如果看原始定义,MDK会做一个自动的4字节倍数转换,比如我们这里配置的是8192字节,那么原始定义是#define MEM_SIZE  2048,也就是8192/4 = 2048。
(3)Tick Timer interval
      可取10,20,25,40,50,100,200,单位ms。
      系统滴答时钟间隔,也就是网络协议栈的系统时间基准,默认情况下,取值100ms。
7.5.png
Ethernet Network Interface
     以太网接口配置,勾选了此选项就可以配置了,如果没有使能DHCP的话,将使用这里配置的固定IP
(1)MAC Address
     局域网内可以随意配置,只要不跟局域网内其它设备的MAC地址冲突即可。
(2)IP Address
      IP地址。
(3)Subnet mask
      子网掩码。
(4)Default Gateway
      默认网关。
7.6.png
Ethernet Network Interface
      以太网接口配置,这个配置里面还有如下两项比较重要的配置需要说明。
(1)NetBIOS Name Service
      NetBIOS局域网域名服务,这里打上对勾就使能了。这样我们就可以通过前面配置的Local Host Name局域网域名进行访问,而不需要通过IP地址访问了。
(2)Dynaminc Host Configuration
      即DHCP,这里打上对勾就使能了。使能了DHCP后,RL-TCPnet就可以从外接的路由器上获得动态IP地址。
7.7.png
UDP Sockets
      UDP Sockets配置,打上对勾就使能了此项功能
(1)Number of UDP Sockets
      用于配置可创建的UDP Sockets数量,这里配置了5个。
      范围1 – 20。
7.8.png
TCP Sockets
      TCP Sockets配置,打上对勾就使能了此项功能
(1)Number of TCP Sockets
      用于配置可创建的TCP Sockets数量。
(2)Number of Retries
      范围0-20。
      用于配置重试次数,TCP数据传输时,如果在设置的重试时间内得不到应答,算一次重试失败,这里就是配置的最大重试次数。
(3)Retry Timeout in seconds
      范围1-10,单位秒。
      重试时间。如果发送的数据在重试时间内得不到应答,将重新发送数据。
(4)Default Connect Timeout in seconds
      范围1-600,单位秒。
      用于配置默认的保持连接时间,即我们常说的Keep Alive时间,如果时间到了将断开连接。常用于HTTP Server,Telnet Server等。
(5)Maximum Segment Size
      范围536-1460,单位字节。
      MSS定义了TCP数据包能够传输的最大数据分段。
(6)Receive Window Size
      范围536-65535,单位字节。
      TCP接收窗口大小。
7.9.png
HTTP Server
      HTTP配置,打上对勾就使能了此项功能
(1)Number of HTTP Sessions
      同时可以连接的会话个数,即可以连接的HTTP客户端个数。
      范围1-10。
(2)Port Number
      HTTP服务器的监听端口号,一般情况下Web服务器的端口号均为80。
      范围1-65535。
(3)Server-Id header
      HTTPServer header,如果用户没有配置此选项,将使用默认的header,如果配置了,将使用用户配置的。(实际测试发现,这个选项貌似没什么用
(4)Enable User Authentication
      用户认证,如果此选项打上对勾的话,将使能用户认证。
      AuthenticationRealm  认证领域。
      AuthenticationUsername 用户名。
      AuthenticationPassword 用户密码。

47.4 HTTP调试说明(Net_Debug.c)
      (重要说明,RL-TCPnet的调试是通过串口打印出来的)
      RL-TCPnet的调试功能是通过配置文件Net_Debug.c实现。在MDK工程中打开文件Net_Debug.c,可以看到下图所示的工程配置向导:
7.10.png
Print Time Stamp
      勾选了此选项的话,打印消息时,前面会附带时间信息。
其它所有的选项
      默认情况下,所有的调试选项都关闭了,每个选项有三个调试级别可选择,这里我们以HTTP Server Debug为例,点击下拉列表,可以看到里面有Off,Errors only和Fulldebug三个调试级别可供选择,每个调试选项里面都是这三个级别。
7.11.png
      Off:表示关闭此选项的调试功能。
      Errorsonly:表示仅在此选项出错时,将其错误打印出来。
     Fulldebug:表示此选项的全功能调试。
      具体测试,我们这里就不做了,大家可以按照第11章讲解的调试方法进行测试。

努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2018-1-12 15:54:38 | 显示全部楼层
47.5 制作HTML和CGI脚本文件
     下面要制作的网页是在前面第44章的基础上实现的,所以第44章节的网页制作方法务必要掌握。我们这里实现一个如下的网页效果:
7.12.png
                              
点击网页中的“LED控制”后,弹出如下的页面:
7.13.png
对比一下第44章制作的网页,主页面上多了一个小房子一样的图标(用于返回主页面)和一个LED控制链接。这两个都比较好实现,看下面代码中置红的部分:
  1. <html>

  2.   <head>

  3.     <meta http-equiv="Content-Type" content="text/html; charset= GBK" />

  4.     <title>安富莱嵌入式网络服务器</title>

  5.   </head>

  6.   <body>

  7.     <br />

  8.     <div align="center">

  9.       <table style="border: 1px solid #000080" height="600" cellspacing="0" cellpadding="0" width="800">

  10.         <tr bgcolor="#EEEEEE">

  11.           <td style="border-bottom: 1px solid #000080" valign="bottom" nowrap="nowrap" height="90"  margin="50" width="700">

  12.             <h1 align="center">

  13.               <font face="verdana" color="#006699">安富莱嵌入式网络服务器</font>

  14.                 <a href="index.htm">

  15.                  <img border="0" src="home.png" align="center" width="31" height="29">

  16.                 </a>

  17.             </h1>

  18.           </td>

  19.         </tr>

  20.         <tr bgcolor="#EEEEEE">

  21.           <td valign="top" height="510" width="800">

  22.             <h2 align="center">

  23.               <b>

  24.                 <font face="verdana" color="#003366">安富莱电子微信公众号</font>

  25.               </b>

  26.             </h2>

  27.             <p align="center">

  28.               <img border="0" src="weixin.jpg" width="200" height="200"/>

  29.             </p>

  30.             <p align="center" leftmargin="10">

  31.               <font face="Verdana" size="3">基于RL-TCPnet网络协议栈的嵌入式Web服务器</font>

  32.             </p>

  33.             <p align="center">

  34.               <a href="/led.cgi">LED控制</a>

  35.               </a>

  36.             </p>

  37.           </td>

  38.         </tr>

  39.         

  40.         <tr bgcolor="#EEEEEE">

  41.           <td width="800">

  42.             <p align="center">

  43.               <font face="Verdana" size="3">Copyright &#169; 2017-2020

  44.               <a href="http://www.armfly.com/">武汉安富莱电子有限公司</a> 版权所有.</font>

  45.             </p>

  46.           </td>

  47.         </tr>

  48.       </table>

  49.     </div>

  50.   </body>

  51. </html>
复制代码
主页面做好之后,就是子页面的设计了。这个子页面是我们本章节的重点。

47.5.1 制作子页面HTML文件
      Notepad++的设置就不再赘述了,前面第44章已经详细讲解,我们这里的编码字符集依然要选择GB2312。子页面的HTML代码如下:
  1. <html>

  2.   <head>

  3.     <meta http-equiv="Content-Type" content="text/html; charset= GBK" />

  4.     <title>安富莱嵌入式网络服务器</title>

  5.   </head>

  6.   <body>

  7.   <br />

  8.   <div align="center">

  9.     <table style="border: 1px solid #000080" height="600" cellspacing="0" cellpadding="0" width="800">

  10.       <tr bgcolor="#EEEEEE">

  11.         <td style="border-bottom: 1px solid #000080" valign="bottom" nowrap="nowrap" height="90" width="800">

  12.           <h1 align="center">

  13.           <font face="verdana" color="#006699">安富莱嵌入式网络服务器</font>

  14.           <a href="index.htm">

  15.             <img border="0" src="home.png" align="center" width="31" height="29" />

  16.           </a></h1>

  17.         </td>

  18.       </tr>

  19.       <tr bgcolor="#EEEEEE">

  20.         <td valign="top" height="510" width="800">

  21.           <h2 align="center">

  22.           <br />LED控制</h2>

  23.           <p align="center">

  24.             <font size="3">利用CGI POST方式控制LED1,LED3和LED4,其中LED2已经

  25.             被用作系统指示灯。选中Checkbox控件点亮相应LED,否则关闭。

  26.             <br />

  27.             <br /></font>

  28.           </p>

  29.           <form action="beep.cgi" method="post" name="form1">

  30.             <input type="hidden" value="led" name="pg" />

  31.             <table border="0" width="90%" align="center">

  32.               <tr bgcolor="#AACCFF">

  33.                 <th width="40%">

  34.                   <font size="3">选项</font>

  35.                 </th>

  36.                 <th width="60%">设置</th>

  37.               </tr>

  38.               <tr>

  39.                 <td>

  40.                 <img src="pabb.gif" />LED控制:</td>

  41.                 <td>

  42.                   <table>

  43.                     <tr valign="middle">

  44.                       <td>

  45.                       <input type="checkbox" name="TICK1" value="LED1" onchange="submit();" /> LED1

  46.                       <br />

  47.                       <input type="checkbox" name="TICK1" value="LED2" onchange="submit();" /> LED2

  48.                       <br />

  49.                       <input type="checkbox" name="TICK1" value="LED3" onchange="submit();" /> LED3

  50.                       <br /></td>

  51.                     </tr>

  52.                   </table>

  53.                 </td>

  54.               </tr>

  55.             </table>

  56.           </form>

  57.         </td>

  58.       </tr>

  59.       <tr bgcolor="#EEEEEE">

  60.         <td>

  61.           <p align="center">

  62.             <font face="Verdana" size="3">Copyright &#608;2017-2020

  63.             <a href="http://www.armfly.com/">武汉安富莱电子有限公司</a> 版权所有.</font>

  64.           </p>

  65.         </td>

  66.       </tr>

  67.     </table>

  68.   </div>

  69. </body>

  70. </html>
复制代码
实际测试显示效果:
7.14.png
显示效果也没有问题了,现在要做的就是将这个设计好的子页面修改成CGI脚本文件,因为页面里面的复选框控制开发板的LED灯是需要CGI脚本来实现。

47.5.2 将子页面HTML文件修改为CGI脚本文件
      修改前,建议先把这个子页面的HTML文件备份一个出来,方便我们以后调试升级,因为修改成CGI脚本文件后,再修改回来就稍麻烦了。
      给子页面HTML代码前面都加上脚本命令,具体如下:
  1. t <html>  ----------(1)

  2. t <head>

  3. t <meta http-equiv="Content-Type" content="text/html; charset= GBK" />

  4. t <title>安富莱嵌入式网络服务器</title>

  5. t </head>

  6. t <body>

  7. t <br />

  8. t <div align="center">

  9. t <table style="border: 1px solid #000080" height="600" cellspacing="0" cellpadding="0" width="800">

  10. t <tr bgcolor="#EEEEEE">

  11. t <td style="border-bottom: 1px solid #000080" valign="bottom" nowrap="nowrap" height="90" width="800">

  12. t <h1 align="center">

  13. t <font face="verdana" color="#006699">安富莱嵌入式网络服务器</font>

  14. t <a href="index.htm">

  15. t <img border="0" src="home.png" align="center" width="31" height="29">

  16. t </a>

  17. t </h1>

  18. t </td>

  19. t </tr>

  20. t <tr bgcolor="#EEEEEE">

  21. t <td valign="top" height="510" width="800">

  22. t <h2 align="center">

  23. t <br />LED控制</h2>

  24. t <p align="center">

  25. t <font size="3">利用CGI POST方式控制LED1,LED3和LED4,其中LED2已经

  26. t 被用作系统指示灯。选中Checkbox控件点亮相应LED,否则关闭。

  27. t <br />

  28. t <br /></font>

  29. t </p>

  30. t <form action="led.cgi" method="post" name="form1">   ----------(2)

  31. t <input type="hidden" value="led" name="pg" />         ----------(3)

  32. t <table border="0" width="90%" align="center">

  33. t <tr bgcolor="#AACCFF">

  34. t <th width="40%">

  35. t <font size="3">选项</font>

  36. t </th>

  37. t <th width="60%">设置</th>

  38. t </tr>

  39. t <tr>

  40. t <td>

  41. t <img src="pabb.gif" />LED控制:</td>

  42. t <td>

  43. t <table>

  44. t <tr valign="middle">

  45. t <td>

  46. #用OnClick或者OnChange没有区别   ----------(4)

  47. c T11 <input type=checkbox name=TICK1 value=LED1 OnChange="submit();" %s> LED1<br>   ----------(5)

  48. c T12 <input type=checkbox name=TICK1 value=LED2 OnChange="submit();" %s> LED2<br>   ----------(6)

  49. c T14 <input type=checkbox name=TICK1 value=LED3 OnChange="submit();" %s> LED3<br>   ----------(7)

  50. t </td>

  51. t </tr>

  52. t </table>

  53. t </td>

  54. t </tr>

  55. t </table>

  56. t </form>

  57. t </td>

  58. t </tr>

  59. t <tr bgcolor="#EEEEEE">

  60. t <td>

  61. t <p align="center">

  62. t <font face="Verdana" size="3">Copyright &#169; 2017-2020

  63. t <a href="http://www.armfly.com/">武汉安富莱电子有限公司</a> 版权所有.</font>

  64. t </p>

  65. t </td>

  66. t </tr>

  67. t </table>

  68. t </div>

  69. t </body>

  70. t </html>

  71. .           ----------(8)
复制代码
1.     大部分HTML语句都是以CGI脚本命令t开头,并且每行语句的长度不可以超过120个字符
2.     这句比较重要,是我们之前一直强调的HTTP表单,这里采用POST方式。
3.     这里是一个hidden隐藏类型的输入表单,既然是隐藏就是什么也不会显示到网页上,但是会有消息发给POST方式的消息处理函数cgi_process_data。这里加入隐藏类型输入表单有一个很重要的作用,当用户选择的复选框全部取消选择后,POST方式的消息处理函数cgi_process_data是不会执行的,所以加入此输入表单,方便控制。详见本章47.7小节的解释。
4.     这里用到了CGI脚本注释命令#,不参与实际代码。
5.     这里就是一个以CGI脚本命令c开头的命令行,并且含控制字符T11。实现了一个复选框输入表单,用户点击了网页上面的复选框后将触发POST方式的消息处理函数cgi_process_data,LED的亮灭控制就是在这个函数里面实现。另外,由于这个是CGI脚本的c命令,HTTP服务器调用完毕函数cgi_process_data后,还会调用函数cgi_func进行脚本解析,在这个函数里面实现复选框当前状态的反馈,返回的是HTML格式代码。具体这两个函数实现的代码,详见本章47.7小节的解释。
6.     同上,控制字符是T14。
7.     同上,控制字符是T18。
8.     脚本文件结束字符,这个点号一定不能省略。

HTML文件中添加完毕CGI脚本命令后,就可以将这个HTML文件另存为led.cgi。注意,后缀名一定要是cgi。
1、点击菜单上的文件->另存为
7.15.png
2、保存时,文件名直接填led.cgi即可
7.16.png
3、至此,网页设计所需的四个文件就都准备好了
7.17.png

47.5.3 添加HTML和CGI文件到MDK
      添加方法和网页相关文件的存放路径位置已经在前面第44章节详细进行了说明,我们这里不再赘述。如果还没有掌握好,务必要返回地44章学习如何添加
1、添加index.htm和led.cgi文件到MDK工程。
7.18.png
添加led.cgi的时候也选择下面这种类型:
7.19.png
2、新建并添加一个Web.inp文件到MDK工程。
      这个文件要设置的地方较多,详情看第44章。
7.20.png
文件Web.inp填写的内容如下:
  1. weixin.jpg,

  2. led.cgi,

  3. home.png,

  4. index.htm to Web.c nopr root(Web)
复制代码
这里是将文件weixin.jpg,led.cgi,home.png和index.htm通过FCARM命令转换后存到Web.c文件里面。
3、添加HTTP_CGI.c文件。
      最后还有一个HTTP_CGI.c文件,这个文件也要添加的MDK中,此文件在MDK4.74安装目录:C:\Keil_v474\ARM\RL\TCPnet\User里面。我们这里将其复制到工程目录:\RL-ARM\RL-TCPnet里面了。用户添加此文件到MDK工程中后,要根据自己设计的网页来修改此文件。具体此文件的实现看47.7小节。
      HTTP_CGI.c文件也添加到MDK工程后:
7.21.png
全编译后,将生成的Web.c文件(关于此文件的添加和相关问题看第44章)也添加进来:
7.22.png
这个Web.c文件务必要添加进来,否则会出现Web服务器网页无法访问的情况:
7.23.png
最后,下载程序到开发板之前,最好再全编译一遍,防止Web.c文件中的网页内容没有参与编译。

努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2018-1-12 16:00:07 | 显示全部楼层
47.6 访问开发板Web服务器的方法
      (强烈推荐将网线接到路由器或者交换机上面测试,因为已经使能了DHCP,可以自动获取IP地址)
      用户可在浏览器中直接输入IP地址访问Web服务器,跟大家访问路由器后台一样,也可以通过NetBIOS Name直接访问,即http://armfly/,这样就无需查看具体IP了。下面我们两种方式都说下。

47.6.1 输入NetBIOS Name访问
1、浏览器输入地址http://armfly/,点击键盘回车键(点击回车后,前面的http://会自动隐藏了)。
7.24.png
2、用户名输入admin,密码输入123456,点击“登录”按钮即可访问:
7.25.png
3、登录Web服务器后的效果如下:
7.26.png
4、点击页面上的“LED控制”超链接,进入LED控制页面。
    在LED控制页面里面可以控制开发板上LED的亮灭了。选中复选框点亮LED,取消选中,关闭LED。
7.27.png

47.6.2 输入IP地址访问
      访问Web服务器前,要先获取板子的IP地址。由于已经使能了DHCP,板子可以自动获取IP地址,而且使能了局域网域名NetBIOS,用户只需在电脑端ping armfly就可以获取板子的IP地址,获取方法如下:
(1)WIN+R组合键打开“运行”窗口,输入cmd。
7.28.png
(2)弹出的命令窗口中,输入ping armfly。
7.29.png
(3)输入ping armfly后,回车。
7.30.png
获得IP地址是192.168.1.7。
1、浏览器输入192.168.1.7,点击键盘回车键(IP地址前面加不加http://都没有关系,不加的话,浏览器会自动加上)。
7.31.png
2、用户名输入admin,密码输入123456,点击“登录”按钮即可访问:
7.32.png
3、登录Web服务器后的效果如下:
7.33.png
4、点击页面上的“LED控制”超链接,进入LED控制页面。
      在LED控制页面里面可以控制开发板上LED的亮灭了。选中复选框点亮LED,取消选中,关闭LED。
7.34.png
至此,访问开发板Web服务器的方法已经介绍完毕。

努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2018-1-12 16:05:17 | 显示全部楼层
47.7 HTTP_CGI.c文件中接口函数讲解说明
      这里对HTTP_CGI.c中的函数cgi_process_data和cgi_func做一个说明,方便大家更好的理解。

47.7.1 函数cgi_process_data
      这个函数主要处理POST方式发来的消息。
  1. /*--------------------------- cgi_process_data ------------------------------*/



  2. void cgi_process_data (U8 code, U8 *dat, U16 len) {

  3.   /* This function is called by HTTP server to process the returned Data    */

  4.   /* for the CGI Form POST method. It is called on SUBMIT from the browser. */

  5.   /* Parameters:                                                            */

  6.   /*   code  - callback context code                                        */

  7.   /*           0 = www-url-encoded form data                                */

  8.   /*           1 = filename for file upload (0-terminated string)           */

  9.   /*           2 = file upload raw data                                     */

  10.   /*           3 = end of file upload (file close requested)                */

  11.   /*           4 = any xml encoded POST data (single or last stream)        */

  12.   /*           5 = the same as 4, but with more xml data to follow          */

  13.   /*               Use http_get_content_type() to check the content type    */

  14.   /*   dat   - pointer to POST received data                                */

  15.   /*   len   - received data length                                         */

  16.   U8 *var;



  17.   switch (code) {

  18.     case 0:

  19.       /* Url encoded form data received. */

  20.       break;



  21.     case 1:

  22.       /* Filename for file upload received as encoded by the browser. */

  23.       /* It might contain an absolute path to a file from the sending */

  24.       /* host. Open a file for writing. */

  25.       return;



  26.     case 2:

  27.       /* File content data received. Write data to a file. */

  28.       /* This function will be called several times with   */

  29.       /* code 2 when a big file is being uploaded.         */

  30.       return;



  31.     case 3:

  32.       /* File upload finished. Close a file. */

  33.       return;



  34.     case 4:

  35.       /* XML encoded content type, last packet. */

  36.      // pType = http_get_content_type ();

  37.       /* check the content type for CGX file request. */

  38.       /* pType is a pointer to a 0-terminated string  */

  39.       /* For example: text/xml; charset=utf-8         */

  40.       return;

  41.    

  42.     case 5:

  43.       /* XML encoded as under 4, but with more to follow. */

  44.       return;



  45.     default:

  46.       /* Ignore all other codes. */

  47.       return;

  48.   }



  49.   if (len == 0) {

  50.     /* No data or all items (radio, checkbox) are off. */

  51.     return;

  52.   }



  53.   var = (U8 *)alloc_mem (40);



  54.   do {

  55.     /* Parse all returned parameters. */

  56.     dat = http_get_var (dat, var, 40);

  57.     if (var[0] != 0) {

  58.        if (str_scomp (var, "TICK1=") == __TRUE || str_scomp (var, "pg=") == __TRUE)  //--------(1)

  59.        {

  60.           if (str_scomp (var, "pg=") == __TRUE)  //--------(2)

  61.           {

  62.               LEDControl = 0;

  63.           }

  64.          

  65.           if(*(var+9) =='1')     //--------(3)

  66.           {

  67.             LEDControl |= 0x01;

  68.           }

  69.           else if(*(var+9) =='2') //--------(4)

  70.           {

  71.             LEDControl |= 0x02;

  72.           }

  73.           else if(*(var+9) =='3') //--------(5)

  74.           {

  75.             LEDControl |= 0x04;

  76.           }

  77.       }

  78.     }

  79.   }while (dat);

  80.   free_mem ((OS_FRAME *)var);



  81.   //LED Control

  82.   if(LEDControl & 0x01)    //--------(6)

  83.   {

  84.      bsp_LedOn(1);

  85.   }

  86.   else

  87.   {

  88.      bsp_LedOff(1);   

  89.   }



  90.   if(LEDControl & 0x02)

  91.   {

  92.      bsp_LedOn(2);

  93.   }

  94.   else

  95.   {

  96.      bsp_LedOff(2);   

  97.   }



  98.   if(LEDControl & 0x04)

  99.   {

  100.      bsp_LedOn(3);

  101.   }

  102.   else

  103.   {

  104.      bsp_LedOff(3);   

  105.   }



  106. }
复制代码
1.      先说下这里为什么是判断接收到的消息中是否有字符串“TICK1=”和“pg=”,因为我们前面制作的led.cgi脚本文件中的HTTP输入表单,首先是隐藏表单:
  1. t <input type="hidden" value="led" name="pg" />
复制代码
只要用户在浏览器上面改变复选框的状态,函数cgi_process_data就会接收到字符串“pg=led”的消息。所以这里有个“pg=”的字符串判断。
     而“TCIK1=”是由复选框提供的:
  1. c T11 <input type=checkbox name=TICK1 value=LED1 OnChange="submit();" %s> LED1<br>

  2. c T12 <input type=checkbox name=TICK1 value=LED2 OnChange="submit();" %s> LED2<br>

  3. c T14 <input type=checkbox name=TICK1 value=LED3 OnChange="submit();" %s> LED3<br>
复制代码
只要用户选中了复选框,就会收到字符串消息,比如选中LED1就会收到字符串“TICK1=LED1”,选中LED2就会收到字符串“TICK1=LED2”,选中LED3就会收到字符串“TICK1=LED3”,而取消选中或者没有选中的复选框是不会收到字符串消息的,这点要特别注意。正是因为这个原因,才专门添加了一个隐藏表单,因为当所有选项都取消选中后,函数cgi_process_data并不会收到字符串消息,而有了隐藏表单后就会收到“pg=led”消息了,从而可以有效控制LED的亮灭。
2.      收到“pg=”的字符串,设置全局变量LEDControl = 0,即所有LED1,LED2和LED3关闭。这个全局变量的bit0控制LED1,bit1控制LED2,bit2控制LED3。置1打开LED,清零关闭LED。
3.      这里的“*(var+9)”就是“TICK1=LED1”字符串的最后一个字符,通过判断它来查看LED1复选框是否被选中了。
4.      同上,查看LED2复选框是否被选中。
5.      同上,查看LED3复选框是否被选中。
6.      LED亮灭控制要放在do while循环检测的外面实现,不可放在循环检测里面,因为消息还没有处理完毕。

      说完了这些细节,我们这里再说下这个函数的执行流程。首先,对于接收到的POST消息,程序里面通过一个do while语句进行循环检测,直到消息里面的所有字符串全部检测了出来。只要用户改变了复选框的状态,就会收到“pg=led”字符串,这个字符串是最先被检测出来的,如果有复选框处于选中状态,对应的字符串也会被检测出来,比如LED1和LED2都处于选中状态,那么就会检测出TICK1=LED1”和TICK1=LED2”,而取消选中和没有选中的复选框是不会检测到字符串消息。
      对于这个执行流程,建议大家通过在程序中加上串口打印,实际观察下,以便有个深入的认识。

47.7.2 函数cgi_func
      这个函数主要是脚本命令的解析和处理。
  1. /*--------------------------- cgi_func --------------------------------------*/



  2. U16 cgi_func (U8 *env, U8 *buf, U16 buflen, U32 *pcgi) {

  3.   /* This function is called by HTTP server script interpreter to make a    */

  4.   /* formated output for 'stdout'. It returns the number of bytes written   */

  5.   /* to the output buffer. Hi-bit of return value (len is or-ed with 0x8000)*/

  6.   /* is a repeat flag for the system script interpreter. If this bit is set */

  7.   /* to 1, the system will call the 'cgi_func()' again for the same script  */

  8.   /* line with parameter 'pcgi' pointing to a 4-byte buffer. This buffer    */

  9.   /* can be used for storing different status variables for this function.  */

  10.   /* It is set to 0 by HTTP Server on first call and is not altered by      */

  11.   /* HTTP server for repeated calls. This function should NEVER write more  */

  12.   /* than 'buflen' bytes to the buffer.                                     */

  13.   /* Parameters:                                                            */

  14.   /*   env    - environment variable string                                 */

  15.   /*   buf    - HTTP transmit buffer                                        */

  16.   /*   buflen - length of this buffer (500-1400 bytes - depends on MSS)     */

  17.   /*   pcgi   - pointer to session local buffer used for repeated loops     */

  18.   /*            This is a U32 variable - size is 4 bytes. Value is:         */

  19.   /*            - on 1st call = 0                                           */

  20.   /*            - 2nd call    = as set by this function on first call       */

  21.   U32 len = 0;

  22.   unsigned int mask;



  23.   switch (env[0]) {   //--------(1)

  24.     /* Analyze the environment string. It is the script 'c' line starting */

  25.     /* at position 2. What you write to the script file is returned here. */

  26.        case 'T' :

  27.          if(env[1] =='1') //--------(2)

  28.             

  29.          {        

  30.            mask = env[2]-'0'; //--------(3)

  31.            len = sprintf((char *)buf,(const char *)&env[4],(LEDControl& mask) ? "checked" : "");//----(4)

  32.          }

  33.          break;

  34.       

  35.   }

  36.   return ((U16)len);

  37. }
复制代码
      在前面的led.cgi脚本文件中,三个复选框都是在一个输入表单中:
  1. t <form action="led.cgi" method="post" name="form1">

  2. ………

  3. c T11 <input type=checkbox name=TICK1 value=LED1 OnChange="submit();" %s> LED1<br>

  4. c T12 <input type=checkbox name=TICK1 value=LED2 OnChange="submit();" %s> LED2<br>

  5. c T14 <input type=checkbox name=TICK1 value=LED3 OnChange="submit();" %s> LED3<br>  

  6. ………

  7. t </form>
复制代码

所以,有一个复选框的状态变化,就会触发HTTP服务器调用三次cgi_func函数进行解析,并返回复选框的状态。
1.      这里是判断接收到的环境变量字符串的第一个字符,也就是我们在复选框输入表单中设置的控制字符T11,T12和T14。
2.      判断控制字符的第2个字符‘1’。
3.      求出控制字符的第3个字符实际数值,也就是将字符转换成数值。对于复选框1会求出数值1,复选框2会求出数值2,复选框3会求出数值4。求出这些数值方便我们下一步操作。
4.      这一步比较关键了,我们这里详细解释下,HTTP服务器调用cgi_func函数解析第一个复选框时,函数中环境变量env的完整字符串就是:
  1. T11 <input type=checkbox name=TICK1 value=LED1 OnChange="submit();" %s> LED1<br>
复制代码
     从这里可以看出env[0]对应的字符‘T’,env[1]对应的字符‘1’,env[2]对应的字符‘1’,env[3]对应的是个空格,从env[4]就是HTML格式的代码了。这样sprintf语句就变成了:
  1. len = sprintf ((char *) buf,

  2. <input type=checkbox name=TICK1 value=LED1 OnChange="submit();" %s> LED1<br> ,

  3. (LEDControl& mask) ? "checked" : "");
复制代码
如果复选框选中了,那么buf中的字符串就是:
  1. <input type=checkbox name=TICK1 value=LED1 OnChange="submit();" checked> LED1<br>
复制代码
这个HTML代码返回给用户浏览器就是复选框被选中的效果:
7.35.png
                              
如果复选框未选择,那么buf中的字符串就是:
  1. <input type=checkbox name=TICK1 value=LED1 OnChange="submit();" > LED1<br>
复制代码
这个HTML代码返回给用户浏览器就是复选框未选中的效果:
7.36.png
第2个和第3个复选框的解析过程跟第1个是一样的。对于这个函数,建议大家加入一个串口打印,打印出env和buf两个字符串,方便大家更好的理解cgi解析

努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2018-1-12 16:15:16 | 显示全部楼层
47.8 实验例程说明(RTX)

47.8.1 STM32F407开发板实验
配套例子:
      V5-1066_RL-TCPnet实验_WebServer之CGI实现动态网页(RTX)
实验目的:
      1.     学习CGI脚本实现动态网页制作方法和RL-TCPnet的Web服务器实现。
实验内容:
      1.      强烈推荐将网线接到路由器或者交换机上面测试,因为已经使能了DHCP,可以自动获取IP地址。
      2.      用户可在浏览器中直接输入IP地址访问Web服务器,跟大家访问路由器后台一样,也可以通过NetBIOS局域网域名直接访问,即http://armfly/,这样就无需查看具体IP了。
      3.      Web服务器的用户名admin,密码123456。
      4.      例子中利用CGI脚本实现了一个Web浏览器中通过复选框控制LED亮灭的功能。
      5.      关于网页的制作和Web服务器的测试方法,务必看本例子配套的教程,有详细讲解!!!
网页制作:
      详见本章节47.5小节。
配置向导文件设置(Net_Config.c):
      详见本章节47.3小节。
调试文件设置(Net_Debug.c):
      详见本章节47.4小节。
Web服务器访问效果:
      详见本章节47.6小节。
RTX配置:
       RTX配置向导详情如下:
7.37.png
                              
Task Configuration
(1)Number of concurrent running tasks
      允许创建6个任务,实际创建了如下5个任务:
      AppTaskUserIF任务   :按键消息处理。
      AppTaskLED任务     :LED闪烁。
      AppTaskMsgPro任务 :按键检测。
      AppTaskTCPMain任务:RL-TCPnet测试任务。
      AppTaskStart任务  :启动任务,也是最高优先级任务,这里实现RL-TCPnet的时间基准更新。
(2)Number of tasks with user-provided stack
      创建的5个任务都是采用自定义堆栈方式。
(3)Run in privileged mode
      设置任务运行在非特权级模式。
RTX任务调试信息:
7.38.png
程序设计:
任务栈大小分配:
      staticuint64_t AppTaskUserIFStk[1024/8];   /* 任务栈 */
      staticuint64_t AppTaskLEDStk[1024/8];      /* 任务栈 */
      staticuint64_t AppTaskMsgProStk[1024/8];  /* 任务栈 */
      staticuint64_t AppTaskTCPMainStk[4096/8]; /* 任务栈 */
      staticuint64_t AppTaskStartStk[1024/8];     /* 任务栈 */
      将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数、浮点运算和uint64_t类型数据运算会出问题。
系统栈大小分配:
7.39.png
RTX初始化:
  1. /*

  2. *********************************************************************************************************

  3. *    函 数 名: main

  4. *    功能说明: 标准c程序入口。

  5. *    形    参: 无

  6. *    返 回 值: 无

  7. *********************************************************************************************************

  8. */

  9. int main (void)

  10. {   

  11.      /* 初始化外设 */

  12.      bsp_Init();

  13.    

  14.      /* 创建启动任务 */

  15.      os_sys_init_user (AppTaskStart,              /* 任务函数 */

  16.                        5,                         /* 任务优先级 */

  17.                        &AppTaskStartStk,          /* 任务栈 */

  18.                        sizeof(AppTaskStartStk));  /* 任务栈大小,单位字节数 */

  19.      while(1);

  20. }
复制代码

硬件外设初始化
     硬件外设的初始化是在 bsp.c 文件实现:
  1. /*

  2. *********************************************************************************************************

  3. *    函 数 名: bsp_Init

  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次

  5. *    形    参:无

  6. *    返 回 值: 无

  7. *********************************************************************************************************

  8. */

  9. void bsp_Init(void)

  10. {

  11.      /*

  12.          由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。

  13.          启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。



  14.          系统时钟缺省配置为168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件

  15.      */

  16.      /* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/

  17.      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);



  18.      bsp_InitDWT();     /* 初始化DWT */

  19.      bsp_InitUart();    /* 初始化串口 */

  20.      bsp_InitKey();    /* 初始化按键变量(必须在 bsp_InitTimer() 之前调用) */

  21.      bsp_InitLed();    /* 初始LED指示灯端口 */

  22. }
复制代码

RTX任务创建:
  1. /*

  2. *********************************************************************************************************

  3. *    函 数 名: AppTaskCreate

  4. *    功能说明: 创建应用任务

  5. *    形    参: 无

  6. *    返 回 值: 无

  7. *********************************************************************************************************

  8. */

  9. static void AppTaskCreate (void)

  10. {

  11.      HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */

  12.                                            1,                         /* 任务优先级 */

  13.                                            &AppTaskUserIFStk,         /* 任务栈 */

  14.                                            sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */

  15.    

  16.      HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */

  17.                                         2,                       /* 任务优先级 */

  18.                                         &AppTaskLEDStk,          /* 任务栈 */

  19.                                         sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */

  20.    

  21.      HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */

  22.                                            3,                         /* 任务优先级 */

  23.                                            &AppTaskMsgProStk,         /* 任务栈 */

  24.                                            sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */

  25.    

  26.     HandleTaskTCPMain = os_tsk_create_user(AppTaskTCPMain,             /* 任务函数 */

  27.                                            4,                         /* 任务优先级 */

  28.                                            &AppTaskTCPMainStk,         /* 任务栈 */

  29.                                            sizeof(AppTaskTCPMainStk)); /* 任务栈大小,单位字节数 */

  30. }
复制代码

五个RTX任务的实现:
  1. /*

  2. *********************************************************************************************************

  3. *    函 数 名: AppTaskUserIF

  4. *    功能说明: 按键消息处理     

  5. *    形    参: 无

  6. *    返 回 值: 无

  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)

  8. *********************************************************************************************************

  9. */

  10. __task void AppTaskUserIF(void)

  11. {

  12.      uint8_t ucKeyCode;



  13.     while(1)

  14.     {

  15.          ucKeyCode = bsp_GetKey();

  16.         

  17.          if (ucKeyCode != KEY_NONE)

  18.          {

  19.               switch (ucKeyCode)

  20.               {   

  21.                    /* K1键按下 */

  22.                    case KEY_DOWN_K1:

  23.                        printf("K1键按下\r\n");        

  24.                        break;  

  25.                   

  26.                    /* K2键按下 */

  27.                    case KEY_DOWN_K2:

  28.                        printf("K2键按下\r\n");        

  29.                        break;  

  30.                   

  31.                    /* K3键按下 */

  32.                    case KEY_DOWN_K3:

  33.                        printf("K3键按下\r\n");

  34.                        break;

  35.                                     

  36.                    /* 其他的键值不处理 */

  37.                    default:                    

  38.                        break;

  39.               }

  40.          }

  41.         

  42.          os_dly_wait(20);

  43.      }

  44. }



  45. /*

  46. *********************************************************************************************************

  47. *    函 数 名: AppTaskLED

  48. *    功能说明: LED闪烁。

  49. *    形    参: 无

  50. *    返 回 值: 无

  51. *   优 先 级: 2

  52. *********************************************************************************************************

  53. */

  54. __task void AppTaskLED(void)

  55. {

  56.      const uint16_t usFrequency = 500; /* 延迟周期 */

  57.    

  58.      /* 设置延迟周期 */

  59.      os_itv_set(usFrequency);

  60.    

  61.     while(1)

  62.     {

  63.          bsp_LedToggle(4);



  64.          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/

  65.          os_itv_wait();

  66.     }

  67. }



  68. /*

  69. *********************************************************************************************************

  70. *    函 数 名: AppTaskMsgPro

  71. *    功能说明: 按键检测

  72. *    形    参: 无

  73. *    返 回 值: 无

  74. *   优 先 级: 3

  75. *********************************************************************************************************

  76. */

  77. __task void AppTaskMsgPro(void)

  78. {

  79.     while(1)

  80.     {

  81.          bsp_KeyScan();

  82.          os_dly_wait(10);

  83.     }

  84. }



  85. /*

  86. *********************************************************************************************************

  87. *    函 数 名: AppTaskTCPMain

  88. *    功能说明: RL-TCPnet测试任务

  89. *    形    参: 无

  90. *    返 回 值: 无

  91. *   优 先 级: 4

  92. *********************************************************************************************************

  93. */

  94. __task void AppTaskTCPMain(void)

  95. {

  96.      while (1)

  97.      {

  98.          TCPnetTest();

  99.      }

  100. }



  101. /*

  102. *********************************************************************************************************

  103. *    函 数 名: AppTaskStart

  104. *    功能说明: 启动任务,也是最高优先级任务,这里实现RL-TCPnet的时间基准更新。

  105. *    形    参: 无

  106. *    返 回 值: 无

  107. *   优 先 级: 5

  108. *********************************************************************************************************

  109. */

  110. __task void AppTaskStart(void)

  111. {

  112.      /* 初始化RL-TCPnet */

  113.      init_TcpNet ();

  114.    

  115.      /* 创建任务 */

  116.      AppTaskCreate();

  117.    

  118.      os_itv_set (100);

  119.    

  120.     while(1)

  121.     {

  122.          os_itv_wait ();

  123.         

  124.          /* RL-TCPnet时间基准更新函数 */

  125.          timer_tick ();

  126.          os_evt_set(0x0001, HandleTaskTCPMain);

  127.     }

  128. }
复制代码

RL-TCPnet功能测试
      这里专门创建了一个app_tcpnet_lib.c文件用于RL-TCPnet功能的测试,此文件主要实现网络主函数main_TcpNet的调用。
  1. #include "includes.h"







  2. /*

  3. *********************************************************************************************************

  4. *    函 数 名: TCPnetTest

  5. *    功能说明: TCPent测试函数。

  6. *    形    参: 无

  7. *    返 回 值: 无

  8. *********************************************************************************************************

  9. */

  10. void TCPnetTest(void)

  11. {

  12.    

  13.      while (1)

  14.      {

  15.          os_evt_wait_or(0x0001, 0xFFFF);

  16.         

  17.          /* RL-TCPnet主处理函数 */      

  18.          while (main_TcpNet() == __TRUE);

  19.      }

  20. }
复制代码

HTTP_CGI.c文件中接口函数的实现
     KEIL官网有提供HTTPCGI的接口文件,名为HTTP_CGI.c。我们就是在这个文件上修改实现,主要是函数cgi_process_data和cgi_func,其它函数未使用。关于这两个函数在本章47.7小节有详细讲解,具体实现内容如下:
  1. /*--------------------------- cgi_process_data ------------------------------*/



  2. #include <Net_Config.h>

  3. #include <stdio.h>

  4. #include <string.h>

  5. #include "bsp.h"





  6. /* ---------------------------------------------------------------------------

  7. * The HTTP server provides a small scripting language.

  8. *

  9. * The script language is simple and works as follows. Each script line starts

  10. * with a command character, either "i", "t", "c", "#" or ".".

  11. *   "i" - command tells the script interpreter to "include" a file from the

  12. *         virtual file system and output it to the web browser.

  13. *   "t" - command should be followed by a line of text that is to be output

  14. *         to the browser.

  15. *   "c" - command is used to call one of the C functions from the this file.

  16. *         It may be followed by the line of text. This text is passed to

  17. *         'cgi_func()' as a pointer to environment variable.

  18. *   "#' - command is a comment line and is ignored (the "#" denotes a comment)

  19. *   "." - denotes the last script line.

  20. *

  21. * --------------------------------------------------------------------------*/



  22. /* at_System.c */

  23. extern  LOCALM localm[];

  24. #define LocM   localm[NETIF_ETH]



  25. /* Net_Config.c */

  26. extern struct tcp_cfg   tcp_config;

  27. extern struct http_cfg  http_config;

  28. #define tcp_NumSocks    tcp_config.NumSocks

  29. #define tcp_socket      tcp_config.Scb

  30. #define http_EnAuth     http_config.EnAuth

  31. #define http_auth_passw http_config.Passw





  32. /* Local variables. */

  33. U8 LEDControl;





  34. /* My structure of CGI status U32 variable. This variable is private for */

  35. /* each HTTP Session and is not altered by HTTP Server. It is only set to  */

  36. /* zero when the cgi_func() is called for the first time.                  */

  37. typedef struct {

  38.   U16 xcnt;

  39.   U16 unused;

  40. } MY_BUF;

  41. #define MYBUF(p)        ((MY_BUF *)p)



  42. /*----------------------------------------------------------------------------

  43. * HTTP Server Common Gateway Interface Functions

  44. *---------------------------------------------------------------------------*/



  45. /*--------------------------- cgi_process_var -------------------------------*/



  46. void cgi_process_var (U8 *qs) {

  47.   /* This function is called by HTTP server to process the Querry_String   */

  48.   /* for the CGI Form GET method. It is called on SUBMIT from the browser. */

  49.   /*.The Querry_String.is SPACE terminated.                                */

  50.   U8 *var;

  51.   int s[4];



  52.   var = (U8 *)alloc_mem (40);

  53.   do {

  54.     /* Loop through all the parameters. */

  55.     qs = http_get_var (qs, var, 40);

  56.     /* Check the returned string, 'qs' now points to the next. */

  57.     if (var[0] != 0) {

  58.       /* Returned string is non 0-length. */

  59.       if (str_scomp (var, "ip=") == __TRUE) {

  60.         /* My IP address parameter. */

  61.         sscanf ((const char *)&var[3], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);

  62.         LocM.IpAdr[0]   = s[0];

  63.         LocM.IpAdr[1]   = s[1];

  64.         LocM.IpAdr[2]   = s[2];

  65.         LocM.IpAdr[3]   = s[3];

  66.       }

  67.       else if (str_scomp (var, "msk=") == __TRUE) {

  68.         /* Net mask parameter. */

  69.         sscanf ((const char *)&var[4], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);

  70.         LocM.NetMask[0] = s[0];

  71.         LocM.NetMask[1] = s[1];

  72.         LocM.NetMask[2] = s[2];

  73.         LocM.NetMask[3] = s[3];

  74.       }

  75.       else if (str_scomp (var, "gw=") == __TRUE) {

  76.         /* Default gateway parameter. */

  77.         sscanf ((const char *)&var[3], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);

  78.         LocM.DefGW[0]   = s[0];

  79.         LocM.DefGW[1]   = s[1];

  80.         LocM.DefGW[2]   = s[2];

  81.         LocM.DefGW[3]   = s[3];

  82.       }

  83.       else if (str_scomp (var, "pdns=") == __TRUE) {

  84.         /* Default gateway parameter. */

  85.         sscanf ((const char *)&var[5], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);

  86.         LocM.PriDNS[0]  = s[0];

  87.         LocM.PriDNS[1]  = s[1];

  88.         LocM.PriDNS[2]  = s[2];

  89.         LocM.PriDNS[3]  = s[3];

  90.       }

  91.       else if (str_scomp (var, "sdns=") == __TRUE) {

  92.         /* Default gateway parameter. */

  93.         sscanf ((const char *)&var[5], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);

  94.         LocM.SecDNS[0]  = s[0];

  95.         LocM.SecDNS[1]  = s[1];

  96.         LocM.SecDNS[2]  = s[2];

  97.         LocM.SecDNS[3]  = s[3];

  98.       }

  99.     }

  100.   }while (qs);

  101.   free_mem ((OS_FRAME *)var);

  102. }





  103. /*--------------------------- cgi_process_data ------------------------------*/



  104. void cgi_process_data (U8 code, U8 *dat, U16 len) {

  105.   /* This function is called by HTTP server to process the returned Data    */

  106.   /* for the CGI Form POST method. It is called on SUBMIT from the browser. */

  107.   /* Parameters:                                                            */

  108.   /*   code  - callback context code                                        */

  109.   /*           0 = www-url-encoded form data                                */

  110.   /*           1 = filename for file upload (0-terminated string)           */

  111.   /*           2 = file upload raw data                                     */

  112.   /*           3 = end of file upload (file close requested)                */

  113.   /*           4 = any xml encoded POST data (single or last stream)        */

  114.   /*           5 = the same as 4, but with more xml data to follow          */

  115.   /*               Use http_get_content_type() to check the content type    */

  116.   /*   dat   - pointer to POST received data                                */

  117.   /*   len   - received data length                                         */

  118.   U8 *var;



  119.   switch (code) {

  120.     case 0:

  121.       /* Url encoded form data received. */

  122.       break;



  123.     case 1:

  124.       /* Filename for file upload received as encoded by the browser. */

  125.       /* It might contain an absolute path to a file from the sending */

  126.       /* host. Open a file for writing. */

  127.       return;



  128.     case 2:

  129.       /* File content data received. Write data to a file. */

  130.       /* This function will be called several times with   */

  131.       /* code 2 when a big file is being uploaded.         */

  132.       return;



  133.     case 3:

  134.       /* File upload finished. Close a file. */

  135.       return;



  136.     case 4:

  137.       /* XML encoded content type, last packet. */

  138.      // pType = http_get_content_type ();

  139.       /* check the content type for CGX file request. */

  140.       /* pType is a pointer to a 0-terminated string  */

  141.       /* For example: text/xml; charset=utf-8         */

  142.       return;

  143.    

  144.     case 5:

  145.       /* XML encoded as under 4, but with more to follow. */

  146.       return;



  147.     default:

  148.       /* Ignore all other codes. */

  149.       return;

  150.   }



  151.   if (len == 0) {

  152.     /* No data or all items (radio, checkbox) are off. */

  153.     return;

  154.   }



  155.   var = (U8 *)alloc_mem (40);



  156.   do {

  157.     /* Parse all returned parameters. */

  158.     dat = http_get_var (dat, var, 40);

  159.     if (var[0] != 0) {

  160.        if (str_scomp (var, "TICK1=") == __TRUE || str_scomp (var, "pg=") == __TRUE)

  161.        {

  162.           if (str_scomp (var, "pg=") == __TRUE)

  163.           {

  164.               LEDControl = 0;

  165.           }

  166.          

  167.           if(*(var+9) =='1')

  168.           {

  169.             LEDControl |= 0x01;

  170.           }

  171.           else if(*(var+9) =='2')

  172.           {

  173.             LEDControl |= 0x02;

  174.           }

  175.           else if(*(var+9) =='3')

  176.           {

  177.             LEDControl |= 0x04;

  178.           }

  179.       }

  180.     }

  181.   }while (dat);

  182.   free_mem ((OS_FRAME *)var);



  183.   //LED Control

  184.   if(LEDControl & 0x01)

  185.   {

  186.      bsp_LedOn(1);

  187.   }

  188.   else

  189.   {

  190.      bsp_LedOff(1);   

  191.   }



  192.   if(LEDControl & 0x02)

  193.   {

  194.      bsp_LedOn(2);

  195.   }

  196.   else

  197.   {

  198.      bsp_LedOff(2);   

  199.   }



  200.   if(LEDControl & 0x04)

  201.   {

  202.      bsp_LedOn(3);

  203.   }

  204.   else

  205.   {

  206.      bsp_LedOff(3);   

  207.   }



  208. }



  209. /*--------------------------- cgi_func --------------------------------------*/



  210. U16 cgi_func (U8 *env, U8 *buf, U16 buflen, U32 *pcgi) {

  211.   /* This function is called by HTTP server script interpreter to make a    */

  212.   /* formated output for 'stdout'. It returns the number of bytes written   */

  213.   /* to the output buffer. Hi-bit of return value (len is or-ed with 0x8000)*/

  214.   /* is a repeat flag for the system script interpreter. If this bit is set */

  215.   /* to 1, the system will call the 'cgi_func()' again for the same script  */

  216.   /* line with parameter 'pcgi' pointing to a 4-byte buffer. This buffer    */

  217.   /* can be used for storing different status variables for this function.  */

  218.   /* It is set to 0 by HTTP Server on first call and is not altered by      */

  219.   /* HTTP server for repeated calls. This function should NEVER write more  */

  220.   /* than 'buflen' bytes to the buffer.                                     */

  221.   /* Parameters:                                                            */

  222.   /*   env    - environment variable string                                 */

  223.   /*   buf    - HTTP transmit buffer                                        */

  224.   /*   buflen - length of this buffer (500-1400 bytes - depends on MSS)     */

  225.   /*   pcgi   - pointer to session local buffer used for repeated loops     */

  226.   /*            This is a U32 variable - size is 4 bytes. Value is:         */

  227.   /*            - on 1st call = 0                                           */

  228.   /*            - 2nd call    = as set by this function on first call       */

  229.   U32 len = 0;

  230.   unsigned int mask;



  231.   switch (env[0]) {

  232.     /* Analyze the environment string. It is the script 'c' line starting */

  233.     /* at position 2. What you write to the script file is returned here. */

  234.        case 'T' :

  235.          if(env[1] =='1')                    

  236.          {      

  237.            mask = env[2]-'0';               

  238.            len = sprintf((char *)buf,(const char *)&env[4],(LEDControl& mask) ? "checked" : "");

  239.          }

  240.          break;

  241.       

  242.   }

  243.   return ((U16)len);

  244. }



  245. /*--------------------------- cgx_content_type ------------------------------*/

  246. #if 0

  247. U8 *cgx_content_type (void) {

  248.   /* User configurable Content-type for CGX script files. If this function */

  249.   /* is missing, or returns a NULL pointer, the default 'text/xml' content */

  250.   /* type from the library is used for xml-script file types.              */

  251.   return ("text/xml; charset=utf-8");

  252. }

  253. #endif



  254. /*--------------------------- http_encoding ---------------------------------*/



  255. #if 0

  256. U8 *http_encoding (void) {

  257.   /* User configurable character encoding for text types. If this function */

  258.   /* is missing, or returns a NULL pointer, web browser uses a default     */

  259.   /* character encoding, which is set in the browser configuration.        */

  260.   return ("utf-8");

  261. }

  262. #endif



  263. /*--------------------------- http_accept_host ------------------------------*/

  264. #if 0

  265. BOOL http_accept_host (U8 *rem_ip, U16 rem_port) {

  266.   /* This function checks if a connection from remote host is accepted or  */

  267.   /* not. If this function is missing, all remote hosts are accepted.      */



  268.    if (rem_ip[0] == 192  &&

  269.        rem_ip[1] == 168  &&

  270.        rem_ip[2] == 1    &&

  271.        rem_ip[3] == 1) {

  272.       /* Accept a connection. */

  273.       return (__TRUE);

  274.    }

  275.    /* Deny a connection. */

  276.    return (__FALSE);

  277. }

  278. #endif



  279. /*----------------------------------------------------------------------------

  280. * end of file

  281. *---------------------------------------------------------------------------*/
复制代码


努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2018-1-12 16:41:40 | 显示全部楼层
47.8.2 STM32F429开发板实验
配套例子:
      V6-1066_RL-TCPnet实验_WebServer之CGI实现动态网页(RTX)
实验目的:
      1.     学习CGI脚本实现动态网页制作方法和RL-TCPnet的Web服务器实现。
实验内容:
      1.      强烈推荐将网线接到路由器或者交换机上面测试,因为已经使能了DHCP,可以自动获取IP地址。
      2.      用户可在浏览器中直接输入IP地址访问Web服务器,跟大家访问路由器后台一样,也可以通过NetBIOS局域网域名直接访问,即http://armfly/,这样就无需查看具体IP了。
      3.      Web服务器的用户名admin,密码123456。
      4.      例子中利用CGI脚本实现了一个Web浏览器中通过复选框控制LED亮灭的功能。
      5.      关于网页的制作和Web服务器的测试方法,务必看本例子配套的教程,有详细讲解!!!
网页制作:
      详见本章节47.5小节。
配置向导文件设置(Net_Config.c):
      详见本章节47.3小节。
调试文件设置(Net_Debug.c):
      详见本章节47.4小节。
Web服务器访问效果:
      详见本章节47.6小节。
RTX配置:
     RTX配置向导详情如下:
7.40.png
                              
Task Configuration
(1)Number of concurrent running tasks
      允许创建6个任务,实际创建了如下5个任务:
      AppTaskUserIF任务   :按键消息处理。
      AppTaskLED任务     :LED闪烁。
      AppTaskMsgPro任务 :按键检测。
      AppTaskTCPMain任务:RL-TCPnet测试任务。
      AppTaskStart任务  :启动任务,也是最高优先级任务,这里实现RL-TCPnet的时间基准更新。
(2)Number of tasks with user-provided stack
      创建的5个任务都是采用自定义堆栈方式。
(3)Run in privileged mode
      设置任务运行在非特权级模式。
RTX任务调试信息:
7.41.png
程序设计:
任务栈大小分配:
      staticuint64_t AppTaskUserIFStk[1024/8];   /* 任务栈 */
      staticuint64_t AppTaskLEDStk[1024/8];      /* 任务栈 */
      staticuint64_t AppTaskMsgProStk[1024/8];  /* 任务栈 */
      staticuint64_t AppTaskTCPMainStk[4096/8]; /* 任务栈 */
       staticuint64_t AppTaskStartStk[1024/8];     /* 任务栈 */
      将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数、浮点运算和uint64_t类型数据运算会出问题。
系统栈大小分配:
7.42.png
RTX初始化:
  1. /*

  2. *********************************************************************************************************

  3. *    函 数 名: main

  4. *    功能说明: 标准c程序入口。

  5. *    形    参: 无

  6. *    返 回 值: 无

  7. *********************************************************************************************************

  8. */

  9. int main (void)

  10. {   

  11.      /* 初始化外设 */

  12.      bsp_Init();

  13.    

  14.      /* 创建启动任务 */

  15.      os_sys_init_user (AppTaskStart,              /* 任务函数 */

  16.                        5,                         /* 任务优先级 */

  17.                        &AppTaskStartStk,          /* 任务栈 */

  18.                        sizeof(AppTaskStartStk));  /* 任务栈大小,单位字节数 */

  19.      while(1);

  20. }
复制代码

硬件外设初始化
      硬件外设的初始化是在 bsp.c 文件实现:
  1. /*

  2. *********************************************************************************************************

  3. *    函 数 名: bsp_Init

  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次

  5. *    形    参:无

  6. *    返 回 值: 无

  7. *********************************************************************************************************

  8. */

  9. void bsp_Init(void)

  10. {

  11.      /*

  12.          由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。

  13.          启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。



  14.          系统时钟缺省配置为168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件

  15.      */

  16.      /* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/

  17.      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);



  18.      SystemCoreClockUpdate();    /* 根据PLL配置更新系统时钟频率变量 SystemCoreClock */



  19.      bsp_InitDWT();      /* 初始化DWT */

  20.      bsp_InitUart();     /* 初始化串口 */

  21.      bsp_InitKey();     /* 初始化按键变量(必须在 bsp_InitTimer() 之前调用) */



  22.      bsp_InitExtIO();    /* FMC总线上扩展了32位输出IO, 操作LED等外设必须初始化 */

  23.      bsp_InitLed();      /* 初始LED指示灯端口 */

  24. }
复制代码

RTX任务创建:
  1. /*

  2. *********************************************************************************************************

  3. *    函 数 名: AppTaskCreate

  4. *    功能说明: 创建应用任务

  5. *    形    参: 无

  6. *    返 回 值: 无

  7. *********************************************************************************************************

  8. */

  9. static void AppTaskCreate (void)

  10. {

  11.      HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */

  12.                                            1,                         /* 任务优先级 */

  13.                                            &AppTaskUserIFStk,         /* 任务栈 */

  14.                                            sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */

  15.    

  16.      HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */

  17.                                         2,                       /* 任务优先级 */

  18.                                         &AppTaskLEDStk,          /* 任务栈 */

  19.                                         sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */

  20.    

  21.      HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */

  22.                                            3,                         /* 任务优先级 */

  23.                                            &AppTaskMsgProStk,         /* 任务栈 */

  24.                                            sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */

  25.    

  26.     HandleTaskTCPMain = os_tsk_create_user(AppTaskTCPMain,             /* 任务函数 */

  27.                                            4,                         /* 任务优先级 */

  28.                                            &AppTaskTCPMainStk,         /* 任务栈 */

  29.                                            sizeof(AppTaskTCPMainStk)); /* 任务栈大小,单位字节数 */

  30. }
复制代码

五个RTX任务的实现:
  1. /*

  2. *********************************************************************************************************

  3. *    函 数 名: AppTaskUserIF

  4. *    功能说明: 按键消息处理     

  5. *    形    参: 无

  6. *    返 回 值: 无

  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)

  8. *********************************************************************************************************

  9. */

  10. __task void AppTaskUserIF(void)

  11. {

  12.      uint8_t ucKeyCode;



  13.     while(1)

  14.     {

  15.          ucKeyCode = bsp_GetKey();

  16.         

  17.          if (ucKeyCode != KEY_NONE)

  18.          {

  19.               switch (ucKeyCode)

  20.               {

  21.                   /* K1键按下 */

  22.                    case KEY_DOWN_K1:

  23.                        printf("K1键按下\r\n");        

  24.                        break;  

  25.                   

  26.                    /* K2键按下 */

  27.                    case KEY_DOWN_K2:

  28.                        printf("K2键按下\r\n");        

  29.                        break;  

  30.                   

  31.                    /* K3键按下 */

  32.                    case KEY_DOWN_K3:

  33.                        printf("K3键按下\r\n");

  34.                        break;

  35.                                     

  36.                    /* 其他的键值不处理 */

  37.                    default:                    

  38.                        break;

  39.               }

  40.          }

  41.         

  42.          os_dly_wait(20);

  43.      }

  44. }



  45. /*

  46. *********************************************************************************************************

  47. *    函 数 名: AppTaskLED

  48. *    功能说明: LED闪烁。

  49. *    形    参: 无

  50. *    返 回 值: 无

  51. *   优 先 级: 2

  52. *********************************************************************************************************

  53. */

  54. __task void AppTaskLED(void)

  55. {

  56.      const uint16_t usFrequency = 500; /* 延迟周期 */

  57.    

  58.      /* 设置延迟周期 */

  59.      os_itv_set(usFrequency);

  60.    

  61.     while(1)

  62.     {

  63.          bsp_LedToggle(4);



  64.          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/

  65.          os_itv_wait();

  66.     }

  67. }



  68. /*

  69. *********************************************************************************************************

  70. *    函 数 名: AppTaskMsgPro

  71. *    功能说明: 按键检测

  72. *    形    参: 无

  73. *    返 回 值: 无

  74. *   优 先 级: 3

  75. *********************************************************************************************************

  76. */

  77. __task void AppTaskMsgPro(void)

  78. {

  79.     while(1)

  80.     {

  81.          bsp_KeyScan();

  82.          os_dly_wait(10);

  83.     }

  84. }



  85. /*

  86. *********************************************************************************************************

  87. *    函 数 名: AppTaskTCPMain

  88. *    功能说明: RL-TCPnet测试任务

  89. *    形    参: 无

  90. *    返 回 值: 无

  91. *   优 先 级: 4

  92. *********************************************************************************************************

  93. */

  94. __task void AppTaskTCPMain(void)

  95. {

  96.      while (1)

  97.      {

  98.          TCPnetTest();

  99.      }

  100. }



  101. /*

  102. *********************************************************************************************************

  103. *    函 数 名: AppTaskStart

  104. *    功能说明: 启动任务,也是最高优先级任务,这里实现RL-TCPnet的时间基准更新。

  105. *    形    参: 无

  106. *    返 回 值: 无

  107. *   优 先 级: 5

  108. *********************************************************************************************************

  109. */

  110. __task void AppTaskStart(void)

  111. {

  112.      /* 初始化RL-TCPnet */

  113.      init_TcpNet ();

  114.    

  115.      /* 创建任务 */

  116.      AppTaskCreate();

  117.    

  118.      os_itv_set (100);

  119.    

  120.     while(1)

  121.     {

  122.          os_itv_wait ();

  123.         

  124.          /* RL-TCPnet时间基准更新函数 */

  125.          timer_tick ();

  126.          os_evt_set(0x0001, HandleTaskTCPMain);

  127.     }

  128. }
复制代码

RL-TCPnet功能测试
      这里专门创建了一个app_tcpnet_lib.c文件用于RL-TCPnet功能的测试,此文件主要实现网络主函数main_TcpNet的调用。
  1. #include "includes.h"







  2. /*

  3. *********************************************************************************************************

  4. *    函 数 名: TCPnetTest

  5. *    功能说明: TCPent测试函数。

  6. *    形    参: 无

  7. *    返 回 值: 无

  8. *********************************************************************************************************

  9. */

  10. void TCPnetTest(void)

  11. {

  12.    

  13.      while (1)

  14.      {

  15.          os_evt_wait_or(0x0001, 0xFFFF);

  16.         

  17.          /* RL-TCPnet主处理函数 */      

  18.          while (main_TcpNet() == __TRUE);

  19.      }

  20. }
复制代码

HTTP_CGI.c文件中接口函数的实现
      KEIL官网有提供HTTPCGI的接口文件,名为HTTP_CGI.c。我们就是在这个文件上修改实现,主要是函数cgi_process_data和cgi_func,其它函数未使用。关于这两个函数在本章47.7小节有详细讲解,具体实现内容如下:
  1. /*--------------------------- cgi_process_data ------------------------------*/



  2. #include <Net_Config.h>

  3. #include <stdio.h>

  4. #include <string.h>

  5. #include "bsp.h"





  6. /* ---------------------------------------------------------------------------

  7. * The HTTP server provides a small scripting language.

  8. *

  9. * The script language is simple and works as follows. Each script line starts

  10. * with a command character, either "i", "t", "c", "#" or ".".

  11. *   "i" - command tells the script interpreter to "include" a file from the

  12. *         virtual file system and output it to the web browser.

  13. *   "t" - command should be followed by a line of text that is to be output

  14. *         to the browser.

  15. *   "c" - command is used to call one of the C functions from the this file.

  16. *         It may be followed by the line of text. This text is passed to

  17. *         'cgi_func()' as a pointer to environment variable.

  18. *   "#' - command is a comment line and is ignored (the "#" denotes a comment)

  19. *   "." - denotes the last script line.

  20. *

  21. * --------------------------------------------------------------------------*/



  22. /* at_System.c */

  23. extern  LOCALM localm[];

  24. #define LocM   localm[NETIF_ETH]



  25. /* Net_Config.c */

  26. extern struct tcp_cfg   tcp_config;

  27. extern struct http_cfg  http_config;

  28. #define tcp_NumSocks    tcp_config.NumSocks

  29. #define tcp_socket      tcp_config.Scb

  30. #define http_EnAuth     http_config.EnAuth

  31. #define http_auth_passw http_config.Passw





  32. /* Local variables. */

  33. U8 LEDControl;





  34. /* My structure of CGI status U32 variable. This variable is private for */

  35. /* each HTTP Session and is not altered by HTTP Server. It is only set to  */

  36. /* zero when the cgi_func() is called for the first time.                  */

  37. typedef struct {

  38.   U16 xcnt;

  39.   U16 unused;

  40. } MY_BUF;

  41. #define MYBUF(p)        ((MY_BUF *)p)



  42. /*----------------------------------------------------------------------------

  43. * HTTP Server Common Gateway Interface Functions

  44. *---------------------------------------------------------------------------*/



  45. /*--------------------------- cgi_process_var -------------------------------*/



  46. void cgi_process_var (U8 *qs) {

  47.   /* This function is called by HTTP server to process the Querry_String   */

  48.   /* for the CGI Form GET method. It is called on SUBMIT from the browser. */

  49.   /*.The Querry_String.is SPACE terminated.                                */

  50.   U8 *var;

  51.   int s[4];



  52.   var = (U8 *)alloc_mem (40);

  53.   do {

  54.     /* Loop through all the parameters. */

  55.     qs = http_get_var (qs, var, 40);

  56.     /* Check the returned string, 'qs' now points to the next. */

  57.     if (var[0] != 0) {

  58.       /* Returned string is non 0-length. */

  59.       if (str_scomp (var, "ip=") == __TRUE) {

  60.         /* My IP address parameter. */

  61.         sscanf ((const char *)&var[3], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);

  62.         LocM.IpAdr[0]   = s[0];

  63.         LocM.IpAdr[1]   = s[1];

  64.         LocM.IpAdr[2]   = s[2];

  65.         LocM.IpAdr[3]   = s[3];

  66.       }

  67.       else if (str_scomp (var, "msk=") == __TRUE) {

  68.         /* Net mask parameter. */

  69.         sscanf ((const char *)&var[4], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);

  70.         LocM.NetMask[0] = s[0];

  71.         LocM.NetMask[1] = s[1];

  72.         LocM.NetMask[2] = s[2];

  73.         LocM.NetMask[3] = s[3];

  74.       }

  75.       else if (str_scomp (var, "gw=") == __TRUE) {

  76.         /* Default gateway parameter. */

  77.         sscanf ((const char *)&var[3], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);

  78.         LocM.DefGW[0]   = s[0];

  79.         LocM.DefGW[1]   = s[1];

  80.         LocM.DefGW[2]   = s[2];

  81.         LocM.DefGW[3]   = s[3];

  82.       }

  83.       else if (str_scomp (var, "pdns=") == __TRUE) {

  84.         /* Default gateway parameter. */

  85.         sscanf ((const char *)&var[5], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);

  86.         LocM.PriDNS[0]  = s[0];

  87.         LocM.PriDNS[1]  = s[1];

  88.         LocM.PriDNS[2]  = s[2];

  89.         LocM.PriDNS[3]  = s[3];

  90.       }

  91.       else if (str_scomp (var, "sdns=") == __TRUE) {

  92.         /* Default gateway parameter. */

  93.         sscanf ((const char *)&var[5], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);

  94.         LocM.SecDNS[0]  = s[0];

  95.         LocM.SecDNS[1]  = s[1];

  96.         LocM.SecDNS[2]  = s[2];

  97.         LocM.SecDNS[3]  = s[3];

  98.       }

  99.     }

  100.   }while (qs);

  101.   free_mem ((OS_FRAME *)var);

  102. }





  103. /*--------------------------- cgi_process_data ------------------------------*/



  104. void cgi_process_data (U8 code, U8 *dat, U16 len) {

  105.   /* This function is called by HTTP server to process the returned Data    */

  106.   /* for the CGI Form POST method. It is called on SUBMIT from the browser. */

  107.   /* Parameters:                                                            */

  108.   /*   code  - callback context code                                        */

  109.   /*           0 = www-url-encoded form data                                */

  110.   /*           1 = filename for file upload (0-terminated string)           */

  111.   /*           2 = file upload raw data                                     */

  112.   /*           3 = end of file upload (file close requested)                */

  113.   /*           4 = any xml encoded POST data (single or last stream)        */

  114.   /*           5 = the same as 4, but with more xml data to follow          */

  115.   /*               Use http_get_content_type() to check the content type    */

  116.   /*   dat   - pointer to POST received data                                */

  117.   /*   len   - received data length                                         */

  118.   U8 *var;



  119.   switch (code) {

  120.     case 0:

  121.       /* Url encoded form data received. */

  122.       break;



  123.     case 1:

  124.       /* Filename for file upload received as encoded by the browser. */

  125.       /* It might contain an absolute path to a file from the sending */

  126.       /* host. Open a file for writing. */

  127.       return;



  128.     case 2:

  129.       /* File content data received. Write data to a file. */

  130.       /* This function will be called several times with   */

  131.       /* code 2 when a big file is being uploaded.         */

  132.       return;



  133.     case 3:

  134.       /* File upload finished. Close a file. */

  135.       return;



  136.     case 4:

  137.       /* XML encoded content type, last packet. */

  138.      // pType = http_get_content_type ();

  139.       /* check the content type for CGX file request. */

  140.       /* pType is a pointer to a 0-terminated string  */

  141.       /* For example: text/xml; charset=utf-8         */

  142.       return;

  143.    

  144.     case 5:

  145.       /* XML encoded as under 4, but with more to follow. */

  146.       return;



  147.     default:

  148.       /* Ignore all other codes. */

  149.       return;

  150.   }



  151.   if (len == 0) {

  152.     /* No data or all items (radio, checkbox) are off. */

  153.     return;

  154.   }



  155.   var = (U8 *)alloc_mem (40);



  156.   do {

  157.     /* Parse all returned parameters. */

  158.     dat = http_get_var (dat, var, 40);

  159.     if (var[0] != 0) {

  160.        if (str_scomp (var, "TICK1=") == __TRUE || str_scomp (var, "pg=") == __TRUE)

  161.        {

  162.           if (str_scomp (var, "pg=") == __TRUE)

  163.           {

  164.               LEDControl = 0;

  165.           }

  166.          

  167.           if(*(var+9) =='1')

  168.           {

  169.             LEDControl |= 0x01;

  170.           }

  171.           else if(*(var+9) =='2')

  172.           {

  173.             LEDControl |= 0x02;

  174.           }

  175.           else if(*(var+9) =='3')

  176.           {

  177.             LEDControl |= 0x04;

  178.           }

  179.       }

  180.     }

  181.   }while (dat);

  182.   free_mem ((OS_FRAME *)var);



  183.   //LED Control

  184.   if(LEDControl & 0x01)

  185.   {

  186.      bsp_LedOn(1);

  187.   }

  188.   else

  189.   {

  190.      bsp_LedOff(1);   

  191.   }



  192.   if(LEDControl & 0x02)

  193.   {

  194.      bsp_LedOn(2);

  195.   }

  196.   else

  197.   {

  198.      bsp_LedOff(2);   

  199.   }



  200.   if(LEDControl & 0x04)

  201.   {

  202.      bsp_LedOn(3);

  203.   }

  204.   else

  205.   {

  206.      bsp_LedOff(3);   

  207.   }



  208. }



  209. /*--------------------------- cgi_func --------------------------------------*/



  210. U16 cgi_func (U8 *env, U8 *buf, U16 buflen, U32 *pcgi) {

  211.   /* This function is called by HTTP server script interpreter to make a    */

  212.   /* formated output for 'stdout'. It returns the number of bytes written   */

  213.   /* to the output buffer. Hi-bit of return value (len is or-ed with 0x8000)*/

  214.   /* is a repeat flag for the system script interpreter. If this bit is set */

  215.   /* to 1, the system will call the 'cgi_func()' again for the same script  */

  216.   /* line with parameter 'pcgi' pointing to a 4-byte buffer. This buffer    */

  217.   /* can be used for storing different status variables for this function.  */

  218.   /* It is set to 0 by HTTP Server on first call and is not altered by      */

  219.   /* HTTP server for repeated calls. This function should NEVER write more  */

  220.   /* than 'buflen' bytes to the buffer.                                     */

  221.   /* Parameters:                                                            */

  222.   /*   env    - environment variable string                                 */

  223.   /*   buf    - HTTP transmit buffer                                        */

  224.   /*   buflen - length of this buffer (500-1400 bytes - depends on MSS)     */

  225.   /*   pcgi   - pointer to session local buffer used for repeated loops     */

  226.   /*            This is a U32 variable - size is 4 bytes. Value is:         */

  227.   /*            - on 1st call = 0                                           */

  228.   /*            - 2nd call    = as set by this function on first call       */

  229.   U32 len = 0;

  230.   unsigned int mask;



  231.   switch (env[0]) {

  232.     /* Analyze the environment string. It is the script 'c' line starting */

  233.     /* at position 2. What you write to the script file is returned here. */

  234.        case 'T' :

  235.          if(env[1] =='1')                    

  236.          {      

  237.            mask = env[2]-'0';               

  238.            len = sprintf((char *)buf,(const char *)&env[4],(LEDControl& mask) ? "checked" : "");

  239.          }

  240.          break;

  241.       

  242.   }

  243.   return ((U16)len);

  244. }



  245. /*--------------------------- cgx_content_type ------------------------------*/

  246. #if 0

  247. U8 *cgx_content_type (void) {

  248.   /* User configurable Content-type for CGX script files. If this function */

  249.   /* is missing, or returns a NULL pointer, the default 'text/xml' content */

  250.   /* type from the library is used for xml-script file types.              */

  251.   return ("text/xml; charset=utf-8");

  252. }

  253. #endif



  254. /*--------------------------- http_encoding ---------------------------------*/



  255. #if 0

  256. U8 *http_encoding (void) {

  257.   /* User configurable character encoding for text types. If this function */

  258.   /* is missing, or returns a NULL pointer, web browser uses a default     */

  259.   /* character encoding, which is set in the browser configuration.        */

  260.   return ("utf-8");

  261. }

  262. #endif



  263. /*--------------------------- http_accept_host ------------------------------*/

  264. #if 0

  265. BOOL http_accept_host (U8 *rem_ip, U16 rem_port) {

  266.   /* This function checks if a connection from remote host is accepted or  */

  267.   /* not. If this function is missing, all remote hosts are accepted.      */



  268.    if (rem_ip[0] == 192  &&

  269.        rem_ip[1] == 168  &&

  270.        rem_ip[2] == 1    &&

  271.        rem_ip[3] == 1) {

  272.       /* Accept a connection. */

  273.       return (__TRUE);

  274.    }

  275.    /* Deny a connection. */

  276.    return (__FALSE);

  277. }

  278. #endif



  279. /*----------------------------------------------------------------------------

  280. * end of file

  281. *---------------------------------------------------------------------------*/

  282. /*--------------------------- http_accept_host ------------------------------*/

  283. #if 0

  284. BOOL http_accept_host (U8 *rem_ip, U16 rem_port) {

  285.   /* This function checks if a connection from remote host is accepted or  */

  286.   /* not. If this function is missing, all remote hosts are accepted.      */



  287.    if (rem_ip[0] == 192  &&

  288.        rem_ip[1] == 168  &&

  289.        rem_ip[2] == 1    &&

  290.        rem_ip[3] == 1) {

  291.       /* Accept a connection. */

  292.       return (__TRUE);

  293.    }

  294.    /* Deny a connection. */

  295.    return (__FALSE);

  296. }

  297. #endif



  298. /*----------------------------------------------------------------------------

  299. * end of file

  300. *---------------------------------------------------------------------------*/
复制代码


努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2018-1-12 16:42:25 | 显示全部楼层
47.9 总结
      本章节就为大家讲解这么多,其中网页的制作比较麻烦,希望大家实际动手操作一遍,并将其熟练掌握

努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-4 04:15 , Processed in 0.342393 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表