2014年(2)
分类: 嵌入式
2014-01-18 16:18:15
uIP主要用于8位或16位嵌入式系统中,以解决单片机在网络中的通信问题。本案例是uIP基于stm32下的移植,使之能在stm32平台下能进行网络通信。在uIP下一个IP包最大长度为1500 bytes,最小不能低于60。每0.5s读一个IP包,即一个IP包读取的速度为3kbytes/s,则uIP的最大传输速度为24kbps。
在Net中主要做的是Net与MSG Mannge的数据交互,Net与Prv中的数据交互,Net又主要是通过Rj45或者是通过3G网连接到网络的。而在Net的一切的数据交互中,都是通过网络来控制完成。
Net uIP主要工作:
在Net中要做的事有:
1、 以mac登陆,连通网络;
2、 查看Msg Manage的相关信息;由于查的命令是通过网络的,在得到数据这后还的在发到,网络上去。
Client -> MSG -> NET-> MSG -> host
Client <- MSG<- NET <- MSG <- host
3、 在Prv中有实时数据(包括出错信息等)传出,在Net中要处理,可能会与MSG Manage 交互,flash交互,,在实时数据的读取上,要有时钟控制监听,在时钟内不断的去轮询是否有实时数据到达,有则优先处理实时数据。
4、 登陆后还可能要做些配置管理,如IP,gateway, netmask,,或者是密码的修改等。
5、 命令下达管理。
6、 以后可能还要实现,软件的远程升级等。
在整个案例中所在解决的问题有:
1、 解决uIP下基于TCP协议的webserver服务,使之能实现服务器端与客户端的正常通信。
2、 定义集中器中uIP下的网络通信协议书。使各种要处理的事件数据能在网络中正常传输。
在移植中UIP_BUFSIZE d的最大长为1500(在驱动中可以一次收发的长为1500),而tcpbuf用来存收到的uip_len,tcpbuf最大限度长可以为1440(1500-60),60长为TCP+IP头。
--------------------------------------------------------------------------------------------------------------------
tcp_demoappcall.c
//TCP应用接口函数(UIP_APPCALL)
//完成TCP服务(包括server和client)和HTTP服务
void tcp_demo_appcall(void)
{
switch(uip_conn->lport)//本地监听端口80和1200
{
case HTONS(HTTPPORT):
httpd_appcall();
break;
case HTONS(CLIENTPORT):
tcp_server_demo_appcall();
break;
default:
break;
}
switch(uip_conn->rport) //远程连接1400端口
{
case HTONS(SERVERPORT):
tcp_client_demo_appcall();
break;
default:
break;
}
------------------------------------------------------------------------------------------------------------------------------
tcp_client.c
#include "uip.h"
#include
#include
u8 g_loginflag=1;
u32 g_logtime;
u32 g_relogtime;
u16 g_revnumb;
u8 pmac[4] = {0x11,0x10,0x3c,0x11};
u8 tcp_client_databuf[TCPLEN]; //发送数据缓存
u8 tcp_client_sta; //客户端状态
//[7]:0,无连接;1,已经连接;
//[6]:0,无数据;1,收到客户端数据
//[5]:0,无数据;1,有数据需要发送
//这是一个TCP 客户端应用回调函数。
//该函数通过UIP_APPCALL(tcp_demo_appcall)调用,实现Web Client的功能.
//当uip事件发生时,UIP_APPCALL函数会被调用,根据所属端口(1400),确定是否执行该函数。
//例如 : 当一个TCP连接被创建时、有新的数据到达、数据已经被应答、数据需要重发等事件
void tcp_client_demo_appcall(void)
{
u16 i;
u16 mbuflen;
u8 heattime;
u32 heatlen;
struct tcp_demo_appstate *s = (struct tcp_demo_appstate *)&uip_conn->appstate;
if(uip_aborted())tcp_client_aborted(); //连接终止
if(uip_timedout())tcp_client_timedout(); //连接超时
if(uip_closed())tcp_client_closed(); //连接关闭
if(uip_connected())tcp_client_connected(); //连接成功
if(uip_acked())tcp_client_acked(); //发送的数据成功送达
//接收到一个新的TCP数据包
mbuflen = TCPLEN-1;
if (uip_newdata())
{
if((tcp_client_sta&(1<<6))==0)//还未收到数据
{
if(uip_len>mbuflen)
{
((u8*)uip_appdata)[mbuflen]=0;
}
//strcpy((char*)tcp_client_databuf,uip_appdata);
for(i = 0;i
tcp_client_databuf[i] = ((u8*)uip_appdata)[i];
}
tcp_client_sta|=1<<6;//表示收到客户端数据
}
}else if(tcp_client_sta&(1<<5))//有数据需要发送
{
s->textptr=tcp_client_databuf;
s->textlen=strlen((const char*)tcp_client_databuf);
tcp_client_sta&=~(1<<5);//清除标记
}
/*
//当需要重发、新数据到达、数据包送达、连接建立时,通知uip发送数据
if(uip_rexmit()||uip_newdata()||uip_acked()||uip_connected()||uip_poll())
{
tcp_client_senddata();
}*/
if(tcp_client_sta&(1<<7)) // 连接成功
{
if(g_loginflag)
{
g_revnumb = LogInToPc(CMD_LOGINPC, pmac);
g_logtime = t1_unixTime;
g_loginflag = 0;
}
if(g_heatflag)
{
g_heatnow = t1_unixTime;
heattime = g_heatnow-g_heatbefor;
if(heattime >= 60)
{
heatlen = heatbeat(CMD_HEARTBEATACK, pmac);
//uip_send(s_RevPcBuf,heatlen+2);
g_heatbefor=0;
g_heatnow = 0;
g_heatflag = 0;
}
}
if(g_loginflag == 0)
{
if(uip_rexmit())
{
AgainLogInToPc(CMD_LOGINPC, pmac, g_revnumb);
}
}
if(g_heatflag == 0)
{
if(uip_rexmit())
{
Againheatbeat(CMD_HEARTBEATACK, pmac, heatlen);
}
}
}
}
//这里我们假定Server端的IP地址为:192.168.1.103
//这个IP必须根据Server端的IP修改.
//尝试重新连接
u8 host_ip_buff[4]={192,168,0,149}; //serv 121
void tcp_client_reconnect()
{
uip_ipaddr_t ipaddr;
uip_ipaddr(&ipaddr,host_ip_buff[0],host_ip_buff[1],host_ip_buff[2],host_ip_buff[3]); //设置IP为192.168.1.103
vTaskDelay(1);
uip_connect(&ipaddr,htons(SERVERPORT)); //端口为1400
}
u8 Connect(u8 i1,u8 i2,u8 i3,u8 i4)
{
uip_ipaddr_t ipaddr;
host_ip_buff[0] = i1;
host_ip_buff[1] = i2;
host_ip_buff[2] = i3;
host_ip_buff[3] = i4;
uip_ipaddr(&ipaddr,host_ip_buff[0],host_ip_buff[1],host_ip_buff[2],host_ip_buff[3]); //设置IP为192.168.1.103
uip_connect(&ipaddr,htons(SERVERPORT)); //端口为1400
}
//终止连接
void tcp_client_aborted(void)
{
tcp_client_sta&=~(1<<7); //标志没有连接
#if UARTPRINT
if(uip_aborted())
{
Uartprint(7,"\4aborted");
}
#endif
g_loginflag = 1;
tcp_client_reconnect(); //尝试重新连接
//uip_log("tcp_client aborted!\r\n");//打印log
}
//连接超时
void tcp_client_timedout(void)
{
tcp_client_sta&=~(1<<7); //标志没有连接
#if UARTPRINT
if(uip_timedout())
{
Uartprint(7,"\4outtime");
}
#endif
g_loginflag = 1;
tcp_client_reconnect(); //尝试重新连接
//uip_log("tcp_client timeout!\r\n");//打印log
}
//连接关闭
void tcp_client_closed(void)
{
tcp_client_sta&=~(1<<7); //标志没有连接
#if UARTPRINT
if(uip_closed())
{
Uartprint(6,"\4closed");
}
#endif
g_loginflag = 1;
tcp_client_reconnect(); //尝试重新连接
//uip_log("tcp_client closed!\r\n");//打印log
}
//连接建立
void tcp_client_connected(void)
{
struct tcp_demo_appstate *s=(struct tcp_demo_appstate *)&uip_conn->appstate;
tcp_client_sta|=1<<7; //标志连接成功
#if UARTPRINT
if(uip_connected())
{
Uartprint(9,"\4connected");
}
#endif
//uip_log("tcp_client connected!\r\n");//打印log
s->state=STATE_CMD; //指令状态
s->textlen=0;
#if 0
s->textptr="ALIENTEK STM32 Board Connected Successfully!\r\n";//回应消息
s->textlen=strlen((char *)s->textptr);
#endif
//if(LogIn(uip_ethaddr.addr,(char *)scanf("%s", mPassWord)) == 0)
//pritnf("log in is Successfull!\r\n");
}
//发送的数据成功送达
void tcp_client_acked(void)
{
struct tcp_demo_appstate *s=(struct tcp_demo_appstate *)&uip_conn->appstate;
s->textlen=0;//发送清零
//uip_log("tcp_client acked!\r\n");//表示成功发送
}
//发送数据给服务端
void tcp_client_senddata(void)
{
struct tcp_demo_appstate *s = (struct tcp_demo_appstate *)&uip_conn->appstate;
//s->textptr:发送的数据包缓冲区指针
//s->textlen:数据包的大小(单位字节)
if(s->textlen>0)uip_send(s->textptr, s->textlen);//发送TCP数据包
}
------------------------------------------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////////////
u8 tcp_server_databuf[TCPLEN]; //发送数据缓存
u8 tcp_server_sta; //服务端状态
//[7]:0,无连接;1,已经连接;
//[6]:0,无数据;1,收到客户端数据
//[5]:0,无数据;1,有数据需要发送
//这是一个TCP 服务器应用回调函数。
//该函数通过UIP_APPCALL(tcp_demo_appcall)调用,实现Web Server的功能.
//当uip事件发生时,UIP_APPCALL函数会被调用,根据所属端口(1200),确定是否执行该函数。
//例如 : 当一个TCP连接被创建时、有新的数据到达、数据已经被应答、数据需要重发等事件
void tcp_server_demo_appcall(void)
{
u16 mbuflen;
struct tcp_demo_appstate *s = (struct tcp_demo_appstate *)&uip_conn->appstate;
if(uip_aborted())tcp_server_aborted(); //连接终止
if(uip_timedout())tcp_server_timedout(); //连接超时
if(uip_closed())tcp_server_closed(); //连接关闭
if(uip_connected())tcp_server_connected(); //连接成功
if(uip_acked())tcp_server_acked(); //发送的数据成功送达
//接收到一个新的TCP数据包
mbuflen = TCPLEN-1;
if (uip_newdata())//收到客户端发过来的数据
{
if((tcp_server_sta&(1<<6))==0)//还未收到数据
{
if(uip_len>mbuflen)
{
((u8*)uip_appdata)[mbuflen]=0;
}
strcpy((char*)tcp_server_databuf,uip_appdata);
//printf("ssss%d\n",tcp_server_databuf[0]);
tcp_server_sta|=1<<6;//表示收到客户端数据
}
}else if(tcp_server_sta&(1<<5))//有数据需要发送
{
s->textptr=tcp_server_databuf;
s->textlen=strlen((const char*)tcp_server_databuf);
tcp_server_sta&=~(1<<5);//清除标记
}
//当需要重发、新数据到达、数据包送达、连接建立时,通知uip发送数据
if(uip_rexmit()||uip_newdata()||uip_acked()||uip_connected()||uip_poll())
{
tcp_server_senddata();
}
}
//终止连接
void tcp_server_aborted(void)
{
tcp_server_sta&=~(1<<7); //标志没有连接
//uip_log("tcp_server aborted!\r\n");//打印log
}
//连接超时
void tcp_server_timedout(void)
{
tcp_server_sta&=~(1<<7); //标志没有连接
//uip_log("tcp_server timeout!\r\n");//打印log
}
//连接关闭
void tcp_server_closed(void)
{
tcp_server_sta&=~(1<<7); //标志没有连接
//uip_log("tcp_server closed!\r\n");//打印log
}
//连接建立
void tcp_server_connected(void)
{
struct tcp_demo_appstate *s = (struct tcp_demo_appstate *)&uip_conn->appstate;
//uip_conn结构体有一个"appstate"字段指向应用程序自定义的结构体。
//声明一个s指针,是为了便于使用。
//不需要再单独为每个uip_conn分配内存,这个已经在uip中分配好了。
//在uip.c 中 的相关代码如下:
// struct uip_conn *uip_conn;
// struct uip_conn uip_conns[UIP_CONNS]; //UIP_CONNS缺省=10
//定义了1个连接的数组,支持同时创建几个连接。
//uip_conn是一个全局的指针,指向当前的tcp或udp连接。
tcp_server_sta|=1<<7; //标志连接成功
//uip_log("tcp_server connected!\r\n");//打印log
s->state=STATE_CMD; //指令状态
s->textlen=0;
s->textptr="Connect to ALIENTEK STM32 Board Successfully!\r\n";
s->textlen=strlen((char *)s->textptr);
}
//发送的数据成功送达
void tcp_server_acked(void)
{
struct tcp_demo_appstate *s=(struct tcp_demo_appstate *)&uip_conn->appstate;
s->textlen=0;//发送清零
//uip_log("tcp_server acked!\r\n");//表示成功发送
}
//发送数据给客户端
void tcp_server_senddata(void)
{
struct tcp_demo_appstate *s = (struct tcp_demo_appstate *)&uip_conn->appstate;
//s->textptr : 发送的数据包缓冲区指针
//s->textlen :数据包的大小(单位字节)
if(s->textlen>0)uip_send(s->textptr, s->textlen);//发送TCP数据包
}