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

Update ModbusMaster.cpp #98

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
221 changes: 207 additions & 14 deletions src/ModbusMaster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,15 @@ ModbusMaster::ModbusMaster(void)
_idle = 0;
_preTransmission = 0;
_postTransmission = 0;
ku8MaxBufferSize=ku8DefMaxBufferSize;
_u16ResponseBuffer=_u16DefResponseBuffer;

}

#ifndef debugSerialPort
#define debugSerialPort Serial
#endif

/**
Initialize class object.

Expand Down Expand Up @@ -100,7 +107,7 @@ uint8_t ModbusMaster::requestFrom(uint16_t address, uint16_t quantity)
void ModbusMaster::sendBit(bool data)
{
uint8_t txBitIndex = u16TransmitBufferLength % 16;
if ((u16TransmitBufferLength >> 4) < ku8MaxBufferSize)
if ((u16TransmitBufferLength >> 4) < ku8DefMaxBufferSize)
{
if (0 == txBitIndex)
{
Expand All @@ -115,7 +122,7 @@ void ModbusMaster::sendBit(bool data)

void ModbusMaster::send(uint16_t data)
{
if (_u8TransmitBufferIndex < ku8MaxBufferSize)
if (_u8TransmitBufferIndex < ku8DefMaxBufferSize)
{
_u16TransmitBuffer[_u8TransmitBufferIndex++] = data;
u16TransmitBufferLength = _u8TransmitBufferIndex << 4;
Expand Down Expand Up @@ -266,7 +273,7 @@ Place data in transmit buffer.
*/
uint8_t ModbusMaster::setTransmitBuffer(uint8_t u8Index, uint16_t u16Value)
{
if (u8Index < ku8MaxBufferSize)
if (u8Index < ku8DefMaxBufferSize)
{
_u16TransmitBuffer[u8Index] = u16Value;
return ku8MBSuccess;
Expand All @@ -288,7 +295,7 @@ void ModbusMaster::clearTransmitBuffer()
{
uint8_t i;

for (i = 0; i < ku8MaxBufferSize; i++)
for (i = 0; i < ku8DefMaxBufferSize; i++)
{
_u16TransmitBuffer[i] = 0;
}
Expand Down Expand Up @@ -709,13 +716,34 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction)
{
_preTransmission();
}

#ifdef MODBUS_DEBUG
debugSerialPort.println();
#endif

for (i = 0; i < u8ModbusADUSize; i++)
{
_serial->write(u8ModbusADU[i]);

#ifdef MODBUS_DEBUG
if (u8ModbusADU[i]<15) debugSerialPort.print("0");
debugSerialPort.print (u8ModbusADU[i],HEX);
debugSerialPort.print(">");
#endif

}

#ifdef MODBUS_DEBUG
debugSerialPort.println();
#endif

u8ModbusADUSize = 0;
_serial->flush(); // flush transmit buffer

/* while (_tx_buffer->_iHead != _tx_buffer->_iTail); //wait for transmit data to be sent
// Wait for transmission to complete
while ((_pUart->UART_SR & UART_SR_TXEMPTY) != UART_SR_TXEMPTY)
;*/
if (_postTransmission)
{
_postTransmission();
Expand All @@ -726,12 +754,24 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction)
while (u8BytesLeft && !u8MBStatus)
{
if (_serial->available())
{
{ uint8_t ch;
#if __MODBUSMASTER_DEBUG__
digitalWrite(__MODBUSMASTER_DEBUG_PIN_A__, true);
#endif
u8ModbusADU[u8ModbusADUSize++] = _serial->read();
u8BytesLeft--;
ch = _serial->read();

#ifdef MODBUS_DEBUG
if (ch<15) debugSerialPort.print("0");
debugSerialPort.print (ch,HEX);
debugSerialPort.print("<");
#endif


if ((ch == _u8MBSlave) || u8ModbusADUSize)
{
u8ModbusADU[u8ModbusADUSize++]=ch;
u8BytesLeft--;
}
#if __MODBUSMASTER_DEBUG__
digitalWrite(__MODBUSMASTER_DEBUG_PIN_A__, false);
#endif
Expand All @@ -744,6 +784,7 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction)
if (_idle)
{
_idle();
if (_serial->available()) continue;
}
#if __MODBUSMASTER_DEBUG__
digitalWrite(__MODBUSMASTER_DEBUG_PIN_B__, false);
Expand All @@ -753,13 +794,6 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction)
// evaluate slave ID, function code once enough bytes have been read
if (u8ModbusADUSize == 5)
{
// verify response is for correct Modbus slave
if (u8ModbusADU[0] != _u8MBSlave)
{
u8MBStatus = ku8MBInvalidSlaveID;
break;
}

// verify response is for correct Modbus function code (mask exception bit 7)
if ((u8ModbusADU[1] & 0x7F) != u8MBFunction)
{
Expand Down Expand Up @@ -874,3 +908,162 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction)
_u8ResponseBufferIndex = 0;
return u8MBStatus;
}

/**
Modbus-like protocols transaction engine.
Sequence:
- calculate CRC
- transmit buffer over selected serial port + CRC
- wait for/retrieve response
- return status (success/exception)

@param u8ModbusADU - pointer to buffer
@param u8ModbusADUSize - request size
@param u8BytesLeft - how many bytes to be collected back (include CRC) - should be less then buffer size
@return 0 on success; exception number on failure

*/
uint8_t ModbusMaster::ModbusRawTransaction(uint8_t *u8ModbusADU,uint8_t u8ModbusADUSize, uint8_t u8BytesLeft )
{

uint16_t u16CRC;
uint32_t u32StartTime;

uint8_t u8MBStatus = ku8MBSuccess;
u8ModbusADU[0] = _u8MBSlave;
// calculate CRC
u16CRC = 0xFFFF;
for (uint8_t i = 0; i < u8ModbusADUSize; i++)
{
u16CRC = crc16_update(u16CRC, u8ModbusADU[i]);
}

// flush receive buffer before transmitting request
while (_serial->read() != -1);

// transmit request
if (_preTransmission)
{
_preTransmission();
}

#ifdef MODBUS_DEBUG
debugSerialPort.println();
#endif

for (uint8_t i = 0; i < u8ModbusADUSize; i++)
{
_serial->write(u8ModbusADU[i]);

#ifdef MODBUS_DEBUG
if (u8ModbusADU[i]<15) debugSerialPort.print("0");
debugSerialPort.print (u8ModbusADU[i],HEX);
debugSerialPort.print(">");
#endif

}
_serial->write(lowByte(u16CRC));
_serial->write(highByte(u16CRC));

#ifdef MODBUS_DEBUG
if (lowByte(u16CRC)<15) debugSerialPort.print("0");
debugSerialPort.print (lowByte(u16CRC),HEX);

if (highByte(u16CRC)<15) debugSerialPort.print("0");
debugSerialPort.print (highByte(u16CRC),HEX);
debugSerialPort.print(">");

debugSerialPort.println();
#endif


u8ModbusADUSize = 0;
_serial->flush(); // flush transmit buffer
if (_postTransmission)
{
_postTransmission();
}

// loop until we run out of time or bytes, or an error occurs
u32StartTime = millis();
while (u8BytesLeft && !u8MBStatus)
{
if (_serial->available())
{ uint8_t ch;
#if __MODBUSMASTER_DEBUG__
digitalWrite(__MODBUSMASTER_DEBUG_PIN_A__, true);
#endif
ch = _serial->read();

#ifdef MODBUS_DEBUG
if (ch<15) debugSerialPort.print("0");
debugSerialPort.print (ch,HEX);
debugSerialPort.print("<");
#endif


if ((ch == _u8MBSlave) || u8ModbusADUSize)
{
u8ModbusADU[u8ModbusADUSize++]=ch;
u8BytesLeft--;
}
#if __MODBUSMASTER_DEBUG__
digitalWrite(__MODBUSMASTER_DEBUG_PIN_A__, false);
#endif
}
else
{
#if __MODBUSMASTER_DEBUG__
digitalWrite(__MODBUSMASTER_DEBUG_PIN_B__, true);
#endif
if (_idle)
{
_idle();
if (_serial->available()) continue;
}
#if __MODBUSMASTER_DEBUG__
digitalWrite(__MODBUSMASTER_DEBUG_PIN_B__, false);
#endif
}

if ((millis() - u32StartTime) > ku16MBResponseTimeout)
{
u8MBStatus = ku8MBResponseTimedOut;
}
}

// verify response is large enough to inspect further
if (!u8MBStatus && u8ModbusADUSize >= 4)
{
// calculate CRC
u16CRC = 0xFFFF;
for (uint8_t i = 0; i < (u8ModbusADUSize - 2); i++)
{
u16CRC = crc16_update(u16CRC, u8ModbusADU[i]);
}

// verify CRC
if (!u8MBStatus && (lowByte(u16CRC) != u8ModbusADU[u8ModbusADUSize - 2] ||
highByte(u16CRC) != u8ModbusADU[u8ModbusADUSize - 1]))
{
u8MBStatus = ku8MBInvalidCRC;
}
}

_u8TransmitBufferIndex = 0;
u16TransmitBufferLength = 0;
_u8ResponseBufferIndex = 0;
return u8MBStatus;
}
void ModbusMaster::setResponseBuffer(uint16_t *bufPtr,size_t bufLen)
{
ku8MaxBufferSize=bufLen;
_u16ResponseBuffer=bufPtr;

}

void ModbusMaster::setDefaultResponseBuffer()
{
ku8MaxBufferSize=ku8DefMaxBufferSize;
_u16ResponseBuffer=_u16DefResponseBuffer;
}
20 changes: 14 additions & 6 deletions src/ModbusMaster.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Set to 1 to enable debugging features within class:

/* _____PROJECT INCLUDES_____________________________________________________ */
// functions to calculate Modbus Application Data Unit CRC
#include "util/crc16.h"
#include "util/crc16_.h"

// functions to manipulate words
#include "util/word.h"
Expand Down Expand Up @@ -216,17 +216,23 @@ class ModbusMaster
uint8_t maskWriteRegister(uint16_t, uint16_t, uint16_t);
uint8_t readWriteMultipleRegisters(uint16_t, uint16_t, uint16_t, uint16_t);
uint8_t readWriteMultipleRegisters(uint16_t, uint16_t);

uint8_t ModbusRawTransaction(uint8_t *u8ModbusADU,uint8_t u8ModbusADUSize, uint8_t u8BytesLeft);
void setResponseBuffer(uint16_t *bufPtr,size_t bufLen);
void setDefaultResponseBuffer();

private:
Stream* _serial; ///< reference to serial port object
uint8_t _u8MBSlave; ///< Modbus slave (1..255) initialized in begin()
static const uint8_t ku8MaxBufferSize = 64; ///< size of response/transmit buffers

static const uint8_t ku8DefMaxBufferSize = 64; ///< size of response/transmit buffers
uint8_t ku8MaxBufferSize ;
uint16_t _u16ReadAddress; ///< slave register from which to read
uint16_t _u16ReadQty; ///< quantity of words to read
uint16_t _u16ResponseBuffer[ku8MaxBufferSize]; ///< buffer to store Modbus slave response; read via GetResponseBuffer()
uint16_t _u16DefResponseBuffer[ku8DefMaxBufferSize]; ///< buffer to store Modbus slave response; read via GetResponseBuffer()
uint16_t *_u16ResponseBuffer;
uint16_t _u16WriteAddress; ///< slave register to which to write
uint16_t _u16WriteQty; ///< quantity of words to write
uint16_t _u16TransmitBuffer[ku8MaxBufferSize]; ///< buffer containing data to transmit to Modbus slave; set via SetTransmitBuffer()
uint16_t _u16WriteQty; //< quantity of words to write
uint16_t _u16TransmitBuffer[ku8DefMaxBufferSize]; ///< buffer containing data to transmit to Modbus slave; set via SetTransmitBuffer()
uint16_t* txBuffer; // from Wire.h -- need to clean this up Rx
uint8_t _u8TransmitBufferIndex;
uint16_t u16TransmitBufferLength;
Expand Down Expand Up @@ -260,6 +266,8 @@ class ModbusMaster
void (*_preTransmission)();
// postTransmission callback function; gets called after a Modbus message has been sent
void (*_postTransmission)();


};
#endif

Expand Down
File renamed without changes.