123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394 |
- #include "includes.h"
- /*文件描述
- 1、本文件主要处理终端向服务器授权的功能,DTU作为中间的网络桥梁
- 2、主要通讯链路包括两部分:终端<-->DTU, DTU<-->服务器
- 3、终端到DTU之间的通讯是自定义协议,带加密
- 4、DTU到服务器之间使用部标协议,自定义消息ID
- 5、支持多串口通道授权操作,每个串口要独立配置好外设
- */
- CHANNEL_DEF channel[CHANNEL_NUM];
- void authSendCmd(unsigned char cmd, unsigned char *data, unsigned char len);
- unsigned char authSocketStatus;
- //授权初始化
- void authNewInit(void)
- {
- unsigned char i;
- for(i=0;i<CHL_TOTAL;i++) memset((unsigned char *)&channel[i], 0, sizeof(CHANNEL_DEF));
- authSocketStatus=0;
- }
- //DTU处理终端发过来的协议包
- char authHandleData(char uartType,unsigned char *data, unsigned short len)
- {
- unsigned short i;
- unsigned char sum=0;
- unsigned char temp[3];
- unsigned char *dataPtr=data+3;
- unsigned char id[UNIQUE_ID_BYTES];
- unsigned char queuebuf[4];//
- if(data[0] != PRO_HEADER) return 1;
- if((data[2]+3) != len) return 2;
-
- for(i=0;i<len-1;i++) sum ^= data[i];
- if(sum != data[len-1]) return 3;
-
- temp[0]=len;
- temp[1]=data[0];
- temp[2]=data[1];
- for(i=0;i<data[2]-1;i++){
- dataPtr[i] ^= temp[i % 3];
- dataPtr[i] ^= TX_RX_SEED;
- }
- memcpy(id, dataPtr+2, UNIQUE_ID_BYTES);
- if(data[1]==PRO_AUTH_REQ){//终端请求鉴权
- //请求信息压进队列去
- if(channel[uartType].root==0){//此通道还没有发起来鉴权请求
- NEED_AUTH:
- channel[uartType].root=1;
- channel[uartType].reqTime=0;
- memcpy(channel[uartType].id, id, UNIQUE_ID_BYTES);
- channel[uartType].result=SER_AUTH_BUSY;
- }else{//已经有数据了
- if(0 != memcmp(id, channel[uartType].id,sizeof(id))) goto NEED_AUTH;//不相等,表示是新设备请求鉴权
- else{//已存在,如果是已经失败的状态下,也要允许重新请求鉴权
- goto NEED_AUTH;
- }
- }
- }else if(data[1]==PRO_AUTH_OK){//终端鉴权码与服务器给的一致
- if(channel[uartType].root != 0){
- channel[uartType].result=SER_AUTH_DEV_OK_DLY;
- channel[uartType].waitTime=os_time_get()+50;
- }
- //显示成功状态
- }else if(data[1]==PRO_AUTH_FAI){//终端鉴权码与服务器给的不一致
- if(channel[uartType].root != 0){
- channel[uartType].result=SER_AUTH_DEV_FAI;
- }
- }
- }
- //多通道授权状态机处理接口
- void AuthIndicator(void)
- {
- CHANNEL_TYPEENUM scanChannel;
-
- for(scanChannel=CHL_UART1;scanChannel<CHL_TOTAL;scanChannel++){
- if(channel[scanChannel].root != 0){
- switch(channel[scanChannel].result){
- case SER_AUTH_IDLE://通道空闲,没有终端鉴权请求
- break;
- case SER_AUTH_BUSY://通道忙,表示正在处理终端鉴权请求
- break;
- case SER_AUTH_OK://鉴权成功,可以显示状态,但不清除结构体,通知终端成功了
- authSendCmd(PRO_AUTH_SUC,(unsigned char *)&channel[scanChannel].encodeValue,4);
- channel[scanChannel].result=SER_AUTH_WAIT;
- channel[scanChannel].waitTime=os_time_get()+200;
- break;
- case SER_AUTH_WAIT:
- if(os_time_get()>channel[scanChannel].waitTime){
- //两秒超时终端没响应,则清掉本结构体
- memset((unsigned char *)&channel[scanChannel], 0, sizeof(CHANNEL_DEF));
- channel[scanChannel].result=SER_AUTH_IDLE;
- }
- break;
- case SER_AUTH_FAILED:break;//鉴权失败,可以显示状态,但不清除结构体
- case SER_AUTH_DEV_OK_DLY://防止由于鉴权太快了,灯看不到灭的瞬间而作出的一小会灭延时
- if(os_time_get()>channel[scanChannel].waitTime){
- channel[scanChannel].result=SER_AUTH_DEV_OK;
- }
- break;
- }
- }
- }
- }
- void ModemTryAuthNow(unsigned char *id);
- //应用发起向服务器请求授权的入口
- void ModemSendAuthReqHandle(void)
- {
- static CHANNEL_TYPEENUM scanChannel=CHL_UART1;
- static unsigned int tick=0;
- unsigned char reReqNum;
- AuthIndicator();
- if(sutModemStatus.PDPStatus != OPENED) return;
- if(authSocketStatus==0) return;
- if(os_time_get()<tick) return;
- tick=os_time_get()+50;//0.5秒一次
-
- reReqNum=300/(50*CHL_TOTAL);//3秒重新发一次鉴权请求(超时请求)
- if(channel[scanChannel].root != 0){//有要请求的通道数据
- if(channel[scanChannel].result==SER_AUTH_BUSY){
- if(channel[scanChannel].reqTime==0) ModemTryAuthNow(channel[scanChannel].id);
- if(++channel[scanChannel].reqTime >= reReqNum) channel[scanChannel].reqTime=0;
- }
- }
-
- if(++scanChannel >= CHL_TOTAL) scanChannel=CHL_UART1;
- }
- void testMakeReqAck(unsigned char *id);
- //模块通过部标向服务器请示某终端鉴权请求接口
- void ModemTryAuthNow(unsigned char *id)
- {//打包并通过UDP发送数据
- unsigned char sendbuf[128];
- unsigned short i,j;
- unsigned char *ptr=sendbuf;
- unsigned char th,tl,sum=0;
- char temp[20];
- static unsigned short liushui=0;
-
- j=0;
- //header
- //sms type 2bytes
- ptr[j++]=AUTH_REQ_ID>>8;
- ptr[j++]=AUTH_REQ_ID&0xff;
- //sms property 2bytes
- i=45;//only low 10bits are define as sms length
- ptr[j++]=i>>8;//no sub packets,no encrypt
- ptr[j++]=i;//sms length
- //device SN 6bytes
- snprintf(temp, sizeof(temp),"%012d",sutProductPara.PSN);
- for(i=0;i<6;i++){
- th=temp[2*i];
- tl=temp[2*i+1];
- th <<= 4;th &= 0xF0;
- tl &= 0x0F;
- ptr[j++]=th | tl;
- }
- //serial nuber 2bytes
- ptr[j++]=(liushui>>8)&0xFF;
- ptr[j++]=liushui&0xFF;
- liushui++;
- //sms info
- //生厂产家标识
- i=sizeof(sutProductPara.proName);
- memset(&ptr[j], 0, i);
- memcpy(&ptr[j], sutProductPara.proName, i);
- j += i;
- //产品型号
- i=sizeof(sutProductPara.devName);
- memset(&ptr[j], 0, i);
- memcpy(&ptr[j], sutProductPara.devName, i);
- j += i;
- //id len
- ptr[j++]=UNIQUE_ID_BYTES;
- //id data
- memcpy(ptr+j, id, UNIQUE_ID_BYTES);
- j += UNIQUE_ID_BYTES;
-
- //verify code
- for(i=0;i<j;i++) sum ^= sendbuf[i];
- ptr[j++]=sum;
- //translate
- j=PacketConvert(sendbuf,sizeof(sendbuf),j);
-
- ModemSendToUdpSocket(AUTH_UDP_SOCKET,sendbuf, j);
- }
- //DTU与终端之间的通讯发送函数接口,为了不让别人容易监听串口数据,协议对数据内容作了加密处理
- void authSendCmd(unsigned char cmd, unsigned char *data, unsigned char len)
- {
- //协议格式
- //head cmd len data
- //data:liushui[2] id[12] 均经过cmd和长度加密
- static unsigned short liushui=0;
- unsigned char sendbuf[64];
- unsigned char i,k;
- unsigned char *dataPtr=sendbuf+3;
- unsigned char datalen=2+len+1;//加上sum
- unsigned char temp[3],sum;
-
- i=0;
- sendbuf[i++]=PRO_HEADER;
- sendbuf[i++]=cmd;
- sendbuf[i++]=datalen;
- sendbuf[i++]=liushui>>8;
- sendbuf[i++]=liushui;
- for(k=0;k<len;k++)
- sendbuf[i++]=data[k];
-
- temp[0]=3+datalen;//总长度,包括sum
- temp[1]=sendbuf[0];
- temp[2]=sendbuf[1];
- for(k=0;k<datalen-1;k++){
- dataPtr[k] ^= temp[k % 3];
- dataPtr[k] ^= TX_RX_SEED;
- }
-
- sum=0;
- for(k=0;k<i;k++) sum ^= sendbuf[k];
- sendbuf[i++]=sum;
- Uart1Send(sendbuf, i);
-
- // printf("Data:%d\r\n", i);
- // {
- // int j;
- // for(j=0;j<i;j++) printf("%02x",sendbuf[j]);
- // }
- // printf("\r\nEnd\r\n");
- }
- //显示多通道串口灯的显示状态
- //每个通道有两个灯,一个是表示DTU是否有鉴权能力的红灯
- //一个是表示DTU的授权状态
- void authLedShow()
- {//这里只做显示,不做任何跟逻辑有关
- //红灯:
- //灭 表示本设备正常使用
- //亮 表示本设备无权向服务器鉴权,需要向我们反馈
- //蓝/绿灯:
- //灭 表示没有终端请求鉴权操作
- //亮 表示终端鉴权成功了
- //均匀闪 表示正在忙于鉴权操作
- //快闪1次 表示终端鉴权失败了
- CHANNEL_TYPEENUM scanChannel;
-
- for(scanChannel=CHL_UART1;scanChannel<CHL_TOTAL;scanChannel++){
- if(channel[scanChannel].root != 0){
- switch(channel[scanChannel].result){
- case SER_AUTH_IDLE://通道空闲,没有终端鉴权请求
- SetLedStatus(2*scanChannel,NotBright);//红灯灭,表示设备正常
- SetLedStatus(2*scanChannel+1,NotBright);//非红灯灭,表示设备空闲
- break;
- case SER_AUTH_BUSY://通道忙,表示正在处理终端鉴权请求
- case SER_AUTH_OK://鉴权成功,可以显示状态,但不清除结构体,通知终端成功了
- case SER_AUTH_WAIT://正在等待终端响应结果
- SetLedStatus(2*scanChannel,NotBright);//红灯灭,表示设备正常
- SetLedStatus(2*scanChannel+1,Flash);//非红灯均匀闪烁,表示设备忙于鉴权
- break;
- case SER_AUTH_FAILED://鉴权失败,设备无权
- SetLedStatus(2*scanChannel,Bright);//红灯灭,表示设备正常
- SetLedStatus(2*scanChannel+1,Flash);//非红灯均匀闪烁,表示设备忙于鉴权
- break;
- case SER_AUTH_DEV_FAI://终端鉴权失败
- SetLedStatus(2*scanChannel,NotBright);//红灯灭,表示设备正常
- SetLedStatus(2*scanChannel+1,OneFlashFast);//非红灯快闪1次,表示鉴权失败了
- break;
- case SER_AUTH_DEV_OK_DLY://终端鉴权成功延时
- SetLedStatus(2*scanChannel,NotBright);//红灯灭,表示设备正常
- SetLedStatus(2*scanChannel+1,NotBright);//非红灯常亮,用于给用户能看到变化
- break;
- case SER_AUTH_DEV_OK://终端鉴权成功
- SetLedStatus(2*scanChannel,NotBright);//红灯灭,表示设备正常
- SetLedStatus(2*scanChannel+1,Bright);//非红灯常亮,表示鉴权成功了
- break;
- }
- }else{//此通道收到任何终端请求
- SetLedStatus(2*scanChannel,NotBright);//红灯灭,表示设备正常
- SetLedStatus(2*scanChannel+1,NotBright);//非红灯灭,表示设备空闲
- }
- }
- }
- //接收到从服务器响应的部标数据包且包正确,处理接收到的数据
- void authBubiaoHandleRecv(unsigned char *msg)
- {//37ffd6054b543335504302430000000000000000000000000000000000000000 00 1f 04 6735d710 40
- unsigned char id[UNIQUE_ID_BYTES];
- unsigned char result;
- unsigned char factor;
- unsigned char len,i;
- unsigned int code;
- CHANNEL_TYPEENUM scanChannel;
- memcpy(id, msg, UNIQUE_ID_BYTES);
- result=msg[32];
- factor=msg[33];
- len=msg[34];
-
- if(result!=0) {
-
- for(scanChannel=CHL_UART1;scanChannel<CHL_TOTAL;scanChannel++){
- if(0==memcmp(id,channel[scanChannel].id,UNIQUE_ID_BYTES))
- channel[scanChannel].result=SER_AUTH_FAILED;
- }
- return;
- }
- //服务器授权成功
- //检测ID是否还存在
- for(i=CHL_UART1;i<CHL_TOTAL;i++){
- if(channel[i].root != 0){
- if(0==memcmp(id, channel[i].id, UNIQUE_ID_BYTES)){//存在
- goto GO_ON;
- }
- }
- }
- return;
- GO_ON:
- //printf("Code1:%02x,%02x%02x%02x%02x\r\n", factor, msg[35],msg[36],msg[37],msg[38]);
- code=msg[38]^factor;code <<= 8;code &= 0xff00;
- code |= msg[37]^factor;code <<= 8;code &= 0xffff00;
- code |= msg[36]^factor;code <<= 8;code &= 0xffffff00;
- code |= msg[35]^factor;
- channel[i].encodeValue=code;
- channel[i].result=SER_AUTH_OK;
-
- //printf("Code2:%08x\r\n", code);
- }
- //以下只是用来模拟服务器产生ACK的包的函数
- void testMakeReqAck(unsigned char *id)
- {
- unsigned char sendbuf[128];
- unsigned short i,j;
- unsigned char *ptr=sendbuf;
- unsigned char th,tl,sum=0;
- char temp[20];
- static unsigned short liushui=0;
- #define ENCODE_VALUE 0x1f
- j=0;
- //header
- //sms type 2bytes
- ptr[j++]=AUTH_ACK_ID>>8;
- ptr[j++]=AUTH_ACK_ID&0xff;
- //sms property 2bytes
- i=39;//授权成功长度 36 授权失败长度
- ptr[j++]=i>>8;//no sub packets,no encrypt
- ptr[j++]=i;//sms length
- //device SN 6bytes
- snprintf(temp, sizeof(temp),"%012d",sutProductPara.PSN);
- for(i=0;i<6;i++){
- th=temp[2*i];
- tl=temp[2*i+1];
- th <<= 4;th &= 0xF0;
- tl &= 0x0F;
- ptr[j++]=th | tl;
- }
- //serial nuber 2bytes
- ptr[j++]=(liushui>>8)&0xFF;
- ptr[j++]=liushui&0xFF;
- liushui++;
- //sms info
- memset(ptr+j, 0, 32);
- memcpy(ptr+j, id, UNIQUE_ID_BYTES);
- j += 32;
- ptr[j++]=0;
- ptr[j++]=ENCODE_VALUE;
- ptr[j++]=4;
- ptr[j++]=0x78^ENCODE_VALUE;
- ptr[j++]=0x2a^ENCODE_VALUE;
- ptr[j++]=0xc8^ENCODE_VALUE;
- ptr[j++]=0x0f^ENCODE_VALUE;
-
- //verify code
- for(i=0;i<j;i++) sum ^= sendbuf[i];
- ptr[j++]=sum;
- //translate
- j=PacketConvert(sendbuf,sizeof(sendbuf),j);
-
- printf("Data:");
- for(i=0;i<j;i++){
- printf("%02x",sendbuf[i]);
- }
- printf("\r\n");
- }
|