// CModbus_TcpS.cpp: implementation of the CModbus_TcpS class. // //MODBUS_tcp 转发规约 //#include "stdafx.h" #include "se_log.h" #include "se_btl.h" #include "L02ATS_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() { } 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_RcvTimeOuts = pLink->GetRxTimeouts(); //等待间隔 if (m_RcvTimeOuts <= 0) m_RcvTimeOuts = 5; m_LastRecvTime = GetNowSecond(); } //规约发送过程 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->SetCommStatus(CMST_NORMAL); } void CModbus_TcpS::ReturnException(uint8 func,uint8 expCode) //func代表请求功能码 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++; //单元标识——rtu站址 buf[buflen]=func|0x80; buflen++;//fun 响应功能码=请求功能码+0x80 buf[buflen]=expCode; buflen++; //对应文档中的异常处理的异常码 pTxBuf->Write(buf,buflen); pLink->SetCommStatus(CMST_NORMAL); } //请求AI数据 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>250) { 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->SetCommStatus(CMST_NORMAL); return 1; } //请求DI数据 sint32 CModbus_TcpS::SendDiOne(uint16 startAddr,uint16 Num) { sint32 rtuno = pLink->GetRtuNo(); //获取rtu编号 uint8 rtuadd = pRtu->GetRtuAddr(rtuno); //获取rtu站址 sint32 startno = startAddr+1; S_RDB_ZFYx *yxinfo; CEasyList *yxlist=pZfDataCtrl->GetYxStructList(); //获取前置转发数据.遥信结构列表 if(yxlist == NULL || Num>2000)//250*8 前置转发遥信结构列表为空||请求的寄存器个数过大 { ReturnException(0x01,0x02); //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++; //Length长度(Length长度字段后面的包含字节。也就是3 + 2 * N Data(as requested)字段包含的字节) buf[buflen]=dl%256; buflen++; //Length长度 buf[buflen]=rtuadd; buflen++; //单元标识(RTU站址) buf[buflen]=0x01; buflen++;//fun //功能码 buf[buflen]=bytecount; buflen++; //Data的数据长度 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->SetCommStatus(CMST_NORMAL); return 1; } //规约接收函数 sint32 CModbus_TcpS::RxProc() { sint32 rtuno = pLink->GetRtuNo(); uint8 rtuaddr = pRtu->GetRtuAddr(rtuno); //RTU站址 uint8 buf[512]; sint32 buflen = 0 ,datalen = 0,datanum =0; sint32 nowTime = GetNowSecond(); buflen=pRxBuf->GetReadableSize(); if(buflen< 12) { if ((nowTime - m_LastRecvTime) >= m_RcvTimeOuts) { pLink->RegisterFrm(FRAME_RX_TIMEOUT); m_LastRecvTime = nowTime; } return 0; } m_LastRecvTime = nowTime; pLink->RegisterFrm(FRAME_RX_SUC); 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; } TransIdHi = buf[0]; //header报头 事务标识 TransIdLo = buf[1]; //header报头 事务标识 //按功能码区分数据 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] == 0x02)//读开关量输入 { uint16 startAddr = buf[8] * 256 + buf[9]; uint16 pntNum = buf[10] * 256 + buf[11]; SendSwitch(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] == 0x04) { //读输入CIOS寄存器 uint16 startAddr = buf[8] * 256 + buf[9]; uint16 pntNum = buf[10] * 256 + buf[11]; SendMeasureOne(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->SetCommStatus(CMST_NORMAL); } //WYF 20190110 //读输入CIOS寄存器 sint32 CModbus_TcpS::SendMeasureOne(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 > 2000) { ReturnException(0x04, 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(0x04, 0x02); return 0; } uint8 buf[4009] = { 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] = 4; buflen++;//fun if (RegNum * 2 > 250) { buf[buflen] = 0; buflen++; } else { 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, "应答数据04: 起始地址%d - 点数%d)", RegOffset, RegNum); pTxBuf->Write(buf, buflen + RegNum * 2); pLink->SetCommStatus(CMST_NORMAL); return 1; } //读开关量输入 sint32 CModbus_TcpS::SendSwitch(uint16 startAddr, uint16 Num) { sint32 rtuno = pLink->GetRtuNo(); //获取rtu编号 uint8 rtuadd = pRtu->GetRtuAddr(rtuno); //获取rtu站址 sint32 startno = startAddr + 1; S_RDB_ZFYx *yxinfo; CEasyList *yxlist = pZfDataCtrl->GetYxStructList(); //获取前置转发数据.遥信结构列表 if (yxlist == NULL || Num>2000)//250*8 前置转发遥信结构列表为空||请求的寄存器个数过大 { ReturnException(0x02, 0x02); //0x02:请求功能码 0x02:返回的异常码 return 0; } sint32 yxnum = yxlist->GetListLen(); if (yxnum<0) { ReturnException(0x02, 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(0x02, 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++; //Length长度(Length长度字段后面的包含字节。也就是3 + 2 * N Data(as requested)字段包含的字节) buf[buflen] = dl % 256; buflen++; //Length长度 buf[buflen] = rtuadd; buflen++; //单元标识(RTU站址) buf[buflen] = 0x02; buflen++;//fun //功能码 buf[buflen] = bytecount; buflen++; //Data的数据长度 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 << bitIdx; } else { byteIdx = (yxinfo->YxNo - startno) / 8 + buflen; bitIdx = (yxinfo->YxNo - startno) % 8; buf[byteIdx] &= (~(1 << bitIdx)) & 0xff; ///**Modified by WYF20180616 先移动再取反**/ // buf[byteIdx] &= (~1<OldVal = yxinfo->Val; UNSETBIT(yxinfo->qds, PTMSK_DI_CHANGE);//FEP // yxinfo->chgFlag = 0x00;//WIN } PrintLog(LOG_INFORMATION, "应答数据02: 起始地址%d - 点数%d)", startAddr, Num); pTxBuf->Write(buf, buflen + bytecount); pLink->SetCommStatus(CMST_NORMAL); return 1; } //获取当前时间 sint32 CModbus_TcpS::GetNowSecond() { CSeTime SE_T; TCriterionTime tmptime;//sint32 SE_T.GetNow(&tmptime); return (sint32)tmptime; } //规约对象创建函数 #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; }