Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Modbus function 0x2B/0E Read DeviceIdentifiers, add get/set SlaveID, get/set ResponseTimeout, get . #185

Closed
wants to merge 7 commits into from
Prev Previous commit
Next Next commit
Add method to change/request (get/set) the SlaveID.
Add method to change/request (get/set) the ResponseTimeout.
Add method to request the response size of data in the response buffer.
Add Modbus function 0x2B/0E Read DeviceIdentifiers ku8MBReadDeviceIdentifiers.
  • Loading branch information
rob040 committed Feb 20, 2023
commit 3ef6b4482f7a3b001b9b8dd8b9c17cd299c5de78
116 changes: 114 additions & 2 deletions src/ModbusMaster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ ModbusMaster::ModbusMaster(void)
_idle = 0;
_preTransmission = 0;
_postTransmission = 0;
_u16ResponseTimeout = ku16MBDefaultResponseTimeout;
}

/**
Expand Down Expand Up @@ -183,6 +184,7 @@ void ModbusMaster::postTransmission(void (*postTransmission)())
Retrieve data from response buffer.

@see ModbusMaster::clearResponseBuffer()
@see ModbusMaster::getResponseSize()
@param u8Index index of response buffer array (0x00..0x3F)
@return value in position u8Index of response buffer (0x0000..0xFFFF)
@ingroup buffer
Expand All @@ -199,6 +201,17 @@ uint16_t ModbusMaster::getResponseBuffer(uint8_t u8Index)
}
}

/**
Get number of words in response buffer.

@see ModbusMaster::getResponseBuffer
@return value in position u8Index of response buffer (0x0000..0xFFFF)
@ingroup buffer
*/
uint8_t ModbusMaster::getResponseSize()
{
return _u8ResponseBufferLength;
}

/**
Clear Modbus response buffer.
Expand Down Expand Up @@ -254,6 +267,41 @@ void ModbusMaster::clearTransmitBuffer()
}
}

/**
* Set Modbus save id
* Change the slave id that is set with begin method.
* */
void ModbusMaster::setSlaveId(uint8_t slaveid)
{
_u8MBSlave = slaveid;
}

/**
* Get Modbus save id
* */
uint8_t ModbusMaster::getSlaveId(void)
{
return _u8MBSlave;
}


/**
Get the response timeout. Value is in ms.
*/
uint16_t ModbusMaster::getResponseTimeout()
{
return _u16ResponseTimeout;
}

/**
Sets the response timeout. Value should be given in ms.
The default is 2000 ms.
*/
void ModbusMaster::setResponseTimeout(uint16_t timeout)
{
_u16ResponseTimeout = timeout;
}


/**
Modbus function 0x01 Read Coils.
Expand Down Expand Up @@ -533,6 +581,18 @@ uint8_t ModbusMaster::readWriteMultipleRegisters(uint16_t u16ReadAddress,
return ModbusMasterTransaction(ku8MBReadWriteMultipleRegisters);
}

/*
* ku8MBReadDeviceIdentifiers = 0x2B/0E
*/
//uint8_t ModbusMaster::readDeviceIdentifiers(uint8_t ObjectId)
uint8_t ModbusMaster::readDeviceIdentifiers(uint8_t ReadId, uint8_t ObjectId, char *pu8ReadStrBuffer, uint8_t u8ReadStrBufferMaxSize, uint8_t *pu8ReadStrSize)
{
_u16ReadAddress = ((uint16_t)ReadId << 8) | ObjectId;
_pu8ReadStrBuffer = pu8ReadStrBuffer;
_u8ReadStrBufferMaxSize = u8ReadStrBufferMaxSize;
_pu8ReadStrSize = pu8ReadStrSize;
return ModbusMasterTransaction(ku8MBReadDeviceIdentifiers);
}

