// 103.cpp: implementation of the C103 class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "se_log.h" #include "se_btl.h" //#include "comm\dc_comm.h" #include "103.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// typedef struct EVENT_INFO { uint8 fun; uint8 inf; uint8 sort; uint8 inx; }EVENT_INFO; static EVENT_INFO event_table1[]= { {0x01, 0x01, 0, 1}, {0x02, 0x02, 0, 2}, {0x03, 0x03, 0, 3}, {0x04, 0x04, 0, 4}, {0x05, 0x05, 0, 5}, {0x06, 0x06, 0, 6}, {0x07, 0x07, 0, 7}, {0x08, 0x08, 0, 8}, {0x09, 0x09, 0, 9}, {0x0a, 0x0a, 0, 10}, {0x0b, 0x0b, 0, 11}, //保护信息 {0x02, 0x07, 1, 19}, {0x96, 0xa1, 1, 20}, {0xa0, 0x2f, 1, 21}, {0x3c, 0x3a, 1, 22}, {0xa0, 0x5a, 1, 23}, //{0xa0, 0x5b, 1, 23}, {0xa0, 0x5c, 1, 24}, {0xa0, 0x5d, 1, 25}, {0xa0, 0x80, 1, 26}, {0x0c, 0x0c, 1, 27}, {0x04, 0x03, 1, 28}, {0x4a, 0x46, 1, 29}, {0x97, 0x75, 1, 30}, {0x4a, 0x27, 1, 31},//低电压 {0xb0, 0x44, 1, 32}, {0x3c, 0x48, 1, 33}, {0x3c, 0x3d, 1, 34}, {0xff, 0xff, 1, 35}, {0x4b, 0x5b, 1, 36}, {0x4f, 0x28, 1, 37},//过电压 }; //取事件信息 static EVENT_INFO get_event_info(BYTE btFun, BYTE btInfo, EVENT_INFO *p_tab) { WORD i = 0; EVENT_INFO evt_info; WORD wEvetNum = sizeof(event_table1)/sizeof(EVENT_INFO); for( ; iPRawCtrl; pRxBuf = pcfg->pRxBuf; pTxBuf = pcfg->pTxBuf; pCmdMem = pcfg->pCmdMem; pRtu = pcfg->pRtu; pLink = pcfg->pLink; pTable = pcfg->pTable; pZfDataCtrl = pcfg->pZfDataCtrl; pHis = pcfg->pHis; m_rii=0; m_scn=0; m_LastRxProtSoe = 1; InitRtu(); } void C103::InitRtu() { sint32 rtuno=pLink->GetRtuNo(); //清除缓冲区 int buflen=pRxBuf->GetReadableSize(); pRxBuf->Move(buflen); buflen=pTxBuf->GetReadableSize(); pTxBuf->Move(buflen); m_LinkStatus=LSTATUS_INIT; m_ReSendCnt=-1; m_SendBufLen=0; m_LastSendTime=GetNowSecond(); m_LastCallAllTime=0; m_LastSyncTime=0; m_ACDFlag=0; m_OverTimeFlag=0; m_MainFCBFlag=0; m_SubFCBFlag=0; m_cmdf =0; m_CRC_ErrCnt=15; m_RcvTimeOuts=pLink->GetRxTimeouts(); if(m_RcvTimeOuts<=0) m_RcvTimeOuts=2; m_ReSendMaxCount=pLink->GetRetryTimes(); if(m_ReSendMaxCount<=0) m_ReSendMaxCount=3; pLink->SetCommStatus(CMST_NORMAL); } void C103::SetTxRxStatus(E103_STATUS status) { sint32 rtuno=pLink->GetRtuNo(); switch(status) { case STATUS_CRCERR: { m_CRC_ErrCnt--; pLink->RegisterFrm( FRAME_RX_CHECKERR ); if(m_CRC_ErrCnt<=0) { InitRtu(); } else { //按简单超时逻辑开始 m_ReSendCnt++; m_OverTimeFlag=1; if(m_ReSendCnt>=m_ReSendMaxCount) { if(m_ReSendCnt>5*m_ReSendMaxCount) InitRtu(); pLink->SetCommStatus(CMST_NORMAL); } else { pLink->SetCommStatus(CMST_TX_CNT); } } break; } case STATUS_OVERTIME: m_ReSendCnt++; m_OverTimeFlag=1; pLink->RegisterFrm( FRAME_RX_TIMEOUT ); if(m_ReSendCnt>=m_ReSendMaxCount) { if(m_ReSendCnt>5*m_ReSendMaxCount) InitRtu(); else { int buflen = pRxBuf->GetReadableSize(); pRxBuf->Move(buflen); buflen = pTxBuf->GetReadableSize(); pTxBuf->Move(buflen); pLink->SetCommStatus(CMST_NORMAL); m_OverTimeFlag=0; } } else { pLink->SetCommStatus(CMST_TX_CNT); kprintf(LOG_COMM,DCV_LOG_103, LOG_VIOLATION, "%d号终端-等待接收数据超时", rtuno); } m_CRC_ErrCnt=15; break; case STATUS_RXOK: case STATUS_NODATA: m_CRC_ErrCnt=15; m_ReSendCnt=-1; pLink->RegisterFrm( FRAME_RX_SUC ); sint32 rtuno=pLink->GetRtuNo(); if(m_ACDFlag )pLink->SetCommStatus(CMST_TX_CNT); else pLink->SetCommStatus(CMST_NORMAL); break; } } //规约发送过程 sint32 C103::TxProc() { sint32 rtuno=pLink->GetRtuNo(); if(pLink->GetCommStatus()==CMST_RX_CNT) return 1; //处理命令,如果链路不通,删除所有该链路的命令 if(m_LinkStatus!=LSTATUS_OK) { while(pCmdMem->GetCmdNum(rtuno)>0) pCmdMem->DelACmd(rtuno); } //把保护事项自动复归 int nowtime=GetNowSecond(); if(m_LastRxProtSoe>0 && (nowtime-m_LastRxProtSoe)>10) { reset_protect_info(); m_LastRxProtSoe=-1; } //有时分站会发送多帧数据必须完全处理完毕。 int buflen=pRxBuf->GetReadableSize(); if (buflen >0 ) return 1; unsigned char rtuaddr=pRtu->GetRtuAddr(rtuno); if(m_OverTimeFlag && m_ReSendCnt>=0) { ReSendData();//超时重发 return 1; } switch(m_LinkStatus) { case LSTATUS_INIT: SendRequestLinkStatusCmd(); return 1; case LSTATUS_RESET: SendResetLinkCmd(); return 1; case LSTATUS_OK: if(m_ACDFlag) //召唤一类数据 { SendCallClassOneDataCmd(); m_ACDFlag=0; return 1; } if(ProcCmd()) //处理外部下发命令 { return 1; } //处理校时 uint32 spacetime=pRtu->GetSyncTimeInt(rtuno); if(spacetime ==0) spacetime = 10; if( uint32(nowtime-m_LastSyncTime) >= spacetime*60) { SendTimeCmd(); m_LastSyncTime = nowtime; return 1; } //招全数据 spacetime=pLink->GetAllDataScanInterval(); if(spacetime>0) { if( uint32(nowtime-m_LastCallAllTime) >= spacetime*60) { m_LastCallAllTime = nowtime; SendCallAllDataCmd(); return 1; } } SendCallClassTwoDataCmd(); return 1; } return 1; } //复归保护事件 void C103::reset_protect_info() { WORD i; int rtuno=pLink->GetRtuNo(); WORD wEvetNum = sizeof(event_table1)/sizeof(EVENT_INFO); for(i=0; iPutAYx(rtuno,event_table1[i].inx-1,0); } } } /*********************************************************** 命令处理 ***********************************************************/ BOOL C103::ProcCmd() { sint32 rtuno=pLink->GetRtuNo(); if(pCmdMem->GetCmdNum(rtuno)<=0) return FALSE; S_RAWCMD rawcmd; if(pCmdMem->GetACmd(rtuno,&rawcmd)==0) return FALSE; S_CmdInfo *cmdinfo; while(pCmdMem->GetCmdNum(rtuno)>0) { if(pCmdMem->GetACmd(rtuno,&rawcmd)==0) break; switch(rawcmd.type) { case DC_K_PIPE_SYNCTIME: //校时命令 pCmdMem->DelACmd(rtuno); SendTimeCmd(); return TRUE; break; case DC_K_PIPE_YKOPER: //遥控 cmdinfo=(S_CmdInfo *)(&rawcmd.Data); m_cmdprotsort =rawcmd.cmdsrc_sort; m_cmdsrc_rtu =rawcmd.cmdsrc_rtu; m_CmdSrc=rawcmd.addr; if (cmdinfo->func1==DC_K_PIPE_YKCMD) { //选择 SendYKCmd(*cmdinfo,DC_K_YKSELECT); } else if (cmdinfo->func1==DC_K_PIPE_YKEXE) { //执行 SendYKCmd(*cmdinfo,DC_K_YKEXECUTE); } else if (cmdinfo->func1==DC_K_PIPE_YKDEL) { //撤消 SendYKCmd(*cmdinfo,DC_K_YKCANCEL); } pCmdMem->DelACmd(rtuno); return TRUE; break; default: //对其它的下发命令不处理 pCmdMem->DelACmd(rtuno); break; } } return FALSE; } /***************************************************************** 遥控命令,Type为遥控类型 ******************************************************************/ void C103::SendYKCmd(S_CmdInfo cmdinfo ,BYTE type) { sint32 rtuno=pLink->GetRtuNo(); unsigned char rtuaddr=pRtu->GetRtuAddr(rtuno); BYTE status; uint8 ykno,ykbak; ykno = ykbak = (uint8)cmdinfo.ctrlpt;//遥控号 status = (BYTE)cmdinfo.func2;//遥控状态 if(type == DC_K_YKSELECT){//直接返校 S_RAWCMD rawcmd; S_CmdInfo cmdinfo; rawcmd.type=DC_K_PIPE_YKRETURN; rawcmd.rtuno=rtuno; cmdinfo.ctrlpt=ykno; cmdinfo.func1=DC_K_PIPE_YKCMD; if(status==0xcc) cmdinfo.func2=1; else cmdinfo.func2=0; rawcmd.len=sizeof(cmdinfo); rawcmd.cmdsrc_sort = m_cmdprotsort; rawcmd.cmdsrc_rtu = m_cmdsrc_rtu; rawcmd.addr=m_CmdSrc; cmdinfo.ret=1; memcpy(rawcmd.Data,&cmdinfo,sizeof(cmdinfo)); pCmdMem->ZfAResult(rtuno,rawcmd); kprintf(LOG_COMM,DCV_LOG_103,LOG_ERROR,"%d号终端-直接遥控返校正确", rtuno); return; } else if(type == DC_K_YKCANCEL){ return; } S103_CONTROL_BYTE control; BYTE *buf = m_SendBuf; *buf++ = 0x68; *buf++ = 0x0a; *buf++ = 0x0a; *buf++ = 0x68; control.CtrlField.DIR = 0; control.CtrlField.PRM = 1; control.CtrlField.FCV = 1; control.CtrlField.FCB =m_MainFCBFlag ; m_MainFCBFlag=(m_MainFCBFlag+1)%2; control.CtrlField.FC = 3; *buf++ = control.BCtrlField; *buf++ = rtuaddr; //遥控号在后台从零开始 //ykno =ykno+0xb01;// //if(ykno >0xb80) // kprintf(LOG_COMM,DCV_LOG_103,LOG_ERROR,"遥控号超过128,每站的遥控数不能大于128个 %d",rtuno); *buf++=20; *buf++=0x81; *buf++ =20; *buf++=rtuaddr; *buf++=240; *buf++=160+ykno; if(status==0) *buf++=1; else if(status==1) *buf++=2; else return; *buf++ = m_rii++; *buf++=GetByteCheckSum(m_SendBuf+4,buf-m_SendBuf-4); *buf++=0x16; m_SendBufLen = buf - m_SendBuf; SendToPhysical(); kprintf(LOG_COMM,DCV_LOG_103,LOG_INFORMATION,"遥控:性质=%x 序号=%x rtuno:%d" ,status , ykbak,rtuno); } /************************************************************************************************ 复位通信单元 ************************************************************************************************/ void C103::SendRequestLinkStatusCmd() { sint32 rtuno=pLink->GetRtuNo(); unsigned char rtuaddr=pRtu->GetRtuAddr(rtuno); S103_CONTROL_BYTE control; BYTE *buf = m_SendBuf; *buf++ = 0x10; control.CtrlField.DIR = 0; control.CtrlField.PRM = 1; control.CtrlField.FCV = 0; control.CtrlField.FCB = 0; control.CtrlField.FC = 0x00; *buf++ = control.BCtrlField; *buf++ = rtuaddr; *buf++=GetByteCheckSum(m_SendBuf+1,buf-m_SendBuf-1); *buf++=0x16; m_SendBufLen = buf - m_SendBuf; kprintf(LOG_COMM,DCV_LOG_103,LOG_INFORMATION,"%d号终端-请求链路状态", rtuno); SendToPhysical(); } /************************************************************************************************ 复位对方链路 ************************************************************************************************/ void C103::SendResetLinkCmd() { sint32 rtuno=pLink->GetRtuNo(); unsigned char rtuaddr=pRtu->GetRtuAddr(rtuno); S103_CONTROL_BYTE control; BYTE *buf = m_SendBuf; *buf++ = 0x10; control.CtrlField.DIR = 0; control.CtrlField.PRM = 1; control.CtrlField.FCV = 0; control.CtrlField.FCB = 0; control.CtrlField.FC = 0; *buf++ = control.BCtrlField; *buf++ = rtuaddr; *buf++=GetByteCheckSum(m_SendBuf+1,buf-m_SendBuf-1); *buf++=0x16; m_SendBufLen = buf - m_SendBuf; kprintf(LOG_COMM,DCV_LOG_103,LOG_INFORMATION,"%d号终端-复位链路", rtuno); SendToPhysical(); m_MainFCBFlag = 1; //初始化命令发出后将MainstationFCB置0 } /********************************************************************************* 向终端发送总召唤命令 **********************************************************************************/ void C103::SendCallAllDataCmd() { sint32 rtuno=pLink->GetRtuNo(); unsigned char rtuaddr=pRtu->GetRtuAddr(rtuno); S103_CONTROL_BYTE control; BYTE *buf = m_SendBuf; *buf++ = 0x68; *buf++ = 0x09; *buf++ = 0x09; *buf++ = 0x68; control.CtrlField.DIR = 0; control.CtrlField.PRM = 1; control.CtrlField.FCV = 1; control.CtrlField.FCB = m_MainFCBFlag; m_MainFCBFlag=(m_MainFCBFlag+1)%2; control.CtrlField.FC = 3; *buf++ = control.BCtrlField; *buf++ = rtuaddr; *buf++ = 7;//typ *buf++ = 0x81;//vsq *buf++ = 0x09;//cot *buf++ =rtuaddr; *buf++ = 255;//fun *buf++ = 0x00;//inf *buf++ = m_scn++; *buf++=GetByteCheckSum(m_SendBuf+4,buf-m_SendBuf-4); *buf++=0x16; m_SendBufLen = buf - m_SendBuf; kprintf(LOG_COMM,DCV_LOG_103,LOG_INFORMATION,"%d号终端-总召唤命令", rtuno); SendToPhysical(); } /************************************************************************************************************************* 召唤一级数据 *************************************************************************************************************************/ BOOL C103::SendCallClassOneDataCmd() { sint32 rtuno=pLink->GetRtuNo(); unsigned char rtuaddr=pRtu->GetRtuAddr(rtuno); S103_CONTROL_BYTE control; BYTE *buf = m_SendBuf; *buf++ = 0x10; control.CtrlField.DIR = 0; control.CtrlField.PRM = 1; control.CtrlField.FCV = 1; control.CtrlField.FC = 0x0a; control.CtrlField.FCB = m_MainFCBFlag; m_MainFCBFlag=(m_MainFCBFlag+1)%2; *buf++ = control.BCtrlField; *buf=rtuaddr; buf ++; *buf++=GetByteCheckSum(m_SendBuf+1,buf-m_SendBuf-1); *buf++=0x16; m_SendBufLen = buf - m_SendBuf; kprintf(LOG_COMM,DCV_LOG_103,LOG_INFORMATION,"召唤%d号终端-一级数据", rtuno); SendToPhysical(); return TRUE; } /************************************************************************************************************************ 召唤二级数据 *************************************************************************************************************************/ BOOL C103::SendCallClassTwoDataCmd() { sint32 rtuno=pLink->GetRtuNo(); unsigned char rtuaddr=pRtu->GetRtuAddr(rtuno); S103_CONTROL_BYTE control; BYTE *buf = m_SendBuf; *buf++ = 0x10; control.CtrlField.DIR = 0; control.CtrlField.PRM = 1; control.CtrlField.FCV = 1; control.CtrlField.FC = 0x0b; control.CtrlField.FCB = m_MainFCBFlag; m_MainFCBFlag=(m_MainFCBFlag+1)%2; *buf++ = control.BCtrlField; *buf++ = rtuaddr; *buf++=GetByteCheckSum(m_SendBuf+1,buf-m_SendBuf-1); *buf++=0x16; m_SendBufLen = buf - m_SendBuf; // kprintf(LOG_COMM,DCV_LOG_103,LOG_INFORMATION,"召唤%d号终端-二级数据", rtuno); SendToPhysical(); return TRUE; } /************************************************************************************************ 应用层调用的函数,功能是应用层公告链路层向终端进行时钟同步 ************************************************************************************************/ BOOL C103::SendTimeCmd() { sint32 rtuno=pLink->GetRtuNo(); unsigned char rtuaddr=pRtu->GetRtuAddr(rtuno); S103_CONTROL_BYTE control; BYTE *buf = m_SendBuf; *buf++ = 0x68; *buf++ = 15; *buf++ = 15; *buf++ = 0x68; control.CtrlField.DIR = 0; control.CtrlField.PRM = 1; control.CtrlField.FCB = m_MainFCBFlag; m_MainFCBFlag=(m_MainFCBFlag+1)%2; control.CtrlField.FCV = 1; control.CtrlField.FC = 3; *buf++ = control.BCtrlField; *buf++ = rtuaddr; *buf++ = 0x6;//typ *buf++ = 0x81;//vsq *buf++ = 0x08;//cot *buf++ = 255;//广播 *buf++ = 0; //inf SSE_CLOCK sck; CSeTime SE_T; SE_T.GetNow(&sck); *buf++ = (uint8)(sck.msecond+sck.second*1000)%256; *buf++ = (uint8)(sck.msecond+sck.second*1000)/256; *buf++ = sck.minute; *buf++ = sck.hour; *buf++ = ((sck.wday << 5) & 0xE0) | (sck.day & 0x1F); *buf++ = sck.month; *buf++ = (uint8)(sck.year-2000); *buf++=GetByteCheckSum(m_SendBuf+4, buf-m_SendBuf-4); *buf++=0x16; m_SendBufLen = buf - m_SendBuf; kprintf(LOG_COMM,DCV_LOG_103,LOG_WARNING, "向%d号终端发时钟同步命令,系统时钟:(%2d-%2d-%2d %2d:%2d:%2d %4d)", rtuno, sck.year, sck.month, sck.day, sck.hour, sck.minute, sck.second, sck.msecond); m_cmdf = 1; SendToPhysical(); return TRUE; } /************************************************************************************************ 添加GPRS号码支持 ************************************************************************************************/ void C103::AppendIp() { // 报文格式 'k'+'d'+数据长度(2个字节)+号码长度(1个字节)+号码+规约数据 数据长度指报文总长度 if(pLink->GetUseIp() > 0) { char* pIp = pRtu->GetRtuIpAddr(pLink->GetRtuNo()); if(NULL == pIp) { DCV_Printf(LOG_COMM, DCV_LOG_103, LOG_VIOLATION, "未取得RTU %d 的IP指针", pLink->GetRtuNo()); return; } int iplen = strlen(pIp); if(0 == iplen) { DCV_Printf(LOG_COMM, DCV_LOG_103, LOG_VIOLATION, "请输入RTU %d 的IP", pLink->GetRtuNo()); return; } // 添加控制信息 memmove(m_SendBuf+5+iplen, m_SendBuf, m_SendBufLen); m_SendBufLen += 5+iplen; m_SendBuf[0] = 'k'; // 前导字节 m_SendBuf[1] = 'd'; // 前导字节 m_SendBuf[2] = LOBYTE(m_SendBufLen); m_SendBuf[3] = HIBYTE(m_SendBufLen); m_SendBuf[4] = iplen; memcpy(m_SendBuf+5, pIp, iplen); } } /************************************************************************************************ 将数据从链路层缓冲区发送到物理层缓冲区 ************************************************************************************************/ void C103::SendToPhysical(BOOL bResend) { if(!bResend) { AppendIp(); //GPRS专用IP报文头 } pLink->RegisterFrmCode(RAW_CODEDIR_DOWN,(char *)m_SendBuf,m_SendBufLen); pTxBuf->Write(m_SendBuf,m_SendBufLen); if(m_cmdf==1){ //对钟不需要返回 pLink->SetCommStatus(CMST_NORMAL); m_cmdf = 0; } else pLink->SetCommStatus(CMST_RX_CNT); m_LastSendTime = GetNowSecond(); m_OverTimeFlag=0; } //规约接收函数 sint32 C103::RxProc() { sint32 rtuno=pLink->GetRtuNo(); unsigned char rtuaddr=pRtu->GetRtuAddr(rtuno); uint8 buf[512]; int i; int datalen; int buflen=pRxBuf->GetReadableSize(); int nowtime=GetNowSecond(); if (pLink->GetCommStatus()==CMST_RX_CNT && (nowtime-m_LastSendTime) >= m_RcvTimeOuts) { pRxBuf->Move(buflen); SetTxRxStatus(STATUS_OVERTIME); return 1; } if (buflen<=0) //无数据 return 1; if(buflen>510) buflen = 510; pRxBuf->Read(buf,buflen,DEF_BUFF_NOMOVE); if(buflen<5) { for(i=0; iRegisterFrmCode(RAW_CODEDIR_UP,(char *)(buf+i),1); pRxBuf->Move(i+1); SetTxRxStatus(STATUS_NODATA); kprintf(LOG_COMM,DCV_LOG_103,LOG_WARNING,"%d号终端-无所请求的数据", rtuno); return 1; } if(buf[i] == 0X10 || buf[i] == 0X68) //移除起始符之前的无效数据 { pRxBuf->Move(i); break; } } if(i==buflen) //移除全部无效数据 pRxBuf->Move(buflen); } S103_CONTROL_BYTE contrl; while ((buflen=pRxBuf->GetReadableSize()) >= 5) { pRxBuf->Read(buf, 5, DEF_BUFF_NOMOVE ); if (buf[0]!= 0x10 && buf[0] != 0x68 && buf[0]!=0xe5) { pRxBuf->Move(1); continue; } if(buf[0]==0xe5) { pRxBuf->Move(1); SetTxRxStatus(STATUS_NODATA); kprintf(LOG_COMM,DCV_LOG_103,LOG_WARNING,"%d号终端-无所请求的数据", rtuno); pLink->RegisterFrmCode(RAW_CODEDIR_UP,(char *)buf,1); continue; } if(buf[0]==0x10) //固定帧长 { buflen=5; if(buf[buflen-1]!=0x16) { pRxBuf->Move(1); continue; } if(GetByteCheckSum(&(buf[1]),2)!=buf[3]) { pRxBuf->Move(buflen); SetTxRxStatus(STATUS_CRCERR); kprintf(LOG_COMM,DCV_LOG_103,LOG_ERROR,"%d号终端-返回帧校验和错误", rtuno); continue; } m_CRC_ErrCnt=15; contrl.BCtrlField =buf[1]; if (!contrl.CtrlField.PRM) { if (buf[2] != rtuaddr) { //判站址 kprintf(LOG_COMM,DCV_LOG_103,LOG_WARNING,"%d号终端-返回帧中站址不对,本站址:%d 主站请求站址为%d", rtuno, rtuaddr, buf[2]); pRxBuf->Move(buflen); continue; } } pLink->RegisterFrmCode(RAW_CODEDIR_UP,(char *)buf,5); // if (contrl.CtrlField.PRM) //收到终端主动上报的数据后,超时时间重新计算 // OverSendTimeCount = 0; if (contrl.CtrlField.PRM == 0) m_ACDFlag = contrl.CtrlField.FCB; if(buf[1]==0) m_ACDFlag=1; //西门子设备特殊处理; ProcShortCmd(buf,buflen); pRxBuf->Move(buflen); SetTxRxStatus(STATUS_RXOK);//lingws break; } //end buf[0]==0x10 else if(buf[0]==0x68) { //判断第二个启动码 if(buf[3] != 0x68) { pRxBuf->Move(1); continue; } //判两个数据长度是否相同 datalen =buf[1]; if (buf[1] != buf[2]) { pRxBuf->Move(1); continue; } //判数据长度是否足够 if (buflen < (datalen + 6)) { // kprintf(LOG_COMM,DCV_LOG_103,LOG_ERROR,"判数据长度不够 %d",rtuno); return 2; } contrl.BCtrlField =buf[4]; //找到恰当的头 pRxBuf->Read(buf, datalen+6, DEF_BUFF_NOMOVE ); //结束符校验 if(buf[datalen+5]!=0x16) { pRxBuf->Move(1); kprintf(LOG_COMM,DCV_LOG_103,LOG_ERROR,"%d号终端-返回帧结束符校验错误", rtuno); continue; } if(GetByteCheckSum(&(buf[4]),datalen)!=buf[datalen+4]) { pRxBuf->Move(datalen+6); SetTxRxStatus(STATUS_CRCERR); kprintf(LOG_COMM,DCV_LOG_103,LOG_ERROR,"%d号终端-返回帧校验和错误", rtuno); continue; } //一切准备就绪,进入正常处理 m_CRC_ErrCnt=15; if (!contrl.CtrlField.PRM) { if (buf[5] != rtuaddr) { kprintf(LOG_COMM,DCV_LOG_103,LOG_WARNING,"%d号终端-返回帧中站址不对,本站址:%d 主站请求站址为%d", rtuno, rtuaddr, buf[2]); pRxBuf->Move(datalen+6); continue; //判站址 } } pLink->RegisterFrmCode(RAW_CODEDIR_UP,(char *)buf,datalen+6); if (contrl.CtrlField.PRM && contrl.CtrlField.FCV) //判FCB和处理FCB { if (contrl.CtrlField.FCB == m_SubFCBFlag) { kprintf(LOG_COMM,DCV_LOG_103,LOG_WARNING,"%d号终端-返回帧数据FCB重复!", rtuno); pRxBuf->Move(datalen+6); SetTxRxStatus(STATUS_RXOK);//lingws continue; } else m_SubFCBFlag = (m_SubFCBFlag+1)%2; } if (contrl.CtrlField.PRM == 0) m_ACDFlag = contrl.CtrlField.FCB; ProcLongCmd(buf,datalen+6); pRxBuf->Move(datalen+6); SetTxRxStatus(STATUS_RXOK);//lingws break; } } return 1; } void C103::ProcShortCmd(uint8 *buf,int buflen) { sint32 rtuno=pLink->GetRtuNo(); unsigned char rtuaddr=pRtu->GetRtuAddr(rtuno); S103_CONTROL_BYTE contrl; contrl.BCtrlField =buf[1]; if (contrl.CtrlField.PRM)//终端主动上传的链路层命令 { //主站复位终端未成功,不允许终端复位主站 } else { //终端应答的链路层命令 switch (m_LinkStatus) { case LSTATUS_INIT: //链路层尚未初始化结束 if(contrl.CtrlField.FC==11) { //复位链路层 kprintf(LOG_COMM,DCV_LOG_103,LOG_INFORMATION,"收到%d号终端-链路状态良好帧", rtuno); } else kprintf(LOG_COMM,DCV_LOG_103,LOG_INFORMATION,"收到%d号终端-链路状态不好帧", rtuno); m_LinkStatus=LSTATUS_RESET; //lingws 不关心对方链路的状态直接复位对方链路 break; case LSTATUS_RESET: //应该收到复位链路结束保文 if(contrl.CtrlField.FC==0) { m_LinkStatus=LSTATUS_OK; kprintf(LOG_COMM,DCV_LOG_103,LOG_INFORMATION,"收到%d号终端-复位链路结束保文", rtuno); } break; case LSTATUS_OK: //终端报告没有所请求的数据 if (contrl.CtrlField.FC == 0x09) { m_LinkStatus = LSTATUS_OK; kprintf(LOG_COMM,DCV_LOG_103,LOG_INFORMATION,"%d号终端-报告没有所请求的数据", rtuno); } if (contrl.CtrlField.FC == 0x00 ) { m_LinkStatus = LSTATUS_OK; kprintf(LOG_COMM,DCV_LOG_103,LOG_INFORMATION,"%d号终端-遥控成功", rtuno); } if(contrl.CtrlField.FC == 0x20) { m_LinkStatus = LSTATUS_OK; kprintf(LOG_COMM,DCV_LOG_103,LOG_INFORMATION,"%d号终端-遥控不成功", rtuno); } break; } } } void C103::ProcLongCmd(uint8 *buf,int buflen) { if(m_LinkStatus!=LSTATUS_OK) return; int nowtime=GetNowSecond(); CSeTime kdt; SSE_CLOCK ck; kdt.GetNow(&ck); sint32 rtuno=pLink->GetRtuNo(); unsigned char rtuaddr=pRtu->GetRtuAddr(rtuno); S103_CONTROL_BYTE contrl; contrl.BCtrlField =buf[4]; unsigned char func,type,sendfor; func=contrl.CtrlField.FC; type=buf[6]; sendfor=buf[8]; switch(type) { case 0x68: //链路测试确认帧 kprintf(LOG_COMM,DCV_LOG_103,LOG_INFORMATION,"收到%d号终端-链路测试确认帧", rtuno); break; case 0x69://复位RTU确认 m_LinkStatus=LSTATUS_INIT; kprintf(LOG_COMM,DCV_LOG_103,LOG_INFORMATION,"收到%d号终端-复位RTU确认帧", rtuno); break; case 0x15: case 0x09: case 0x03: //kprintf(LOG_COMM,DCV_LOG_103,LOG_INFORMATION,"收到%d号终端-不带品质的yc帧,传送原因:%d", rtuno, sendfor); Recv_ProcYC(buf,buflen); break; case 8: //总召唤结束 pLink->SetCommStatus(CMST_NORMAL); kprintf(LOG_COMM,DCV_LOG_103,LOG_INFORMATION,"收到%d号终端-总召唤结束帧", rtuno); break; case 0x01: case 0x02: { kprintf(LOG_COMM,DCV_LOG_103,LOG_INFORMATION,"收到%d号终端-变位YX帧", rtuno); Recv_ProcSOE(buf,buflen); } break; case 205: { kprintf(LOG_COMM,DCV_LOG_103,LOG_INFORMATION,"收到%d号终端-KWH帧",rtuno); Recv_ProcKWH(buf,buflen); } break; } } /************************************************************************** 处理单点遥信和双点遥信的SOE DataHead 为应用数据单元标识 ***************************************************************************/ void C103::Recv_ProcSOE(BYTE *buf,int buflen) { if(buflen<12) return; CSeTime SE_T; sint32 rtuno=pLink->GetRtuNo(); BYTE TypeID=buf[6]; BYTE sq; if((buf[7]&0x80)==0) sq=0; else sq=1; BYTE number=buf[7]&0x7f; BYTE addr= buf[9]; BYTE cause = buf[8]; int lenpt=12; uint8 fun = buf[10]; uint8 inf = buf[11]; EVENT_INFO evt = get_event_info(fun,inf,event_table1); if(evt.fun ==0)return; uint8 oldyx=0; if(PRawCtrl->GetAYx(rtuno,evt.inx-1,&oldyx)){ if ((buf[12] == 2 && oldyx==1) || (buf[12] == 1 && oldyx==0) )return;//遥信没有变化 if(evt.sort == 1){ SE_T.GetNow(&m_LastRxProtSoe); } } if(buf[12] == 2)oldyx=1; else if(buf[12] == 1)oldyx=0; else return; PRawCtrl->PutAYx(rtuno,evt.inx-1,oldyx); SSE_CLOCK systime; SE_T.GetNow(&systime); S_RAWSOE rawsoe; rawsoe.Source=DC_K_RTUSOE; rawsoe.Rtuno=rtuno; rawsoe.Year=systime.year; rawsoe.Month=systime.month; rawsoe.Day=systime.day; rawsoe.Yxno=evt.inx-1; rawsoe.Val=oldyx; rawsoe.Hour=buf[16]&0x1f; rawsoe.Minute=buf[15]&0x3f; rawsoe.Second=(buf[13]*256+buf[14])/1000; rawsoe.Ms=(buf[13]*256+buf[14])%1000; PRawCtrl->PutASoe(rawsoe); } /********************************************************************** 遥测处理过程, ***********************************************************************/ void C103::Recv_ProcYC(BYTE *buf,int buflen) { if(buflen<12) return; sint32 rtuno=pLink->GetRtuNo(); BYTE TypeID=buf[6]; BYTE sq; if((buf[7]&0x80)==0) sq=0; else sq=1; BYTE number=buf[7]&0x7f;//vsq BYTE addr=buf[9]; BYTE cause = buf[8];//cot BYTE inf = buf[11]; if( (TypeID==9 && inf==0x89) || TypeID==3) { int lenpt; short int YcValue; lenpt= 12; for(int i=0;iPutAYc(rtuno,i,YcValue); } } } /************************************************************** 电度处理 **************************************************************/ void C103::Recv_ProcKWH(BYTE *buf,int buflen) { if(buflen<16) return; sint32 rtuno=pLink->GetRtuNo(); BYTE cause = buf[8]; uint8 KwhValue[4]; uint8 index= buf[11]- 0x33; if(index>=6)return; memcpy(KwhValue, buf+12, 4); uint32 val = (((KwhValue[3]*256+KwhValue[2])*256)+KwhValue[1])*256+KwhValue[0]; val = val&0x0fffffff; PRawCtrl->PutAKwh(rtuno,index,val); } /************************************************************************************************ 将链路层数据重新发送 *************************************************************************************************/ void C103::ReSendData() { int rtuno=pLink->GetRtuNo(); SendToPhysical(TRUE); kprintf(LOG_COMM,DCV_LOG_103, LOG_WARNING, "%d号终端-重新发送上条命令", rtuno); } /*********************************************************************************************** 103规约校验码计算 Buff是待计算缓冲区的起始地址,Len是长度 ***********************************************************************************************/ unsigned char C103::GetByteCheckSum(unsigned char *buf,int buflen) { unsigned char result = 0; int i; for (i=0;i>=3; if(YcValue&0x1000){ YcValue= ~(YcValue&0x0fff); YcValue= YcValue&0x0fff; YcValue= YcValue*(-1); } return YcValue; } extern "C" __declspec(dllexport) CProtocol *CreateProtocol(char *defpara) { return (CProtocol*)(new C103()); }