// CModbus_TcpS.cpp: implementation of the CModbus_TcpS class. // //MODBUS_tcp 转发规约 //#include "stdafx.h" #include "se_log.h" #include "se_btl.h" #include "modbus_tcps.h" //#include #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CModbus_TcpS::~CModbus_TcpS() { } sint32 CModbus_TcpS::GetNowSecond() { CSeTime SE_T; TCriterionTime tmptime;//sint32 SE_T.GetNow(&tmptime); return (sint32)tmptime; } void CModbus_TcpS::Init(S_PROTOCOLCFG * pcfg ) { PRawCtrl = pcfg->PRawCtrl; 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_LastSendTime=GetNowSecond(); m_RcvTimeOuts=pLink->GetRxTimeouts(); if(m_RcvTimeOuts<=0) m_RcvTimeOuts=10; } //规约发送过程 sint32 CModbus_TcpS::TxProc() { ProcCmd(); return 1; } /*********************************************************** 命令处理 ***********************************************************/ uint8 CModbus_TcpS::ProcCmd() { sint32 rtuno = pLink->GetRtuNo(); unsigned char rtuaddr = pRtu->GetRtuAddr(rtuno); //不处理命令,简单把命令删除,因为没有遥控反校 if(pCmdMem->GetResultNum(rtuno)<=0) return FALSE; S_RAWCMD rawcmd; if(pCmdMem->GetAResult(rtuno,&rawcmd)==0) return FALSE; while(pCmdMem->GetResultNum(rtuno)>0) { if(pCmdMem->GetAResult(rtuno,&rawcmd)==0) break; switch(rawcmd.type) { case DC_K_CMDRET_DOOPER: default: //对其它的下发命令不处理 pCmdMem->DelAResult(rtuno); break; } } return FALSE; } void CModbus_TcpS::ProcYKCmd(uint16 YaoKongNo,uint16 YkStatus) { sint32 rtuno=pLink->GetRtuNo(); unsigned char rtuaddr=pRtu->GetRtuAddr(rtuno); //把命令直接压入其他遥控队列 S_DO_CTL cmdinfo; S_RAWCMD rawcmd; memset(&rawcmd,0,sizeof(S_RAWCMD)); cmdinfo.funcCode = DC_K_CTL_DOEXE; cmdinfo.ptAddr = YaoKongNo+1; cmdinfo.ctlVal = YkStatus; cmdinfo.retCode = 0; rawcmd.type=DC_K_CMD_DOOPER; rawcmd.len=sizeof(cmdinfo); memcpy(rawcmd.data,&cmdinfo,sizeof(cmdinfo)); if(pCmdMem->RptAZfCmd(rtuno,rawcmd)==0) { ReturnException(0x05,0x02); PrintLog(LOG_INFORMATION,"应答遥控命令 ERROR (%d:%d)",YaoKongNo,YkStatus); return; } //简单返回一个一样的命令 unsigned char buf[1024]; int buflen =0; buf[buflen]=TransIdHi; buflen++; buf[buflen]=TransIdLo; buflen++; buf[buflen]=0; buflen++; buf[buflen]=0; buflen++; buf[buflen]=0; buflen++; buf[buflen]=6; buflen++; buf[buflen]=rtuaddr; buflen++; buf[buflen]=5; buflen++;//fun buf[buflen]=HIBYTE(YaoKongNo); buflen++; buf[buflen]=LOBYTE(YaoKongNo); buflen++; buf[buflen]=HIBYTE(YkStatus); buflen++; buf[buflen]=LOBYTE(YkStatus); buflen++; PrintLog(LOG_INFORMATION,"应答遥控命令 (%d:%d)",YaoKongNo,YkStatus); pTxBuf->Write(buf,buflen); pLink->RegisterFrm(FRAME_TX_SUC); pLink->SetCommStatus(CMST_RX_CNT); m_LastSendTime = GetNowSecond(); } void CModbus_TcpS::ReturnException(uint8 func,uint8 expCode) { sint32 rtuno = pLink->GetRtuNo(); unsigned char rtuadd = pRtu->GetRtuAddr(rtuno); unsigned char buf[20]={0}; sint32 buflen =0; buf[buflen]=TransIdHi; buflen++; buf[buflen]=TransIdLo; buflen++; buf[buflen]=0; buflen++; buf[buflen]=0; buflen++; buf[buflen]=0; buflen++; buf[buflen]=3; buflen++; buf[buflen]=rtuadd; buflen++; buf[buflen]=func|0x80; buflen++;//fun buf[buflen]=expCode; buflen++; pTxBuf->Write(buf,buflen); pLink->RegisterFrm(FRAME_TX_SUC); pLink->SetCommStatus(CMST_RX_CNT); m_LastSendTime = GetNowSecond(); } sint32 CModbus_TcpS::SendMeasure(uint16 RegOffset,uint16 RegNum) { sint32 rtuno = pLink->GetRtuNo(); uint8 rtuadd = pRtu->GetRtuAddr(rtuno); sint32 startno = RegOffset+1; S_RDB_ZFYc *ycinfo; CEasyList *yclist=pZfDataCtrl->GetYcStructList(); sint32 ycnum=yclist->GetListLen(); if(yclist==NULL || ycnum<0 || RegNum*2>255) { ReturnException(0x03,0x02); return 0; } ycinfo = (S_RDB_ZFYc *)((*yclist)[ycnum-1]); if(ycinfo->YcNo < startno || ycinfo->YcNo<(RegOffset+RegNum)) { PrintLog(LOG_ERROR,"转发数据错误, MAX YCNO=%d",ycinfo->YcNo); ReturnException(0x03,0x02); return 0; } uint8 buf[300]={0}; uint16 dl = RegNum*2+3; sint32 buflen =0; buf[buflen]=TransIdHi; buflen++; buf[buflen]=TransIdLo; buflen++; buf[buflen]=0; buflen++; buf[buflen]=0; buflen++; buf[buflen]=dl/256; buflen++; buf[buflen]=dl%256; buflen++; buf[buflen]=rtuadd; buflen++; buf[buflen]=3; buflen++;//fun buf[buflen]=RegNum*2; buflen++; sint32 j; for(j=0;jGetListLen();j++) { ycinfo=(S_RDB_ZFYc *)((*yclist)[j]); if(ycinfo->YcNo> (RegNum+RegOffset))break; if(ycinfo->YcNoYcNo-startno)*2+buflen] = ((sint32)(ycinfo->Val))/256; buf[(ycinfo->YcNo-startno)*2+1+buflen] = ((sint32)(ycinfo->Val))%256; ycinfo->OldVal=ycinfo->Val;///**Modified by WYF20191112 增加更新老值+清变化标志**/ UNSETBIT(ycinfo->qds, PTMSK_AI_CHANGE );//FEP // ycinfo->chgFlag = 0x00;//WIN } PrintLog(LOG_INFORMATION,"应答数据03: 起始地址%d - 点数%d)",RegOffset,RegNum); pTxBuf->Write(buf,buflen+RegNum*2); pLink->RegisterFrm(FRAME_TX_SUC); pLink->SetCommStatus(CMST_RX_CNT); m_LastSendTime = GetNowSecond(); return 1; } sint32 CModbus_TcpS::SendDiOne(uint16 startAddr,uint16 Num) { sint32 rtuno = pLink->GetRtuNo(); uint8 rtuadd = pRtu->GetRtuAddr(rtuno); sint32 startno = startAddr+1; S_RDB_ZFYx *yxinfo; CEasyList *yxlist=pZfDataCtrl->GetYxStructList(); if(yxlist == NULL || Num>2040)//255*8 { ReturnException(0x01,0x02); return 0; } sint32 yxnum=yxlist->GetListLen(); if(yxnum<0 ) { ReturnException(0x01,0x02); return 0; } yxinfo = (S_RDB_ZFYx *)((*yxlist)[yxnum-1]); if(yxinfo->YxNo < startno || yxinfo->YxNo<(startAddr+Num)) { PrintLog(LOG_ERROR,"转发数据错误, MAX YXNO=%d,startno=%d,Num=%d",yxinfo->YxNo,startno,Num); ReturnException(0x01,0x02); return 0; } uint8 buf[300]={0}; sint32 buflen =0; sint32 bytecount = (Num+7)/8; uint16 dl = bytecount+3; buf[buflen]=TransIdHi; buflen++; buf[buflen]=TransIdLo; buflen++; buf[buflen]=0; buflen++; buf[buflen]=0; buflen++; buf[buflen]=dl/256; buflen++; buf[buflen]=dl%256; buflen++; buf[buflen]=rtuadd; buflen++; buf[buflen]=0x01; buflen++;//fun buf[buflen]=bytecount; buflen++; sint32 j,byteIdx,bitIdx; for(j=0;jGetListLen();j++) { yxinfo=(S_RDB_ZFYx *)((*yxlist)[j]); if(yxinfo->YxNo> (Num+startAddr))break; if(yxinfo->YxNoVal == 1) { byteIdx = (yxinfo->YxNo-startno)/8 + buflen; bitIdx = (yxinfo->YxNo-startno)%8; buf[byteIdx] |= 1<YxNo-startno)/8 + buflen; bitIdx = (yxinfo->YxNo-startno)%8; buf[byteIdx] &= (~(1<OldVal=yxinfo->Val; UNSETBIT(yxinfo->qds, PTMSK_DI_CHANGE );//FEP // yxinfo->chgFlag = 0x00;//WIN } PrintLog(LOG_INFORMATION,"应答数据01: 起始地址%d - 点数%d)",startAddr,Num); pTxBuf->Write(buf,buflen+bytecount); pLink->RegisterFrm(FRAME_TX_SUC); pLink->SetCommStatus(CMST_RX_CNT); m_LastSendTime = GetNowSecond(); return 1; } //规约接收函数 sint32 CModbus_TcpS::RxProc() { sint32 rtuno = pLink->GetRtuNo(); uint8 rtuaddr = pRtu->GetRtuAddr(rtuno); uint8 buf[512]; sint32 buflen = 0 ,datalen = 0,datanum =0; buflen=pRxBuf->GetReadableSize(); //Added by WYF 20210106 int nowtime=GetNowSecond(); E_RAW_ComStat commstatus = pLink->GetCommStatus(); if ( commstatus==CMST_RX_CNT && (nowtime-m_LastSendTime) >= m_RcvTimeOuts) { //超时不重发,直接跳到下一个终端 pRxBuf->Move(buflen); pLink->RegisterFrm(FRAME_RX_TIMEOUT); pLink->SetCommStatus(CMST_RX_CNT); PrintLog(LOG_VIOLATION, " 接收数据超时\n"); m_LastSendTime=nowtime; return -1; } //Added by WYF 20210106 if(buflen< 12) return 0; if(buflen>500) buflen=500; datalen = pRxBuf->Read(buf, buflen, DEF_BUFF_NOMOVE ); sint32 framelen = buf[4]*256 + buf[5]; if( (framelen+6)<=datalen) //长度足够 { if (buf[6]!= rtuaddr)//站址不对 { pRxBuf->Move(datalen); return 0; } pLink->RegisterFrm(FRAME_RX_SUC); pLink->SetCommStatus(CMST_TX_CNT); TransIdHi = buf[0]; TransIdLo = buf[1]; //按功能码区分数据 if(buf[7] == 0x01)//请求DI数据 { uint16 startAddr = buf[8]*256 + buf[9]; uint16 pntNum = buf[10]*256 + buf[11]; SendDiOne(startAddr,pntNum); } else if(buf[7]==0x03)//请求AI数据 { uint16 startAddr = buf[8]*256 + buf[9]; uint16 pntNum = buf[10]*256 + buf[11]; SendMeasure(startAddr,pntNum); } else if(buf[7]==0x05)//遥控 { uint16 m_YaoKongNo = buf[8]*256 + buf[9]; uint16 m_YkStatus = buf[10]*256 + buf[11]; ProcYKCmd(m_YaoKongNo,m_YkStatus); } else if(buf[7]==0x06)//遥调//WYF 20190110 { uint16 m_YaoKongNo = buf[8]*256 + buf[9]; uint16 m_YkStatus = buf[10]*256 + buf[11]; ProcYTCmd(m_YaoKongNo,m_YkStatus); }//WYF 20190110 else ReturnException(buf[7],0x01);//illegal function pRxBuf->Move(framelen+6); } return 1; } //WYF 20190110 void CModbus_TcpS::ProcYTCmd(uint16 YaoKongNo,uint16 YkStatus) { sint32 rtuno=pLink->GetRtuNo(); unsigned char rtuaddr=pRtu->GetRtuAddr(rtuno); //把命令直接压入其他遥控队列 S_AO_CTL cmdinfo; S_RAWCMD rawcmd; memset(&rawcmd,0,sizeof(S_RAWCMD)); cmdinfo.funcCode = DC_K_CTL_AOEXE; cmdinfo.ptAddr = YaoKongNo+1; cmdinfo.ptVal = YkStatus; cmdinfo.retCode = 0; rawcmd.type=DC_K_CMD_AOOPER; rawcmd.len=sizeof(cmdinfo); memcpy(rawcmd.data,&cmdinfo,sizeof(cmdinfo)); if(pCmdMem->RptAZfCmd(rtuno,rawcmd)==0) { ReturnException(0x06,0x02); PrintLog(LOG_INFORMATION,"应答遥调命令 ERROR (%d:%d)",YaoKongNo,YkStatus); return; } //简单返回一个一样的命令 unsigned char buf[1024]; int buflen =0; buf[buflen]=TransIdHi; buflen++; buf[buflen]=TransIdLo; buflen++; buf[buflen]=0; buflen++; buf[buflen]=0; buflen++; buf[buflen]=0; buflen++; buf[buflen]=6; buflen++; buf[buflen]=rtuaddr; buflen++; buf[buflen]=6; buflen++;//fun buf[buflen]=HIBYTE(YaoKongNo); buflen++; buf[buflen]=LOBYTE(YaoKongNo); buflen++; buf[buflen]=HIBYTE(YkStatus); buflen++; buf[buflen]=LOBYTE(YkStatus); buflen++; PrintLog(LOG_INFORMATION,"应答遥调命令 (%d:%d)",YaoKongNo,YkStatus); pTxBuf->Write(buf,buflen); pLink->RegisterFrm(FRAME_TX_SUC); pLink->SetCommStatus(CMST_RX_CNT); m_LastSendTime = GetNowSecond(); } //WYF 20190110 //规约对象创建函数 #ifdef __unix extern "C" CProtocol* CreateProtocol(char *defpara) #else extern "C" __declspec(dllexport) CProtocol* CreateProtocol(char *defpara) #endif { CProtocol *pEpv = new CModbus_TcpS; return pEpv; }