/* _____PRIVATE FUNCTIONS____________________________________________________ */
/**
Expand All @@ -553,6 +613,8 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction)
uint8_t u8ModbusADU[256];
uint8_t u8ModbusADUSize = 0;
uint8_t i, u8Qty;
uint8_t u8RDIobjcnt = 0;
uint8_t u8RDInextObjSzIdx = 255;
uint16_t u16CRC;
uint32_t u32StartTime;
uint8_t u8BytesLeft = 8;
Expand All @@ -574,6 +636,14 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction)
u8ModbusADU[u8ModbusADUSize++] = highByte(_u16ReadQty);
u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16ReadQty);
break;
case ku8MBReadDeviceIdentifiers:
//u8ModbusADUSize = 0;
//u8ModbusADU[u8ModbusADUSize++] = u8MBFunction;
u8ModbusADU[u8ModbusADUSize++] = 0x0E; // MEI type
u8ModbusADU[u8ModbusADUSize++] = highByte(_u16ReadAddress); // ReadId code
u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16ReadAddress); // ObjectId code
u8BytesLeft = 12;
break;
}

switch(u8MBFunction)
Expand Down Expand Up @@ -730,7 +800,7 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction)
}

// evaluate slave ID, function code once enough bytes have been read
if (u8ModbusADUSize == 5)
if ((u8ModbusADUSize == 5) && (u8ModbusADU[1] != ku8MBReadDeviceIdentifiers))
{
// verify response is for correct Modbus slave
if (u8ModbusADU[0] != _u8MBSlave)
Expand Down Expand Up @@ -774,9 +844,27 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction)
case ku8MBMaskWriteRegister:
u8BytesLeft = 5;
break;
break;
}
}
if (u8ModbusADU[1] == ku8MBReadDeviceIdentifiers) // function 2B-0E
{
if ((u8ModbusADUSize == 8) && (u8RDIobjcnt == 0))
{
u8RDIobjcnt = u8ModbusADU[7];
u8BytesLeft = u8RDIobjcnt * 2 + 2;
u8RDInextObjSzIdx = u8ModbusADUSize + 2;
}
if ((u8ModbusADUSize == u8RDInextObjSzIdx) && (u8RDIobjcnt != 0))
{
u8BytesLeft += u8ModbusADU[u8ModbusADUSize - 1];
if (--u8RDIobjcnt != 0)
{
u8RDInextObjSzIdx += u8ModbusADU[u8ModbusADUSize - 1] + 2;
}
}
}
if ((millis() - u32StartTime) > ku16MBResponseTimeout)
if ((millis() - u32StartTime) > _u16ResponseTimeout)
{
u8MBStatus = ku8MBResponseTimedOut;
}
Expand Down Expand Up @@ -878,6 +966,30 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction)
_u8ResponseBufferLength = i;
}
break;
case ku8MBReadDeviceIdentifiers:
// The payload data of this function is a linked list of mostly ascii strings
// Here we concatenate the passed device ID strings, separated by spaces, and return to the caller.
u8RDIobjcnt = u8ModbusADU[7];
u8RDInextObjSzIdx = 7 + 2;
*_pu8ReadStrSize = 0;
_u8ResponseBufferIndex = 0;
for (i = 0; i < u8RDIobjcnt; i++)
{
int len = u8ModbusADU[u8RDInextObjSzIdx];
if ((len > 2) && (_u8ResponseBufferIndex + len < _u8ReadStrBufferMaxSize))
{
if (_u8ResponseBufferIndex > 0)
{
_pu8ReadStrBuffer[_u8ResponseBufferIndex++] = ' ';
}
memcpy(_pu8ReadStrBuffer + _u8ResponseBufferIndex, u8ModbusADU + u8RDInextObjSzIdx + 1, len);
_u8ResponseBufferIndex += len;
_pu8ReadStrBuffer[_u8ResponseBufferIndex] = 0;
}
u8RDInextObjSzIdx += len + 2;
*_pu8ReadStrSize = _u8ResponseBufferIndex;
}
break;
}
}

Expand Down
15 changes: 14 additions & 1 deletion src/ModbusMaster.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,14 @@ class ModbusMaster
static const uint8_t ku8MBInvalidCRC = 0xE3;

uint16_t getResponseBuffer(uint8_t Index);
uint8_t getResponseSize(void);
void clearResponseBuffer(void);
uint8_t setTransmitBuffer(uint8_t Offset, uint16_t Value);
void clearTransmitBuffer(void);
void setSlaveId(uint8_t slaveid);
uint8_t getSlaveId(void);
uint16_t getResponseTimeout(void);
void setResponseTimeout(uint16_t timeout_ms);

void beginTransmission(uint16_t u16Address);
//uint8_t requestFrom(uint16_t Addr, uint16_t Qty);
Expand All @@ -258,6 +263,8 @@ class ModbusMaster
uint8_t maskWriteRegister(uint16_t u16WriteAddress, uint16_t u16AndMask, uint16_t u16OrMask);
uint8_t readWriteMultipleRegisters(uint16_t u16ReadAddress, uint16_t u16ReadQty, uint16_t u16WriteAddress, uint16_t u16WriteQty);
uint8_t readWriteMultipleRegisters(uint16_t Addr, uint16_t Qty);
//uint8_t readDeviceIdentifiers(uint8_t ReadId, uint8_t ObjectId);
uint8_t readDeviceIdentifiers(uint8_t ReadId, uint8_t ObjectId, char *pu8ReadStrBuffer, uint8_t u8ReadStrBufferMaxSize, uint8_t *pu8ReadStrSize);

private:
Stream* _serial; ///< reference to serial port object
Expand All @@ -273,6 +280,10 @@ class ModbusMaster
uint16_t u16TransmitBufferLength;
uint8_t _u8ResponseBufferIndex;
uint8_t _u8ResponseBufferLength;
char *_pu8ReadStrBuffer;
uint8_t _u8ReadStrBufferMaxSize;
uint8_t *_pu8ReadStrSize;
uint16_t _u16ResponseTimeout;

// Modbus function codes for bit access
static const uint8_t ku8MBReadCoils = 0x01; ///< Modbus function 0x01 Read Coils
Expand All @@ -288,8 +299,10 @@ class ModbusMaster
static const uint8_t ku8MBMaskWriteRegister = 0x16; ///< Modbus function 0x16 Mask Write Register
static const uint8_t ku8MBReadWriteMultipleRegisters = 0x17; ///< Modbus function 0x17 Read Write Multiple Registers

static const uint8_t ku8MBReadDeviceIdentifiers = 0x2B; ///< Modbus function 0x2B/0E Read DeviceIdentifiers

// Modbus timeout [milliseconds]
static const uint16_t ku16MBResponseTimeout = 2000; ///< Modbus timeout [milliseconds]
static const uint16_t ku16MBDefaultResponseTimeout = 2000; ///< Modbus timeout [milliseconds]

// master function that conducts Modbus transactions
uint8_t ModbusMasterTransaction(uint8_t u8MBFunction);
Expand Down