799 lines
23 KiB
C
799 lines
23 KiB
C
/****************************************************************************
|
|
文件名称 : chrg_comm.c
|
|
完成日期 :
|
|
当前版本号 : V1.0
|
|
主要功能 : 实现对外通讯协议 MODBUS 服务端,以独立线程等待处理响应请求数据。
|
|
版本历史 : 创建原始版本
|
|
说明 :
|
|
******************************************************************************/
|
|
|
|
#include <string.h>
|
|
#include <rtthread.h>
|
|
|
|
#include "chrg_comm.h"
|
|
#include "chrg_utils.h"
|
|
|
|
|
|
#define LOG_TAG "chrg.comm"
|
|
#define DBG_LEVEL DBG_LOG
|
|
#include <rtdbg.h>
|
|
|
|
rt_uint16_t usSDiscInStart = S_DISCRETE_INPUT_START;
|
|
rt_uint8_t ucSDiscInBuf[(S_DISCRETE_INPUT_NDISCRETES+BITS_UCHAR-1)/BITS_UCHAR];
|
|
|
|
rt_uint16_t usSCoilStart = S_COIL_START;
|
|
rt_uint8_t ucSCoilBuf[(S_COIL_NCOILS+BITS_UCHAR-1)/BITS_UCHAR];
|
|
|
|
rt_uint16_t usSRegInStart = S_REG_INPUT_START;
|
|
rt_uint16_t usSRegInBuf[S_REG_INPUT_NREGS];
|
|
|
|
rt_uint16_t usSRegHoldStart = S_REG_HOLDING_START;
|
|
rt_uint16_t usSRegHoldBuf[S_REG_HOLDING_NREGS];
|
|
|
|
|
|
|
|
struct chrg_comm_t chrgcomm = {
|
|
.devname = DEV_NAME_COMM,
|
|
.tty = RT_NULL,
|
|
.rx_len = 0,
|
|
.tx_len = 0,
|
|
.addr = MODBUS_ADDRESS_DEFAULT,
|
|
|
|
};
|
|
|
|
|
|
/*! \brief Function to set bits in a byte buffer.
|
|
*
|
|
* This function allows the efficient use of an array to implement bitfields.
|
|
* The array used for storing the bits must always be a multiple of two
|
|
* bytes. Up to eight bits can be set or cleared in one operation.
|
|
*
|
|
* \param ucByteBuf A buffer where the bit values are stored. Must be a
|
|
* multiple of 2 bytes. No length checking is performed and if
|
|
* usBitOffset / 8 is greater than the size of the buffer memory contents
|
|
* is overwritten.
|
|
* \param usBitOffset The starting address of the bits to set. The first
|
|
* bit has the offset 0.
|
|
* \param ucNBits Number of bits to modify. The value must always be smaller
|
|
* than 8.
|
|
* \param ucValues Thew new values for the bits. The value for the first bit
|
|
* starting at <code>usBitOffset</code> is the LSB of the value
|
|
* <code>ucValues</code>
|
|
*
|
|
* \code
|
|
* ucBits[2] = {0, 0};
|
|
*
|
|
* // Set bit 4 to 1 (read: set 1 bit starting at bit offset 4 to value 1)
|
|
* mb_set_bits( ucBits, 4, 1, 1 );
|
|
*
|
|
* // Set bit 7 to 1 and bit 8 to 0.
|
|
* mb_set_bits( ucBits, 7, 2, 0x01 );
|
|
*
|
|
* // Set bits 8 - 11 to 0x05 and bits 12 - 15 to 0x0A;
|
|
* mb_set_bits( ucBits, 8, 8, 0x5A);
|
|
* \endcode
|
|
*/
|
|
void mb_set_bits (rt_uint8_t *ucByteBuf, rt_uint16_t usBitOffset,
|
|
rt_uint8_t ucNBits, rt_uint8_t ucValue)
|
|
{
|
|
rt_uint16_t usWordBuf;
|
|
rt_uint16_t usMask;
|
|
rt_uint16_t usByteOffset;
|
|
rt_uint16_t usNPreBits;
|
|
rt_uint16_t usValue = ucValue;
|
|
|
|
RT_ASSERT(ucNBits <= BITS_UCHAR);
|
|
RT_ASSERT((size_t)BITS_UCHAR == sizeof(rt_uint8_t) * 8);
|
|
|
|
/* Calculate byte offset for first byte containing the bit values starting
|
|
* at usBitOffset. */
|
|
usByteOffset = (rt_uint16_t)((usBitOffset) / BITS_UCHAR);
|
|
|
|
/* How many bits precede our bits to set. */
|
|
usNPreBits = (rt_uint16_t)(usBitOffset - usByteOffset * BITS_UCHAR);
|
|
|
|
/* Move bit field into position over bits to set */
|
|
usValue <<= usNPreBits;
|
|
|
|
/* Prepare a mask for setting the new bits. */
|
|
usMask = (rt_uint16_t)((1 << (rt_uint16_t)ucNBits) - 1);
|
|
usMask <<= usBitOffset - usByteOffset * BITS_UCHAR;
|
|
|
|
/* copy bits into temporary storage. */
|
|
usWordBuf = ucByteBuf[usByteOffset];
|
|
usWordBuf |= ucByteBuf[usByteOffset + 1] << BITS_UCHAR;
|
|
|
|
/* Zero out bit field bits and then or value bits into them. */
|
|
usWordBuf = (rt_uint16_t)((usWordBuf & (~usMask)) | usValue);
|
|
|
|
/* move bits back into storage */
|
|
ucByteBuf[usByteOffset] = (rt_uint8_t)(usWordBuf & 0xFF);
|
|
ucByteBuf[usByteOffset + 1] = (rt_uint8_t)(usWordBuf >> BITS_UCHAR);
|
|
}
|
|
|
|
/*! \brief Function to read bits in a byte buffer.
|
|
*
|
|
* This function is used to extract up bit values from an array. Up to eight
|
|
* bit values can be extracted in one step.
|
|
*
|
|
* \param ucByteBuf A buffer where the bit values are stored.
|
|
* \param usBitOffset The starting address of the bits to set. The first
|
|
* bit has the offset 0.
|
|
* \param ucNBits Number of bits to modify. The value must always be smaller
|
|
* than 8.
|
|
*
|
|
* \code
|
|
* rt_uint8_t ucBits[2] = {0, 0};
|
|
* rt_uint8_t ucResult;
|
|
*
|
|
* // Extract the bits 3 - 10.
|
|
* ucResult = mb_get_bits( ucBits, 3, 8 );
|
|
* \endcode
|
|
*/
|
|
rt_uint8_t mb_get_bits (rt_uint8_t * ucByteBuf, rt_uint16_t usBitOffset, rt_uint8_t ucNBits)
|
|
{
|
|
rt_uint16_t usWordBuf;
|
|
rt_uint16_t usMask;
|
|
rt_uint16_t usByteOffset;
|
|
rt_uint16_t usNPreBits;
|
|
|
|
/* Calculate byte offset for first byte containing the bit values starting
|
|
* at usBitOffset. */
|
|
usByteOffset = (rt_uint16_t)((usBitOffset) / BITS_UCHAR);
|
|
|
|
/* How many bits precede our bits to set. */
|
|
usNPreBits = (rt_uint16_t)(usBitOffset - usByteOffset * BITS_UCHAR);
|
|
|
|
/* Prepare a mask for setting the new bits. */
|
|
usMask = (rt_uint16_t)((1 << (rt_uint16_t)ucNBits) - 1);
|
|
|
|
/* copy bits into temporary storage. */
|
|
usWordBuf = ucByteBuf[usByteOffset];
|
|
usWordBuf |= ucByteBuf[usByteOffset + 1] << BITS_UCHAR;
|
|
|
|
/* throw away unneeded bits. */
|
|
usWordBuf >>= usNPreBits;
|
|
|
|
/* mask away bits above the requested bitfield. */
|
|
usWordBuf &= usMask;
|
|
|
|
return (rt_uint8_t)usWordBuf;
|
|
}
|
|
|
|
static eMBException mb_error (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;
|
|
}
|
|
|
|
|
|
eMBErrorCode mb_reg_input_cb (rt_uint8_t *pucRegBuffer, rt_uint16_t usAddress, rt_uint16_t usNRegs)
|
|
{
|
|
eMBErrorCode eStatus = MB_ENOERR;
|
|
rt_uint16_t iRegIndex;
|
|
rt_uint16_t *pusRegInputBuf = usSRegInBuf;
|
|
rt_uint16_t REG_INPUT_START = S_REG_INPUT_START;
|
|
rt_uint16_t REG_INPUT_NREGS = S_REG_INPUT_NREGS;
|
|
rt_uint16_t usRegInStart = usSRegInStart;
|
|
|
|
if ((usAddress >= REG_INPUT_START)
|
|
&& (usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS)) {
|
|
iRegIndex = usAddress - usRegInStart;
|
|
while (usNRegs > 0) {
|
|
*pucRegBuffer++ = (rt_uint8_t)(pusRegInputBuf[iRegIndex] >> BITS_UCHAR);
|
|
*pucRegBuffer++ = (rt_uint8_t)(pusRegInputBuf[iRegIndex] & 0xFF);
|
|
iRegIndex++;
|
|
usNRegs--;
|
|
}
|
|
} else {
|
|
eStatus = MB_ENOREG;
|
|
}
|
|
|
|
return eStatus;
|
|
}
|
|
|
|
eMBErrorCode mb_reg_holding_cb (rt_uint8_t *req, rt_uint8_t *pucRegBuffer, rt_uint16_t usAddress,
|
|
rt_uint16_t usNRegs, eMBRegisterMode eMode)
|
|
{
|
|
eMBErrorCode eStatus = MB_ENOERR;
|
|
rt_uint16_t iRegIndex;
|
|
rt_uint16_t *pusRegHoldingBuf = usSRegHoldBuf;
|
|
rt_uint16_t REG_HOLDING_START = S_REG_HOLDING_START;
|
|
rt_uint16_t REG_HOLDING_NREGS = S_REG_HOLDING_NREGS;
|
|
rt_uint16_t usRegHoldStart = usSRegHoldStart;
|
|
|
|
if ((usAddress >= REG_HOLDING_START)
|
|
&& (usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS)) {
|
|
iRegIndex = usAddress - usRegHoldStart;
|
|
switch (eMode) {
|
|
/* read current register values from the protocol stack. */
|
|
case MB_REG_READ:
|
|
while (usNRegs > 0) {
|
|
*pucRegBuffer++ = (rt_uint8_t)(pusRegHoldingBuf[iRegIndex] >> BITS_UCHAR);
|
|
*pucRegBuffer++ = (rt_uint8_t)(pusRegHoldingBuf[iRegIndex] & 0xFF);
|
|
iRegIndex++;
|
|
usNRegs--;
|
|
}
|
|
break;
|
|
|
|
/* write current register values with new values from the protocol stack. */
|
|
case MB_REG_WRITE:
|
|
while (usNRegs > 0) {
|
|
pusRegHoldingBuf[iRegIndex] = *req++ << BITS_UCHAR;
|
|
pusRegHoldingBuf[iRegIndex] |= *req++;
|
|
iRegIndex++;
|
|
usNRegs--;
|
|
}
|
|
break;
|
|
}
|
|
} else {
|
|
eStatus = MB_ENOREG;
|
|
}
|
|
|
|
return eStatus;
|
|
}
|
|
|
|
eMBErrorCode mb_reg_coils_cb (rt_uint8_t *req, rt_uint8_t *pucRegBuffer, rt_uint16_t usAddress,
|
|
rt_uint16_t usNCoils, eMBRegisterMode eMode)
|
|
{
|
|
eMBErrorCode eStatus = MB_ENOERR;
|
|
rt_uint16_t iRegIndex = 0, iRegBitIndex = 0, iNReg = 0;
|
|
rt_uint8_t *pucCoilBuf = ucSCoilBuf;
|
|
rt_uint16_t COIL_START = S_COIL_START;
|
|
rt_uint16_t COIL_NCOILS = S_COIL_NCOILS;
|
|
rt_uint16_t usCoilStart = usSCoilStart;
|
|
|
|
iNReg = (usNCoils+BITS_UCHAR-1)/BITS_UCHAR;
|
|
|
|
if ((usAddress >= COIL_START) && (usAddress + usNCoils <= COIL_START + COIL_NCOILS)) {
|
|
iRegIndex = (rt_uint16_t)(usAddress - usCoilStart) / BITS_UCHAR;
|
|
iRegBitIndex = (rt_uint16_t)(usAddress - usCoilStart) % BITS_UCHAR;
|
|
switch (eMode) {
|
|
/* read current coil values from the protocol stack. */
|
|
case MB_REG_READ:
|
|
while (iNReg > 0) {
|
|
*pucRegBuffer++ = mb_get_bits(&pucCoilBuf[iRegIndex++], iRegBitIndex, BITS_UCHAR);
|
|
iNReg--;
|
|
}
|
|
pucRegBuffer--;
|
|
/* last coils */
|
|
usNCoils = usNCoils % BITS_UCHAR;
|
|
/* filling zero to high bit */
|
|
*pucRegBuffer = *pucRegBuffer << (BITS_UCHAR - usNCoils);
|
|
*pucRegBuffer = *pucRegBuffer >> (BITS_UCHAR - usNCoils);
|
|
break;
|
|
|
|
/* write current coil values with new values from the protocol stack. */
|
|
case MB_REG_WRITE:
|
|
while (iNReg > 1) {
|
|
mb_set_bits(&pucCoilBuf[iRegIndex++], iRegBitIndex, BITS_UCHAR, *req++);
|
|
iNReg--;
|
|
}
|
|
/* last coils */
|
|
usNCoils = usNCoils % BITS_UCHAR;
|
|
/* mb_set_bits has bug when ucNBits is zero */
|
|
if (usNCoils != 0) {
|
|
mb_set_bits(&pucCoilBuf[iRegIndex++], iRegBitIndex, usNCoils, *req++);
|
|
}
|
|
break;
|
|
}
|
|
} else {
|
|
eStatus = MB_ENOREG;
|
|
}
|
|
|
|
return eStatus;
|
|
}
|
|
|
|
eMBErrorCode mb_reg_discrete_cb (rt_uint8_t *pucRegBuffer, rt_uint16_t usAddress, rt_uint16_t usNDiscrete)
|
|
{
|
|
eMBErrorCode eStatus = MB_ENOERR;
|
|
rt_uint16_t iRegIndex , iRegBitIndex , iNReg;
|
|
rt_uint8_t *pucDiscreteInputBuf = ucSDiscInBuf;
|
|
rt_uint16_t DISCRETE_INPUT_START = S_DISCRETE_INPUT_START;
|
|
rt_uint16_t DISCRETE_INPUT_NDISCRETES = S_DISCRETE_INPUT_NDISCRETES;
|
|
rt_uint16_t usDiscreteInputStart = usSDiscInStart;
|
|
iNReg = (usNDiscrete+BITS_UCHAR-1) / BITS_UCHAR;
|
|
|
|
if ((usAddress >= DISCRETE_INPUT_START)
|
|
&& ((usAddress + usNDiscrete) <= (DISCRETE_INPUT_START + DISCRETE_INPUT_NDISCRETES))) {
|
|
iRegIndex = (rt_uint16_t) (usAddress - usDiscreteInputStart) / BITS_UCHAR;
|
|
iRegBitIndex = (rt_uint16_t) (usAddress - usDiscreteInputStart) % BITS_UCHAR;
|
|
|
|
while (iNReg > 0) {
|
|
*pucRegBuffer++ = mb_get_bits(&pucDiscreteInputBuf[iRegIndex++], iRegBitIndex, BITS_UCHAR);
|
|
iNReg--;
|
|
}
|
|
pucRegBuffer--;
|
|
/* last discrete */
|
|
usNDiscrete = usNDiscrete % BITS_UCHAR;
|
|
/* filling zero to high bit */
|
|
*pucRegBuffer = *pucRegBuffer << (BITS_UCHAR - usNDiscrete);
|
|
*pucRegBuffer = *pucRegBuffer >> (BITS_UCHAR - usNDiscrete);
|
|
} else {
|
|
eStatus = MB_ENOREG;
|
|
}
|
|
|
|
return eStatus;
|
|
}
|
|
|
|
/*****************************************************************
|
|
函数名称: funcReadCoils
|
|
函数描述: 读多个继电器
|
|
输入参数: reqFrame: 请求数据 reqLen: 请求长度 resFrame:响应数据 resLen:响应长度
|
|
输出参数: -
|
|
返回说明: -
|
|
其它说明: -
|
|
*****************************************************************/
|
|
eMBException funcReadCoils (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
|
|
rt_uint8_t *resFrame, rt_uint16_t *resLen)
|
|
{
|
|
rt_uint16_t regAddress = 0, cntCoils = 0;
|
|
rt_uint8_t ucNBytes = 0;
|
|
eMBException eStatus = MB_EX_NONE;
|
|
eMBErrorCode eRegStatus;
|
|
|
|
if (4+MB_PDU_FUNC_READ_SIZE != reqLen) {
|
|
return MB_EX_ILLEGAL_DATA_VALUE;
|
|
}
|
|
|
|
regAddress = u8v_to_u16(&reqFrame[2]);
|
|
cntCoils = u8v_to_u16(&reqFrame[4]);
|
|
|
|
if ((0 == cntCoils)||(cntCoils >= MB_PDU_FUNC_READ_COILCNT_MAX)) {
|
|
return MB_EX_ILLEGAL_DATA_VALUE;
|
|
}
|
|
|
|
ucNBytes = (cntCoils+BITS_UCHAR-1)/BITS_UCHAR;
|
|
|
|
resFrame[1] = MB_READ_COILS;
|
|
resFrame[2] = ucNBytes;
|
|
eRegStatus = mb_reg_coils_cb(RT_NULL, &resFrame[3], regAddress, cntCoils, MB_REG_READ);
|
|
if (eRegStatus != MB_ENOERR) {
|
|
eStatus = mb_error(eRegStatus);
|
|
} else {
|
|
*resLen = 3+ucNBytes;
|
|
}
|
|
|
|
return eStatus;
|
|
}
|
|
|
|
/*****************************************************************
|
|
函数名称: funcReadDiscreteInputs
|
|
函数描述: 读离散输入
|
|
输入参数: reqFrame: 请求数据 reqLen: 请求长度 resFrame:响应数据 resLen:响应长度
|
|
输出参数: -
|
|
返回说明: -
|
|
其它说明: -
|
|
*****************************************************************/
|
|
eMBException funcReadDiscreteInputs (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
|
|
rt_uint8_t *resFrame, rt_uint16_t *resLen)
|
|
{
|
|
rt_uint16_t regAddress = 0, cntDisCrete = 0;
|
|
rt_uint8_t ucNBytes = 0;
|
|
eMBException eStatus = MB_EX_NONE;
|
|
eMBErrorCode eRegStatus;
|
|
|
|
if (4+MB_PDU_FUNC_READ_SIZE != reqLen) {
|
|
return MB_EX_ILLEGAL_DATA_VALUE;
|
|
}
|
|
|
|
regAddress = u8v_to_u16(&reqFrame[2]);
|
|
cntDisCrete = u8v_to_u16(&reqFrame[4]);
|
|
|
|
if ((0 == cntDisCrete)||(cntDisCrete >= MB_PDU_FUNC_READ_DISCCNT_MAX)) {
|
|
return MB_EX_ILLEGAL_DATA_VALUE;
|
|
}
|
|
|
|
ucNBytes = (cntDisCrete+BITS_UCHAR-1)/BITS_UCHAR;
|
|
|
|
resFrame[1] = MB_READ_DISCRETE_INPUTS;
|
|
resFrame[2] = ucNBytes;
|
|
eRegStatus = mb_reg_discrete_cb(&resFrame[3], regAddress, cntDisCrete);
|
|
if (eRegStatus != MB_ENOERR) {
|
|
eStatus = mb_error(eRegStatus);
|
|
} else {
|
|
*resLen = 3+ucNBytes;
|
|
}
|
|
|
|
return eStatus;
|
|
}
|
|
|
|
/*****************************************************************
|
|
函数名称: funcReadHoldingRegister
|
|
函数描述: 读保持寄存器
|
|
输入参数: reqFrame: 请求数据 reqLen: 请求长度 resFrame:响应数据 resLen:响应长度
|
|
输出参数: -
|
|
返回说明: -
|
|
其它说明: -
|
|
*****************************************************************/
|
|
eMBException funcReadHoldingRegister (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
|
|
rt_uint8_t *resFrame, rt_uint16_t *resLen)
|
|
{
|
|
rt_uint16_t regAddress = 0, cntReg = 0;
|
|
|
|
eMBException eStatus = MB_EX_NONE;
|
|
eMBErrorCode eRegStatus;
|
|
|
|
if (4+MB_PDU_FUNC_READ_SIZE != reqLen) {
|
|
return MB_EX_ILLEGAL_DATA_VALUE;
|
|
}
|
|
|
|
regAddress = u8v_to_u16(&reqFrame[2]);
|
|
cntReg = u8v_to_u16(&reqFrame[4]);
|
|
|
|
if ((0 == cntReg)||(cntReg >= MB_PDU_FUNC_READ_REGCNT_MAX)) {
|
|
return MB_EX_ILLEGAL_DATA_VALUE;
|
|
}
|
|
|
|
resFrame[1] = MB_READ_HOLDING_REGISTER;
|
|
resFrame[2] = cntReg * 2;
|
|
|
|
eRegStatus = mb_reg_holding_cb(RT_NULL, &resFrame[3], regAddress, cntReg, MB_REG_READ);
|
|
if (eRegStatus != MB_ENOERR) {
|
|
eStatus = mb_error(eRegStatus);
|
|
} else {
|
|
*resLen = 3+cntReg * 2;
|
|
}
|
|
|
|
return eStatus;
|
|
}
|
|
|
|
/*****************************************************************
|
|
函数名称: funcReadInputRegister
|
|
函数描述: 读输入寄存器
|
|
输入参数: reqFrame: 请求数据 reqLen: 请求长度 resFrame:响应数据 resLen:响应长度
|
|
输出参数: -
|
|
返回说明: -
|
|
其它说明: -
|
|
*****************************************************************/
|
|
eMBException funcReadInputRegister (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
|
|
rt_uint8_t *resFrame, rt_uint16_t *resLen)
|
|
{
|
|
rt_uint16_t regAddress = 0, cntReg = 0;
|
|
|
|
eMBException eStatus = MB_EX_NONE;
|
|
eMBErrorCode eRegStatus;
|
|
|
|
if (4+MB_PDU_FUNC_READ_SIZE != reqLen) {
|
|
return MB_EX_ILLEGAL_DATA_VALUE;
|
|
}
|
|
|
|
regAddress = u8v_to_u16(&reqFrame[2]);
|
|
cntReg = u8v_to_u16(&reqFrame[4]);
|
|
|
|
if ((0 == cntReg)||(cntReg >= MB_PDU_FUNC_READ_REGCNT_MAX)) {
|
|
return MB_EX_ILLEGAL_DATA_VALUE;
|
|
}
|
|
|
|
resFrame[1] = MB_READ_INPUT_REGISTER;
|
|
resFrame[2] = cntReg * 2;
|
|
|
|
eRegStatus = mb_reg_discrete_cb(&resFrame[3], regAddress, cntReg);
|
|
if (eRegStatus != MB_ENOERR) {
|
|
eStatus = mb_error(eRegStatus);
|
|
} else {
|
|
*resLen = 3+cntReg*2;
|
|
}
|
|
|
|
return eStatus;
|
|
}
|
|
|
|
/*****************************************************************
|
|
函数名称: funcWriteCoil
|
|
函数描述: 写单个保持继电器
|
|
输入参数: reqFrame: 请求数据 reqLen: 请求长度 resFrame:响应数据 resLen:响应长度
|
|
输出参数: -
|
|
返回说明: -
|
|
其它说明: -
|
|
*****************************************************************/
|
|
eMBException funcWriteCoil (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
|
|
rt_uint8_t *resFrame, rt_uint16_t *resLen)
|
|
{
|
|
rt_uint16_t regAddress = 0, value = 0;
|
|
rt_uint8_t ucBuf[2] = {0};
|
|
|
|
eMBException eStatus = MB_EX_NONE;
|
|
eMBErrorCode eRegStatus;
|
|
|
|
if (4+MB_PDU_FUNC_WRITE_SIZE != reqLen) {
|
|
return MB_EX_ILLEGAL_DATA_VALUE;
|
|
}
|
|
|
|
regAddress = u8v_to_u16(&reqFrame[2]);
|
|
value = u8v_to_u16(&reqFrame[4]);
|
|
|
|
if (0x0000 == value) {
|
|
ucBuf[0] = 0;
|
|
ucBuf[1] = 0;
|
|
} else if (0xFF00 == value) {
|
|
ucBuf[0] = 1;
|
|
ucBuf[1] = 0;
|
|
} else {
|
|
return MB_EX_ILLEGAL_DATA_VALUE;
|
|
}
|
|
|
|
rt_memcpy(resFrame, reqFrame, reqLen);
|
|
*resLen = reqLen-2;
|
|
|
|
eRegStatus = mb_reg_coils_cb(RT_NULL, ucBuf, regAddress, 1, MB_REG_WRITE);
|
|
if (eRegStatus != MB_ENOERR) {
|
|
eStatus = mb_error(eRegStatus);
|
|
}
|
|
|
|
return eStatus;
|
|
}
|
|
|
|
/*****************************************************************
|
|
函数名称: funcWriteHoldingRegister
|
|
函数描述: 写多个保持继电器
|
|
输入参数: reqFrame: 请求数据 reqLen: 请求长度 resFrame:响应数据 resLen:响应长度
|
|
输出参数: -
|
|
返回说明: -
|
|
其它说明: -
|
|
*****************************************************************/
|
|
eMBException funcWriteHoldingRegister (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
|
|
rt_uint8_t *resFrame, rt_uint16_t *resLen)
|
|
{
|
|
rt_uint16_t regAddress = 0;
|
|
|
|
eMBException eStatus = MB_EX_NONE;
|
|
eMBErrorCode eRegStatus;
|
|
|
|
if (4+MB_PDU_FUNC_WRITE_SIZE != reqLen) {
|
|
return MB_EX_ILLEGAL_DATA_VALUE;
|
|
}
|
|
|
|
regAddress = u8v_to_u16(&reqFrame[2]);
|
|
|
|
rt_memcpy(resFrame, reqFrame, reqLen);
|
|
*resLen = reqLen-2;
|
|
|
|
eRegStatus = mb_reg_holding_cb(&reqFrame[4], &resFrame[3], regAddress, 1, MB_REG_WRITE);
|
|
if (eRegStatus != MB_ENOERR) {
|
|
eStatus = mb_error(eRegStatus);
|
|
}
|
|
|
|
return eStatus;
|
|
}
|
|
|
|
/*****************************************************************
|
|
函数名称: funcWriteMultipleCoils
|
|
函数描述: 写多个继电器
|
|
输入参数: reqFrame: 请求数据 reqLen: 请求长度 resFrame:响应数据 resLen:响应长度
|
|
输出参数: -
|
|
返回说明: -
|
|
其它说明: -
|
|
*****************************************************************/
|
|
eMBException funcWriteMultipleCoils (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
|
|
rt_uint8_t *resFrame, rt_uint16_t *resLen)
|
|
{
|
|
rt_uint16_t regAddress = 0, cntCoils = 0;
|
|
rt_uint8_t ucByteCount;
|
|
rt_uint8_t ucByteCountVerify;
|
|
|
|
eMBException eStatus = MB_EX_NONE;
|
|
eMBErrorCode eRegStatus;
|
|
|
|
if (4+MB_PDU_FUNC_WRITE_SIZE > reqLen) {
|
|
return MB_EX_ILLEGAL_DATA_VALUE;
|
|
}
|
|
|
|
regAddress = u8v_to_u16(&reqFrame[2]);
|
|
cntCoils = u8v_to_u16(&reqFrame[4]);
|
|
ucByteCount = reqFrame[6];
|
|
ucByteCountVerify = (cntCoils+BITS_UCHAR-1)/BITS_UCHAR;
|
|
|
|
if ((0 == cntCoils)
|
|
||(cntCoils > MB_PDU_FUNC_WRITE_MUL_COILCNT_MAX)
|
|
||(ucByteCountVerify != ucByteCount)) {
|
|
return MB_EX_ILLEGAL_DATA_VALUE;
|
|
}
|
|
|
|
rt_memcpy(resFrame, reqFrame, reqLen);
|
|
*resLen = 6;
|
|
|
|
eRegStatus = mb_reg_coils_cb(reqFrame, &resFrame[3], regAddress, cntCoils, MB_REG_WRITE);
|
|
if (eRegStatus != MB_ENOERR) {
|
|
eStatus = mb_error(eRegStatus);
|
|
}
|
|
|
|
return eStatus;
|
|
}
|
|
|
|
/*****************************************************************
|
|
函数名称: funcWriteMultipleHoldingRegister
|
|
函数描述: 写多个寄存器
|
|
输入参数: reqFrame: 请求数据 reqLen: 请求长度 resFrame:响应数据 resLen:响应长度
|
|
输出参数: -
|
|
返回说明: -
|
|
其它说明: -
|
|
*****************************************************************/
|
|
eMBException funcWriteMultipleHoldingRegister (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
|
|
rt_uint8_t *resFrame, rt_uint16_t *resLen)
|
|
{
|
|
rt_uint16_t regAddress = 0, cntReg = 0;
|
|
rt_uint8_t ucRegByteCount;
|
|
|
|
eMBException eStatus = MB_EX_NONE;
|
|
eMBErrorCode eRegStatus;
|
|
|
|
if (4+MB_PDU_FUNC_WRITE_MUL_SIZE_MIN > reqLen) {
|
|
return MB_EX_ILLEGAL_DATA_VALUE;
|
|
}
|
|
|
|
regAddress = u8v_to_u16(&reqFrame[2]);
|
|
cntReg = u8v_to_u16(&reqFrame[4]);
|
|
ucRegByteCount = reqFrame[6];
|
|
|
|
if ((0 == cntReg)
|
|
||(cntReg > MB_PDU_FUNC_WRITE_MUL_COILCNT_MAX)
|
|
||(ucRegByteCount != cntReg*2)) {
|
|
return MB_EX_ILLEGAL_DATA_VALUE;
|
|
}
|
|
|
|
rt_memcpy(resFrame, reqFrame, reqLen);
|
|
*resLen = 6;
|
|
|
|
eRegStatus = mb_reg_holding_cb(reqFrame, &resFrame[3], regAddress, cntReg, MB_REG_WRITE);
|
|
if (eRegStatus != MB_ENOERR) {
|
|
eStatus = mb_error(eRegStatus);
|
|
}
|
|
|
|
return eStatus;
|
|
}
|
|
|
|
|
|
|
|
static struct code_func_t funcHandlers[MB_HANDLERS_MAX] = {
|
|
{MB_READ_COILS, funcReadCoils},
|
|
{MB_READ_DISCRETE_INPUTS, funcReadDiscreteInputs},
|
|
{MB_READ_HOLDING_REGISTER, funcReadHoldingRegister},
|
|
{MB_READ_INPUT_REGISTER, funcReadInputRegister},
|
|
{MB_WRITE_SINGLE_COIL, funcWriteCoil},
|
|
{MB_WRITE_REGISTER, funcWriteHoldingRegister},
|
|
{MB_WRITE_MULTIPLE_COILS, funcWriteMultipleCoils},
|
|
{MB_WRITE_MULTIPLE_REGISTERS, funcWriteMultipleHoldingRegister},
|
|
};
|
|
|
|
/*****************************************************************
|
|
函数名称: chrg_comm_parse_msg
|
|
函数描述: 解析请求的消息
|
|
输入参数: pCOMM: 消息结构
|
|
输出参数: -
|
|
返回说明: -
|
|
其它说明: 分命令处理对应消息。地址为广播时不应答
|
|
*****************************************************************/
|
|
static int chrg_comm_parse_msg (struct chrg_comm_t *pCOMM)
|
|
{
|
|
if (RT_NULL == pCOMM) {
|
|
return -1;
|
|
}
|
|
|
|
if (pCOMM->rx_len < 8) {
|
|
return -2;
|
|
}
|
|
|
|
if (0 != mb_crc16(pCOMM->rx_buf, pCOMM->rx_len)) {
|
|
rt_kprintf("crc %04X ", mb_crc16(pCOMM->rx_buf, pCOMM->rx_len-2));
|
|
return -3;
|
|
}
|
|
|
|
int i = 0, ret = -1;
|
|
rt_uint16_t crc = 0;
|
|
eMBException eStatus = MB_EX_ILLEGAL_FUNCTION;
|
|
rt_uint8_t address = 0, functionCode = 0x00;
|
|
address = pCOMM->rx_buf[0];
|
|
functionCode = pCOMM->rx_buf[1];
|
|
|
|
if ((address != pCOMM->addr)&&(MB_ADDRESS_BROADCAST != address)) {
|
|
return ret;
|
|
}
|
|
|
|
struct code_func_t *pFunc = RT_NULL;
|
|
for (i = 0; i < MB_HANDLERS_MAX; i++) {
|
|
pFunc = &funcHandlers[i];
|
|
if (RT_NULL == pFunc) {
|
|
break;
|
|
}
|
|
|
|
if ((functionCode == pFunc->code)&&(RT_NULL != pFunc->func)) {
|
|
eStatus = pFunc->func(pCOMM->rx_buf, pCOMM->rx_len,
|
|
pCOMM->tx_buf, &pCOMM->tx_len);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (MB_ADDRESS_BROADCAST != address) {
|
|
pCOMM->tx_buf[0] = address;
|
|
if (MB_EX_NONE != eStatus) {
|
|
pCOMM->tx_buf[1] = (functionCode | MB_FUNC_ERROR);
|
|
pCOMM->tx_buf[2] = eStatus;
|
|
pCOMM->tx_len = 3;
|
|
}
|
|
|
|
crc = mb_crc16(pCOMM->tx_buf, pCOMM->tx_len);
|
|
u16_to_u8v(crc, &pCOMM->tx_buf[pCOMM->tx_len]);
|
|
pCOMM->tx_len += 2;
|
|
|
|
ret = chrg_tty_send(pCOMM->tty, pCOMM->tx_buf, pCOMM->tx_len);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*****************************************************************
|
|
函数名称: chrg_comm_thread_entry
|
|
函数描述: 对外RS485通信线程体
|
|
输入参数: *data: 本线程信息
|
|
输出参数: -
|
|
返回说明: -
|
|
其它说明: -
|
|
*****************************************************************/
|
|
void chrg_comm_thread_entry (void *data)
|
|
{
|
|
struct chrg_thread_t *pTHR = (struct chrg_thread_t *)data;
|
|
|
|
if (RT_NULL == pTHR) {
|
|
return ;
|
|
}
|
|
|
|
int len = 0;
|
|
struct chrg_tty_t *pTTY = RT_NULL;
|
|
struct chrg_comm_t *pCOMM = &chrgcomm;
|
|
|
|
pTTY = chrg_tty_create(pCOMM->devname, BAUD_RATE_115200, 0, 8, 1);
|
|
if (RT_NULL == pTTY) {
|
|
LOG_E("tty can't create.");
|
|
return ;
|
|
}
|
|
|
|
chrg_tty_set_recv_tmo(pTTY, 8);
|
|
if (chrg_tty_connect(pTTY) != RT_EOK) {
|
|
chrg_tty_destory(pTTY);
|
|
return;
|
|
}
|
|
chrg_tty_mode_set(pTTY, 0);
|
|
|
|
pCOMM->tty = pTTY;
|
|
|
|
while (1) {
|
|
rt_memset(pCOMM->rx_buf, 0, sizeof(pCOMM->rx_buf));
|
|
len = chrg_tty_recv(pTTY, pCOMM->rx_buf, sizeof(pCOMM->rx_buf));
|
|
if (len <= 0) {
|
|
rt_thread_mdelay(1);
|
|
continue;
|
|
}
|
|
|
|
pCOMM->rx_len = len;
|
|
pCOMM->tx_len = 0;
|
|
chrg_comm_parse_msg(pCOMM);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|