#include "sub_modbus_rtu.h" /*! * Constants which defines the format of a modbus frame. The example is * shown for a Modbus RTU/ASCII frame. Note that the Modbus PDU is not * dependent on the underlying transport. * * * <------------------------ MODBUS SERIAL LINE PDU (1) -------------------> * <----------- MODBUS PDU (1') ----------------> * +-----------+---------------+----------------------------+-------------+ * | Address | Function Code | Data | CRC/LRC | * +-----------+---------------+----------------------------+-------------+ * | | | | * (2) (3/2') (3') (4) * * (1) ... MB_SER_PDU_SIZE_MAX = 256 * (2) ... MB_SER_PDU_ADDR_OFF = 0 * (3) ... MB_SER_PDU_PDU_OFF = 1 * (4) ... MB_SER_PDU_SIZE_CRC = 2 * * (1') ... MB_PDU_SIZE_MAX = 253 * (2') ... MB_PDU_FUNC_OFF = 0 * (3') ... MB_PDU_DATA_OFF = 1 * */ CSubModbusRtuProcessItem::CSubModbusRtuProcessItem() { m_YCRegCount = 0; m_YMRegCount = 0; m_YXRegCount = 0; m_pYCRegTab = NULL; m_pYMRegTab = NULL; m_pYXRegTab = NULL; } CSubModbusRtuProcessItem::~CSubModbusRtuProcessItem() { if (m_pYCRegTab) { delete[] m_pYCRegTab; m_pYCRegTab = NULL; } if (m_pYMRegTab) { delete[] m_pYMRegTab; m_pYMRegTab = NULL; } if (m_pYXRegTab) { delete[] m_pYXRegTab; m_pYXRegTab = NULL; } } void CSubModbusRtuProcessItem::Attach(int uid, int physicsAddress /* = 0 */, int commonAddress /* = 0 */, int originatorAddress /* = 0 */) { CPortProcessItem::Attach(uid, physicsAddress); } void CSubModbusRtuProcessItem::Release(void) { CPortProcessItem::Release(); } CSubModbusRtuProcess::CSubModbusRtuProcess() { } CSubModbusRtuProcess::~CSubModbusRtuProcess() { } CPortProcessItem *CSubModbusRtuProcess::CreateItem(int ord) { return dynamic_cast(new CSubModbusRtuProcessItem); } void CSubModbusRtuProcess::DestroyItem(int ord, BOOLEAN bDeleted /* = FALSE */) { CSubModbusRtuProcessItem *pItem = (CSubModbusRtuProcessItem *)GetItem(ord); if (pItem != NULL && !bDeleted) { delete pItem; return CPortProcess::DestroyItem(ord, TRUE); } return CPortProcess::DestroyItem(ord, bDeleted); } BOOLEAN CSubModbusRtuProcess::OnPreCreate(int id) { int i; int uid; int port; BYTE addr; DWORD ulBaudRate; CSubModbusRtuProcessItem *pItem; if (!CPortProcess::OnPreCreate(id)) return FALSE; port = config.processes[id].order; if (port < 0 || port >= HARDWARE_PORTS_NUM) return FALSE; ulBaudRate = config.hardware.ports[port].baud; if (ulBaudRate > 19200) { usTimerT35_50us = 1750; /* 1800us. */ } else { /* The timer reload value for a character is given by: * * ChTimeValue = Ticks_per_1s / ( Baudrate / 11 ) * = 11 * Ticks_per_1s / Baudrate * = 220000 / Baudrate * The reload for t3.5 is 1.5 times this value and similary * for t3.5. */ usTimerT35_50us = 38500000L / ulBaudRate; } for (i = 0; i < PROCESS_UNIT_NUM; i++) { pItem = (CSubModbusRtuProcessItem *)GetItem(i); if (NULL == pItem) continue; uid = GetUnitID(i); if (uid < 0 || uid >= UNIT_NUM) continue; if (GetUnitAddr(uid, &addr, 1)) { //获取单元地址成功,则该段原地址采用配置地址,否则该单元为无效地址。 pItem->Attach(uid, addr); //pItem->m_addr = addr; //配置地址 } pItem->m_YCRegCount = GetUnitYCCount(uid); if (m_YC_Type == M_ME_NC) { pItem->m_YCRegCount = (GetUnitYCCount(uid) << 1); //采用浮点数上传 } pItem->m_YMRegCount = (GetUnitYMCount(uid) << 1); //遥脉采用4字节传输 pItem->m_YXRegCount = GetUnitYXCount(uid); if (pItem->m_YCRegCount) { pItem->m_pYCRegTab = new WORD[pItem->m_YCRegCount]; if (pItem->m_pYCRegTab == NULL) return FALSE; } if (pItem->m_YMRegCount) { pItem->m_pYMRegTab = new WORD[pItem->m_YMRegCount]; if (pItem->m_pYMRegTab == NULL) return FALSE; } if (pItem->m_YXRegCount) { pItem->m_pYXRegTab = new BYTE[pItem->m_YXRegCount]; if (pItem->m_pYXRegTab == NULL) return FALSE; } } return TRUE; } BOOLEAN CSubModbusRtuProcess::Run(void) { //if (!CPortProcess::Run()) return FALSE; if (!CProcess::Run()) return FALSE; SerialPortRead(usTimerT35_50us); //数据发送 SerialPortWrite(); int i, j, uid; FeedDog(); for (i = 0; i < PROCESS_UNIT_NUM; i++) { CSubModbusRtuProcessItem *pItem = (CSubModbusRtuProcessItem *)GetItem(i); if (NULL == pItem) continue; uid = pItem->GetUnitID(); if (uid < 0) continue; //刷新寄存器 float *fvalue = NULL; short *svalue = NULL; DWORD *dvalue = NULL; BYTE *bvalue = NULL; if (m_YC_Type == M_ME_NC) fvalue = (float *)pItem->m_pYCRegTab; else svalue = (short *)pItem->m_pYCRegTab; for (j = 0; j < GetUnitYCCount(uid); j++) { if (m_YC_Type == M_ME_NC) { *fvalue = GetUnitYCReal(uid, j); fvalue++; } else { *svalue = (short)GetUnitYC(uid, j); svalue++; } } dvalue = (DWORD *)pItem->m_pYMRegTab; for (j = 0; j < GetUnitYMCount(uid); j++) { *dvalue = (DWORD)GetUnitYM(uid, j); dvalue++; } bvalue = (BYTE *)pItem->m_pYXRegTab; for (j = 0; j < GetUnitYXCount(uid); j++) { *bvalue = (BYTE)GetUnitYX(uid, j); bvalue++; } int order; BYTE action, result; DWORD value; BYTE by_value; if (GetUnitYT(uid, order, value, action, result)) { vLog(LOG_DEBUG, "Unit(%d) set point(%d) %d state is %s result is %s\n", uid, order, value, val_to_str(action, yt_state, "STATE=%d"), val_to_str(result, yt_result, "RESULT=%d")); if (YTS_SELED == action && YTR_FAIL == result) { action = YTS_ABRED; } else if (YTS_SELREQ == action && YTR_OVER == result) { action = YTS_ABRED; } else if (YTS_SELING == action && YTR_OVER == result) { action = YTS_ABRED; } if (YTS_SELED == action) { SetUnitYT(uid, order, value, YTS_EXEREQ, YTR_IDLE); vLog(LOG_DEBUG, "Unit(%d) set point(%d) %d state is YTS_EXEREQ result is YTR_IDLE.\n", uid, order, value); } else if (YTS_ABRED == action) { SetUnitYT(uid, order, value, YTS_ABRREQ, YTR_IDLE); vLog(LOG_DEBUG, "Unit(%d) set point(%d) %d state is YTS_ABRREQ result is YTR_IDLE.\n", uid, order, value); } } if (GetUnitYK(uid, order, by_value, action, result)) { vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is %s result is %s\n", uid, order, (by_value ? "CLOSE" : "TRIP"), val_to_str(action, yk_state, "STATE=%d"), val_to_str(result, yk_result, "RESULT=%d")); if (YKS_SELED == action && YKR_FAIL == result) { action = YKS_ABRED; } else if (YKS_SELREQ == action && YKR_OVER == result) { action = YKS_ABRED; } else if (YKS_SELING == action && YKR_OVER == result) { action = YKS_ABRED; } if (YKS_ABRED == action) { SetUnitYK(uid, order, by_value, YKS_ABRREQ, YKR_IDLE); vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is YKS_ABRREQ result is YKR_IDLE.\n", uid, order, (by_value ? "CLOSE" : "TRIP")); } else if (YKS_SELED == action) { SetUnitYK(uid, order, by_value, YKS_EXEREQ, YKR_IDLE); vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is YKS_EXEREQ result is YKR_IDLE.\n", uid, order, (by_value ? "CLOSE" : "TRIP")); } } } return TRUE; } BOOLEAN CSubModbusRtuProcess::OnTimer(void) { if (!CPortProcess::OnTimer()) return FALSE; return TRUE; } BOOLEAN CSubModbusRtuProcess::OnReceiveData(BYTE* pData, int count) { return TRUE; } BOOLEAN CSubModbusRtuProcess::SerialPortTimeout(void) { eMBErrorCode eStatus = MB_ENOERR; BYTE ucRcvAddress; BYTE *pucFrame; WORD usLength; WORD usRcvBufferPos = GetDataCount(); if (!GetData(ucRTUBuf, usRcvBufferPos)) { vLog(LOG_ERROR, "%s GetData() ERROR!\n", __FILE__); return FALSE; } /* Length and CRC check */ if ((usRcvBufferPos >= MB_SER_PDU_SIZE_MIN) && (GetCRC16((BYTE *)ucRTUBuf, usRcvBufferPos) == 0)) { /* Save the address field. All frames are passed to the upper layed * and the decision if a frame is used is done there. */ ucRcvAddress = ucRTUBuf[MB_SER_PDU_ADDR_OFF]; /* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus * size of address field and CRC checksum. */ usLength = (WORD)(usRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_CRC); /* Return the start of the Modbus PDU to the caller. */ pucFrame = (BYTE *)&ucRTUBuf[MB_SER_PDU_PDU_OFF]; DropData(usRcvBufferPos); int uid, order; CSubModbusRtuProcessItem* pItem; uid = GetUnitByAddr(&ucRcvAddress, 1); if (uid < 0 || uid >= UNIT_NUM) return FALSE; order = GetOrderByUnitID(uid); if (order < 0 || order >= PROCESS_UNIT_NUM) return FALSE; pItem = (CSubModbusRtuProcessItem *)GetItem(order); if ((ucRcvAddress != pItem->m_physicsAddress) && (ucRcvAddress != MB_ADDRESS_BROADCAST)) { return TRUE; } BYTE ucFunctionCode = pucFrame[MB_PDU_FUNC_OFF]; eMBException eException; DisplayRxData(ucRTUBuf, usRcvBufferPos, TRUE, uid); UnitFeedDog(uid); eException = MB_EX_ILLEGAL_FUNCTION; switch (ucFunctionCode) { case MB_FUNC_READ_INPUT_REGISTER: eException = eMBFuncReadInputRegister(pItem, pucFrame, &usLength); break; case MB_FUNC_READ_HOLDING_REGISTER: eException = eMBFuncReadHoldingRegister(pItem, pucFrame, &usLength); break; case MB_FUNC_WRITE_MULTIPLE_REGISTERS: eException = eMBFuncWriteMultipleHoldingRegister(pItem, pucFrame, &usLength); break; case MB_FUNC_WRITE_REGISTER: eException = eMBFuncWriteHoldingRegister(pItem, pucFrame, &usLength); break; case MB_FUNC_READ_COILS: eException = eMBFuncReadCoils(pItem, pucFrame, &usLength); break; case MB_FUNC_WRITE_SINGLE_COIL: eException = eMBFuncWriteCoil(pItem, pucFrame, &usLength); break; case MB_FUNC_WRITE_MULTIPLE_COILS: eException = eMBFuncWriteMultipleCoils(pItem, pucFrame, &usLength); break; case MB_FUNC_READ_DISCRETE_INPUTS: eException = eMBFuncReadDiscreteInputs(pItem, pucFrame, &usLength); break; default: break; } if (ucRcvAddress != MB_ADDRESS_BROADCAST) { if (eException != MB_EX_NONE) { /* An exception occured. Build an error frame. */ usLength = 0; pucFrame[usLength++] = (BYTE)(ucFunctionCode | MB_FUNC_ERROR); pucFrame[usLength++] = eException; } eStatus = eMBRTUSend(ucRcvAddress, pucFrame, usLength); } } else { DropData(usRcvBufferPos); eStatus = MB_EIO; } if (eStatus != MB_ENOERR) { vLog(LOG_ERROR, "modbus have error(%d)!\n", eStatus); return FALSE; } return TRUE; } eMBErrorCode CSubModbusRtuProcess::eMBRTUSend(BYTE ucSlaveAddress, const BYTE *pucFrame, WORD usLength) { eMBErrorCode eStatus = MB_ENOERR; BYTE *pucSndBufferCur; WORD usSndBufferCount; WORD usCRC16; pucSndBufferCur = (BYTE *) pucFrame - 1; usSndBufferCount = 1; /* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */ pucSndBufferCur[MB_SER_PDU_ADDR_OFF] = ucSlaveAddress; usSndBufferCount += usLength; /* Calculate CRC16 checksum for Modbus-Serial-Line-PDU. */ usCRC16 = GetCRC16((BYTE *) pucSndBufferCur, usSndBufferCount); ucRTUBuf[usSndBufferCount++] = (BYTE)(usCRC16 >> 8); ucRTUBuf[usSndBufferCount++] = (BYTE)(usCRC16 & 0xFF); if (WriteData(ucRTUBuf, usSndBufferCount)) { DisplayTxData(ucRTUBuf, usSndBufferCount, TRUE); eStatus = MB_EIO; } return eStatus; } eMBException CSubModbusRtuProcess::prveMBError2Exception(eMBErrorCode eErrorCode) { eMBException eStatus; switch (eErrorCode) { case MB_ENOERR: eStatus = MB_EX_NONE; break; case MB_ENOREG: eStatus = MB_EX_ILLEGAL_DATA_ADDRESS; break; case MB_ETIMEDOUT: eStatus = MB_EX_SLAVE_BUSY; break; default: eStatus = MB_EX_SLAVE_DEVICE_FAILURE; break; } return eStatus; } eMBException CSubModbusRtuProcess::eMBFuncReadInputRegister(CSubModbusRtuProcessItem *pItem, BYTE* pucFrame, WORD* usLen) { WORD usRegAddress; WORD usRegCount; BYTE *pucFrameCur; eMBException eStatus = MB_EX_NONE; eMBErrorCode eRegStatus; if (*usLen == (MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN)) { usRegAddress = (WORD)(pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8); usRegAddress |= (WORD)(pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1]); usRegCount = (WORD)(pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8); usRegCount |= (WORD)(pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1]); /* Check if the number of registers to read is valid. If not * return Modbus illegal data value exception. */ if ((usRegCount >= 1) && (usRegCount < MB_PDU_FUNC_READ_REGCNT_MAX)) { /* Set the current PDU data pointer to the beginning. */ pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF]; *usLen = MB_PDU_FUNC_OFF; /* First byte contains the function code. */ *pucFrameCur++ = MB_FUNC_READ_INPUT_REGISTER; *usLen += 1; /* Second byte in the response contain the number of bytes. */ *pucFrameCur++ = (BYTE)(usRegCount << 1); *usLen += 1; eRegStatus = eMBRegInputCB(pItem, pucFrameCur, usRegAddress, usRegCount); /* If an error occured convert it into a Modbus exception. */ if (eRegStatus != MB_ENOERR) { eStatus = prveMBError2Exception(eRegStatus); } else { *usLen += usRegCount << 1; } } else { eStatus = MB_EX_ILLEGAL_DATA_VALUE; } } else { /* Can't be a valid read input register request because the length * is incorrect. */ eStatus = MB_EX_ILLEGAL_DATA_VALUE; } return eStatus; } eMBException CSubModbusRtuProcess::eMBFuncWriteHoldingRegister(CSubModbusRtuProcessItem *pItem, BYTE* pucFrame, WORD* usLen) { WORD usRegAddress; eMBException eStatus = MB_EX_NONE; eMBErrorCode eRegStatus; if (*usLen == (MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN)) { usRegAddress = (WORD)(pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8); usRegAddress |= (WORD)(pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1]); /* Make callback to update the value. */ eRegStatus = eMBRegHoldingCB(pItem, &pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF], usRegAddress, 1, MB_REG_WRITE); /* If an error occured convert it into a Modbus exception. */ if (eRegStatus != MB_ENOERR) { eStatus = prveMBError2Exception(eRegStatus); } } else { /* Can't be a valid request because the length is incorrect. */ eStatus = MB_EX_ILLEGAL_DATA_VALUE; } return eStatus; } eMBException CSubModbusRtuProcess::eMBFuncWriteMultipleHoldingRegister(CSubModbusRtuProcessItem *pItem, BYTE* pucFrame, WORD* usLen) { WORD usRegAddress; WORD usRegCount; BYTE ucRegByteCount; eMBException eStatus = MB_EX_NONE; eMBErrorCode eRegStatus; if (*usLen >= (MB_PDU_FUNC_WRITE_MUL_SIZE_MIN + MB_PDU_SIZE_MIN)) { usRegAddress = (WORD)(pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8); usRegAddress |= (WORD)(pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF + 1]); usRegCount = (WORD)(pucFrame[MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF] << 8); usRegCount |= (WORD)(pucFrame[MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF + 1]); ucRegByteCount = pucFrame[MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF]; if ((usRegCount >= 1) && (usRegCount <= MB_PDU_FUNC_WRITE_MUL_REGCNT_MAX) && (ucRegByteCount == (BYTE) (usRegCount << 1))) { /* Make callback to update the register values. */ eRegStatus = eMBRegHoldingCB(pItem, &pucFrame[MB_PDU_FUNC_WRITE_MUL_VALUES_OFF], usRegAddress, usRegCount, MB_REG_WRITE); /* If an error occured convert it into a Modbus exception. */ if (eRegStatus != MB_ENOERR) { eStatus = prveMBError2Exception(eRegStatus); } else { /* The response contains the function code, the starting * address and the quantity of registers. We reuse the * old values in the buffer because they are still valid. */ *usLen = MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF; } } else { eStatus = MB_EX_ILLEGAL_DATA_VALUE; } } else { /* Can't be a valid request because the length is incorrect. */ eStatus = MB_EX_ILLEGAL_DATA_VALUE; } return eStatus; } eMBException CSubModbusRtuProcess::eMBFuncReadHoldingRegister(CSubModbusRtuProcessItem *pItem, BYTE* pucFrame, WORD* usLen) { WORD usRegAddress; WORD usRegCount; BYTE *pucFrameCur; eMBException eStatus = MB_EX_NONE; eMBErrorCode eRegStatus; if (*usLen == (MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN)) { usRegAddress = (WORD)(pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8); usRegAddress |= (WORD)(pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1]); usRegCount = (WORD)(pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8); usRegCount = (WORD)(pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1]); /* Check if the number of registers to read is valid. If not * return Modbus illegal data value exception. */ if ((usRegCount >= 1) && (usRegCount <= MB_PDU_FUNC_READ_REGCNT_MAX)) { /* Set the current PDU data pointer to the beginning. */ pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF]; *usLen = MB_PDU_FUNC_OFF; /* First byte contains the function code. */ *pucFrameCur++ = MB_FUNC_READ_HOLDING_REGISTER; *usLen += 1; /* Second byte in the response contain the number of bytes. */ *pucFrameCur++ = (BYTE) (usRegCount << 1); *usLen += 1; /* Make callback to fill the buffer. */ eRegStatus = eMBRegHoldingCB(pItem, pucFrameCur, usRegAddress, usRegCount, MB_REG_READ); /* If an error occured convert it into a Modbus exception. */ if (eRegStatus != MB_ENOERR) { eStatus = prveMBError2Exception(eRegStatus); } else { *usLen += usRegCount << 1; } } else { eStatus = MB_EX_ILLEGAL_DATA_VALUE; } } else { /* Can't be a valid request because the length is incorrect. */ eStatus = MB_EX_ILLEGAL_DATA_VALUE; } return eStatus; } eMBException CSubModbusRtuProcess::eMBFuncReadCoils(CSubModbusRtuProcessItem *pItem, BYTE* pucFrame, WORD* usLen) { WORD usRegAddress; WORD usCoilCount; BYTE ucNBytes; BYTE *pucFrameCur; eMBException eStatus = MB_EX_NONE; eMBErrorCode eRegStatus; if (*usLen == (MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN)) { usRegAddress = (WORD)(pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8); usRegAddress |= (WORD)(pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1]); usCoilCount = (WORD)(pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF] << 8); usCoilCount |= (WORD)(pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF + 1]); /* Check if the number of registers to read is valid. If not * return Modbus illegal data value exception. */ if ((usCoilCount >= 1) && (usCoilCount < MB_PDU_FUNC_READ_COILCNT_MAX)) { /* Set the current PDU data pointer to the beginning. */ pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF]; *usLen = MB_PDU_FUNC_OFF; /* First byte contains the function code. */ *pucFrameCur++ = MB_FUNC_READ_COILS; *usLen += 1; /* Test if the quantity of coils is a multiple of 8. If not last * byte is only partially field with unused coils set to zero. */ if ((usCoilCount & 0x0007) != 0) { ucNBytes = (BYTE)((usCoilCount >> 3) + 1); } else { ucNBytes = (BYTE)(usCoilCount >> 3); } *pucFrameCur++ = ucNBytes; *usLen += 1; eRegStatus = eMBRegCoilsCB(pItem, pucFrameCur, usRegAddress, usCoilCount, MB_REG_READ); /* If an error occured convert it into a Modbus exception. */ if (eRegStatus != MB_ENOERR) { eStatus = prveMBError2Exception(eRegStatus); } else { /* The response contains the function code, the starting address * and the quantity of registers. We reuse the old values in the * buffer because they are still valid. */ *usLen += ucNBytes;; } } else { eStatus = MB_EX_ILLEGAL_DATA_VALUE; } } else { /* Can't be a valid read coil register request because the length * is incorrect. */ eStatus = MB_EX_ILLEGAL_DATA_VALUE; } return eStatus; } eMBException CSubModbusRtuProcess::eMBFuncWriteCoil(CSubModbusRtuProcessItem *pItem, BYTE* pucFrame, WORD* usLen) { WORD usRegAddress; BYTE ucBuf[2]; eMBException eStatus = MB_EX_NONE; eMBErrorCode eRegStatus; if (*usLen == (MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN)) { usRegAddress = (WORD)(pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8); usRegAddress |= (WORD)(pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1]); if ((pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF + 1] == 0x00) && ((pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0xFF) || (pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0x00))) { ucBuf[1] = 0; if (pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0xFF) { ucBuf[0] = 1; } else { ucBuf[0] = 0; } eRegStatus = eMBRegCoilsCB(pItem, &ucBuf[0], usRegAddress, 1, MB_REG_WRITE); /* If an error occured convert it into a Modbus exception. */ if (eRegStatus != MB_ENOERR) { eStatus = prveMBError2Exception(eRegStatus); } } else { eStatus = MB_EX_ILLEGAL_DATA_VALUE; } } else { /* Can't be a valid write coil register request because the length * is incorrect. */ eStatus = MB_EX_ILLEGAL_DATA_VALUE; } return eStatus; } eMBException CSubModbusRtuProcess::eMBFuncWriteMultipleCoils(CSubModbusRtuProcessItem *pItem, BYTE* pucFrame, WORD* usLen) { WORD usRegAddress; WORD usCoilCnt; BYTE ucByteCount; BYTE ucByteCountVerify; eMBException eStatus = MB_EX_NONE; eMBErrorCode eRegStatus; if (*usLen > (MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN)) { usRegAddress = (WORD)(pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8); usRegAddress |= (WORD)(pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF + 1]); usCoilCnt = (WORD)(pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF] << 8); usCoilCnt |= (WORD)(pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF + 1]); ucByteCount = pucFrame[MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF]; /* Compute the number of expected bytes in the request. */ if ((usCoilCnt & 0x0007) != 0) { ucByteCountVerify = (BYTE)(usCoilCnt / 8 + 1); } else { ucByteCountVerify = (BYTE)(usCoilCnt / 8); } if ((usCoilCnt >= 1) && (usCoilCnt <= MB_PDU_FUNC_WRITE_MUL_COILCNT_MAX) && (ucByteCountVerify == ucByteCount)) { eRegStatus = eMBRegCoilsCB(pItem, &pucFrame[MB_PDU_FUNC_WRITE_MUL_VALUES_OFF], usRegAddress, usCoilCnt, MB_REG_WRITE); /* If an error occured convert it into a Modbus exception. */ if (eRegStatus != MB_ENOERR) { eStatus = prveMBError2Exception(eRegStatus); } else { /* The response contains the function code, the starting address * and the quantity of registers. We reuse the old values in the * buffer because they are still valid. */ *usLen = MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF; } } else { eStatus = MB_EX_ILLEGAL_DATA_VALUE; } } else { /* Can't be a valid write coil register request because the length * is incorrect. */ eStatus = MB_EX_ILLEGAL_DATA_VALUE; } return eStatus; } eMBException CSubModbusRtuProcess::eMBFuncReadDiscreteInputs(CSubModbusRtuProcessItem *pItem, BYTE* pucFrame, WORD* usLen) { WORD usRegAddress; WORD usDiscreteCnt; BYTE ucNBytes; BYTE *pucFrameCur; eMBException eStatus = MB_EX_NONE; eMBErrorCode eRegStatus; if (*usLen == (MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN)) { usRegAddress = (WORD)(pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8); usRegAddress |= (WORD)(pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1]); usDiscreteCnt = (WORD)(pucFrame[MB_PDU_FUNC_READ_DISCCNT_OFF] << 8); usDiscreteCnt |= (WORD)(pucFrame[MB_PDU_FUNC_READ_DISCCNT_OFF + 1]); /* Check if the number of registers to read is valid. If not * return Modbus illegal data value exception. */ if ((usDiscreteCnt >= 1) && (usDiscreteCnt < MB_PDU_FUNC_READ_DISCCNT_MAX)) { /* Set the current PDU data pointer to the beginning. */ pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF]; *usLen = MB_PDU_FUNC_OFF; /* First byte contains the function code. */ *pucFrameCur++ = MB_FUNC_READ_DISCRETE_INPUTS; *usLen += 1; /* Test if the quantity of coils is a multiple of 8. If not last * byte is only partially field with unused coils set to zero. */ if ((usDiscreteCnt & 0x0007) != 0) { ucNBytes = (BYTE) ((usDiscreteCnt >> 3) + 1); } else { ucNBytes = (BYTE) (usDiscreteCnt >> 3); } *pucFrameCur++ = ucNBytes; *usLen += 1; eRegStatus = eMBRegDiscreteCB(pItem, pucFrameCur, usRegAddress, usDiscreteCnt); /* If an error occured convert it into a Modbus exception. */ if (eRegStatus != MB_ENOERR) { eStatus = prveMBError2Exception(eRegStatus); } else { /* The response contains the function code, the starting address * and the quantity of registers. We reuse the old values in the * buffer because they are still valid. */ *usLen += ucNBytes;; } } else { eStatus = MB_EX_ILLEGAL_DATA_VALUE; } } else { /* Can't be a valid read coil register request because the length * is incorrect. */ eStatus = MB_EX_ILLEGAL_DATA_VALUE; } return eStatus; } eMBErrorCode CSubModbusRtuProcess::eMBRegInputCB(CSubModbusRtuProcessItem *pItem, BYTE* pucRegBuffer, WORD usAddress, WORD usNRegs) { eMBErrorCode eStatus = MB_ENOERR; int iRegIndex; if ((usAddress >= 0) && (usAddress + usNRegs <= 0 + pItem->m_YCRegCount)) { iRegIndex = (int)(usAddress - 0); while (usNRegs > 0) { *pucRegBuffer++ = (BYTE)(pItem->m_pYCRegTab[iRegIndex] >> 8); *pucRegBuffer++ = (BYTE)(pItem->m_pYCRegTab[iRegIndex] & 0xFF); iRegIndex++; usNRegs--; } } else { eStatus = MB_ENOREG; } return eStatus; } eMBErrorCode CSubModbusRtuProcess::eMBRegHoldingCB(CSubModbusRtuProcessItem *pItem, BYTE* pucRegBuffer, WORD usAddress, WORD usNRegs, eMBRegisterMode eMode) { eMBErrorCode eStatus = MB_ENOERR; WORD usRegHoldingValue; int iRegIndex; int uid; uid = pItem->GetUnitID(); if ((usAddress >= 0) && (usAddress + usNRegs <= 0 + pItem->m_YMRegCount)) { iRegIndex = (int)(usAddress - 0); switch (eMode) { /* Pass current register values to the protocol stack. */ case MB_REG_READ: while (usNRegs > 0) { *pucRegBuffer++ = (BYTE)(pItem->m_pYMRegTab[iRegIndex] >> 8); *pucRegBuffer++ = (BYTE)(pItem->m_pYMRegTab[iRegIndex] & 0xFF); iRegIndex++; usNRegs--; } break; /* Update current register values with new values from the * protocol stack. */ case MB_REG_WRITE: while (usNRegs > 0) { usRegHoldingValue = *pucRegBuffer++ << 8; usRegHoldingValue |= *pucRegBuffer++; //写寄存器 SetUnitYT(uid, iRegIndex, usRegHoldingValue, YTS_EXEREQ, YTR_IDLE); vLog(LOG_DEBUG, "Unit(%d) set point(%d) %d state is YTS_EXEREQ result is YTR_IDLE.\n", uid, iRegIndex, usRegHoldingValue); iRegIndex++; usNRegs--; } } } else { eStatus = MB_ENOREG; } return eStatus; } eMBErrorCode CSubModbusRtuProcess::eMBRegCoilsCB(CSubModbusRtuProcessItem *pItem, BYTE* pucRegBuffer, WORD usAddress, WORD usNCoils, eMBRegisterMode eMode) { eMBErrorCode eStatus = MB_ENOERR; WORD usCoilGroups = ((usNCoils - 1) / 8 + 1); BYTE ucStatus = 0; BYTE usRegCoilsValue; BYTE ucBits = 0; BYTE ucDisp = 0; int iRegIndex = usAddress - 0; int uid; uid = pItem->GetUnitID(); if ((usAddress >= 0) && (usAddress + usNCoils <= 0 + pItem->m_YXRegCount)) { iRegIndex = (int)(usAddress - 0); switch (eMode) { /* Pass current register values to the protocol stack. */ case MB_REG_READ: while (usCoilGroups--) { ucDisp = 0; ucBits = 8; ucStatus = 0; while((usNCoils--) != 0 && (ucBits--) != 0) { ucStatus |= (pItem->m_pYXRegTab[iRegIndex++] << (ucDisp++)); } *pucRegBuffer++ = ucStatus; } break; /* Update current register values with new values from the * protocol stack. */ case MB_REG_WRITE: while (usCoilGroups--) { ucStatus = *pucRegBuffer++; ucBits = 8; while ((usNCoils--) != 0 && (ucBits--) != 0) { usRegCoilsValue = ucStatus & 0X01; //写线圈 SetUnitYK(uid, iRegIndex, usRegCoilsValue, YKS_SELREQ, YKR_IDLE); vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is YKS_EXEREQ result is YKR_IDLE.\n", uid, iRegIndex, (usRegCoilsValue ? "CLOSE" : "TRIP")); iRegIndex++; ucStatus >>= 1; } } } } else { eStatus = MB_ENOREG; } return eStatus; } eMBErrorCode CSubModbusRtuProcess::eMBRegDiscreteCB(CSubModbusRtuProcessItem *pItem, BYTE* pucRegBuffer, WORD usAddress, WORD usNDiscrete) { eMBErrorCode eStatus = MB_ENOERR; WORD usDiscreteGroups = ((usNDiscrete - 1) / 8 + 1); BYTE ucStatus = 0; BYTE ucBits = 0; BYTE ucDisp = 0; int iRegIndex = usAddress - 0; if ((usAddress >= 0) && (usAddress + usNDiscrete <= 0 + pItem->m_YXRegCount)) { iRegIndex = (int)(usAddress - 0); while (usDiscreteGroups--) { ucDisp = 0; ucBits = 8; ucStatus = 0; while((usNDiscrete--) != 0 && (ucBits--) != 0) { ucStatus |= (pItem->m_pYXRegTab[iRegIndex++] << (ucDisp++)); } *pucRegBuffer++ = ucStatus; } } else { eStatus = MB_ENOREG; } return eStatus; }