// ProtocolPMC916.cpp: implementation of the CProtocolModbus class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "ProtocolModbus.h" #include "winsock2.h" #include "modbusrtu.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CProtocolModbus::CProtocolModbus() : CProtocol() { InitializeCriticalSection( &m_csReadFinished ); InitializeCriticalSection( &m_csWrFinished ); MTVERIFY( m_hSemComm = CreateEvent( NULL, TRUE, TRUE, 0 ) ); } CProtocolModbus::~CProtocolModbus() { DeleteCriticalSection( &m_csReadFinished ); DeleteCriticalSection( &m_csWrFinished ); MTVERIFY( CloseHandle( m_hSemComm ) ); } int CProtocolModbus::WorkMain(SETBASEPARAM SetBasePara, int nDataLen, char chMsg[80]) { if(!m_pComm) return ERR_CODE_MODBUS_RTU_COM_FAULT; // 串口通信故障 int nRet; nRet = RequestStatus(SetBasePara); if( nRet != 0 ) { return nRet; // 串口忙 } nRet = ResponseStatus(SetBasePara.nAddr, SetBasePara.nRegNum, nDataLen, chMsg); return nRet; } int CProtocolModbus:: WriteCommand(SETBASEPARAM SetBasePara, double dbData, int nDataLen) { int iResult = 0; if(!m_pComm) return ERR_CODE_MODBUS_RTU_COM_FAULT; iResult = RequestWrStatus(SetBasePara, dbData, nDataLen); if (iResult == 0) return ResponseWrStatus(SetBasePara.nAddr, SetBasePara.nRegNum, nDataLen); else return iResult; } int CProtocolModbus::ResponseStatus( int nAddr, int nRegNum, int nDataLen, char chMsg[80]) { RESPONSE_STRUCT structResponse; memset( &structResponse, 0, sizeof(RESPONSE_STRUCT) ); if (nDataLen <= 0) { SetEvent( m_hSemComm ); //LOG4C((LOG_NOTICE, "ModbusRtu设备地址:%d, 变量长度小于等于0,为非法变量", nAddr)); return ERR_CODE_MODBUS_RTU_COM_VARLEN; } int nLen = sizeof(RESPONSE_STRUCT) - sizeof(structResponse.StrRtnMsg) + nDataLen; char *pBuffer = new char[ nLen ]; memset(pBuffer, 0, nLen); int nProcessLen = 0; int nReadLen = 0; nReadLen = ReadMessage((BYTE *)pBuffer, nLen); if( nReadLen <= 0) { // 串口没有读到数据 SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_RTU_COM_READ_NO_DATA; } // 判断校验 int iCrc = GetCRC((byte*) pBuffer, (nLen - sizeof(structResponse.Crc))); //BYTE btCrc = GetCheckCode(pBuffer, // nLen - sizeof(structResponse.Lrc) - sizeof(structResponse.End)); //char chAsc[3] = {0}; //sprintf(chAsc, "%X", btCrc); BYTE high = iCrc>>8&0xff; BYTE low = iCrc&0xff; if( !( ((byte)pBuffer[nLen - 2] == low) && ((byte)pBuffer[nLen - 1] ==high) ) ) { LOG4C((LOG_NOTICE, "ModbusRtu设备地址:%d, crc校验出错!", nAddr)); SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_RTU_COM_LRC_LOST; } EnterCriticalSection( &m_csWrFinished ); //for( int i = 0; i < 4 * nRegNum; i++ ) for( int i = 0; i < nDataLen; i++ ) { chMsg[i] = pBuffer[sizeof(STATUS_STRUCT) + i]; } LeaveCriticalSection(&m_csWrFinished); // 设置串口等待事件为有信号 SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return 0; } int CProtocolModbus::RequestStatus(SETBASEPARAM SetBasePara) { int iLen = sizeof(REQUESTPARAM); REQUESTPARAM RequestPara; memset( &RequestPara, 0, iLen ); RequestPara.AddrCode = SetBasePara.nAddr; //地址码 RequestPara.FuncCode = SetBasePara.FuncCode; //功能码 RequestPara.StartAddr = htons(SetBasePara.nStartAddr); //起始地址 RequestPara.RequestRegNum = htons(SetBasePara.nRegNum); //寄存器数 BYTE *pDataBuf = new BYTE[ iLen - sizeof(RequestPara.Crc) ]; memset(pDataBuf, 0, iLen - sizeof(RequestPara.Crc) ); memcpy(pDataBuf, &RequestPara, iLen - sizeof(RequestPara.Crc) ); int iCrc = GetCRC( pDataBuf, iLen - 2 ); BYTE high = iCrc>>8&0xff; BYTE low = iCrc&0xff; RequestPara.Crc[0] = low; RequestPara.Crc[1] = high; if( WaitForSingleObject( m_hSemComm, 0 ) == WAIT_OBJECT_0 ) // 有信号才写串口 { //TRACE("Rtu设备设置串口无信号!\r\n"); ResetEvent( m_hSemComm ); int nResult = WriteMessage( (BYTE *)&RequestPara, iLen ); if( nResult == iLen ) { } else { if( pDataBuf ) { delete []pDataBuf; pDataBuf = NULL; } SetEvent( m_hSemComm ); return EER_CODE_MODBUS_RTU_COM_WRITE_DATA; } } else { if( pDataBuf ) { delete []pDataBuf; pDataBuf = NULL; } return ERR_CODE_MODBUS_RTU_COM_BUSY; } if( pDataBuf ) { delete []pDataBuf; pDataBuf = NULL; } return 0; } int CProtocolModbus::RequestWrStatus( SETBASEPARAM SetBasePara, double dbData, int nDataLen) { REQUESTWRPARAM tagRequestWrite; int nLen = sizeof(REQUESTWRPARAM); memset( &tagRequestWrite, 0, nLen ); //BYTE AddrCode[2]; //地址码 //BYTE FuncCode[2]; //功能码 //BYTE StartAddr[4]; //起始地址 //BYTE RequestRegNum[4]; //读取的寄存器个数 //BYTE Data[8]; //设置的数据 //BYTE Crc[2]; //校验码位 tagRequestWrite.AddrCode = SetBasePara.nAddr; //地址码 tagRequestWrite.FuncCode = SetBasePara.FuncCode; //功能码 tagRequestWrite.StartAddr = htons(SetBasePara.nStartAddr); //起始地址 tagRequestWrite.SetValue = htons((int)dbData); BYTE *pDataBuf = new BYTE[ nLen - sizeof(tagRequestWrite.Crc) ]; memset(pDataBuf, 0, nLen - sizeof(tagRequestWrite.Crc) ); memcpy(pDataBuf, &tagRequestWrite, nLen - sizeof(tagRequestWrite.Crc) ); int iCrc = GetCRC( pDataBuf, nLen - 2 ); BYTE high = iCrc>>8&0xff; BYTE low = iCrc&0xff; tagRequestWrite.Crc[0] = low; tagRequestWrite.Crc[1] = high; ResetEvent( m_hSemComm ); int nResult = WriteMessage( (BYTE *)&tagRequestWrite, nLen ); if( nResult == nLen ) { } else { delete []pDataBuf; SetEvent( m_hSemComm ); return EER_CODE_MODBUS_RTU_COM_WRITE_DATA; } SetEvent( m_hSemComm ); delete[]pDataBuf; return 0; } int CProtocolModbus::ResponseWrStatus(int nAddr, int nRegNum, int nDataLen) { REQUESTWRPARAM RequestWrPara; int iLen = sizeof(REQUESTWRPARAM); memset(&RequestWrPara, 0, iLen); char *pBuffer = new char[iLen]; memset(pBuffer, 0, iLen); int iProcessLen = 0; //int iReadLen = ReadMessage((BYTE *)&RequestWrPara, iLen); int iReadLen = ReadMessage((BYTE *)pBuffer, iLen); if( iReadLen <= 0) // 串口没有读到数据 { if( pBuffer ) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_RTU_COM_READ_NO_DATA; } else if(iReadLen< iLen) { TRACE("长度没有收够,断续接收,直到收完为止!\r\n"); SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_RTU_COM_FAULT; } else if( iReadLen > iLen )//实际读到包长度大于要求包的长度 { // 完全代码,不一定能执行到 TRACE("接收的长度超时所需的长度,认为是非法包,扔掉\r\n"); SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_RTU_COM_READ_LEN_OVER; } int iCrc = GetCRC( (BYTE *)pBuffer, iLen - sizeof(RequestWrPara.Crc) ); BYTE high = iCrc>>8&0xff; BYTE low = iCrc&0xff; if( !( ((byte)pBuffer[iLen - 2] == low) && ((byte)pBuffer[iLen - 1] ==high) ) ) { TRACE("lrc 校验失败!\r\n"); SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_RTU_COM_LRC_LOST; } EnterCriticalSection( &m_csWrFinished ); memset(&m_RequestWrParam, 0, sizeof(REQUESTWRPARAM)); int iTmpLen = sizeof(m_RequestWrParam.AddrCode) + sizeof(m_RequestWrParam.FuncCode) + sizeof(m_RequestWrParam.StartAddr) + sizeof(m_RequestWrParam.SetValue); memcpy( &m_RequestWrParam, pBuffer, iTmpLen);//起始位、地址码、功能码、起始地址、数据 iTmpLen = iTmpLen; memcpy( &m_RequestWrParam.Crc, pBuffer + iTmpLen, 2);//校验位 iTmpLen = iTmpLen + 2; LeaveCriticalSection(&m_csWrFinished); // 设置串口等待事件为有信号 if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } SetEvent( m_hSemComm ); return 0; } UINT CProtocolModbus::GetCRC(BYTE *pBuf, int len) { unsigned int Genpoly=0xA001; unsigned int CRC=0xFFFF; unsigned int index; while(len--) { CRC=CRC^(unsigned int)*pBuf++; for(index=0;index<8;index++) { if((CRC & 0x0001)==1) CRC=(CRC>>1)^Genpoly; else (CRC=CRC>>1); } } return(CRC); } BOOL CProtocolModbus::InitParam(PPORTPARAM pPortParam, CCommAsyn *pComm) { int addr=pPortParam->StartAddr; m_pComm=pComm; return TRUE; } void strReverse( char *str ) { int l = strlen(str); for( int i = 0; i < l; i++ ) { for(int i = 0; i < l; i++) { if( str[i] >= 'A' && str[i] <= 'Z' ) { str[i] += 32; } else if(str[i] >= 'a' && str[i] <= 'z') { str[i] -= 32; } } } } char lowercase2uppercase(BYTE btSrc) { if( btSrc >= 'a' && btSrc <= 'z' ) { return btSrc - 'a' + 'A'; } return btSrc; } char ByteToAscii(BYTE btSrc) { char chDest; if( btSrc < 10 ) { chDest = (char)(btSrc % 10 + '0'); chDest = lowercase2uppercase(chDest); return chDest; } else { chDest = ByteToAscii( btSrc / 10 ) + (char)( btSrc % 10 + '0' ); chDest = lowercase2uppercase(chDest); return chDest; } } WORD AsciiToBYTE(BYTE btSrc) { WORD chDest = (WORD)btSrc; if ((btSrc >= 'A')&&(btSrc <= 'F')) { chDest = chDest - 'A' + 10; } else if ((btSrc >= 'a')&&(btSrc <= 'f')) { chDest = chDest - 'a' + 10; } else if ((btSrc >= '0')&&(btSrc <= '9')) { chDest -= '0'; } return chDest; }