6.案例——最简单的TCP echo程序
先来一个最简单的TCP程序。uIP作为server,IP地址为192.168.1.15。PC机做client,IP地址为192.168.1.10X。 【1】在网络调试助手中,选择以太网通信种类为client(表示PC机为Client),IP地址输入192.168.1.15,端口号输入1234。最后点击连接。 【2】在发送区域输入任意内容,点击发送数据。 【3】观察返回结果,是否和发送数据相同。 为了实现该功能新建example1.c和example1.两个文件。代码如下: #include "example1.h" #include "uip.h" #include <string.h> #include <stdio.h> #include <stdint.h> void example1_init(void) { uip_listen(HTONS(1234)); } void example1_appcall(void) { if( uip_newdata() ) { // 输出远程IP和端口号 printf("remote ip addr:%d.%d.%d.%d\r\n", (uip_conn->ripaddr[0]) & 0X00ff, (uip_conn->ripaddr[0]) >> 8, (uip_conn->ripaddr[1]) & 0X00ff, (uip_conn->ripaddr[1]) >> 8 ); printf("remote ip port:%d\r\n",HTONS(uip_conn->rport)); // TCP ECHO uip_send(uip_appdata,uip_len); } } 图3 TCP Echo实验结果 代码做如下分析: 1. uip_listen(HTONS(1234));侦听1234端口, 2. uip_newdata()即查询uip_buf中是否有新数据,如果返回1的话,表示接收到新数据。 3. uip_send(uip_appdata,uip_len);uip_send为发送数据报函数 4. uip_appdata指向用户数据,所谓用户数据即TCP负载数据,例如网络调试助手发送XX,那么uip_appdata指向xukai871105. 5. uip_len为用户数据长度,若串口调试助手发送XX,那么uip_len为11。 7.web页面控制1. 打开IE浏览器,地址栏输入DM9051的IP地址: 回车后打开下面控制页面: 2. 网頁下可以看到MCU跟IP基本訊息(如:MAC、IP address),最下面有LED Test,可通过网页控制STM32板上的LED灯。 LED Test說明,在按下 ON 的時候,GPIOF6 腳位LED 燈會亮,按下OFF後會滅掉,Flash 代表閃爍,會從GPIOF6 ~9 LED順序亮滅,网址列上會顯示LED1跟LED0,1代表亮,0但表滅,2代表閃爍。
3. 具体code如下介紹: (1). 稍微介绍一下web相关,另外标出端口、IP、GPIO/LED的修改位置。 在void main()中,系統初始化完成後加入httpd_init(); 來初始化webserver port,預設web 用80 port。 (2). 在初始化完成後,在uip-conf.h最下面將#include "webserver.h"的注釋拿掉,這樣UIP_APPCALL 就能對應到 httpd_appcall。 (3). 首先我們先在main.c初始 LED燈GPIO PIN,代码如下: void LedInit(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOF, ENABLE); /*初始化 GPIOF的 Pin_6为推挽输出*/ GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOF,&GPIO_InitStructure); /*初始化 GPIOF的 Pin_7为推挽输出*/ GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOF,&GPIO_InitStructure); /*初始化 GPIOF的 Pin_8为推挽输出*/ GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOF,&GPIO_InitStructure); /*初始化 GPIOF的 Pin_9为推挽输出*/ GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOF,&GPIO_InitStructure); } 初始化完成后,在webserver目录下新增web_led.c和web_led.h档,代码參考如下: (1). 首先設定LED 亮灭delay 时间: void Delay(uint32_t times) { while(times--) { uint32_t i; for (i=0; i<0xffff; i++); } } (2). 接下來設定LED 亮滅順序,我們使用ascii码來判斷亮滅, void Set_LED_mode(char lkkcode) { //int i; /* 0代表LED6滅, 1代表LED6亮, 2代表LED6~9依序閃爍 */ if(lkkcode == ('0')) { GPIO_ResetBits(GPIOF,GPIO_Pin_6); }else if (lkkcode == '1'){ GPIO_SetBits(GPIOF,GPIO_Pin_6); }else if(lkkcode == '2') { //for(i = 0 ; i< 30 ; ++i) { GPIO_SetBits(GPIOF,GPIO_Pin_6); Delay(25); GPIO_ResetBits(GPIOF,GPIO_Pin_6); Delay(25); GPIO_SetBits(GPIOF,GPIO_Pin_7); Delay(25); GPIO_ResetBits(GPIOF,GPIO_Pin_7); Delay(25); GPIO_SetBits(GPIOF,GPIO_Pin_8); Delay(25); GPIO_ResetBits(GPIOF,GPIO_Pin_8); Delay(25); GPIO_SetBits(GPIOF,GPIO_Pin_9); Delay(25); GPIO_ResetBits(GPIOF,GPIO_Pin_9); Delay(25); } } } (3). 设定好初始化LED GPIO后,在网址列输入IP后会显预设的示网页,网页内容为html放在app/webserver/ httpd-fs目录下,主要为index.html,如想要修改显示使用者网页有两种方式: (4). 修改代码参考如下: 1. 直接修改index.html。 2. 将使用者的html 放入httpd-fs目录下,然后在handle_input修改 3. 判断LED亮灭,s->inputbuf array中填入ascii码或其他使用者想实现的判断,如s->inputbuf[3] = 'L','E','D'。 static PT_THREAD(handle_input(struct httpd_state *s)) { PSOCK_BEGIN(&s->sin); PSOCK_READTO(&s->sin, ISO_space); if(strncmp(s->inputbuf, http_get, 4) != 0) { PSOCK_CLOSE_EXIT(&s->sin); } PSOCK_READTO(&s->sin, ISO_space); if(s->inputbuf[0] != ISO_slash) { PSOCK_CLOSE_EXIT(&s->sin); } if(s->inputbuf[1] == ISO_space) { //strncpy(s->filename, http_index_html, sizeof(s->filename)); //修改成想要顯示的html檔,如下: strncpy(s->filename, http_webMain_html, sizeof(s->filename)); } /* Control led , 0 = OFF, 1 = ON, 2 = Flash */ #if 1 //Joseph add else if (s->inputbuf[3] == 'L','E','D' && ((s->inputbuf[4] == '0') || (s->inputbuf[4] == '1') || (s->inputbuf[4] == '2'))){ Set_LED_mode(s->inputbuf[4]); s->inputbuf[4]= 0; //strncpy(s->filename, "/home.html", 10); strncpy(s->filename, http_webMain_html, sizeof(s->filename)); } #endif else { s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0; strncpy(s->filename, &s->inputbuf[0], sizeof(s->filename)); } /* httpd_log_file(uip_conn->ripaddr, s->filename);*/ s->state = STATE_OUTPUT; while(1) { PSOCK_READTO(&s->sin, ISO_nl); if(strncmp(s->inputbuf, http_referer, 8) == 0) { s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0; /* httpd_log(&s->inputbuf[9]);*/ } } PSOCK_END(&s->sin); } (5).上面介绍完网頁和控制LED燈后,接著說明如何在网頁上显示目前的MAC、IP address等,在httpd-cgi.c档下新增sys_ stats function,代码參考如下: static unsigned short generate_sys_stats(void *arg) { struct httpd_state *s = (struct httpd_state *)arg; return snprintf((char *)uip_appdata, UIP_APPDATA_SIZE, "<tr> <td >MAC Address :</td> <td style=\"text-align: left\">%02x:%02x:%02x:%02x:%02x:%02x</td> </tr> \ <tr> <td >IP Address : </td> <td style=\"text-align: left\"> %d.%d.%d.%d </td> </tr> \ <tr> <td >Network Mask : </td> <td style=\"text-align: left\"> %d.%d.%d.%d </td> </tr> \ <tr><td >Getway : </td> <td style=\"text-align: left\"> %d.%d.%d.%d </td> </tr>\r\n", /* MAC address */ (unsigned int)uip_ethaddr.addr[0], (unsigned int)uip_ethaddr.addr[1], (unsigned int)uip_ethaddr.addr[2], (unsigned int)uip_ethaddr.addr[3], (unsigned int)uip_ethaddr.addr[4], (unsigned int)uip_ethaddr.addr[5], /* IP address */ (uip_hostaddr[0]&0xff), ((uip_hostaddr[0] >> 8)&0xff), (uip_hostaddr[1]&0xff), ((uip_hostaddr[1] >> 8)&0xff), /* network mask */ (uip_netmask[0]&0xff), ((uip_netmask[0] >> 8)&0xff), (uip_netmask[1]&0xff), ((uip_netmask[1] >> 8)&0xff), /* Getway address */ (uip_draddr[0]&0xff), ((uip_draddr[0] >> 8)&0xff), (uip_draddr[1]&0xff), ((uip_draddr[1] >> 8)&0xff) ); } static PT_THREAD(sys_stats(struct httpd_state *s, char *ptr)) { PSOCK_BEGIN(&s->sout); //for(s->count = 0; s->count < UIP_CONNS; ++s->count) { if((uip_conns[s->count].tcpstateflags & UIP_TS_MASK) != UIP_CLOSED) { PSOCK_GENERATOR_SEND(&s->sout, generate_sys_stats, s); } //} PSOCK_END(&s->sout);
|